xref: /aosp_15_r20/external/skia/tools/skqp/src/skqp_main.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
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 "tools/skqp/src/skqp.h"
12 
13 #include "include/core/SkData.h"
14 #include "src/core/SkOSFile.h"
15 #include "src/utils/SkOSPath.h"
16 #include "tools/Resources.h"
17 
18 ////////////////////////////////////////////////////////////////////////////////
19 
20 namespace {
21 class StdAssetManager : public SkQPAssetManager {
22 public:
StdAssetManager(const char * p)23     StdAssetManager(const char* p) : fPrefix(p) {
24         SkASSERT(!fPrefix.empty());
25     }
26 
open(const char * subpath)27     sk_sp<SkData> open(const char* subpath) override {
28         SkString path = SkOSPath::Join(fPrefix.c_str(), subpath);
29         return SkData::MakeFromFileName(path.c_str());
30     }
31 
iterateDir(const char * directory,const char * extension)32     std::vector<std::string> iterateDir(const char* directory, const char* extension) override {
33         std::vector<std::string> paths;
34         SkString resourceDirectory = GetResourcePath(directory);
35         SkOSFile::Iter iter(resourceDirectory.c_str(), extension);
36         SkString name;
37 
38         while (iter.next(&name, /*getDir=*/false)) {
39             SkString path(SkOSPath::Join(directory, name.c_str()));
40             paths.push_back(path.c_str());
41         }
42 
43         return paths;
44     }
45 
46 private:
47     std::string fPrefix;
48 };
49 
50 struct Args {
51     char* assetDir;
52     char* outputDir;
53 };
54 }  // namespace
55 
56 static constexpr char kSkipUsage[] =
57     " TEST_MATCH_RULES:"
58     "    [~][^]substring[$] [...] of name to run.\n"
59     "    Multiple matches may be separated by spaces.\n"
60     "    ~ causes a matching name to always be skipped\n"
61     "    ^ requires the start of the name to match\n"
62     "    $ requires the end of the name to match\n"
63     "    ^ and $ requires an exact match\n"
64     "    If a name does not match any list entry,\n"
65     "    it is skipped unless some list entry starts with ~\n";
66 
should_skip(const char * const * rules,size_t count,const char * name)67 static bool should_skip(const char* const* rules, size_t count, const char* name) {
68     size_t testLen = strlen(name);
69     bool anyExclude = count == 0;
70     for (size_t i = 0; i < count; ++i) {
71         const char* matchName = rules[i];
72         size_t matchLen = strlen(matchName);
73         bool matchExclude, matchStart, matchEnd;
74         if ((matchExclude = matchName[0] == '~')) {
75             anyExclude = true;
76             matchName++;
77             matchLen--;
78         }
79         if ((matchStart = matchName[0] == '^')) {
80             matchName++;
81             matchLen--;
82         }
83         if ((matchEnd = matchName[matchLen - 1] == '$')) {
84             matchLen--;
85         }
86         if (matchStart ? (!matchEnd || matchLen == testLen)
87                 && strncmp(name, matchName, matchLen) == 0
88                 : matchEnd ? matchLen <= testLen
89                 && strncmp(name + testLen - matchLen, matchName, matchLen) == 0
90                 : strstr(name, matchName) != nullptr) {
91             return matchExclude;
92         }
93     }
94     return !anyExclude;
95 }
96 
parse_args(int argc,char * argv[],Args * args)97 static void parse_args(int argc, char *argv[], Args *args) {
98   if (argc < 3) {
99       std::cerr << "Usage:\n  " << argv[0] << " ASSET_DIR OUTPUT_DIR [TEST_MATCH_RULES]\n"
100                 << kSkipUsage << '\n';
101       exit(1);
102   }
103   args->assetDir = argv[1];
104   args->outputDir = argv[2];
105 }
106 
main(int argc,char * argv[])107 int main(int argc, char *argv[]) {
108     Args args;
109     parse_args(argc, argv, &args);
110 
111     SetResourcePath(std::string(args.assetDir + std::string("/resources")).c_str());
112     if (!sk_mkdir(args.outputDir)) {
113         std::cerr << "sk_mkdir(" << args.outputDir << ") failed.\n";
114         return 2;
115     }
116 
117     StdAssetManager mgr(args.assetDir);
118     SkQP skqp;
119     skqp.init(&mgr, args.outputDir);
120     int ret = 0;
121 
122     const char* const* matchRules = &argv[3];
123     size_t matchRulesCount = (size_t)(argc - 3);
124 
125     // Unit Tests
126     for (SkQP::UnitTest test : skqp.getUnitTests()) {
127         auto testName = std::string("unitTest_") + SkQP::GetUnitTestName(test);
128         if (should_skip(matchRules, matchRulesCount, testName.c_str())) {
129             continue;
130         }
131         std::cout << "Starting: " << testName << " ";
132         std::vector<std::string> errors = skqp.executeTest(test);
133         if (!errors.empty()) {
134             std::cout << "[FAILED: " << errors.size() << " error(s)]" << std::endl;
135             for (const std::string& error : errors) {
136                 std::cout << "  " <<  error << std::endl;
137             }
138             ret = 1;
139         } else {
140             std::cout << "[PASSED]" << std::endl;
141         }
142         std::cout.flush();
143     }
144     skqp.makeReport();
145 
146     return ret;
147 }
148