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