blob: b8f80e0c4b54662cf5df300c3aa95d82b597e0c5 [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 "SkTArray.h"
12#include "SkTemplates.h"
commit-bot@chromium.org0506b9d2013-04-22 16:43:07 +000013#include "SkThreadPool.h"
14#include "SkTime.h"
reed@android.comed673312009-02-27 16:24:51 +000015#include "Test.h"
16
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();
commit-bot@chromium.org0506b9d2013-04-22 16:43:07 +000030 this->reset();
31 }
32
33 void reset() {
reed@android.comed673312009-02-27 16:24:51 +000034 fReg = TestRegistry::Head();
35 }
reed@android.com80e39a72009-04-02 16:59:40 +000036
reed@android.comed673312009-02-27 16:24:51 +000037 ~Iter() {
38 fReporter->unref();
39 }
reed@android.com80e39a72009-04-02 16:59:40 +000040
reed@android.comed673312009-02-27 16:24:51 +000041 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 }
reed@android.com80e39a72009-04-02 16:59:40 +000051
reed@android.comed673312009-02-27 16:24:51 +000052private:
53 Reporter* fReporter;
54 const TestRegistry* fReg;
55};
56
reed@android.comd252db02009-04-01 18:31:44 +000057class DebugfReporter : public Reporter {
reed@android.com57b799e2009-04-01 20:26:42 +000058public:
caryclark@google.com07e97fc2013-07-08 17:17:02 +000059 DebugfReporter(bool allowExtendedTest, bool allowThreaded, bool verbose)
commit-bot@chromium.org197845a2013-04-19 13:24:28 +000060 : fNextIndex(0)
commit-bot@chromium.org0506b9d2013-04-22 16:43:07 +000061 , fPending(0)
caryclark@google.comd54e1e92013-04-10 15:57:31 +000062 , fTotal(0)
caryclark@google.com16cfe402013-04-18 18:47:37 +000063 , fAllowExtendedTest(allowExtendedTest)
caryclark@google.com07e97fc2013-07-08 17:17:02 +000064 , fAllowThreaded(allowThreaded)
65 , fVerbose(verbose) {
caryclark@google.comd54e1e92013-04-10 15:57:31 +000066 }
reed@android.comeeb3b7f2009-04-09 04:06:54 +000067
commit-bot@chromium.org197845a2013-04-19 13:24:28 +000068 void setTotal(int total) {
reed@android.com57b799e2009-04-01 20:26:42 +000069 fTotal = total;
70 }
caryclark@google.comd54e1e92013-04-10 15:57:31 +000071
commit-bot@chromium.orge1c54292013-04-22 17:35:55 +000072 virtual bool allowExtendedTest() const SK_OVERRIDE {
skia.committer@gmail.com391ca662013-04-11 07:01:45 +000073 return fAllowExtendedTest;
caryclark@google.comd54e1e92013-04-10 15:57:31 +000074 }
75
commit-bot@chromium.orge1c54292013-04-22 17:35:55 +000076 virtual bool allowThreaded() const SK_OVERRIDE {
caryclark@google.com16cfe402013-04-18 18:47:37 +000077 return fAllowThreaded;
78 }
79
caryclark@google.com07e97fc2013-07-08 17:17:02 +000080 virtual bool verbose() const SK_OVERRIDE {
81 return fVerbose;
82 }
83
reed@android.comed673312009-02-27 16:24:51 +000084protected:
85 virtual void onStart(Test* test) {
commit-bot@chromium.orgf6842e72013-10-01 18:43:50 +000086 SkAutoMutexAcquire lock(fStartEndMutex);
87 fNextIndex++;
88 fPending++;
89 SkDebugf("[%3d/%3d] (%d) %s\n", fNextIndex, fTotal, fPending, test->getName());
reed@android.comed673312009-02-27 16:24:51 +000090 }
commit-bot@chromium.orgf6842e72013-10-01 18:43:50 +000091
commit-bot@chromium.org1f792862013-06-18 20:50:34 +000092 virtual void onReportFailed(const SkString& desc) {
93 SkDebugf("\tFAILED: %s\n", desc.c_str());
reed@android.comed673312009-02-27 16:24:51 +000094 }
commit-bot@chromium.org197845a2013-04-19 13:24:28 +000095
96 virtual void onEnd(Test* test) {
commit-bot@chromium.orgf6842e72013-10-01 18:43:50 +000097 SkAutoMutexAcquire lock(fStartEndMutex);
commit-bot@chromium.org197845a2013-04-19 13:24:28 +000098 if (!test->passed()) {
commit-bot@chromium.org0506b9d2013-04-22 16:43:07 +000099 SkDebugf("---- %s FAILED\n", test->getName());
100 }
101
commit-bot@chromium.orgf6842e72013-10-01 18:43:50 +0000102 fPending--;
commit-bot@chromium.org0506b9d2013-04-22 16:43:07 +0000103 if (fNextIndex == fTotal) {
104 // Just waiting on straggler tests. Shame them by printing their name and runtime.
105 SkDebugf(" (%d) %5.1fs %s\n",
106 fPending, test->elapsedMs() / 1e3, test->getName());
reed@android.comeeb3b7f2009-04-09 04:06:54 +0000107 }
108 }
commit-bot@chromium.org197845a2013-04-19 13:24:28 +0000109
djsollen@google.comf4d1b392012-11-29 16:29:58 +0000110private:
commit-bot@chromium.orgf6842e72013-10-01 18:43:50 +0000111 SkMutex fStartEndMutex; // Guards fNextIndex and fPending.
commit-bot@chromium.org197845a2013-04-19 13:24:28 +0000112 int32_t fNextIndex;
commit-bot@chromium.org0506b9d2013-04-22 16:43:07 +0000113 int32_t fPending;
commit-bot@chromium.orgf6842e72013-10-01 18:43:50 +0000114
115 // Once the tests get going, these are logically const.
commit-bot@chromium.org197845a2013-04-19 13:24:28 +0000116 int fTotal;
caryclark@google.comd54e1e92013-04-10 15:57:31 +0000117 bool fAllowExtendedTest;
caryclark@google.com16cfe402013-04-18 18:47:37 +0000118 bool fAllowThreaded;
caryclark@google.com07e97fc2013-07-08 17:17:02 +0000119 bool fVerbose;
reed@android.comed673312009-02-27 16:24:51 +0000120};
121
caryclark@google.comb631eec2013-05-02 13:14:40 +0000122DEFINE_string2(match, m, NULL, "[~][^]substring[$] [...] of test name to run.\n" \
123 "Multiple matches may be separated by spaces.\n" \
124 "~ causes a matching test to always be skipped\n" \
125 "^ requires the start of the test to match\n" \
126 "$ requires the end of the test to match\n" \
127 "^ and $ requires an exact match\n" \
128 "If a test does not match any list entry,\n" \
129 "it is skipped unless some list entry starts with ~");
commit-bot@chromium.orgba59d642013-04-11 16:54:09 +0000130DEFINE_string2(tmpDir, t, NULL, "tmp directory for tests to use.");
131DEFINE_string2(resourcePath, i, NULL, "directory for test resources.");
132DEFINE_bool2(extendedTest, x, false, "run extended tests for pathOps.");
caryclark@google.com8d0a5242013-07-16 16:11:16 +0000133DEFINE_bool2(single, z, false, "run tests on a single thread internally.");
commit-bot@chromium.orgba59d642013-04-11 16:54:09 +0000134DEFINE_bool2(verbose, v, false, "enable verbose output.");
commit-bot@chromium.org44c661f2013-04-22 15:23:14 +0000135DEFINE_int32(threads, SkThreadPool::kThreadPerCore,
136 "Run threadsafe tests on a threadpool with this many threads.");
commit-bot@chromium.org197845a2013-04-19 13:24:28 +0000137
scroggo@google.comc76218d2013-06-06 14:59:56 +0000138SkString Test::GetTmpDir() {
139 const char* tmpDir = FLAGS_tmpDir.isEmpty() ? NULL : FLAGS_tmpDir[0];
140 return SkString(tmpDir);
141}
142
143SkString Test::GetResourcePath() {
144 const char* resourcePath = FLAGS_resourcePath.isEmpty() ? NULL : FLAGS_resourcePath[0];
145 return SkString(resourcePath);
146}
147
commit-bot@chromium.org197845a2013-04-19 13:24:28 +0000148// Deletes self when run.
149class SkTestRunnable : public SkRunnable {
150public:
151 // Takes ownership of test.
152 SkTestRunnable(Test* test, int32_t* failCount) : fTest(test), fFailCount(failCount) {}
153
154 virtual void run() {
155 fTest->run();
156 if(!fTest->passed()) {
157 sk_atomic_inc(fFailCount);
158 }
159 SkDELETE(this);
160 }
161
162private:
163 SkAutoTDelete<Test> fTest;
164 int32_t* fFailCount;
165};
commit-bot@chromium.orgba59d642013-04-11 16:54:09 +0000166
caryclark@google.com5987f582012-10-02 18:33:14 +0000167int tool_main(int argc, char** argv);
168int tool_main(int argc, char** argv) {
commit-bot@chromium.orgba59d642013-04-11 16:54:09 +0000169 SkCommandLineFlags::SetUsage("");
170 SkCommandLineFlags::Parse(argc, argv);
171
bsalomon@google.com4e230682013-01-15 20:37:04 +0000172#if SK_ENABLE_INST_COUNT
reed@google.coma2769752012-07-22 22:33:05 +0000173 gPrintInstCount = true;
174#endif
caryclark@google.comd54e1e92013-04-10 15:57:31 +0000175
reed@google.coma2769752012-07-22 22:33:05 +0000176 SkGraphics::Init();
bungeman@google.com5af16f82011-09-02 15:06:44 +0000177
reed@google.com91d449e2011-10-26 15:25:18 +0000178 {
179 SkString header("Skia UnitTests:");
reed@google.com9aff1482013-04-11 18:27:52 +0000180 if (!FLAGS_match.isEmpty()) {
caryclark@google.comb631eec2013-05-02 13:14:40 +0000181 header.appendf(" --match");
182 for (int index = 0; index < FLAGS_match.count(); ++index) {
183 header.appendf(" %s", FLAGS_match[index]);
184 }
reed@google.com91d449e2011-10-26 15:25:18 +0000185 }
scroggo@google.comc76218d2013-06-06 14:59:56 +0000186 SkString tmpDir = Test::GetTmpDir();
187 if (!tmpDir.isEmpty()) {
188 header.appendf(" --tmpDir %s", tmpDir.c_str());
djsollen@google.comcb626502013-03-20 13:48:20 +0000189 }
scroggo@google.comc76218d2013-06-06 14:59:56 +0000190 SkString resourcePath = Test::GetResourcePath();
191 if (!resourcePath.isEmpty()) {
192 header.appendf(" --resourcePath %s", resourcePath.c_str());
reed@google.com789c6f22013-02-25 20:24:24 +0000193 }
reed@google.com91d449e2011-10-26 15:25:18 +0000194#ifdef SK_DEBUG
195 header.append(" SK_DEBUG");
196#else
197 header.append(" SK_RELEASE");
198#endif
199#ifdef SK_SCALAR_IS_FIXED
200 header.append(" SK_SCALAR_IS_FIXED");
201#else
202 header.append(" SK_SCALAR_IS_FLOAT");
203#endif
reed@google.com5696baa2013-08-29 20:20:39 +0000204 header.appendf(" skia_arch_width=%d", (int)sizeof(void*) * 8);
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.com8d0a5242013-07-16 16:11:16 +0000208 DebugfReporter reporter(FLAGS_extendedTest, !FLAGS_single, FLAGS_verbose);
reed@android.comed673312009-02-27 16:24:51 +0000209 Iter iter(&reporter);
reed@android.com80e39a72009-04-02 16:59:40 +0000210
commit-bot@chromium.org0506b9d2013-04-22 16:43:07 +0000211 // Count tests first.
212 int total = 0;
213 int toRun = 0;
214 Test* test;
sglez@google.com586db932013-07-24 17:24:23 +0000215
commit-bot@chromium.org0506b9d2013-04-22 16:43:07 +0000216 while ((test = iter.next()) != NULL) {
217 SkAutoTDelete<Test> owned(test);
sglez@google.com586db932013-07-24 17:24:23 +0000218
commit-bot@chromium.orga6f37e72013-08-30 15:52:46 +0000219 if(!SkCommandLineFlags::ShouldSkip(FLAGS_match, test->getName())) {
commit-bot@chromium.org0506b9d2013-04-22 16:43:07 +0000220 toRun++;
221 }
222 total++;
223 }
224 reporter.setTotal(toRun);
225
226 // Now run them.
227 iter.reset();
commit-bot@chromium.org197845a2013-04-19 13:24:28 +0000228 int32_t failCount = 0;
bungeman@google.com5af16f82011-09-02 15:06:44 +0000229 int skipCount = 0;
commit-bot@chromium.org197845a2013-04-19 13:24:28 +0000230
commit-bot@chromium.orga7538ba2013-10-10 18:49:04 +0000231 SkThreadPool threadpool(FLAGS_threads);
commit-bot@chromium.org197845a2013-04-19 13:24:28 +0000232 SkTArray<Test*> unsafeTests; // Always passes ownership to an SkTestRunnable
commit-bot@chromium.org0506b9d2013-04-22 16:43:07 +0000233 for (int i = 0; i < total; i++) {
commit-bot@chromium.org197845a2013-04-19 13:24:28 +0000234 SkAutoTDelete<Test> test(iter.next());
commit-bot@chromium.orga6f37e72013-08-30 15:52:46 +0000235 if (SkCommandLineFlags::ShouldSkip(FLAGS_match, test->getName())) {
bungeman@google.com5af16f82011-09-02 15:06:44 +0000236 ++skipCount;
commit-bot@chromium.org197845a2013-04-19 13:24:28 +0000237 } else if (!test->isThreadsafe()) {
238 unsafeTests.push_back() = test.detach();
bungeman@google.com5af16f82011-09-02 15:06:44 +0000239 } else {
commit-bot@chromium.orga7538ba2013-10-10 18:49:04 +0000240 threadpool.add(SkNEW_ARGS(SkTestRunnable, (test.detach(), &failCount)));
bungeman@google.com5af16f82011-09-02 15:06:44 +0000241 }
reed@android.comed673312009-02-27 16:24:51 +0000242 }
reed@android.com57b799e2009-04-01 20:26:42 +0000243
commit-bot@chromium.org197845a2013-04-19 13:24:28 +0000244 // Run the tests that aren't threadsafe.
245 for (int i = 0; i < unsafeTests.count(); i++) {
246 SkNEW_ARGS(SkTestRunnable, (unsafeTests[i], &failCount))->run();
247 }
248
commit-bot@chromium.orga7538ba2013-10-10 18:49:04 +0000249 // Block until threaded tests finish.
250 threadpool.wait();
commit-bot@chromium.org197845a2013-04-19 13:24:28 +0000251
djsollen@google.comf4d1b392012-11-29 16:29:58 +0000252 SkDebugf("Finished %d tests, %d failures, %d skipped.\n",
commit-bot@chromium.org0506b9d2013-04-22 16:43:07 +0000253 toRun, failCount, skipCount);
commit-bot@chromium.org197845a2013-04-19 13:24:28 +0000254 const int testCount = reporter.countTests();
commit-bot@chromium.orgba59d642013-04-11 16:54:09 +0000255 if (FLAGS_verbose && testCount > 0) {
caryclark@google.comd54e1e92013-04-10 15:57:31 +0000256 SkDebugf("Ran %d Internal tests.\n", testCount);
257 }
robertphillips@google.combdb1be52012-09-07 18:24:43 +0000258#if SK_SUPPORT_GPU
259
260#if GR_CACHE_STATS
261 GrContext *gr = GpuTest::GetContext();
262
263 gr->printCacheStats();
264#endif
265
266#endif
267
reed@google.coma2769752012-07-22 22:33:05 +0000268 SkGraphics::Term();
bsalomon@google.com67b915d2013-02-04 16:13:32 +0000269 GpuTest::DestroyContexts();
reed@google.coma2769752012-07-22 22:33:05 +0000270
bungeman@google.com5af16f82011-09-02 15:06:44 +0000271 return (failCount == 0) ? 0 : 1;
reed@android.comed673312009-02-27 16:24:51 +0000272}
caryclark@google.com5987f582012-10-02 18:33:14 +0000273
borenet@google.com7158e6a2012-11-01 17:43:44 +0000274#if !defined(SK_BUILD_FOR_IOS) && !defined(SK_BUILD_FOR_NACL)
caryclark@google.com5987f582012-10-02 18:33:14 +0000275int main(int argc, char * const argv[]) {
276 return tool_main(argc, (char**) argv);
277}
278#endif