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 "SkCommonFlags.h"
12#include "SkGraphics.h"
13#include "SkOSFile.h"
14#include "SkTArray.h"
15#include "SkTaskGroup.h"
16#include "SkTemplates.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_bool2(extendedTest, x, false, "run extended tests for pathOps.");
28
29// need to explicitly declare this, or we get some weird infinite loop llist
30template TestRegistry* TestRegistry::gHead;
31
32class Iter {
33public:
34    Iter() { this->reset(); }
35    void reset() { fReg = TestRegistry::Head(); }
36
37    Test* next(Reporter* r) {
38        if (fReg) {
39            TestRegistry::Factory fact = fReg->factory();
40            fReg = fReg->next();
41            Test* test = fact(NULL);
42            test->setReporter(r);
43            return test;
44        }
45        return NULL;
46    }
47
48private:
49    const TestRegistry* fReg;
50};
51
52class DebugfReporter : public Reporter {
53public:
54    explicit DebugfReporter(int total) : fDone(0), fTotal(total) {}
55
56    virtual bool allowExtendedTest() const SK_OVERRIDE { return FLAGS_extendedTest; }
57    virtual bool verbose()           const SK_OVERRIDE { return FLAGS_veryVerbose; }
58
59protected:
60    virtual void onReportFailed(const SkString& desc) SK_OVERRIDE {
61        SkDebugf("\nFAILED: %s", desc.c_str());
62    }
63
64    virtual void onEnd(Test* test) SK_OVERRIDE {
65        const int done = 1 + sk_atomic_inc(&fDone);
66
67        if (!test->passed()) {
68            SkDebugf("\n---- %s FAILED", test->getName());
69        }
70
71        SkString prefix(kSkOverwriteLine);
72        SkString time;
73        if (FLAGS_verbose) {
74            prefix.printf("\n");
75            time.printf("%5dms ", test->elapsedMs());
76        }
77        SkDebugf("%s[%3d/%3d] %s%s", prefix.c_str(), done, fTotal, time.c_str(), test->getName());
78    }
79
80private:
81    int32_t fDone;  // atomic
82    const int fTotal;
83};
84
85// Deletes self when run.
86class SkTestRunnable : public SkRunnable {
87public:
88  // Takes ownership of test.
89  SkTestRunnable(Test* test, int32_t* failCount) : fTest(test), fFailCount(failCount) {}
90
91  virtual void run() {
92      fTest->run();
93      if(!fTest->passed()) {
94          sk_atomic_inc(fFailCount);
95      }
96      SkDELETE(this);
97  }
98
99private:
100    SkAutoTDelete<Test> fTest;
101    int32_t* fFailCount;
102};
103
104static bool should_run(const char* testName, bool isGPUTest) {
105    if (SkCommandLineFlags::ShouldSkip(FLAGS_match, testName)) {
106        return false;
107    }
108    if (!FLAGS_cpu && !isGPUTest) {
109        return false;
110    }
111    if (!FLAGS_gpu && isGPUTest) {
112        return false;
113    }
114    return true;
115}
116
117int test_main();
118int test_main() {
119    SetupCrashHandler();
120
121#if SK_ENABLE_INST_COUNT
122    if (FLAGS_leaks) {
123        gPrintInstCount = true;
124    }
125#endif
126
127    SkGraphics::Init();
128
129    {
130        SkString header("Skia UnitTests:");
131        if (!FLAGS_match.isEmpty()) {
132            header.appendf(" --match");
133            for (int index = 0; index < FLAGS_match.count(); ++index) {
134                header.appendf(" %s", FLAGS_match[index]);
135            }
136        }
137        SkString tmpDir = Test::GetTmpDir();
138        if (!tmpDir.isEmpty()) {
139            header.appendf(" --tmpDir %s", tmpDir.c_str());
140        }
141        SkString resourcePath = GetResourcePath();
142        if (!resourcePath.isEmpty()) {
143            header.appendf(" --resourcePath %s", resourcePath.c_str());
144        }
145#ifdef SK_DEBUG
146        header.append(" SK_DEBUG");
147#else
148        header.append(" SK_RELEASE");
149#endif
150        header.appendf(" skia_arch_width=%d", (int)sizeof(void*) * 8);
151        if (FLAGS_veryVerbose) {
152            header.appendf("\n");
153        }
154        SkDebugf(header.c_str());
155    }
156
157
158    // Count tests first.
159    int total = 0;
160    int toRun = 0;
161    Test* test;
162
163    Iter iter;
164    while ((test = iter.next(NULL/*reporter not needed*/)) != NULL) {
165        SkAutoTDelete<Test> owned(test);
166        if (should_run(test->getName(), test->isGPUTest())) {
167            toRun++;
168        }
169        total++;
170    }
171
172    // Now run them.
173    iter.reset();
174    int32_t failCount = 0;
175    int skipCount = 0;
176
177    SkTaskGroup::Enabler enabled(FLAGS_threads);
178    SkTaskGroup cpuTests;
179    SkTArray<Test*> gpuTests;  // Always passes ownership to an SkTestRunnable
180
181    DebugfReporter reporter(toRun);
182    for (int i = 0; i < total; i++) {
183        SkAutoTDelete<Test> test(iter.next(&reporter));
184        if (!should_run(test->getName(), test->isGPUTest())) {
185            ++skipCount;
186        } else if (test->isGPUTest()) {
187            gpuTests.push_back() = test.detach();
188        } else {
189            cpuTests.add(SkNEW_ARGS(SkTestRunnable, (test.detach(), &failCount)));
190        }
191    }
192
193#if SK_SUPPORT_GPU
194    // Give GPU tests a context factory if that makes sense on this machine.
195    GrContextFactory grContextFactory;
196    for (int i = 0; i < gpuTests.count(); i++) {
197        gpuTests[i]->setGrContextFactory(&grContextFactory);
198    }
199#endif
200
201    // Run GPU tests on this thread.
202    for (int i = 0; i < gpuTests.count(); i++) {
203        SkNEW_ARGS(SkTestRunnable, (gpuTests[i], &failCount))->run();
204    }
205
206    // Block until threaded tests finish.
207    cpuTests.wait();
208
209    if (FLAGS_verbose) {
210        SkDebugf("\nFinished %d tests, %d failures, %d skipped. (%d internal tests)",
211                 toRun, failCount, skipCount, reporter.countTests());
212    }
213    SkGraphics::Term();
214
215    SkDebugf("\n");
216    return (failCount == 0) ? 0 : 1;
217}
218
219#if !defined(SK_BUILD_FOR_IOS) && !defined(SK_BUILD_FOR_NACL)
220int main(int argc, char** argv) {
221    SkCommandLineFlags::Parse(argc, argv);
222    return test_main();
223}
224#endif
225