From 2b27b788e56e47c1e96f0a595b198a43d4f39e00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20Boy=C3=A9?= Date: Sat, 12 Aug 2023 23:52:26 +0200 Subject: [PATCH] Test TreeWalker + some fixes. --- Cargo.lock | 203 ++++++++++++++++++++++---------------- libbsv/Cargo.toml | 5 +- libbsv/src/ignore.rs | 42 ++++---- libbsv/src/lib.rs | 17 ++-- libbsv/src/permissions.rs | 4 +- libbsv/src/repository.rs | 2 +- libbsv/src/tree_item.rs | 2 +- libbsv/src/tree_walker.rs | 120 +++++++++++++++++++--- 8 files changed, 266 insertions(+), 129 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6b4be79..e42182d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,6 +17,12 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" +[[package]] +name = "bitflags" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635" + [[package]] name = "block-buffer" version = "0.9.0" @@ -54,6 +60,15 @@ dependencies = [ "toml", ] +[[package]] +name = "cc" +version = "1.0.82" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "305fe645edc1442a0fa8b6726ba61d422798d37a52e12eaecf4b022ebbb88f01" +dependencies = [ + "libc", +] + [[package]] name = "cfg-if" version = "1.0.0" @@ -79,24 +94,40 @@ dependencies = [ ] [[package]] -name = "generic-array" -version = "0.14.4" +name = "errno" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "501466ecc8a30d1d3b7fc9229b122b2ce8ed6e9d9223f1138d4babb253e51817" +checksum = "6b30f669a7961ef1631673d2766cc92f52d64f7ef354d4fe0ddfd30ed52f0f4f" dependencies = [ - "typenum", - "version_check", + "errno-dragonfly", + "libc", + "windows-sys", ] [[package]] -name = "getrandom" -version = "0.2.3" +name = "errno-dragonfly" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753" +checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" dependencies = [ - "cfg-if", + "cc", "libc", - "wasi", +] + +[[package]] +name = "fastrand" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6999dc1837253364c2ebb0704ba97994bd874e8f195d665c50b7548f6ea92764" + +[[package]] +name = "generic-array" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "501466ecc8a30d1d3b7fc9229b122b2ce8ed6e9d9223f1138d4babb253e51817" +dependencies = [ + "typenum", + "version_check", ] [[package]] @@ -107,14 +138,21 @@ dependencies = [ "cas-core", "cas-simple", "regex", + "tempfile", "toml", ] [[package]] name = "libc" -version = "0.2.98" +version = "0.2.147" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "320cfe77175da3a483efed4bc0adc1968ca050b098ce4f2f1c13a56626128790" +checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" + +[[package]] +name = "linux-raw-sys" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57bcfdad1b858c2db7c38303a6d2ad4dfaf5eb53dfeb0910128b2c26d6158503" [[package]] name = "memchr" @@ -128,12 +166,6 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" -[[package]] -name = "ppv-lite86" -version = "0.2.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857" - [[package]] name = "proc-macro2" version = "1.0.27" @@ -152,53 +184,13 @@ dependencies = [ "proc-macro2", ] -[[package]] -name = "rand" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e7573632e6454cf6b99d7aac4ccca54be06da05aca2ef7423d22d27d4d4bcd8" -dependencies = [ - "libc", - "rand_chacha", - "rand_core", - "rand_hc", -] - -[[package]] -name = "rand_chacha" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" -dependencies = [ - "ppv-lite86", - "rand_core", -] - -[[package]] -name = "rand_core" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" -dependencies = [ - "getrandom", -] - -[[package]] -name = "rand_hc" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d51e9f596de227fda2ea6c84607f5558e196eeaf43c986b724ba4fb8fdf497e7" -dependencies = [ - "rand_core", -] - [[package]] name = "redox_syscall" -version = "0.2.9" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ab49abadf3f9e1c4bc499e8845e152ad87d2ad2d30371841171169e9d75feee" +checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" dependencies = [ - "bitflags", + "bitflags 1.2.1", ] [[package]] @@ -219,12 +211,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a3f87b73ce11b1619a3c6332f45341e0047173771e8b8b73f87bfeefb7b56244" [[package]] -name = "remove_dir_all" -version = "0.5.3" +name = "rustix" +version = "0.38.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" +checksum = "19ed4fa021d81c8392ce04db050a3da9a60299050b7ae1cf482d862b54a7218f" dependencies = [ - "winapi", + "bitflags 2.4.0", + "errno", + "libc", + "linux-raw-sys", + "windows-sys", ] [[package]] @@ -259,16 +255,15 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.2.0" +version = "3.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22" +checksum = "dc02fddf48964c42031a0b3fe0428320ecf3a73c401040fc0096f97794310651" dependencies = [ "cfg-if", - "libc", - "rand", + "fastrand", "redox_syscall", - "remove_dir_all", - "winapi", + "rustix", + "windows-sys", ] [[package]] @@ -319,29 +314,67 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe" [[package]] -name = "wasi" -version = "0.10.2+wasi-snapshot-preview1" +name = "windows-sys" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets", +] [[package]] -name = "winapi" -version = "0.3.9" +name = "windows-targets" +version = "0.48.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +checksum = "05d4b17490f70499f20b9e791dcf6a299785ce8af4d709018206dc5b4953e95f" dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", ] [[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" +name = "windows_aarch64_gnullvm" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" [[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" +name = "windows_x86_64_msvc" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" diff --git a/libbsv/Cargo.toml b/libbsv/Cargo.toml index b226b18..b38f087 100644 --- a/libbsv/Cargo.toml +++ b/libbsv/Cargo.toml @@ -10,4 +10,7 @@ toml = "0.5.8" camino = "1.0.7" regex = "1.6.0" cas-core = { path = "../cas-core" } -cas-simple = { path = "../cas-simple" } \ No newline at end of file +cas-simple = { path = "../cas-simple" } + +[dev-dependencies] +tempfile = "3.7.1" diff --git a/libbsv/src/ignore.rs b/libbsv/src/ignore.rs index c47d31f..38b9a24 100644 --- a/libbsv/src/ignore.rs +++ b/libbsv/src/ignore.rs @@ -14,14 +14,14 @@ // along with bsv. If not, see . -use camino::{Utf8Path, Utf8PathBuf}; +use camino::Utf8Path; use regex::RegexSet; use cas_core::{err, Error, Result}; #[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum Action { +pub enum IgnoreAction { Ignore, Accept, } @@ -30,7 +30,7 @@ pub enum Action { #[derive(Debug)] pub struct IgnoreRules { patterns: RegexSet, - actions: Vec, + actions: Vec, } @@ -54,7 +54,7 @@ impl IgnoreRules { }; let mut patterns = Vec::::default(); - let mut actions = Vec::::default(); + let mut actions = Vec::::default(); for line in source.lines() { let rule = line.trim(); @@ -65,10 +65,10 @@ impl IgnoreRules { if rule_it.peek() == Some(&'!') { rule_it.next(); - actions.push(Action::Accept); + actions.push(IgnoreAction::Accept); } else { - actions.push(Action::Ignore); + actions.push(IgnoreAction::Ignore); } let mut pat = String::new(); @@ -125,13 +125,13 @@ impl IgnoreRules { }) } - pub fn action_for>(&self, path: P) -> Action { + pub fn action_for>(&self, path: P) -> IgnoreAction { assert!(path.as_ref().is_absolute()); let index = self.patterns.matches(path.as_ref().as_str()) .iter() .next() .unwrap_or(self.actions.len()); - *self.actions.get(index).unwrap_or(&Action::Accept) + *self.actions.get(index).unwrap_or(&IgnoreAction::Accept) } } @@ -139,6 +139,8 @@ impl IgnoreRules { #[cfg(test)] mod tests { + use camino::Utf8PathBuf; + use super::*; #[test] @@ -147,17 +149,17 @@ mod tests { let patterns = "!hello/world\nhello\n/world/\n\\!\\*\n*.bak"; let ignore = IgnoreRules::from_source(patterns, root).unwrap(); - assert_eq!(ignore.action_for(Utf8PathBuf::from("/foo.dir/bar/test")), Action::Accept); - assert_eq!(ignore.action_for(Utf8PathBuf::from("/foo.dir/bar/test/hello/aoeu")), Action::Ignore); - assert_eq!(ignore.action_for(Utf8PathBuf::from("/foo.dir/bar/test/hello_world/aoeu")), Action::Accept); - assert_eq!(ignore.action_for(Utf8PathBuf::from("/foo.dir/bar/test/world/aoeu")), Action::Accept); - assert_eq!(ignore.action_for(Utf8PathBuf::from("/foo.dir/bar/test/hello/world/aoeu")), Action::Accept); - assert_eq!(ignore.action_for(Utf8PathBuf::from("/foo.dir/bar/world/aoeu")), Action::Ignore); - assert_eq!(ignore.action_for(Utf8PathBuf::from("/foo.dir/bar/world")), Action::Ignore); - assert_eq!(ignore.action_for(Utf8PathBuf::from("/fooXdir/bar/world")), Action::Accept); - assert_eq!(ignore.action_for(Utf8PathBuf::from("/foo.dir/bar/test/!*/aoeu")), Action::Ignore); - assert_eq!(ignore.action_for(Utf8PathBuf::from("/foo.dir/bar/test/file.bak")), Action::Ignore); - assert_eq!(ignore.action_for(Utf8PathBuf::from("/foo.dir/bar/test/fileXbak")), Action::Accept); - assert_eq!(ignore.action_for(Utf8PathBuf::from("/foo.dir/bar/test.bak/file")), Action::Ignore); + assert_eq!(ignore.action_for(Utf8PathBuf::from("/foo.dir/bar/test")), IgnoreAction::Accept); + assert_eq!(ignore.action_for(Utf8PathBuf::from("/foo.dir/bar/test/hello/aoeu")), IgnoreAction::Ignore); + assert_eq!(ignore.action_for(Utf8PathBuf::from("/foo.dir/bar/test/hello_world/aoeu")), IgnoreAction::Accept); + assert_eq!(ignore.action_for(Utf8PathBuf::from("/foo.dir/bar/test/world/aoeu")), IgnoreAction::Accept); + assert_eq!(ignore.action_for(Utf8PathBuf::from("/foo.dir/bar/test/hello/world/aoeu")), IgnoreAction::Accept); + assert_eq!(ignore.action_for(Utf8PathBuf::from("/foo.dir/bar/world/aoeu")), IgnoreAction::Ignore); + assert_eq!(ignore.action_for(Utf8PathBuf::from("/foo.dir/bar/world")), IgnoreAction::Ignore); + assert_eq!(ignore.action_for(Utf8PathBuf::from("/fooXdir/bar/world")), IgnoreAction::Accept); + assert_eq!(ignore.action_for(Utf8PathBuf::from("/foo.dir/bar/test/!*/aoeu")), IgnoreAction::Ignore); + assert_eq!(ignore.action_for(Utf8PathBuf::from("/foo.dir/bar/test/file.bak")), IgnoreAction::Ignore); + assert_eq!(ignore.action_for(Utf8PathBuf::from("/foo.dir/bar/test/fileXbak")), IgnoreAction::Accept); + assert_eq!(ignore.action_for(Utf8PathBuf::from("/foo.dir/bar/test.bak/file")), IgnoreAction::Ignore); } } diff --git a/libbsv/src/lib.rs b/libbsv/src/lib.rs index 0a1207c..2311357 100644 --- a/libbsv/src/lib.rs +++ b/libbsv/src/lib.rs @@ -18,19 +18,24 @@ extern crate toml; extern crate camino; extern crate regex; +#[cfg(test)] +extern crate tempfile; + extern crate cas_core; -mod permissions; -mod tree_item; -mod tree_walker; // mod config; -mod path_map; mod ignore; +mod path_map; +mod permissions; mod repository; +mod tree_item; +mod tree_walker; +pub use crate::ignore::{IgnoreAction, IgnoreRules}; +pub use crate::path_map::{PathMap, PathPair}; pub use crate::permissions::Permissions; +pub use crate::repository::Repository; pub use crate::tree_item::{Serialize, TreeItem}; -pub use crate::path_map::{PathMap, PathPair}; -pub use crate::repository::{Repository}; +pub use crate::tree_walker::{Action, TreeWalker}; diff --git a/libbsv/src/permissions.rs b/libbsv/src/permissions.rs index cb6adad..da10d45 100644 --- a/libbsv/src/permissions.rs +++ b/libbsv/src/permissions.rs @@ -40,9 +40,9 @@ impl Permissions { use std::os::unix::fs::MetadataExt; let mode = metadata.mode(); Ok(Self { - read: mode & 0o100 != 0, + read: mode & 0o400 != 0, write: mode & 0o200 != 0, - execute: mode & 0o400 != 0, + execute: mode & 0o100 != 0, }) } diff --git a/libbsv/src/repository.rs b/libbsv/src/repository.rs index b4d597d..a16de7d 100644 --- a/libbsv/src/repository.rs +++ b/libbsv/src/repository.rs @@ -18,7 +18,7 @@ use camino::{Utf8Path, Utf8PathBuf}; use toml::Value; use cas_core::{Cas, err, Error, ObjectId, Result}; -use cas_simple::{SimpleCas}; +use cas_simple::SimpleCas; pub use crate::permissions::Permissions; pub use crate::tree_item::{Serialize, TreeItem}; diff --git a/libbsv/src/tree_item.rs b/libbsv/src/tree_item.rs index e958368..5e3fbe2 100644 --- a/libbsv/src/tree_item.rs +++ b/libbsv/src/tree_item.rs @@ -58,7 +58,7 @@ impl TreeItem { Ok(Self { name: name, otype, - size: metadata.len(), + size: if metadata.is_file() { metadata.len() } else { 0 }, created: metadata.created().unwrap_or(UNIX_EPOCH), modified: metadata.modified().unwrap_or(UNIX_EPOCH), permissions, diff --git a/libbsv/src/tree_walker.rs b/libbsv/src/tree_walker.rs index 6c28ed6..505db0a 100644 --- a/libbsv/src/tree_walker.rs +++ b/libbsv/src/tree_walker.rs @@ -15,14 +15,14 @@ use std::iter::Peekable; -use std::fs::{DirEntry, Metadata, ReadDir, read_dir}; +use std::fs::read_dir; use std::vec::IntoIter; -use camino::{Utf8Path, Utf8PathBuf}; +use camino::Utf8Path; -use cas_core::{err, Error, ObjectId, Result}; +use cas_core::{Error, ObjectId, Result}; -use crate::{PathPair, Repository, TreeItem}; +use crate::TreeItem; #[derive(Debug, Clone, Copy, PartialEq, Eq)] @@ -87,13 +87,15 @@ impl Iterator for TreeWalker { (Some(Ok(curr_item)), Some(prev_item)) => { if curr_item.name == prev_item.name { let action = - if curr_item.modified != prev_item.modified { + if curr_item.modified != prev_item.modified + || curr_item.otype != prev_item.otype + || curr_item.size != prev_item.size { Action::Update } else { Action::Skip }; - self.prev_tree_it.next(); + self.prev_tree_it.next().unwrap(); Some(Ok((action, self.dir_it.next().unwrap().unwrap()))) } else if curr_item.name < prev_item.name { @@ -117,15 +119,107 @@ impl Iterator for TreeWalker { #[cfg(test)] mod tests { + use std::fs::{create_dir, remove_file as fs_remove_file, write}; + + use tempfile::tempdir; + + use cas_core::ObjectType; + use crate::Permissions; use super::*; + fn mkdir(root: &Utf8Path, path: &str) -> Result<()> { + let mut full_path = root.to_path_buf(); + full_path.push(path); + create_dir(full_path).map_err(|err| err.into()) + } + + fn write_file(root: &Utf8Path, path: &str, content: &[u8]) -> Result<()> { + let mut full_path = root.to_path_buf(); + full_path.push(path); + write(full_path, content).map_err(|err| err.into()) + } + + fn remove_file(root: &Utf8Path, path: &str) -> Result<()> { + let mut full_path = root.to_path_buf(); + full_path.push(path); + fs_remove_file(full_path).map_err(|err| err.into()) + } + + fn to_tree_items(items: Vec>) -> Vec { + items.into_iter() + .filter(|ref item| item.as_ref().unwrap().0 != Action::Remove) + .map(|item| item.unwrap().1) + .collect() + } + #[test] - fn test_tree_walker() { - for item in TreeWalker::new("/home/draklaw/tmp", vec![]).unwrap() { - match item { - Ok((action, tree_item)) => println!("{:?} {:?}", action, tree_item.name), - Err(err) => println!("error while iterating directory: {}", err), - } - } + fn test_tree_walker() -> Result<()>{ + let root_dir = tempdir()?; + let root = Utf8Path::from_path(root_dir.path()).unwrap(); + + mkdir(root, "test")?; + write_file(root, "test/foobar.txt", b"baz")?; + write_file(root, "readme", b"hello world!")?; + + let items: Vec<_> = TreeWalker::new(root, vec![]).unwrap().collect(); + assert_eq!(items.len(), 2); + let (action, item) = items[0].as_ref().unwrap(); + assert_eq!(action, &Action::Add); + assert_eq!(item.name, "readme"); + assert_eq!(item.otype, ObjectType::new(b"blob").unwrap()); + assert_eq!(item.size, 12); + assert_eq!(item.permissions, Permissions{read: true, write: true, execute: false}); + let (action, item) = items[1].as_ref().unwrap(); + assert_eq!(action, &Action::Add); + assert_eq!(item.name, "test"); + assert_eq!(item.otype, ObjectType::new(b"tree").unwrap()); + assert_eq!(item.size, 0); + assert_eq!(item.permissions, Permissions{read: true, write: true, execute: true}); + + write_file(root, "abc", b"xxxx")?; + + let items: Vec<_> = TreeWalker::new(root, to_tree_items(items)).unwrap().collect(); + assert_eq!(items.len(), 3); + let (action, item) = items[0].as_ref().unwrap(); + assert_eq!(action, &Action::Add); + assert_eq!(item.name, "abc"); + assert_eq!(item.otype, ObjectType::new(b"blob").unwrap()); + assert_eq!(item.size, 4); + assert_eq!(item.permissions, Permissions{read: true, write: true, execute: false}); + let (action, item) = items[1].as_ref().unwrap(); + assert_eq!(action, &Action::Skip); + assert_eq!(item.name, "readme"); + let (action, item) = items[2].as_ref().unwrap(); + assert_eq!(action, &Action::Skip); + assert_eq!(item.name, "test"); + + remove_file(root, "readme")?; + + let items: Vec<_> = TreeWalker::new(root, to_tree_items(items)).unwrap().collect(); + assert_eq!(items.len(), 3); + let (action, item) = items[0].as_ref().unwrap(); + assert_eq!(action, &Action::Skip); + assert_eq!(item.name, "abc"); + let (action, item) = items[1].as_ref().unwrap(); + assert_eq!(action, &Action::Remove); + assert_eq!(item.name, "readme"); + let (action, item) = items[2].as_ref().unwrap(); + assert_eq!(action, &Action::Skip); + assert_eq!(item.name, "test"); + + write_file(root, "abc", b"ab")?; + write_file(root, "test/foobar.txt", b"redacted")?; + + let items: Vec<_> = TreeWalker::new(root, to_tree_items(items)).unwrap().collect(); + assert_eq!(items.len(), 2); + let (action, item) = items[0].as_ref().unwrap(); + assert_eq!(action, &Action::Update); + assert_eq!(item.name, "abc"); + assert_eq!(item.size, 2); + let (action, item) = items[1].as_ref().unwrap(); + assert_eq!(action, &Action::Skip); + assert_eq!(item.name, "test"); + + Ok(()) } }