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 "CrashHandler.h" 9 #include "OverwriteLine.h" 10 #include "Resources.h" 11 #include "SkAtomics.h" 12 #include "SkCommonFlags.h" 13 #include "SkGraphics.h" 14 #include "SkOSFile.h" 15 #include "SkPathOpsDebug.h" 16 #include "SkTArray.h" 17 #include "SkTaskGroup.h" 18 #include "SkTemplates.h" 19 #include "SkTime.h" 20 #include "Test.h" 21 22 #if SK_SUPPORT_GPU 23 #include "GrContext.h" 24 #include "GrContextFactory.h" 25 #else 26 struct GrContextOptions {}; 27 #endif 28 29 using namespace skiatest; 30 using namespace sk_gpu_test; 31 32 DEFINE_bool2(dumpOp, d, false, "dump the pathOps to a file to recover mid-crash."); 33 DEFINE_bool2(extendedTest, x, false, "run extended tests for pathOps."); 34 DEFINE_bool2(runFail, f, false, "check for success on tests known to fail."); 35 DEFINE_bool2(verifyOp, y, false, "compare the pathOps result against a region."); 36 37 #if DEBUG_COIN 38 DEFINE_bool2(coinTest, c, false, "detect unused coincidence algorithms."); 39 #endif 40 41 // need to explicitly declare this, or we get some weird infinite loop llist 42 template TestRegistry* TestRegistry::gHead; 43 void (*gVerboseFinalize)() = nullptr; 44 45 // The threads report back to this object when they are done. 46 class Status { 47 public: 48 explicit Status(int total) 49 : fDone(0), fTestCount(0), fFailCount(0), fTotal(total) {} 50 // Threadsafe. 51 void endTest(const char* testName, 52 bool success, 53 SkMSec elapsed, 54 int testCount) { 55 const int done = 1 + sk_atomic_inc(&fDone); 56 for (int i = 0; i < testCount; ++i) { 57 sk_atomic_inc(&fTestCount); 58 } 59 if (!success) { 60 SkDebugf("\n---- %s FAILED", testName); 61 } 62 63 SkString prefix(kSkOverwriteLine); 64 SkString time; 65 if (FLAGS_verbose) { 66 prefix.printf("\n"); 67 time.printf("%5dms ", elapsed); 68 } 69 SkDebugf("%s[%3d/%3d] %s%s", prefix.c_str(), done, fTotal, time.c_str(), 70 testName); 71 } 72 73 void reportFailure() { sk_atomic_inc(&fFailCount); } 74 75 int32_t testCount() { return fTestCount; } 76 int32_t failCount() { return fFailCount; } 77 78 private: 79 int32_t fDone; // atomic 80 int32_t fTestCount; // atomic 81 int32_t fFailCount; // atomic 82 const int fTotal; 83 }; 84 85 class SkTestRunnable { 86 public: 87 SkTestRunnable(const Test& test, Status* status) : fTest(test), fStatus(status) {} 88 89 void operator()() { 90 struct TestReporter : public skiatest::Reporter { 91 public: 92 TestReporter() : fStats(nullptr), fError(false), fTestCount(0) {} 93 void bumpTestCount() override { ++fTestCount; } 94 bool allowExtendedTest() const override { return FLAGS_extendedTest; } 95 bool verbose() const override { return FLAGS_veryVerbose; } 96 void reportFailed(const skiatest::Failure& failure) override { 97 SkDebugf("\nFAILED: %s", failure.toString().c_str()); 98 fError = true; 99 } 100 void* stats() const override { return fStats; } 101 void* fStats; 102 bool fError; 103 int fTestCount; 104 } reporter; 105 106 const Timer timer; 107 fTest.proc(&reporter, GrContextOptions()); 108 SkMSec elapsed = timer.elapsedMsInt(); 109 if (reporter.fError) { 110 fStatus->reportFailure(); 111 } 112 fStatus->endTest(fTest.name, !reporter.fError, elapsed, reporter.fTestCount); 113 } 114 115 private: 116 Test fTest; 117 Status* fStatus; 118 }; 119 120 static bool should_run(const char* testName, bool isGPUTest) { 121 if (SkCommandLineFlags::ShouldSkip(FLAGS_match, testName)) { 122 return false; 123 } 124 if (!FLAGS_cpu && !isGPUTest) { 125 return false; 126 } 127 if (!FLAGS_gpu && isGPUTest) { 128 return false; 129 } 130 return true; 131 } 132 133 int main(int argc, char** argv) { 134 SkCommandLineFlags::Parse(argc, argv); 135 #if DEBUG_DUMP_VERIFY 136 SkPathOpsDebug::gDumpOp = FLAGS_dumpOp; 137 SkPathOpsDebug::gVerifyOp = FLAGS_verifyOp; 138 #endif 139 SkPathOpsDebug::gRunFail = FLAGS_runFail; 140 SkPathOpsDebug::gVeryVerbose = FLAGS_veryVerbose; 141 SetupCrashHandler(); 142 143 SkAutoGraphics ag; 144 145 { 146 SkString header("Skia UnitTests:"); 147 if (!FLAGS_match.isEmpty()) { 148 header.appendf(" --match"); 149 for (int index = 0; index < FLAGS_match.count(); ++index) { 150 header.appendf(" %s", FLAGS_match[index]); 151 } 152 } 153 SkString tmpDir = skiatest::GetTmpDir(); 154 if (!tmpDir.isEmpty()) { 155 header.appendf(" --tmpDir %s", tmpDir.c_str()); 156 } 157 SkString resourcePath = GetResourcePath(); 158 if (!resourcePath.isEmpty()) { 159 header.appendf(" --resourcePath %s", resourcePath.c_str()); 160 } 161 #if DEBUG_COIN 162 if (FLAGS_coinTest) { 163 header.appendf(" -c"); 164 } 165 #endif 166 if (FLAGS_dumpOp) { 167 header.appendf(" -d"); 168 } 169 #ifdef SK_DEBUG 170 if (FLAGS_runFail) { 171 header.appendf(" -f"); 172 } 173 #endif 174 if (FLAGS_verbose) { 175 header.appendf(" -v"); 176 } 177 if (FLAGS_veryVerbose) { 178 header.appendf(" -V"); 179 } 180 if (FLAGS_extendedTest) { 181 header.appendf(" -x"); 182 } 183 if (FLAGS_verifyOp) { 184 header.appendf(" -y"); 185 } 186 #ifdef SK_DEBUG 187 header.append(" SK_DEBUG"); 188 #else 189 header.append(" SK_RELEASE"); 190 #endif 191 if (FLAGS_veryVerbose) { 192 header.appendf("\n"); 193 } 194 SkDebugf("%s", header.c_str()); 195 } 196 197 198 // Count tests first. 199 int total = 0; 200 int toRun = 0; 201 202 for (const TestRegistry* iter = TestRegistry::Head(); iter; 203 iter = iter->next()) { 204 const Test& test = iter->factory(); 205 if (should_run(test.name, test.needsGpu)) { 206 toRun++; 207 } 208 total++; 209 } 210 211 // Now run them. 212 int skipCount = 0; 213 214 SkTaskGroup::Enabler enabled(FLAGS_threads); 215 SkTaskGroup cpuTests; 216 SkTArray<const Test*> gpuTests; 217 218 Status status(toRun); 219 for (const TestRegistry* iter = TestRegistry::Head(); iter; 220 iter = iter->next()) { 221 const Test& test = iter->factory(); 222 if (!should_run(test.name, test.needsGpu)) { 223 ++skipCount; 224 } else if (test.needsGpu) { 225 gpuTests.push_back(&test); 226 } else { 227 cpuTests.add(SkTestRunnable(test, &status)); 228 } 229 } 230 231 // Run GPU tests on this thread. 232 for (int i = 0; i < gpuTests.count(); i++) { 233 SkTestRunnable(*gpuTests[i], &status)(); 234 } 235 236 // Block until threaded tests finish. 237 cpuTests.wait(); 238 239 if (FLAGS_verbose) { 240 SkDebugf( 241 "\nFinished %d tests, %d failures, %d skipped. " 242 "(%d internal tests)", 243 toRun, status.failCount(), skipCount, status.testCount()); 244 if (gVerboseFinalize) { 245 (*gVerboseFinalize)(); 246 } 247 } 248 249 SkDebugf("\n"); 250 #if DEBUG_COIN 251 if (FLAGS_coinTest) { 252 SkPathOpsDebug::DumpCoinDict(); 253 } 254 #endif 255 256 return (status.failCount() == 0) ? 0 : 1; 257 } 258