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