changeset 1698:dbd13eb7dad1

Add tests for audio file readers presented with empty or nonsense input
author Chris Cannam
date Fri, 03 May 2019 13:33:53 +0100
parents ea1aa24ebf89
children ad33d6c10738 5d4831c2e8aa
files data/fileio/AudioFileReaderFactory.cpp data/fileio/test/AudioFileReaderTest.h data/fileio/test/BogusAudioFileReaderTest.h data/fileio/test/EncodingTest.h data/fileio/test/UnsupportedFormat.h data/fileio/test/files.pri data/fileio/test/svcore-data-fileio-test.cpp
diffstat 7 files changed, 175 insertions(+), 31 deletions(-) [+]
line wrap: on
line diff
--- a/data/fileio/AudioFileReaderFactory.cpp	Tue Apr 23 16:17:13 2019 +0100
+++ b/data/fileio/AudioFileReaderFactory.cpp	Fri May 03 13:33:53 2019 +0100
@@ -78,12 +78,12 @@
     SVDEBUG << "AudioFileReaderFactory: local filename \"" << source.getLocalFilename() << "\", content type \"" << source.getContentType() << "\"" << endl;
 
     if (!source.isOK()) {
-        SVCERR << "AudioFileReaderFactory::createReader(\"" << source.getLocation() << "\": Failed to retrieve source (transmission error?): " << source.getErrorString() << endl;
+        SVDEBUG << "AudioFileReaderFactory::createReader(\"" << source.getLocation() << "\": Failed to retrieve source (transmission error?): " << source.getErrorString() << endl;
         return nullptr;
     }
 
     if (!source.isAvailable()) {
-        SVCERR << "AudioFileReaderFactory::createReader(\"" << source.getLocation() << "\": Source not found" << endl;
+        SVDEBUG << "AudioFileReaderFactory::createReader(\"" << source.getLocation() << "\": Source not found" << endl;
         return nullptr;
     }
 
@@ -213,11 +213,11 @@
         }
     }
     
-    SVCERR << "AudioFileReaderFactory::Failed to create a reader for "
-           << "url \"" << source.getLocation()
-           << "\" (local filename \"" << source.getLocalFilename()
-           << "\", content type \""
-           << source.getContentType() << "\")" << endl;
+    SVDEBUG << "AudioFileReaderFactory::Failed to create a reader for "
+            << "url \"" << source.getLocation()
+            << "\" (local filename \"" << source.getLocalFilename()
+            << "\", content type \""
+            << source.getContentType() << "\")" << endl;
     return nullptr;
 }
 
--- a/data/fileio/test/AudioFileReaderTest.h	Tue Apr 23 16:17:13 2019 +0100
+++ b/data/fileio/test/AudioFileReaderTest.h	Fri May 03 13:33:53 2019 +0100
@@ -21,6 +21,7 @@
 #include "../WavFileWriter.h"
 
 #include "AudioTestData.h"
+#include "UnsupportedFormat.h"
 
 #include <cmath>
 
@@ -73,7 +74,7 @@
             bitdepth = bits[2].toInt();
         }
     }
-    
+
     void getExpectedThresholds(QString format,
                                QString filename,
                                bool resampled,
@@ -305,11 +306,13 @@
             (audioDir + "/" + format + "/" + audiofile, params);
         
         if (!reader) {
+            if (isLegitimatelyUnsupported(format)) {
 #if ( QT_VERSION >= 0x050000 )
-            QSKIP("Unsupported file, skipping");
+                QSKIP("Unsupported file, skipping");
 #else
-            QSKIP("Unsupported file, skipping", SkipSingle);
+                QSKIP("Unsupported file, skipping", SkipSingle);
 #endif
+            }
         }
 
         QString extension;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/data/fileio/test/BogusAudioFileReaderTest.h	Fri May 03 13:33:53 2019 +0100
@@ -0,0 +1,94 @@
+/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
+
+/*
+    Sonic Visualiser
+    An audio file viewer and annotation editor.
+    Centre for Digital Music, Queen Mary, University of London.
+    
+    This program is free software; you can redistribute it and/or
+    modify it under the terms of the GNU General Public License as
+    published by the Free Software Foundation; either version 2 of the
+    License, or (at your option) any later version.  See the file
+    COPYING included with this distribution for more information.
+*/
+
+#ifndef SV_BOGUS_AUDIO_FILE_READER_TEST_H
+#define SV_BOGUS_AUDIO_FILE_READER_TEST_H
+
+#include "../AudioFileReaderFactory.h"
+
+#include "base/TempDirectory.h"
+
+#include <QObject>
+#include <QtTest>
+#include <QDir>
+
+// Tests for malformed audio files - primarily to ensure we don't crash
+
+class BogusAudioFileReaderTest : public QObject
+{
+    Q_OBJECT
+
+private slots:
+    void bogus_data()
+    {
+        QTest::addColumn<QString>("format");
+        QTest::addColumn<bool>("empty");
+        QStringList patterns = AudioFileReaderFactory::getKnownExtensions()
+            .split(" ", QString::SkipEmptyParts);
+
+        for (auto p: patterns) {
+
+            QStringList bits = p.split(".");
+            QString extension = bits[bits.size()-1];
+
+            QString testName = QString("%1, empty").arg(extension);
+            QTest::newRow(strdup(testName.toLocal8Bit().data()))
+                << extension << true;
+
+            testName = QString("%1, nonsense").arg(extension);
+            QTest::newRow(strdup(testName.toLocal8Bit().data()))
+                << extension << false;
+        }
+    }
+
+    void bogus()
+    {
+        QFETCH(QString, format);
+        QFETCH(bool, empty);
+
+        if (format == "au") { // au is headerless, so any file is legal
+#if ( QT_VERSION >= 0x050000 )
+            QSKIP("Skipping headerless file");
+#else
+            QSKIP("Skipping headerless file", SkipSingle);
+#endif
+        }
+            
+        QString tmpdir = TempDirectory::getInstance()->getPath();
+
+        QString path = QString("%1/%2.%3")
+            .arg(tmpdir)
+            .arg(empty ? "empty" : "nonsense")
+            .arg(format);
+        QFile f(path);
+        if (!f.open(QIODevice::WriteOnly)) {
+            std::cerr << "Failed to create temporary file "
+                      << path << std::endl;
+            throw std::runtime_error("Failed to create temporary file");
+        }
+        if (!empty) {
+            for (int i = 0; i < 1000; ++i) {
+                f.write("weeble");
+            }
+        }
+        f.close();
+
+        AudioFileReader *reader =
+            AudioFileReaderFactory::createReader(path, {});
+        QCOMPARE((void *)reader, nullptr);
+    }
+
+};
+
+#endif
--- a/data/fileio/test/EncodingTest.h	Tue Apr 23 16:17:13 2019 +0100
+++ b/data/fileio/test/EncodingTest.h	Fri May 03 13:33:53 2019 +0100
@@ -22,6 +22,8 @@
 #include "../AudioFileReader.h"
 #include "../WavFileWriter.h"
 
+#include "UnsupportedFormat.h"
+
 #include <cmath>
 
 #include <QObject>
@@ -132,13 +134,18 @@
         
         QFETCH(QString, audiofile);
 
+        QStringList fileAndExt = audiofile.split(".");
+        QString extension = fileAndExt[1];
+
         if (!AudioFileReaderFactory::isSupported(encodingDir + "/" +
                                                  audiofile)) {
+            if (isLegitimatelyUnsupported(extension)) {
 #if ( QT_VERSION >= 0x050000 )
-            QSKIP("Known unsupported file, skipping");
+                QSKIP("Known unsupported file, skipping");
 #else
-            QSKIP("Known unsupported file, skipping", SkipSingle);
+                QSKIP("Known unsupported file, skipping", SkipSingle);
 #endif
+            }
         }            
         
         AudioFileReaderFactory::Parameters params;
@@ -163,22 +170,26 @@
         
         QFETCH(QString, audiofile);
 
+        QStringList fileAndExt = audiofile.split(".");
+        QString file = fileAndExt[0];
+        QString extension = fileAndExt[1];
+
         AudioFileReaderFactory::Parameters params;
         AudioFileReader *reader =
             AudioFileReaderFactory::createReader
             (encodingDir + "/" + audiofile, params);
 
         if (!reader) {
+            if (isLegitimatelyUnsupported(extension)) {
 #if ( QT_VERSION >= 0x050000 )
-            QSKIP("Unsupported file, skipping");
+                QSKIP("Unsupported file, skipping");
 #else
-            QSKIP("Unsupported file, skipping", SkipSingle);
+                QSKIP("Unsupported file, skipping", SkipSingle);
 #endif
+            }
         }
 
-        QStringList fileAndExt = audiofile.split(".");
-        QString file = fileAndExt[0];
-        QString extension = fileAndExt[1];
+        QVERIFY(reader != nullptr);
 
         if (extension == "wav") {
 
@@ -188,12 +199,6 @@
 
         } else {
 
-//#if (!defined (HAVE_OGGZ) || !defined(HAVE_FISHSOUND))
-//            if (extension == "ogg") {
-//                QSKIP("Lack native Ogg Vorbis reader, so won't be getting metadata");
-//            }
-//#endif
-            
             auto blah = reader->getInterleavedFrames(0, 10);
             
             QString title = reader->getTitle();
@@ -261,25 +266,23 @@
             return;
         }
 
-//#if (!defined (HAVE_OGGZ) || !defined(HAVE_FISHSOUND))
-//        if (extension == "ogg") {
-//            QSKIP("Lack native Ogg Vorbis reader, so won't be getting metadata");
-//        }
-//#endif
-
         AudioFileReaderFactory::Parameters params;
         AudioFileReader *reader =
             AudioFileReaderFactory::createReader
             (encodingDir + "/" + audiofile, params);
         
         if (!reader) {
+            if (isLegitimatelyUnsupported(extension)) {
 #if ( QT_VERSION >= 0x050000 )
-            QSKIP("Unsupported file, skipping");
+                QSKIP("Unsupported file, skipping");
 #else
-            QSKIP("Unsupported file, skipping", SkipSingle);
+                QSKIP("Unsupported file, skipping", SkipSingle);
 #endif
+            }
         }
 
+        QVERIFY(reader != nullptr);
+
         QString title = reader->getTitle();
         QVERIFY(title != QString());
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/data/fileio/test/UnsupportedFormat.h	Fri May 03 13:33:53 2019 +0100
@@ -0,0 +1,35 @@
+/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
+
+/*
+    Sonic Visualiser
+    An audio file viewer and annotation editor.
+    Centre for Digital Music, Queen Mary, University of London.
+    This file copyright 2013 Chris Cannam.
+    
+    This program is free software; you can redistribute it and/or
+    modify it under the terms of the GNU General Public License as
+    published by the Free Software Foundation; either version 2 of the
+    License, or (at your option) any later version.  See the file
+    COPYING included with this distribution for more information.
+*/
+
+#ifndef SV_UNSUPPORTED_FORMAT_H
+#define SV_UNSUPPORTED_FORMAT_H
+
+static bool isLegitimatelyUnsupported(QString format) {
+
+#ifdef Q_OS_WIN
+    return (format == "apple_lossless");
+#else
+#ifdef Q_OS_MAC
+    return (format == "wma");
+#else
+    return (format == "aac" ||
+            format == "apple_lossless" ||
+            format == "m4a" ||
+            format == "wma");
+#endif
+#endif
+}
+
+#endif
--- a/data/fileio/test/files.pri	Tue Apr 23 16:17:13 2019 +0100
+++ b/data/fileio/test/files.pri	Fri May 03 13:33:53 2019 +0100
@@ -2,6 +2,8 @@
 TEST_HEADERS += \
 	../../model/test/MockWaveModel.h \
 	AudioFileReaderTest.h \
+	UnsupportedFormat.h \
+	BogusAudioFileReaderTest.h \
 	AudioFileWriterTest.h \
 	AudioTestData.h \
 	EncodingTest.h \
--- a/data/fileio/test/svcore-data-fileio-test.cpp	Tue Apr 23 16:17:13 2019 +0100
+++ b/data/fileio/test/svcore-data-fileio-test.cpp	Fri May 03 13:33:53 2019 +0100
@@ -13,6 +13,7 @@
 */
 
 #include "AudioFileReaderTest.h"
+#include "BogusAudioFileReaderTest.h"
 #include "AudioFileWriterTest.h"
 #include "EncodingTest.h"
 #include "MIDIFileReaderTest.h"
@@ -65,6 +66,12 @@
     }
 
     {
+        BogusAudioFileReaderTest t;
+        if (QTest::qExec(&t, argc, argv) == 0) ++good;
+        else ++bad;
+    }
+
+    {
         EncodingTest t(testDir);
         if (QTest::qExec(&t, argc, argv) == 0) ++good;
         else ++bad;