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