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 "SkRunnable.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 22 using namespace skiatest; 23 24 // need to explicitly declare this, or we get some weird infinite loop llist 25 template TestRegistry* TestRegistry::gHead; 26 27 class Iter { 28 public: 29 Iter(Reporter* r) : fReporter(r) { 30 r->ref(); 31 this->reset(); 32 } 33 34 void reset() { 35 fReg = TestRegistry::Head(); 36 } 37 38 ~Iter() { 39 fReporter->unref(); 40 } 41 42 Test* next() { 43 if (fReg) { 44 TestRegistry::Factory fact = fReg->factory(); 45 fReg = fReg->next(); 46 Test* test = fact(NULL); 47 test->setReporter(fReporter); 48 return test; 49 } 50 return NULL; 51 } 52 53 private: 54 Reporter* fReporter; 55 const TestRegistry* fReg; 56 }; 57 58 class DebugfReporter : public Reporter { 59 public: 60 DebugfReporter(bool allowExtendedTest, bool allowThreaded, bool verbose) 61 : fNextIndex(0) 62 , fPending(0) 63 , fTotal(0) 64 , fAllowExtendedTest(allowExtendedTest) 65 , fAllowThreaded(allowThreaded) 66 , fVerbose(verbose) { 67 } 68 69 void setTotal(int total) { 70 fTotal = total; 71 } 72 73 virtual bool allowExtendedTest() const SK_OVERRIDE { 74 return fAllowExtendedTest; 75 } 76 77 virtual bool allowThreaded() const SK_OVERRIDE { 78 return fAllowThreaded; 79 } 80 81 virtual bool verbose() const SK_OVERRIDE { 82 return fVerbose; 83 } 84 85 protected: 86 virtual void onStart(Test* test) { 87 const int index = sk_atomic_inc(&fNextIndex); 88 sk_atomic_inc(&fPending); 89 SkDebugf("[%3d/%3d] (%d) %s\n", index+1, fTotal, fPending, test->getName()); 90 } 91 virtual void onReportFailed(const SkString& desc) { 92 SkDebugf("\tFAILED: %s\n", desc.c_str()); 93 } 94 95 virtual void onEnd(Test* test) { 96 if (!test->passed()) { 97 SkDebugf("---- %s FAILED\n", test->getName()); 98 } 99 100 sk_atomic_dec(&fPending); 101 if (fNextIndex == fTotal) { 102 // Just waiting on straggler tests. Shame them by printing their name and runtime. 103 SkDebugf(" (%d) %5.1fs %s\n", 104 fPending, test->elapsedMs() / 1e3, test->getName()); 105 } 106 } 107 108 private: 109 int32_t fNextIndex; 110 int32_t fPending; 111 int fTotal; 112 bool fAllowExtendedTest; 113 bool fAllowThreaded; 114 bool fVerbose; 115 }; 116 117 DEFINE_string2(match, m, NULL, "[~][^]substring[$] [...] of test name to run.\n" \ 118 "Multiple matches may be separated by spaces.\n" \ 119 "~ causes a matching test to always be skipped\n" \ 120 "^ requires the start of the test to match\n" \ 121 "$ requires the end of the test to match\n" \ 122 "^ and $ requires an exact match\n" \ 123 "If a test does not match any list entry,\n" \ 124 "it is skipped unless some list entry starts with ~"); 125 DEFINE_string2(tmpDir, t, NULL, "tmp directory for tests to use."); 126 DEFINE_string2(resourcePath, i, NULL, "directory for test resources."); 127 DEFINE_bool2(extendedTest, x, false, "run extended tests for pathOps."); 128 DEFINE_bool2(single, z, false, "run tests on a single thread internally."); 129 DEFINE_bool2(verbose, v, false, "enable verbose output."); 130 DEFINE_int32(threads, SkThreadPool::kThreadPerCore, 131 "Run threadsafe tests on a threadpool with this many threads."); 132 133 SkString Test::GetTmpDir() { 134 const char* tmpDir = FLAGS_tmpDir.isEmpty() ? NULL : FLAGS_tmpDir[0]; 135 return SkString(tmpDir); 136 } 137 138 SkString Test::GetResourcePath() { 139 const char* resourcePath = FLAGS_resourcePath.isEmpty() ? NULL : FLAGS_resourcePath[0]; 140 return SkString(resourcePath); 141 } 142 143 // Deletes self when run. 144 class SkTestRunnable : public SkRunnable { 145 public: 146 // Takes ownership of test. 147 SkTestRunnable(Test* test, int32_t* failCount) : fTest(test), fFailCount(failCount) {} 148 149 virtual void run() { 150 fTest->run(); 151 if(!fTest->passed()) { 152 sk_atomic_inc(fFailCount); 153 } 154 SkDELETE(this); 155 } 156 157 private: 158 SkAutoTDelete<Test> fTest; 159 int32_t* fFailCount; 160 }; 161 162 int tool_main(int argc, char** argv); 163 int tool_main(int argc, char** argv) { 164 SkCommandLineFlags::SetUsage(""); 165 SkCommandLineFlags::Parse(argc, argv); 166 167 #if SK_ENABLE_INST_COUNT 168 gPrintInstCount = true; 169 #endif 170 171 SkGraphics::Init(); 172 173 { 174 SkString header("Skia UnitTests:"); 175 if (!FLAGS_match.isEmpty()) { 176 header.appendf(" --match"); 177 for (int index = 0; index < FLAGS_match.count(); ++index) { 178 header.appendf(" %s", FLAGS_match[index]); 179 } 180 } 181 SkString tmpDir = Test::GetTmpDir(); 182 if (!tmpDir.isEmpty()) { 183 header.appendf(" --tmpDir %s", tmpDir.c_str()); 184 } 185 SkString resourcePath = Test::GetResourcePath(); 186 if (!resourcePath.isEmpty()) { 187 header.appendf(" --resourcePath %s", resourcePath.c_str()); 188 } 189 #ifdef SK_DEBUG 190 header.append(" SK_DEBUG"); 191 #else 192 header.append(" SK_RELEASE"); 193 #endif 194 #ifdef SK_SCALAR_IS_FIXED 195 header.append(" SK_SCALAR_IS_FIXED"); 196 #else 197 header.append(" SK_SCALAR_IS_FLOAT"); 198 #endif 199 SkDebugf("%s\n", header.c_str()); 200 } 201 202 DebugfReporter reporter(FLAGS_extendedTest, !FLAGS_single, FLAGS_verbose); 203 Iter iter(&reporter); 204 205 // Count tests first. 206 int total = 0; 207 int toRun = 0; 208 Test* test; 209 210 SkTDArray<const char*> matchStrs; 211 for(int i = 0; i < FLAGS_match.count(); ++i) { 212 matchStrs.push(FLAGS_match[i]); 213 } 214 215 while ((test = iter.next()) != NULL) { 216 SkAutoTDelete<Test> owned(test); 217 218 if(!SkCommandLineFlags::ShouldSkip(matchStrs, test->getName())) { 219 toRun++; 220 } 221 total++; 222 } 223 reporter.setTotal(toRun); 224 225 // Now run them. 226 iter.reset(); 227 int32_t failCount = 0; 228 int skipCount = 0; 229 230 SkAutoTDelete<SkThreadPool> threadpool(SkNEW_ARGS(SkThreadPool, (FLAGS_threads))); 231 SkTArray<Test*> unsafeTests; // Always passes ownership to an SkTestRunnable 232 for (int i = 0; i < total; i++) { 233 SkAutoTDelete<Test> test(iter.next()); 234 if (SkCommandLineFlags::ShouldSkip(matchStrs, test->getName())) { 235 ++skipCount; 236 } else if (!test->isThreadsafe()) { 237 unsafeTests.push_back() = test.detach(); 238 } else { 239 threadpool->add(SkNEW_ARGS(SkTestRunnable, (test.detach(), &failCount))); 240 } 241 } 242 243 // Run the tests that aren't threadsafe. 244 for (int i = 0; i < unsafeTests.count(); i++) { 245 SkNEW_ARGS(SkTestRunnable, (unsafeTests[i], &failCount))->run(); 246 } 247 248 // Blocks until threaded tests finish. 249 threadpool.free(); 250 251 SkDebugf("Finished %d tests, %d failures, %d skipped.\n", 252 toRun, failCount, skipCount); 253 const int testCount = reporter.countTests(); 254 if (FLAGS_verbose && testCount > 0) { 255 SkDebugf("Ran %d Internal tests.\n", testCount); 256 } 257 #if SK_SUPPORT_GPU 258 259 #if GR_CACHE_STATS 260 GrContext *gr = GpuTest::GetContext(); 261 262 gr->printCacheStats(); 263 #endif 264 265 #endif 266 267 SkGraphics::Term(); 268 GpuTest::DestroyContexts(); 269 270 return (failCount == 0) ? 0 : 1; 271 } 272 273 #if !defined(SK_BUILD_FOR_IOS) && !defined(SK_BUILD_FOR_NACL) 274 int main(int argc, char * const argv[]) { 275 return tool_main(argc, (char**) argv); 276 } 277 #endif 278