//! Integration tests for [`wifi_densepose_train::proof`]. //! //! The proof module verifies checkpoint directories and (in the full //! implementation) runs a short deterministic training proof. All tests here //! use temporary directories and fixed inputs — no `rand`, no OS entropy. //! //! Tests that depend on functions not yet implemented (`run_proof`, //! `generate_expected_hash`) are marked `#[ignore]` so they compile and //! document the expected API without failing CI until the implementation lands. //! //! This entire module is gated behind `tch-backend` because the `proof` //! module is only compiled when that feature is enabled. #[cfg(feature = "tch-backend")] mod tch_proof_tests { use tempfile::TempDir; use wifi_densepose_train::proof; // --------------------------------------------------------------------------- // verify_checkpoint_dir // --------------------------------------------------------------------------- /// `verify_checkpoint_dir` must return `true` for an existing directory. #[test] fn verify_checkpoint_dir_returns_true_for_existing_dir() { let tmp = TempDir::new().expect("TempDir must be created"); let result = proof::verify_checkpoint_dir(tmp.path()); assert!( result, "verify_checkpoint_dir must return true for an existing directory: {:?}", tmp.path() ); } /// `verify_checkpoint_dir` must return `false` for a non-existent path. #[test] fn verify_checkpoint_dir_returns_false_for_nonexistent_path() { let nonexistent = std::path::Path::new( "/tmp/wifi_densepose_proof_test_no_such_dir_at_all", ); assert!( !nonexistent.exists(), "test precondition: path must not exist before test" ); let result = proof::verify_checkpoint_dir(nonexistent); assert!( !result, "verify_checkpoint_dir must return false for a non-existent path" ); } /// `verify_checkpoint_dir` must return `false` for a path pointing to a file /// (not a directory). #[test] fn verify_checkpoint_dir_returns_false_for_file() { let tmp = TempDir::new().expect("TempDir must be created"); let file_path = tmp.path().join("not_a_dir.txt"); std::fs::write(&file_path, b"test file content").expect("file must be writable"); let result = proof::verify_checkpoint_dir(&file_path); assert!( !result, "verify_checkpoint_dir must return false for a file, got true for {:?}", file_path ); } /// `verify_checkpoint_dir` called twice on the same directory must return the /// same result (deterministic, no side effects). #[test] fn verify_checkpoint_dir_is_idempotent() { let tmp = TempDir::new().expect("TempDir must be created"); let first = proof::verify_checkpoint_dir(tmp.path()); let second = proof::verify_checkpoint_dir(tmp.path()); assert_eq!( first, second, "verify_checkpoint_dir must return the same result on repeated calls" ); } /// A newly created sub-directory inside the temp root must also return `true`. #[test] fn verify_checkpoint_dir_works_for_nested_directory() { let tmp = TempDir::new().expect("TempDir must be created"); let nested = tmp.path().join("checkpoints").join("epoch_01"); std::fs::create_dir_all(&nested).expect("nested dir must be created"); let result = proof::verify_checkpoint_dir(&nested); assert!( result, "verify_checkpoint_dir must return true for a valid nested directory: {:?}", nested ); } // --------------------------------------------------------------------------- // Future API: run_proof // --------------------------------------------------------------------------- // The tests below document the intended proof API and will be un-ignored once // `wifi_densepose_train::proof::run_proof` is implemented. /// Proof must run without panicking and report that loss decreased. /// /// This test is `#[ignore]`d until `run_proof` is implemented. #[test] #[ignore = "run_proof not yet implemented — remove #[ignore] when the function lands"] fn proof_runs_without_panic() { // When implemented, proof::run_proof(dir) should return a struct whose // `loss_decreased` field is true, demonstrating that the training proof // converges on the synthetic dataset. // // Expected signature: // pub fn run_proof(dir: &Path) -> anyhow::Result // // Where ProofResult has: // .loss_decreased: bool // .initial_loss: f32 // .final_loss: f32 // .steps_completed: usize // .model_hash: String // .hash_matches: Option let _tmp = TempDir::new().expect("TempDir must be created"); // Uncomment when run_proof is available: // let result = proof::run_proof(_tmp.path()).unwrap(); // assert!(result.loss_decreased, // "proof must show loss decreased: initial={}, final={}", // result.initial_loss, result.final_loss); } /// Two proof runs with the same parameters must produce identical results. /// /// This test is `#[ignore]`d until `run_proof` is implemented. #[test] #[ignore = "run_proof not yet implemented — remove #[ignore] when the function lands"] fn proof_is_deterministic() { // When implemented, two independent calls to proof::run_proof must: // - produce the same model_hash // - produce the same final_loss (bit-identical or within 1e-6) let _tmp1 = TempDir::new().expect("TempDir 1 must be created"); let _tmp2 = TempDir::new().expect("TempDir 2 must be created"); // Uncomment when run_proof is available: // let r1 = proof::run_proof(_tmp1.path()).unwrap(); // let r2 = proof::run_proof(_tmp2.path()).unwrap(); // assert_eq!(r1.model_hash, r2.model_hash, "model hashes must match"); // assert_eq!(r1.final_loss, r2.final_loss, "final losses must match"); } /// Hash generation and verification must roundtrip. /// /// This test is `#[ignore]`d until `generate_expected_hash` is implemented. #[test] #[ignore = "generate_expected_hash not yet implemented — remove #[ignore] when the function lands"] fn hash_generation_and_verification_roundtrip() { // When implemented: // 1. generate_expected_hash(dir) stores a reference hash file in dir // 2. run_proof(dir) loads the reference file and sets hash_matches = Some(true) // when the model hash matches let _tmp = TempDir::new().expect("TempDir must be created"); // Uncomment when both functions are available: // let hash = proof::generate_expected_hash(_tmp.path()).unwrap(); // let result = proof::run_proof(_tmp.path()).unwrap(); // assert_eq!(result.hash_matches, Some(true)); // assert_eq!(result.model_hash, hash); } // --------------------------------------------------------------------------- // Filesystem helpers (deterministic, no randomness) // --------------------------------------------------------------------------- /// Creating and verifying a checkpoint directory within a temp tree must /// succeed without errors. #[test] fn checkpoint_dir_creation_and_verification_workflow() { let tmp = TempDir::new().expect("TempDir must be created"); let checkpoint_dir = tmp.path().join("model_checkpoints"); // Directory does not exist yet. assert!( !proof::verify_checkpoint_dir(&checkpoint_dir), "must return false before the directory is created" ); // Create the directory. std::fs::create_dir_all(&checkpoint_dir).expect("checkpoint dir must be created"); // Now it should be valid. assert!( proof::verify_checkpoint_dir(&checkpoint_dir), "must return true after the directory is created" ); } /// Multiple sibling checkpoint directories must each independently return the /// correct result. #[test] fn multiple_checkpoint_dirs_are_independent() { let tmp = TempDir::new().expect("TempDir must be created"); let dir_a = tmp.path().join("epoch_01"); let dir_b = tmp.path().join("epoch_02"); let dir_missing = tmp.path().join("epoch_99"); std::fs::create_dir_all(&dir_a).unwrap(); std::fs::create_dir_all(&dir_b).unwrap(); // dir_missing is intentionally not created. assert!( proof::verify_checkpoint_dir(&dir_a), "dir_a must be valid" ); assert!( proof::verify_checkpoint_dir(&dir_b), "dir_b must be valid" ); assert!( !proof::verify_checkpoint_dir(&dir_missing), "dir_missing must be invalid" ); } } // mod tch_proof_tests