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