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