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 "SkCommandLineFlags.h"
     12 #include "SkGraphics.h"
     13 #include "SkOSFile.h"
     14 #include "SkTArray.h"
     15 #include "SkTemplates.h"
     16 #include "SkThreadPool.h"
     17 #include "SkTime.h"
     18 #include "Test.h"
     19 
     20 #if SK_SUPPORT_GPU
     21 #include "GrContext.h"
     22 #include "GrContextFactory.h"
     23 #endif
     24 
     25 using namespace skiatest;
     26 
     27 DEFINE_string2(match, m, NULL, "[~][^]substring[$] [...] of test name to run.\n" \
     28                                "Multiple matches may be separated by spaces.\n" \
     29                                "~ causes a matching test to always be skipped\n" \
     30                                "^ requires the start of the test to match\n" \
     31                                "$ requires the end of the test to match\n" \
     32                                "^ and $ requires an exact match\n" \
     33                                "If a test does not match any list entry,\n" \
     34                                "it is skipped unless some list entry starts with ~");
     35 DEFINE_bool2(extendedTest, x, false, "run extended tests for pathOps.");
     36 DEFINE_bool2(leaks, l, false, "show leaked ref cnt'd objects.");
     37 DEFINE_bool2(single, z, false, "run tests on a single thread internally.");
     38 DEFINE_bool2(verbose, v, false, "enable verbose output from the test driver.");
     39 DEFINE_bool2(veryVerbose, V, false, "tell individual tests to be verbose.");
     40 DEFINE_bool(cpu, true, "whether or not to run CPU tests.");
     41 DEFINE_bool(gpu, true, "whether or not to run GPU tests.");
     42 DEFINE_int32(threads, SkThreadPool::kThreadPerCore,
     43              "Run threadsafe tests on a threadpool with this many threads.");
     44 
     45 // need to explicitly declare this, or we get some weird infinite loop llist
     46 template TestRegistry* TestRegistry::gHead;
     47 
     48 class Iter {
     49 public:
     50     Iter() { this->reset(); }
     51     void reset() { fReg = TestRegistry::Head(); }
     52 
     53     Test* next(Reporter* r) {
     54         if (fReg) {
     55             TestRegistry::Factory fact = fReg->factory();
     56             fReg = fReg->next();
     57             Test* test = fact(NULL);
     58             test->setReporter(r);
     59             return test;
     60         }
     61         return NULL;
     62     }
     63 
     64 private:
     65     const TestRegistry* fReg;
     66 };
     67 
     68 class DebugfReporter : public Reporter {
     69 public:
     70     explicit DebugfReporter(int total) : fDone(0), fTotal(total) {}
     71 
     72     virtual bool allowExtendedTest() const SK_OVERRIDE { return FLAGS_extendedTest; }
     73     virtual bool allowThreaded()     const SK_OVERRIDE { return !FLAGS_single; }
     74     virtual bool verbose()           const SK_OVERRIDE { return FLAGS_veryVerbose; }
     75 
     76 protected:
     77     virtual void onReportFailed(const SkString& desc) SK_OVERRIDE {
     78         SkDebugf("\nFAILED: %s", desc.c_str());
     79     }
     80 
     81     virtual void onEnd(Test* test) SK_OVERRIDE {
     82         const int done = 1 + sk_atomic_inc(&fDone);
     83 
     84         if (!test->passed()) {
     85             SkDebugf("\n---- %s FAILED", test->getName());
     86         }
     87 
     88         SkString prefix(kSkOverwriteLine);
     89         SkString time;
     90         if (FLAGS_verbose) {
     91             prefix.printf("\n");
     92             time.printf("%5dms ", test->elapsedMs());
     93         }
     94         SkDebugf("%s[%3d/%3d] %s%s", prefix.c_str(), done, fTotal, time.c_str(), test->getName());
     95     }
     96 
     97 private:
     98     int32_t fDone;  // atomic
     99     const int fTotal;
    100 };
    101 
    102 // Deletes self when run.
    103 class SkTestRunnable : public SkRunnable {
    104 public:
    105   // Takes ownership of test.
    106   SkTestRunnable(Test* test, int32_t* failCount) : fTest(test), fFailCount(failCount) {}
    107 
    108   virtual void run() {
    109       fTest->run();
    110       if(!fTest->passed()) {
    111           sk_atomic_inc(fFailCount);
    112       }
    113       SkDELETE(this);
    114   }
    115 
    116 private:
    117     SkAutoTDelete<Test> fTest;
    118     int32_t* fFailCount;
    119 };
    120 
    121 static bool should_run(const char* testName, bool isGPUTest) {
    122     if (SkCommandLineFlags::ShouldSkip(FLAGS_match, testName)) {
    123         return false;
    124     }
    125     if (!FLAGS_cpu && !isGPUTest) {
    126         return false;
    127     }
    128     if (!FLAGS_gpu && isGPUTest) {
    129         return false;
    130     }
    131     return true;
    132 }
    133 
    134 int tool_main(int argc, char** argv);
    135 int tool_main(int argc, char** argv) {
    136     SetupCrashHandler();
    137     SkCommandLineFlags::SetUsage("");
    138     SkCommandLineFlags::Parse(argc, argv);
    139 
    140 #if SK_ENABLE_INST_COUNT
    141     if (FLAGS_leaks) {
    142         gPrintInstCount = true;
    143     }
    144 #endif
    145 
    146     SkGraphics::Init();
    147 
    148     {
    149         SkString header("Skia UnitTests:");
    150         if (!FLAGS_match.isEmpty()) {
    151             header.appendf(" --match");
    152             for (int index = 0; index < FLAGS_match.count(); ++index) {
    153                 header.appendf(" %s", FLAGS_match[index]);
    154             }
    155         }
    156         SkString tmpDir = Test::GetTmpDir();
    157         if (!tmpDir.isEmpty()) {
    158             header.appendf(" --tmpDir %s", tmpDir.c_str());
    159         }
    160         SkString resourcePath = GetResourcePath();
    161         if (!resourcePath.isEmpty()) {
    162             header.appendf(" --resourcePath %s", resourcePath.c_str());
    163         }
    164 #ifdef SK_DEBUG
    165         header.append(" SK_DEBUG");
    166 #else
    167         header.append(" SK_RELEASE");
    168 #endif
    169         header.appendf(" skia_arch_width=%d", (int)sizeof(void*) * 8);
    170         if (FLAGS_veryVerbose) {
    171             header.appendf("\n");
    172         }
    173         SkDebugf(header.c_str());
    174     }
    175 
    176 
    177     // Count tests first.
    178     int total = 0;
    179     int toRun = 0;
    180     Test* test;
    181 
    182     Iter iter;
    183     while ((test = iter.next(NULL/*reporter not needed*/)) != NULL) {
    184         SkAutoTDelete<Test> owned(test);
    185         if (should_run(test->getName(), test->isGPUTest())) {
    186             toRun++;
    187         }
    188         total++;
    189     }
    190 
    191     // Now run them.
    192     iter.reset();
    193     int32_t failCount = 0;
    194     int skipCount = 0;
    195 
    196     SkThreadPool threadpool(FLAGS_threads);
    197     SkTArray<Test*> gpuTests;  // Always passes ownership to an SkTestRunnable
    198 
    199     DebugfReporter reporter(toRun);
    200     for (int i = 0; i < total; i++) {
    201         SkAutoTDelete<Test> test(iter.next(&reporter));
    202         if (!should_run(test->getName(), test->isGPUTest())) {
    203             ++skipCount;
    204         } else if (test->isGPUTest()) {
    205             gpuTests.push_back() = test.detach();
    206         } else {
    207             threadpool.add(SkNEW_ARGS(SkTestRunnable, (test.detach(), &failCount)));
    208         }
    209     }
    210 
    211 #if SK_SUPPORT_GPU
    212     // Give GPU tests a context factory if that makes sense on this machine.
    213     GrContextFactory grContextFactory;
    214     for (int i = 0; i < gpuTests.count(); i++) {
    215         gpuTests[i]->setGrContextFactory(&grContextFactory);
    216     }
    217 #endif
    218 
    219     // Run GPU tests on this thread.
    220     for (int i = 0; i < gpuTests.count(); i++) {
    221         SkNEW_ARGS(SkTestRunnable, (gpuTests[i], &failCount))->run();
    222     }
    223 
    224     // Block until threaded tests finish.
    225     threadpool.wait();
    226 
    227     if (FLAGS_verbose) {
    228         SkDebugf("\nFinished %d tests, %d failures, %d skipped. (%d internal tests)",
    229                  toRun, failCount, skipCount, reporter.countTests());
    230     }
    231     SkGraphics::Term();
    232 
    233     SkDebugf("\n");
    234     return (failCount == 0) ? 0 : 1;
    235 }
    236 
    237 #if !defined(SK_BUILD_FOR_IOS) && !defined(SK_BUILD_FOR_NACL)
    238 int main(int argc, char * const argv[]) {
    239     return tool_main(argc, (char**) argv);
    240 }
    241 #endif
    242