@@ -58,6 +58,84 @@ fn sample_tree() -> SampleTree {
5858 . into_par_sorted ( |left, right| left. size ( ) . cmp ( & right. size ( ) ) . reverse ( ) )
5959}
6060
61+ /// Sample tree whose entries are deliberately stored in ascending order of size,
62+ /// which is the opposite of the descending order produced by the default sorting.
63+ fn ascending_sample_tree ( ) -> SampleTree {
64+ let file =
65+ |name : & ' static str , size : u64 | SampleTree :: file ( name. to_string ( ) , Bytes :: from ( size) ) ;
66+ SampleTree :: dir (
67+ "root" . to_string ( ) ,
68+ 1024 . into ( ) ,
69+ vec ! [ file( "a" , 50 ) , file( "b" , 500 ) , file( "c" , 5000 ) ] ,
70+ )
71+ }
72+
73+ /// Apply the same post-deserialization pipeline that `--json-input` performs,
74+ /// so that the expected visualization can be derived directly from a tree.
75+ fn apply_pipeline ( tree : SampleTree , max_depth : u64 , min_ratio : f32 , no_sort : bool ) -> SampleTree {
76+ let mut tree = tree. into_par_retained ( |_, depth| depth + 1 < max_depth) ;
77+ if min_ratio > 0.0 {
78+ tree. par_cull_insignificant_data ( min_ratio) ;
79+ }
80+ if !no_sort {
81+ tree. par_sort_by ( |left, right| left. size ( ) . cmp ( & right. size ( ) ) . reverse ( ) ) ;
82+ }
83+ tree
84+ }
85+
86+ /// Render a tree the same way the `--json-input` code path does.
87+ fn visualize ( tree : & SampleTree ) -> String {
88+ let visualizer = Visualizer {
89+ data_tree : tree,
90+ bytes_format : BytesFormat :: MetricUnits ,
91+ direction : Direction :: BottomUp ,
92+ bar_alignment : BarAlignment :: Left ,
93+ column_width_distribution : ColumnWidthDistribution :: total ( 100 ) ,
94+ } ;
95+ format ! ( "{visualizer}" ) . trim_end ( ) . to_string ( )
96+ }
97+
98+ /// Feed a tree to `pdu --json-input` and return its trimmed stdout.
99+ fn run_json_input ( tree : SampleTree , extra_args : & [ & str ] ) -> String {
100+ let json_tree = JsonTree {
101+ tree : tree. into_reflection ( ) ,
102+ shared : Default :: default ( ) ,
103+ } ;
104+ let json_data = JsonData {
105+ schema_version : SchemaVersion ,
106+ binary_version : None ,
107+ body : json_tree. into ( ) ,
108+ } ;
109+ let json = serde_json:: to_string_pretty ( & json_data) . expect ( "convert sample tree to JSON" ) ;
110+ let workspace = Temp :: new_dir ( ) . expect ( "create temporary directory" ) ;
111+ let mut command = Command :: new ( PDU )
112+ . with_current_dir ( & workspace)
113+ . with_arg ( "--json-input" )
114+ . with_arg ( "--bytes-format=metric" )
115+ . with_arg ( "--total-width=100" ) ;
116+ for arg in extra_args {
117+ command = command. with_arg ( * arg) ;
118+ }
119+ let mut child = command
120+ . with_stdin ( Stdio :: piped ( ) )
121+ . with_stdout ( Stdio :: piped ( ) )
122+ . with_stderr ( Stdio :: piped ( ) )
123+ . spawn ( )
124+ . expect ( "spawn command" ) ;
125+ child
126+ . stdin
127+ . as_mut ( )
128+ . expect ( "get stdin of child process" )
129+ . write_all ( json. as_bytes ( ) )
130+ . expect ( "write JSON string to child process's stdin" ) ;
131+ child
132+ . wait_with_output ( )
133+ . expect ( "wait for output of child process" )
134+ . pipe ( stdout_text)
135+ . trim_end ( )
136+ . to_string ( )
137+ }
138+
61139#[ test]
62140fn json_output ( ) {
63141 let workspace = SampleWorkspace :: default ( ) ;
@@ -119,6 +197,7 @@ fn json_input() {
119197 . with_arg ( "--bytes-format=metric" )
120198 . with_arg ( "--total-width=100" )
121199 . with_arg ( "--max-depth=10" )
200+ . with_arg ( "--min-ratio=0" )
122201 . with_stdin ( Stdio :: piped ( ) )
123202 . with_stdout ( Stdio :: piped ( ) )
124203 . with_stderr ( Stdio :: piped ( ) )
@@ -151,6 +230,39 @@ fn json_input() {
151230 assert_eq ! ( actual, expected) ;
152231}
153232
233+ #[ test]
234+ fn json_input_max_depth ( ) {
235+ let actual = run_json_input ( sample_tree ( ) , & [ "--max-depth=2" , "--min-ratio=0" ] ) ;
236+ let expected = visualize ( & apply_pipeline ( sample_tree ( ) , 2 , 0.0 , false ) ) ;
237+ assert_eq ! ( actual, expected) ;
238+
239+ // The truncation must actually drop the deeper levels of the tree.
240+ let untruncated = visualize ( & apply_pipeline ( sample_tree ( ) , u64:: MAX , 0.0 , false ) ) ;
241+ assert_ne ! ( expected, untruncated) ;
242+ }
243+
244+ #[ test]
245+ fn json_input_min_ratio ( ) {
246+ let actual = run_json_input ( sample_tree ( ) , & [ "--max-depth=10" , "--min-ratio=0.1" ] ) ;
247+ let expected = visualize ( & apply_pipeline ( sample_tree ( ) , 10 , 0.1 , false ) ) ;
248+ assert_eq ! ( actual, expected) ;
249+
250+ // The culling must actually drop the insignificant entries.
251+ let unculled = visualize ( & apply_pipeline ( sample_tree ( ) , 10 , 0.0 , false ) ) ;
252+ assert_ne ! ( expected, unculled) ;
253+ }
254+
255+ #[ test]
256+ fn json_input_no_sort ( ) {
257+ let actual = run_json_input ( ascending_sample_tree ( ) , & [ "--no-sort" , "--min-ratio=0" ] ) ;
258+ let expected = visualize ( & apply_pipeline ( ascending_sample_tree ( ) , 10 , 0.0 , true ) ) ;
259+ assert_eq ! ( actual, expected) ;
260+
261+ // Without `--no-sort` the entries are reordered, proving the flag is honored.
262+ let sorted = run_json_input ( ascending_sample_tree ( ) , & [ "--min-ratio=0" ] ) ;
263+ assert_ne ! ( actual, sorted) ;
264+ }
265+
154266#[ test]
155267fn json_output_json_input ( ) {
156268 let workspace = SampleWorkspace :: default ( ) ;
0 commit comments