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
38class tst_QWaveDecoder : public QObject
39{
40 Q_OBJECT
41public:
42 enum Corruption {
43 None = 1,
44 NotAWav = 2,
45 NoSampleData = 4,
46 FormatDescriptor = 8,
47 FormatString = 16,
48 DataDescriptor = 32
49 };
50
51public slots:
52
53 void initTestCase();
54 void cleanupTestCase();
55 void init();
56 void cleanup();
57
58private 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
70Q_DECLARE_METATYPE(tst_QWaveDecoder::Corruption)
71
72void tst_QWaveDecoder::init()
73{
74}
75
76void tst_QWaveDecoder::cleanup()
77{
78}
79
80void tst_QWaveDecoder::initTestCase()
81{
82}
83
84void tst_QWaveDecoder::cleanupTestCase()
85{
86}
87
88static QString testFilePath(const char *filename)
89{
90 QString path = QString("data/%1").arg(a: filename);
91 return QFINDTESTDATA(path);
92}
93
94void 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
130void 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
189void 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
252void 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
278void 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
302QTEST_MAIN(tst_QWaveDecoder)
303
304#include "tst_qwavedecoder.moc"
305
306

source code of qtmultimedia/tests/auto/unit/qwavedecoder/tst_qwavedecoder.cpp