@@ -335,10 +335,12 @@ fn sha256_for_lines<'a>(lines: impl IntoIterator<Item = &'a str>) -> String {
335335 format ! ( "{:x}" , hasher. finalize( ) )
336336}
337337
338- /// Run with: `cargo test -p uffs-mft -- chaos_order --nocapture --ignored`
338+ /// Run with: `cargo test -p uffs-mft --lib -- chaos_order --nocapture --ignored`
339339#[ test]
340340#[ ignore = "requires offline MFT at /Users/rnio/uffs_data/drive_d/D_mft.bin" ]
341341fn test_chaos_order_d_drive ( ) {
342+ use std:: fs:: File ;
343+ use std:: io:: { BufRead , BufReader } ;
342344 use std:: path:: PathBuf ;
343345
344346 // Initialize logging for diagnostics
@@ -359,129 +361,131 @@ fn test_chaos_order_d_drive() {
359361 println ! ( " (Full-field parity with C++ ground truth)" ) ;
360362 println ! ( "═══════════════════════════════════════════════════════\n " ) ;
361363
362- // Step 1: Export chaos-order results using CLI with --chaos-seed
363- println ! ( "📤 Step 1: Exporting chaos-order results to CSV format via CLI" ) ;
364- println ! ( " (Uses --chaos-seed 42 to randomize chunk processing order)" ) ;
364+ // ──────────────────────────────────────────────────────────────
365+ // Phase 1: Build binary upfront (single compilation)
366+ // ──────────────────────────────────────────────────────────────
367+ println ! ( "🔨 Phase 1: Building uffs CLI (release mode)" ) ;
368+ let build_status = std:: process:: Command :: new ( "cargo" )
369+ . args ( [ "build" , "--release" , "-p" , "uffs-cli" , "--bin" , "uffs" ] )
370+ . status ( )
371+ . expect ( "Failed to build uffs CLI" ) ;
372+ assert ! ( build_status. success( ) , "uffs CLI build failed with status: {}" , build_status) ;
373+
374+ // Get path to built binary
375+ let uffs_bin = std:: env:: current_dir ( )
376+ . expect ( "current dir" )
377+ . join ( "target/release/uffs" ) ;
378+ assert ! ( uffs_bin. exists( ) , "uffs binary not found at: {}" , uffs_bin. display( ) ) ;
379+ println ! ( " ✓ Build complete: {}" , uffs_bin. display( ) ) ;
380+ println ! ( ) ;
381+
382+ // ──────────────────────────────────────────────────────────────
383+ // Phase 2: Run chaos-order export
384+ // ──────────────────────────────────────────────────────────────
385+ println ! ( "📤 Phase 2: Exporting chaos-order results (--chaos-seed 42)" ) ;
365386 let temp_output = std:: env:: temp_dir ( ) . join ( "chaos_d.txt" ) ;
366387
367- let status = std:: process:: Command :: new ( "cargo" )
368- . args ( & [ "run" , "--release" , "-p" , "uffs-cli" , "--bin" , "uffs" , "--" ] )
369- . args ( & [ "*" ] )
370- . args ( & [ "--mft-file" , mft_path. to_str ( ) . expect ( "valid path" ) ] )
371- . args ( & [ "--drive" , "D" ] )
372- . args ( & [ "--chaos-seed" , "42" ] )
373- . args ( & [ "--tz-offset" , "-8" ] )
374- . args ( & [ "--format" , "custom" ] )
375- . args ( & [ "--out" , temp_output. to_str ( ) . expect ( "valid path" ) ] )
388+ let status = std:: process:: Command :: new ( & uffs_bin)
389+ . args ( [ "*" ] )
390+ . args ( [ "--mft-file" , mft_path. to_str ( ) . expect ( "valid path" ) ] )
391+ . args ( [ "--drive" , "D" ] )
392+ . args ( [ "--chaos-seed" , "42" ] )
393+ . args ( [ "--tz-offset" , "-8" ] )
394+ . args ( [ "--format" , "custom" ] )
395+ . args ( [ "--out" , temp_output. to_str ( ) . expect ( "valid path" ) ] )
376396 . status ( )
377397 . expect ( "Failed to run uffs CLI" ) ;
378398
379- assert ! ( status. success( ) , "uffs CLI failed with status: {}" , status) ;
380- println ! ( " ✓ CSV export completed " ) ;
399+ assert ! ( status. success( ) , "uffs CLI (chaos) failed with status: {}" , status) ;
400+ println ! ( " ✓ Chaos export complete " ) ;
381401 println ! ( ) ;
382402
383- // Step 2: Compute sorted SHA256 of chaos output
384- println ! ( "🔐 Step 2: Computing sorted SHA256 of chaos-order output" ) ;
385- use std:: fs:: File ;
386- use std:: io:: { BufRead , BufReader } ;
387-
388- let chaos_lines: Vec < String > = BufReader :: new ( File :: open ( & temp_output) . expect ( "temp file exists" ) )
389- . lines ( )
390- . collect :: < Result < _ , _ > > ( )
391- . expect ( "read lines" ) ;
392-
393- let chaos_sha = sorted_sha256 ( & chaos_lines) ;
394- println ! ( " Chaos SHA256: {}" , chaos_sha) ;
395- println ! ( ) ;
396-
397- // Step 3: Export sequential output for comparison
398- println ! ( "📤 Step 3: Exporting sequential-order output for baseline comparison" ) ;
403+ // ──────────────────────────────────────────────────────────────
404+ // Phase 3: Run sequential-order export
405+ // ──────────────────────────────────────────────────────────────
406+ println ! ( "📤 Phase 3: Exporting sequential-order results (baseline)" ) ;
399407 let sequential_output = std:: env:: temp_dir ( ) . join ( "sequential_d.txt" ) ;
400408
401- let status = std:: process:: Command :: new ( "cargo" )
402- . args ( & [ "run" , "--release" , "-p" , "uffs-cli" , "--bin" , "uffs" , "--" ] )
403- . args ( & [ "*" ] )
404- . args ( & [ "--mft-file" , mft_path. to_str ( ) . expect ( "valid path" ) ] )
405- . args ( & [ "--drive" , "D" ] )
406- . args ( & [ "--tz-offset" , "-8" ] )
407- . args ( & [ "--format" , "custom" ] )
408- . args ( & [ "--out" , sequential_output. to_str ( ) . expect ( "valid path" ) ] )
409+ let status = std:: process:: Command :: new ( & uffs_bin)
410+ . args ( [ "*" ] )
411+ . args ( [ "--mft-file" , mft_path. to_str ( ) . expect ( "valid path" ) ] )
412+ . args ( [ "--drive" , "D" ] )
413+ . args ( [ "--tz-offset" , "-8" ] )
414+ . args ( [ "--format" , "custom" ] )
415+ . args ( [ "--out" , sequential_output. to_str ( ) . expect ( "valid path" ) ] )
409416 . status ( )
410- . expect ( "Failed to run uffs CLI for sequential export " ) ;
417+ . expect ( "Failed to run uffs CLI" ) ;
411418
412- assert ! ( status. success( ) , "Sequential uffs CLI failed with status: {}" , status) ;
413- println ! ( " ✓ Sequential CSV export completed " ) ;
419+ assert ! ( status. success( ) , "uffs CLI (sequential) failed with status: {}" , status) ;
420+ println ! ( " ✓ Sequential export complete " ) ;
414421 println ! ( ) ;
415422
416- // Step 4: Compute SHA256 of sequential output
417- println ! ( "🔐 Step 4: Computing sorted SHA256 of sequential-order output" ) ;
418- let sequential_lines: Vec < String > = BufReader :: new ( File :: open ( & sequential_output) . expect ( "sequential file exists" ) )
423+ // ──────────────────────────────────────────────────────────────
424+ // Phase 4: Read and compute SHA256 hashes
425+ // ──────────────────────────────────────────────────────────────
426+ println ! ( "🔐 Phase 4: Computing sorted SHA256 hashes" ) ;
427+
428+ let chaos_lines: Vec < String > = BufReader :: new ( File :: open ( & temp_output) . expect ( "chaos file" ) )
419429 . lines ( )
420430 . collect :: < Result < _ , _ > > ( )
421- . expect ( "read sequential lines" ) ;
431+ . expect ( "read chaos lines" ) ;
432+ let chaos_sha = sorted_sha256 ( & chaos_lines) ;
433+ println ! ( " Chaos SHA256: {}" , chaos_sha) ;
422434
435+ let sequential_lines: Vec < String > = BufReader :: new ( File :: open ( & sequential_output) . expect ( "sequential file" ) )
436+ . lines ( )
437+ . collect :: < Result < _ , _ > > ( )
438+ . expect ( "read sequential lines" ) ;
423439 let sequential_sha = sorted_sha256 ( & sequential_lines) ;
424440 println ! ( " Sequential SHA256: {}" , sequential_sha) ;
425441 println ! ( ) ;
426442
427- // Step 5: Compare against C++ ground truth (sorted comparison, like verify_parity.rs)
428- println ! ( "✅ Step 5: Validating against C++ ground truth (sorted SHA256)" ) ;
443+ // ──────────────────────────────────────────────────────────────
444+ // Phase 5: Validate against C++ ground truth
445+ // ──────────────────────────────────────────────────────────────
446+ println ! ( "✅ Phase 5: Validating against C++ ground truth" ) ;
429447 const EXPECTED_SORTED_SHA : & str = "028356d4c9298ca8ef790229f4d4270ea29827ad155051e01181181fa34a531e" ;
430- println ! ( " Expected sorted SHA: {}" , EXPECTED_SORTED_SHA ) ;
431- println ! ( " Sequential sorted: {}" , sequential_sha) ;
432- println ! ( " Chaos sorted: {}" , chaos_sha) ;
448+ println ! ( " Expected: {}" , EXPECTED_SORTED_SHA ) ;
449+ println ! ( " Sequential: {}" , sequential_sha) ;
450+ println ! ( " Chaos: {}" , chaos_sha) ;
433451 println ! ( ) ;
434452
435- // Verify sequential matches ground truth (sorted comparison)
436- // Note: Row order may differ (C++ vs Rust MFT/tree walk), but content must match
453+ // Verify sequential matches ground truth
437454 if sequential_sha != EXPECTED_SORTED_SHA {
438455 println ! ( "❌ SEQUENTIAL SHA256 MISMATCH!" ) ;
439- println ! ( ) ;
440- println ! ( " This indicates a critical bug in the base parser or output format." ) ;
441- println ! ( " Line counts:" ) ;
442- println ! ( " Expected: 7,065,330 lines" ) ;
443- println ! ( " Sequential: {} lines" , sequential_lines. len( ) ) ;
444- panic ! ( "Sequential sorted SHA256 mismatch! Expected: {}, Got: {}" , EXPECTED_SORTED_SHA , sequential_sha) ;
456+ println ! ( " Expected lines: 7,065,330" ) ;
457+ println ! ( " Actual lines: {}" , sequential_lines. len( ) ) ;
458+ panic ! ( "Sequential SHA256 mismatch! Expected: {}, Got: {}" , EXPECTED_SORTED_SHA , sequential_sha) ;
445459 }
446460
447- // Verify chaos matches sequential (sorted comparison)
461+ // Verify chaos matches sequential
448462 if chaos_sha != sequential_sha {
449463 println ! ( "❌ CHAOS-ORDER SHA256 MISMATCH!" ) ;
450- println ! ( ) ;
451- println ! ( " This indicates the directory index merge fix is broken for out-of-order processing." ) ;
452- println ! ( " Line counts:" ) ;
453- println ! ( " Sequential: {} lines" , sequential_lines. len( ) ) ;
454- println ! ( " Chaos: {} lines" , chaos_lines. len( ) ) ;
455- println ! ( ) ;
456-
457- // Show first few differences using verify_parity.rs-style diagnostics
458- println ! ( " 📊 Comparing sorted outputs (first 10 differences):" ) ;
459- let mut sequential_sorted = sequential_lines. clone ( ) ;
464+ println ! ( " Sequential: {} lines" , sequential_lines. len( ) ) ;
465+ println ! ( " Chaos: {} lines" , chaos_lines. len( ) ) ;
466+
467+ // Show first differences
468+ let mut seq_sorted = sequential_lines. clone ( ) ;
460469 let mut chaos_sorted = chaos_lines. clone ( ) ;
461- sequential_sorted . sort_unstable ( ) ;
470+ seq_sorted . sort_unstable ( ) ;
462471 chaos_sorted. sort_unstable ( ) ;
463472
464- let n = sequential_sorted . len ( ) . min ( chaos_sorted . len ( ) ) ;
473+ println ! ( " \n First 10 differences:" ) ;
465474 let mut diff_count = 0 ;
466- for i in 0 ..n {
467- if sequential_sorted[ i] != chaos_sorted[ i] && diff_count < 10 {
468- println ! ( " Line {} differs:" , i + 1 ) ;
469- println ! ( " Sequential: {}" , & sequential_sorted[ i] [ ..sequential_sorted[ i] . len( ) . min( 100 ) ] ) ;
470- println ! ( " Chaos: {}" , & chaos_sorted[ i] [ ..chaos_sorted[ i] . len( ) . min( 100 ) ] ) ;
475+ for i in 0 ..seq_sorted. len ( ) . min ( chaos_sorted. len ( ) ) {
476+ if seq_sorted[ i] != chaos_sorted[ i] && diff_count < 10 {
477+ println ! ( " Line {}: SEQ={}" , i + 1 , & seq_sorted[ i] [ ..seq_sorted[ i] . len( ) . min( 80 ) ] ) ;
478+ println ! ( " CHS={}" , & chaos_sorted[ i] [ ..chaos_sorted[ i] . len( ) . min( 80 ) ] ) ;
471479 diff_count += 1 ;
472480 }
473481 }
474-
475- panic ! ( "Chaos-order SHA256 mismatch! Expected: {}, Got: {}" , sequential_sha, chaos_sha) ;
482+ panic ! ( "Chaos SHA256 mismatch!" ) ;
476483 }
477484
478- assert_eq ! ( chaos_sha, EXPECTED_SORTED_SHA ,
479- "Chaos-order SHA256 mismatch! This indicates the directory index merge fix is broken." ) ;
480-
481- println ! ( ) ;
485+ println ! ( "═══════════════════════════════════════════════════════" ) ;
482486 println ! ( "✅ VALIDATION PASSED!" ) ;
483- println ! ( " Chaos-order output matches C++ ground truth exactly (all fields, all records) ." ) ;
484- println ! ( " This proves 100% parity - not just 4 fields! " ) ;
487+ println ! ( " Chaos-order matches C++ ground truth exactly." ) ;
488+ println ! ( "═══════════════════════════════════════════════════════ " ) ;
485489}
486490
487491/// Tests reverse-order parsing (simpler chaos strategy).
0 commit comments