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 17#if SK_SUPPORT_GPU 18#include "GrContext.h" 19#endif 20 21using namespace skiatest; 22 23// need to explicitly declare this, or we get some weird infinite loop llist 24template TestRegistry* TestRegistry::gHead; 25 26class Iter { 27public: 28 Iter(Reporter* r) : fReporter(r) { 29 r->ref(); 30 this->reset(); 31 } 32 33 void reset() { 34 fReg = TestRegistry::Head(); 35 } 36 37 ~Iter() { 38 fReporter->unref(); 39 } 40 41 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 } 51 52private: 53 Reporter* fReporter; 54 const TestRegistry* fReg; 55}; 56 57class DebugfReporter : public Reporter { 58public: 59 DebugfReporter(bool allowExtendedTest, bool allowThreaded, bool verbose) 60 : fNextIndex(0) 61 , fPending(0) 62 , fTotal(0) 63 , fAllowExtendedTest(allowExtendedTest) 64 , fAllowThreaded(allowThreaded) 65 , fVerbose(verbose) { 66 } 67 68 void setTotal(int total) { 69 fTotal = total; 70 } 71 72 virtual bool allowExtendedTest() const SK_OVERRIDE { 73 return fAllowExtendedTest; 74 } 75 76 virtual bool allowThreaded() const SK_OVERRIDE { 77 return fAllowThreaded; 78 } 79 80 virtual bool verbose() const SK_OVERRIDE { 81 return fVerbose; 82 } 83 84protected: 85 virtual void onStart(Test* test) { 86 SkAutoMutexAcquire lock(fStartEndMutex); 87 fNextIndex++; 88 fPending++; 89 SkDebugf("[%3d/%3d] (%d) %s\n", fNextIndex, fTotal, fPending, test->getName()); 90 } 91 92 virtual void onReportFailed(const SkString& desc) { 93 SkDebugf("\tFAILED: %s\n", desc.c_str()); 94 } 95 96 virtual void onEnd(Test* test) { 97 SkAutoMutexAcquire lock(fStartEndMutex); 98 if (!test->passed()) { 99 SkDebugf("---- %s FAILED\n", test->getName()); 100 } 101 102 fPending--; 103 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()); 107 } 108 } 109 110private: 111 SkMutex fStartEndMutex; // Guards fNextIndex and fPending. 112 int32_t fNextIndex; 113 int32_t fPending; 114 115 // Once the tests get going, these are logically const. 116 int fTotal; 117 bool fAllowExtendedTest; 118 bool fAllowThreaded; 119 bool fVerbose; 120}; 121 122DEFINE_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 ~"); 130DEFINE_string2(tmpDir, t, NULL, "tmp directory for tests to use."); 131DEFINE_string2(resourcePath, i, "resources", "directory for test resources."); 132DEFINE_bool2(extendedTest, x, false, "run extended tests for pathOps."); 133DEFINE_bool2(single, z, false, "run tests on a single thread internally."); 134DEFINE_bool2(verbose, v, false, "enable verbose output."); 135DEFINE_int32(threads, SkThreadPool::kThreadPerCore, 136 "Run threadsafe tests on a threadpool with this many threads."); 137 138SkString 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 148// 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}; 166 167int tool_main(int argc, char** argv); 168int tool_main(int argc, char** argv) { 169 SkCommandLineFlags::SetUsage(""); 170 SkCommandLineFlags::Parse(argc, argv); 171 172#if SK_ENABLE_INST_COUNT 173 gPrintInstCount = true; 174#endif 175 176 SkGraphics::Init(); 177 178 { 179 SkString header("Skia UnitTests:"); 180 if (!FLAGS_match.isEmpty()) { 181 header.appendf(" --match"); 182 for (int index = 0; index < FLAGS_match.count(); ++index) { 183 header.appendf(" %s", FLAGS_match[index]); 184 } 185 } 186 SkString tmpDir = Test::GetTmpDir(); 187 if (!tmpDir.isEmpty()) { 188 header.appendf(" --tmpDir %s", tmpDir.c_str()); 189 } 190 SkString resourcePath = Test::GetResourcePath(); 191 if (!resourcePath.isEmpty()) { 192 header.appendf(" --resourcePath %s", resourcePath.c_str()); 193 } 194#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 204 header.appendf(" skia_arch_width=%d", (int)sizeof(void*) * 8); 205 SkDebugf("%s\n", header.c_str()); 206 } 207 208 DebugfReporter reporter(FLAGS_extendedTest, !FLAGS_single, FLAGS_verbose); 209 Iter iter(&reporter); 210 211 // Count tests first. 212 int total = 0; 213 int toRun = 0; 214 Test* test; 215 216 while ((test = iter.next()) != NULL) { 217 SkAutoTDelete<Test> owned(test); 218 219 if(!SkCommandLineFlags::ShouldSkip(FLAGS_match, test->getName())) { 220 toRun++; 221 } 222 total++; 223 } 224 reporter.setTotal(toRun); 225 226 // Now run them. 227 iter.reset(); 228 int32_t failCount = 0; 229 int skipCount = 0; 230 231 SkThreadPool threadpool(FLAGS_threads); 232 SkTArray<Test*> unsafeTests; // Always passes ownership to an SkTestRunnable 233 for (int i = 0; i < total; i++) { 234 SkAutoTDelete<Test> test(iter.next()); 235 if (SkCommandLineFlags::ShouldSkip(FLAGS_match, test->getName())) { 236 ++skipCount; 237 } else if (!test->isThreadsafe()) { 238 unsafeTests.push_back() = test.detach(); 239 } else { 240 threadpool.add(SkNEW_ARGS(SkTestRunnable, (test.detach(), &failCount))); 241 } 242 } 243 244 // 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 249 // Block until threaded tests finish. 250 threadpool.wait(); 251 252 SkDebugf("Finished %d tests, %d failures, %d skipped.\n", 253 toRun, failCount, skipCount); 254 const int testCount = reporter.countTests(); 255 if (FLAGS_verbose && testCount > 0) { 256 SkDebugf("Ran %d Internal tests.\n", testCount); 257 } 258 SkGraphics::Term(); 259 GpuTest::DestroyContexts(); 260 261 return (failCount == 0) ? 0 : 1; 262} 263 264#if !defined(SK_BUILD_FOR_IOS) && !defined(SK_BUILD_FOR_NACL) 265int main(int argc, char * const argv[]) { 266 return tool_main(argc, (char**) argv); 267} 268#endif 269