| 23 | #include "fl/math/math.h" |
| 24 | |
| 25 | FL_TEST_FILE(FL_FILEPATH) { |
| 26 | |
| 27 | using namespace fl; |
| 28 | using fl::audio::test::makeSample; |
| 29 | using fl::audio::test::makeSilence; |
| 30 | using fl::audio::test::makeDC; |
| 31 | using fl::audio::test::makeMaxAmplitude; |
| 32 | |
| 33 | namespace { |
| 34 | |
| 35 | static audio::Sample makeSample_Adversarial(float freq, fl::u32 timestamp, float amplitude = 16000.0f) { |
| 36 | return makeSample(freq, timestamp, amplitude); |
| 37 | } |
| 38 | |
| 39 | // Safe NaN check that doesn't rely on isnan |
| 40 | static bool isNaN(float x) { |
| 41 | return !(x == x); |
| 42 | } |
| 43 | |
| 44 | } // anonymous namespace |
| 45 | |
| 46 | // F1: audio::fft::FFT Edge Cases |
| 47 | |
| 48 | FL_TEST_CASE("Adversarial - audio::fft::FFT with DC-only input produces no spectral peaks") { |
| 49 | audio::fft::FFT fft; |
| 50 | fl::vector<fl::i16> dcSignal(512, 10000); // Pure DC |
| 51 | audio::fft::Bins bins(16); |
| 52 | fft.run(dcSignal, &bins); |
| 53 | |
| 54 | // DC should not produce significant energy in frequency bins. |
| 55 | // With fmin=90 Hz, the lowest CQ bin is closer to DC than with the old |
| 56 | // fmin=174.6 Hz, so some leakage is expected. The energy should still |
| 57 | // be modest compared to an in-band sine wave (~30000+ total energy). |
| 58 | float totalEnergy = 0.0f; |
| 59 | for (fl::size i = 0; i < bins.raw().size(); ++i) { |
| 60 | totalEnergy += bins.raw()[i]; |
| 61 | } |
| 62 | FL_CHECK_LT(totalEnergy, 5000.0f); |
| 63 | } |
| 64 | |
| 65 | FL_TEST_CASE("Adversarial - audio::fft::FFT with alternating max samples") { |
| 66 | audio::fft::FFT fft; |
| 67 | fl::vector<fl::i16> alternating; |
| 68 | alternating.reserve(512); |
| 69 | for (int i = 0; i < 512; ++i) { |
| 70 | alternating.push_back((i % 2 == 0) ? 32767 : -32768); |
| 71 | } |
| 72 | audio::fft::Bins bins(16); |
| 73 | fft.run(alternating, &bins); |
| 74 | |
| 75 | // Should not crash, bins should have values |
| 76 | FL_CHECK_GT(bins.raw().size(), 0u); |
| 77 | |
| 78 | // Alternating +-max is essentially Nyquist frequency |
| 79 | // Energy should be concentrated in the highest bins (if within CQ range) |
| 80 | // At minimum, it should not produce NaN or Inf |
| 81 | for (fl::size i = 0; i < bins.raw().size(); ++i) { |
| 82 | FL_CHECK_FALSE(isNaN(bins.raw()[i])); |
nothing calls this directly
no test coverage detected