Chris@1573: /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ Chris@1573: Chris@1573: /* Chris@1573: Sonic Visualiser Chris@1573: An audio file viewer and annotation editor. Chris@1573: Centre for Digital Music, Queen Mary, University of London. Chris@1573: Chris@1573: This program is free software; you can redistribute it and/or Chris@1573: modify it under the terms of the GNU General Public License as Chris@1573: published by the Free Software Foundation; either version 2 of the Chris@1573: License, or (at your option) any later version. See the file Chris@1573: COPYING included with this distribution for more information. Chris@1573: */ Chris@1573: Chris@1573: #ifndef TEST_MOVING_MEDIAN_H Chris@1573: #define TEST_MOVING_MEDIAN_H Chris@1573: Chris@1573: #include "../MovingMedian.h" Chris@1573: Chris@1573: #include Chris@1573: #include Chris@1573: #include Chris@1573: Chris@1573: #include Chris@1573: Chris@1573: using namespace std; Chris@1573: Chris@1573: class TestMovingMedian : public QObject Chris@1573: { Chris@1573: Q_OBJECT Chris@1573: Chris@1573: template Chris@1573: void checkExpected(const vector &output, Chris@1573: const vector &expected) { Chris@1573: if (output.size() != expected.size()) { Chris@1573: cerr << "ERROR: output array size " << output.size() Chris@1573: << " differs from expected size " << expected.size() << endl; Chris@1573: } Chris@1573: for (int i = 0; i < int(output.size()); ++i) { Chris@1573: if (output[i] != expected[i]) { Chris@1573: cerr << "ERROR: Value at index " << i Chris@1573: << " in output array differs from expected" << endl; Chris@1573: cerr << "Output: "; Chris@1573: for (auto v: output) cerr << v << " "; Chris@1573: cerr << "\nExpected: "; Chris@1573: for (auto v: expected) cerr << v << " "; Chris@1573: cerr << endl; Chris@1573: break; Chris@1573: } Chris@1573: } Chris@1573: QCOMPARE(output, expected); Chris@1573: } Chris@1573: Chris@1573: template Chris@1573: void testFixed(int n, Chris@1573: const vector &input, Chris@1573: const vector &expected, Chris@1573: double percentile = 50.0) { Chris@1573: vector output; Chris@1573: MovingMedian mm(n, percentile); Chris@1573: for (auto v: input) { Chris@1573: mm.push(v); Chris@1573: mm.checkIntegrity(); Chris@1573: output.push_back(mm.get()); Chris@1573: } Chris@1573: mm.checkIntegrity(); Chris@1573: checkExpected(output, expected); Chris@1573: } Chris@1573: Chris@1573: private slots: Chris@1573: Chris@1573: void empty() { Chris@1573: MovingMedian mm(3); Chris@1573: QCOMPARE(mm.get(), 0.0); Chris@1573: } Chris@1573: Chris@1573: void zeros() { Chris@1573: vector input { 0.0, 0.0, 0.0, 0.0, 0.0 }; Chris@1573: vector expected { 0.0, 0.0, 0.0, 0.0, 0.0 }; Chris@1573: testFixed(3, input, expected); Chris@1573: } Chris@1573: Chris@1573: void ascending() { Chris@1573: vector input { 1.0, 2.0, 3.0, 4.0, 5.0 }; Chris@1573: vector expected { 0.0, 1.0, 2.0, 3.0, 4.0 }; Chris@1573: testFixed(3, input, expected); Chris@1573: } Chris@1573: Chris@1573: void ascendingInt() { Chris@1573: vector input { 1, 2, 3, 4, 5 }; Chris@1573: vector expected { 0, 1, 2, 3, 4 }; Chris@1573: testFixed(3, input, expected); Chris@1573: } Chris@1573: Chris@1573: void descending() { Chris@1573: vector input { 5.0, 4.0, 3.0, 2.0, 1.0 }; Chris@1573: vector expected { 0.0, 4.0, 4.0, 3.0, 2.0 }; Chris@1573: testFixed(3, input, expected); Chris@1573: } Chris@1573: Chris@1573: void descendingInt() { Chris@1573: vector input { 5, 4, 3, 2, 1 }; Chris@1573: vector expected { 0, 4, 4, 3, 2 }; Chris@1573: testFixed(3, input, expected); Chris@1573: } Chris@1573: Chris@1573: void duplicates() { Chris@1573: vector input { 2.0, 2.0, 3.0, 4.0, 3.0 }; Chris@1573: vector expected { 0.0, 2.0, 2.0, 3.0, 3.0 }; Chris@1573: testFixed(3, input, expected); Chris@1573: } Chris@1573: Chris@1573: void percentile10() { Chris@1573: vector input { 1.0, 2.0, 3.0, 4.0, 5.0 }; Chris@1573: vector expected { 0.0, 0.0, 1.0, 2.0, 3.0 }; Chris@1573: testFixed(3, input, expected, 10); Chris@1573: } Chris@1573: Chris@1573: void percentile90() { Chris@1573: vector input { 1.0, 2.0, 3.0, 4.0, 5.0 }; Chris@1573: vector expected { 1.0, 2.0, 3.0, 4.0, 5.0 }; Chris@1573: testFixed(3, input, expected, 90); Chris@1573: } Chris@1573: Chris@1573: void even() { Chris@1573: vector input { 5.0, 4.0, 3.0, 2.0, 1.0 }; Chris@1573: vector expected { 0.0, 4.0, 4.0, 4.0, 3.0 }; Chris@1573: testFixed(4, input, expected); Chris@1573: } Chris@1573: Chris@1573: void growing() { Chris@1573: vector input { 2.0, 4.0, 3.0, 2.5, 2.5, 3.0, 1.0, 2.0, 1.0, 0.0 }; Chris@1573: vector expected { 2.0, 4.0, 4.0, 3.0, 2.5, 2.5, 2.5, 2.5, 2.0, 1.0 }; Chris@1573: vector output; Chris@1573: MovingMedian mm(1); Chris@1573: for (int i = 0; i < int(input.size()); ++i) { Chris@1573: // sizes 1, 1, 2, 2, 3, 3, 4, 4, 5, 5 Chris@1573: int sz = i/2 + 1; Chris@1573: mm.resize(sz); Chris@1573: QCOMPARE(mm.size(), sz); Chris@1573: mm.push(input[i]); Chris@1573: mm.checkIntegrity(); Chris@1573: output.push_back(mm.get()); Chris@1573: } Chris@1573: mm.checkIntegrity(); Chris@1573: checkExpected(output, expected); Chris@1573: } Chris@1573: Chris@1573: void shrinking() { Chris@1573: vector input { 2.0, 4.0, 3.0, 2.5, 2.5, 3.0, 1.0, 2.0, 1.0, 0.0 }; Chris@1573: vector expected { 0.0, 0.0, 3.0, 3.0, 2.5, 2.5, 3.0, 2.0, 1.0, 0.0 }; Chris@1573: vector output; Chris@1573: MovingMedian mm(99); Chris@1573: for (int i = 0; i < int(input.size()); ++i) { Chris@1573: // sizes 5, 5, 4, 4, 3, 3, 2, 2, 1, 1 Chris@1573: int sz = 5 - i/2; Chris@1573: mm.resize(sz); Chris@1573: QCOMPARE(mm.size(), sz); Chris@1573: mm.push(input[i]); Chris@1573: mm.checkIntegrity(); Chris@1573: output.push_back(mm.get()); Chris@1573: } Chris@1573: mm.checkIntegrity(); Chris@1573: checkExpected(output, expected); Chris@1573: } Chris@1573: }; Chris@1573: Chris@1573: #endif