| 
							- #pragma once
 - 
 - #include "asserts.h"
 - #include <vector>
 - 
 - /**
 -  * Utility class that counts up in binary using an array of ints to hold the bits.
 -  *
 -  */
 - class BitCounter
 - {
 - public:
 -     void reset(int size)
 -     {
 -         done = false;
 -         state.resize(size);
 -         for (int i = 0; i < size; ++i) {
 -             state[i] = 0;
 -         }
 -     }
 -     bool atMax() const
 -     {
 -         for (size_t i = 0; i < state.size(); ++i) {
 -             if (state[i] == 0) {
 -                 return false;
 -             }
 -         }
 -         return true;
 -     }
 -     bool isDone() const
 -     {
 -         return done;
 -     }
 -     void next()
 -     {
 -         if (atMax()) {
 -             done = true;
 -             return;
 -         }
 -         state[0]++;
 -         for (size_t i = 0; i < state.size(); ++i) {
 -             if (state[i] > 1) {
 -                 state[i] = 0;
 -                 ++state[i + 1];
 -             }
 -         }
 - 
 -     }
 - 
 -     template <typename Q>
 -     void setState(std::vector<Q>& testSignal, const std::vector< std::pair<float, float>>* signalLimits)
 -     {
 -         for (int i = (int) state.size() - 1; i >= 0; --i) {
 -             float min = -10.f;
 -             float max = 10.f;
 -             if (signalLimits) { // here we want to clip these to the possible values of params
 -                 min = (*signalLimits)[i].first;
 -                 max = (*signalLimits)[i].second;
 - 
 -                 assertNE(min, max);
 -                 assertGT(max, min);
 -             }
 -             testSignal[i].value = state[i] > 0 ? max : min;
 -         }
 -     }
 - 
 - 
 -     void dump(const char * label)
 -     {
 -         printf("State (%s): ", label);
 -         for (int i = (int) state.size() - 1; i >= 0; --i) {
 -             printf("%d ", state[i]);
 -         }
 -         printf("\n");
 -     }
 - private:
 -     std::vector<int> state;
 -     bool done;
 - 
 - };
 - 
 - 
 - /**
 - * Tests a composite by feeding all the inputs and parameters (in every possible permutation)
 - * with extreme inputs. Asserts that the output stays in a semi-sane range.
 - * Typically this test will fail by triggering an assert in some distant code.
 - */
 - template <typename T>
 - class ExtremeTester
 - {
 - public:
 - 
 -     static void test(T& dut,
 -         const std::vector< std::pair<float, float>>& paramLimits,
 -         bool checkOutput,
 -         const char * testName)
 -     {
 -         printf("extreme test starting for %s. %s ....\n", testName, checkOutput ? "test output" : "");
 -         const int numInputs = dut.NUM_INPUTS;
 -         const int numParams = dut.NUM_PARAMS;
 -         const int numOutputs = dut.NUM_OUTPUTS;
 -         assert(numInputs < 20);
 -         assertEQ(paramLimits.size(), numParams);
 - 
 -         const std::vector< std::pair<float, float>> * nullLimits = nullptr;
 -         BitCounter inputState;
 -         BitCounter paramsState;
 -         for (inputState.reset(numInputs); !inputState.isDone(); inputState.next()) {
 -             inputState.setState(dut.inputs, nullLimits);
 -             for (paramsState.reset(numParams); !paramsState.isDone(); paramsState.next()) {
 -                 paramsState.setState(dut.params, ¶mLimits);
 -                 for (int i = 0; i < 100; ++i) {
 -                     dut.step();
 -                     for (int j = 0; j < numOutputs; ++j) {
 -                         const float out = dut.outputs[j].value;
 -                         if (checkOutput) {
 -                             assertGE(out, -150);
 -                             assertLE(out, 150);
 -                         }
 -                     }
 -                 }
 -             }
 -         }
 -         printf("extreme test done\n");
 -     }
 - };
 
 
  |