blob: da63d42ea5c7c7af499464ee3ac6245b2bc6a9b6 [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001/*
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 */
commit-bot@chromium.orgba59d642013-04-11 16:54:09 +00007
scroggo@google.com5a6324e2013-04-11 20:11:40 +00008#include "SkCommandLineFlags.h"
reed@android.com5e5adfd2009-03-07 03:39:23 +00009#include "SkGraphics.h"
commit-bot@chromium.org0506b9d2013-04-22 16:43:07 +000010#include "SkOSFile.h"
commit-bot@chromium.org197845a2013-04-19 13:24:28 +000011#include "SkRunnable.h"
commit-bot@chromium.org197845a2013-04-19 13:24:28 +000012#include "SkTArray.h"
13#include "SkTemplates.h"
commit-bot@chromium.org0506b9d2013-04-22 16:43:07 +000014#include "SkThreadPool.h"
15#include "SkTime.h"
reed@android.comed673312009-02-27 16:24:51 +000016#include "Test.h"
17
robertphillips@google.combdb1be52012-09-07 18:24:43 +000018#if SK_SUPPORT_GPU
19#include "GrContext.h"
20#endif
21
reed@android.comed673312009-02-27 16:24:51 +000022using namespace skiatest;
23
reed@android.comd252db02009-04-01 18:31:44 +000024// need to explicitly declare this, or we get some weird infinite loop llist
25template TestRegistry* TestRegistry::gHead;
26
reed@android.comed673312009-02-27 16:24:51 +000027class Iter {
28public:
29 Iter(Reporter* r) : fReporter(r) {
30 r->ref();
commit-bot@chromium.org0506b9d2013-04-22 16:43:07 +000031 this->reset();
32 }
33
34 void reset() {
reed@android.comed673312009-02-27 16:24:51 +000035 fReg = TestRegistry::Head();
36 }
reed@android.com80e39a72009-04-02 16:59:40 +000037
reed@android.comed673312009-02-27 16:24:51 +000038 ~Iter() {
39 fReporter->unref();
40 }
reed@android.com80e39a72009-04-02 16:59:40 +000041
reed@android.comed673312009-02-27 16:24:51 +000042 Test* next() {
43 if (fReg) {
44 TestRegistry::Factory fact = fReg->factory();
45 fReg = fReg->next();
46 Test* test = fact(NULL);
47 test->setReporter(fReporter);
48 return test;
49 }
50 return NULL;
51 }
reed@android.com80e39a72009-04-02 16:59:40 +000052
reed@android.comed673312009-02-27 16:24:51 +000053private:
54 Reporter* fReporter;
55 const TestRegistry* fReg;
56};
57
reed@android.comd252db02009-04-01 18:31:44 +000058class DebugfReporter : public Reporter {
reed@android.com57b799e2009-04-01 20:26:42 +000059public:
caryclark@google.com07e97fc2013-07-08 17:17:02 +000060 DebugfReporter(bool allowExtendedTest, bool allowThreaded, bool verbose)
commit-bot@chromium.org197845a2013-04-19 13:24:28 +000061 : fNextIndex(0)
commit-bot@chromium.org0506b9d2013-04-22 16:43:07 +000062 , fPending(0)
caryclark@google.comd54e1e92013-04-10 15:57:31 +000063 , fTotal(0)
caryclark@google.com16cfe402013-04-18 18:47:37 +000064 , fAllowExtendedTest(allowExtendedTest)
caryclark@google.com07e97fc2013-07-08 17:17:02 +000065 , fAllowThreaded(allowThreaded)
66 , fVerbose(verbose) {
caryclark@google.comd54e1e92013-04-10 15:57:31 +000067 }
reed@android.comeeb3b7f2009-04-09 04:06:54 +000068
commit-bot@chromium.org197845a2013-04-19 13:24:28 +000069 void setTotal(int total) {
reed@android.com57b799e2009-04-01 20:26:42 +000070 fTotal = total;
71 }
caryclark@google.comd54e1e92013-04-10 15:57:31 +000072
commit-bot@chromium.orge1c54292013-04-22 17:35:55 +000073 virtual bool allowExtendedTest() const SK_OVERRIDE {
skia.committer@gmail.com391ca662013-04-11 07:01:45 +000074 return fAllowExtendedTest;
caryclark@google.comd54e1e92013-04-10 15:57:31 +000075 }
76
commit-bot@chromium.orge1c54292013-04-22 17:35:55 +000077 virtual bool allowThreaded() const SK_OVERRIDE {
caryclark@google.com16cfe402013-04-18 18:47:37 +000078 return fAllowThreaded;
79 }
80
caryclark@google.com07e97fc2013-07-08 17:17:02 +000081 virtual bool verbose() const SK_OVERRIDE {
82 return fVerbose;
83 }
84
reed@android.comed673312009-02-27 16:24:51 +000085protected:
86 virtual void onStart(Test* test) {
commit-bot@chromium.org197845a2013-04-19 13:24:28 +000087 const int index = sk_atomic_inc(&fNextIndex);
commit-bot@chromium.org0506b9d2013-04-22 16:43:07 +000088 sk_atomic_inc(&fPending);
89 SkDebugf("[%3d/%3d] (%d) %s\n", index+1, fTotal, fPending, test->getName());
reed@android.comed673312009-02-27 16:24:51 +000090 }
commit-bot@chromium.org1f792862013-06-18 20:50:34 +000091 virtual void onReportFailed(const SkString& desc) {
92 SkDebugf("\tFAILED: %s\n", desc.c_str());
reed@android.comed673312009-02-27 16:24:51 +000093 }
commit-bot@chromium.org197845a2013-04-19 13:24:28 +000094
95 virtual void onEnd(Test* test) {
96 if (!test->passed()) {
commit-bot@chromium.org0506b9d2013-04-22 16:43:07 +000097 SkDebugf("---- %s FAILED\n", test->getName());
98 }
99
100 sk_atomic_dec(&fPending);
101 if (fNextIndex == fTotal) {
102 // Just waiting on straggler tests. Shame them by printing their name and runtime.
103 SkDebugf(" (%d) %5.1fs %s\n",
104 fPending, test->elapsedMs() / 1e3, test->getName());
reed@android.comeeb3b7f2009-04-09 04:06:54 +0000105 }
106 }
commit-bot@chromium.org197845a2013-04-19 13:24:28 +0000107
djsollen@google.comf4d1b392012-11-29 16:29:58 +0000108private:
commit-bot@chromium.org197845a2013-04-19 13:24:28 +0000109 int32_t fNextIndex;
commit-bot@chromium.org0506b9d2013-04-22 16:43:07 +0000110 int32_t fPending;
commit-bot@chromium.org197845a2013-04-19 13:24:28 +0000111 int fTotal;
caryclark@google.comd54e1e92013-04-10 15:57:31 +0000112 bool fAllowExtendedTest;
caryclark@google.com16cfe402013-04-18 18:47:37 +0000113 bool fAllowThreaded;
caryclark@google.com07e97fc2013-07-08 17:17:02 +0000114 bool fVerbose;
reed@android.comed673312009-02-27 16:24:51 +0000115};
116
caryclark@google.comb631eec2013-05-02 13:14:40 +0000117DEFINE_string2(match, m, NULL, "[~][^]substring[$] [...] of test name to run.\n" \
118 "Multiple matches may be separated by spaces.\n" \
119 "~ causes a matching test to always be skipped\n" \
120 "^ requires the start of the test to match\n" \
121 "$ requires the end of the test to match\n" \
122 "^ and $ requires an exact match\n" \
123 "If a test does not match any list entry,\n" \
124 "it is skipped unless some list entry starts with ~");
commit-bot@chromium.orgba59d642013-04-11 16:54:09 +0000125DEFINE_string2(tmpDir, t, NULL, "tmp directory for tests to use.");
126DEFINE_string2(resourcePath, i, NULL, "directory for test resources.");
127DEFINE_bool2(extendedTest, x, false, "run extended tests for pathOps.");
caryclark@google.com8d0a5242013-07-16 16:11:16 +0000128DEFINE_bool2(single, z, false, "run tests on a single thread internally.");
commit-bot@chromium.orgba59d642013-04-11 16:54:09 +0000129DEFINE_bool2(verbose, v, false, "enable verbose output.");
commit-bot@chromium.org44c661f2013-04-22 15:23:14 +0000130DEFINE_int32(threads, SkThreadPool::kThreadPerCore,
131 "Run threadsafe tests on a threadpool with this many threads.");
commit-bot@chromium.org197845a2013-04-19 13:24:28 +0000132
scroggo@google.comc76218d2013-06-06 14:59:56 +0000133SkString Test::GetTmpDir() {
134 const char* tmpDir = FLAGS_tmpDir.isEmpty() ? NULL : FLAGS_tmpDir[0];
135 return SkString(tmpDir);
136}
137
138SkString Test::GetResourcePath() {
139 const char* resourcePath = FLAGS_resourcePath.isEmpty() ? NULL : FLAGS_resourcePath[0];
140 return SkString(resourcePath);
141}
142
commit-bot@chromium.org197845a2013-04-19 13:24:28 +0000143// Deletes self when run.
144class SkTestRunnable : public SkRunnable {
145public:
146 // Takes ownership of test.
147 SkTestRunnable(Test* test, int32_t* failCount) : fTest(test), fFailCount(failCount) {}
148
149 virtual void run() {
150 fTest->run();
151 if(!fTest->passed()) {
152 sk_atomic_inc(fFailCount);
153 }
154 SkDELETE(this);
155 }
156
157private:
158 SkAutoTDelete<Test> fTest;
159 int32_t* fFailCount;
160};
commit-bot@chromium.orgba59d642013-04-11 16:54:09 +0000161
caryclark@google.comb631eec2013-05-02 13:14:40 +0000162/* Takes a list of the form [~][^]match[$]
163 ~ causes a matching test to always be skipped
164 ^ requires the start of the test to match
165 $ requires the end of the test to match
166 ^ and $ requires an exact match
167 If a test does not match any list entry, it is skipped unless some list entry starts with ~
168 */
commit-bot@chromium.org0506b9d2013-04-22 16:43:07 +0000169static bool shouldSkip(const char* testName) {
caryclark@google.comb631eec2013-05-02 13:14:40 +0000170 int count = FLAGS_match.count();
171 size_t testLen = strlen(testName);
caryclark@google.com89d18272013-05-02 14:23:07 +0000172 bool anyExclude = count == 0;
caryclark@google.comb631eec2013-05-02 13:14:40 +0000173 for (int index = 0; index < count; ++index) {
174 const char* matchName = FLAGS_match[index];
175 size_t matchLen = strlen(matchName);
176 bool matchExclude, matchStart, matchEnd;
177 if ((matchExclude = matchName[0] == '~')) {
178 anyExclude = true;
179 matchName++;
180 matchLen--;
181 }
182 if ((matchStart = matchName[0] == '^')) {
183 matchName++;
184 matchLen--;
185 }
186 if ((matchEnd = matchName[matchLen - 1] == '$')) {
187 matchLen--;
188 }
189 if (matchStart ? (!matchEnd || matchLen == testLen)
190 && strncmp(testName, matchName, matchLen) == 0
191 : matchEnd ? matchLen <= testLen
192 && strncmp(testName + testLen - matchLen, matchName, matchLen) == 0
193 : strstr(testName, matchName) != 0) {
194 return matchExclude;
195 }
196 }
197 return !anyExclude;
commit-bot@chromium.org0506b9d2013-04-22 16:43:07 +0000198}
199
caryclark@google.com5987f582012-10-02 18:33:14 +0000200int tool_main(int argc, char** argv);
201int tool_main(int argc, char** argv) {
commit-bot@chromium.orgba59d642013-04-11 16:54:09 +0000202 SkCommandLineFlags::SetUsage("");
203 SkCommandLineFlags::Parse(argc, argv);
204
bsalomon@google.com4e230682013-01-15 20:37:04 +0000205#if SK_ENABLE_INST_COUNT
reed@google.coma2769752012-07-22 22:33:05 +0000206 gPrintInstCount = true;
207#endif
caryclark@google.comd54e1e92013-04-10 15:57:31 +0000208
reed@google.coma2769752012-07-22 22:33:05 +0000209 SkGraphics::Init();
bungeman@google.com5af16f82011-09-02 15:06:44 +0000210
reed@google.com91d449e2011-10-26 15:25:18 +0000211 {
212 SkString header("Skia UnitTests:");
reed@google.com9aff1482013-04-11 18:27:52 +0000213 if (!FLAGS_match.isEmpty()) {
caryclark@google.comb631eec2013-05-02 13:14:40 +0000214 header.appendf(" --match");
215 for (int index = 0; index < FLAGS_match.count(); ++index) {
216 header.appendf(" %s", FLAGS_match[index]);
217 }
reed@google.com91d449e2011-10-26 15:25:18 +0000218 }
scroggo@google.comc76218d2013-06-06 14:59:56 +0000219 SkString tmpDir = Test::GetTmpDir();
220 if (!tmpDir.isEmpty()) {
221 header.appendf(" --tmpDir %s", tmpDir.c_str());
djsollen@google.comcb626502013-03-20 13:48:20 +0000222 }
scroggo@google.comc76218d2013-06-06 14:59:56 +0000223 SkString resourcePath = Test::GetResourcePath();
224 if (!resourcePath.isEmpty()) {
225 header.appendf(" --resourcePath %s", resourcePath.c_str());
reed@google.com789c6f22013-02-25 20:24:24 +0000226 }
reed@google.com91d449e2011-10-26 15:25:18 +0000227#ifdef SK_DEBUG
228 header.append(" SK_DEBUG");
229#else
230 header.append(" SK_RELEASE");
231#endif
232#ifdef SK_SCALAR_IS_FIXED
233 header.append(" SK_SCALAR_IS_FIXED");
234#else
235 header.append(" SK_SCALAR_IS_FLOAT");
236#endif
djsollen@google.comf4d1b392012-11-29 16:29:58 +0000237 SkDebugf("%s\n", header.c_str());
reed@google.com91d449e2011-10-26 15:25:18 +0000238 }
239
caryclark@google.com8d0a5242013-07-16 16:11:16 +0000240 DebugfReporter reporter(FLAGS_extendedTest, !FLAGS_single, FLAGS_verbose);
reed@android.comed673312009-02-27 16:24:51 +0000241 Iter iter(&reporter);
reed@android.com80e39a72009-04-02 16:59:40 +0000242
commit-bot@chromium.org0506b9d2013-04-22 16:43:07 +0000243 // Count tests first.
244 int total = 0;
245 int toRun = 0;
246 Test* test;
247 while ((test = iter.next()) != NULL) {
248 SkAutoTDelete<Test> owned(test);
249 if(!shouldSkip(test->getName())) {
250 toRun++;
251 }
252 total++;
253 }
254 reporter.setTotal(toRun);
255
256 // Now run them.
257 iter.reset();
commit-bot@chromium.org197845a2013-04-19 13:24:28 +0000258 int32_t failCount = 0;
bungeman@google.com5af16f82011-09-02 15:06:44 +0000259 int skipCount = 0;
commit-bot@chromium.org197845a2013-04-19 13:24:28 +0000260
261 SkAutoTDelete<SkThreadPool> threadpool(SkNEW_ARGS(SkThreadPool, (FLAGS_threads)));
262 SkTArray<Test*> unsafeTests; // Always passes ownership to an SkTestRunnable
commit-bot@chromium.org0506b9d2013-04-22 16:43:07 +0000263 for (int i = 0; i < total; i++) {
commit-bot@chromium.org197845a2013-04-19 13:24:28 +0000264 SkAutoTDelete<Test> test(iter.next());
commit-bot@chromium.org0506b9d2013-04-22 16:43:07 +0000265 if (shouldSkip(test->getName())) {
bungeman@google.com5af16f82011-09-02 15:06:44 +0000266 ++skipCount;
commit-bot@chromium.org197845a2013-04-19 13:24:28 +0000267 } else if (!test->isThreadsafe()) {
268 unsafeTests.push_back() = test.detach();
bungeman@google.com5af16f82011-09-02 15:06:44 +0000269 } else {
commit-bot@chromium.org197845a2013-04-19 13:24:28 +0000270 threadpool->add(SkNEW_ARGS(SkTestRunnable, (test.detach(), &failCount)));
bungeman@google.com5af16f82011-09-02 15:06:44 +0000271 }
reed@android.comed673312009-02-27 16:24:51 +0000272 }
reed@android.com57b799e2009-04-01 20:26:42 +0000273
commit-bot@chromium.org197845a2013-04-19 13:24:28 +0000274 // Run the tests that aren't threadsafe.
275 for (int i = 0; i < unsafeTests.count(); i++) {
276 SkNEW_ARGS(SkTestRunnable, (unsafeTests[i], &failCount))->run();
277 }
278
279 // Blocks until threaded tests finish.
280 threadpool.free();
281
djsollen@google.comf4d1b392012-11-29 16:29:58 +0000282 SkDebugf("Finished %d tests, %d failures, %d skipped.\n",
commit-bot@chromium.org0506b9d2013-04-22 16:43:07 +0000283 toRun, failCount, skipCount);
commit-bot@chromium.org197845a2013-04-19 13:24:28 +0000284 const int testCount = reporter.countTests();
commit-bot@chromium.orgba59d642013-04-11 16:54:09 +0000285 if (FLAGS_verbose && testCount > 0) {
caryclark@google.comd54e1e92013-04-10 15:57:31 +0000286 SkDebugf("Ran %d Internal tests.\n", testCount);
287 }
robertphillips@google.combdb1be52012-09-07 18:24:43 +0000288#if SK_SUPPORT_GPU
289
290#if GR_CACHE_STATS
291 GrContext *gr = GpuTest::GetContext();
292
293 gr->printCacheStats();
294#endif
295
296#endif
297
reed@google.coma2769752012-07-22 22:33:05 +0000298 SkGraphics::Term();
bsalomon@google.com67b915d2013-02-04 16:13:32 +0000299 GpuTest::DestroyContexts();
reed@google.coma2769752012-07-22 22:33:05 +0000300
bungeman@google.com5af16f82011-09-02 15:06:44 +0000301 return (failCount == 0) ? 0 : 1;
reed@android.comed673312009-02-27 16:24:51 +0000302}
caryclark@google.com5987f582012-10-02 18:33:14 +0000303
borenet@google.com7158e6a2012-11-01 17:43:44 +0000304#if !defined(SK_BUILD_FOR_IOS) && !defined(SK_BUILD_FOR_NACL)
caryclark@google.com5987f582012-10-02 18:33:14 +0000305int main(int argc, char * const argv[]) {
306 return tool_main(argc, (char**) argv);
307}
308#endif