blob: 6330b326a883a6cb26551ca4f985571c144410f7 [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.org197845a2013-04-19 13:24:28 +000010#include "SkRunnable.h"
11#include "SkThreadPool.h"
12#include "SkTArray.h"
13#include "SkTemplates.h"
reed@android.comed673312009-02-27 16:24:51 +000014#include "Test.h"
reed@google.com789c6f22013-02-25 20:24:24 +000015#include "SkOSFile.h"
reed@android.comed673312009-02-27 16:24:51 +000016
robertphillips@google.combdb1be52012-09-07 18:24:43 +000017#if SK_SUPPORT_GPU
18#include "GrContext.h"
19#endif
20
reed@android.comed673312009-02-27 16:24:51 +000021using namespace skiatest;
22
reed@android.comd252db02009-04-01 18:31:44 +000023// need to explicitly declare this, or we get some weird infinite loop llist
24template TestRegistry* TestRegistry::gHead;
25
reed@android.comed673312009-02-27 16:24:51 +000026class Iter {
27public:
28 Iter(Reporter* r) : fReporter(r) {
29 r->ref();
30 fReg = TestRegistry::Head();
31 }
reed@android.com80e39a72009-04-02 16:59:40 +000032
reed@android.comed673312009-02-27 16:24:51 +000033 ~Iter() {
34 fReporter->unref();
35 }
reed@android.com80e39a72009-04-02 16:59:40 +000036
reed@android.comed673312009-02-27 16:24:51 +000037 Test* next() {
38 if (fReg) {
39 TestRegistry::Factory fact = fReg->factory();
40 fReg = fReg->next();
41 Test* test = fact(NULL);
42 test->setReporter(fReporter);
43 return test;
44 }
45 return NULL;
46 }
reed@android.com80e39a72009-04-02 16:59:40 +000047
reed@android.com57b799e2009-04-01 20:26:42 +000048 static int Count() {
49 const TestRegistry* reg = TestRegistry::Head();
50 int count = 0;
51 while (reg) {
52 count += 1;
53 reg = reg->next();
54 }
55 return count;
56 }
reed@android.com80e39a72009-04-02 16:59:40 +000057
reed@android.comed673312009-02-27 16:24:51 +000058private:
59 Reporter* fReporter;
60 const TestRegistry* fReg;
61};
62
63static const char* result2string(Reporter::Result result) {
64 return result == Reporter::kPassed ? "passed" : "FAILED";
65}
66
reed@android.comd252db02009-04-01 18:31:44 +000067class DebugfReporter : public Reporter {
reed@android.com57b799e2009-04-01 20:26:42 +000068public:
caryclark@google.com16cfe402013-04-18 18:47:37 +000069 DebugfReporter(bool allowExtendedTest, bool allowThreaded)
commit-bot@chromium.org197845a2013-04-19 13:24:28 +000070 : fNextIndex(0)
caryclark@google.comd54e1e92013-04-10 15:57:31 +000071 , fTotal(0)
caryclark@google.com16cfe402013-04-18 18:47:37 +000072 , fAllowExtendedTest(allowExtendedTest)
73 , fAllowThreaded(allowThreaded) {
caryclark@google.comd54e1e92013-04-10 15:57:31 +000074 }
reed@android.comeeb3b7f2009-04-09 04:06:54 +000075
commit-bot@chromium.org197845a2013-04-19 13:24:28 +000076 void setTotal(int total) {
reed@android.com57b799e2009-04-01 20:26:42 +000077 fTotal = total;
78 }
caryclark@google.comd54e1e92013-04-10 15:57:31 +000079
80 virtual bool allowExtendedTest() const {
skia.committer@gmail.com391ca662013-04-11 07:01:45 +000081 return fAllowExtendedTest;
caryclark@google.comd54e1e92013-04-10 15:57:31 +000082 }
83
caryclark@google.com16cfe402013-04-18 18:47:37 +000084 virtual bool allowThreaded() const {
85 return fAllowThreaded;
86 }
87
reed@android.comed673312009-02-27 16:24:51 +000088protected:
89 virtual void onStart(Test* test) {
commit-bot@chromium.org197845a2013-04-19 13:24:28 +000090 const int index = sk_atomic_inc(&fNextIndex);
91 SkDebugf("[%d/%d] %s...\n", index+1, fTotal, test->getName());
reed@android.comed673312009-02-27 16:24:51 +000092 }
93 virtual void onReport(const char desc[], Reporter::Result result) {
djsollen@google.comf4d1b392012-11-29 16:29:58 +000094 SkDebugf("\t%s: %s\n", result2string(result), desc);
reed@android.comed673312009-02-27 16:24:51 +000095 }
commit-bot@chromium.org197845a2013-04-19 13:24:28 +000096
97 virtual void onEnd(Test* test) {
98 if (!test->passed()) {
99 SkDebugf("---- FAILED\n");
reed@android.comeeb3b7f2009-04-09 04:06:54 +0000100 }
101 }
commit-bot@chromium.org197845a2013-04-19 13:24:28 +0000102
djsollen@google.comf4d1b392012-11-29 16:29:58 +0000103private:
commit-bot@chromium.org197845a2013-04-19 13:24:28 +0000104 int32_t fNextIndex;
105 int fTotal;
caryclark@google.comd54e1e92013-04-10 15:57:31 +0000106 bool fAllowExtendedTest;
caryclark@google.com16cfe402013-04-18 18:47:37 +0000107 bool fAllowThreaded;
reed@android.comed673312009-02-27 16:24:51 +0000108};
109
reed@google.com789c6f22013-02-25 20:24:24 +0000110static const char* make_canonical_dir_path(const char* path, SkString* storage) {
111 if (path) {
112 // clean it up so it always has a trailing searator
113 size_t len = strlen(path);
114 if (0 == len) {
115 path = NULL;
116 } else if (SkPATH_SEPARATOR != path[len - 1]) {
117 // resize to len + 1, to make room for searator
118 storage->set(path, len + 1);
119 storage->writable_str()[len] = SkPATH_SEPARATOR;
120 path = storage->c_str();
121 }
122 }
123 return path;
124}
125
djsollen@google.comcb626502013-03-20 13:48:20 +0000126static SkString gTmpDir;
reed@google.com789c6f22013-02-25 20:24:24 +0000127
djsollen@google.comcb626502013-03-20 13:48:20 +0000128const SkString& Test::GetTmpDir() {
reed@google.com789c6f22013-02-25 20:24:24 +0000129 return gTmpDir;
130}
131
djsollen@google.comcb626502013-03-20 13:48:20 +0000132static SkString gResourcePath;
133
134const SkString& Test::GetResourcePath() {
135 return gResourcePath;
136}
137
reed@google.com9aff1482013-04-11 18:27:52 +0000138DEFINE_string2(match, m, NULL, "substring of test name to run.");
commit-bot@chromium.orgba59d642013-04-11 16:54:09 +0000139DEFINE_string2(tmpDir, t, NULL, "tmp directory for tests to use.");
140DEFINE_string2(resourcePath, i, NULL, "directory for test resources.");
141DEFINE_bool2(extendedTest, x, false, "run extended tests for pathOps.");
commit-bot@chromium.org197845a2013-04-19 13:24:28 +0000142DEFINE_bool2(threaded, z, false, "allow tests to use multiple threads internally.");
commit-bot@chromium.orgba59d642013-04-11 16:54:09 +0000143DEFINE_bool2(verbose, v, false, "enable verbose output.");
commit-bot@chromium.org197845a2013-04-19 13:24:28 +0000144DEFINE_int32(threads, 8,
145 "If >0, run threadsafe tests on a threadpool with this many threads.");
146
147// Deletes self when run.
148class SkTestRunnable : public SkRunnable {
149public:
150 // Takes ownership of test.
151 SkTestRunnable(Test* test, int32_t* failCount) : fTest(test), fFailCount(failCount) {}
152
153 virtual void run() {
154 fTest->run();
155 if(!fTest->passed()) {
156 sk_atomic_inc(fFailCount);
157 }
158 SkDELETE(this);
159 }
160
161private:
162 SkAutoTDelete<Test> fTest;
163 int32_t* fFailCount;
164};
commit-bot@chromium.orgba59d642013-04-11 16:54:09 +0000165
caryclark@google.com5987f582012-10-02 18:33:14 +0000166int tool_main(int argc, char** argv);
167int tool_main(int argc, char** argv) {
commit-bot@chromium.orgba59d642013-04-11 16:54:09 +0000168 SkCommandLineFlags::SetUsage("");
169 SkCommandLineFlags::Parse(argc, argv);
170
171 if (!FLAGS_tmpDir.isEmpty()) {
172 make_canonical_dir_path(FLAGS_tmpDir[0], &gTmpDir);
173 }
174 if (!FLAGS_resourcePath.isEmpty()) {
175 make_canonical_dir_path(FLAGS_resourcePath[0], &gResourcePath);
176 }
177
bsalomon@google.com4e230682013-01-15 20:37:04 +0000178#if SK_ENABLE_INST_COUNT
reed@google.coma2769752012-07-22 22:33:05 +0000179 gPrintInstCount = true;
180#endif
caryclark@google.comd54e1e92013-04-10 15:57:31 +0000181
reed@google.coma2769752012-07-22 22:33:05 +0000182 SkGraphics::Init();
bungeman@google.com5af16f82011-09-02 15:06:44 +0000183
reed@google.com91d449e2011-10-26 15:25:18 +0000184 {
185 SkString header("Skia UnitTests:");
reed@google.com9aff1482013-04-11 18:27:52 +0000186 if (!FLAGS_match.isEmpty()) {
187 header.appendf(" --match %s", FLAGS_match[0]);
reed@google.com91d449e2011-10-26 15:25:18 +0000188 }
djsollen@google.comcb626502013-03-20 13:48:20 +0000189 if (!gTmpDir.isEmpty()) {
190 header.appendf(" --tmpDir %s", gTmpDir.c_str());
191 }
192 if (!gResourcePath.isEmpty()) {
193 header.appendf(" --resourcePath %s", gResourcePath.c_str());
reed@google.com789c6f22013-02-25 20:24:24 +0000194 }
reed@google.com91d449e2011-10-26 15:25:18 +0000195#ifdef SK_DEBUG
196 header.append(" SK_DEBUG");
197#else
198 header.append(" SK_RELEASE");
199#endif
200#ifdef SK_SCALAR_IS_FIXED
201 header.append(" SK_SCALAR_IS_FIXED");
202#else
203 header.append(" SK_SCALAR_IS_FLOAT");
204#endif
djsollen@google.comf4d1b392012-11-29 16:29:58 +0000205 SkDebugf("%s\n", header.c_str());
reed@google.com91d449e2011-10-26 15:25:18 +0000206 }
207
caryclark@google.com16cfe402013-04-18 18:47:37 +0000208 DebugfReporter reporter(FLAGS_extendedTest, FLAGS_threaded);
reed@android.comed673312009-02-27 16:24:51 +0000209 Iter iter(&reporter);
reed@android.com80e39a72009-04-02 16:59:40 +0000210
reed@android.com57b799e2009-04-01 20:26:42 +0000211 const int count = Iter::Count();
commit-bot@chromium.org197845a2013-04-19 13:24:28 +0000212 reporter.setTotal(count);
213 int32_t failCount = 0;
bungeman@google.com5af16f82011-09-02 15:06:44 +0000214 int skipCount = 0;
commit-bot@chromium.org197845a2013-04-19 13:24:28 +0000215
216 SkAutoTDelete<SkThreadPool> threadpool(SkNEW_ARGS(SkThreadPool, (FLAGS_threads)));
217 SkTArray<Test*> unsafeTests; // Always passes ownership to an SkTestRunnable
218 for (int i = 0; i < count; i++) {
219 SkAutoTDelete<Test> test(iter.next());
reed@google.com9aff1482013-04-11 18:27:52 +0000220 if (!FLAGS_match.isEmpty() && !strstr(test->getName(), FLAGS_match[0])) {
bungeman@google.com5af16f82011-09-02 15:06:44 +0000221 ++skipCount;
commit-bot@chromium.org197845a2013-04-19 13:24:28 +0000222 } else if (!test->isThreadsafe()) {
223 unsafeTests.push_back() = test.detach();
bungeman@google.com5af16f82011-09-02 15:06:44 +0000224 } else {
commit-bot@chromium.org197845a2013-04-19 13:24:28 +0000225 threadpool->add(SkNEW_ARGS(SkTestRunnable, (test.detach(), &failCount)));
bungeman@google.com5af16f82011-09-02 15:06:44 +0000226 }
reed@android.comed673312009-02-27 16:24:51 +0000227 }
reed@android.com57b799e2009-04-01 20:26:42 +0000228
commit-bot@chromium.org197845a2013-04-19 13:24:28 +0000229 // Run the tests that aren't threadsafe.
230 for (int i = 0; i < unsafeTests.count(); i++) {
231 SkNEW_ARGS(SkTestRunnable, (unsafeTests[i], &failCount))->run();
232 }
233
234 // Blocks until threaded tests finish.
235 threadpool.free();
236
djsollen@google.comf4d1b392012-11-29 16:29:58 +0000237 SkDebugf("Finished %d tests, %d failures, %d skipped.\n",
238 count, failCount, skipCount);
commit-bot@chromium.org197845a2013-04-19 13:24:28 +0000239 const int testCount = reporter.countTests();
commit-bot@chromium.orgba59d642013-04-11 16:54:09 +0000240 if (FLAGS_verbose && testCount > 0) {
caryclark@google.comd54e1e92013-04-10 15:57:31 +0000241 SkDebugf("Ran %d Internal tests.\n", testCount);
242 }
robertphillips@google.combdb1be52012-09-07 18:24:43 +0000243#if SK_SUPPORT_GPU
244
245#if GR_CACHE_STATS
246 GrContext *gr = GpuTest::GetContext();
247
248 gr->printCacheStats();
249#endif
250
251#endif
252
reed@google.coma2769752012-07-22 22:33:05 +0000253 SkGraphics::Term();
bsalomon@google.com67b915d2013-02-04 16:13:32 +0000254 GpuTest::DestroyContexts();
reed@google.coma2769752012-07-22 22:33:05 +0000255
bungeman@google.com5af16f82011-09-02 15:06:44 +0000256 return (failCount == 0) ? 0 : 1;
reed@android.comed673312009-02-27 16:24:51 +0000257}
caryclark@google.com5987f582012-10-02 18:33:14 +0000258
borenet@google.com7158e6a2012-11-01 17:43:44 +0000259#if !defined(SK_BUILD_FOR_IOS) && !defined(SK_BUILD_FOR_NACL)
caryclark@google.com5987f582012-10-02 18:33:14 +0000260int main(int argc, char * const argv[]) {
261 return tool_main(argc, (char**) argv);
262}
263#endif