use super::*;
#[test]
fn falsify_wer_known_substitution() {
let wer = word_error_rate("a b c", "a x c");
assert!((wer - 1.0 / 3.0).abs() < 1e-10, "1 substitution in 3 words → WER = 1/3, got {wer}");
}
#[test]
fn falsify_wer_known_two_insertions() {
let wer = word_error_rate("a", "x a y");
assert!((wer - 2.0).abs() < 1e-10, "2 insertions in 1-word ref → WER = 2.0, got {wer}");
}
#[test]
fn falsify_wer_exceeds_one() {
let wer = word_error_rate("a", "b c d e f");
assert!(wer > 1.0, "WER should exceed 1.0 for heavily inserted hyp, got {wer}");
}
#[test]
fn falsify_wer_asymmetry() {
let wer_ab = word_error_rate("a b c", "a b c d e");
let wer_ba = word_error_rate("a b c d e", "a b c");
assert!(
(wer_ab - wer_ba).abs() > 1e-10,
"WER must be asymmetric: WER(abc, abcde)={wer_ab} vs WER(abcde, abc)={wer_ba}"
);
}
#[test]
fn falsify_wer_triangle_inequality() {
let a = "the quick brown fox";
let b = "a quick brown dog";
let c = "the slow red cat";
let d_ab = word_error_rate(a, b) * 4.0; let d_bc = word_error_rate(b, c) * 4.0; let d_ac = word_error_rate(a, c) * 4.0;
assert!(
d_ac <= d_ab + d_bc + 1e-10,
"Triangle inequality violated: d(a,c)={d_ac} > d(a,b)={d_ab} + d(b,c)={d_bc}"
);
}
#[test]
fn falsify_wer_whitespace_only_reference() {
let wer = word_error_rate(" ", "hello");
assert!(wer.is_infinite(), "Whitespace-only ref has 0 words → WER should be inf, got {wer}");
}
#[test]
fn falsify_wer_whitespace_only_hypothesis() {
let wer = word_error_rate("hello world", " ");
assert!((wer - 1.0).abs() < 1e-10, "Whitespace-only hyp → all deletions → WER=1.0, got {wer}");
}
#[test]
fn falsify_bleu_brevity_penalty_applied() {
let short = bleu_score(&["a b c d e f g h i j"], "a b c", 1);
let full = bleu_score(&["a b c d e f g h i j"], "a b c d e f g h i j", 1);
assert!(
short < full,
"Brevity penalty: short hyp ({short}) should score less than full ({full})"
);
}
#[test]
fn falsify_bleu_clipped_precision() {
let score = bleu_score(&["the cat"], "the the the the", 1);
assert!(score < 0.3, "Clipped precision should limit repeated words, got {score}");
assert!(score > 0.0, "Some unigrams match, should be > 0, got {score}");
}
#[test]
fn falsify_bleu_multi_reference() {
let score_single = bleu_score(&["the cat sat"], "the cat sat", 2);
let score_multi = bleu_score(&["the cat sat", "the dog sat"], "the cat sat", 2);
assert!(
(score_single - score_multi).abs() < 1e-10,
"Adding a non-matching ref should not change score: single={score_single}, multi={score_multi}"
);
}
#[test]
fn falsify_bleu_max_n_1_equals_unigram() {
let score = bleu_score(&["a b c d"], "a b x d", 1);
assert!((score - 0.75).abs() < 1e-10, "BLEU-1 should be unigram precision = 3/4, got {score}");
}
#[test]
fn falsify_bleu_zero_for_no_bigram_match() {
let score = bleu_score(&["a b"], "b a", 4);
assert_eq!(score, 0.0, "No bigram overlap should make BLEU-4 = 0, got {score}");
}