1- //! Tests for the `--one-file-system` / `-x` flag.
1+ //! Tests for the `--one-file-system` flag.
22//!
33//! ## Unit-style test
44//!
88//! ## Integration test via FUSE
99//!
1010//! [`cross_device_excludes_mount`] uses `squashfuse` to mount a squashfs image via FUSE
11- //! (no root or user namespaces required) and checks that `-x ` correctly excludes entries on
12- //! the mounted filesystem.
11+ //! (no root or user namespaces required) and checks that `--one-file-system ` correctly
12+ //! excludes entries on the mounted filesystem.
1313//!
1414//! The FUSE test panics when `mksquashfs`, `squashfuse`, `/dev/fuse`, or `fusermount` are
1515//! unavailable. It can be excluded via `RUSTFLAGS='--cfg pdu_test_skip_cross_device'`.
@@ -22,13 +22,15 @@ pub use _utils::*;
2222
2323use command_extra:: CommandExtra ;
2424use parallel_disk_usage:: {
25+ bytes_format:: BytesFormat ,
2526 data_tree:: DataTree ,
2627 fs_tree_builder:: FsTreeBuilder ,
2728 get_size:: GetApparentSize ,
2829 hardlink:: HardlinkIgnorant ,
2930 os_string_display:: OsStringDisplay ,
3031 reporter:: { ErrorOnlyReporter , ErrorReport } ,
3132 size:: Bytes ,
33+ visualizer:: { BarAlignment , ColumnWidthDistribution , Direction , Visualizer } ,
3234} ;
3335use pipe_trait:: Pipe ;
3436use pretty_assertions:: assert_eq;
@@ -139,7 +141,8 @@ impl Drop for FuseMount {
139141 }
140142}
141143
142- /// When a subdirectory is a mount point for a different filesystem, `-x` should exclude it.
144+ /// When a subdirectory is a mount point for a different filesystem,
145+ /// `--one-file-system` should exclude it.
143146///
144147/// Uses `squashfuse` to mount a squashfs image via FUSE — no root privileges or
145148/// user namespaces required. The image is pre-built with `mksquashfs` containing the
@@ -162,7 +165,6 @@ fn cross_device_excludes_mount() {
162165 )
163166 } ) ;
164167
165- let pdu = env ! ( "CARGO_BIN_EXE_pdu" ) ;
166168 let temp = Temp :: new_dir ( ) . expect ( "create temp dir for cross-device test" ) ;
167169 let workspace = temp. join ( "workspace" ) ;
168170 let mount_point = workspace. join ( "mounted" ) ;
@@ -232,58 +234,59 @@ fn cross_device_excludes_mount() {
232234 wait_ms *= 2 ;
233235 }
234236
235- // Run pdu WITHOUT -x — should see both files
236- let without_x = Command :: new ( pdu)
237- . with_arg ( "--bytes-format=plain" )
238- . with_arg ( & workspace)
239- . with_stdout ( Stdio :: piped ( ) )
240- . with_stderr ( Stdio :: piped ( ) )
241- . output ( )
242- . expect ( "run pdu without -x" ) ;
243- let without_x_stdout = String :: from_utf8_lossy ( & without_x. stdout ) ;
244- let without_x_stderr = String :: from_utf8_lossy ( & without_x. stderr ) ;
245- if !without_x_stderr. is_empty ( ) {
246- eprintln ! ( "pdu (no -x) STDERR:\n {without_x_stderr}" ) ;
247- }
248- eprintln ! ( "pdu (no -x) STDOUT:\n {without_x_stdout}" ) ;
249- assert ! (
250- without_x. status. success( ) ,
251- "pdu without -x failed: {without_x_stderr}" ,
252- ) ;
253- assert ! (
254- without_x_stdout. contains( "inside.txt" ) ,
255- "without -x should show inside.txt:\n {without_x_stdout}" ,
256- ) ;
257- assert ! (
258- without_x_stdout. contains( "outside.txt" ) ,
259- "without -x should show outside.txt:\n {without_x_stdout}" ,
260- ) ;
237+ let build_expected_tree = |one_file_system : bool | -> String {
238+ let builder = FsTreeBuilder {
239+ root : workspace. clone ( ) ,
240+ size_getter : GetApparentSize ,
241+ hardlinks_recorder : & HardlinkIgnorant ,
242+ reporter : & ErrorOnlyReporter :: new ( ErrorReport :: SILENT ) ,
243+ one_file_system,
244+ max_depth : 10 ,
245+ } ;
246+ let mut data_tree: DataTree < OsStringDisplay , Bytes > = builder. into ( ) ;
247+ data_tree. par_cull_insignificant_data ( 0.01 ) ;
248+ data_tree. par_sort_by ( |left, right| left. size ( ) . cmp ( & right. size ( ) ) . reverse ( ) ) ;
249+ * data_tree. name_mut ( ) = OsStringDisplay :: os_string_from ( "." ) ;
250+ let visualizer = Visualizer :: < OsStringDisplay , _ > {
251+ data_tree : & data_tree,
252+ bytes_format : BytesFormat :: PlainNumber ,
253+ direction : Direction :: BottomUp ,
254+ bar_alignment : BarAlignment :: Left ,
255+ column_width_distribution : ColumnWidthDistribution :: total ( 100 ) ,
256+ } ;
257+ let expected = format ! ( "{visualizer}" ) ;
258+ expected. trim_end ( ) . to_string ( )
259+ } ;
261260
262- // Run pdu WITH -x — should only see outside.txt
263- let with_x = Command :: new ( pdu)
264- . with_arg ( "--bytes-format=plain" )
265- . with_arg ( "-x" )
266- . with_arg ( & workspace)
267- . with_stdout ( Stdio :: piped ( ) )
268- . with_stderr ( Stdio :: piped ( ) )
269- . output ( )
270- . expect ( "run pdu with -x" ) ;
271- let with_x_stdout = String :: from_utf8_lossy ( & with_x. stdout ) ;
272- let with_x_stderr = String :: from_utf8_lossy ( & with_x. stderr ) ;
273- if !with_x_stderr. is_empty ( ) {
274- eprintln ! ( "pdu (-x) STDERR:\n {with_x_stderr}" ) ;
275- }
276- eprintln ! ( "pdu (-x) STDOUT:\n {with_x_stdout}" ) ;
277- assert ! (
278- with_x. status. success( ) ,
279- "pdu with -x failed: {with_x_stderr}" ,
280- ) ;
281- assert ! (
282- with_x_stdout. contains( "outside.txt" ) ,
283- "with -x should show outside.txt:\n {with_x_stdout}" ,
284- ) ;
285- assert ! (
286- !with_x_stdout. contains( "inside.txt" ) ,
287- "with -x should exclude inside.txt (on different filesystem):\n {with_x_stdout}" ,
288- ) ;
261+ let run_pdu = |one_file_system : bool | -> String {
262+ let command = Command :: new ( PDU )
263+ . with_arg ( "--quantity=apparent-size" )
264+ . with_arg ( "--total-width=100" )
265+ . with_arg ( "--bytes-format=plain" )
266+ . with_stdin ( Stdio :: null ( ) )
267+ . with_stdout ( Stdio :: piped ( ) )
268+ . with_stderr ( Stdio :: piped ( ) ) ;
269+ let command = if one_file_system {
270+ command. with_arg ( "--one-file-system" )
271+ } else {
272+ command
273+ } ;
274+ command
275+ . with_arg ( & workspace)
276+ . output ( )
277+ . expect ( "run pdu" )
278+ . pipe ( stdout_text)
279+ } ;
280+
281+ // Run pdu WITHOUT --one-file-system — should see both files
282+ let actual = run_pdu ( false ) ;
283+ let expected = build_expected_tree ( false ) ;
284+ eprintln ! ( "WITHOUT --one-file-system:\n ACTUAL:\n {actual}\n \n EXPECTED:\n {expected}\n " ) ;
285+ assert_eq ! ( actual, expected) ;
286+
287+ // Run pdu WITH --one-file-system — should only see outside.txt
288+ let actual = run_pdu ( true ) ;
289+ let expected = build_expected_tree ( true ) ;
290+ eprintln ! ( "WITH --one-file-system:\n ACTUAL:\n {actual}\n \n EXPECTED:\n {expected}\n " ) ;
291+ assert_eq ! ( actual, expected) ;
289292}
0 commit comments