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