blob: 7db5e5ccc3dec2b14b0ae6e3bc573f18a491282d [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
58static const char* result2string(Reporter::Result result) {
59 return result == Reporter::kPassed ? "passed" : "FAILED";
60}
61
reed@android.comd252db02009-04-01 18:31:44 +000062class DebugfReporter : public Reporter {
reed@android.com57b799e2009-04-01 20:26:42 +000063public:
caryclark@google.com16cfe402013-04-18 18:47:37 +000064 DebugfReporter(bool allowExtendedTest, bool allowThreaded)
commit-bot@chromium.org197845a2013-04-19 13:24:28 +000065 : fNextIndex(0)
commit-bot@chromium.org0506b9d2013-04-22 16:43:07 +000066 , fPending(0)
caryclark@google.comd54e1e92013-04-10 15:57:31 +000067 , fTotal(0)
caryclark@google.com16cfe402013-04-18 18:47:37 +000068 , fAllowExtendedTest(allowExtendedTest)
69 , fAllowThreaded(allowThreaded) {
caryclark@google.comd54e1e92013-04-10 15:57:31 +000070 }
reed@android.comeeb3b7f2009-04-09 04:06:54 +000071
commit-bot@chromium.org197845a2013-04-19 13:24:28 +000072 void setTotal(int total) {
reed@android.com57b799e2009-04-01 20:26:42 +000073 fTotal = total;
74 }
caryclark@google.comd54e1e92013-04-10 15:57:31 +000075
76 virtual bool allowExtendedTest() const {
skia.committer@gmail.com391ca662013-04-11 07:01:45 +000077 return fAllowExtendedTest;
caryclark@google.comd54e1e92013-04-10 15:57:31 +000078 }
79
caryclark@google.com16cfe402013-04-18 18:47:37 +000080 virtual bool allowThreaded() const {
81 return fAllowThreaded;
82 }
83
reed@android.comed673312009-02-27 16:24:51 +000084protected:
85 virtual void onStart(Test* test) {
commit-bot@chromium.org197845a2013-04-19 13:24:28 +000086 const int index = sk_atomic_inc(&fNextIndex);
commit-bot@chromium.org0506b9d2013-04-22 16:43:07 +000087 sk_atomic_inc(&fPending);
88 SkDebugf("[%3d/%3d] (%d) %s\n", index+1, fTotal, fPending, test->getName());
reed@android.comed673312009-02-27 16:24:51 +000089 }
90 virtual void onReport(const char desc[], Reporter::Result result) {
djsollen@google.comf4d1b392012-11-29 16:29:58 +000091 SkDebugf("\t%s: %s\n", result2string(result), desc);
reed@android.comed673312009-02-27 16:24:51 +000092 }
commit-bot@chromium.org197845a2013-04-19 13:24:28 +000093
94 virtual void onEnd(Test* test) {
95 if (!test->passed()) {
commit-bot@chromium.org0506b9d2013-04-22 16:43:07 +000096 SkDebugf("---- %s FAILED\n", test->getName());
97 }
98
99 sk_atomic_dec(&fPending);
100 if (fNextIndex == fTotal) {
101 // Just waiting on straggler tests. Shame them by printing their name and runtime.
102 SkDebugf(" (%d) %5.1fs %s\n",
103 fPending, test->elapsedMs() / 1e3, test->getName());
reed@android.comeeb3b7f2009-04-09 04:06:54 +0000104 }
105 }
commit-bot@chromium.org197845a2013-04-19 13:24:28 +0000106
djsollen@google.comf4d1b392012-11-29 16:29:58 +0000107private:
commit-bot@chromium.org197845a2013-04-19 13:24:28 +0000108 int32_t fNextIndex;
commit-bot@chromium.org0506b9d2013-04-22 16:43:07 +0000109 int32_t fPending;
commit-bot@chromium.org197845a2013-04-19 13:24:28 +0000110 int fTotal;
caryclark@google.comd54e1e92013-04-10 15:57:31 +0000111 bool fAllowExtendedTest;
caryclark@google.com16cfe402013-04-18 18:47:37 +0000112 bool fAllowThreaded;
reed@android.comed673312009-02-27 16:24:51 +0000113};
114
reed@google.com789c6f22013-02-25 20:24:24 +0000115static const char* make_canonical_dir_path(const char* path, SkString* storage) {
116 if (path) {
117 // clean it up so it always has a trailing searator
118 size_t len = strlen(path);
119 if (0 == len) {
120 path = NULL;
121 } else if (SkPATH_SEPARATOR != path[len - 1]) {
122 // resize to len + 1, to make room for searator
123 storage->set(path, len + 1);
124 storage->writable_str()[len] = SkPATH_SEPARATOR;
125 path = storage->c_str();
126 }
127 }
128 return path;
129}
130
djsollen@google.comcb626502013-03-20 13:48:20 +0000131static SkString gTmpDir;
reed@google.com789c6f22013-02-25 20:24:24 +0000132
djsollen@google.comcb626502013-03-20 13:48:20 +0000133const SkString& Test::GetTmpDir() {
reed@google.com789c6f22013-02-25 20:24:24 +0000134 return gTmpDir;
135}
136
djsollen@google.comcb626502013-03-20 13:48:20 +0000137static SkString gResourcePath;
138
139const SkString& Test::GetResourcePath() {
140 return gResourcePath;
141}
142
reed@google.com9aff1482013-04-11 18:27:52 +0000143DEFINE_string2(match, m, NULL, "substring of test name to run.");
commit-bot@chromium.orgba59d642013-04-11 16:54:09 +0000144DEFINE_string2(tmpDir, t, NULL, "tmp directory for tests to use.");
145DEFINE_string2(resourcePath, i, NULL, "directory for test resources.");
146DEFINE_bool2(extendedTest, x, false, "run extended tests for pathOps.");
commit-bot@chromium.org197845a2013-04-19 13:24:28 +0000147DEFINE_bool2(threaded, z, false, "allow tests to use multiple threads internally.");
commit-bot@chromium.orgba59d642013-04-11 16:54:09 +0000148DEFINE_bool2(verbose, v, false, "enable verbose output.");
commit-bot@chromium.org44c661f2013-04-22 15:23:14 +0000149DEFINE_int32(threads, SkThreadPool::kThreadPerCore,
150 "Run threadsafe tests on a threadpool with this many threads.");
commit-bot@chromium.org197845a2013-04-19 13:24:28 +0000151
152// Deletes self when run.
153class SkTestRunnable : public SkRunnable {
154public:
155 // Takes ownership of test.
156 SkTestRunnable(Test* test, int32_t* failCount) : fTest(test), fFailCount(failCount) {}
157
158 virtual void run() {
159 fTest->run();
160 if(!fTest->passed()) {
161 sk_atomic_inc(fFailCount);
162 }
163 SkDELETE(this);
164 }
165
166private:
167 SkAutoTDelete<Test> fTest;
168 int32_t* fFailCount;
169};
commit-bot@chromium.orgba59d642013-04-11 16:54:09 +0000170
commit-bot@chromium.org0506b9d2013-04-22 16:43:07 +0000171static bool shouldSkip(const char* testName) {
172 return !FLAGS_match.isEmpty() && !strstr(testName, FLAGS_match[0]);
173}
174
caryclark@google.com5987f582012-10-02 18:33:14 +0000175int tool_main(int argc, char** argv);
176int tool_main(int argc, char** argv) {
commit-bot@chromium.orgba59d642013-04-11 16:54:09 +0000177 SkCommandLineFlags::SetUsage("");
178 SkCommandLineFlags::Parse(argc, argv);
179
180 if (!FLAGS_tmpDir.isEmpty()) {
181 make_canonical_dir_path(FLAGS_tmpDir[0], &gTmpDir);
182 }
183 if (!FLAGS_resourcePath.isEmpty()) {
184 make_canonical_dir_path(FLAGS_resourcePath[0], &gResourcePath);
185 }
186
bsalomon@google.com4e230682013-01-15 20:37:04 +0000187#if SK_ENABLE_INST_COUNT
reed@google.coma2769752012-07-22 22:33:05 +0000188 gPrintInstCount = true;
189#endif
caryclark@google.comd54e1e92013-04-10 15:57:31 +0000190
reed@google.coma2769752012-07-22 22:33:05 +0000191 SkGraphics::Init();
bungeman@google.com5af16f82011-09-02 15:06:44 +0000192
reed@google.com91d449e2011-10-26 15:25:18 +0000193 {
194 SkString header("Skia UnitTests:");
reed@google.com9aff1482013-04-11 18:27:52 +0000195 if (!FLAGS_match.isEmpty()) {
196 header.appendf(" --match %s", FLAGS_match[0]);
reed@google.com91d449e2011-10-26 15:25:18 +0000197 }
djsollen@google.comcb626502013-03-20 13:48:20 +0000198 if (!gTmpDir.isEmpty()) {
199 header.appendf(" --tmpDir %s", gTmpDir.c_str());
200 }
201 if (!gResourcePath.isEmpty()) {
202 header.appendf(" --resourcePath %s", gResourcePath.c_str());
reed@google.com789c6f22013-02-25 20:24:24 +0000203 }
reed@google.com91d449e2011-10-26 15:25:18 +0000204#ifdef SK_DEBUG
205 header.append(" SK_DEBUG");
206#else
207 header.append(" SK_RELEASE");
208#endif
209#ifdef SK_SCALAR_IS_FIXED
210 header.append(" SK_SCALAR_IS_FIXED");
211#else
212 header.append(" SK_SCALAR_IS_FLOAT");
213#endif
djsollen@google.comf4d1b392012-11-29 16:29:58 +0000214 SkDebugf("%s\n", header.c_str());
reed@google.com91d449e2011-10-26 15:25:18 +0000215 }
216
caryclark@google.com16cfe402013-04-18 18:47:37 +0000217 DebugfReporter reporter(FLAGS_extendedTest, FLAGS_threaded);
reed@android.comed673312009-02-27 16:24:51 +0000218 Iter iter(&reporter);
reed@android.com80e39a72009-04-02 16:59:40 +0000219
commit-bot@chromium.org0506b9d2013-04-22 16:43:07 +0000220 // Count tests first.
221 int total = 0;
222 int toRun = 0;
223 Test* test;
224 while ((test = iter.next()) != NULL) {
225 SkAutoTDelete<Test> owned(test);
226 if(!shouldSkip(test->getName())) {
227 toRun++;
228 }
229 total++;
230 }
231 reporter.setTotal(toRun);
232
233 // Now run them.
234 iter.reset();
commit-bot@chromium.org197845a2013-04-19 13:24:28 +0000235 int32_t failCount = 0;
bungeman@google.com5af16f82011-09-02 15:06:44 +0000236 int skipCount = 0;
commit-bot@chromium.org197845a2013-04-19 13:24:28 +0000237
238 SkAutoTDelete<SkThreadPool> threadpool(SkNEW_ARGS(SkThreadPool, (FLAGS_threads)));
239 SkTArray<Test*> unsafeTests; // Always passes ownership to an SkTestRunnable
commit-bot@chromium.org0506b9d2013-04-22 16:43:07 +0000240 for (int i = 0; i < total; i++) {
commit-bot@chromium.org197845a2013-04-19 13:24:28 +0000241 SkAutoTDelete<Test> test(iter.next());
commit-bot@chromium.org0506b9d2013-04-22 16:43:07 +0000242 if (shouldSkip(test->getName())) {
bungeman@google.com5af16f82011-09-02 15:06:44 +0000243 ++skipCount;
commit-bot@chromium.org197845a2013-04-19 13:24:28 +0000244 } else if (!test->isThreadsafe()) {
245 unsafeTests.push_back() = test.detach();
bungeman@google.com5af16f82011-09-02 15:06:44 +0000246 } else {
commit-bot@chromium.org197845a2013-04-19 13:24:28 +0000247 threadpool->add(SkNEW_ARGS(SkTestRunnable, (test.detach(), &failCount)));
bungeman@google.com5af16f82011-09-02 15:06:44 +0000248 }
reed@android.comed673312009-02-27 16:24:51 +0000249 }
reed@android.com57b799e2009-04-01 20:26:42 +0000250
commit-bot@chromium.org197845a2013-04-19 13:24:28 +0000251 // Run the tests that aren't threadsafe.
252 for (int i = 0; i < unsafeTests.count(); i++) {
253 SkNEW_ARGS(SkTestRunnable, (unsafeTests[i], &failCount))->run();
254 }
255
256 // Blocks until threaded tests finish.
257 threadpool.free();
258
djsollen@google.comf4d1b392012-11-29 16:29:58 +0000259 SkDebugf("Finished %d tests, %d failures, %d skipped.\n",
commit-bot@chromium.org0506b9d2013-04-22 16:43:07 +0000260 toRun, failCount, skipCount);
commit-bot@chromium.org197845a2013-04-19 13:24:28 +0000261 const int testCount = reporter.countTests();
commit-bot@chromium.orgba59d642013-04-11 16:54:09 +0000262 if (FLAGS_verbose && testCount > 0) {
caryclark@google.comd54e1e92013-04-10 15:57:31 +0000263 SkDebugf("Ran %d Internal tests.\n", testCount);
264 }
robertphillips@google.combdb1be52012-09-07 18:24:43 +0000265#if SK_SUPPORT_GPU
266
267#if GR_CACHE_STATS
268 GrContext *gr = GpuTest::GetContext();
269
270 gr->printCacheStats();
271#endif
272
273#endif
274
reed@google.coma2769752012-07-22 22:33:05 +0000275 SkGraphics::Term();
bsalomon@google.com67b915d2013-02-04 16:13:32 +0000276 GpuTest::DestroyContexts();
reed@google.coma2769752012-07-22 22:33:05 +0000277
bungeman@google.com5af16f82011-09-02 15:06:44 +0000278 return (failCount == 0) ? 0 : 1;
reed@android.comed673312009-02-27 16:24:51 +0000279}
caryclark@google.com5987f582012-10-02 18:33:14 +0000280
borenet@google.com7158e6a2012-11-01 17:43:44 +0000281#if !defined(SK_BUILD_FOR_IOS) && !defined(SK_BUILD_FOR_NACL)
caryclark@google.com5987f582012-10-02 18:33:14 +0000282int main(int argc, char * const argv[]) {
283 return tool_main(argc, (char**) argv);
284}
285#endif