annotate data/fileio/test/CSVStreamWriterTest.h @ 1752:6d09d68165a4 by-id

Further review of ById: make IDs only available when adding a model to the ById store, not by querying the item directly. This means any id encountered in the wild must have been added to the store at some point (even if later released), which simplifies reasoning about lifecycles
author Chris Cannam
date Fri, 05 Jul 2019 15:28:07 +0100
parents 0d89abd631ac
children 21c792334c2e
rev   line source
dev@1430 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
dev@1430 2
dev@1430 3 /*
dev@1430 4 Sonic Visualiser
dev@1430 5 An audio file viewer and annotation editor.
dev@1430 6 Centre for Digital Music, Queen Mary, University of London.
dev@1438 7 This file copyright 2017 Queen Mary, University of London.
dev@1430 8
dev@1430 9 This program is free software; you can redistribute it and/or
dev@1430 10 modify it under the terms of the GNU General Public License as
dev@1430 11 published by the Free Software Foundation; either version 2 of the
dev@1430 12 License, or (at your option) any later version. See the file
dev@1430 13 COPYING included with this distribution for more information.
dev@1430 14 */
dev@1430 15
dev@1430 16 #ifndef TEST_CSV_STREAM_H
dev@1430 17 #define TEST_CSV_STREAM_H
dev@1430 18
dev@1434 19 #include <QtTest>
dev@1430 20 #include <QObject>
dev@1434 21 #include <sstream>
dev@1434 22 #include <functional>
dev@1434 23
dev@1434 24 #include "base/ProgressReporter.h"
dev@1434 25 #include "base/DataExportOptions.h"
dev@1446 26 #include "base/Selection.h"
dev@1449 27 #include "data/model/NoteModel.h"
dev@1430 28 #include "../CSVStreamWriter.h"
dev@1434 29 #include "../../model/test/MockWaveModel.h"
dev@1434 30
dev@1448 31 class StubReporter : public ProgressReporter
dev@1434 32 {
dev@1448 33 public:
dev@1448 34 StubReporter( std::function<bool()> isCancelled )
dev@1448 35 : m_isCancelled(isCancelled) {}
dev@1448 36 bool isDefinite() const override { return true; }
dev@1448 37 void setDefinite(bool) override {}
dev@1448 38 bool wasCancelled() const override { return m_isCancelled(); }
dev@1448 39 void setMessage(QString) override {}
dev@1448 40 void setProgress(int p) override
dev@1449 41 {
dev@1448 42 ++m_calls;
dev@1448 43 m_percentageLog.push_back(p);
dev@1448 44 }
dev@1440 45
dev@1448 46 size_t getCallCount() const { return m_calls; }
dev@1448 47 std::vector<int> getPercentageLog() const { return m_percentageLog; }
dev@1448 48 void reset() { m_calls = 0; }
dev@1448 49 private:
dev@1448 50 size_t m_calls = 0;
dev@1448 51 std::function<bool()> m_isCancelled;
dev@1448 52 std::vector<int> m_percentageLog;
dev@1448 53 };
dev@1430 54
dev@1430 55 class CSVStreamWriterTest : public QObject
dev@1430 56 {
dev@1430 57 Q_OBJECT
dev@1430 58 public:
dev@1434 59 std::string getExpectedString()
dev@1434 60 {
dev@1434 61 return
dev@1434 62 {
dev@1434 63 "0,0,0\n"
dev@1434 64 "1,0,0\n"
dev@1434 65 "2,0,0\n"
dev@1434 66 "3,0,0\n"
dev@1434 67 "4,1,1\n"
dev@1434 68 "5,1,1\n"
dev@1434 69 "6,1,1\n"
dev@1434 70 "7,1,1\n"
dev@1434 71 "8,1,1\n"
dev@1434 72 "9,1,1\n"
dev@1434 73 "10,1,1\n"
dev@1434 74 "11,1,1\n"
dev@1434 75 "12,1,1\n"
dev@1434 76 "13,1,1\n"
dev@1434 77 "14,1,1\n"
dev@1434 78 "15,1,1\n"
dev@1434 79 "16,1,1\n"
dev@1434 80 "17,1,1\n"
dev@1434 81 "18,1,1\n"
dev@1434 82 "19,1,1\n"
dev@1434 83 "20,0,0\n"
dev@1434 84 "21,0,0\n"
dev@1434 85 "22,0,0\n"
dev@1434 86 "23,0,0"
dev@1434 87 };
dev@1434 88 }
dev@1430 89
dev@1430 90 private slots:
dev@1434 91 void simpleValidOutput()
dev@1430 92 {
dev@1434 93 MockWaveModel mwm({ DC, DC }, 16, 4);
dev@1430 94
dev@1434 95 std::ostringstream oss;
dev@1438 96 const auto result = CSVStreamWriter::writeInChunks(oss, mwm);
dev@1434 97 QVERIFY( oss.str() == getExpectedString() );
dev@1434 98 QVERIFY( result );
dev@1434 99 }
dev@1434 100
dev@1434 101 void callsReporterCorrectTimes()
dev@1434 102 {
dev@1434 103 MockWaveModel mwm({ DC, DC }, 16, 4);
dev@1434 104 StubReporter reporter { []() -> bool { return false; } };
dev@1434 105 const auto expected = getExpectedString();
dev@1434 106
dev@1434 107 std::ostringstream oss;
dev@1434 108 const auto writeStreamWithBlockSize = [&](int blockSize) {
dev@1438 109 return CSVStreamWriter::writeInChunks(
dev@1434 110 oss,
dev@1434 111 mwm,
dev@1434 112 &reporter,
dev@1434 113 ",",
dev@1434 114 DataExportDefaults,
dev@1434 115 blockSize
dev@1434 116 );
dev@1434 117 };
dev@1434 118
dev@1434 119 const auto reset = [&]() {
dev@1434 120 oss.str({});
dev@1434 121 reporter.reset();
dev@1434 122 };
dev@1434 123
dev@1434 124 const auto nonIntegerMultipleResult = writeStreamWithBlockSize(5);
dev@1434 125 QVERIFY( nonIntegerMultipleResult );
dev@1434 126 QVERIFY( reporter.getCallCount() == 5 /* 4.8 rounded up */ );
dev@1434 127 QVERIFY( oss.str() == expected );
dev@1434 128 reset();
dev@1434 129
dev@1434 130 const auto integerMultiple = writeStreamWithBlockSize(2);
dev@1434 131 QVERIFY( integerMultiple );
dev@1434 132 QVERIFY( reporter.getCallCount() == 12 );
dev@1434 133 QVERIFY( oss.str() == expected );
dev@1434 134 reset();
dev@1434 135
dev@1434 136 const auto largerThanNumberOfSamples = writeStreamWithBlockSize(100);
dev@1434 137 QVERIFY( largerThanNumberOfSamples );
dev@1434 138 QVERIFY( reporter.getCallCount() == 1 );
dev@1434 139 QVERIFY( oss.str() == expected );
dev@1434 140 reset();
dev@1434 141
dev@1434 142 const auto zero = writeStreamWithBlockSize(0);
dev@1434 143 QVERIFY( zero == false );
dev@1434 144 QVERIFY( reporter.getCallCount() == 0 );
dev@1434 145 }
dev@1434 146
dev@1434 147 void isCancellable()
dev@1434 148 {
dev@1434 149 MockWaveModel mwm({ DC, DC }, 16, 4);
dev@1434 150 StubReporter reporter { []() -> bool { return true; } };
dev@1434 151
dev@1434 152 std::ostringstream oss;
dev@1438 153 const auto cancelImmediately = CSVStreamWriter::writeInChunks(
dev@1434 154 oss,
dev@1434 155 mwm,
dev@1434 156 &reporter,
dev@1434 157 ",",
dev@1434 158 DataExportDefaults,
dev@1434 159 4
dev@1434 160 );
dev@1434 161 QVERIFY( cancelImmediately == false );
dev@1434 162 QVERIFY( reporter.getCallCount() == 0 );
dev@1434 163
dev@1434 164 StubReporter cancelMidway {
dev@1434 165 [&]() { return cancelMidway.getCallCount() == 3; }
dev@1434 166 };
dev@1438 167 const auto cancelledMidway = CSVStreamWriter::writeInChunks(
dev@1434 168 oss,
dev@1434 169 mwm,
dev@1434 170 &cancelMidway,
dev@1434 171 ",",
dev@1434 172 DataExportDefaults,
dev@1434 173 4
dev@1434 174 );
dev@1434 175 QVERIFY( cancelMidway.getCallCount() == 3 );
dev@1434 176 QVERIFY( cancelledMidway == false );
dev@1430 177 }
dev@1440 178
dev@1440 179 void zeroStartTimeReportsPercentageCorrectly()
dev@1440 180 {
dev@1440 181 MockWaveModel mwm({ DC, DC }, 16, 4);
dev@1440 182 StubReporter reporter { []() -> bool { return false; } };
dev@1440 183 std::ostringstream oss;
dev@1440 184 const auto succeeded = CSVStreamWriter::writeInChunks(
dev@1440 185 oss,
dev@1440 186 mwm,
dev@1440 187 &reporter,
dev@1440 188 ",",
dev@1440 189 DataExportDefaults,
dev@1440 190 4
dev@1440 191 );
dev@1440 192 QVERIFY( succeeded == true );
dev@1440 193 QVERIFY( reporter.getCallCount() == 6 );
dev@1440 194 const std::vector<int> expectedCallLog {
dev@1440 195 16,
dev@1440 196 33,
dev@1440 197 50,
dev@1440 198 66,
dev@1440 199 83,
dev@1440 200 100
dev@1440 201 };
dev@1440 202 QVERIFY( reporter.getPercentageLog() == expectedCallLog );
dev@1440 203 QVERIFY( oss.str() == getExpectedString() );
dev@1440 204 }
dev@1440 205
dev@1440 206 void nonZeroStartTimeReportsPercentageCorrectly()
dev@1440 207 {
dev@1440 208 MockWaveModel mwm({ DC, DC }, 16, 4);
dev@1440 209 StubReporter reporter { []() -> bool { return false; } };
dev@1440 210 std::ostringstream oss;
dev@1440 211 const auto writeSubSection = CSVStreamWriter::writeInChunks(
dev@1440 212 oss,
dev@1440 213 mwm,
dev@1440 214 {4, 20},
dev@1440 215 &reporter,
dev@1440 216 ",",
dev@1440 217 DataExportDefaults,
dev@1440 218 4
dev@1440 219 );
dev@1440 220 QVERIFY( reporter.getCallCount() == 4 );
dev@1440 221 const std::vector<int> expectedCallLog {
dev@1440 222 25,
dev@1440 223 50,
dev@1440 224 75,
dev@1440 225 100
dev@1440 226 };
dev@1440 227 QVERIFY( reporter.getPercentageLog() == expectedCallLog );
dev@1440 228 QVERIFY( writeSubSection == true );
dev@1440 229 const std::string expectedOutput {
dev@1440 230 "4,1,1\n"
dev@1440 231 "5,1,1\n"
dev@1440 232 "6,1,1\n"
dev@1440 233 "7,1,1\n"
dev@1440 234 "8,1,1\n"
dev@1440 235 "9,1,1\n"
dev@1440 236 "10,1,1\n"
dev@1440 237 "11,1,1\n"
dev@1440 238 "12,1,1\n"
dev@1440 239 "13,1,1\n"
dev@1440 240 "14,1,1\n"
dev@1440 241 "15,1,1\n"
dev@1440 242 "16,1,1\n"
dev@1440 243 "17,1,1\n"
dev@1440 244 "18,1,1\n"
dev@1440 245 "19,1,1"
dev@1440 246 };
dev@1440 247 QVERIFY( oss.str() == expectedOutput );
dev@1440 248 }
dev@1446 249
dev@1446 250 void multipleSelectionOutput()
dev@1446 251 {
dev@1446 252 MockWaveModel mwm({ DC, DC }, 16, 4);
dev@1446 253 StubReporter reporter { []() -> bool { return false; } };
dev@1446 254 std::ostringstream oss;
dev@1446 255 MultiSelection regions;
dev@1446 256 regions.addSelection({0, 2});
dev@1446 257 regions.addSelection({4, 6});
dev@1446 258 regions.addSelection({16, 18});
Chris@1494 259 // qDebug("End frame: %lld", (long long int)mwm.getEndFrame());
dev@1446 260 const std::string expectedOutput {
dev@1446 261 "0,0,0\n"
dev@1446 262 "1,0,0\n"
dev@1446 263 "4,1,1\n"
dev@1446 264 "5,1,1\n"
dev@1446 265 "16,1,1\n"
dev@1446 266 "17,1,1"
dev@1446 267 };
dev@1446 268 const auto wroteMultiSection = CSVStreamWriter::writeInChunks(
dev@1446 269 oss,
dev@1446 270 mwm,
dev@1446 271 regions,
dev@1446 272 &reporter,
dev@1446 273 ",",
dev@1446 274 DataExportDefaults,
dev@1446 275 2
dev@1446 276 );
dev@1446 277 QVERIFY( wroteMultiSection == true );
dev@1446 278 QVERIFY( reporter.getCallCount() == 3 );
dev@1446 279 const std::vector<int> expectedCallLog { 33, 66, 100 };
dev@1446 280 QVERIFY( reporter.getPercentageLog() == expectedCallLog );
Chris@1494 281 // qDebug("%s", oss.str().c_str());
dev@1446 282 QVERIFY( oss.str() == expectedOutput );
dev@1446 283 }
dev@1449 284
dev@1449 285 void writeSparseModel()
dev@1449 286 {
dev@1449 287 const auto pentatonicFromRoot = [](float midiPitch) {
dev@1449 288 return std::vector<float> {
dev@1449 289 0 + midiPitch,
dev@1449 290 2 + midiPitch,
dev@1449 291 4 + midiPitch,
dev@1449 292 7 + midiPitch,
dev@1449 293 9 + midiPitch
dev@1449 294 };
dev@1449 295 };
dev@1449 296 const auto cMajorPentatonic = pentatonicFromRoot(60.0);
dev@1449 297 NoteModel notes(8 /* sampleRate */, 4 /* resolution */);
dev@1449 298 sv_frame_t startFrame = 0;
dev@1449 299 for (const auto& note : cMajorPentatonic) {
Chris@1644 300 notes.add({startFrame, note, 4, 1.f, ""});
dev@1449 301 startFrame += 8;
dev@1449 302 }
Chris@1494 303 // qDebug("Create Expected Output\n");
dev@1449 304
dev@1449 305 // NB. removed end line break
Chris@1679 306 const auto expectedOutput =
Chris@1679 307 notes.toDelimitedDataString(",", {}, 0, notes.getEndFrame())
Chris@1679 308 .trimmed();
dev@1449 309
dev@1449 310 StubReporter reporter { []() -> bool { return false; } };
dev@1449 311 std::ostringstream oss;
Chris@1494 312 // qDebug("End frame: %lld", (long long int)notes.getEndFrame());
Chris@1494 313 // qDebug("Write streaming\n");
dev@1449 314 const auto wroteSparseModel = CSVStreamWriter::writeInChunks(
dev@1449 315 oss,
dev@1449 316 notes,
dev@1449 317 &reporter,
dev@1449 318 ",",
dev@1449 319 DataExportDefaults,
dev@1449 320 2
dev@1449 321 );
dev@1449 322
Chris@1609 323 // qDebug("\n->>%s<<-\n", expectedOutput.toLocal8Bit().data());
Chris@1609 324 // qDebug("\n->>%s<<-\n", oss.str().c_str());
dev@1449 325 QVERIFY( wroteSparseModel == true );
Chris@1679 326 QVERIFY( oss.str() != std::string() );
dev@1449 327 QVERIFY( oss.str() == expectedOutput.toStdString() );
dev@1449 328 }
dev@1430 329 };
dev@1430 330
Chris@1454 331 #endif