skia_test.cpp revision 4239fc2f69bdbd1a1f01ee66112f46033b47b743
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 "SkRunnable.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; 28 29DEFINE_bool2(extendedTest, x, false, "run extended tests for pathOps."); 30 31// need to explicitly declare this, or we get some weird infinite loop llist 32template TestRegistry* TestRegistry::gHead; 33 34// The threads report back to this object when they are done. 35class Status { 36public: 37 explicit Status(int total) 38 : fDone(0), fTestCount(0), fFailCount(0), fTotal(total) {} 39 // Threadsafe. 40 void endTest(const char* testName, 41 bool success, 42 SkMSec elapsed, 43 int testCount) { 44 const int done = 1 + sk_atomic_inc(&fDone); 45 for (int i = 0; i < testCount; ++i) { 46 sk_atomic_inc(&fTestCount); 47 } 48 if (!success) { 49 SkDebugf("\n---- %s FAILED", testName); 50 } 51 52 SkString prefix(kSkOverwriteLine); 53 SkString time; 54 if (FLAGS_verbose) { 55 prefix.printf("\n"); 56 time.printf("%5dms ", elapsed); 57 } 58 SkDebugf("%s[%3d/%3d] %s%s", prefix.c_str(), done, fTotal, time.c_str(), 59 testName); 60 } 61 62 void reportFailure() { sk_atomic_inc(&fFailCount); } 63 64 int32_t testCount() { return fTestCount; } 65 int32_t failCount() { return fFailCount; } 66 67private: 68 int32_t fDone; // atomic 69 int32_t fTestCount; // atomic 70 int32_t fFailCount; // atomic 71 const int fTotal; 72}; 73 74// Deletes self when run. 75class SkTestRunnable : public SkRunnable { 76public: 77 SkTestRunnable(const Test& test, 78 Status* status, 79 GrContextFactory* grContextFactory = NULL) 80 : fTest(test), fStatus(status), fGrContextFactory(grContextFactory) {} 81 82 virtual void run() { 83 struct TestReporter : public skiatest::Reporter { 84 public: 85 TestReporter() : fError(false), fTestCount(0) {} 86 void bumpTestCount() override { ++fTestCount; } 87 bool allowExtendedTest() const override { 88 return FLAGS_extendedTest; 89 } 90 bool verbose() const override { return FLAGS_veryVerbose; } 91 void reportFailed(const skiatest::Failure& failure) override { 92 SkDebugf("\nFAILED: %s", failure.toString().c_str()); 93 fError = true; 94 } 95 bool fError; 96 int fTestCount; 97 } reporter; 98 99 const SkMSec start = SkTime::GetMSecs(); 100 fTest.proc(&reporter, fGrContextFactory); 101 SkMSec elapsed = SkTime::GetMSecs() - start; 102 if (reporter.fError) { 103 fStatus->reportFailure(); 104 } 105 fStatus->endTest(fTest.name, !reporter.fError, elapsed, 106 reporter.fTestCount); 107 SkDELETE(this); 108 } 109 110private: 111 Test fTest; 112 Status* fStatus; 113 GrContextFactory* fGrContextFactory; 114}; 115 116static bool should_run(const char* testName, bool isGPUTest) { 117 if (SkCommandLineFlags::ShouldSkip(FLAGS_match, testName)) { 118 return false; 119 } 120 if (!FLAGS_cpu && !isGPUTest) { 121 return false; 122 } 123 if (!FLAGS_gpu && isGPUTest) { 124 return false; 125 } 126 return true; 127} 128 129int test_main(); 130int test_main() { 131 SetupCrashHandler(); 132 133 SkAutoGraphics ag; 134 135 { 136 SkString header("Skia UnitTests:"); 137 if (!FLAGS_match.isEmpty()) { 138 header.appendf(" --match"); 139 for (int index = 0; index < FLAGS_match.count(); ++index) { 140 header.appendf(" %s", FLAGS_match[index]); 141 } 142 } 143 SkString tmpDir = skiatest::GetTmpDir(); 144 if (!tmpDir.isEmpty()) { 145 header.appendf(" --tmpDir %s", tmpDir.c_str()); 146 } 147 SkString resourcePath = GetResourcePath(); 148 if (!resourcePath.isEmpty()) { 149 header.appendf(" --resourcePath %s", resourcePath.c_str()); 150 } 151#ifdef SK_DEBUG 152 header.append(" SK_DEBUG"); 153#else 154 header.append(" SK_RELEASE"); 155#endif 156 if (FLAGS_veryVerbose) { 157 header.appendf("\n"); 158 } 159 SkDebugf("%s", header.c_str()); 160 } 161 162 163 // Count tests first. 164 int total = 0; 165 int toRun = 0; 166 167 for (const TestRegistry* iter = TestRegistry::Head(); iter; 168 iter = iter->next()) { 169 const Test& test = iter->factory(); 170 if (should_run(test.name, test.needsGpu)) { 171 toRun++; 172 } 173 total++; 174 } 175 176 // Now run them. 177 int skipCount = 0; 178 179 SkTaskGroup::Enabler enabled(FLAGS_threads); 180 SkTaskGroup cpuTests; 181 SkTArray<const Test*> gpuTests; 182 183 Status status(toRun); 184 for (const TestRegistry* iter = TestRegistry::Head(); iter; 185 iter = iter->next()) { 186 const Test& test = iter->factory(); 187 if (!should_run(test.name, test.needsGpu)) { 188 ++skipCount; 189 } else if (test.needsGpu) { 190 gpuTests.push_back(&test); 191 } else { 192 cpuTests.add(SkNEW_ARGS(SkTestRunnable, (test, &status))); 193 } 194 } 195 196 GrContextFactory* grContextFactoryPtr = NULL; 197#if SK_SUPPORT_GPU 198 // Give GPU tests a context factory if that makes sense on this machine. 199 GrContextFactory grContextFactory; 200 grContextFactoryPtr = &grContextFactory; 201 202#endif 203 204 // Run GPU tests on this thread. 205 for (int i = 0; i < gpuTests.count(); i++) { 206 SkNEW_ARGS(SkTestRunnable, (*gpuTests[i], &status, grContextFactoryPtr)) 207 ->run(); 208 } 209 210 // Block until threaded tests finish. 211 cpuTests.wait(); 212 213 if (FLAGS_verbose) { 214 SkDebugf( 215 "\nFinished %d tests, %d failures, %d skipped. " 216 "(%d internal tests)", 217 toRun, status.failCount(), skipCount, status.testCount()); 218 } 219 220 SkDebugf("\n"); 221 return (status.failCount() == 0) ? 0 : 1; 222} 223 224#if !defined(SK_BUILD_FOR_IOS) 225int main(int argc, char** argv) { 226 SkCommandLineFlags::Parse(argc, argv); 227 return test_main(); 228} 229#endif 230