OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2011 Google Inc. | 2 * Copyright 2011 Google Inc. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
6 */ | 6 */ |
7 | 7 |
8 #include "SkCommandLineFlags.h" | 8 #include "SkCommandLineFlags.h" |
9 #include "SkGraphics.h" | 9 #include "SkGraphics.h" |
10 #include "SkOSFile.h" | 10 #include "SkOSFile.h" |
11 #include "SkTArray.h" | 11 #include "SkTArray.h" |
12 #include "SkTemplates.h" | 12 #include "SkTemplates.h" |
13 #include "SkThreadPool.h" | 13 #include "SkThreadPool.h" |
14 #include "SkTime.h" | 14 #include "SkTime.h" |
15 #include "Test.h" | 15 #include "Test.h" |
| 16 #include "OverwriteLine.h" |
16 | 17 |
17 #if SK_SUPPORT_GPU | 18 #if SK_SUPPORT_GPU |
18 #include "GrContext.h" | 19 #include "GrContext.h" |
19 #endif | 20 #endif |
20 | 21 |
21 using namespace skiatest; | 22 using namespace skiatest; |
22 | 23 |
23 // need to explicitly declare this, or we get some weird infinite loop llist | |
24 template TestRegistry* TestRegistry::gHead; | |
25 | |
26 class Iter { | |
27 public: | |
28 Iter(Reporter* r) : fReporter(r) { | |
29 r->ref(); | |
30 this->reset(); | |
31 } | |
32 | |
33 void reset() { | |
34 fReg = TestRegistry::Head(); | |
35 } | |
36 | |
37 ~Iter() { | |
38 fReporter->unref(); | |
39 } | |
40 | |
41 Test* next() { | |
42 if (fReg) { | |
43 TestRegistry::Factory fact = fReg->factory(); | |
44 fReg = fReg->next(); | |
45 Test* test = fact(NULL); | |
46 test->setReporter(fReporter); | |
47 return test; | |
48 } | |
49 return NULL; | |
50 } | |
51 | |
52 private: | |
53 Reporter* fReporter; | |
54 const TestRegistry* fReg; | |
55 }; | |
56 | |
57 class DebugfReporter : public Reporter { | |
58 public: | |
59 DebugfReporter(bool allowExtendedTest, bool allowThreaded, bool verbose) | |
60 : fNextIndex(0) | |
61 , fPending(0) | |
62 , fTotal(0) | |
63 , fAllowExtendedTest(allowExtendedTest) | |
64 , fAllowThreaded(allowThreaded) | |
65 , fVerbose(verbose) { | |
66 } | |
67 | |
68 void setTotal(int total) { | |
69 fTotal = total; | |
70 } | |
71 | |
72 virtual bool allowExtendedTest() const SK_OVERRIDE { | |
73 return fAllowExtendedTest; | |
74 } | |
75 | |
76 virtual bool allowThreaded() const SK_OVERRIDE { | |
77 return fAllowThreaded; | |
78 } | |
79 | |
80 virtual bool verbose() const SK_OVERRIDE { | |
81 return fVerbose; | |
82 } | |
83 | |
84 protected: | |
85 virtual void onStart(Test* test) { | |
86 SkAutoMutexAcquire lock(fStartEndMutex); | |
87 fNextIndex++; | |
88 fPending++; | |
89 SkDebugf("[%3d/%3d] (%d) %s\n", fNextIndex, fTotal, fPending, test->getN
ame()); | |
90 } | |
91 | |
92 virtual void onReportFailed(const SkString& desc) { | |
93 SkDebugf("\tFAILED: %s\n", desc.c_str()); | |
94 } | |
95 | |
96 virtual void onEnd(Test* test) { | |
97 SkAutoMutexAcquire lock(fStartEndMutex); | |
98 if (!test->passed()) { | |
99 SkDebugf("---- %s FAILED\n", test->getName()); | |
100 } | |
101 | |
102 fPending--; | |
103 if (fNextIndex == fTotal) { | |
104 // Just waiting on straggler tests. Shame them by printing their na
me and runtime. | |
105 SkDebugf(" (%d) %5.1fs %s\n", | |
106 fPending, test->elapsedMs() / 1e3, test->getName()); | |
107 } | |
108 } | |
109 | |
110 private: | |
111 SkMutex fStartEndMutex; // Guards fNextIndex and fPending. | |
112 int32_t fNextIndex; | |
113 int32_t fPending; | |
114 | |
115 // Once the tests get going, these are logically const. | |
116 int fTotal; | |
117 bool fAllowExtendedTest; | |
118 bool fAllowThreaded; | |
119 bool fVerbose; | |
120 }; | |
121 | |
122 DEFINE_string2(match, m, NULL, "[~][^]substring[$] [...] of test name to run.\n"
\ | 24 DEFINE_string2(match, m, NULL, "[~][^]substring[$] [...] of test name to run.\n"
\ |
123 "Multiple matches may be separated by spaces.\n"
\ | 25 "Multiple matches may be separated by spaces.\n"
\ |
124 "~ causes a matching test to always be skipped\n"
\ | 26 "~ causes a matching test to always be skipped\n"
\ |
125 "^ requires the start of the test to match\n" \ | 27 "^ requires the start of the test to match\n" \ |
126 "$ requires the end of the test to match\n" \ | 28 "$ requires the end of the test to match\n" \ |
127 "^ and $ requires an exact match\n" \ | 29 "^ and $ requires an exact match\n" \ |
128 "If a test does not match any list entry,\n" \ | 30 "If a test does not match any list entry,\n" \ |
129 "it is skipped unless some list entry starts with
~"); | 31 "it is skipped unless some list entry starts with
~"); |
130 DEFINE_string2(tmpDir, t, NULL, "tmp directory for tests to use."); | 32 DEFINE_string2(tmpDir, t, NULL, "tmp directory for tests to use."); |
131 DEFINE_string2(resourcePath, i, "resources", "directory for test resources."); | 33 DEFINE_string2(resourcePath, i, "resources", "directory for test resources."); |
132 DEFINE_bool2(extendedTest, x, false, "run extended tests for pathOps."); | 34 DEFINE_bool2(extendedTest, x, false, "run extended tests for pathOps."); |
133 DEFINE_bool2(single, z, false, "run tests on a single thread internally."); | 35 DEFINE_bool2(single, z, false, "run tests on a single thread internally."); |
134 DEFINE_bool2(verbose, v, false, "enable verbose output."); | 36 DEFINE_bool2(verbose, v, false, "enable verbose output."); |
135 DEFINE_int32(threads, SkThreadPool::kThreadPerCore, | 37 DEFINE_int32(threads, SkThreadPool::kThreadPerCore, |
136 "Run threadsafe tests on a threadpool with this many threads."); | 38 "Run threadsafe tests on a threadpool with this many threads."); |
137 | 39 |
| 40 // need to explicitly declare this, or we get some weird infinite loop llist |
| 41 template TestRegistry* TestRegistry::gHead; |
| 42 |
| 43 class Iter { |
| 44 public: |
| 45 Iter() { this->reset(); } |
| 46 void reset() { fReg = TestRegistry::Head(); } |
| 47 |
| 48 Test* next(Reporter* r) { |
| 49 if (fReg) { |
| 50 TestRegistry::Factory fact = fReg->factory(); |
| 51 fReg = fReg->next(); |
| 52 Test* test = fact(NULL); |
| 53 test->setReporter(r); |
| 54 return test; |
| 55 } |
| 56 return NULL; |
| 57 } |
| 58 |
| 59 private: |
| 60 const TestRegistry* fReg; |
| 61 }; |
| 62 |
| 63 class DebugfReporter : public Reporter { |
| 64 public: |
| 65 explicit DebugfReporter(int total) : fDone(0), fTotal(total) {} |
| 66 |
| 67 virtual bool allowExtendedTest() const SK_OVERRIDE { return FLAGS_extendedTe
st; } |
| 68 virtual bool allowThreaded() const SK_OVERRIDE { return !FLAGS_single; } |
| 69 virtual bool verbose() const SK_OVERRIDE { return FLAGS_verbose; } |
| 70 |
| 71 protected: |
| 72 virtual void onReportFailed(const SkString& desc) SK_OVERRIDE { |
| 73 SkDebugf("\nFAILED: %s", desc.c_str()); |
| 74 } |
| 75 |
| 76 virtual void onEnd(Test* test) SK_OVERRIDE { |
| 77 const int done = 1 + sk_atomic_inc(&fDone); |
| 78 |
| 79 if (!test->passed()) { |
| 80 SkDebugf("\n---- %s FAILED", test->getName()); |
| 81 } |
| 82 |
| 83 SkString prefix(kSkOverwriteLine); |
| 84 SkString time; |
| 85 if (FLAGS_verbose) { |
| 86 prefix.printf("\n"); |
| 87 time.printf("%5dms ", test->elapsedMs()); |
| 88 } |
| 89 SkDebugf("%s[%3d/%3d] %s%s", prefix.c_str(), done, fTotal, time.c_str(),
test->getName()); |
| 90 } |
| 91 |
| 92 private: |
| 93 int32_t fDone; // atomic |
| 94 const int fTotal; |
| 95 }; |
| 96 |
138 SkString Test::GetTmpDir() { | 97 SkString Test::GetTmpDir() { |
139 const char* tmpDir = FLAGS_tmpDir.isEmpty() ? NULL : FLAGS_tmpDir[0]; | 98 const char* tmpDir = FLAGS_tmpDir.isEmpty() ? NULL : FLAGS_tmpDir[0]; |
140 return SkString(tmpDir); | 99 return SkString(tmpDir); |
141 } | 100 } |
142 | 101 |
143 SkString Test::GetResourcePath() { | 102 SkString Test::GetResourcePath() { |
144 const char* resourcePath = FLAGS_resourcePath.isEmpty() ? NULL : FLAGS_resou
rcePath[0]; | 103 const char* resourcePath = FLAGS_resourcePath.isEmpty() ? NULL : FLAGS_resou
rcePath[0]; |
145 return SkString(resourcePath); | 104 return SkString(resourcePath); |
146 } | 105 } |
147 | 106 |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
190 SkString resourcePath = Test::GetResourcePath(); | 149 SkString resourcePath = Test::GetResourcePath(); |
191 if (!resourcePath.isEmpty()) { | 150 if (!resourcePath.isEmpty()) { |
192 header.appendf(" --resourcePath %s", resourcePath.c_str()); | 151 header.appendf(" --resourcePath %s", resourcePath.c_str()); |
193 } | 152 } |
194 #ifdef SK_DEBUG | 153 #ifdef SK_DEBUG |
195 header.append(" SK_DEBUG"); | 154 header.append(" SK_DEBUG"); |
196 #else | 155 #else |
197 header.append(" SK_RELEASE"); | 156 header.append(" SK_RELEASE"); |
198 #endif | 157 #endif |
199 header.appendf(" skia_arch_width=%d", (int)sizeof(void*) * 8); | 158 header.appendf(" skia_arch_width=%d", (int)sizeof(void*) * 8); |
200 SkDebugf("%s\n", header.c_str()); | 159 SkDebugf(header.c_str()); |
201 } | 160 } |
202 | 161 |
203 DebugfReporter reporter(FLAGS_extendedTest, !FLAGS_single, FLAGS_verbose); | |
204 Iter iter(&reporter); | |
205 | 162 |
206 // Count tests first. | 163 // Count tests first. |
207 int total = 0; | 164 int total = 0; |
208 int toRun = 0; | 165 int toRun = 0; |
209 Test* test; | 166 Test* test; |
210 | 167 |
211 while ((test = iter.next()) != NULL) { | 168 Iter iter; |
| 169 while ((test = iter.next(NULL/*reporter not needed*/)) != NULL) { |
212 SkAutoTDelete<Test> owned(test); | 170 SkAutoTDelete<Test> owned(test); |
213 | 171 |
214 if(!SkCommandLineFlags::ShouldSkip(FLAGS_match, test->getName())) { | 172 if(!SkCommandLineFlags::ShouldSkip(FLAGS_match, test->getName())) { |
215 toRun++; | 173 toRun++; |
216 } | 174 } |
217 total++; | 175 total++; |
218 } | 176 } |
219 reporter.setTotal(toRun); | |
220 | 177 |
221 // Now run them. | 178 // Now run them. |
222 iter.reset(); | 179 iter.reset(); |
223 int32_t failCount = 0; | 180 int32_t failCount = 0; |
224 int skipCount = 0; | 181 int skipCount = 0; |
225 | 182 |
226 SkThreadPool threadpool(FLAGS_threads); | 183 SkThreadPool threadpool(FLAGS_threads); |
227 SkTArray<Test*> unsafeTests; // Always passes ownership to an SkTestRunnabl
e | 184 SkTArray<Test*> unsafeTests; // Always passes ownership to an SkTestRunnabl
e |
| 185 |
| 186 DebugfReporter reporter(toRun); |
228 for (int i = 0; i < total; i++) { | 187 for (int i = 0; i < total; i++) { |
229 SkAutoTDelete<Test> test(iter.next()); | 188 SkAutoTDelete<Test> test(iter.next(&reporter)); |
230 if (SkCommandLineFlags::ShouldSkip(FLAGS_match, test->getName())) { | 189 if (SkCommandLineFlags::ShouldSkip(FLAGS_match, test->getName())) { |
231 ++skipCount; | 190 ++skipCount; |
232 } else if (!test->isThreadsafe()) { | 191 } else if (!test->isThreadsafe()) { |
233 unsafeTests.push_back() = test.detach(); | 192 unsafeTests.push_back() = test.detach(); |
234 } else { | 193 } else { |
235 threadpool.add(SkNEW_ARGS(SkTestRunnable, (test.detach(), &failCount
))); | 194 threadpool.add(SkNEW_ARGS(SkTestRunnable, (test.detach(), &failCount
))); |
236 } | 195 } |
237 } | 196 } |
238 | 197 |
239 // Run the tests that aren't threadsafe. | 198 // Run the tests that aren't threadsafe. |
240 for (int i = 0; i < unsafeTests.count(); i++) { | 199 for (int i = 0; i < unsafeTests.count(); i++) { |
241 SkNEW_ARGS(SkTestRunnable, (unsafeTests[i], &failCount))->run(); | 200 SkNEW_ARGS(SkTestRunnable, (unsafeTests[i], &failCount))->run(); |
242 } | 201 } |
243 | 202 |
244 // Block until threaded tests finish. | 203 // Block until threaded tests finish. |
245 threadpool.wait(); | 204 threadpool.wait(); |
246 | 205 |
247 SkDebugf("Finished %d tests, %d failures, %d skipped.\n", | 206 if (FLAGS_verbose) { |
248 toRun, failCount, skipCount); | 207 SkDebugf("\nFinished %d tests, %d failures, %d skipped. (%d internal tes
ts)", |
249 const int testCount = reporter.countTests(); | 208 toRun, failCount, skipCount, reporter.countTests()); |
250 if (FLAGS_verbose && testCount > 0) { | |
251 SkDebugf("Ran %d Internal tests.\n", testCount); | |
252 } | 209 } |
253 SkGraphics::Term(); | 210 SkGraphics::Term(); |
254 GpuTest::DestroyContexts(); | 211 GpuTest::DestroyContexts(); |
255 | 212 |
| 213 SkDebugf("\n"); |
256 return (failCount == 0) ? 0 : 1; | 214 return (failCount == 0) ? 0 : 1; |
257 } | 215 } |
258 | 216 |
259 #if !defined(SK_BUILD_FOR_IOS) && !defined(SK_BUILD_FOR_NACL) | 217 #if !defined(SK_BUILD_FOR_IOS) && !defined(SK_BUILD_FOR_NACL) |
260 int main(int argc, char * const argv[]) { | 218 int main(int argc, char * const argv[]) { |
261 return tool_main(argc, (char**) argv); | 219 return tool_main(argc, (char**) argv); |
262 } | 220 } |
263 #endif | 221 #endif |
OLD | NEW |