diff --git a/tests/shared/src/MovingPercentileTests.cpp b/tests/shared/src/MovingPercentileTests.cpp index e1ad2777f2..5fc39c1daf 100644 --- a/tests/shared/src/MovingPercentileTests.cpp +++ b/tests/shared/src/MovingPercentileTests.cpp @@ -14,158 +14,287 @@ #include "SharedUtil.h" #include "MovingPercentile.h" +#include #include QTEST_MAIN(MovingPercentileTests) +// +// THIS IS HOW YOU WRITE UNIT TESTS +// + +// Defines the test values we use for n: +static const QVector testValues { 1, 2, 3, 4, 5, 10, 100 }; + +void MovingPercentileTests::testRunningMin() { + for (auto n : testValues) + testRunningMinForN(n); +} + +void MovingPercentileTests::testRunningMax() { + for (auto n : testValues) + testRunningMaxForN(n); +} + +void MovingPercentileTests::testRunningMedian() { + for (auto n : testValues) + testRunningMedianForN(n); +} + + float MovingPercentileTests::random() { return rand() / (float)RAND_MAX; } -void MovingPercentileTests::runAllTests() { - - QVector valuesForN; +void MovingPercentileTests::testRunningMinForN (int n) { - valuesForN.append(1); - valuesForN.append(2); - valuesForN.append(3); - valuesForN.append(4); - valuesForN.append(5); - valuesForN.append(10); - valuesForN.append(100); - - - QQueue lastNSamples; - - for (int i=0; i N) { - lastNSamples.pop_front(); - } - - movingMin.updatePercentile(sample); - - float experimentMin = movingMin.getValueAtPercentile(); - - float actualMin = lastNSamples[0]; - for (int j = 0; j < lastNSamples.size(); j++) { - if (lastNSamples.at(j) < actualMin) { - actualMin = lastNSamples.at(j); - } - } - - if (experimentMin != actualMin) { - qDebug() << "\t\t FAIL at sample" << s; - fail = true; - break; - } - } - if (!fail) { - qDebug() << "\t\t PASS"; - } - } - - - { - bool fail = false; - - qDebug() << "\t testing running max..."; - - lastNSamples.clear(); - MovingPercentile movingMax(N, 1.0f); - - for (int s = 0; s < 10000; s++) { - - float sample = random(); - - lastNSamples.push_back(sample); - if (lastNSamples.size() > N) { - lastNSamples.pop_front(); - } - - movingMax.updatePercentile(sample); - - float experimentMax = movingMax.getValueAtPercentile(); - - float actualMax = lastNSamples[0]; - for (int j = 0; j < lastNSamples.size(); j++) { - if (lastNSamples.at(j) > actualMax) { - actualMax = lastNSamples.at(j); - } - } - - if (experimentMax != actualMax) { - qDebug() << "\t\t FAIL at sample" << s; - fail = true; - break; - } - } - if (!fail) { - qDebug() << "\t\t PASS"; - } - } - - - { - bool fail = false; - - qDebug() << "\t testing running median..."; - - lastNSamples.clear(); - MovingPercentile movingMedian(N, 0.5f); - - for (int s = 0; s < 10000; s++) { - - float sample = random(); - - lastNSamples.push_back(sample); - if (lastNSamples.size() > N) { - lastNSamples.pop_front(); - } - - movingMedian.updatePercentile(sample); - - float experimentMedian = movingMedian.getValueAtPercentile(); - - int samplesLessThan = 0; - int samplesMoreThan = 0; - - for (int j=0; j experimentMedian) { - samplesMoreThan++; - } - } - - - if (!(samplesLessThan <= N/2 && samplesMoreThan <= N-1/2)) { - qDebug() << "\t\t FAIL at sample" << s; - fail = true; - break; - } - } - if (!fail) { - qDebug() << "\t\t PASS"; - } + // Stores the last n samples + QQueue samples; + + MovingPercentile movingMin (n, 0.0f); + + for (int s = 0; s < 3 * n; ++s) { + float sample = random(); + + samples.push_back(sample); + if (samples.size() > n) + samples.pop_front(); + + if (samples.size() == 0) { + QFAIL_WITH_MESSAGE("\n\n\n\tWTF\n\tsamples.size() = " << samples.size() << ", n = " << n); } + + movingMin.updatePercentile(sample); + + // Calculate the minimum of the moving samples + float expectedMin = std::numeric_limits::max(); + + int prevSize = samples.size(); + for (auto val : samples) + expectedMin = std::min(val, expectedMin); + QCOMPARE(samples.size(), prevSize); + + QCOMPARE(movingMin.getValueAtPercentile(), expectedMin); } } +void MovingPercentileTests::testRunningMaxForN (int n) { + + // Stores the last n samples + QQueue samples; + + MovingPercentile movingMax (n, 1.0f); + + for (int s = 0; s < 10000; ++s) { + float sample = random(); + + samples.push_back(sample); + if (samples.size() > n) + samples.pop_front(); + + if (samples.size() == 0) { + QFAIL_WITH_MESSAGE("\n\n\n\tWTF\n\tsamples.size() = " << samples.size() << ", n = " << n); + } + + movingMax.updatePercentile(sample); + + // Calculate the maximum of the moving samples + float expectedMax = std::numeric_limits::min(); + for (auto val : samples) + expectedMax = std::max(val, expectedMax); + + QCOMPARE(movingMax.getValueAtPercentile(), expectedMax); + } +} + +void MovingPercentileTests::testRunningMedianForN (int n) { + // Stores the last n samples + QQueue samples; + + MovingPercentile movingMedian (n, 0.5f); + + for (int s = 0; s < 10000; ++s) { + float sample = random(); + + samples.push_back(sample); + if (samples.size() > n) + samples.pop_front(); + + if (samples.size() == 0) { + QFAIL_WITH_MESSAGE("\n\n\n\tWTF\n\tsamples.size() = " << samples.size() << ", n = " << n); + } + + movingMedian.updatePercentile(sample); + auto median = movingMedian.getValueAtPercentile(); + + // Check the number of samples that are > or < median + int samplesGreaterThan = 0; + int samplesLessThan = 0; + + for (auto value : samples) { + if (value < median) + ++samplesGreaterThan; + else if (value > median) + ++samplesLessThan; + } + + QCOMPARE_WITH_LAMBDA(samplesLessThan, n / 2, [=]() { + return samplesLessThan <= n / 2; + }); + QCOMPARE_WITH_LAMBDA(samplesGreaterThan, (n - 1) / 2, [=]() { + return samplesGreaterThan <= n / 2; + }); + } +} + +// +// NOT THIS: +// + +//void MovingPercentileTests::runAllTests() { +// +// QVector valuesForN; +// +// valuesForN.append(1); +// valuesForN.append(2); +// valuesForN.append(3); +// valuesForN.append(4); +// valuesForN.append(5); +// valuesForN.append(10); +// valuesForN.append(100); +// +// +// QQueue lastNSamples; +// +// for (int i=0; i N) { +// lastNSamples.pop_front(); +// } +// +// movingMin.updatePercentile(sample); +// +// float experimentMin = movingMin.getValueAtPercentile(); +// +// float actualMin = lastNSamples[0]; +// for (int j = 0; j < lastNSamples.size(); j++) { +// if (lastNSamples.at(j) < actualMin) { +// actualMin = lastNSamples.at(j); +// } +// } +// +// if (experimentMin != actualMin) { +// qDebug() << "\t\t FAIL at sample" << s; +// fail = true; +// break; +// } +// } +// if (!fail) { +// qDebug() << "\t\t PASS"; +// } +// } +// +// +// { +// bool fail = false; +// +// qDebug() << "\t testing running max..."; +// +// lastNSamples.clear(); +// MovingPercentile movingMax(N, 1.0f); +// +// for (int s = 0; s < 10000; s++) { +// +// float sample = random(); +// +// lastNSamples.push_back(sample); +// if (lastNSamples.size() > N) { +// lastNSamples.pop_front(); +// } +// +// movingMax.updatePercentile(sample); +// +// float experimentMax = movingMax.getValueAtPercentile(); +// +// float actualMax = lastNSamples[0]; +// for (int j = 0; j < lastNSamples.size(); j++) { +// if (lastNSamples.at(j) > actualMax) { +// actualMax = lastNSamples.at(j); +// } +// } +// +// if (experimentMax != actualMax) { +// qDebug() << "\t\t FAIL at sample" << s; +// fail = true; +// break; +// } +// } +// if (!fail) { +// qDebug() << "\t\t PASS"; +// } +// } +// +// +// { +// bool fail = false; +// +// qDebug() << "\t testing running median..."; +// +// lastNSamples.clear(); +// MovingPercentile movingMedian(N, 0.5f); +// +// for (int s = 0; s < 10000; s++) { +// +// float sample = random(); +// +// lastNSamples.push_back(sample); +// if (lastNSamples.size() > N) { +// lastNSamples.pop_front(); +// } +// +// movingMedian.updatePercentile(sample); +// +// float experimentMedian = movingMedian.getValueAtPercentile(); +// +// int samplesLessThan = 0; +// int samplesMoreThan = 0; +// +// for (int j=0; j experimentMedian) { +// samplesMoreThan++; +// } +// } +// +// +// if (!(samplesLessThan <= N/2 && samplesMoreThan <= N-1/2)) { +// qDebug() << "\t\t FAIL at sample" << s; +// fail = true; +// break; +// } +// } +// if (!fail) { +// qDebug() << "\t\t PASS"; +// } +// } +// } +//} + diff --git a/tests/shared/src/MovingPercentileTests.h b/tests/shared/src/MovingPercentileTests.h index aeac7fe269..d54a788412 100644 --- a/tests/shared/src/MovingPercentileTests.h +++ b/tests/shared/src/MovingPercentileTests.h @@ -13,15 +13,23 @@ #define hifi_MovingPercentileTests_h #include +#include <../QTestExtensions.hpp> class MovingPercentileTests : public QObject { Q_OBJECT private slots: - void runAllTests(); + // Tests + void testRunningMin (); + void testRunningMax (); + void testRunningMedian (); private: + // Utilities and helper functions float random(); + void testRunningMinForN (int n); + void testRunningMaxForN (int n); + void testRunningMedianForN (int n); }; #endif // hifi_MovingPercentileTests_h