From 2c2dd12417311ae5345202052973fb839567fe2e Mon Sep 17 00:00:00 2001 From: Martin Ball Date: Sun, 1 Nov 2026 18:26:48 +0000 Subject: [PATCH] =?UTF-8?q?CP6.3:=20property=20test=20=E2=80=94=20FULLSTRI?= =?UTF-8?q?P,=20NEEDAFFIX=20and=20CIRCUMFIX=20never=20panic=20and=20forms(?= =?UTF-8?q?)=20stays=20checkable?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Random stems and words through a dictionary that uses all three directives (whole-stem strips, empty forms, circumfix pairs, forms that need another affix): no panic, and every form forms() lists is non-empty and accepted by the checker. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01FypgCX8LsYYE8fsj4byBm2 --- crates/proof/src/affix.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/crates/proof/src/affix.rs b/crates/proof/src/affix.rs index 6dea3f6e..bde194a4 100644 --- a/crates/proof/src/affix.rs +++ b/crates/proof/src/affix.rs @@ -3007,6 +3007,21 @@ pub(crate) mod tests { let _ = AffixDict::from_bytes(&miniz_oxide::deflate::compress_to_vec(&bytes, 1)); } + /// FULLSTRIP, NEEDAFFIX and CIRCUMFIX on hostile stems and words: no panic, and every + /// form `forms()` lists is one the checker accepts. + #[test] + fn needaffix_circumfix_and_fullstrip_never_panic(stem in "[abx]{0,4}", word in "\\PC{0,12}") { + let aff = "SET UTF-8\nFULLSTRIP\nNEEDAFFIX N\nCIRCUMFIX C\nPFX P Y 2\nPFX P a 0/C .\nPFX P 0 x/N a\nSFX S Y 3\nSFX S b 0/C b\nSFX S 0 x/NT .\nSFX S ab y .\nSFX T Y 1\nSFX T x 0 .\n"; + if let Ok(d) = AffixDict::from_hunspell(aff, &format!("2\n{stem}/PSN\n{stem}b/PS\n"), &[]) { + let _ = d.check(&word); + for s in [stem.clone(), format!("{stem}b")] { + for f in d.forms(&s) { + proptest::prop_assert!(!f.is_empty() && d.contains(&f), "{s} → {f:?}"); + } + } + } + } + #[test] fn any_flag_field_reads_without_panicking(field in "[0-9,a-zA-Z!\u{fe0f}\u{1f6ab}]{0,24}", word in "\\PC{0,12}") { for mode in ["num", "long", "UTF-8"] {