dev@1430: /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ dev@1430: dev@1430: /* dev@1430: Sonic Visualiser dev@1430: An audio file viewer and annotation editor. dev@1430: Centre for Digital Music, Queen Mary, University of London. dev@1438: This file copyright 2017 Queen Mary, University of London. dev@1430: dev@1430: This program is free software; you can redistribute it and/or dev@1430: modify it under the terms of the GNU General Public License as dev@1430: published by the Free Software Foundation; either version 2 of the dev@1430: License, or (at your option) any later version. See the file dev@1430: COPYING included with this distribution for more information. dev@1430: */ dev@1430: dev@1430: #ifndef TEST_CSV_STREAM_H dev@1430: #define TEST_CSV_STREAM_H dev@1430: dev@1434: #include dev@1430: #include dev@1434: #include dev@1434: #include dev@1434: dev@1434: #include "base/ProgressReporter.h" dev@1434: #include "base/DataExportOptions.h" dev@1446: #include "base/Selection.h" dev@1449: #include "data/model/NoteModel.h" dev@1430: #include "../CSVStreamWriter.h" dev@1434: #include "../../model/test/MockWaveModel.h" dev@1434: dev@1448: class StubReporter : public ProgressReporter dev@1434: { dev@1448: public: dev@1448: StubReporter( std::function isCancelled ) dev@1448: : m_isCancelled(isCancelled) {} dev@1448: bool isDefinite() const override { return true; } dev@1448: void setDefinite(bool) override {} dev@1448: bool wasCancelled() const override { return m_isCancelled(); } dev@1448: void setMessage(QString) override {} dev@1448: void setProgress(int p) override dev@1449: { dev@1448: ++m_calls; dev@1448: m_percentageLog.push_back(p); dev@1448: } dev@1440: dev@1448: size_t getCallCount() const { return m_calls; } dev@1448: std::vector getPercentageLog() const { return m_percentageLog; } dev@1448: void reset() { m_calls = 0; } dev@1448: private: dev@1448: size_t m_calls = 0; dev@1448: std::function m_isCancelled; dev@1448: std::vector m_percentageLog; dev@1448: }; dev@1430: dev@1430: class CSVStreamWriterTest : public QObject dev@1430: { dev@1430: Q_OBJECT dev@1430: public: dev@1434: std::string getExpectedString() dev@1434: { dev@1434: return dev@1434: { dev@1434: "0,0,0\n" dev@1434: "1,0,0\n" dev@1434: "2,0,0\n" dev@1434: "3,0,0\n" dev@1434: "4,1,1\n" dev@1434: "5,1,1\n" dev@1434: "6,1,1\n" dev@1434: "7,1,1\n" dev@1434: "8,1,1\n" dev@1434: "9,1,1\n" dev@1434: "10,1,1\n" dev@1434: "11,1,1\n" dev@1434: "12,1,1\n" dev@1434: "13,1,1\n" dev@1434: "14,1,1\n" dev@1434: "15,1,1\n" dev@1434: "16,1,1\n" dev@1434: "17,1,1\n" dev@1434: "18,1,1\n" dev@1434: "19,1,1\n" dev@1434: "20,0,0\n" dev@1434: "21,0,0\n" dev@1434: "22,0,0\n" dev@1434: "23,0,0" dev@1434: }; dev@1434: } dev@1430: dev@1430: private slots: dev@1434: void simpleValidOutput() dev@1430: { dev@1434: MockWaveModel mwm({ DC, DC }, 16, 4); dev@1430: dev@1434: std::ostringstream oss; dev@1438: const auto result = CSVStreamWriter::writeInChunks(oss, mwm); dev@1434: QVERIFY( oss.str() == getExpectedString() ); dev@1434: QVERIFY( result ); dev@1434: } dev@1434: dev@1434: void callsReporterCorrectTimes() dev@1434: { dev@1434: MockWaveModel mwm({ DC, DC }, 16, 4); dev@1434: StubReporter reporter { []() -> bool { return false; } }; dev@1434: const auto expected = getExpectedString(); dev@1434: dev@1434: std::ostringstream oss; dev@1434: const auto writeStreamWithBlockSize = [&](int blockSize) { dev@1438: return CSVStreamWriter::writeInChunks( dev@1434: oss, dev@1434: mwm, dev@1434: &reporter, dev@1434: ",", dev@1434: DataExportDefaults, dev@1434: blockSize dev@1434: ); dev@1434: }; dev@1434: dev@1434: const auto reset = [&]() { dev@1434: oss.str({}); dev@1434: reporter.reset(); dev@1434: }; dev@1434: dev@1434: const auto nonIntegerMultipleResult = writeStreamWithBlockSize(5); dev@1434: QVERIFY( nonIntegerMultipleResult ); dev@1434: QVERIFY( reporter.getCallCount() == 5 /* 4.8 rounded up */ ); dev@1434: QVERIFY( oss.str() == expected ); dev@1434: reset(); dev@1434: dev@1434: const auto integerMultiple = writeStreamWithBlockSize(2); dev@1434: QVERIFY( integerMultiple ); dev@1434: QVERIFY( reporter.getCallCount() == 12 ); dev@1434: QVERIFY( oss.str() == expected ); dev@1434: reset(); dev@1434: dev@1434: const auto largerThanNumberOfSamples = writeStreamWithBlockSize(100); dev@1434: QVERIFY( largerThanNumberOfSamples ); dev@1434: QVERIFY( reporter.getCallCount() == 1 ); dev@1434: QVERIFY( oss.str() == expected ); dev@1434: reset(); dev@1434: dev@1434: const auto zero = writeStreamWithBlockSize(0); dev@1434: QVERIFY( zero == false ); dev@1434: QVERIFY( reporter.getCallCount() == 0 ); dev@1434: } dev@1434: dev@1434: void isCancellable() dev@1434: { dev@1434: MockWaveModel mwm({ DC, DC }, 16, 4); dev@1434: StubReporter reporter { []() -> bool { return true; } }; dev@1434: dev@1434: std::ostringstream oss; dev@1438: const auto cancelImmediately = CSVStreamWriter::writeInChunks( dev@1434: oss, dev@1434: mwm, dev@1434: &reporter, dev@1434: ",", dev@1434: DataExportDefaults, dev@1434: 4 dev@1434: ); dev@1434: QVERIFY( cancelImmediately == false ); dev@1434: QVERIFY( reporter.getCallCount() == 0 ); dev@1434: dev@1434: StubReporter cancelMidway { dev@1434: [&]() { return cancelMidway.getCallCount() == 3; } dev@1434: }; dev@1438: const auto cancelledMidway = CSVStreamWriter::writeInChunks( dev@1434: oss, dev@1434: mwm, dev@1434: &cancelMidway, dev@1434: ",", dev@1434: DataExportDefaults, dev@1434: 4 dev@1434: ); dev@1434: QVERIFY( cancelMidway.getCallCount() == 3 ); dev@1434: QVERIFY( cancelledMidway == false ); dev@1430: } dev@1440: dev@1440: void zeroStartTimeReportsPercentageCorrectly() dev@1440: { dev@1440: MockWaveModel mwm({ DC, DC }, 16, 4); dev@1440: StubReporter reporter { []() -> bool { return false; } }; dev@1440: std::ostringstream oss; dev@1440: const auto succeeded = CSVStreamWriter::writeInChunks( dev@1440: oss, dev@1440: mwm, dev@1440: &reporter, dev@1440: ",", dev@1440: DataExportDefaults, dev@1440: 4 dev@1440: ); dev@1440: QVERIFY( succeeded == true ); dev@1440: QVERIFY( reporter.getCallCount() == 6 ); dev@1440: const std::vector expectedCallLog { dev@1440: 16, dev@1440: 33, dev@1440: 50, dev@1440: 66, dev@1440: 83, dev@1440: 100 dev@1440: }; dev@1440: QVERIFY( reporter.getPercentageLog() == expectedCallLog ); dev@1440: QVERIFY( oss.str() == getExpectedString() ); dev@1440: } dev@1440: dev@1440: void nonZeroStartTimeReportsPercentageCorrectly() dev@1440: { dev@1440: MockWaveModel mwm({ DC, DC }, 16, 4); dev@1440: StubReporter reporter { []() -> bool { return false; } }; dev@1440: std::ostringstream oss; dev@1440: const auto writeSubSection = CSVStreamWriter::writeInChunks( dev@1440: oss, dev@1440: mwm, dev@1440: {4, 20}, dev@1440: &reporter, dev@1440: ",", dev@1440: DataExportDefaults, dev@1440: 4 dev@1440: ); dev@1440: QVERIFY( reporter.getCallCount() == 4 ); dev@1440: const std::vector expectedCallLog { dev@1440: 25, dev@1440: 50, dev@1440: 75, dev@1440: 100 dev@1440: }; dev@1440: QVERIFY( reporter.getPercentageLog() == expectedCallLog ); dev@1440: QVERIFY( writeSubSection == true ); dev@1440: const std::string expectedOutput { dev@1440: "4,1,1\n" dev@1440: "5,1,1\n" dev@1440: "6,1,1\n" dev@1440: "7,1,1\n" dev@1440: "8,1,1\n" dev@1440: "9,1,1\n" dev@1440: "10,1,1\n" dev@1440: "11,1,1\n" dev@1440: "12,1,1\n" dev@1440: "13,1,1\n" dev@1440: "14,1,1\n" dev@1440: "15,1,1\n" dev@1440: "16,1,1\n" dev@1440: "17,1,1\n" dev@1440: "18,1,1\n" dev@1440: "19,1,1" dev@1440: }; dev@1440: QVERIFY( oss.str() == expectedOutput ); dev@1440: } dev@1446: dev@1446: void multipleSelectionOutput() dev@1446: { dev@1446: MockWaveModel mwm({ DC, DC }, 16, 4); dev@1446: StubReporter reporter { []() -> bool { return false; } }; dev@1446: std::ostringstream oss; dev@1446: MultiSelection regions; dev@1446: regions.addSelection({0, 2}); dev@1446: regions.addSelection({4, 6}); dev@1446: regions.addSelection({16, 18}); Chris@1494: // qDebug("End frame: %lld", (long long int)mwm.getEndFrame()); dev@1446: const std::string expectedOutput { dev@1446: "0,0,0\n" dev@1446: "1,0,0\n" dev@1446: "4,1,1\n" dev@1446: "5,1,1\n" dev@1446: "16,1,1\n" dev@1446: "17,1,1" dev@1446: }; dev@1446: const auto wroteMultiSection = CSVStreamWriter::writeInChunks( dev@1446: oss, dev@1446: mwm, dev@1446: regions, dev@1446: &reporter, dev@1446: ",", dev@1446: DataExportDefaults, dev@1446: 2 dev@1446: ); dev@1446: QVERIFY( wroteMultiSection == true ); dev@1446: QVERIFY( reporter.getCallCount() == 3 ); dev@1446: const std::vector expectedCallLog { 33, 66, 100 }; dev@1446: QVERIFY( reporter.getPercentageLog() == expectedCallLog ); Chris@1494: // qDebug("%s", oss.str().c_str()); dev@1446: QVERIFY( oss.str() == expectedOutput ); dev@1446: } dev@1449: dev@1449: void writeSparseModel() dev@1449: { dev@1449: const auto pentatonicFromRoot = [](float midiPitch) { dev@1449: return std::vector { dev@1449: 0 + midiPitch, dev@1449: 2 + midiPitch, dev@1449: 4 + midiPitch, dev@1449: 7 + midiPitch, dev@1449: 9 + midiPitch dev@1449: }; dev@1449: }; dev@1449: const auto cMajorPentatonic = pentatonicFromRoot(60.0); dev@1449: NoteModel notes(8 /* sampleRate */, 4 /* resolution */); dev@1449: sv_frame_t startFrame = 0; dev@1449: for (const auto& note : cMajorPentatonic) { Chris@1644: notes.add({startFrame, note, 4, 1.f, ""}); dev@1449: startFrame += 8; dev@1449: } Chris@1494: // qDebug("Create Expected Output\n"); dev@1449: dev@1449: // NB. removed end line break Chris@1679: const auto expectedOutput = Chris@1679: notes.toDelimitedDataString(",", {}, 0, notes.getEndFrame()) Chris@1679: .trimmed(); dev@1449: dev@1449: StubReporter reporter { []() -> bool { return false; } }; dev@1449: std::ostringstream oss; Chris@1494: // qDebug("End frame: %lld", (long long int)notes.getEndFrame()); Chris@1494: // qDebug("Write streaming\n"); dev@1449: const auto wroteSparseModel = CSVStreamWriter::writeInChunks( dev@1449: oss, dev@1449: notes, dev@1449: &reporter, dev@1449: ",", dev@1449: DataExportDefaults, dev@1449: 2 dev@1449: ); dev@1449: Chris@1609: // qDebug("\n->>%s<<-\n", expectedOutput.toLocal8Bit().data()); Chris@1609: // qDebug("\n->>%s<<-\n", oss.str().c_str()); dev@1449: QVERIFY( wroteSparseModel == true ); Chris@1679: QVERIFY( oss.str() != std::string() ); dev@1449: QVERIFY( oss.str() == expectedOutput.toStdString() ); dev@1449: } dev@1430: }; dev@1430: Chris@1454: #endif