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