skia_test.cpp revision 434251f87292808c1c461e48dba5d22735e74f97
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
22using namespace skiatest;
23
24// need to explicitly declare this, or we get some weird infinite loop llist
25template TestRegistry* TestRegistry::gHead;
26
27class Iter {
28public:
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
53private:
54    Reporter* fReporter;
55    const TestRegistry* fReg;
56};
57
58class DebugfReporter : public Reporter {
59public:
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
85protected:
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
108private:
109    int32_t fNextIndex;
110    int32_t fPending;
111    int fTotal;
112    bool fAllowExtendedTest;
113    bool fAllowThreaded;
114    bool fVerbose;
115};
116
117DEFINE_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 ~");
125DEFINE_string2(tmpDir, t, NULL, "tmp directory for tests to use.");
126DEFINE_string2(resourcePath, i, NULL, "directory for test resources.");
127DEFINE_bool2(extendedTest, x, false, "run extended tests for pathOps.");
128DEFINE_bool2(single, z, false, "run tests on a single thread internally.");
129DEFINE_bool2(verbose, v, false, "enable verbose output.");
130DEFINE_int32(threads, SkThreadPool::kThreadPerCore,
131             "Run threadsafe tests on a threadpool with this many threads.");
132
133SkString Test::GetTmpDir() {
134    const char* tmpDir = FLAGS_tmpDir.isEmpty() ? NULL : FLAGS_tmpDir[0];
135    return SkString(tmpDir);
136}
137
138SkString Test::GetResourcePath() {
139    const char* resourcePath = FLAGS_resourcePath.isEmpty() ? NULL : FLAGS_resourcePath[0];
140    return SkString(resourcePath);
141}
142
143// Deletes self when run.
144class SkTestRunnable : public SkRunnable {
145public:
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
157private:
158    SkAutoTDelete<Test> fTest;
159    int32_t* fFailCount;
160};
161
162int tool_main(int argc, char** argv);
163int 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)
274int main(int argc, char * const argv[]) {
275    return tool_main(argc, (char**) argv);
276}
277#endif
278