blob: 48d87719d562c31c4cb7a3116f49d96fb41e4992 [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
tfarina@chromium.org8f6884a2014-01-24 20:56:26 +00008#include "OverwriteLine.h"
scroggo@google.com5a6324e2013-04-11 20:11:40 +00009#include "SkCommandLineFlags.h"
reed@android.com5e5adfd2009-03-07 03:39:23 +000010#include "SkGraphics.h"
commit-bot@chromium.org0506b9d2013-04-22 16:43:07 +000011#include "SkOSFile.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
caryclark@google.comb631eec2013-05-02 13:14:40 +000024DEFINE_string2(match, m, NULL, "[~][^]substring[$] [...] of test name to run.\n" \
25 "Multiple matches may be separated by spaces.\n" \
26 "~ causes a matching test to always be skipped\n" \
27 "^ requires the start of the test to match\n" \
28 "$ requires the end of the test to match\n" \
29 "^ and $ requires an exact match\n" \
30 "If a test does not match any list entry,\n" \
31 "it is skipped unless some list entry starts with ~");
commit-bot@chromium.orgba59d642013-04-11 16:54:09 +000032DEFINE_string2(tmpDir, t, NULL, "tmp directory for tests to use.");
commit-bot@chromium.orgf9a27592013-10-29 19:50:39 +000033DEFINE_string2(resourcePath, i, "resources", "directory for test resources.");
commit-bot@chromium.orgba59d642013-04-11 16:54:09 +000034DEFINE_bool2(extendedTest, x, false, "run extended tests for pathOps.");
commit-bot@chromium.org6dda8272014-01-23 17:21:19 +000035DEFINE_bool2(leaks, l, false, "show leaked ref cnt'd objects.");
caryclark@google.com8d0a5242013-07-16 16:11:16 +000036DEFINE_bool2(single, z, false, "run tests on a single thread internally.");
commit-bot@chromium.org11ea96c2014-01-28 21:15:42 +000037DEFINE_bool2(verbose, v, false, "enable verbose output from the test driver.");
38DEFINE_bool2(veryVerbose, V, false, "tell individual tests to be verbose.");
commit-bot@chromium.org5a47b092014-01-30 15:30:50 +000039DEFINE_bool(cpu, true, "whether or not to run CPU tests.");
40DEFINE_bool(gpu, true, "whether or not to run GPU tests.");
commit-bot@chromium.org44c661f2013-04-22 15:23:14 +000041DEFINE_int32(threads, SkThreadPool::kThreadPerCore,
42 "Run threadsafe tests on a threadpool with this many threads.");
commit-bot@chromium.org197845a2013-04-19 13:24:28 +000043
commit-bot@chromium.org261c6662014-01-02 16:19:53 +000044// need to explicitly declare this, or we get some weird infinite loop llist
45template TestRegistry* TestRegistry::gHead;
46
47class Iter {
48public:
49 Iter() { this->reset(); }
50 void reset() { fReg = TestRegistry::Head(); }
51
52 Test* next(Reporter* r) {
53 if (fReg) {
54 TestRegistry::Factory fact = fReg->factory();
55 fReg = fReg->next();
56 Test* test = fact(NULL);
57 test->setReporter(r);
58 return test;
59 }
60 return NULL;
61 }
62
63private:
64 const TestRegistry* fReg;
65};
66
67class DebugfReporter : public Reporter {
68public:
69 explicit DebugfReporter(int total) : fDone(0), fTotal(total) {}
70
71 virtual bool allowExtendedTest() const SK_OVERRIDE { return FLAGS_extendedTest; }
72 virtual bool allowThreaded() const SK_OVERRIDE { return !FLAGS_single; }
commit-bot@chromium.org11ea96c2014-01-28 21:15:42 +000073 virtual bool verbose() const SK_OVERRIDE { return FLAGS_veryVerbose; }
commit-bot@chromium.org261c6662014-01-02 16:19:53 +000074
75protected:
76 virtual void onReportFailed(const SkString& desc) SK_OVERRIDE {
77 SkDebugf("\nFAILED: %s", desc.c_str());
78 }
79
80 virtual void onEnd(Test* test) SK_OVERRIDE {
81 const int done = 1 + sk_atomic_inc(&fDone);
82
83 if (!test->passed()) {
84 SkDebugf("\n---- %s FAILED", test->getName());
85 }
86
87 SkString prefix(kSkOverwriteLine);
88 SkString time;
89 if (FLAGS_verbose) {
90 prefix.printf("\n");
91 time.printf("%5dms ", test->elapsedMs());
92 }
93 SkDebugf("%s[%3d/%3d] %s%s", prefix.c_str(), done, fTotal, time.c_str(), test->getName());
94 }
95
96private:
97 int32_t fDone; // atomic
98 const int fTotal;
99};
100
scroggo@google.comc76218d2013-06-06 14:59:56 +0000101SkString Test::GetTmpDir() {
102 const char* tmpDir = FLAGS_tmpDir.isEmpty() ? NULL : FLAGS_tmpDir[0];
103 return SkString(tmpDir);
104}
105
106SkString Test::GetResourcePath() {
107 const char* resourcePath = FLAGS_resourcePath.isEmpty() ? NULL : FLAGS_resourcePath[0];
108 return SkString(resourcePath);
109}
110
commit-bot@chromium.org197845a2013-04-19 13:24:28 +0000111// Deletes self when run.
112class SkTestRunnable : public SkRunnable {
113public:
114 // Takes ownership of test.
115 SkTestRunnable(Test* test, int32_t* failCount) : fTest(test), fFailCount(failCount) {}
116
117 virtual void run() {
118 fTest->run();
119 if(!fTest->passed()) {
120 sk_atomic_inc(fFailCount);
121 }
122 SkDELETE(this);
123 }
124
125private:
126 SkAutoTDelete<Test> fTest;
127 int32_t* fFailCount;
128};
commit-bot@chromium.orgba59d642013-04-11 16:54:09 +0000129
commit-bot@chromium.org5a47b092014-01-30 15:30:50 +0000130static bool should_run(const char* testName, bool isGPUTest) {
131 if (SkCommandLineFlags::ShouldSkip(FLAGS_match, testName)) {
132 return false;
133 }
134 if (!FLAGS_cpu && !isGPUTest) {
135 return false;
136 }
137 if (!FLAGS_gpu && isGPUTest) {
138 return false;
139 }
140 return true;
141}
142
caryclark@google.com5987f582012-10-02 18:33:14 +0000143int tool_main(int argc, char** argv);
144int tool_main(int argc, char** argv) {
commit-bot@chromium.orgba59d642013-04-11 16:54:09 +0000145 SkCommandLineFlags::SetUsage("");
146 SkCommandLineFlags::Parse(argc, argv);
147
bsalomon@google.com4e230682013-01-15 20:37:04 +0000148#if SK_ENABLE_INST_COUNT
commit-bot@chromium.org6dda8272014-01-23 17:21:19 +0000149 if (FLAGS_leaks) {
150 gPrintInstCount = true;
151 }
reed@google.coma2769752012-07-22 22:33:05 +0000152#endif
caryclark@google.comd54e1e92013-04-10 15:57:31 +0000153
reed@google.coma2769752012-07-22 22:33:05 +0000154 SkGraphics::Init();
bungeman@google.com5af16f82011-09-02 15:06:44 +0000155
reed@google.com91d449e2011-10-26 15:25:18 +0000156 {
157 SkString header("Skia UnitTests:");
reed@google.com9aff1482013-04-11 18:27:52 +0000158 if (!FLAGS_match.isEmpty()) {
caryclark@google.comb631eec2013-05-02 13:14:40 +0000159 header.appendf(" --match");
160 for (int index = 0; index < FLAGS_match.count(); ++index) {
161 header.appendf(" %s", FLAGS_match[index]);
162 }
reed@google.com91d449e2011-10-26 15:25:18 +0000163 }
scroggo@google.comc76218d2013-06-06 14:59:56 +0000164 SkString tmpDir = Test::GetTmpDir();
165 if (!tmpDir.isEmpty()) {
166 header.appendf(" --tmpDir %s", tmpDir.c_str());
djsollen@google.comcb626502013-03-20 13:48:20 +0000167 }
scroggo@google.comc76218d2013-06-06 14:59:56 +0000168 SkString resourcePath = Test::GetResourcePath();
169 if (!resourcePath.isEmpty()) {
170 header.appendf(" --resourcePath %s", resourcePath.c_str());
reed@google.com789c6f22013-02-25 20:24:24 +0000171 }
reed@google.com91d449e2011-10-26 15:25:18 +0000172#ifdef SK_DEBUG
173 header.append(" SK_DEBUG");
174#else
175 header.append(" SK_RELEASE");
176#endif
reed@google.com5696baa2013-08-29 20:20:39 +0000177 header.appendf(" skia_arch_width=%d", (int)sizeof(void*) * 8);
commit-bot@chromium.org261c6662014-01-02 16:19:53 +0000178 SkDebugf(header.c_str());
reed@google.com91d449e2011-10-26 15:25:18 +0000179 }
180
reed@android.com80e39a72009-04-02 16:59:40 +0000181
commit-bot@chromium.org0506b9d2013-04-22 16:43:07 +0000182 // Count tests first.
183 int total = 0;
184 int toRun = 0;
185 Test* test;
sglez@google.com586db932013-07-24 17:24:23 +0000186
commit-bot@chromium.org261c6662014-01-02 16:19:53 +0000187 Iter iter;
188 while ((test = iter.next(NULL/*reporter not needed*/)) != NULL) {
commit-bot@chromium.org0506b9d2013-04-22 16:43:07 +0000189 SkAutoTDelete<Test> owned(test);
commit-bot@chromium.org5a47b092014-01-30 15:30:50 +0000190 if (should_run(test->getName(), test->isGPUTest())) {
commit-bot@chromium.org0506b9d2013-04-22 16:43:07 +0000191 toRun++;
192 }
193 total++;
194 }
commit-bot@chromium.org0506b9d2013-04-22 16:43:07 +0000195
196 // Now run them.
197 iter.reset();
commit-bot@chromium.org197845a2013-04-19 13:24:28 +0000198 int32_t failCount = 0;
bungeman@google.com5af16f82011-09-02 15:06:44 +0000199 int skipCount = 0;
commit-bot@chromium.org197845a2013-04-19 13:24:28 +0000200
commit-bot@chromium.orga7538ba2013-10-10 18:49:04 +0000201 SkThreadPool threadpool(FLAGS_threads);
commit-bot@chromium.org197845a2013-04-19 13:24:28 +0000202 SkTArray<Test*> unsafeTests; // Always passes ownership to an SkTestRunnable
commit-bot@chromium.org261c6662014-01-02 16:19:53 +0000203
204 DebugfReporter reporter(toRun);
commit-bot@chromium.org0506b9d2013-04-22 16:43:07 +0000205 for (int i = 0; i < total; i++) {
commit-bot@chromium.org261c6662014-01-02 16:19:53 +0000206 SkAutoTDelete<Test> test(iter.next(&reporter));
commit-bot@chromium.org5a47b092014-01-30 15:30:50 +0000207 if (!should_run(test->getName(), test->isGPUTest())) {
bungeman@google.com5af16f82011-09-02 15:06:44 +0000208 ++skipCount;
commit-bot@chromium.org5a47b092014-01-30 15:30:50 +0000209 } else if (test->isGPUTest()) {
commit-bot@chromium.org197845a2013-04-19 13:24:28 +0000210 unsafeTests.push_back() = test.detach();
bungeman@google.com5af16f82011-09-02 15:06:44 +0000211 } else {
commit-bot@chromium.orga7538ba2013-10-10 18:49:04 +0000212 threadpool.add(SkNEW_ARGS(SkTestRunnable, (test.detach(), &failCount)));
bungeman@google.com5af16f82011-09-02 15:06:44 +0000213 }
reed@android.comed673312009-02-27 16:24:51 +0000214 }
reed@android.com57b799e2009-04-01 20:26:42 +0000215
commit-bot@chromium.org197845a2013-04-19 13:24:28 +0000216 // Run the tests that aren't threadsafe.
217 for (int i = 0; i < unsafeTests.count(); i++) {
218 SkNEW_ARGS(SkTestRunnable, (unsafeTests[i], &failCount))->run();
219 }
220
commit-bot@chromium.orga7538ba2013-10-10 18:49:04 +0000221 // Block until threaded tests finish.
222 threadpool.wait();
commit-bot@chromium.org197845a2013-04-19 13:24:28 +0000223
commit-bot@chromium.org261c6662014-01-02 16:19:53 +0000224 if (FLAGS_verbose) {
225 SkDebugf("\nFinished %d tests, %d failures, %d skipped. (%d internal tests)",
226 toRun, failCount, skipCount, reporter.countTests());
caryclark@google.comd54e1e92013-04-10 15:57:31 +0000227 }
reed@google.coma2769752012-07-22 22:33:05 +0000228 SkGraphics::Term();
bsalomon@google.com67b915d2013-02-04 16:13:32 +0000229 GpuTest::DestroyContexts();
reed@google.coma2769752012-07-22 22:33:05 +0000230
commit-bot@chromium.org261c6662014-01-02 16:19:53 +0000231 SkDebugf("\n");
bungeman@google.com5af16f82011-09-02 15:06:44 +0000232 return (failCount == 0) ? 0 : 1;
reed@android.comed673312009-02-27 16:24:51 +0000233}
caryclark@google.com5987f582012-10-02 18:33:14 +0000234
borenet@google.com7158e6a2012-11-01 17:43:44 +0000235#if !defined(SK_BUILD_FOR_IOS) && !defined(SK_BUILD_FOR_NACL)
caryclark@google.com5987f582012-10-02 18:33:14 +0000236int main(int argc, char * const argv[]) {
237 return tool_main(argc, (char**) argv);
238}
239#endif