Home | History | Annotate | Download | only in src
      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