comparison data/fileio/test/CSVStreamWriterTest.h @ 1527:710e6250a401 zoom

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