#[cfg(test)] mod test { use crate::*; use futures::future::join5; use std::cmp::{max, min}; use std::fs::{create_dir, read_to_string, remove_file}; #[test] fn test_branch() { let d: TreeBuilder = TreeBuilder::new(); d.add_leaf("1"); { let _l = d.enter_scoped(); d.add_leaf("1.1"); d.add_leaf("1.2"); } d.add_leaf("2"); d.add_leaf("3"); let _l = d.enter_scoped(); d.add_leaf("3.1"); d.add_leaf("3.2"); d.peek_print(); assert_eq!( "\ 1 ├╼ 1.1 └╼ 1.2 2 3 ├╼ 3.1 └╼ 3.2", d.string() ); } #[test] fn test_branch2() { let d = TreeBuilder::new(); d.add_leaf("1"); { let _scope = d.enter_scoped(); d.add_leaf("1.1"); { let _scope = d.enter_scoped(); d.add_leaf("1.1.1"); } } d.add_leaf("2"); d.enter(); d.add_leaf("2.1"); d.enter(); d.add_leaf("2.1.1"); d.peek_print(); assert_eq!( "\ 1 └╼ 1.1 └╼ 1.1.1 2 └╼ 2.1 └╼ 2.1.1", d.string() ); } #[test] fn simple() { let d = TreeBuilder::new(); d.add_leaf("Hi"); assert_eq!("Hi", d.string()); } #[test] fn depth() { let d = TreeBuilder::new(); assert_eq!(0, d.depth()); d.add_leaf("Hi"); assert_eq!(0, d.depth()); let _b = d.add_branch("Hi"); assert_eq!(1, d.depth()); d.add_leaf("Hi"); assert_eq!(1, d.depth()); } #[test] fn indent() { let d = TreeBuilder::new(); d.add_leaf("1"); add_branch_to!(d); d.add_leaf("1.1"); { add_branch_to!(d); d.add_leaf("1.1.1"); } d.set_config_override(TreeConfig::new().indent(4)); d.peek_print(); assert_eq!( "\ 1 └──╼ 1.1 └──╼ 1.1.1", d.string() ); } #[test] fn macros() { let d = TreeBuilder::new(); add_leaf_to!(d, "1"); { add_branch_to!(d); add_leaf_to!(d, "1.1") } d.peek_print(); assert_eq!( "\ 1 └╼ 1.1", d.string() ); } #[test] fn macros_with_fn() { let d = TreeBuilder::new(); let tree = || d.clone(); add_leaf_to!(tree(), "1"); { add_branch_to!(tree()); add_leaf_to!(tree(), "1.1") } tree().peek_print(); assert_eq!( "\ 1 └╼ 1.1", d.string() ); } #[test] fn leaf_with_value() { let d = TreeBuilder::new(); let value = add_leaf_value_to!(d, 1); d.peek_print(); assert_eq!("1", d.string()); assert_eq!(1, value); } #[test] fn macros2() { let d = TreeBuilder::new(); add_branch_to!(d, "1"); add_leaf_to!(d, "1.1"); d.peek_print(); assert_eq!( "\ 1 └╼ 1.1", d.string() ); } #[test] fn mid() { let d = TreeBuilder::new(); d.add_leaf(&format!("{}{}", "1", "0")); d.enter(); d.add_leaf("10.1"); d.add_leaf("10.2"); d.enter(); d.add_leaf("10.1.1"); d.add_leaf("10.1.2\nNext line"); d.exit(); d.add_leaf(&format!("10.3")); d.peek_print(); assert_eq!( "\ 10 ├╼ 10.1 ├╼ 10.2 │ ├╼ 10.1.1 │ └╼ 10.1.2 │ Next line └╼ 10.3", d.string() ); } fn factors(x: usize) { add_branch!("{}", x); for i in 1..x { if x % i == 0 { factors(i); } } } #[test] fn recursive() { factors(6); default_tree().peek_print(); assert_eq!( "\ 6 ├╼ 1 ├╼ 2 │ └╼ 1 └╼ 3 └╼ 1", default_tree().string() ); } fn a() { add_branch!("a"); b(); c(); } fn b() { add_branch!("b"); c(); } fn c() { add_branch!("c"); add_leaf!("Nothing to see here"); } #[test] fn nested() { a(); default_tree().peek_print(); assert_eq!( "\ a ├╼ b │ └╼ c │ └╼ Nothing to see here └╼ c └╼ Nothing to see here", default_tree().string() ); } #[test] fn disabled_output() { let tree = TreeBuilder::new(); tree.set_enabled(false); add_leaf_to!(tree, "Leaf"); tree.add_leaf("Leaf"); add_branch_to!(tree, "Branch"); tree.add_branch("Branch"); assert_eq!("", tree.string()); } #[test] fn enabled_output() { let tree = TreeBuilder::new(); tree.set_enabled(false); add_branch_to!(tree, "Ignored branch"); add_leaf_to!(tree, "Ignored leaf"); tree.set_enabled(true); add_leaf_to!(tree, "Leaf"); tree.add_leaf("Leaf"); add_branch_to!(tree, "Branch"); tree.add_branch("Branch"); assert_eq!( "Leaf Leaf Branch └╼ Branch", tree.string() ); } #[test] fn tree_by_name() { clear("A"); let b = tree("B"); b.clear(); { add_branch_to!("A", "1"); add_branch_to!(b, "3"); add_leaf_to!("A", "1.1"); add_leaf_to!("B", "3.1"); } add_leaf_to!("A", "2"); peek_print("A"); b.peek_print(); assert_eq!( "1 └╼ 1.1 2", string("A") ); assert_eq!( "3 └╼ 3.1", b.string() ); } #[test] fn tree_by_name_disabled() { let d = tree("D"); d.clear(); d.set_enabled(true); clear("C"); set_enabled("C", false); { add_branch_to!("C", "1"); set_enabled("C", true); add_branch_to!(d, "3"); add_leaf_to!("C", "1.1"); d.set_enabled(false); add_leaf_to!("D", "3.1"); } add_leaf_to!("C", "2"); peek_print("C"); d.peek_print(); assert_eq!( "1.1 2", string("C") ); assert_eq!("3", d.string()); } #[test] fn defer_write() { let tree = TreeBuilder::new(); { create_dir("test_out").ok(); remove_file("test_out/defer_write.txt").ok(); File::create("test_out/defer_write.txt").unwrap(); defer_write!(tree, "test_out/defer_write.txt"); tree.add_leaf("Branch"); assert_eq!(read_to_string("test_out/defer_write.txt").unwrap(), ""); assert_eq!(tree.peek_string(), "Branch"); } assert_eq!(tree.peek_string(), ""); assert_eq!( read_to_string("test_out/defer_write.txt").unwrap(), "Branch" ); } #[test] fn defer_peek_write() { let tree = TreeBuilder::new(); { create_dir("test_out").ok(); remove_file("test_out/defer_peek_write.txt").ok(); File::create("test_out/defer_peek_write.txt").unwrap(); defer_peek_write!(tree, "test_out/defer_peek_write.txt"); tree.add_leaf("Branch"); assert_eq!(read_to_string("test_out/defer_peek_write.txt").unwrap(), ""); assert_eq!(tree.peek_string(), "Branch"); } assert_eq!(tree.peek_string(), "Branch"); assert_eq!( read_to_string("test_out/defer_peek_write.txt").unwrap(), "Branch" ); } #[test] #[should_panic] #[allow(unreachable_code)] fn defer_peek_write_panic() { let tree = TreeBuilder::new(); { create_dir("test_out").ok(); remove_file("test_out/defer_peek_write_panic.txt").ok(); File::create("test_out/defer_peek_write_panic.txt").unwrap(); defer_peek_write!(tree, "test_out/defer_peek_write_panic.txt"); tree.add_leaf("This should be the only line in this file"); assert_eq!(read_to_string("test_out/defer_peek_write.txt").unwrap(), ""); assert_eq!( tree.peek_string(), "This should be the only line in this file" ); panic!(); tree.add_leaf("This line should not exist"); } } fn example_tree() -> TreeBuilder { let tree = TreeBuilder::new(); { add_branch_to!(tree, "1"); { add_branch_to!(tree, "1.1"); add_leaf_to!(tree, "1.1.1"); add_leaf_to!(tree, "1.1.2\nWith two\nextra lines"); add_leaf_to!(tree, "1.1.3"); } add_branch_to!(tree, "1.2"); add_leaf_to!(tree, "1.2.1"); } { add_branch_to!(tree, "2"); add_leaf_to!(tree, "2.1"); add_leaf_to!(tree, "2.2"); } add_leaf_to!(tree, "3"); tree } #[test] fn format_output() { let tree = example_tree(); tree.set_config_override( TreeConfig::new() .indent(8) .symbols(TreeSymbols { continued: "| |", join_first: "|A|", join_last: "|Z|", join_inner: "|N|", join_only: "|O|", branch: "123456[NOT SHOWN]", leaf: ")}>", multiline_first: Some(")}MULTI>"), multiline_continued: Some(".. CONTINUED: "), }) .show_first_level(), ); tree.peek_print(); assert_eq!( tree.string(), "\ |A|123456)}>1 | | |A|123456)}>1.1 | | | | |A|123456)}>1.1.1 | | | | |N|123456)}MULTI>1.1.2 | | | | | | .. CONTINUED: With two | | | | | | .. CONTINUED: extra lines | | | | |Z|123456)}>1.1.3 | | |Z|123456)}>1.2 | | |O|123456)}>1.2.1 |N|123456)}>2 | | |A|123456)}>2.1 | | |Z|123456)}>2.2 |Z|123456)}>3" ); } #[test] fn format_output_thick() { let tree = example_tree(); tree.set_config_override( TreeConfig::new() .symbols(TreeSymbols::with_thick()) .indent(4) .show_first_level(), ); tree.peek_print(); assert_eq!( tree.string(), "\ ┣━━╼ 1 ┃ ┣━━╼ 1.1 ┃ ┃ ┣━━╼ 1.1.1 ┃ ┃ ┣━━╼ 1.1.2 ┃ ┃ ┃ With two ┃ ┃ ┃ extra lines ┃ ┃ ┗━━╼ 1.1.3 ┃ ┗━━╼ 1.2 ┃ ┗━━╼ 1.2.1 ┣━━╼ 2 ┃ ┣━━╼ 2.1 ┃ ┗━━╼ 2.2 ┗━━╼ 3" ); } #[test] fn format_output_pipes() { let tree = example_tree(); tree.set_config_override( TreeConfig::new() .symbols(TreeSymbols::with_pipes()) .indent(3) .show_first_level(), ); tree.peek_print(); assert_eq!( tree.string(), "\ ╠═╼ 1 ║ ╠═╼ 1.1 ║ ║ ╠═╼ 1.1.1 ║ ║ ╠═╼ 1.1.2 ║ ║ ║ With two ║ ║ ║ extra lines ║ ║ ╚═╼ 1.1.3 ║ ╚═╼ 1.2 ║ ╚═╼ 1.2.1 ╠═╼ 2 ║ ╠═╼ 2.1 ║ ╚═╼ 2.2 ╚═╼ 3" ); } #[test] fn format_output_dashed() { let tree = example_tree(); tree.set_config_override( TreeConfig::new() .symbols(TreeSymbols::with_dashed().multiline_continued(" > ")) .indent(4) .show_first_level(), ); tree.peek_print(); assert_eq!( tree.string(), "\ ┊╌╌- 1 ┊ ┊╌╌- 1.1 ┊ ┊ ┊╌╌- 1.1.1 ┊ ┊ ┊╌╌- 1.1.2 ┊ ┊ ┊ > With two ┊ ┊ ┊ > extra lines ┊ ┊ '╌╌- 1.1.3 ┊ '╌╌- 1.2 ┊ '╌╌- 1.2.1 ┊╌╌- 2 ┊ ┊╌╌- 2.1 ┊ '╌╌- 2.2 '╌╌- 3" ); } #[test] fn format_output_rounded() { let tree = example_tree(); tree.set_config_override( TreeConfig::new() .symbols(TreeSymbols::with_rounded()) .indent(4), ); tree.peek_print(); assert_eq!( tree.string(), "\ 1 ├──╼ 1.1 │ ├──╼ 1.1.1 │ ├──╼ 1.1.2 │ │ With two │ │ extra lines │ ╰──╼ 1.1.3 ╰──╼ 1.2 ╰──╼ 1.2.1 2 ├──╼ 2.1 ╰──╼ 2.2 3" ); } async fn wait_a_bit(tree: TreeBuilder, index: usize) { tree.print(); add_branch_to!(tree, "inside async branch {}", index); tree.print(); add_leaf_to!(tree, "inside async leaf {}", index); tree.print(); } #[tokio::test] async fn async_barrier() { let tree = TreeBuilder::new(); defer_peek_print!(tree); add_branch_to!(tree, "root"); add_leaf_to!(tree, "before async"); let x2 = wait_a_bit(tree.clone(), 4); let x1 = wait_a_bit(tree.clone(), 5); let x3 = wait_a_bit(tree.clone(), 3); let x4 = wait_a_bit(tree.clone(), 2); let x5 = wait_a_bit(tree.clone(), 1); add_leaf_to!(tree, "before join async"); join5(x1, x2, x3, x4, x5).await; add_leaf_to!(tree, "after join async"); assert_eq!(tree.peek_string(), "after join async"); } }