skia_test.cpp revision 5a47b09fe8fff1439510f1839722e24ed6a91eae
1/* 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 */ 7 8#include "OverwriteLine.h" 9#include "SkCommandLineFlags.h" 10#include "SkGraphics.h" 11#include "SkOSFile.h" 12#include "SkTArray.h" 13#include "SkTemplates.h" 14#include "SkThreadPool.h" 15#include "SkTime.h" 16#include "Test.h" 17 18#if SK_SUPPORT_GPU 19#include "GrContext.h" 20#endif 21 22using namespace skiatest; 23 24DEFINE_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 ~"); 32DEFINE_string2(tmpDir, t, NULL, "tmp directory for tests to use."); 33DEFINE_string2(resourcePath, i, "resources", "directory for test resources."); 34DEFINE_bool2(extendedTest, x, false, "run extended tests for pathOps."); 35DEFINE_bool2(leaks, l, false, "show leaked ref cnt'd objects."); 36DEFINE_bool2(single, z, false, "run tests on a single thread internally."); 37DEFINE_bool2(verbose, v, false, "enable verbose output from the test driver."); 38DEFINE_bool2(veryVerbose, V, false, "tell individual tests to be verbose."); 39DEFINE_bool(cpu, true, "whether or not to run CPU tests."); 40DEFINE_bool(gpu, true, "whether or not to run GPU tests."); 41DEFINE_int32(threads, SkThreadPool::kThreadPerCore, 42 "Run threadsafe tests on a threadpool with this many threads."); 43 44// 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; } 73 virtual bool verbose() const SK_OVERRIDE { return FLAGS_veryVerbose; } 74 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 101SkString 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 111// 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}; 129 130static 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 143int tool_main(int argc, char** argv); 144int tool_main(int argc, char** argv) { 145 SkCommandLineFlags::SetUsage(""); 146 SkCommandLineFlags::Parse(argc, argv); 147 148#if SK_ENABLE_INST_COUNT 149 if (FLAGS_leaks) { 150 gPrintInstCount = true; 151 } 152#endif 153 154 SkGraphics::Init(); 155 156 { 157 SkString header("Skia UnitTests:"); 158 if (!FLAGS_match.isEmpty()) { 159 header.appendf(" --match"); 160 for (int index = 0; index < FLAGS_match.count(); ++index) { 161 header.appendf(" %s", FLAGS_match[index]); 162 } 163 } 164 SkString tmpDir = Test::GetTmpDir(); 165 if (!tmpDir.isEmpty()) { 166 header.appendf(" --tmpDir %s", tmpDir.c_str()); 167 } 168 SkString resourcePath = Test::GetResourcePath(); 169 if (!resourcePath.isEmpty()) { 170 header.appendf(" --resourcePath %s", resourcePath.c_str()); 171 } 172#ifdef SK_DEBUG 173 header.append(" SK_DEBUG"); 174#else 175 header.append(" SK_RELEASE"); 176#endif 177 header.appendf(" skia_arch_width=%d", (int)sizeof(void*) * 8); 178 SkDebugf(header.c_str()); 179 } 180 181 182 // Count tests first. 183 int total = 0; 184 int toRun = 0; 185 Test* test; 186 187 Iter iter; 188 while ((test = iter.next(NULL/*reporter not needed*/)) != NULL) { 189 SkAutoTDelete<Test> owned(test); 190 if (should_run(test->getName(), test->isGPUTest())) { 191 toRun++; 192 } 193 total++; 194 } 195 196 // Now run them. 197 iter.reset(); 198 int32_t failCount = 0; 199 int skipCount = 0; 200 201 SkThreadPool threadpool(FLAGS_threads); 202 SkTArray<Test*> unsafeTests; // Always passes ownership to an SkTestRunnable 203 204 DebugfReporter reporter(toRun); 205 for (int i = 0; i < total; i++) { 206 SkAutoTDelete<Test> test(iter.next(&reporter)); 207 if (!should_run(test->getName(), test->isGPUTest())) { 208 ++skipCount; 209 } else if (test->isGPUTest()) { 210 unsafeTests.push_back() = test.detach(); 211 } else { 212 threadpool.add(SkNEW_ARGS(SkTestRunnable, (test.detach(), &failCount))); 213 } 214 } 215 216 // 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 221 // Block until threaded tests finish. 222 threadpool.wait(); 223 224 if (FLAGS_verbose) { 225 SkDebugf("\nFinished %d tests, %d failures, %d skipped. (%d internal tests)", 226 toRun, failCount, skipCount, reporter.countTests()); 227 } 228 SkGraphics::Term(); 229 GpuTest::DestroyContexts(); 230 231 SkDebugf("\n"); 232 return (failCount == 0) ? 0 : 1; 233} 234 235#if !defined(SK_BUILD_FOR_IOS) && !defined(SK_BUILD_FOR_NACL) 236int main(int argc, char * const argv[]) { 237 return tool_main(argc, (char**) argv); 238} 239#endif 240