1cb93a386Sopenharmony_ci/* 2cb93a386Sopenharmony_ci * Copyright 2017 Google Inc. 3cb93a386Sopenharmony_ci * 4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be 5cb93a386Sopenharmony_ci * found in the LICENSE file. 6cb93a386Sopenharmony_ci */ 7cb93a386Sopenharmony_ci 8cb93a386Sopenharmony_ci#include <iostream> 9cb93a386Sopenharmony_ci#include <sys/stat.h> 10cb93a386Sopenharmony_ci 11cb93a386Sopenharmony_ci#include "tools/skqp/src/skqp.h" 12cb93a386Sopenharmony_ci 13cb93a386Sopenharmony_ci#include "include/core/SkData.h" 14cb93a386Sopenharmony_ci#include "src/core/SkOSFile.h" 15cb93a386Sopenharmony_ci#include "tools/Resources.h" 16cb93a386Sopenharmony_ci 17cb93a386Sopenharmony_ci//////////////////////////////////////////////////////////////////////////////// 18cb93a386Sopenharmony_ci 19cb93a386Sopenharmony_cinamespace { 20cb93a386Sopenharmony_ciclass StdAssetManager : public SkQPAssetManager { 21cb93a386Sopenharmony_cipublic: 22cb93a386Sopenharmony_ci StdAssetManager(const char* p) : fPrefix(p) { 23cb93a386Sopenharmony_ci SkASSERT(!fPrefix.empty()); 24cb93a386Sopenharmony_ci //TODO(halcanary): does this need to be changed if I run SkQP in Windows? 25cb93a386Sopenharmony_ci fPrefix += "/"; 26cb93a386Sopenharmony_ci } 27cb93a386Sopenharmony_ci sk_sp<SkData> open(const char* path) override { 28cb93a386Sopenharmony_ci return SkData::MakeFromFileName((fPrefix + path).c_str()); 29cb93a386Sopenharmony_ci } 30cb93a386Sopenharmony_ciprivate: 31cb93a386Sopenharmony_ci std::string fPrefix; 32cb93a386Sopenharmony_ci}; 33cb93a386Sopenharmony_ci 34cb93a386Sopenharmony_cistruct Args { 35cb93a386Sopenharmony_ci char *assetDir; 36cb93a386Sopenharmony_ci char *renderTests; 37cb93a386Sopenharmony_ci char *outputDir; 38cb93a386Sopenharmony_ci}; 39cb93a386Sopenharmony_ci} // namespace 40cb93a386Sopenharmony_ci 41cb93a386Sopenharmony_cistatic constexpr char kSkipUsage[] = 42cb93a386Sopenharmony_ci " TEST_MATCH_RULES:" 43cb93a386Sopenharmony_ci " [~][^]substring[$] [...] of name to run.\n" 44cb93a386Sopenharmony_ci " Multiple matches may be separated by spaces.\n" 45cb93a386Sopenharmony_ci " ~ causes a matching name to always be skipped\n" 46cb93a386Sopenharmony_ci " ^ requires the start of the name to match\n" 47cb93a386Sopenharmony_ci " $ requires the end of the name to match\n" 48cb93a386Sopenharmony_ci " ^ and $ requires an exact match\n" 49cb93a386Sopenharmony_ci " If a name does not match any list entry,\n" 50cb93a386Sopenharmony_ci " it is skipped unless some list entry starts with ~\n"; 51cb93a386Sopenharmony_ci 52cb93a386Sopenharmony_cistatic bool should_skip(const char* const* rules, size_t count, const char* name) { 53cb93a386Sopenharmony_ci size_t testLen = strlen(name); 54cb93a386Sopenharmony_ci bool anyExclude = count == 0; 55cb93a386Sopenharmony_ci for (size_t i = 0; i < count; ++i) { 56cb93a386Sopenharmony_ci const char* matchName = rules[i]; 57cb93a386Sopenharmony_ci size_t matchLen = strlen(matchName); 58cb93a386Sopenharmony_ci bool matchExclude, matchStart, matchEnd; 59cb93a386Sopenharmony_ci if ((matchExclude = matchName[0] == '~')) { 60cb93a386Sopenharmony_ci anyExclude = true; 61cb93a386Sopenharmony_ci matchName++; 62cb93a386Sopenharmony_ci matchLen--; 63cb93a386Sopenharmony_ci } 64cb93a386Sopenharmony_ci if ((matchStart = matchName[0] == '^')) { 65cb93a386Sopenharmony_ci matchName++; 66cb93a386Sopenharmony_ci matchLen--; 67cb93a386Sopenharmony_ci } 68cb93a386Sopenharmony_ci if ((matchEnd = matchName[matchLen - 1] == '$')) { 69cb93a386Sopenharmony_ci matchLen--; 70cb93a386Sopenharmony_ci } 71cb93a386Sopenharmony_ci if (matchStart ? (!matchEnd || matchLen == testLen) 72cb93a386Sopenharmony_ci && strncmp(name, matchName, matchLen) == 0 73cb93a386Sopenharmony_ci : matchEnd ? matchLen <= testLen 74cb93a386Sopenharmony_ci && strncmp(name + testLen - matchLen, matchName, matchLen) == 0 75cb93a386Sopenharmony_ci : strstr(name, matchName) != nullptr) { 76cb93a386Sopenharmony_ci return matchExclude; 77cb93a386Sopenharmony_ci } 78cb93a386Sopenharmony_ci } 79cb93a386Sopenharmony_ci return !anyExclude; 80cb93a386Sopenharmony_ci} 81cb93a386Sopenharmony_ci 82cb93a386Sopenharmony_cistatic void parse_args(int argc, char *argv[], Args *args) { 83cb93a386Sopenharmony_ci if (argc < 4) { 84cb93a386Sopenharmony_ci std::cerr << "Usage:\n " << argv[0] 85cb93a386Sopenharmony_ci << " ASSET_DIR RENDER_TESTS OUTPUT_DIR [TEST_MATCH_RULES]\n" 86cb93a386Sopenharmony_ci << kSkipUsage << '\n'; 87cb93a386Sopenharmony_ci exit(1); 88cb93a386Sopenharmony_ci } 89cb93a386Sopenharmony_ci args->assetDir = argv[1]; 90cb93a386Sopenharmony_ci args->renderTests = argv[2]; 91cb93a386Sopenharmony_ci args->outputDir = argv[3]; 92cb93a386Sopenharmony_ci} 93cb93a386Sopenharmony_ci 94cb93a386Sopenharmony_ciint main(int argc, char *argv[]) { 95cb93a386Sopenharmony_ci Args args; 96cb93a386Sopenharmony_ci parse_args(argc, argv, &args); 97cb93a386Sopenharmony_ci 98cb93a386Sopenharmony_ci SetResourcePath(std::string(args.assetDir + std::string("/resources")).c_str()); 99cb93a386Sopenharmony_ci if (!sk_mkdir(args.outputDir)) { 100cb93a386Sopenharmony_ci std::cerr << "sk_mkdir(" << args.outputDir << ") failed.\n"; 101cb93a386Sopenharmony_ci return 2; 102cb93a386Sopenharmony_ci } 103cb93a386Sopenharmony_ci StdAssetManager mgr(args.assetDir); 104cb93a386Sopenharmony_ci SkQP skqp; 105cb93a386Sopenharmony_ci skqp.init(&mgr, args.renderTests, args.outputDir); 106cb93a386Sopenharmony_ci int ret = 0; 107cb93a386Sopenharmony_ci 108cb93a386Sopenharmony_ci const char* const* matchRules = &argv[4]; 109cb93a386Sopenharmony_ci size_t matchRulesCount = (size_t)(argc - 4); 110cb93a386Sopenharmony_ci 111cb93a386Sopenharmony_ci // Rendering Tests 112cb93a386Sopenharmony_ci std::ostream& out = std::cout; 113cb93a386Sopenharmony_ci for (auto backend : skqp.getSupportedBackends()) { 114cb93a386Sopenharmony_ci auto testPrefix = std::string(SkQP::GetBackendName(backend)) + "_"; 115cb93a386Sopenharmony_ci for (auto gmFactory : skqp.getGMs()) { 116cb93a386Sopenharmony_ci auto testName = testPrefix + SkQP::GetGMName(gmFactory); 117cb93a386Sopenharmony_ci if (should_skip(matchRules, matchRulesCount, testName.c_str())) { 118cb93a386Sopenharmony_ci continue; 119cb93a386Sopenharmony_ci } 120cb93a386Sopenharmony_ci out << "Starting: " << testName << std::endl; 121cb93a386Sopenharmony_ci SkQP::RenderOutcome outcome; 122cb93a386Sopenharmony_ci std::string except; 123cb93a386Sopenharmony_ci 124cb93a386Sopenharmony_ci std::tie(outcome, except) = skqp.evaluateGM(backend, gmFactory); 125cb93a386Sopenharmony_ci if (!except.empty()) { 126cb93a386Sopenharmony_ci out << "ERROR: " << testName << " (" << except << ")\n"; 127cb93a386Sopenharmony_ci ret = 1; 128cb93a386Sopenharmony_ci } else if (outcome.fMaxError != 0) { 129cb93a386Sopenharmony_ci out << "FAILED: " << testName << " (" << outcome.fMaxError << ")\n"; 130cb93a386Sopenharmony_ci ret = 1; 131cb93a386Sopenharmony_ci } else { 132cb93a386Sopenharmony_ci out << "Passed: " << testName << "\n"; 133cb93a386Sopenharmony_ci } 134cb93a386Sopenharmony_ci out.flush(); 135cb93a386Sopenharmony_ci } 136cb93a386Sopenharmony_ci } 137cb93a386Sopenharmony_ci 138cb93a386Sopenharmony_ci // Unit Tests 139cb93a386Sopenharmony_ci for (auto test : skqp.getUnitTests()) { 140cb93a386Sopenharmony_ci auto testName = std::string("unitTest_") + SkQP::GetUnitTestName(test); 141cb93a386Sopenharmony_ci if (should_skip(matchRules, matchRulesCount, testName.c_str())) { 142cb93a386Sopenharmony_ci continue; 143cb93a386Sopenharmony_ci } 144cb93a386Sopenharmony_ci out << "Starting test: " << testName << std::endl; 145cb93a386Sopenharmony_ci std::vector<std::string> errors = skqp.executeTest(test); 146cb93a386Sopenharmony_ci if (!errors.empty()) { 147cb93a386Sopenharmony_ci out << "TEST FAILED (" << errors.size() << "): " << testName << "\n"; 148cb93a386Sopenharmony_ci for (const std::string& error : errors) { 149cb93a386Sopenharmony_ci out << error << "\n"; 150cb93a386Sopenharmony_ci } 151cb93a386Sopenharmony_ci ret = 1; 152cb93a386Sopenharmony_ci } else { 153cb93a386Sopenharmony_ci out << "Test passed: " << testName << "\n"; 154cb93a386Sopenharmony_ci } 155cb93a386Sopenharmony_ci out.flush(); 156cb93a386Sopenharmony_ci } 157cb93a386Sopenharmony_ci skqp.makeReport(); 158cb93a386Sopenharmony_ci 159cb93a386Sopenharmony_ci return ret; 160cb93a386Sopenharmony_ci} 161