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 "SkCommandLineFlags.h"
      9 #include "SkGraphics.h"
     10 #include "SkOSFile.h"
     11 #include "SkTArray.h"
     12 #include "SkTemplates.h"
     13 #include "SkThreadPool.h"
     14 #include "SkTime.h"
     15 #include "Test.h"
     16 
     17 #if SK_SUPPORT_GPU
     18 #include "GrContext.h"
     19 #endif
     20 
     21 using namespace skiatest;
     22 
     23 // need to explicitly declare this, or we get some weird infinite loop llist
     24 template TestRegistry* TestRegistry::gHead;
     25 
     26 class Iter {
     27 public:
     28     Iter(Reporter* r) : fReporter(r) {
     29         r->ref();
     30         this->reset();
     31     }
     32 
     33     void reset() {
     34         fReg = TestRegistry::Head();
     35     }
     36 
     37     ~Iter() {
     38         fReporter->unref();
     39     }
     40 
     41     Test* next() {
     42         if (fReg) {
     43             TestRegistry::Factory fact = fReg->factory();
     44             fReg = fReg->next();
     45             Test* test = fact(NULL);
     46             test->setReporter(fReporter);
     47             return test;
     48         }
     49         return NULL;
     50     }
     51 
     52 private:
     53     Reporter* fReporter;
     54     const TestRegistry* fReg;
     55 };
     56 
     57 class DebugfReporter : public Reporter {
     58 public:
     59     DebugfReporter(bool allowExtendedTest, bool allowThreaded, bool verbose)
     60         : fNextIndex(0)
     61         , fPending(0)
     62         , fTotal(0)
     63         , fAllowExtendedTest(allowExtendedTest)
     64         , fAllowThreaded(allowThreaded)
     65         , fVerbose(verbose) {
     66     }
     67 
     68     void setTotal(int total) {
     69         fTotal = total;
     70     }
     71 
     72     virtual bool allowExtendedTest() const SK_OVERRIDE {
     73         return fAllowExtendedTest;
     74     }
     75 
     76     virtual bool allowThreaded() const SK_OVERRIDE {
     77         return fAllowThreaded;
     78     }
     79 
     80     virtual bool verbose() const SK_OVERRIDE {
     81         return fVerbose;
     82     }
     83 
     84 protected:
     85     virtual void onStart(Test* test) {
     86         SkAutoMutexAcquire lock(fStartEndMutex);
     87         fNextIndex++;
     88         fPending++;
     89         SkDebugf("[%3d/%3d] (%d) %s\n", fNextIndex, fTotal, fPending, test->getName());
     90     }
     91 
     92     virtual void onReportFailed(const SkString& desc) {
     93         SkDebugf("\tFAILED: %s\n", desc.c_str());
     94     }
     95 
     96     virtual void onEnd(Test* test) {
     97         SkAutoMutexAcquire lock(fStartEndMutex);
     98         if (!test->passed()) {
     99             SkDebugf("---- %s FAILED\n", test->getName());
    100         }
    101 
    102         fPending--;
    103         if (fNextIndex == fTotal) {
    104             // Just waiting on straggler tests.  Shame them by printing their name and runtime.
    105             SkDebugf("          (%d) %5.1fs %s\n",
    106                      fPending, test->elapsedMs() / 1e3, test->getName());
    107         }
    108     }
    109 
    110 private:
    111     SkMutex fStartEndMutex;  // Guards fNextIndex and fPending.
    112     int32_t fNextIndex;
    113     int32_t fPending;
    114 
    115     // Once the tests get going, these are logically const.
    116     int fTotal;
    117     bool fAllowExtendedTest;
    118     bool fAllowThreaded;
    119     bool fVerbose;
    120 };
    121 
    122 DEFINE_string2(match, m, NULL, "[~][^]substring[$] [...] of test name to run.\n" \
    123                                "Multiple matches may be separated by spaces.\n" \
    124                                "~ causes a matching test to always be skipped\n" \
    125                                "^ requires the start of the test to match\n" \
    126                                "$ requires the end of the test to match\n" \
    127                                "^ and $ requires an exact match\n" \
    128                                "If a test does not match any list entry,\n" \
    129                                "it is skipped unless some list entry starts with ~");
    130 DEFINE_string2(tmpDir, t, NULL, "tmp directory for tests to use.");
    131 DEFINE_string2(resourcePath, i, "resources", "directory for test resources.");
    132 DEFINE_bool2(extendedTest, x, false, "run extended tests for pathOps.");
    133 DEFINE_bool2(single, z, false, "run tests on a single thread internally.");
    134 DEFINE_bool2(verbose, v, false, "enable verbose output.");
    135 DEFINE_int32(threads, SkThreadPool::kThreadPerCore,
    136              "Run threadsafe tests on a threadpool with this many threads.");
    137 
    138 SkString Test::GetTmpDir() {
    139     const char* tmpDir = FLAGS_tmpDir.isEmpty() ? NULL : FLAGS_tmpDir[0];
    140     return SkString(tmpDir);
    141 }
    142 
    143 SkString Test::GetResourcePath() {
    144     const char* resourcePath = FLAGS_resourcePath.isEmpty() ? NULL : FLAGS_resourcePath[0];
    145     return SkString(resourcePath);
    146 }
    147 
    148 // Deletes self when run.
    149 class SkTestRunnable : public SkRunnable {
    150 public:
    151   // Takes ownership of test.
    152   SkTestRunnable(Test* test, int32_t* failCount) : fTest(test), fFailCount(failCount) {}
    153 
    154   virtual void run() {
    155       fTest->run();
    156       if(!fTest->passed()) {
    157           sk_atomic_inc(fFailCount);
    158       }
    159       SkDELETE(this);
    160   }
    161 
    162 private:
    163     SkAutoTDelete<Test> fTest;
    164     int32_t* fFailCount;
    165 };
    166 
    167 int tool_main(int argc, char** argv);
    168 int tool_main(int argc, char** argv) {
    169     SkCommandLineFlags::SetUsage("");
    170     SkCommandLineFlags::Parse(argc, argv);
    171 
    172 #if SK_ENABLE_INST_COUNT
    173     gPrintInstCount = true;
    174 #endif
    175 
    176     SkGraphics::Init();
    177 
    178     {
    179         SkString header("Skia UnitTests:");
    180         if (!FLAGS_match.isEmpty()) {
    181             header.appendf(" --match");
    182             for (int index = 0; index < FLAGS_match.count(); ++index) {
    183                 header.appendf(" %s", FLAGS_match[index]);
    184             }
    185         }
    186         SkString tmpDir = Test::GetTmpDir();
    187         if (!tmpDir.isEmpty()) {
    188             header.appendf(" --tmpDir %s", tmpDir.c_str());
    189         }
    190         SkString resourcePath = Test::GetResourcePath();
    191         if (!resourcePath.isEmpty()) {
    192             header.appendf(" --resourcePath %s", resourcePath.c_str());
    193         }
    194 #ifdef SK_DEBUG
    195         header.append(" SK_DEBUG");
    196 #else
    197         header.append(" SK_RELEASE");
    198 #endif
    199 #ifdef SK_SCALAR_IS_FIXED
    200         header.append(" SK_SCALAR_IS_FIXED");
    201 #else
    202         header.append(" SK_SCALAR_IS_FLOAT");
    203 #endif
    204         header.appendf(" skia_arch_width=%d", (int)sizeof(void*) * 8);
    205         SkDebugf("%s\n", header.c_str());
    206     }
    207 
    208     DebugfReporter reporter(FLAGS_extendedTest, !FLAGS_single, FLAGS_verbose);
    209     Iter iter(&reporter);
    210 
    211     // Count tests first.
    212     int total = 0;
    213     int toRun = 0;
    214     Test* test;
    215 
    216     while ((test = iter.next()) != NULL) {
    217         SkAutoTDelete<Test> owned(test);
    218 
    219         if(!SkCommandLineFlags::ShouldSkip(FLAGS_match, test->getName())) {
    220             toRun++;
    221         }
    222         total++;
    223     }
    224     reporter.setTotal(toRun);
    225 
    226     // Now run them.
    227     iter.reset();
    228     int32_t failCount = 0;
    229     int skipCount = 0;
    230 
    231     SkThreadPool threadpool(FLAGS_threads);
    232     SkTArray<Test*> unsafeTests;  // Always passes ownership to an SkTestRunnable
    233     for (int i = 0; i < total; i++) {
    234         SkAutoTDelete<Test> test(iter.next());
    235         if (SkCommandLineFlags::ShouldSkip(FLAGS_match, test->getName())) {
    236             ++skipCount;
    237         } else if (!test->isThreadsafe()) {
    238             unsafeTests.push_back() = test.detach();
    239         } else {
    240             threadpool.add(SkNEW_ARGS(SkTestRunnable, (test.detach(), &failCount)));
    241         }
    242     }
    243 
    244     // Run the tests that aren't threadsafe.
    245     for (int i = 0; i < unsafeTests.count(); i++) {
    246         SkNEW_ARGS(SkTestRunnable, (unsafeTests[i], &failCount))->run();
    247     }
    248 
    249     // Block until threaded tests finish.
    250     threadpool.wait();
    251 
    252     SkDebugf("Finished %d tests, %d failures, %d skipped.\n",
    253              toRun, failCount, skipCount);
    254     const int testCount = reporter.countTests();
    255     if (FLAGS_verbose && testCount > 0) {
    256         SkDebugf("Ran %d Internal tests.\n", testCount);
    257     }
    258     SkGraphics::Term();
    259     GpuTest::DestroyContexts();
    260 
    261     return (failCount == 0) ? 0 : 1;
    262 }
    263 
    264 #if !defined(SK_BUILD_FOR_IOS) && !defined(SK_BUILD_FOR_NACL)
    265 int main(int argc, char * const argv[]) {
    266     return tool_main(argc, (char**) argv);
    267 }
    268 #endif
    269