// Copyright (c) 2026 Petr Balvín (https://petrbalvin.org) // SPDX-License-Identifier: MIT package integrate import ( "math" "testing" ) // TestIntegrateFilonRejectsInfiniteBounds pins the refusal: an infinite // bound used to fall into an unrepresentable panel count (the conversion // of the ceiling of infinity) and come back as a quiet NaN pair with a // nil error, and with k = 0 it sampled the amplitude at infinity. The // error contract refuses NaN bounds and an infinite frequency; an // infinite bound is the same breach and answers the same way. func TestIntegrateFilonRejectsInfiniteBounds(t *testing.T) { f := func(x float64) (float64, error) { return math.Exp(-x), nil } cases := []struct { label string a, b, k float64 }{ {"upper tail", 0, math.Inf(1), 1}, {"lower tail", math.Inf(-1), 0, 1}, {"whole line", math.Inf(-1), math.Inf(1), 1}, {"zero frequency upper tail", 0, math.Inf(1), 0}, {"span product overflow", 0, 1e100, 1e300}, } for _, c := range cases { cos, sin, err := IntegrateFilon(f, c.a, c.b, c.k, FilonOptions{}) if err == nil { t.Fatalf("%s: [%g, %g] at k=%g integrated to (%g, %g) with no error, want a refusal", c.label, c.a, c.b, c.k, cos, sin) } } } // TestIntegrateFilonRejectsUnrepresentablePanels pins the two refusals // the infinite-bound guard alone does not reach. A panel estimate that // stays finite but sits beyond the int range converted to garbage: a // wrapped negative count iterated zero times and answered a quiet zero, // and a saturated count would iterate forever. And two finite bounds // far enough apart that their span overflows leave an infinite panel // width, where a constant amplitude stays finite and the carrier phase // 0·Inf comes back as a quiet NaN pair. Both answer with the error // contract instead. func TestIntegrateFilonRejectsUnrepresentablePanels(t *testing.T) { constant := func(float64) (float64, error) { return 1, nil } cases := []struct { label string a, b, k float64 opts FilonOptions f func(x float64) (float64, error) }{ {"finite estimate beyond the int range", 0, 1e8, 1e300, FilonOptions{}, constant}, {"finite estimate just above the int range", 0, 1e18, 6e2, FilonOptions{}, constant}, {"overflowing span at zero frequency", -math.MaxFloat64, math.MaxFloat64, 0, FilonOptions{}, constant}, {"overflowing span with forced panels", -math.MaxFloat64, math.MaxFloat64, 0, FilonOptions{Panels: 2}, constant}, {"overflowing span with a frequency", -math.MaxFloat64, math.MaxFloat64, 1, FilonOptions{}, constant}, } for _, c := range cases { cos, sin, err := IntegrateFilon(c.f, c.a, c.b, c.k, c.opts) if err == nil { t.Fatalf("%s: [%g, %g] at k=%g integrated to (%g, %g) with no error, want a refusal", c.label, c.a, c.b, c.k, cos, sin) } } }