Commit graph CultLib/packages/cultmath/tests/CultMath.Tests/FirstOrderInterceptTests.cs
Author SHA1 Message Date
Meta Vens
6d8195811d Fix a tolerance-overload bug that made intercept precision asserts inert
`Precision` was declared `const float`, so `Assert.Equal(a, b, Precision)`
bound to xunit's absolute-tolerance overload (allowing any two values
within 4.0 of each other) instead of the intended 4-decimal-place
overload. Hand-mutating the `t2 > 0 ? min(t1, t2) : t1` ternary to always
return `t1` (math.cs:287) exposed it: the assertion silently accepted a
result almost 0.27 away from the expected value. Declaring it `const int`
selects the correct overload; confirmed the same hand mutation now fails.

Also add the float2-overload euler-integration length-validation test the
mutation report showed missing (BatchMath.cs:208's ValidateEqualLengths
call had no test at all).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-24 19:38:30 +02:00
Meta Vens
446859927a Fix degenerate fixtures that let real mutants survive their own tests
Soul-style self-check against the actual mutation report (not just green
tests) found several fixtures whose values coincidentally produced the
same output on the buggy path as on the correct one:

- BatchMath's scalar-tail fixtures put the one remainder particle/step
  either outside the falloff radius or mask-frozen, so the y-axis
  arithmetic a mutation would touch was never reached with an observable
  effect. Pin the remainder particle in range (radial falloff) and dynamic
  (Euler integration) so the scalar tail's own math is exercised, not just
  the vector body's.
- The float2-overload of AddRadialFalloffAcceleration2D had no no-op
  (radius <= 0 / strength == 0) test at all.
- first_order_intercept_time's negative-determinant test used a
  perpendicular relative velocity, making b = 2*dot(vel, pos) exactly
  zero; a mutant that drops the "no solution" branch entirely and falls
  through to the linear fallback coincidentally computes 0 too. Use a
  non-perpendicular fixture so the fallback's nonzero value is
  distinguishable from the correct zero.
- No fixture ever reached the `t1 > 0` branch at all (a > 0, both
  quadratic roots real and positive), so the boundary/negate checks
  guarding it and the `t2 > 0 ? min(t1, t2) : t1` line were never
  covered. Add that case.
- bool2.@false/@true, bool3.@true and bool4.@false have no consumer
  anywhere in the suite (bool3.@false and bool4.@true are read by
  HlslSemanticsTests); pin all six vector constants directly.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-24 19:26:48 +02:00
Meta Vens
71c42b125f Test first_order_intercept's branches beyond the one happy path
math.first_order_intercept_time had a single closing-target test. Add
coverage for zero relative velocity, the a-approx-zero linear fallback, a
target that outruns the projectile (negative determinant), a receding
target with both quadratic roots non-positive, and a closing case with
off-origin, off-axis shooter and target state. The closing cases assert
that the projectile (inheriting the shooter's velocity) and the target
actually coincide at the returned time; the no-solution branches pin the
value the source's own contract specifies.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-24 19:06:41 +02:00