skia_test.cpp revision 4239fc2f69bdbd1a1f01ee66112f46033b47b743
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 "SkAtomics.h"
12#include "SkCommonFlags.h"
13#include "SkGraphics.h"
14#include "SkOSFile.h"
15#include "SkRunnable.h"
16#include "SkTArray.h"
17#include "SkTaskGroup.h"
18#include "SkTemplates.h"
19#include "SkTime.h"
20#include "Test.h"
21
22#if SK_SUPPORT_GPU
23#include "GrContext.h"
24#include "GrContextFactory.h"
25#endif
26
27using namespace skiatest;
28
29DEFINE_bool2(extendedTest, x, false, "run extended tests for pathOps.");
30
31// need to explicitly declare this, or we get some weird infinite loop llist
32template TestRegistry* TestRegistry::gHead;
33
34// The threads report back to this object when they are done.
35class Status {
36public:
37    explicit Status(int total)
38        : fDone(0), fTestCount(0), fFailCount(0), fTotal(total) {}
39    // Threadsafe.
40    void endTest(const char* testName,
41                 bool success,
42                 SkMSec elapsed,
43                 int testCount) {
44        const int done = 1 + sk_atomic_inc(&fDone);
45        for (int i = 0; i < testCount; ++i) {
46            sk_atomic_inc(&fTestCount);
47        }
48        if (!success) {
49            SkDebugf("\n---- %s FAILED", testName);
50        }
51
52        SkString prefix(kSkOverwriteLine);
53        SkString time;
54        if (FLAGS_verbose) {
55            prefix.printf("\n");
56            time.printf("%5dms ", elapsed);
57        }
58        SkDebugf("%s[%3d/%3d] %s%s", prefix.c_str(), done, fTotal, time.c_str(),
59                 testName);
60    }
61
62    void reportFailure() { sk_atomic_inc(&fFailCount); }
63
64    int32_t testCount() { return fTestCount; }
65    int32_t failCount() { return fFailCount; }
66
67private:
68    int32_t fDone;  // atomic
69    int32_t fTestCount;  // atomic
70    int32_t fFailCount;  // atomic
71    const int fTotal;
72};
73
74// Deletes self when run.
75class SkTestRunnable : public SkRunnable {
76public:
77    SkTestRunnable(const Test& test,
78                   Status* status,
79                   GrContextFactory* grContextFactory = NULL)
80        : fTest(test), fStatus(status), fGrContextFactory(grContextFactory) {}
81
82  virtual void run() {
83      struct TestReporter : public skiatest::Reporter {
84      public:
85          TestReporter() : fError(false), fTestCount(0) {}
86          void bumpTestCount() override { ++fTestCount; }
87          bool allowExtendedTest() const override {
88              return FLAGS_extendedTest;
89          }
90          bool verbose() const override { return FLAGS_veryVerbose; }
91          void reportFailed(const skiatest::Failure& failure) override {
92              SkDebugf("\nFAILED: %s", failure.toString().c_str());
93              fError = true;
94          }
95          bool fError;
96          int fTestCount;
97      } reporter;
98
99      const SkMSec start = SkTime::GetMSecs();
100      fTest.proc(&reporter, fGrContextFactory);
101      SkMSec elapsed = SkTime::GetMSecs() - start;
102      if (reporter.fError) {
103          fStatus->reportFailure();
104      }
105      fStatus->endTest(fTest.name, !reporter.fError, elapsed,
106                       reporter.fTestCount);
107      SkDELETE(this);
108  }
109
110private:
111    Test fTest;
112    Status* fStatus;
113    GrContextFactory* fGrContextFactory;
114};
115
116static bool should_run(const char* testName, bool isGPUTest) {
117    if (SkCommandLineFlags::ShouldSkip(FLAGS_match, testName)) {
118        return false;
119    }
120    if (!FLAGS_cpu && !isGPUTest) {
121        return false;
122    }
123    if (!FLAGS_gpu && isGPUTest) {
124        return false;
125    }
126    return true;
127}
128
129int test_main();
130int test_main() {
131    SetupCrashHandler();
132
133    SkAutoGraphics ag;
134
135    {
136        SkString header("Skia UnitTests:");
137        if (!FLAGS_match.isEmpty()) {
138            header.appendf(" --match");
139            for (int index = 0; index < FLAGS_match.count(); ++index) {
140                header.appendf(" %s", FLAGS_match[index]);
141            }
142        }
143        SkString tmpDir = skiatest::GetTmpDir();
144        if (!tmpDir.isEmpty()) {
145            header.appendf(" --tmpDir %s", tmpDir.c_str());
146        }
147        SkString resourcePath = GetResourcePath();
148        if (!resourcePath.isEmpty()) {
149            header.appendf(" --resourcePath %s", resourcePath.c_str());
150        }
151#ifdef SK_DEBUG
152        header.append(" SK_DEBUG");
153#else
154        header.append(" SK_RELEASE");
155#endif
156        if (FLAGS_veryVerbose) {
157            header.appendf("\n");
158        }
159        SkDebugf("%s", header.c_str());
160    }
161
162
163    // Count tests first.
164    int total = 0;
165    int toRun = 0;
166
167    for (const TestRegistry* iter = TestRegistry::Head(); iter;
168         iter = iter->next()) {
169        const Test& test = iter->factory();
170        if (should_run(test.name, test.needsGpu)) {
171            toRun++;
172        }
173        total++;
174    }
175
176    // Now run them.
177    int skipCount = 0;
178
179    SkTaskGroup::Enabler enabled(FLAGS_threads);
180    SkTaskGroup cpuTests;
181    SkTArray<const Test*> gpuTests;
182
183    Status status(toRun);
184    for (const TestRegistry* iter = TestRegistry::Head(); iter;
185         iter = iter->next()) {
186        const Test& test = iter->factory();
187        if (!should_run(test.name, test.needsGpu)) {
188            ++skipCount;
189        } else if (test.needsGpu) {
190            gpuTests.push_back(&test);
191        } else {
192            cpuTests.add(SkNEW_ARGS(SkTestRunnable, (test, &status)));
193        }
194    }
195
196    GrContextFactory* grContextFactoryPtr = NULL;
197#if SK_SUPPORT_GPU
198    // Give GPU tests a context factory if that makes sense on this machine.
199    GrContextFactory grContextFactory;
200    grContextFactoryPtr = &grContextFactory;
201
202#endif
203
204    // Run GPU tests on this thread.
205    for (int i = 0; i < gpuTests.count(); i++) {
206        SkNEW_ARGS(SkTestRunnable, (*gpuTests[i], &status, grContextFactoryPtr))
207                ->run();
208    }
209
210    // Block until threaded tests finish.
211    cpuTests.wait();
212
213    if (FLAGS_verbose) {
214        SkDebugf(
215                "\nFinished %d tests, %d failures, %d skipped. "
216                "(%d internal tests)",
217                toRun, status.failCount(), skipCount, status.testCount());
218    }
219
220    SkDebugf("\n");
221    return (status.failCount() == 0) ? 0 : 1;
222}
223
224#if !defined(SK_BUILD_FOR_IOS)
225int main(int argc, char** argv) {
226    SkCommandLineFlags::Parse(argc, argv);
227    return test_main();
228}
229#endif
230