From 769e85e4e4f2786a43018574d24b6e5302d7d49a Mon Sep 17 00:00:00 2001 From: Igor Barcik Date: Tue, 8 Sep 2026 14:55:22 +0200 Subject: [PATCH] test: add headless QA harness --- Source/Tests/TestMain.cpp | 135 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 135 insertions(+) create mode 100644 Source/Tests/TestMain.cpp diff --git a/Source/Tests/TestMain.cpp b/Source/Tests/TestMain.cpp new file mode 100644 index 0000000..9fb965d --- /dev/null +++ b/Source/Tests/TestMain.cpp @@ -0,0 +1,135 @@ +#include +#include +#include +#include "../PluginProcessor.h" + +// =========================================================================== +// Headless QA harness: instantiates the processor, plays notes through every +// factory preset and reports NaN/inf and silence failures. +// =========================================================================== +namespace +{ + bool hasNaN (const juce::AudioBuffer& b) + { + for (int ch = 0; ch < b.getNumChannels(); ++ch) + { + const float* d = b.getReadPointer (ch); + for (int i = 0; i < b.getNumSamples(); ++i) + if (! std::isfinite (d[i])) + return true; + } + return false; + } + + float peak (const juce::AudioBuffer& b) + { + float p = 0.0f; + for (int ch = 0; ch < b.getNumChannels(); ++ch) + { + const float* d = b.getReadPointer (ch); + for (int i = 0; i < b.getNumSamples(); ++i) + p = std::max (p, std::abs (d[i])); + } + return p; + } +} + +int main() +{ + juce::ScopedJuceInitialiser_GUI initialiser; + + serum::SerumAltAudioProcessor processor; + processor.prepareToPlay (44100.0, 512); + + const int numPresets = processor.getNumPrograms(); + int failures = 0; + + const int notes[3] = { 48, 60, 67 }; + + // Default (init) preset. + { + juce::MidiBuffer midi; + for (int n : notes) + midi.addEvent (juce::MidiMessage::noteOn (1, n, (juce::uint8) 100), 0); + + juce::AudioBuffer buffer (2, 512); + float maxPeak = 0.0f; + bool nan = false; + + for (int block = 0; block < 240; ++block) + { + buffer.clear(); + processor.processBlock (buffer, midi); + midi.clear(); + if (block == 180) + for (int n : notes) + midi.addEvent (juce::MidiMessage::noteOff (1, n), 0); + nan = nan || hasNaN (buffer); + maxPeak = std::max (maxPeak, peak (buffer)); + } + + const bool ok = ! nan && maxPeak > 0.001f; + if (! ok) ++failures; + std::cout << (ok ? "PASS" : "FAIL") << " [Init] peak=" << maxPeak << (nan ? " " : "") << "\n"; + } + + // Every factory preset. + for (int preset = 0; preset < numPresets; ++preset) + { + processor.setCurrentProgram (preset); + + juce::MidiBuffer midi; + for (int n : notes) + midi.addEvent (juce::MidiMessage::noteOn (1, n, (juce::uint8) 100), 0); + + juce::AudioBuffer buffer (2, 512); + float maxPeak = 0.0f; + bool nan = false; + + for (int block = 0; block < 240; ++block) + { + buffer.clear(); + processor.processBlock (buffer, midi); + midi.clear(); + if (block == 180) + for (int n : notes) + midi.addEvent (juce::MidiMessage::noteOff (1, n), 0); + nan = nan || hasNaN (buffer); + maxPeak = std::max (maxPeak, peak (buffer)); + } + + const bool ok = ! nan && maxPeak > 0.001f; + if (! ok) ++failures; + std::cout << (ok ? "PASS" : "FAIL") << " [" << processor.getProgramName (preset) << "]" + << " peak=" << maxPeak << (nan ? " " : "") << "\n"; + } + + // RAVE toggle + parameter churn while playing (no crash / NaN). + { + processor.setCurrentProgram (0); + juce::MidiBuffer midi; + for (int n : notes) + midi.addEvent (juce::MidiMessage::noteOn (1, n, (juce::uint8) 100), 0); + + processor.setRaveEnabled (true); + + juce::AudioBuffer buffer (2, 512); + bool nan = false; + for (int block = 0; block < 120; ++block) + { + buffer.clear(); + processor.processBlock (buffer, midi); + midi.clear(); + if (block == 60) + processor.setRaveEnabled (false); + nan = nan || hasNaN (buffer); + } + const bool ok = ! nan; + if (! ok) ++failures; + std::cout << (ok ? "PASS" : "FAIL") << " [RAVE toggle / param churn]" << (nan ? " " : "") << "\n"; + } + + std::cout << "\n" << (failures == 0 ? "ALL QA CHECKS PASSED" : "QA FAILURES DETECTED") + << " (" << failures << " failures)\n"; + return failures == 0 ? 0 : 1; +}