cannam@0: /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ cannam@0: cannam@0: /* cannam@0: Vamp Plugin Tester cannam@0: Chris Cannam, cannam@all-day-breakfast.com cannam@0: Centre for Digital Music, Queen Mary, University of London. Chris@59: Copyright 2009-2015 QMUL. cannam@0: cannam@0: This program loads a Vamp plugin and tests its susceptibility to a cannam@0: number of common pitfalls, including handling of extremes of input cannam@0: data. If you can think of any additional useful tests that are cannam@0: easily added, please send them to me. cannam@0: cannam@0: Permission is hereby granted, free of charge, to any person cannam@0: obtaining a copy of this software and associated documentation cannam@0: files (the "Software"), to deal in the Software without cannam@0: restriction, including without limitation the rights to use, copy, cannam@0: modify, merge, publish, distribute, sublicense, and/or sell copies cannam@0: of the Software, and to permit persons to whom the Software is cannam@0: furnished to do so, subject to the following conditions: cannam@0: cannam@0: The above copyright notice and this permission notice shall be cannam@0: included in all copies or substantial portions of the Software. cannam@0: cannam@0: THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, cannam@0: EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF cannam@0: MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND cannam@0: NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR cannam@0: ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF cannam@0: CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION cannam@0: WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. cannam@0: cannam@0: Except as contained in this notice, the names of the Centre for cannam@0: Digital Music; Queen Mary, University of London; and Chris Cannam cannam@0: shall not be used in advertising or otherwise to promote the sale, cannam@0: use or other dealings in this Software without prior written cannam@0: authorization. cannam@0: */ cannam@0: cannam@0: #include cannam@0: #include cannam@0: #include cannam@0: cannam@0: #include cannam@0: cannam@0: #include cannam@8: #include cannam@0: cannam@0: #include "Tester.h" cannam@0: cannam@0: using namespace std; cannam@0: Chris@40: static const std::string VERSION="1.1"; Chris@40: cannam@0: void usage(const char *name) cannam@0: { cannam@0: cerr << "\n" cannam@9: << name << ": A Vamp plugin host that tests plugins for common errors.\n" cannam@0: "Chris Cannam, Centre for Digital Music, Queen Mary, University of London.\n" Chris@59: "Copyright 2009-2015 QMUL.\n" cannam@0: "Freely redistributable; published under a BSD-style license.\n\n" cannam@0: "Usage:\n" Chris@40: " " << name << " [-nv] [-t ] :\n" Chris@40: " " << name << " [-nv] [-t ] -a\n" Chris@40: " " << name << " -l\n\n" cannam@0: "Example:\n" cannam@0: " " << name << " vamp-example-plugins:amplitudefollower\n\n" cannam@25: "Options:\n" cannam@25: " -a, --all Test all plugins found in Vamp path\n\n" cannam@25: " -n, --nondeterministic Plugins may be nondeterministic: print a note\n" cannam@25: " instead of an error if results differ between runs\n\n" cannam@25: " -v, --verbose Show returned features each time a note, warning,\n" Chris@40: " or error arises from feature data\n\n" Chris@40: " -t, --test Run only a single test, not the full test suite.\n" Chris@40: " Identify the test by its id, e.g. A3\n\n" Chris@40: " -l, --list-tests List tests by id and name\n\n" Chris@40: " --version Display the version of " << name << "\n" cannam@8: "\nIf you have access to a runtime memory checker, you may find it especially\n" cannam@0: "helpful to run this tester under it and watch for errors thus provoked.\n" cannam@0: << endl; cannam@0: exit(2); cannam@0: } cannam@0: cannam@0: int main(int argc, char **argv) cannam@0: { cannam@0: char *scooter = argv[0]; cannam@0: char *name = 0; cannam@0: while (scooter && *scooter) { cannam@0: if (*scooter == '/' || *scooter == '\\') name = ++scooter; cannam@0: else ++scooter; cannam@0: } cannam@0: if (!name || !*name) name = argv[0]; cannam@8: cannam@8: bool nondeterministic = false; cannam@8: bool verbose = false; cannam@25: bool all = false; Chris@40: bool list = false; Chris@40: string plugin; Chris@40: string single; Chris@40: Chris@40: // Would be better to use getopt, but let's avoid the dependency for now cannam@8: for (int i = 1; i < argc; ++i) { cannam@8: if (!argv[i]) break; cannam@8: if (argv[i][0] == '-') { Chris@40: if (!strcmp(argv[i], "-vn") || Chris@40: !strcmp(argv[i], "-nv")) { Chris@40: verbose = true; Chris@40: nondeterministic = true; Chris@40: continue; Chris@40: } cannam@8: if (!strcmp(argv[i], "-v") || cannam@8: !strcmp(argv[i], "--verbose")) { cannam@25: verbose = true; cannam@8: continue; cannam@8: } cannam@8: if (!strcmp(argv[i], "-n") || cannam@8: !strcmp(argv[i], "--nondeterministic")) { cannam@25: nondeterministic = true; cannam@25: continue; cannam@25: } cannam@25: if (!strcmp(argv[i], "-a") || cannam@25: !strcmp(argv[i], "--all")) { cannam@25: all = true; cannam@8: continue; cannam@8: } Chris@40: if (!strcmp(argv[i], "-l") || Chris@40: !strcmp(argv[i], "--list-tests")) { Chris@40: list = true; Chris@40: continue; Chris@40: } Chris@40: if (!strcmp(argv[i], "-t") || Chris@40: !strcmp(argv[i], "--test")) { Chris@40: if (i + 1 < argc) { Chris@40: single = argv[i+1]; Chris@40: ++i; Chris@40: } else { Chris@40: usage(name); Chris@40: } Chris@40: continue; Chris@40: } Chris@40: if (!strcmp(argv[i], "--version")) { Chris@40: cout << "v" << VERSION << endl; Chris@40: return 0; Chris@40: } cannam@8: usage(name); cannam@8: } else { Chris@40: if (plugin != "") usage(name); Chris@40: else plugin = argv[i]; cannam@8: } cannam@8: } Chris@40: Chris@40: if (list) { Chris@40: if (all || nondeterministic || (single != "") || (plugin != "")) { Chris@40: usage(name); Chris@40: } Chris@40: Tester::listTests(); Chris@40: return 0; Chris@40: } cannam@0: Chris@40: if (plugin == "" && !all) usage(name); Chris@40: if (plugin != "" && all) usage(name); cannam@25: cannam@0: cerr << name << ": Running..." << endl; cannam@0: cannam@8: Test::Options opts = Test::NoOption; cannam@8: if (nondeterministic) opts |= Test::NonDeterministic; cannam@8: if (verbose) opts |= Test::Verbose; Chris@39: if (single != "") opts |= Test::SingleTest; cannam@8: cannam@25: if (all) { cannam@0: bool good = true; cannam@0: Vamp::HostExt::PluginLoader::PluginKeyList keys = cannam@0: Vamp::HostExt::PluginLoader::getInstance()->listPlugins(); Chris@33: if (keys.size() == 0) { Chris@33: cout << name << ": NOTE: No plugins found!" << endl; Chris@33: cout << name << ": (No libraries in search path, or no descriptors in library)" << endl; Chris@37: return 2; Chris@33: } cannam@4: int notes = 0, warnings = 0, errors = 0; cannam@0: for (int i = 0; i < (int)keys.size(); ++i) { cannam@3: cout << "Testing plugin: " << keys[i] << endl; Chris@39: Tester tester(keys[i], opts, single); cannam@4: if (tester.test(notes, warnings, errors)) { cannam@3: cout << name << ": All tests succeeded for this plugin" << endl; cannam@0: } else { cannam@3: cout << name << ": Some tests failed for this plugin" << endl; cannam@0: good = false; cannam@0: } cannam@3: cout << endl; cannam@0: } cannam@0: if (good) { cannam@4: cout << name << ": All tests succeeded"; cannam@4: if (warnings > 0) { cannam@4: cout << ", with " << warnings << " warning(s)"; cannam@4: if (notes > 0) { cannam@4: cout << " and " << notes << " other note(s)"; cannam@4: } cannam@4: } else if (notes > 0) { cannam@4: cout << ", with " << notes << " note(s)"; cannam@4: } cannam@4: cout << endl; cannam@0: return 0; cannam@0: } else { cannam@3: cout << name << ": Some tests failed" << endl; cannam@0: return 1; cannam@0: } cannam@0: } else { Chris@40: Tester tester(plugin, opts, single); cannam@4: int notes = 0, warnings = 0, errors = 0; cannam@4: if (tester.test(notes, warnings, errors)) { cannam@4: cout << name << ": All tests succeeded"; cannam@4: if (warnings > 0) { cannam@4: cout << ", with " << warnings << " warning(s)"; cannam@4: if (notes > 0) { cannam@4: cout << " and " << notes << " other note(s)"; cannam@4: } cannam@4: } else if (notes > 0) { cannam@4: cout << ", with " << notes << " note(s)"; cannam@4: } cannam@4: cout << endl; cannam@0: return 0; cannam@0: } else { cannam@3: cout << name << ": Some tests failed" << endl; cannam@0: return 1; cannam@0: } cannam@0: } cannam@0: } cannam@0: