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 #ifndef skiatest_Test_DEFINED 8 #define skiatest_Test_DEFINED 9 10 #include "../tools/Registry.h" 11 #include "GrContextFactory.h" 12 #include "SkClipOpPriv.h" 13 #include "SkString.h" 14 #include "SkTraceEvent.h" 15 #include "SkTypes.h" 16 17 namespace skiatest { 18 19 SkString GetTmpDir(); 20 21 struct Failure { FailureFailure22 Failure(const char* f, int l, const char* c, const SkString& m) 23 : fileName(f), lineNo(l), condition(c), message(m) {} 24 const char* fileName; 25 int lineNo; 26 const char* condition; 27 SkString message; 28 SkString toString() const; 29 }; 30 31 class Reporter : SkNoncopyable { 32 public: ~Reporter()33 virtual ~Reporter() {} 34 virtual void bumpTestCount(); 35 virtual void reportFailed(const skiatest::Failure&) = 0; 36 virtual bool allowExtendedTest() const; 37 virtual bool verbose() const; stats()38 virtual void* stats() const { return nullptr; } 39 reportFailedWithContext(const skiatest::Failure & f)40 void reportFailedWithContext(const skiatest::Failure& f) { 41 SkString fullMessage = f.message; 42 if (!fContextStack.empty()) { 43 fullMessage.append(" ["); 44 for (int i = 0; i < fContextStack.count(); ++i) { 45 if (i > 0) { 46 fullMessage.append(", "); 47 } 48 fullMessage.append(fContextStack[i]); 49 } 50 fullMessage.append("]"); 51 } 52 this->reportFailed(skiatest::Failure(f.fileName, f.lineNo, f.condition, fullMessage)); 53 } push(const SkString & message)54 void push(const SkString& message) { 55 fContextStack.push_back(message); 56 } pop()57 void pop() { 58 fContextStack.pop_back(); 59 } 60 61 private: 62 SkTArray<SkString> fContextStack; 63 }; 64 65 #define REPORT_FAILURE(reporter, cond, message) \ 66 reporter->reportFailedWithContext(skiatest::Failure(__FILE__, __LINE__, cond, message)) 67 68 class ReporterContext : SkNoncopyable { 69 public: ReporterContext(Reporter * reporter,const SkString & message)70 ReporterContext(Reporter* reporter, const SkString& message) : fReporter(reporter) { 71 fReporter->push(message); 72 } ~ReporterContext()73 ~ReporterContext() { 74 fReporter->pop(); 75 } 76 77 private: 78 Reporter* fReporter; 79 }; 80 81 typedef void (*TestProc)(skiatest::Reporter*, const GrContextOptions&); 82 typedef void (*ContextOptionsProc)(GrContextOptions*); 83 84 struct Test { 85 Test(const char* n, bool g, TestProc p, ContextOptionsProc optionsProc = nullptr) nameTest86 : name(n), needsGpu(g), proc(p), fContextOptionsProc(optionsProc) {} 87 const char* name; 88 bool needsGpu; 89 TestProc proc; 90 ContextOptionsProc fContextOptionsProc; 91 modifyGrContextOptionsTest92 void modifyGrContextOptions(GrContextOptions* options) { 93 if (fContextOptionsProc) { 94 (*fContextOptionsProc)(options); 95 } 96 } 97 runTest98 void run(skiatest::Reporter* r, const GrContextOptions& options) const { 99 TRACE_EVENT1("test", TRACE_FUNC, "name", this->name/*these are static*/); 100 this->proc(r, options); 101 } 102 }; 103 104 typedef sk_tools::Registry<Test> TestRegistry; 105 106 /* 107 Use the following macros to make use of the skiatest classes, e.g. 108 109 #include "Test.h" 110 111 DEF_TEST(TestName, reporter) { 112 ... 113 REPORTER_ASSERT(reporter, x == 15); 114 ... 115 REPORTER_ASSERT(reporter, x == 15, "x should be 15"); 116 ... 117 if (x != 15) { 118 ERRORF(reporter, "x should be 15, but is %d", x); 119 return; 120 } 121 ... 122 } 123 */ 124 125 using GrContextFactoryContextType = sk_gpu_test::GrContextFactory::ContextType; 126 127 typedef void GrContextTestFn(Reporter*, const sk_gpu_test::ContextInfo&); 128 typedef bool GrContextTypeFilterFn(GrContextFactoryContextType); 129 130 extern bool IsGLContextType(GrContextFactoryContextType); 131 extern bool IsVulkanContextType(GrContextFactoryContextType); 132 extern bool IsMetalContextType(GrContextFactoryContextType); 133 extern bool IsRenderingGLContextType(GrContextFactoryContextType); 134 extern bool IsNullGLContextType(GrContextFactoryContextType); 135 void RunWithGPUTestContexts(GrContextTestFn*, GrContextTypeFilterFn*, Reporter*, 136 const GrContextOptions&); 137 138 /** Timer provides wall-clock duration since its creation. */ 139 class Timer { 140 public: 141 /** Starts the timer. */ 142 Timer(); 143 144 /** Nanoseconds since creation. */ 145 double elapsedNs() const; 146 147 /** Milliseconds since creation. */ 148 double elapsedMs() const; 149 150 /** Milliseconds since creation as an integer. 151 Behavior is undefined for durations longer than SK_MSecMax. 152 */ 153 SkMSec elapsedMsInt() const; 154 private: 155 double fStartNanos; 156 }; 157 158 } // namespace skiatest 159 160 #define REPORTER_ASSERT(r, cond, ...) \ 161 do { \ 162 if (!(cond)) { \ 163 REPORT_FAILURE(r, #cond, SkStringPrintf(__VA_ARGS__)); \ 164 } \ 165 } while (0) 166 167 #define ERRORF(r, ...) \ 168 do { \ 169 REPORT_FAILURE(r, "", SkStringPrintf(__VA_ARGS__)); \ 170 } while (0) 171 172 #define INFOF(REPORTER, ...) \ 173 do { \ 174 if ((REPORTER)->verbose()) { \ 175 SkDebugf(__VA_ARGS__); \ 176 } \ 177 } while (0) 178 179 #define DEF_TEST(name, reporter) \ 180 static void test_##name(skiatest::Reporter*, const GrContextOptions&); \ 181 skiatest::TestRegistry name##TestRegistry(skiatest::Test(#name, false, test_##name)); \ 182 void test_##name(skiatest::Reporter* reporter, const GrContextOptions&) 183 184 #define DEF_GPUTEST(name, reporter, options) \ 185 static void test_##name(skiatest::Reporter*, const GrContextOptions&); \ 186 skiatest::TestRegistry name##TestRegistry(skiatest::Test(#name, true, test_##name)); \ 187 void test_##name(skiatest::Reporter* reporter, const GrContextOptions& options) 188 189 #define DEF_GPUTEST_FOR_CONTEXTS(name, context_filter, reporter, context_info, options_filter) \ 190 static void test_##name(skiatest::Reporter*, const sk_gpu_test::ContextInfo& context_info); \ 191 static void test_gpu_contexts_##name(skiatest::Reporter* reporter, \ 192 const GrContextOptions& options) { \ 193 skiatest::RunWithGPUTestContexts(test_##name, context_filter, reporter, options); \ 194 } \ 195 skiatest::TestRegistry name##TestRegistry( \ 196 skiatest::Test(#name, true, test_gpu_contexts_##name, options_filter)); \ 197 void test_##name(skiatest::Reporter* reporter, const sk_gpu_test::ContextInfo& context_info) 198 199 #define DEF_GPUTEST_FOR_ALL_CONTEXTS(name, reporter, context_info) \ 200 DEF_GPUTEST_FOR_CONTEXTS(name, nullptr, reporter, context_info, nullptr) 201 202 #define DEF_GPUTEST_FOR_RENDERING_CONTEXTS(name, reporter, context_info) \ 203 DEF_GPUTEST_FOR_CONTEXTS(name, sk_gpu_test::GrContextFactory::IsRenderingContext, \ 204 reporter, context_info, nullptr) 205 #define DEF_GPUTEST_FOR_ALL_GL_CONTEXTS(name, reporter, context_info) \ 206 DEF_GPUTEST_FOR_CONTEXTS(name, &skiatest::IsGLContextType, \ 207 reporter, context_info, nullptr) 208 #define DEF_GPUTEST_FOR_GL_RENDERING_CONTEXTS(name, reporter, context_info) \ 209 DEF_GPUTEST_FOR_CONTEXTS(name, &skiatest::IsRenderingGLContextType, \ 210 reporter, context_info, nullptr) 211 #define DEF_GPUTEST_FOR_NULLGL_CONTEXT(name, reporter, context_info) \ 212 DEF_GPUTEST_FOR_CONTEXTS(name, &skiatest::IsNullGLContextType, \ 213 reporter, context_info, nullptr) 214 #define DEF_GPUTEST_FOR_VULKAN_CONTEXT(name, reporter, context_info) \ 215 DEF_GPUTEST_FOR_CONTEXTS(name, &skiatest::IsVulkanContextType, \ 216 reporter, context_info, nullptr) 217 #define DEF_GPUTEST_FOR_METAL_CONTEXT(name, reporter, context_info) \ 218 DEF_GPUTEST_FOR_CONTEXTS(name, &skiatest::IsMetalContextType, \ 219 reporter, context_info, nullptr) 220 221 #define REQUIRE_PDF_DOCUMENT(TEST_NAME, REPORTER) \ 222 do { \ 223 SkNullWStream testStream; \ 224 auto testDoc = SkPDF::MakeDocument(&testStream); \ 225 if (!testDoc) { \ 226 INFOF(REPORTER, "PDF disabled; %s test skipped.", #TEST_NAME); \ 227 return; \ 228 } \ 229 } while (false) 230 231 #endif 232