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