Home | History | Annotate | Download | only in tests
      1 /*
      2  * Copyright 2011 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 "CrashHandler.h"
      9 #include "GrContext.h"
     10 #include "GrContextFactory.h"
     11 #include "OverwriteLine.h"
     12 #include "PathOpsDebug.h"
     13 #include "Resources.h"
     14 #include "SkCommonFlags.h"
     15 #include "SkGraphics.h"
     16 #include "SkOSFile.h"
     17 #include "SkPathOpsDebug.h"
     18 #include "SkTArray.h"
     19 #include "SkTaskGroup.h"
     20 #include "SkTemplates.h"
     21 #include "SkTime.h"
     22 #include "Test.h"
     23 #include <atomic>
     24 
     25 using namespace skiatest;
     26 using namespace sk_gpu_test;
     27 
     28 DEFINE_bool2(dumpOp, d, false, "dump the pathOps to a file to recover mid-crash.");
     29 DEFINE_bool2(extendedTest, x, false, "run extended tests for pathOps.");
     30 DEFINE_bool2(runFail, f, false, "check for success on tests known to fail.");
     31 DEFINE_bool2(verifyOp, y, false, "compare the pathOps result against a region.");
     32 DEFINE_string2(json, J, "", "write json version of tests.");
     33 
     34 #if DEBUG_COIN
     35 DEFINE_bool2(coinTest, c, false, "detect unused coincidence algorithms.");
     36 #endif
     37 
     38 // need to explicitly declare this, or we get some weird infinite loop llist
     39 template TestRegistry* TestRegistry::gHead;
     40 void (*gVerboseFinalize)() = nullptr;
     41 
     42 // The threads report back to this object when they are done.
     43 class Status {
     44 public:
     45     explicit Status(int total)
     46         : fDone(0), fTestCount(0), fFailCount(0), fTotal(total) {}
     47     // Threadsafe.
     48     void endTest(const char* testName,
     49                  bool success,
     50                  SkMSec elapsed,
     51                  int testCount) {
     52         const int done = ++fDone;
     53         fTestCount += testCount;
     54         if (!success) {
     55             SkDebugf("\n---- %s FAILED", testName);
     56         }
     57 
     58         SkString prefix(kSkOverwriteLine);
     59         SkString time;
     60         if (FLAGS_verbose) {
     61             prefix.printf("\n");
     62             time.printf("%5dms ", elapsed);
     63         }
     64         SkDebugf("%s[%3d/%3d] %s%s", prefix.c_str(), done, fTotal, time.c_str(),
     65                  testName);
     66     }
     67 
     68     void reportFailure() { fFailCount++; }
     69 
     70     int32_t testCount() { return fTestCount; }
     71     int32_t failCount() { return fFailCount; }
     72 
     73 private:
     74     std::atomic<int32_t> fDone;
     75     std::atomic<int32_t> fTestCount;
     76     std::atomic<int32_t> fFailCount;
     77     const int fTotal;
     78 };
     79 
     80 class SkTestRunnable {
     81 public:
     82     SkTestRunnable(const Test& test, Status* status) : fTest(test), fStatus(status) {}
     83 
     84     void operator()() {
     85         struct TestReporter : public skiatest::Reporter {
     86         public:
     87             TestReporter() : fStats(nullptr), fError(false), fTestCount(0) {}
     88             void bumpTestCount() override { ++fTestCount; }
     89             bool allowExtendedTest() const override { return FLAGS_extendedTest; }
     90             bool verbose() const override { return FLAGS_veryVerbose; }
     91             void reportFailed(const skiatest::Failure& failure) override {
     92                 SkDebugf("\nFAILED: %s", failure.toString().c_str());
     93                 fError = true;
     94             }
     95             void* stats() const override { return fStats; }
     96             void* fStats;
     97             bool fError;
     98             int fTestCount;
     99         } reporter;
    100 
    101         const Timer timer;
    102         fTest.proc(&reporter, GrContextOptions());
    103         SkMSec elapsed = timer.elapsedMsInt();
    104         if (reporter.fError) {
    105             fStatus->reportFailure();
    106         }
    107         fStatus->endTest(fTest.name, !reporter.fError, elapsed, reporter.fTestCount);
    108   }
    109 
    110 private:
    111     Test fTest;
    112     Status* fStatus;
    113 };
    114 
    115 static bool should_run(const char* testName, bool isGPUTest) {
    116     if (SkCommandLineFlags::ShouldSkip(FLAGS_match, testName)) {
    117         return false;
    118     }
    119     if (!FLAGS_cpu && !isGPUTest) {
    120         return false;
    121     }
    122     if (!FLAGS_gpu && isGPUTest) {
    123         return false;
    124     }
    125     return true;
    126 }
    127 
    128 int main(int argc, char** argv) {
    129     SkCommandLineFlags::Parse(argc, argv);
    130 #if DEBUG_DUMP_VERIFY
    131     SkPathOpsDebug::gDumpOp = FLAGS_dumpOp;
    132     SkPathOpsDebug::gVerifyOp = FLAGS_verifyOp;
    133 #endif
    134     SkPathOpsDebug::gRunFail = FLAGS_runFail;
    135     SkPathOpsDebug::gVeryVerbose = FLAGS_veryVerbose;
    136     PathOpsDebug::gOutFirst = true;
    137     PathOpsDebug::gCheckForDuplicateNames = false;
    138     PathOpsDebug::gOutputSVG = false;
    139     if ((PathOpsDebug::gJson = !FLAGS_json.isEmpty())) {
    140         PathOpsDebug::gOut = fopen(FLAGS_json[0], "wb");
    141         fprintf(PathOpsDebug::gOut, "{\n");
    142         FLAGS_threads = 0;
    143         PathOpsDebug::gMarkJsonFlaky = false;
    144     }
    145     SetupCrashHandler();
    146 
    147     SkAutoGraphics ag;
    148 
    149     {
    150         SkString header("Skia UnitTests:");
    151         if (!FLAGS_match.isEmpty()) {
    152             header.appendf(" --match");
    153             for (int index = 0; index < FLAGS_match.count(); ++index) {
    154                 header.appendf(" %s", FLAGS_match[index]);
    155             }
    156         }
    157         SkString tmpDir = skiatest::GetTmpDir();
    158         if (!tmpDir.isEmpty()) {
    159             header.appendf(" --tmpDir %s", tmpDir.c_str());
    160         }
    161         SkString resourcePath = GetResourcePath();
    162         if (!resourcePath.isEmpty()) {
    163             header.appendf(" --resourcePath %s", resourcePath.c_str());
    164         }
    165 #if DEBUG_COIN
    166         if (FLAGS_coinTest) {
    167             header.appendf(" -c");
    168         }
    169 #endif
    170         if (FLAGS_dumpOp) {
    171             header.appendf(" -d");
    172         }
    173 #ifdef SK_DEBUG
    174         if (FLAGS_runFail) {
    175             header.appendf(" -f");
    176         }
    177 #endif
    178         if (FLAGS_verbose) {
    179             header.appendf(" -v");
    180         }
    181         if (FLAGS_veryVerbose) {
    182             header.appendf(" -V");
    183         }
    184         if (FLAGS_extendedTest) {
    185             header.appendf(" -x");
    186         }
    187         if (FLAGS_verifyOp) {
    188             header.appendf(" -y");
    189         }
    190 #ifdef SK_DEBUG
    191         header.append(" SK_DEBUG");
    192 #else
    193         header.append(" SK_RELEASE");
    194 #endif
    195         if (FLAGS_veryVerbose) {
    196             header.appendf("\n");
    197         }
    198         SkDebugf("%s", header.c_str());
    199     }
    200 
    201 
    202     // Count tests first.
    203     int total = 0;
    204     int toRun = 0;
    205 
    206     for (const Test& test : TestRegistry::Range()) {
    207         if (should_run(test.name, test.needsGpu)) {
    208             toRun++;
    209         }
    210         total++;
    211     }
    212 
    213     // Now run them.
    214     int skipCount = 0;
    215 
    216     SkTaskGroup::Enabler enabled(FLAGS_threads);
    217     SkTaskGroup cpuTests;
    218     SkTArray<const Test*> gpuTests;
    219 
    220     Status status(toRun);
    221 
    222     for (const Test& test : TestRegistry::Range()) {
    223         if (!should_run(test.name, test.needsGpu)) {
    224             ++skipCount;
    225         } else if (test.needsGpu) {
    226             gpuTests.push_back(&test);
    227         } else {
    228             cpuTests.add(SkTestRunnable(test, &status));
    229         }
    230     }
    231 
    232     // Run GPU tests on this thread.
    233     for (int i = 0; i < gpuTests.count(); i++) {
    234         SkTestRunnable(*gpuTests[i], &status)();
    235     }
    236 
    237     // Block until threaded tests finish.
    238     cpuTests.wait();
    239 
    240     if (FLAGS_verbose) {
    241         SkDebugf(
    242                 "\nFinished %d tests, %d failures, %d skipped. "
    243                 "(%d internal tests)",
    244                 toRun, status.failCount(), skipCount, status.testCount());
    245         if (gVerboseFinalize) {
    246             (*gVerboseFinalize)();
    247         }
    248     }
    249 
    250     SkDebugf("\n");
    251 #if DEBUG_COIN
    252     if (FLAGS_coinTest) {
    253         SkPathOpsDebug::DumpCoinDict();
    254     }
    255 #endif
    256     if (PathOpsDebug::gJson) {
    257         fprintf(PathOpsDebug::gOut, "\n}\n");
    258         fclose(PathOpsDebug::gOut);
    259     }
    260     return (status.failCount() == 0) ? 0 : 1;
    261 }
    262