#[test]
fn falsifier_fingerprint_diff_all_tensors_missing_in_b_is_a_failure() {
let fps_a: Vec<TensorFingerprint> = (0..27)
.map(|i| make_fingerprint(&format!("model.layers.{i}.weight"), 0.5, 1.0, 0, 0))
.collect();
let fps_b: Vec<TensorFingerprint> = vec![];
let err = print_fingerprint_diff(&fps_a, &fps_b, false, false)
.expect_err("27 of 27 tensors absent from B must not report success");
let msg = err.to_string();
assert!(
msg.contains("27"),
"failure must name how many tensors are missing, got: {msg}"
);
assert!(
matches!(err, CliError::ValidationFailed(_)),
"must be a validation failure so the process exits 5, got: {err:?}"
);
}
#[test]
fn falsifier_fingerprint_diff_tensor_only_in_b_is_a_failure() {
let fps_a: Vec<TensorFingerprint> = vec![];
let fps_b = vec![make_fingerprint("only_in_b.weight", 0.5, 1.0, 0, 0)];
assert!(
print_fingerprint_diff(&fps_a, &fps_b, false, false).is_err(),
"a tensor present only in model B is a difference and must fail the diff"
);
}
#[test]
fn falsifier_fingerprint_diff_identical_models_still_pass() {
let fps_a = vec![
make_fingerprint("model.embed_tokens.weight", 0.01, 0.02, 0, 0),
make_fingerprint("model.norm.weight", 1.0, 0.1, 0, 0),
];
assert!(
print_fingerprint_diff(&fps_a, &fps_a, false, false).is_ok(),
"a model compared against itself must still pass"
);
}
#[test]
fn falsifier_missing_tensor_anomalies_are_counted_by_direction() {
let anomalies = vec![
missing_tensor_anomaly("a1", FIELD_MISSING_IN_B),
missing_tensor_anomaly("a2", FIELD_MISSING_IN_B),
missing_tensor_anomaly("b1", FIELD_MISSING_IN_A),
];
assert_eq!(count_field(&anomalies, FIELD_MISSING_IN_B), 2);
assert_eq!(count_field(&anomalies, FIELD_MISSING_IN_A), 1);
}
fn tensor_count_mismatch_report() -> VerificationReport {
let mut report = VerificationReport::passing();
report.is_equivalent = false;
report.max_diff = f32::INFINITY;
report.mean_diff = f32::INFINITY;
report.failed_tensors = vec!["Tensor count mismatch".to_string()];
report
}
#[test]
fn falsifier_verify_outcome_is_an_error_when_the_report_failed() {
let report = tensor_count_mismatch_report();
let err = verify_outcome(&report, 1e-5).expect_err("a FAILED report must not exit 0");
let msg = err.to_string();
assert!(
msg.contains("FAILED"),
"the error must say what failed, got: {msg}"
);
}
#[test]
fn falsifier_verify_outcome_is_ok_when_the_report_passed() {
assert!(verify_outcome(&VerificationReport::passing(), 1e-5).is_ok());
}
#[test]
fn falsifier_verification_json_is_parseable_when_diffs_are_infinite() {
let report = tensor_count_mismatch_report();
let text = serde_json::to_string(&verification_json(&report)).expect("serialize");
assert!(
!text.contains("inf"),
"the document must not contain a bare inf literal: {text}"
);
let parsed: serde_json::Value = serde_json::from_str(&text)
.unwrap_or_else(|e| panic!("verify --json must be valid JSON, got {text:?}: {e}"));
assert!(parsed["max_diff"].is_null(), "non-finite becomes null");
assert!(parsed["mean_diff"].is_null(), "non-finite becomes null");
assert_eq!(parsed["is_equivalent"], serde_json::json!(false));
}
#[test]
fn falsifier_verification_json_keeps_finite_numbers() {
let mut report = VerificationReport::passing();
report.max_diff = 0.25;
report.mean_diff = 0.125;
let parsed = verification_json(&report);
assert_eq!(parsed["max_diff"], serde_json::json!(0.25));
assert_eq!(parsed["mean_diff"], serde_json::json!(0.125));
}
#[test]
fn falsifier_json_number_maps_non_finite_to_null() {
assert!(json_number(f32::INFINITY).is_null());
assert!(json_number(f32::NEG_INFINITY).is_null());
assert!(json_number(f32::NAN).is_null());
assert_eq!(json_number(1.5), serde_json::json!(1.5));
}
#[test]
fn falsifier_validate_stats_json_is_parseable_with_infinite_deviation() {
let anomalies = vec![StatisticalAnomaly {
tensor: "model.layers.0.weight".to_string(),
field: "nan_count".to_string(),
expected: 0.0,
actual: 12.0,
deviation_sigma: f32::INFINITY,
}];
let doc = validate_stats_json(Path::new("/tmp/m.apr"), 3.0, false, 1, &anomalies);
let text = serde_json::to_string(&doc).expect("serialize");
assert!(!text.contains("inf"), "no bare inf literal: {text}");
let parsed: serde_json::Value = serde_json::from_str(&text)
.unwrap_or_else(|e| panic!("validate-stats --json must be valid JSON: {e}"));
assert!(parsed["anomaly_details"][0]["deviation"].is_null());
assert_eq!(parsed["passed"], serde_json::json!(false));
}
#[test]
fn falsifier_compare_inference_zero_tokens_is_not_a_match() {
let line = inference_result_line(0, 0, 0.1);
assert!(
!line.contains("MATCH (100%)"),
"0 token pairs must not read as a 100% match, got: {line}"
);
assert!(
line.contains("VACUOUS"),
"0 token pairs must be reported as vacuous, got: {line}"
);
}
#[test]
fn falsifier_compare_inference_real_match_still_reads_as_a_match() {
assert!(inference_result_line(5, 0, 0.1).contains("MATCH (100%)"));
}
#[test]
fn falsifier_compare_passed_is_false_with_zero_tokens() {
assert!(
!compare_passed(0, 0, 0.1),
"a comparison of zero token pairs never passes"
);
assert!(compare_passed(5, 0, 0.1), "a real 5/5 match still passes");
assert!(
!compare_passed(5, 5, 0.1),
"a real 0/5 match still does not pass"
);
}
#[test]
fn falsifier_validate_captured_tokens_rejects_vacuous_comparison() {
let err = validate_captured_tokens("4 2", "<unk><unk><unk>")
.expect_err("zero token pairs compared must never be a success");
let msg = err.to_string();
assert!(
msg.contains("VACUOUS"),
"the error must name the vacuous comparison, got: {msg}"
);
}
#[test]
fn falsifier_validate_captured_tokens_still_reports_a_silent_model() {
assert!(validate_captured_tokens("", "").is_err());
assert!(validate_captured_tokens("", "some text").is_err());
assert!(validate_captured_tokens("some text", "").is_err());
assert!(validate_captured_tokens("120 tok/s", "real output").is_err());
}