1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2016 The Qt Company Ltd. |
4 | ** Contact: https://www.qt.io/licensing/ |
5 | ** |
6 | ** This file is part of the Qt Toolkit. |
7 | ** |
8 | ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ |
9 | ** Commercial License Usage |
10 | ** Licensees holding valid commercial Qt licenses may use this file in |
11 | ** accordance with the commercial license agreement provided with the |
12 | ** Software or, alternatively, in accordance with the terms contained in |
13 | ** a written agreement between you and The Qt Company. For licensing terms |
14 | ** and conditions see https://www.qt.io/terms-conditions. For further |
15 | ** information use the contact form at https://www.qt.io/contact-us. |
16 | ** |
17 | ** GNU General Public License Usage |
18 | ** Alternatively, this file may be used under the terms of the GNU |
19 | ** General Public License version 3 as published by the Free Software |
20 | ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT |
21 | ** included in the packaging of this file. Please review the following |
22 | ** information to ensure the GNU General Public License requirements will |
23 | ** be met: https://www.gnu.org/licenses/gpl-3.0.html. |
24 | ** |
25 | ** $QT_END_LICENSE$ |
26 | ** |
27 | ****************************************************************************/ |
28 | |
29 | //TESTED_COMPONENT=src/multimedia |
30 | |
31 | #include <QtTest/QtTest> |
32 | #include <private/qwavedecoder_p.h> |
33 | |
34 | #include <QNetworkAccessManager> |
35 | #include <QNetworkRequest> |
36 | #include <QNetworkReply> |
37 | |
38 | class tst_QWaveDecoder : public QObject |
39 | { |
40 | Q_OBJECT |
41 | public: |
42 | enum Corruption { |
43 | None = 1, |
44 | NotAWav = 2, |
45 | NoSampleData = 4, |
46 | FormatDescriptor = 8, |
47 | FormatString = 16, |
48 | DataDescriptor = 32 |
49 | }; |
50 | |
51 | public slots: |
52 | |
53 | void initTestCase(); |
54 | void cleanupTestCase(); |
55 | void init(); |
56 | void cleanup(); |
57 | |
58 | private slots: |
59 | |
60 | void file_data(); |
61 | void file(); |
62 | |
63 | void http_data() {file_data();} |
64 | void http(); |
65 | |
66 | void readAllAtOnce(); |
67 | void readPerByte(); |
68 | }; |
69 | |
70 | Q_DECLARE_METATYPE(tst_QWaveDecoder::Corruption) |
71 | |
72 | void tst_QWaveDecoder::init() |
73 | { |
74 | } |
75 | |
76 | void tst_QWaveDecoder::cleanup() |
77 | { |
78 | } |
79 | |
80 | void tst_QWaveDecoder::initTestCase() |
81 | { |
82 | } |
83 | |
84 | void tst_QWaveDecoder::cleanupTestCase() |
85 | { |
86 | } |
87 | |
88 | static QString testFilePath(const char *filename) |
89 | { |
90 | QString path = QString("data/%1" ).arg(a: filename); |
91 | return QFINDTESTDATA(path); |
92 | } |
93 | |
94 | void tst_QWaveDecoder::file_data() |
95 | { |
96 | QTest::addColumn<QString>(name: "file" ); |
97 | QTest::addColumn<tst_QWaveDecoder::Corruption>(name: "corruption" ); |
98 | QTest::addColumn<int>(name: "channels" ); |
99 | QTest::addColumn<int>(name: "samplesize" ); |
100 | QTest::addColumn<int>(name: "samplerate" ); |
101 | QTest::addColumn<QAudioFormat::Endian>(name: "byteorder" ); |
102 | |
103 | QTest::newRow(dataTag: "File is empty" ) << testFilePath(filename: "empty.wav" ) << tst_QWaveDecoder::NotAWav << -1 << -1 << -1 << QAudioFormat::LittleEndian; |
104 | QTest::newRow(dataTag: "File is one byte" ) << testFilePath(filename: "onebyte.wav" ) << tst_QWaveDecoder::NotAWav << -1 << -1 << -1 << QAudioFormat::LittleEndian; |
105 | QTest::newRow(dataTag: "File is not a wav(text)" ) << testFilePath(filename: "notawav.wav" ) << tst_QWaveDecoder::NotAWav << -1 << -1 << -1 << QAudioFormat::LittleEndian; |
106 | QTest::newRow(dataTag: "Wav file has no sample data" ) << testFilePath(filename: "nosampledata.wav" ) << tst_QWaveDecoder::NoSampleData << -1 << -1 << -1 << QAudioFormat::LittleEndian; |
107 | QTest::newRow(dataTag: "corrupt fmt chunk descriptor" ) << testFilePath(filename: "corrupt_fmtdesc_1_16_8000.le.wav" ) << tst_QWaveDecoder::FormatDescriptor << -1 << -1 << -1 << QAudioFormat::LittleEndian; |
108 | QTest::newRow(dataTag: "corrupt fmt string" ) << testFilePath(filename: "corrupt_fmtstring_1_16_8000.le.wav" ) << tst_QWaveDecoder::FormatString << -1 << -1 << -1 << QAudioFormat::LittleEndian; |
109 | QTest::newRow(dataTag: "corrupt data chunk descriptor" ) << testFilePath(filename: "corrupt_datadesc_1_16_8000.le.wav" ) << tst_QWaveDecoder::DataDescriptor << -1 << -1 << -1 << QAudioFormat::LittleEndian; |
110 | |
111 | QTest::newRow(dataTag: "File isawav_1_8_8000.wav" ) << testFilePath(filename: "isawav_1_8_8000.wav" ) << tst_QWaveDecoder::None << 1 << 8 << 8000 << QAudioFormat::LittleEndian; |
112 | QTest::newRow(dataTag: "File isawav_1_8_44100.wav" ) << testFilePath(filename: "isawav_1_8_44100.wav" ) << tst_QWaveDecoder::None << 1 << 8 << 44100 << QAudioFormat::LittleEndian; |
113 | QTest::newRow(dataTag: "File isawav_2_8_8000.wav" ) << testFilePath(filename: "isawav_2_8_8000.wav" ) << tst_QWaveDecoder::None << 2 << 8 << 8000 << QAudioFormat::LittleEndian; |
114 | QTest::newRow(dataTag: "File isawav_2_8_44100.wav" ) << testFilePath(filename: "isawav_2_8_44100.wav" ) << tst_QWaveDecoder::None << 2 << 8 << 44100 << QAudioFormat::LittleEndian; |
115 | |
116 | QTest::newRow(dataTag: "File isawav_1_16_8000_le.wav" ) << testFilePath(filename: "isawav_1_16_8000_le.wav" ) << tst_QWaveDecoder::None << 1 << 16 << 8000 << QAudioFormat::LittleEndian; |
117 | QTest::newRow(dataTag: "File isawav_1_16_44100_le.wav" ) << testFilePath(filename: "isawav_1_16_44100_le.wav" ) << tst_QWaveDecoder::None << 1 << 16 << 44100 << QAudioFormat::LittleEndian; |
118 | QTest::newRow(dataTag: "File isawav_2_16_8000_be.wav" ) << testFilePath(filename: "isawav_2_16_8000_be.wav" ) << tst_QWaveDecoder::None << 2 << 16 << 8000 << QAudioFormat::BigEndian; |
119 | QTest::newRow(dataTag: "File isawav_2_16_44100_be.wav" ) << testFilePath(filename: "isawav_2_16_44100_be.wav" ) << tst_QWaveDecoder::None << 2 << 16 << 44100 << QAudioFormat::BigEndian; |
120 | // The next file has extra data in the wave header. |
121 | QTest::newRow(dataTag: "File isawav_1_16_44100_le_2.wav" ) << testFilePath(filename: "isawav_1_16_44100_le_2.wav" ) << tst_QWaveDecoder::None << 1 << 16 << 44100 << QAudioFormat::LittleEndian; |
122 | |
123 | // 32 bit waves are not supported |
124 | QTest::newRow(dataTag: "File isawav_1_32_8000_le.wav" ) << testFilePath(filename: "isawav_1_32_8000_le.wav" ) << tst_QWaveDecoder::FormatDescriptor << 1 << 32 << 8000 << QAudioFormat::LittleEndian; |
125 | QTest::newRow(dataTag: "File isawav_1_32_44100_le.wav" ) << testFilePath(filename: "isawav_1_32_44100_le.wav" ) << tst_QWaveDecoder::FormatDescriptor << 1 << 32 << 44100 << QAudioFormat::LittleEndian; |
126 | QTest::newRow(dataTag: "File isawav_2_32_8000_be.wav" ) << testFilePath(filename: "isawav_2_32_8000_be.wav" ) << tst_QWaveDecoder::FormatDescriptor << 2 << 32 << 8000 << QAudioFormat::BigEndian; |
127 | QTest::newRow(dataTag: "File isawav_2_32_44100_be.wav" ) << testFilePath(filename: "isawav_2_32_44100_be.wav" ) << tst_QWaveDecoder::FormatDescriptor << 2 << 32 << 44100 << QAudioFormat::BigEndian; |
128 | } |
129 | |
130 | void tst_QWaveDecoder::file() |
131 | { |
132 | QFETCH(QString, file); |
133 | QFETCH(tst_QWaveDecoder::Corruption, corruption); |
134 | QFETCH(int, channels); |
135 | QFETCH(int, samplesize); |
136 | QFETCH(int, samplerate); |
137 | QFETCH(QAudioFormat::Endian, byteorder); |
138 | |
139 | QFile stream; |
140 | stream.setFileName(file); |
141 | stream.open(flags: QIODevice::ReadOnly); |
142 | |
143 | QVERIFY(stream.isOpen()); |
144 | |
145 | QWaveDecoder waveDecoder(&stream); |
146 | QSignalSpy validFormatSpy(&waveDecoder, SIGNAL(formatKnown())); |
147 | QSignalSpy parsingErrorSpy(&waveDecoder, SIGNAL(parsingError())); |
148 | |
149 | if (corruption == NotAWav) { |
150 | QSKIP("Not all failures detected correctly yet" ); |
151 | QTRY_COMPARE(parsingErrorSpy.count(), 1); |
152 | QCOMPARE(validFormatSpy.count(), 0); |
153 | } else if (corruption == NoSampleData) { |
154 | QTRY_COMPARE(validFormatSpy.count(), 1); |
155 | QCOMPARE(parsingErrorSpy.count(), 0); |
156 | QVERIFY(waveDecoder.audioFormat().isValid()); |
157 | QVERIFY(waveDecoder.size() == 0); |
158 | QVERIFY(waveDecoder.duration() == 0); |
159 | } else if (corruption == FormatDescriptor) { |
160 | QTRY_COMPARE(parsingErrorSpy.count(), 1); |
161 | QCOMPARE(validFormatSpy.count(), 0); |
162 | } else if (corruption == FormatString) { |
163 | QTRY_COMPARE(parsingErrorSpy.count(), 1); |
164 | QCOMPARE(validFormatSpy.count(), 0); |
165 | QVERIFY(!waveDecoder.audioFormat().isValid()); |
166 | } else if (corruption == DataDescriptor) { |
167 | QTRY_COMPARE(parsingErrorSpy.count(), 1); |
168 | QCOMPARE(validFormatSpy.count(), 0); |
169 | QVERIFY(waveDecoder.size() == 0); |
170 | } else if (corruption == None) { |
171 | QTRY_COMPARE(validFormatSpy.count(), 1); |
172 | QCOMPARE(parsingErrorSpy.count(), 0); |
173 | QVERIFY(waveDecoder.audioFormat().isValid()); |
174 | QVERIFY(waveDecoder.size() > 0); |
175 | QVERIFY(waveDecoder.duration() == 250); |
176 | QAudioFormat format = waveDecoder.audioFormat(); |
177 | QVERIFY(format.isValid()); |
178 | QVERIFY(format.channelCount() == channels); |
179 | QVERIFY(format.sampleSize() == samplesize); |
180 | QVERIFY(format.sampleRate() == samplerate); |
181 | if (format.sampleSize() != 8) { |
182 | QVERIFY(format.byteOrder() == byteorder); |
183 | } |
184 | } |
185 | |
186 | stream.close(); |
187 | } |
188 | |
189 | void tst_QWaveDecoder::http() |
190 | { |
191 | QFETCH(QString, file); |
192 | QFETCH(tst_QWaveDecoder::Corruption, corruption); |
193 | QFETCH(int, channels); |
194 | QFETCH(int, samplesize); |
195 | QFETCH(int, samplerate); |
196 | QFETCH(QAudioFormat::Endian, byteorder); |
197 | |
198 | QFile stream; |
199 | stream.setFileName(file); |
200 | stream.open(flags: QIODevice::ReadOnly); |
201 | |
202 | QVERIFY(stream.isOpen()); |
203 | |
204 | QNetworkAccessManager nam; |
205 | |
206 | QNetworkReply *reply = nam.get(request: QNetworkRequest(QUrl::fromLocalFile(localfile: file))); |
207 | |
208 | QWaveDecoder waveDecoder(reply); |
209 | QSignalSpy validFormatSpy(&waveDecoder, SIGNAL(formatKnown())); |
210 | QSignalSpy parsingErrorSpy(&waveDecoder, SIGNAL(parsingError())); |
211 | |
212 | if (corruption == NotAWav) { |
213 | QSKIP("Not all failures detected correctly yet" ); |
214 | QTRY_COMPARE(parsingErrorSpy.count(), 1); |
215 | QCOMPARE(validFormatSpy.count(), 0); |
216 | } else if (corruption == NoSampleData) { |
217 | QTRY_COMPARE(validFormatSpy.count(), 1); |
218 | QCOMPARE(parsingErrorSpy.count(), 0); |
219 | QVERIFY(waveDecoder.audioFormat().isValid()); |
220 | QVERIFY(waveDecoder.size() == 0); |
221 | QVERIFY(waveDecoder.duration() == 0); |
222 | } else if (corruption == FormatDescriptor) { |
223 | QTRY_COMPARE(parsingErrorSpy.count(), 1); |
224 | QCOMPARE(validFormatSpy.count(), 0); |
225 | } else if (corruption == FormatString) { |
226 | QTRY_COMPARE(parsingErrorSpy.count(), 1); |
227 | QCOMPARE(validFormatSpy.count(), 0); |
228 | QVERIFY(!waveDecoder.audioFormat().isValid()); |
229 | } else if (corruption == DataDescriptor) { |
230 | QTRY_COMPARE(parsingErrorSpy.count(), 1); |
231 | QCOMPARE(validFormatSpy.count(), 0); |
232 | QVERIFY(waveDecoder.size() == 0); |
233 | } else if (corruption == None) { |
234 | QTRY_COMPARE(validFormatSpy.count(), 1); |
235 | QCOMPARE(parsingErrorSpy.count(), 0); |
236 | QVERIFY(waveDecoder.audioFormat().isValid()); |
237 | QVERIFY(waveDecoder.size() > 0); |
238 | QVERIFY(waveDecoder.duration() == 250); |
239 | QAudioFormat format = waveDecoder.audioFormat(); |
240 | QVERIFY(format.isValid()); |
241 | QVERIFY(format.channelCount() == channels); |
242 | QVERIFY(format.sampleSize() == samplesize); |
243 | QVERIFY(format.sampleRate() == samplerate); |
244 | if (format.sampleSize() != 8) { |
245 | QVERIFY(format.byteOrder() == byteorder); |
246 | } |
247 | } |
248 | |
249 | delete reply; |
250 | } |
251 | |
252 | void tst_QWaveDecoder::readAllAtOnce() |
253 | { |
254 | QFile stream; |
255 | stream.setFileName(testFilePath(filename: "isawav_2_8_44100.wav" )); |
256 | stream.open(flags: QIODevice::ReadOnly); |
257 | |
258 | QVERIFY(stream.isOpen()); |
259 | |
260 | QWaveDecoder waveDecoder(&stream); |
261 | QSignalSpy validFormatSpy(&waveDecoder, SIGNAL(formatKnown())); |
262 | |
263 | QTRY_COMPARE(validFormatSpy.count(), 1); |
264 | QVERIFY(waveDecoder.size() > 0); |
265 | |
266 | QByteArray buffer; |
267 | buffer.resize(size: waveDecoder.size()); |
268 | |
269 | qint64 readSize = waveDecoder.read(data: buffer.data(), maxlen: waveDecoder.size()); |
270 | QVERIFY(readSize == waveDecoder.size()); |
271 | |
272 | readSize = waveDecoder.read(data: buffer.data(), maxlen: 1); |
273 | QVERIFY(readSize == 0); |
274 | |
275 | stream.close(); |
276 | } |
277 | |
278 | void tst_QWaveDecoder::readPerByte() |
279 | { |
280 | QFile stream; |
281 | stream.setFileName(testFilePath(filename: "isawav_2_8_44100.wav" )); |
282 | stream.open(flags: QIODevice::ReadOnly); |
283 | |
284 | QVERIFY(stream.isOpen()); |
285 | |
286 | QWaveDecoder waveDecoder(&stream); |
287 | QSignalSpy validFormatSpy(&waveDecoder, SIGNAL(formatKnown())); |
288 | |
289 | QTRY_COMPARE(validFormatSpy.count(), 1); |
290 | QVERIFY(waveDecoder.size() > 0); |
291 | |
292 | qint64 readSize = 0; |
293 | char buf; |
294 | for (int ii = 0; ii < waveDecoder.size(); ++ii) |
295 | readSize += waveDecoder.read(data: &buf, maxlen: 1); |
296 | QVERIFY(readSize == waveDecoder.size()); |
297 | QVERIFY(waveDecoder.read(&buf,1) == 0); |
298 | |
299 | stream.close(); |
300 | } |
301 | |
302 | QTEST_MAIN(tst_QWaveDecoder) |
303 | |
304 | #include "tst_qwavedecoder.moc" |
305 | |
306 | |