skia_test.cpp revision 261c66668269588a26757a0bfe28a3a3eac07665
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 "SkCommandLineFlags.h" 9#include "SkGraphics.h" 10#include "SkOSFile.h" 11#include "SkTArray.h" 12#include "SkTemplates.h" 13#include "SkThreadPool.h" 14#include "SkTime.h" 15#include "Test.h" 16#include "OverwriteLine.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(single, z, false, "run tests on a single thread internally."); 36DEFINE_bool2(verbose, v, false, "enable verbose output."); 37DEFINE_int32(threads, SkThreadPool::kThreadPerCore, 38 "Run threadsafe tests on a threadpool with this many threads."); 39 40// need to explicitly declare this, or we get some weird infinite loop llist 41template TestRegistry* TestRegistry::gHead; 42 43class Iter { 44public: 45 Iter() { this->reset(); } 46 void reset() { fReg = TestRegistry::Head(); } 47 48 Test* next(Reporter* r) { 49 if (fReg) { 50 TestRegistry::Factory fact = fReg->factory(); 51 fReg = fReg->next(); 52 Test* test = fact(NULL); 53 test->setReporter(r); 54 return test; 55 } 56 return NULL; 57 } 58 59private: 60 const TestRegistry* fReg; 61}; 62 63class DebugfReporter : public Reporter { 64public: 65 explicit DebugfReporter(int total) : fDone(0), fTotal(total) {} 66 67 virtual bool allowExtendedTest() const SK_OVERRIDE { return FLAGS_extendedTest; } 68 virtual bool allowThreaded() const SK_OVERRIDE { return !FLAGS_single; } 69 virtual bool verbose() const SK_OVERRIDE { return FLAGS_verbose; } 70 71protected: 72 virtual void onReportFailed(const SkString& desc) SK_OVERRIDE { 73 SkDebugf("\nFAILED: %s", desc.c_str()); 74 } 75 76 virtual void onEnd(Test* test) SK_OVERRIDE { 77 const int done = 1 + sk_atomic_inc(&fDone); 78 79 if (!test->passed()) { 80 SkDebugf("\n---- %s FAILED", test->getName()); 81 } 82 83 SkString prefix(kSkOverwriteLine); 84 SkString time; 85 if (FLAGS_verbose) { 86 prefix.printf("\n"); 87 time.printf("%5dms ", test->elapsedMs()); 88 } 89 SkDebugf("%s[%3d/%3d] %s%s", prefix.c_str(), done, fTotal, time.c_str(), test->getName()); 90 } 91 92private: 93 int32_t fDone; // atomic 94 const int fTotal; 95}; 96 97SkString Test::GetTmpDir() { 98 const char* tmpDir = FLAGS_tmpDir.isEmpty() ? NULL : FLAGS_tmpDir[0]; 99 return SkString(tmpDir); 100} 101 102SkString Test::GetResourcePath() { 103 const char* resourcePath = FLAGS_resourcePath.isEmpty() ? NULL : FLAGS_resourcePath[0]; 104 return SkString(resourcePath); 105} 106 107// Deletes self when run. 108class SkTestRunnable : public SkRunnable { 109public: 110 // Takes ownership of test. 111 SkTestRunnable(Test* test, int32_t* failCount) : fTest(test), fFailCount(failCount) {} 112 113 virtual void run() { 114 fTest->run(); 115 if(!fTest->passed()) { 116 sk_atomic_inc(fFailCount); 117 } 118 SkDELETE(this); 119 } 120 121private: 122 SkAutoTDelete<Test> fTest; 123 int32_t* fFailCount; 124}; 125 126int tool_main(int argc, char** argv); 127int tool_main(int argc, char** argv) { 128 SkCommandLineFlags::SetUsage(""); 129 SkCommandLineFlags::Parse(argc, argv); 130 131#if SK_ENABLE_INST_COUNT 132 gPrintInstCount = true; 133#endif 134 135 SkGraphics::Init(); 136 137 { 138 SkString header("Skia UnitTests:"); 139 if (!FLAGS_match.isEmpty()) { 140 header.appendf(" --match"); 141 for (int index = 0; index < FLAGS_match.count(); ++index) { 142 header.appendf(" %s", FLAGS_match[index]); 143 } 144 } 145 SkString tmpDir = Test::GetTmpDir(); 146 if (!tmpDir.isEmpty()) { 147 header.appendf(" --tmpDir %s", tmpDir.c_str()); 148 } 149 SkString resourcePath = Test::GetResourcePath(); 150 if (!resourcePath.isEmpty()) { 151 header.appendf(" --resourcePath %s", resourcePath.c_str()); 152 } 153#ifdef SK_DEBUG 154 header.append(" SK_DEBUG"); 155#else 156 header.append(" SK_RELEASE"); 157#endif 158 header.appendf(" skia_arch_width=%d", (int)sizeof(void*) * 8); 159 SkDebugf(header.c_str()); 160 } 161 162 163 // Count tests first. 164 int total = 0; 165 int toRun = 0; 166 Test* test; 167 168 Iter iter; 169 while ((test = iter.next(NULL/*reporter not needed*/)) != NULL) { 170 SkAutoTDelete<Test> owned(test); 171 172 if(!SkCommandLineFlags::ShouldSkip(FLAGS_match, test->getName())) { 173 toRun++; 174 } 175 total++; 176 } 177 178 // Now run them. 179 iter.reset(); 180 int32_t failCount = 0; 181 int skipCount = 0; 182 183 SkThreadPool threadpool(FLAGS_threads); 184 SkTArray<Test*> unsafeTests; // Always passes ownership to an SkTestRunnable 185 186 DebugfReporter reporter(toRun); 187 for (int i = 0; i < total; i++) { 188 SkAutoTDelete<Test> test(iter.next(&reporter)); 189 if (SkCommandLineFlags::ShouldSkip(FLAGS_match, test->getName())) { 190 ++skipCount; 191 } else if (!test->isThreadsafe()) { 192 unsafeTests.push_back() = test.detach(); 193 } else { 194 threadpool.add(SkNEW_ARGS(SkTestRunnable, (test.detach(), &failCount))); 195 } 196 } 197 198 // Run the tests that aren't threadsafe. 199 for (int i = 0; i < unsafeTests.count(); i++) { 200 SkNEW_ARGS(SkTestRunnable, (unsafeTests[i], &failCount))->run(); 201 } 202 203 // Block until threaded tests finish. 204 threadpool.wait(); 205 206 if (FLAGS_verbose) { 207 SkDebugf("\nFinished %d tests, %d failures, %d skipped. (%d internal tests)", 208 toRun, failCount, skipCount, reporter.countTests()); 209 } 210 SkGraphics::Term(); 211 GpuTest::DestroyContexts(); 212 213 SkDebugf("\n"); 214 return (failCount == 0) ? 0 : 1; 215} 216 217#if !defined(SK_BUILD_FOR_IOS) && !defined(SK_BUILD_FOR_NACL) 218int main(int argc, char * const argv[]) { 219 return tool_main(argc, (char**) argv); 220} 221#endif 222