Skip to content

Commit dc78b61

Browse files
committed
fix: remove duplicate chaos test, build binary upfront
- Remove duplicate test module import in io.rs (was causing double output) - Refactor test to build uffs binary once upfront before running exports - Clean up test output with clear phase markers
1 parent f594d7b commit dc78b61

File tree

2 files changed

+89
-90
lines changed

2 files changed

+89
-90
lines changed

crates/uffs-mft/src/io.rs

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -35,11 +35,6 @@ mod parser;
3535
// readers module available on all platforms (contains ChaosMftReader for offline MFT)
3636
pub mod readers;
3737

38-
// Chaos test harness - works with offline MFT files on any platform
39-
#[cfg(test)]
40-
#[path = "io/readers/parallel/tests_chaos.rs"]
41-
mod tests_chaos;
42-
4338
pub use aligned_buffer::AlignedBuffer;
4439
pub use chunking::{ReadChunk, generate_precise_read_chunks, generate_read_chunks};
4540
pub use extent_map::MftExtentMap;

crates/uffs-mft/src/io/readers/parallel/tests_chaos.rs

Lines changed: 89 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -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"]
341341
fn 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

Comments
 (0)