diff --git a/crates/proof/src/affix.rs b/crates/proof/src/affix.rs index fefc7f6a..03fc27a6 100644 --- a/crates/proof/src/affix.rs +++ b/crates/proof/src/affix.rs @@ -1310,11 +1310,13 @@ pub(crate) mod tests { #[test] fn self_continuing_rules_check_in_linear_time() { // Thousands of empty-append rules that continue with their own flag: each check used to - // follow every rule from every rule, millions of steps a word (#3613). - let d = many_rules(16_000, |_| "0 0/A .".into()); + // follow every rule from every rule, millions of steps a word (#3613). The checks take + // about a millisecond; the old checker took 14 s for two of them at 16,000 rules, so at + // 40,000 (quadratic: minutes) the 10 s bound leaves a busy machine a wide margin. + let d = many_rules(40_000, |_| "0 0/A .".into()); let t = std::time::Instant::now(); assert!(d.check("kot") && !d.check("pies") && !d.check("kotx")); - assert!(t.elapsed().as_secs_f64() < 2.0, "{:?}", t.elapsed()); + assert!(t.elapsed().as_secs_f64() < 10.0, "{:?}", t.elapsed()); } #[test] @@ -1324,7 +1326,9 @@ pub(crate) mod tests { let distinct = many_rules(3000, |i| format!("0 x{i}/A .")); let t = std::time::Instant::now(); let (a, b) = (same.forms("kot"), distinct.forms("kot")); - assert!(t.elapsed().as_secs_f64() < 2.0, "{:?}", t.elapsed()); + // The cap on the count is what tells the old code (9 million forms each) apart; the + // generous time bound (tens of ms here) only backs up the rule-visit cap. + assert!(t.elapsed().as_secs_f64() < 10.0, "{:?}", t.elapsed()); assert!(a.len() <= MAX_FORMS && b.len() <= MAX_FORMS, "{} {}", a.len(), b.len()); assert!(b.iter().any(|f| f == "kotx0x1"), "chained forms are still listed"); } @@ -1332,11 +1336,13 @@ pub(crate) mod tests { #[test] fn many_strips_per_suffix_index_in_linear_time() { // One append with thousands of strips: the index used to scan the append's groups for - // each rule. + // each rule. Building 200,000 rules takes well under a second; the old index took 3 s at + // 30,000 and over 10 minutes at 300,000. + let n = 200_000; let t = std::time::Instant::now(); - let d = many_rules(30_000, |i| format!("k{i} y .")); - assert!(t.elapsed().as_secs_f64() < 2.0, "{:?}", t.elapsed()); - assert_eq!(d.sfx_index.get("y").map(Vec::len), Some(30_000)); + let d = many_rules(n, |i| format!("k{i} y .")); + assert!(t.elapsed().as_secs_f64() < 10.0, "{:?}", t.elapsed()); + assert_eq!(d.sfx_index.get("y").map(Vec::len), Some(n)); assert!(!d.contains("koty")); } diff --git a/crates/proof/src/hunspell.rs b/crates/proof/src/hunspell.rs index e86c7f68..3449c8ca 100644 --- a/crates/proof/src/hunspell.rs +++ b/crates/proof/src/hunspell.rs @@ -329,13 +329,12 @@ mod tests { // One byte over the cap (sparse: nothing is written) is refused without reading it. let big = dir.join("big.dic"); std::fs::File::create(&big).unwrap().set_len(MAX_FILE + 1).unwrap(); - let t = std::time::Instant::now(); assert!(load(&aff, &big).unwrap_err().contains("too large")); - // A directory, and on Unix an endless device, are not dictionary files. + // A directory, and on Unix an endless device, are not dictionary files. (No clock: a + // reader that read `/dev/zero` would never return, so the error itself is the proof.) assert!(load(&aff, &dir).unwrap_err().contains("not a regular file")); #[cfg(unix)] assert!(load(&aff, Path::new("/dev/zero")).unwrap_err().contains("not a regular file")); - assert!(t.elapsed().as_secs_f64() < 1.0, "{:?}", t.elapsed()); // Turkish reads through the same reader. let (tr_aff, tr_dic) = (dir.join("tr_TR.aff"), dir.join("tr_TR.dic")); std::fs::write(&tr_aff, "SET UTF-8\nSFX 1 Y 1\nSFX 1 0 lar .\n").unwrap(); diff --git a/crates/proof/src/tr/suggest.rs b/crates/proof/src/tr/suggest.rs index 38020ded..c5f4db89 100644 --- a/crates/proof/src/tr/suggest.rs +++ b/crates/proof/src/tr/suggest.rs @@ -298,7 +298,8 @@ mod tests { assert!(suggest_with(&d, &long, 8).is_empty()); assert!(!d.contains(&long) && !d.contains(&format!("kitap{long}"))); assert!(!super::super::is_correct_with(&d, &long)); - assert!(t.elapsed().as_secs_f64() < 1.0, "{:?}", t.elapsed()); + // Tens of milliseconds with the caps; without them this ran for over 5 minutes. + assert!(t.elapsed().as_secs_f64() < 10.0, "{:?}", t.elapsed()); } #[test]