/* * Copyright 2017 Google Inc. * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #include #include #include "tools/skqp/src/skqp.h" #include "include/core/SkData.h" #include "src/core/SkOSFile.h" #include "tools/Resources.h" //////////////////////////////////////////////////////////////////////////////// namespace { class StdAssetManager : public SkQPAssetManager { public: StdAssetManager(const char* p) : fPrefix(p) { SkASSERT(!fPrefix.empty()); //TODO(halcanary): does this need to be changed if I run SkQP in Windows? fPrefix += "/"; } sk_sp open(const char* path) override { return SkData::MakeFromFileName((fPrefix + path).c_str()); } private: std::string fPrefix; }; struct Args { char *assetDir; char *renderTests; char *outputDir; }; } // namespace static constexpr char kSkipUsage[] = " TEST_MATCH_RULES:" " [~][^]substring[$] [...] of name to run.\n" " Multiple matches may be separated by spaces.\n" " ~ causes a matching name to always be skipped\n" " ^ requires the start of the name to match\n" " $ requires the end of the name to match\n" " ^ and $ requires an exact match\n" " If a name does not match any list entry,\n" " it is skipped unless some list entry starts with ~\n"; static bool should_skip(const char* const* rules, size_t count, const char* name) { size_t testLen = strlen(name); bool anyExclude = count == 0; for (size_t i = 0; i < count; ++i) { const char* matchName = rules[i]; size_t matchLen = strlen(matchName); bool matchExclude, matchStart, matchEnd; if ((matchExclude = matchName[0] == '~')) { anyExclude = true; matchName++; matchLen--; } if ((matchStart = matchName[0] == '^')) { matchName++; matchLen--; } if ((matchEnd = matchName[matchLen - 1] == '$')) { matchLen--; } if (matchStart ? (!matchEnd || matchLen == testLen) && strncmp(name, matchName, matchLen) == 0 : matchEnd ? matchLen <= testLen && strncmp(name + testLen - matchLen, matchName, matchLen) == 0 : strstr(name, matchName) != nullptr) { return matchExclude; } } return !anyExclude; } static void parse_args(int argc, char *argv[], Args *args) { if (argc < 4) { std::cerr << "Usage:\n " << argv[0] << " ASSET_DIR RENDER_TESTS OUTPUT_DIR [TEST_MATCH_RULES]\n" << kSkipUsage << '\n'; exit(1); } args->assetDir = argv[1]; args->renderTests = argv[2]; args->outputDir = argv[3]; } int main(int argc, char *argv[]) { Args args; parse_args(argc, argv, &args); SetResourcePath(std::string(args.assetDir + std::string("/resources")).c_str()); if (!sk_mkdir(args.outputDir)) { std::cerr << "sk_mkdir(" << args.outputDir << ") failed.\n"; return 2; } StdAssetManager mgr(args.assetDir); SkQP skqp; skqp.init(&mgr, args.renderTests, args.outputDir); int ret = 0; const char* const* matchRules = &argv[4]; size_t matchRulesCount = (size_t)(argc - 4); // Rendering Tests std::ostream& out = std::cout; for (auto backend : skqp.getSupportedBackends()) { auto testPrefix = std::string(SkQP::GetBackendName(backend)) + "_"; for (auto gmFactory : skqp.getGMs()) { auto testName = testPrefix + SkQP::GetGMName(gmFactory); if (should_skip(matchRules, matchRulesCount, testName.c_str())) { continue; } out << "Starting: " << testName << std::endl; SkQP::RenderOutcome outcome; std::string except; std::tie(outcome, except) = skqp.evaluateGM(backend, gmFactory); if (!except.empty()) { out << "ERROR: " << testName << " (" << except << ")\n"; ret = 1; } else if (outcome.fMaxError != 0) { out << "FAILED: " << testName << " (" << outcome.fMaxError << ")\n"; ret = 1; } else { out << "Passed: " << testName << "\n"; } out.flush(); } } // Unit Tests for (auto test : skqp.getUnitTests()) { auto testName = std::string("unitTest_") + SkQP::GetUnitTestName(test); if (should_skip(matchRules, matchRulesCount, testName.c_str())) { continue; } out << "Starting test: " << testName << std::endl; std::vector errors = skqp.executeTest(test); if (!errors.empty()) { out << "TEST FAILED (" << errors.size() << "): " << testName << "\n"; for (const std::string& error : errors) { out << error << "\n"; } ret = 1; } else { out << "Test passed: " << testName << "\n"; } out.flush(); } skqp.makeReport(); return ret; }