Mercurial > hg > vamp-plugin-tester
changeset 0:f89128a316e7
* Commit beginnings of a Vamp plugin test program
author | cannam |
---|---|
date | Thu, 12 Mar 2009 16:23:55 +0000 |
parents | |
children | d7ef749300ed |
files | Makefile Test.cpp Test.h TestStaticData.cpp TestStaticData.h Tester.cpp Tester.h vamp-plugin-tester.cpp |
diffstat | 8 files changed, 881 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Makefile Thu Mar 12 16:23:55 2009 +0000 @@ -0,0 +1,25 @@ + +LDFLAGS += -lvamp-hostsdk -ldl +CXXFLAGS += -Wall -Wextra + +OBJECTS := vamp-plugin-tester.o Tester.o Test.o TestStaticData.o + +vamp-plugin-tester: $(OBJECTS) + +clean: + rm -f $(OBJECTS) + +distclean: clean + rm -f *~ vamp-plugin-tester + +depend: + makedepend -Y *.cpp *.h + +# DO NOT DELETE + +Test.o: Test.h +TestStaticData.o: TestStaticData.h Test.h Tester.h +Tester.o: Tester.h Test.h +vamp-plugin-tester.o: Tester.h Test.h +TestStaticData.o: Test.h Tester.h +Tester.o: Test.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Test.cpp Thu Mar 12 16:23:55 2009 +0000 @@ -0,0 +1,105 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + Vamp Plugin Fuzz Tester + Chris Cannam, cannam@all-day-breakfast.com + Centre for Digital Music, Queen Mary, University of London. + Copyright 2009 QMUL. + + This program loads a Vamp plugin and tests its susceptibility to a + number of common pitfalls, including handling of extremes of input + data. If you can think of any additional useful tests that are + easily added, please send them to me. + + Permission is hereby granted, free of charge, to any person + obtaining a copy of this software and associated documentation + files (the "Software"), to deal in the Software without + restriction, including without limitation the rights to use, copy, + modify, merge, publish, distribute, sublicense, and/or sell copies + of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR + ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the names of the Centre for + Digital Music; Queen Mary, University of London; and Chris Cannam + shall not be used in advertising or otherwise to promote the sale, + use or other dealings in this Software without prior written + authorization. +*/ + +#include "Test.h" + +#include <vamp-hostsdk/PluginLoader.h> + +using namespace Vamp; +using namespace Vamp::HostExt; + +Test::Test() { } +Test::~Test() { } + +Plugin * +Test::load(std::string key, float rate) +{ + return PluginLoader::getInstance()->loadPlugin + (key, rate, PluginLoader::ADAPT_ALL); +} + +void +Test::appendFeatures(Plugin::FeatureSet &a, const Plugin::FeatureSet &b) +{ + for (Plugin::FeatureSet::const_iterator i = b.begin(); i != b.end(); ++i) { + int output = i->first; + const Plugin::FeatureList &fl = i->second; + Plugin::FeatureList &target = a[output]; + for (Plugin::FeatureList::const_iterator j = fl.begin(); j != fl.end(); ++j) { + target.push_back(*j); + } + } +} + +bool +operator==(const Plugin::FeatureSet &a, const Plugin::FeatureSet &b) +{ + if (a.size() != b.size()) return false; + for (Plugin::FeatureSet::const_iterator ai = a.begin(); + ai != a.end(); ++ai) { + int output = ai->first; + Plugin::FeatureSet::const_iterator bi = b.find(output); + if (bi == b.end()) return false; + if (!(ai->second == bi->second)) return false; + } + return true; +} + +bool +operator==(const Plugin::FeatureList &a, const Plugin::FeatureList &b) +{ + if (a.size() != b.size()) return false; + for (int i = 0; i < (int)a.size(); ++i) { + if (!(a[i] == b[i])) return false; + } + return true; +} + +bool +operator==(const Plugin::Feature &a, const Plugin::Feature &b) +{ + if (a.hasTimestamp != b.hasTimestamp) return false; + if (a.hasTimestamp && (a.timestamp != b.timestamp)) return false; + if (a.hasDuration != b.hasDuration) return false; + if (a.hasDuration && (a.duration != b.duration)) return false; + if (a.values != b.values) return false; + if (a.label != b.label) return false; + return true; +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Test.h Thu Mar 12 16:23:55 2009 +0000 @@ -0,0 +1,96 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + Vamp Plugin Tester + Chris Cannam, cannam@all-day-breakfast.com + Centre for Digital Music, Queen Mary, University of London. + Copyright 2009 QMUL. + + This program loads a Vamp plugin and tests its susceptibility to a + number of common pitfalls, including handling of extremes of input + data. If you can think of any additional useful tests that are + easily added, please send them to me. + + Permission is hereby granted, free of charge, to any person + obtaining a copy of this software and associated documentation + files (the "Software"), to deal in the Software without + restriction, including without limitation the rights to use, copy, + modify, merge, publish, distribute, sublicense, and/or sell copies + of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR + ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the names of the Centre for + Digital Music; Queen Mary, University of London; and Chris Cannam + shall not be used in advertising or otherwise to promote the sale, + use or other dealings in this Software without prior written + authorization. +*/ + +#ifndef _TEST_H_ +#define _TEST_H_ + +#include <string> + +#include <vamp-hostsdk/Plugin.h> + +class Test +{ +public: + virtual ~Test(); + + class Result { + + public: + enum Code { Success, Warning, Error }; + + Result(Code c, std::string m) : m_code(c), m_message(m) { } + + Code code() { return m_code; } + std::string message() { return m_message; } + + protected: + Code m_code; + std::string m_message; + }; + + static Result success() { return Result(Result::Success, ""); } + static Result warning(std::string m) { return Result(Result::Warning, m); } + static Result error(std::string m) { return Result(Result::Error, m); } + + typedef std::vector<Result> Results; + + class FailedToLoadPlugin { }; + + // may throw FailedToLoadPlugin + virtual Results test(std::string key) = 0; + +protected: + Test(); + + // may throw FailedToLoadPlugin + Vamp::Plugin *load(std::string key, float rate = 44100); + + void appendFeatures(Vamp::Plugin::FeatureSet &a, + const Vamp::Plugin::FeatureSet &b); +}; + +extern bool operator==(const Vamp::Plugin::FeatureSet &a, + const Vamp::Plugin::FeatureSet &b); +extern bool operator==(const Vamp::Plugin::FeatureList &a, + const Vamp::Plugin::FeatureList &b); +extern bool operator==(const Vamp::Plugin::Feature &a, + const Vamp::Plugin::Feature &b); + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/TestStaticData.cpp Thu Mar 12 16:23:55 2009 +0000 @@ -0,0 +1,201 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + Vamp Plugin Tester + Chris Cannam, cannam@all-day-breakfast.com + Centre for Digital Music, Queen Mary, University of London. + Copyright 2009 QMUL. + + This program loads a Vamp plugin and tests its susceptibility to a + number of common pitfalls, including handling of extremes of input + data. If you can think of any additional useful tests that are + easily added, please send them to me. + + Permission is hereby granted, free of charge, to any person + obtaining a copy of this software and associated documentation + files (the "Software"), to deal in the Software without + restriction, including without limitation the rights to use, copy, + modify, merge, publish, distribute, sublicense, and/or sell copies + of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR + ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the names of the Centre for + Digital Music; Queen Mary, University of London; and Chris Cannam + shall not be used in advertising or otherwise to promote the sale, + use or other dealings in this Software without prior written + authorization. +*/ + +#include "TestStaticData.h" + +#include <vamp-hostsdk/Plugin.h> +using namespace Vamp; + +#include <memory> +using namespace std; + +#include <cmath> + +Tester::TestRegistrar<TestIdentifiers> +TestIdentifiers::m_registrar("Invalid identifiers"); + +Tester::TestRegistrar<TestEmptyFields> +TestEmptyFields::m_registrar("Empty metadata fields"); + +Tester::TestRegistrar<TestValueRanges> +TestValueRanges::m_registrar("Inappropriate value extents"); + +Test::Results +TestIdentifiers::test(string key) +{ + auto_ptr<Plugin> p(load(key)); + + Results r; + r.push_back(testIdentifier(p->getIdentifier(), "plugin identifier")); + + Plugin::ParameterList params = p->getParameterDescriptors(); + for (int i = 0; i < (int)params.size(); ++i) { + r.push_back(testIdentifier(params[i].identifier, "parameter identifier")); + } + + Plugin::OutputList outputs = p->getOutputDescriptors(); + for (int i = 0; i < (int)outputs.size(); ++i) { + r.push_back(testIdentifier(outputs[i].identifier, "output identifier")); + } + + return r; +} + +Test::Result +TestIdentifiers::testIdentifier(string identifier, string desc) +{ + for (int i = 0; i < (int)identifier.length(); ++i) { + char c = identifier[i]; + if (c >= 'a' && c <= 'z') continue; + if (c >= 'A' && c <= 'Z') continue; + if (c >= '0' && c <= '9') continue; + if (c == '_' || c == '-') continue; + return error + (desc + " \"" + identifier + + "\" contains invalid character(s); permitted are: [a-zA-Z0-9_-]"); + } + return success(); +} + +Test::Results +TestEmptyFields::test(string key) +{ + auto_ptr<Plugin> p(load(key)); + + Results r; + + r.push_back(testMandatory(p->getName(), "plugin name")); + r.push_back(testRecommended(p->getDescription(), "plugin description")); + r.push_back(testRecommended(p->getMaker(), "plugin maker")); + r.push_back(testRecommended(p->getCopyright(), "plugin copyright")); + + Plugin::ParameterList params = p->getParameterDescriptors(); + for (int i = 0; i < (int)params.size(); ++i) { + r.push_back(testMandatory + (params[i].name, + "plugin parameter \"" + params[i].identifier + "\" name")); + r.push_back(testRecommended + (params[i].description, + "plugin parameter \"" + params[i].identifier + "\" description")); + } + + Plugin::OutputList outputs = p->getOutputDescriptors(); + for (int i = 0; i < (int)outputs.size(); ++i) { + r.push_back(testMandatory + (outputs[i].name, + "plugin output \"" + outputs[i].identifier + "\" name")); + r.push_back(testRecommended + (outputs[i].description, + "plugin output \"" + outputs[i].identifier + "\" description")); + } + + return r; +} + +Test::Result +TestEmptyFields::testMandatory(string text, string desc) +{ + if (text == "") { + return error(desc + " is empty"); + } + return success(); +} + +Test::Result +TestEmptyFields::testRecommended(string text, string desc) +{ + if (text == "") { + return warning(desc + " is empty"); + } + return success(); +} + +Test::Results +TestValueRanges::test(string key) +{ + auto_ptr<Plugin> p(load(key)); + + Results r; + + Plugin::ParameterList params = p->getParameterDescriptors(); + for (int i = 0; i < (int)params.size(); ++i) { + Plugin::ParameterDescriptor &pd(params[i]); + string pfx("plugin parameter \"" + pd.identifier + "\""); + float min = pd.minValue; + float max = pd.maxValue; + float deft = pd.defaultValue; + if (max <= min) { + r.push_back(error(pfx + " maxValue <= minValue")); + } + if (deft < min || deft > max) { + r.push_back(error(pfx + " defaultValue out of range")); + } + if (pd.isQuantized) { + if (pd.quantizeStep == 0.f) { + r.push_back(error(pfx + " is quantized, but quantize step is zero")); + } else { + + float epsilon = 0.00001f; + int qty = int((max - min) / pd.quantizeStep + 0.5); + float target = min + pd.quantizeStep * qty; + if (fabsf(max - target) > epsilon) { + r.push_back(warning(pfx + " value range is not a multiple of quantize step")); + } + + if (!pd.valueNames.empty()) { + if ((int)pd.valueNames.size() < qty+1) { + r.push_back(warning(pfx + " has fewer value names than quantize steps")); + } else if ((int)pd.valueNames.size() > qty+1) { + r.push_back(warning(pfx + " has more value names than quantize steps")); + } + } + + qty = int((deft - min) / pd.quantizeStep + 0.5); + target = min + pd.quantizeStep * qty; + if (fabsf(deft - target) > epsilon) { + r.push_back(warning(pfx + " default value is not a multiple of quantize step beyond minimum")); + } + } + } + } + + return r; +} + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/TestStaticData.h Thu Mar 12 16:23:55 2009 +0000 @@ -0,0 +1,79 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + Vamp Plugin Tester + Chris Cannam, cannam@all-day-breakfast.com + Centre for Digital Music, Queen Mary, University of London. + Copyright 2009 QMUL. + + This program loads a Vamp plugin and tests its susceptibility to a + number of common pitfalls, including handling of extremes of input + data. If you can think of any additional useful tests that are + easily added, please send them to me. + + Permission is hereby granted, free of charge, to any person + obtaining a copy of this software and associated documentation + files (the "Software"), to deal in the Software without + restriction, including without limitation the rights to use, copy, + modify, merge, publish, distribute, sublicense, and/or sell copies + of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR + ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the names of the Centre for + Digital Music; Queen Mary, University of London; and Chris Cannam + shall not be used in advertising or otherwise to promote the sale, + use or other dealings in this Software without prior written + authorization. +*/ + +#ifndef _TEST_STATIC_DATA_H_ +#define _TEST_STATIC_DATA_H_ + +#include "Test.h" +#include "Tester.h" + +class TestIdentifiers : public Test +{ +public: + TestIdentifiers() : Test() { } + Results test(std::string key); + +protected: + Result testIdentifier(std::string ident, std::string desc); + static Tester::TestRegistrar<TestIdentifiers> m_registrar; +}; + +class TestEmptyFields : public Test +{ +public: + TestEmptyFields() : Test() { } + Results test(std::string key); + +protected: + Result testMandatory(std::string text, std::string desc); + Result testRecommended(std::string text, std::string desc); + static Tester::TestRegistrar<TestEmptyFields> m_registrar; +}; + +class TestValueRanges : public Test +{ +public: + TestValueRanges() : Test() { } + Results test(std::string key); + +protected: + static Tester::TestRegistrar<TestValueRanges> m_registrar; +}; + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Tester.cpp Thu Mar 12 16:23:55 2009 +0000 @@ -0,0 +1,177 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + Vamp Plugin Tester + Chris Cannam, cannam@all-day-breakfast.com + Centre for Digital Music, Queen Mary, University of London. + Copyright 2009 QMUL. + + This program loads a Vamp plugin and tests its susceptibility to a + number of common pitfalls, including handling of extremes of input + data. If you can think of any additional useful tests that are + easily added, please send them to me. + + Permission is hereby granted, free of charge, to any person + obtaining a copy of this software and associated documentation + files (the "Software"), to deal in the Software without + restriction, including without limitation the rights to use, copy, + modify, merge, publish, distribute, sublicense, and/or sell copies + of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR + ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the names of the Centre for + Digital Music; Queen Mary, University of London; and Chris Cannam + shall not be used in advertising or otherwise to promote the sale, + use or other dealings in this Software without prior written + authorization. +*/ + +#include <vamp-hostsdk/PluginHostAdapter.h> +#include <vamp-hostsdk/PluginInputDomainAdapter.h> +#include <vamp-hostsdk/PluginLoader.h> + +#include <iostream> + +#include <cstring> +#include <cstdlib> +#include <cmath> + +#include "Tester.h" + +using Vamp::Plugin; +using Vamp::PluginHostAdapter; +using Vamp::RealTime; +using Vamp::HostExt::PluginLoader; +using Vamp::HostExt::PluginWrapper; +using Vamp::HostExt::PluginInputDomainAdapter; + +using namespace std; + +Tester::Tester(std::string key) : + m_key(key) +{ +} + +Tester::~Tester() +{ +} + +Tester::Registry & +Tester::registry() +{ + static Registry r; + return r; +} + +bool +Tester::test() +{ + /* + + Things I would like to see tested: + + * Identifiers for parameters, outputs, or plugin itself contain + illegal characters - DONE + + * Any of the plugin's name, maker etc fields are empty - DONE + + * Plugin returns different results if another instance is + constructed and run "interleaved" with it (from same thread) + + * Plugin's returned timestamps do not change as expected when + run with a different base timestamp for input (though there + could be legitimate reasons for this) + + * Plugin fails when given zero-length or very short input + + * Plugin fails when given "all digital zeros" input + + * Plugin fails when given input that exceeds +/-1 + + * Plugin fails when given "normal" random input (just in case!) + + * Plugin produces different results on second run, after reset + called + + * Initial value of a parameter on plugin construction differs + from its default value (i.e. plugin produces different + results depending on whether parameter is set explicitly by + host to default value or not) + + * Default value of a parameter is not quantized as specified - DONE + + * Parameter minValue >= maxValue, or defaultValue < minValue + or > maxValue - DONE + + * If a plugin reports any programs, selecting default program + explicitly changes results (as for default parameters) + + * Output feature does not hasTimestamp when output type is + VariableSampleRate + + * Output feature hasTimestamp or hasDuration when output type is + OneSamplePerStep (warning only, this is not an error) + + * Plugin fails gracelessly when constructed with "weird" sample + rate or initialised with "wrong" step size, block size, or + number of channels + + * Plugin returns features whose output numbers do not have + a corresponding record in output descriptor list + + * Plugin fails to return any features on some output (warning + only) + + * Constructor takes a long time to run. A fuzzy concept, but + suggests that some work should have been deferred to + initialise(). Warning only + + Well, that's quite a lot of tests already. What else? + + */ + + bool good = true; + + try { + for (Registry::const_iterator i = registry().begin(); + i != registry().end(); ++i) { + + std::cerr << " -- Performing test: " << i->first << std::endl; + + Test *test = i->second->makeTest(); + Test::Results results = test->test(m_key); + delete test; + + for (int j = 0; j < (int)results.size(); ++j) { + switch (results[j].code()) { + case Test::Result::Success: + break; + case Test::Result::Warning: + std::cerr << " ** WARNING: " << results[j].message() << std::endl; + break; + case Test::Result::Error: + std::cerr << " ** ERROR: " << results[j].message() << std::endl; + good = false; + break; + } + } + } + } catch (Test::FailedToLoadPlugin) { + std::cerr << "ERROR: Failed to load plugin (key = \"" << m_key + << "\")" << std::endl; + } + + return good; +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Tester.h Thu Mar 12 16:23:55 2009 +0000 @@ -0,0 +1,79 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + Vamp Plugin Tester + Chris Cannam, cannam@all-day-breakfast.com + Centre for Digital Music, Queen Mary, University of London. + Copyright 2009 QMUL. + + This program loads a Vamp plugin and tests its susceptibility to a + number of common pitfalls, including handling of extremes of input + data. If you can think of any additional useful tests that are + easily added, please send them to me. + + Permission is hereby granted, free of charge, to any person + obtaining a copy of this software and associated documentation + files (the "Software"), to deal in the Software without + restriction, including without limitation the rights to use, copy, + modify, merge, publish, distribute, sublicense, and/or sell copies + of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR + ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the names of the Centre for + Digital Music; Queen Mary, University of London; and Chris Cannam + shall not be used in advertising or otherwise to promote the sale, + use or other dealings in this Software without prior written + authorization. +*/ + +#ifndef _TESTER_H_ +#define _TESTER_H_ + +#include <string> + +#include "Test.h" + +class Tester +{ +public: + Tester(std::string pluginKey); + ~Tester(); + + bool test(); + + class Registrar { + public: + Registrar(std::string name) { Tester::registerTest(name, this); } + virtual Test *makeTest() = 0; + }; + + template <typename T> + class TestRegistrar : Registrar { + public: + TestRegistrar(std::string name) : Registrar(name) { } + virtual Test *makeTest() { return new T(); } + }; + + static void registerTest(std::string name, Registrar *r) { + registry()[name] = r; + } + +protected: + std::string m_key; + typedef std::map<std::string, Registrar *> Registry; + static Registry ®istry(); +}; + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vamp-plugin-tester.cpp Thu Mar 12 16:23:55 2009 +0000 @@ -0,0 +1,119 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + Vamp Plugin Tester + Chris Cannam, cannam@all-day-breakfast.com + Centre for Digital Music, Queen Mary, University of London. + Copyright 2009 QMUL. + + This program loads a Vamp plugin and tests its susceptibility to a + number of common pitfalls, including handling of extremes of input + data. If you can think of any additional useful tests that are + easily added, please send them to me. + + Permission is hereby granted, free of charge, to any person + obtaining a copy of this software and associated documentation + files (the "Software"), to deal in the Software without + restriction, including without limitation the rights to use, copy, + modify, merge, publish, distribute, sublicense, and/or sell copies + of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR + ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the names of the Centre for + Digital Music; Queen Mary, University of London; and Chris Cannam + shall not be used in advertising or otherwise to promote the sale, + use or other dealings in this Software without prior written + authorization. +*/ + +#include <vamp-hostsdk/PluginHostAdapter.h> +#include <vamp-hostsdk/PluginInputDomainAdapter.h> +#include <vamp-hostsdk/PluginLoader.h> + +#include <iostream> + +#include <cstdlib> + +#include "Tester.h" + +using namespace std; + +void usage(const char *name) +{ + cerr << "\n" + << name << ": A Vamp plugin host that tests plugins for some likely errors.\n" + "Chris Cannam, Centre for Digital Music, Queen Mary, University of London.\n" + "Copyright 2009 QMUL.\n" + "Freely redistributable; published under a BSD-style license.\n\n" + "Usage:\n" + " " << name << " [<pluginbasename>:<plugin>]\n\n" + "Example:\n" + " " << name << " vamp-example-plugins:amplitudefollower\n\n" + "With an argument, tests one plugin; without, tests all plugins in Vamp path.\n" + "If you have access to a runtime memory checker, you may find it especially\n" + "helpful to run this tester under it and watch for errors thus provoked.\n" + << endl; + exit(2); +} + +int main(int argc, char **argv) +{ + char *scooter = argv[0]; + char *name = 0; + while (scooter && *scooter) { + if (*scooter == '/' || *scooter == '\\') name = ++scooter; + else ++scooter; + } + if (!name || !*name) name = argv[0]; + + if (argc > 2) usage(name); + if (argc == 2 && argv[1][0] == '-') usage(name); + + cerr << name << ": Running..." << endl; + + if (argc == 1) { + bool good = true; + Vamp::HostExt::PluginLoader::PluginKeyList keys = + Vamp::HostExt::PluginLoader::getInstance()->listPlugins(); + for (int i = 0; i < (int)keys.size(); ++i) { + cerr << "Testing plugin: " << keys[i] << endl; + Tester tester(keys[i]); + if (tester.test()) { + cerr << name << ": All tests succeeded for this plugin" << endl; + } else { + cerr << name << ": Some tests failed for this plugin" << endl; + good = false; + } + cerr << endl; + } + if (good) { + cerr << name << ": All tests succeeded" << endl; + return 0; + } else { + cerr << name << ": Some tests failed" << endl; + return 1; + } + } else { + string key = argv[1]; + Tester tester(key); + if (tester.test()) { + cerr << name << ": All tests succeeded" << endl; + return 0; + } else { + cerr << name << ": Some tests failed" << endl; + return 1; + } + } +} +