add unit tests
This commit is contained in:
parent
a2d20dab8e
commit
0c4c957d67
|
@ -0,0 +1,15 @@
|
||||||
|
name: Cargo build & test
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
pull_request:
|
||||||
|
|
||||||
|
env:
|
||||||
|
CARGO_TERM_COLOR: always
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build_and_test:
|
||||||
|
name: Rust project
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- run: cargo test --verbose
|
|
@ -23,3 +23,6 @@ serde = { version = "1.0.197", optional = true, features = ["derive"] }
|
||||||
serde_json = "1.0.114"
|
serde_json = "1.0.114"
|
||||||
tracing = "0.1.40"
|
tracing = "0.1.40"
|
||||||
zip = { version = "2.1.3", default-features = false, features = ["deflate", "time"], optional = true }
|
zip = { version = "2.1.3", default-features = false, features = ["deflate", "time"], optional = true }
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
tempfile = "3.10.1"
|
||||||
|
|
|
@ -421,7 +421,7 @@ impl Condition {
|
||||||
/// Will fail if the condition contains an `Or` variant. Use `compile` instead.
|
/// Will fail if the condition contains an `Or` variant. Use `compile` instead.
|
||||||
fn str_cond(&self) -> Option<String> {
|
fn str_cond(&self) -> Option<String> {
|
||||||
match self {
|
match self {
|
||||||
Self::Atom(s) => Some("if ".to_string() + &s),
|
Self::Atom(s) => Some("if ".to_string() + s),
|
||||||
Self::Not(n) => match *(*n).clone() {
|
Self::Not(n) => match *(*n).clone() {
|
||||||
Self::Atom(s) => Some("unless ".to_string() + &s),
|
Self::Atom(s) => Some("unless ".to_string() + &s),
|
||||||
_ => None,
|
_ => None,
|
||||||
|
@ -491,7 +491,7 @@ mod tests {
|
||||||
#[allow(clippy::redundant_clone)]
|
#[allow(clippy::redundant_clone)]
|
||||||
#[test]
|
#[test]
|
||||||
fn test_condition() {
|
fn test_condition() {
|
||||||
let c1 = Condition::Atom("foo".to_string());
|
let c1 = Condition::from("foo");
|
||||||
let c2 = Condition::Atom("bar".to_string());
|
let c2 = Condition::Atom("bar".to_string());
|
||||||
let c3 = Condition::Atom("baz".to_string());
|
let c3 = Condition::Atom("baz".to_string());
|
||||||
|
|
||||||
|
@ -574,4 +574,56 @@ mod tests {
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_combine_conditions_commands() {
|
||||||
|
let conditions = vec!["a", "b", "c"]
|
||||||
|
.into_iter()
|
||||||
|
.map(str::to_string)
|
||||||
|
.collect();
|
||||||
|
let commands = &[(true, "1".to_string()), (false, "2".to_string())];
|
||||||
|
|
||||||
|
let combined = combine_conditions_commands(conditions, commands);
|
||||||
|
assert_eq!(
|
||||||
|
combined,
|
||||||
|
vec![
|
||||||
|
(true, "a 1".to_string()),
|
||||||
|
(false, "2".to_string()),
|
||||||
|
(true, "b 1".to_string()),
|
||||||
|
(false, "2".to_string()),
|
||||||
|
(true, "c 1".to_string()),
|
||||||
|
(false, "2".to_string())
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_compile() {
|
||||||
|
let compiled = Execute::As(
|
||||||
|
"@ְa".to_string(),
|
||||||
|
Box::new(Execute::If(
|
||||||
|
"block ~ ~-1 ~ minecraft:stone".into(),
|
||||||
|
Box::new(Execute::Run(Box::new("say hi".into()))),
|
||||||
|
None,
|
||||||
|
)),
|
||||||
|
)
|
||||||
|
.compile(
|
||||||
|
&CompileOptions::default(),
|
||||||
|
&MutCompilerState::default(),
|
||||||
|
&FunctionCompilerState::default(),
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
compiled,
|
||||||
|
vec!["execute as @ְa if block ~ ~-1 ~ minecraft:stone run say hi".to_string()]
|
||||||
|
);
|
||||||
|
|
||||||
|
let direct = Execute::Run(Box::new("say direct".into())).compile(
|
||||||
|
&CompileOptions::default(),
|
||||||
|
&MutCompilerState::default(),
|
||||||
|
&FunctionCompilerState::default(),
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(direct, vec!["say direct".to_string()]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,6 +56,7 @@ impl Command {
|
||||||
#[must_use]
|
#[must_use]
|
||||||
fn get_count(&self, options: &CompileOptions) -> usize {
|
fn get_count(&self, options: &CompileOptions) -> usize {
|
||||||
match self {
|
match self {
|
||||||
|
// TODO: change comment to compile to `1`, make sure nothing breaks
|
||||||
Self::Comment(_) => 0,
|
Self::Comment(_) => 0,
|
||||||
Self::Debug(_) => usize::from(options.debug),
|
Self::Debug(_) => usize::from(options.debug),
|
||||||
Self::Raw(cmd) => cmd.split('\n').count(),
|
Self::Raw(cmd) => cmd.split('\n').count(),
|
||||||
|
@ -266,3 +267,60 @@ fn validate_raw_cmd(cmd: &str, pack_formats: &RangeInclusive<u8>) -> bool {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use std::sync::Mutex;
|
||||||
|
|
||||||
|
use crate::util::compile::CompilerState;
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_raw() {
|
||||||
|
let command_a = Command::Raw("say Hello, world!".to_string());
|
||||||
|
let command_b = Command::raw("say foo bar");
|
||||||
|
|
||||||
|
let options = &CompileOptions::default();
|
||||||
|
let global_state = &Mutex::new(CompilerState::default());
|
||||||
|
let function_state = &FunctionCompilerState::default();
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
command_a.compile(options, global_state, function_state),
|
||||||
|
vec!["say Hello, world!".to_string()]
|
||||||
|
);
|
||||||
|
assert_eq!(command_a.get_count(options), 1);
|
||||||
|
assert_eq!(
|
||||||
|
command_b.compile(options, global_state, function_state),
|
||||||
|
vec!["say foo bar".to_string()]
|
||||||
|
);
|
||||||
|
assert_eq!(command_b.get_count(options), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_comment() {
|
||||||
|
let comment = Command::Comment("this is a comment".to_string());
|
||||||
|
|
||||||
|
let options = &CompileOptions::default();
|
||||||
|
let global_state = &Mutex::new(CompilerState::default());
|
||||||
|
let function_state = &FunctionCompilerState::default();
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
comment.compile(options, global_state, function_state),
|
||||||
|
vec!["#this is a comment".to_string()]
|
||||||
|
);
|
||||||
|
assert_eq!(comment.get_count(options), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_validate() {
|
||||||
|
let tag = Command::raw("tag @s add foo");
|
||||||
|
|
||||||
|
assert!(tag.validate(&(6..=9)));
|
||||||
|
assert!(!tag.validate(&(2..=5)));
|
||||||
|
|
||||||
|
let kill = Command::raw("kill @p");
|
||||||
|
|
||||||
|
assert!(kill.validate(&(2..=40)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -74,3 +74,33 @@ impl Function {
|
||||||
self.commands.iter().all(|c| c.validate(pack_formats))
|
self.commands.iter().all(|c| c.validate(pack_formats))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
use crate::util::compile::CompilerState;
|
||||||
|
use std::sync::Mutex;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_function() {
|
||||||
|
let mut function = Function::new("namespace", "name");
|
||||||
|
|
||||||
|
assert_eq!(function.get_commands().len(), 0);
|
||||||
|
|
||||||
|
function.add_command(Command::raw("say Hello, world!"));
|
||||||
|
|
||||||
|
assert_eq!(function.get_commands().len(), 1);
|
||||||
|
|
||||||
|
let options = &CompileOptions::default();
|
||||||
|
let global_state = &Mutex::new(CompilerState::default());
|
||||||
|
let function_state = &FunctionCompilerState::default();
|
||||||
|
|
||||||
|
let compiled = function.compile(options, global_state, function_state);
|
||||||
|
|
||||||
|
assert!(matches!(
|
||||||
|
compiled,
|
||||||
|
VFile::Text(content) if content == "say Hello, world!"
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -158,3 +158,56 @@ fn generate_mcmeta(dp: &Datapack, _options: &CompileOptions, _state: &MutCompile
|
||||||
|
|
||||||
VFile::Text(content.to_string())
|
VFile::Text(content.to_string())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_datapack() {
|
||||||
|
let template_dir = tempfile::tempdir().expect("error creating tempdir");
|
||||||
|
|
||||||
|
let mut dp = Datapack::new(Datapack::LATEST_FORMAT)
|
||||||
|
.with_description("My datapack")
|
||||||
|
.with_template_folder(template_dir.path())
|
||||||
|
.expect("error reading template folder");
|
||||||
|
|
||||||
|
assert_eq!(dp.namespaces.len(), 0);
|
||||||
|
|
||||||
|
let _ = dp.namespace_mut("foo");
|
||||||
|
assert_eq!(dp.namespaces.len(), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_generate_mcmeta() {
|
||||||
|
let dp = &Datapack::new(Datapack::LATEST_FORMAT).with_description("foo");
|
||||||
|
let state = Mutex::new(CompilerState::default());
|
||||||
|
let mcmeta = generate_mcmeta(dp, &CompileOptions::default(), &state);
|
||||||
|
|
||||||
|
let json = if let VFile::Text(text) = mcmeta {
|
||||||
|
serde_json::from_str::<serde_json::Value>(&text).unwrap()
|
||||||
|
} else {
|
||||||
|
panic!("mcmeta should be text not binary")
|
||||||
|
};
|
||||||
|
|
||||||
|
let pack = json
|
||||||
|
.as_object()
|
||||||
|
.expect("mcmeta is not object")
|
||||||
|
.get("pack")
|
||||||
|
.expect("no pack value")
|
||||||
|
.as_object()
|
||||||
|
.expect("mcmeta pack is not object");
|
||||||
|
assert_eq!(
|
||||||
|
pack.get("description")
|
||||||
|
.expect("no key pack.description")
|
||||||
|
.as_str(),
|
||||||
|
Some("foo")
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
pack.get("pack_format")
|
||||||
|
.expect("no key pack.pack_format")
|
||||||
|
.as_u64(),
|
||||||
|
Some(u64::from(Datapack::LATEST_FORMAT))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -109,13 +109,7 @@ impl Namespace {
|
||||||
// compile tags
|
// compile tags
|
||||||
for ((path, tag_type), tag) in &self.tags {
|
for ((path, tag_type), tag) in &self.tags {
|
||||||
let vfile = tag.compile(options, state);
|
let vfile = tag.compile(options, state);
|
||||||
root_folder.add_file(
|
root_folder.add_file(&format!("tags/{tag_type}/{path}.json"), vfile);
|
||||||
&format!(
|
|
||||||
"tags/{tag_type}/{path}.json",
|
|
||||||
tag_type = tag_type.to_string()
|
|
||||||
),
|
|
||||||
vfile,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
root_folder
|
root_folder
|
||||||
|
@ -129,3 +123,23 @@ impl Namespace {
|
||||||
.all(|function| function.validate(pack_formats))
|
.all(|function| function.validate(pack_formats))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_namespace() {
|
||||||
|
let mut namespace = Namespace::new("foo");
|
||||||
|
|
||||||
|
assert_eq!(namespace.get_name(), "foo");
|
||||||
|
assert_eq!(namespace.get_functions().len(), 0);
|
||||||
|
assert_eq!(namespace.get_tags().len(), 0);
|
||||||
|
|
||||||
|
let _ = namespace.function_mut("bar");
|
||||||
|
assert_eq!(namespace.get_functions().len(), 1);
|
||||||
|
|
||||||
|
assert!(namespace.function("bar").is_some());
|
||||||
|
assert!(namespace.function("baz").is_none());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
//! A tag for various types.
|
//! A tag for various types.
|
||||||
|
|
||||||
|
use std::fmt::Display;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
util::compile::{CompileOptions, MutCompilerState},
|
util::compile::{CompileOptions, MutCompilerState},
|
||||||
virtual_fs::VFile,
|
virtual_fs::VFile,
|
||||||
|
@ -81,9 +83,9 @@ pub enum TagType {
|
||||||
/// `Others(<registry path>)` => `data/<namespace>/tags/<registry path>`
|
/// `Others(<registry path>)` => `data/<namespace>/tags/<registry path>`
|
||||||
Others(String),
|
Others(String),
|
||||||
}
|
}
|
||||||
impl ToString for TagType {
|
impl Display for TagType {
|
||||||
fn to_string(&self) -> String {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
match self {
|
let str = match self {
|
||||||
Self::Blocks => "block".to_string(),
|
Self::Blocks => "block".to_string(),
|
||||||
Self::Fluids => "fluid".to_string(),
|
Self::Fluids => "fluid".to_string(),
|
||||||
Self::Items => "item".to_string(),
|
Self::Items => "item".to_string(),
|
||||||
|
@ -91,7 +93,8 @@ impl ToString for TagType {
|
||||||
Self::GameEvents => "game_event".to_string(),
|
Self::GameEvents => "game_event".to_string(),
|
||||||
Self::Functions => "function".to_string(),
|
Self::Functions => "function".to_string(),
|
||||||
Self::Others(path) => path.to_string(),
|
Self::Others(path) => path.to_string(),
|
||||||
}
|
};
|
||||||
|
f.write_str(&str)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -122,11 +125,53 @@ impl TagValue {
|
||||||
match self {
|
match self {
|
||||||
Self::Simple(value) => serde_json::Value::String(value.clone()),
|
Self::Simple(value) => serde_json::Value::String(value.clone()),
|
||||||
Self::Advanced { id, required } => {
|
Self::Advanced { id, required } => {
|
||||||
let mut map = serde_json::Map::new();
|
serde_json::json!({
|
||||||
map.insert("id".to_string(), serde_json::Value::String(id.clone()));
|
"id": id.clone(),
|
||||||
map.insert("required".to_string(), serde_json::Value::Bool(*required));
|
"required": *required
|
||||||
serde_json::Value::Object(map)
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_tag() {
|
||||||
|
let mut tag = Tag::new(false);
|
||||||
|
assert!(!tag.get_replace());
|
||||||
|
|
||||||
|
tag.set_replace(true);
|
||||||
|
assert!(tag.get_replace());
|
||||||
|
|
||||||
|
tag.add_value(TagValue::from("foo:bar"));
|
||||||
|
tag.add_value(TagValue::Advanced {
|
||||||
|
id: "bar:baz".to_string(),
|
||||||
|
required: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
assert_eq!(tag.get_values().len(), 2);
|
||||||
|
|
||||||
|
let compiled = tag.compile(&CompileOptions::default(), &MutCompilerState::default());
|
||||||
|
|
||||||
|
if let VFile::Text(text) = compiled {
|
||||||
|
let deserialized = serde_json::from_str::<serde_json::Value>(&text)
|
||||||
|
.expect("Failed to deserialize tag");
|
||||||
|
assert_eq!(
|
||||||
|
deserialized,
|
||||||
|
serde_json::json!({
|
||||||
|
"replace": true,
|
||||||
|
"values": [
|
||||||
|
"foo:bar",
|
||||||
|
{
|
||||||
|
"id": "bar:baz",
|
||||||
|
"required": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
rustdoc::broken_intra_doc_links,
|
rustdoc::broken_intra_doc_links,
|
||||||
clippy::missing_errors_doc
|
clippy::missing_errors_doc
|
||||||
)]
|
)]
|
||||||
#![warn(clippy::all, clippy::pedantic)]
|
#![warn(clippy::all, clippy::pedantic, clippy::perf)]
|
||||||
#![allow(clippy::missing_panics_doc, clippy::missing_const_for_fn)]
|
#![allow(clippy::missing_panics_doc, clippy::missing_const_for_fn)]
|
||||||
|
|
||||||
pub mod datapack;
|
pub mod datapack;
|
||||||
|
|
|
@ -40,7 +40,7 @@ pub struct CompilerState {}
|
||||||
pub type MutCompilerState = Mutex<CompilerState>;
|
pub type MutCompilerState = Mutex<CompilerState>;
|
||||||
|
|
||||||
/// State of the compiler for each function that can change during compilation.
|
/// State of the compiler for each function that can change during compilation.
|
||||||
#[derive(Debug, Getters)]
|
#[derive(Debug, Getters, Default)]
|
||||||
pub struct FunctionCompilerState {
|
pub struct FunctionCompilerState {
|
||||||
/// Next unique identifier.
|
/// Next unique identifier.
|
||||||
uid_counter: Mutex<usize>,
|
uid_counter: Mutex<usize>,
|
||||||
|
|
|
@ -38,7 +38,7 @@ impl<T> ExtendableQueue<T> {
|
||||||
|
|
||||||
/// Get the queue.
|
/// Get the queue.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn get(&self) -> &Arc<RwLock<VecDeque<T>>> {
|
pub fn get_arc(&self) -> &Arc<RwLock<VecDeque<T>>> {
|
||||||
&self.queue
|
&self.queue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -85,3 +85,39 @@ impl<T> Iterator for ExtendableQueue<T> {
|
||||||
self.queue.write().unwrap().pop_front()
|
self.queue.write().unwrap().pop_front()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_queue() {
|
||||||
|
let mut queue = ExtendableQueue::default();
|
||||||
|
queue.push(1);
|
||||||
|
queue.push(2);
|
||||||
|
queue.push(3);
|
||||||
|
|
||||||
|
assert_eq!(queue.len(), 3);
|
||||||
|
|
||||||
|
let mut count = 0;
|
||||||
|
|
||||||
|
while let Some(el) = queue.next() {
|
||||||
|
count += el;
|
||||||
|
|
||||||
|
if el == 1 {
|
||||||
|
queue.extend(vec![4, 5, 6]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_eq!(count, 21);
|
||||||
|
assert!(queue.is_empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_from() {
|
||||||
|
let base = vec![1, 2, 3, 4];
|
||||||
|
let queue = ExtendableQueue::from(base.clone());
|
||||||
|
|
||||||
|
assert!(queue.into_iter().zip(base).all(|(a, b)| a == b));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -284,11 +284,9 @@ impl TryFrom<&Path> for VFolder {
|
||||||
if let Some(name) = name {
|
if let Some(name) = name {
|
||||||
if path.is_dir() {
|
if path.is_dir() {
|
||||||
root_vfolder.add_existing_folder(&name, Self::try_from(path.as_path())?);
|
root_vfolder.add_existing_folder(&name, Self::try_from(path.as_path())?);
|
||||||
} else if path.is_file() {
|
} else {
|
||||||
let file = VFile::try_from(path.as_path())?;
|
let file = VFile::try_from(path.as_path())?;
|
||||||
root_vfolder.add_file(&name, file);
|
root_vfolder.add_file(&name, file);
|
||||||
} else {
|
|
||||||
unreachable!("Path is neither file nor directory");
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return Err(io::Error::new(
|
return Err(io::Error::new(
|
||||||
|
@ -353,6 +351,8 @@ mod tests {
|
||||||
let v_file_2 = VFile::from("baz");
|
let v_file_2 = VFile::from("baz");
|
||||||
v_folder.add_file("bar/baz.txt", v_file_2);
|
v_folder.add_file("bar/baz.txt", v_file_2);
|
||||||
|
|
||||||
|
v_folder.add_file("bar/foo.bin", VFile::Binary(vec![1, 2, 3, 4]));
|
||||||
|
|
||||||
assert_eq!(v_folder.get_files().len(), 1);
|
assert_eq!(v_folder.get_files().len(), 1);
|
||||||
assert_eq!(v_folder.get_folders().len(), 1);
|
assert_eq!(v_folder.get_folders().len(), 1);
|
||||||
assert!(v_folder.get_file("bar/baz.txt").is_some());
|
assert!(v_folder.get_file("bar/baz.txt").is_some());
|
||||||
|
@ -361,5 +361,79 @@ mod tests {
|
||||||
.expect("folder not found")
|
.expect("folder not found")
|
||||||
.get_file("baz.txt")
|
.get_file("baz.txt")
|
||||||
.is_some());
|
.is_some());
|
||||||
|
|
||||||
|
let temp = tempfile::tempdir().expect("failed to create temp dir");
|
||||||
|
v_folder.place(temp.path()).expect("failed to place folder");
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
fs::read_to_string(temp.path().join("foo.txt")).expect("failed to read file"),
|
||||||
|
"foo"
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
fs::read_to_string(temp.path().join("bar/baz.txt")).expect("failed to read file"),
|
||||||
|
"baz"
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
fs::read(temp.path().join("bar/foo.bin")).expect("failed to read file"),
|
||||||
|
vec![1, 2, 3, 4]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_flatten() {
|
||||||
|
let mut v_folder = VFolder::new();
|
||||||
|
v_folder.add_file("a.txt", VFile::from("a"));
|
||||||
|
v_folder.add_file("a/b.txt", VFile::from("b"));
|
||||||
|
v_folder.add_file("a/b/c.txt", VFile::from("c"));
|
||||||
|
|
||||||
|
let flattened = v_folder.flatten();
|
||||||
|
assert_eq!(flattened.len(), 3);
|
||||||
|
assert!(flattened.iter().any(|(path, _)| path == "a.txt"));
|
||||||
|
assert!(flattened.iter().any(|(path, _)| path == "a/b.txt"));
|
||||||
|
assert!(flattened.iter().any(|(path, _)| path == "a/b/c.txt"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_merge() {
|
||||||
|
let mut first = VFolder::new();
|
||||||
|
first.add_file("a.txt", VFile::from("a"));
|
||||||
|
first.add_file("a/b.txt", VFile::from("b"));
|
||||||
|
|
||||||
|
let mut second = VFolder::new();
|
||||||
|
second.add_file("a.txt", VFile::from("a2"));
|
||||||
|
second.add_file("c.txt", VFile::from("c"));
|
||||||
|
second.add_file("c/d.txt", VFile::from("d"));
|
||||||
|
second.add_file("a/e.txt", VFile::from("e"));
|
||||||
|
|
||||||
|
let replaced = first.merge(second);
|
||||||
|
assert_eq!(replaced.len(), 1);
|
||||||
|
|
||||||
|
assert!(first.get_file("a.txt").is_some());
|
||||||
|
assert!(first.get_file("a/b.txt").is_some());
|
||||||
|
assert!(first.get_file("c.txt").is_some());
|
||||||
|
assert!(first.get_file("c/d.txt").is_some());
|
||||||
|
assert!(first.get_file("a/e.txt").is_some());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_try_from() {
|
||||||
|
let temp_dir = tempfile::tempdir().expect("failed to create temp dir");
|
||||||
|
fs::create_dir_all(temp_dir.path().join("bar")).expect("failed to create dir");
|
||||||
|
fs::write(temp_dir.path().join("foo.txt"), "foo").expect("failed to write file");
|
||||||
|
fs::write(temp_dir.path().join("bar/baz.txt"), "baz").expect("failed to write file");
|
||||||
|
|
||||||
|
let v_folder = VFolder::try_from(temp_dir.path()).expect("failed to convert");
|
||||||
|
assert_eq!(v_folder.get_files().len(), 1);
|
||||||
|
assert_eq!(v_folder.get_folders().len(), 1);
|
||||||
|
if let VFile::Binary(data) = v_folder.get_file("foo.txt").expect("file not found") {
|
||||||
|
assert_eq!(data, b"foo");
|
||||||
|
} else {
|
||||||
|
panic!("File is not binary");
|
||||||
|
}
|
||||||
|
if let VFile::Binary(data) = v_folder.get_file("bar/baz.txt").expect("file not found") {
|
||||||
|
assert_eq!(data, b"baz");
|
||||||
|
} else {
|
||||||
|
panic!("File is not binary");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue