The sweep compares a curve with another segment over a y-span shorter than its tolerance by bounding boxes only, so an edge rising by less than that tolerance (e.g. a rectangle edge cut through a circle's cap, whose computed intersection end sits ~1e-12 off the horizontal) was mis-ordered and the result lost a corner: xor/difference/area disagreed by up to 10%. Every sweep input now snaps on-curve y values within the tolerance to one level (handles follow and are levelled with their anchor), so such edges become exact horizontals, which the sweep handles exactly. - tests/regressions.rs: the six minimal failures found by the properties, the root cause in isolation, and the self-crossing "star" polygon. - The star-polygon strategy rejected no angular step of half a turn or more, so it sometimes drew self-crossing polygons (the shoelace failure). - Property suites run from a fixed seed (PROPTEST_CASES / PROPTEST_RNG_SEED still override), so CI cannot fail at random. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
20 lines
793 B
Rust
20 lines
793 B
Rust
//! Shared property-test configuration for the pathops suites.
|
|
|
|
use proptest::test_runner::{Config, RngSeed};
|
|
|
|
/// Seed the property suites run with unless `PROPTEST_RNG_SEED` is set.
|
|
const SEED: u64 = 0x5eed_9a7f;
|
|
|
|
/// Reproducible property-test config: `cases` cases from a fixed seed, so a CI run can never fail
|
|
/// at random. Explore further locally with `PROPTEST_CASES=5000 PROPTEST_RNG_SEED=<n>`; keep
|
|
/// every minimal failure found that way as a test in `regressions.rs`.
|
|
pub fn config(cases: u32) -> Config {
|
|
let mut c = Config { failure_persistence: None, ..Config::default() };
|
|
if std::env::var_os("PROPTEST_CASES").is_none() {
|
|
c.cases = cases;
|
|
}
|
|
if std::env::var_os("PROPTEST_RNG_SEED").is_none() {
|
|
c.rng_seed = RngSeed::Fixed(SEED);
|
|
}
|
|
c
|
|
}
|