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
25using namespace skiatest;
26
27DEFINE_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 ~");
35DEFINE_bool2(extendedTest, x, false, "run extended tests for pathOps.");
36DEFINE_bool2(leaks, l, false, "show leaked ref cnt'd objects.");
37DEFINE_bool2(single, z, false, "run tests on a single thread internally.");
38DEFINE_bool2(verbose, v, false, "enable verbose output from the test driver.");
39DEFINE_bool2(veryVerbose, V, false, "tell individual tests to be verbose.");
40DEFINE_bool(cpu, true, "whether or not to run CPU tests.");
41DEFINE_bool(gpu, true, "whether or not to run GPU tests.");
42DEFINE_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
46template TestRegistry* TestRegistry::gHead;
47
48class Iter {
49public:
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
64private:
65    const TestRegistry* fReg;
66};
67
68class DebugfReporter : public Reporter {
69public:
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
76protected:
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
97private:
98    int32_t fDone;  // atomic
99    const int fTotal;
100};
101
102// Deletes self when run.
103class SkTestRunnable : public SkRunnable {
104public:
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
116private:
117    SkAutoTDelete<Test> fTest;
118    int32_t* fFailCount;
119};
120
121static 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
134int tool_main(int argc, char** argv);
135int 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)
238int main(int argc, char * const argv[]) {
239    return tool_main(argc, (char**) argv);
240}
241#endif
242