11//! Access common paths and manipulate the filesystem
22
33use filetime:: FileTime ;
4+ use itertools:: Itertools ;
5+ use walkdir:: WalkDir ;
46
57use std:: cell:: RefCell ;
68use std:: env;
@@ -12,6 +14,9 @@ use std::sync::Mutex;
1214use std:: sync:: OnceLock ;
1315use std:: sync:: atomic:: { AtomicUsize , Ordering } ;
1416
17+ use crate :: compare:: assert_e2e;
18+ use crate :: compare:: match_contains;
19+
1520static CARGO_INTEGRATION_TEST_DIR : & str = "cit" ;
1621
1722static GLOBAL_ROOT : OnceLock < Mutex < Option < PathBuf > > > = OnceLock :: new ( ) ;
@@ -152,6 +157,10 @@ pub trait CargoPathExt {
152157 fn move_in_time < F > ( & self , travel_amount : F )
153158 where
154159 F : Fn ( i64 , u32 ) -> ( i64 , u32 ) ;
160+
161+ fn assert_build_dir_layout ( & self , expected : impl snapbox:: IntoData ) ;
162+
163+ fn assert_dir_layout ( & self , expected : impl snapbox:: IntoData , ignored_path_patterns : & [ String ] ) ;
155164}
156165
157166impl CargoPathExt for Path {
@@ -236,6 +245,43 @@ impl CargoPathExt for Path {
236245 } ) ;
237246 }
238247 }
248+
249+ #[ track_caller]
250+ fn assert_build_dir_layout ( & self , expected : impl snapbox:: IntoData ) {
251+ // We call `unordered()` here to because the build-dir has some scenarios that make
252+ // consistent ordering not possible.
253+ // Notably:
254+ // 1. Binaries with `.exe` on Windows causing the ordering to change with the dep-info `.d`
255+ // file.
256+ // 2. Directories with hashes are often reordered differently by platform.
257+ self . assert_dir_layout ( expected. unordered ( ) , & build_dir_ignored_path_patterns ( ) ) ;
258+ }
259+
260+ #[ track_caller]
261+ fn assert_dir_layout (
262+ & self ,
263+ expected : impl snapbox:: IntoData ,
264+ ignored_path_patterns : & [ String ] ,
265+ ) {
266+ let assert = assert_e2e ( ) ;
267+ let actual = WalkDir :: new ( self )
268+ . sort_by_file_name ( )
269+ . into_iter ( )
270+ . filter_map ( |e| e. ok ( ) )
271+ . filter ( |e| e. file_type ( ) . is_file ( ) )
272+ . map ( |e| e. path ( ) . to_string_lossy ( ) . into_owned ( ) )
273+ . filter ( |file| {
274+ for ignored in ignored_path_patterns {
275+ if match_contains ( & ignored, file, & assert. redactions ( ) ) . is_ok ( ) {
276+ return false ;
277+ }
278+ }
279+ return true ;
280+ } )
281+ . join ( "\n " ) ;
282+
283+ assert. eq ( format ! ( "{actual}\n " ) , expected) ;
284+ }
239285}
240286
241287impl CargoPathExt for PathBuf {
@@ -260,6 +306,21 @@ impl CargoPathExt for PathBuf {
260306 {
261307 self . as_path ( ) . move_in_time ( travel_amount)
262308 }
309+
310+ #[ track_caller]
311+ fn assert_build_dir_layout ( & self , expected : impl snapbox:: IntoData ) {
312+ self . as_path ( ) . assert_build_dir_layout ( expected) ;
313+ }
314+
315+ #[ track_caller]
316+ fn assert_dir_layout (
317+ & self ,
318+ expected : impl snapbox:: IntoData ,
319+ ignored_path_patterns : & [ String ] ,
320+ ) {
321+ self . as_path ( )
322+ . assert_dir_layout ( expected, ignored_path_patterns) ;
323+ }
263324}
264325
265326fn do_op < F > ( path : & Path , desc : & str , mut f : F )
@@ -290,6 +351,20 @@ where
290351 }
291352}
292353
354+ /// The paths to ignore when [`CargoPathExt::assert_build_dir_layout`] is called
355+ fn build_dir_ignored_path_patterns ( ) -> Vec < String > {
356+ vec ! [
357+ // Ignore MacOS debug symbols as there are many files/directories that would clutter up
358+ // tests few not a lot of benefit.
359+ "[..].dSYM/[..]" ,
360+ // Ignore Windows debub symbols files (.pdb)
361+ "[..].pdb" ,
362+ ]
363+ . into_iter ( )
364+ . map ( ToString :: to_string)
365+ . collect ( )
366+ }
367+
293368/// Get the filename for a library.
294369///
295370/// `kind` should be one of:
0 commit comments