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 "include/core/SkString.h" 11 #include "include/core/SkTypes.h" 12 #include "src/core/SkTraceEvent.h" 13 #include "tools/Registry.h" 14 #include "tools/gpu/GrContextFactory.h" 15 16 namespace skgpu { class Context; } 17 18 namespace skiatest { 19 20 SkString GetTmpDir(); 21 22 struct Failure { FailureFailure23 Failure(const char* f, int l, const char* c, const SkString& m) 24 : fileName(f), lineNo(l), condition(c), message(m) {} 25 const char* fileName; 26 int lineNo; 27 const char* condition; 28 SkString message; 29 SkString toString() const; 30 }; 31 32 class Reporter : SkNoncopyable { 33 public: ~Reporter()34 virtual ~Reporter() {} 35 virtual void bumpTestCount(); 36 virtual void reportFailed(const skiatest::Failure&) = 0; 37 virtual bool allowExtendedTest() const; 38 virtual bool verbose() const; stats()39 virtual void* stats() const { return nullptr; } 40 41 void reportFailedWithContext(const skiatest::Failure&); 42 push(const SkString & message)43 void push(const SkString& message) { 44 fContextStack.push_back(message); 45 } pop()46 void pop() { 47 fContextStack.pop_back(); 48 } 49 50 private: 51 SkTArray<SkString> fContextStack; 52 }; 53 54 #define REPORT_FAILURE(reporter, cond, message) \ 55 reporter->reportFailedWithContext(skiatest::Failure(__FILE__, __LINE__, cond, message)) 56 57 class ReporterContext : SkNoncopyable { 58 public: ReporterContext(Reporter * reporter,const SkString & message)59 ReporterContext(Reporter* reporter, const SkString& message) : fReporter(reporter) { 60 fReporter->push(message); 61 } ~ReporterContext()62 ~ReporterContext() { 63 fReporter->pop(); 64 } 65 66 private: 67 Reporter* fReporter; 68 }; 69 70 typedef void (*TestProc)(skiatest::Reporter*, const GrContextOptions&); 71 typedef void (*ContextOptionsProc)(GrContextOptions*); 72 73 struct Test { 74 Test(const char* name, 75 bool needsGpu, 76 bool needsGraphite, 77 TestProc proc, 78 ContextOptionsProc optionsProc = nullptr) fNameTest79 : fName(name) 80 , fNeedsGpu(needsGpu) 81 , fNeedsGraphite(needsGraphite) 82 , fProc(proc) 83 , fContextOptionsProc(optionsProc) {} 84 const char* fName; 85 bool fNeedsGpu; 86 bool fNeedsGraphite; 87 TestProc fProc; 88 ContextOptionsProc fContextOptionsProc; 89 modifyGrContextOptionsTest90 void modifyGrContextOptions(GrContextOptions* options) { 91 if (fContextOptionsProc) { 92 (*fContextOptionsProc)(options); 93 } 94 } 95 runTest96 void run(skiatest::Reporter* r, const GrContextOptions& options) const { 97 TRACE_EVENT1("test", TRACE_FUNC, "name", this->fName/*these are static*/); 98 this->fProc(r, options); 99 } 100 }; 101 102 using TestRegistry = sk_tools::Registry<Test>; 103 104 /* 105 Use the following macros to make use of the skiatest classes, e.g. 106 107 #include "tests/Test.h" 108 109 DEF_TEST(TestName, reporter) { 110 ... 111 REPORTER_ASSERT(reporter, x == 15); 112 ... 113 REPORTER_ASSERT(reporter, x == 15, "x should be 15"); 114 ... 115 if (x != 15) { 116 ERRORF(reporter, "x should be 15, but is %d", x); 117 return; 118 } 119 ... 120 } 121 */ 122 123 using GrContextFactoryContextType = sk_gpu_test::GrContextFactory::ContextType; 124 125 typedef void GrContextTestFn(Reporter*, const sk_gpu_test::ContextInfo&); 126 typedef bool GrContextTypeFilterFn(GrContextFactoryContextType); 127 128 extern bool IsGLContextType(GrContextFactoryContextType); 129 extern bool IsVulkanContextType(GrContextFactoryContextType); 130 extern bool IsMetalContextType(GrContextFactoryContextType); 131 extern bool IsDawnContextType(GrContextFactoryContextType); 132 extern bool IsDirect3DContextType(GrContextFactoryContextType); 133 extern bool IsRenderingGLContextType(GrContextFactoryContextType); 134 extern bool IsMockContextType(GrContextFactoryContextType); 135 void RunWithGPUTestContexts(GrContextTestFn*, GrContextTypeFilterFn*, Reporter*, 136 const GrContextOptions&); 137 138 namespace graphite { 139 140 typedef void GraphiteTestFn(Reporter*, skgpu::Context*); 141 142 void RunWithGraphiteTestContexts(GraphiteTestFn*, Reporter*); 143 144 } // namespace graphite 145 146 /** Timer provides wall-clock duration since its creation. */ 147 class Timer { 148 public: 149 /** Starts the timer. */ 150 Timer(); 151 152 /** Nanoseconds since creation. */ 153 double elapsedNs() const; 154 155 /** Milliseconds since creation. */ 156 double elapsedMs() const; 157 158 /** Milliseconds since creation as an integer. 159 Behavior is undefined for durations longer than SK_MSecMax. 160 */ 161 SkMSec elapsedMsInt() const; 162 private: 163 double fStartNanos; 164 }; 165 166 } // namespace skiatest 167 168 #define REPORTER_ASSERT(r, cond, ...) \ 169 do { \ 170 if (!(cond)) { \ 171 REPORT_FAILURE(r, #cond, SkStringPrintf(__VA_ARGS__)); \ 172 } \ 173 } while (0) 174 175 #define ERRORF(r, ...) \ 176 do { \ 177 REPORT_FAILURE(r, "", SkStringPrintf(__VA_ARGS__)); \ 178 } while (0) 179 180 #define INFOF(REPORTER, ...) \ 181 do { \ 182 if ((REPORTER)->verbose()) { \ 183 SkDebugf(__VA_ARGS__); \ 184 } \ 185 } while (0) 186 187 #define DEF_CONDITIONAL_TEST(name, reporter, condition) \ 188 static void test_##name(skiatest::Reporter*, const GrContextOptions&); \ 189 skiatest::TestRegistry name##TestRegistry( \ 190 skiatest::Test(#name, /*gpu=*/false, /*graphite=*/false, test_##name), condition); \ 191 void test_##name(skiatest::Reporter* reporter, const GrContextOptions&) 192 193 #define DEF_TEST(name, reporter) DEF_CONDITIONAL_TEST(name, reporter, true) 194 195 #define DEF_TEST_DISABLED(name, reporter) DEF_CONDITIONAL_TEST(name, reporter, false) 196 197 #ifdef SK_BUILD_FOR_UNIX 198 #define UNIX_ONLY_TEST DEF_TEST 199 #else 200 #define UNIX_ONLY_TEST DEF_TEST_DISABLED 201 #endif 202 203 #define DEF_GRAPHITE_TEST(name, reporter) \ 204 static void test_##name(skiatest::Reporter*); \ 205 static void test_graphite_##name(skiatest::Reporter* reporter, \ 206 const GrContextOptions& /*unused*/) { \ 207 test_##name(reporter); \ 208 } \ 209 skiatest::TestRegistry name##TestRegistry( \ 210 skiatest::Test(#name, /*gpu=*/false, /*graphite=*/true, test_graphite_##name)); \ 211 void test_##name(skiatest::Reporter* reporter) 212 213 #define DEF_GRAPHITE_TEST_FOR_CONTEXTS(name, reporter, graphite_context) \ 214 static void test_##name(skiatest::Reporter*, skgpu::Context*); \ 215 static void test_graphite_contexts_##name(skiatest::Reporter* _reporter, \ 216 const GrContextOptions& /*unused*/) { \ 217 skiatest::graphite::RunWithGraphiteTestContexts(test_##name, _reporter); \ 218 } \ 219 skiatest::TestRegistry name##TestRegistry( \ 220 skiatest::Test(#name, /*gpu=*/false, /*graphite=*/true, \ 221 test_graphite_contexts_##name)); \ 222 void test_##name(skiatest::Reporter* reporter, skgpu::Context* graphite_context) 223 224 #define DEF_GPUTEST(name, reporter, options) \ 225 static void test_##name(skiatest::Reporter*, const GrContextOptions&); \ 226 skiatest::TestRegistry name##TestRegistry( \ 227 skiatest::Test(#name, /*gpu=*/true, /*graphite=*/false, test_##name)); \ 228 void test_##name(skiatest::Reporter* reporter, const GrContextOptions& options) 229 230 #define DEF_CONDITIONAL_GPUTEST_FOR_CONTEXTS(name, context_filter, reporter, context_info, \ 231 options_filter, condition) \ 232 static void test_##name(skiatest::Reporter*, const sk_gpu_test::ContextInfo&); \ 233 static void test_gpu_contexts_##name(skiatest::Reporter* reporter, \ 234 const GrContextOptions& options) { \ 235 skiatest::RunWithGPUTestContexts(test_##name, context_filter, reporter, options); \ 236 } \ 237 skiatest::TestRegistry name##TestRegistry( \ 238 skiatest::Test(#name, /*gpu=*/true, /*graphite=*/false, test_gpu_contexts_##name, \ 239 options_filter), condition); \ 240 void test_##name(skiatest::Reporter* reporter, const sk_gpu_test::ContextInfo& context_info) 241 242 #define DEF_CONDITIONAL_GPUTEST_FOR_ALL_CONTEXTS(name, reporter, context_info, condition) \ 243 DEF_CONDITIONAL_GPUTEST_FOR_CONTEXTS(name, nullptr, reporter, context_info, nullptr, \ 244 condition) 245 #define DEF_CONDITIONAL_GPUTEST_FOR_RENDERING_CONTEXTS(name, reporter, context_info, condition) \ 246 DEF_CONDITIONAL_GPUTEST_FOR_CONTEXTS(name, \ 247 sk_gpu_test::GrContextFactory::IsRenderingContext, \ 248 reporter, context_info, nullptr, condition) 249 250 #define DEF_GPUTEST_FOR_CONTEXTS(name, context_filter, reporter, context_info, options_filter) \ 251 DEF_CONDITIONAL_GPUTEST_FOR_CONTEXTS(name, context_filter, reporter, context_info, \ 252 options_filter, true) 253 #define DEF_GPUTEST_FOR_ALL_CONTEXTS(name, reporter, context_info) \ 254 DEF_GPUTEST_FOR_CONTEXTS(name, nullptr, reporter, context_info, nullptr) 255 256 #define DEF_GPUTEST_FOR_RENDERING_CONTEXTS(name, reporter, context_info) \ 257 DEF_GPUTEST_FOR_CONTEXTS(name, sk_gpu_test::GrContextFactory::IsRenderingContext, \ 258 reporter, context_info, nullptr) 259 #define DEF_GPUTEST_FOR_ALL_GL_CONTEXTS(name, reporter, context_info) \ 260 DEF_GPUTEST_FOR_CONTEXTS(name, &skiatest::IsGLContextType, \ 261 reporter, context_info, nullptr) 262 #define DEF_GPUTEST_FOR_GL_RENDERING_CONTEXTS(name, reporter, context_info) \ 263 DEF_GPUTEST_FOR_CONTEXTS(name, &skiatest::IsRenderingGLContextType, \ 264 reporter, context_info, nullptr) 265 #define DEF_GPUTEST_FOR_MOCK_CONTEXT(name, reporter, context_info) \ 266 DEF_GPUTEST_FOR_CONTEXTS(name, &skiatest::IsMockContextType, \ 267 reporter, context_info, nullptr) 268 #define DEF_GPUTEST_FOR_VULKAN_CONTEXT(name, reporter, context_info) \ 269 DEF_GPUTEST_FOR_CONTEXTS(name, &skiatest::IsVulkanContextType, \ 270 reporter, context_info, nullptr) 271 #define DEF_GPUTEST_FOR_METAL_CONTEXT(name, reporter, context_info) \ 272 DEF_GPUTEST_FOR_CONTEXTS(name, &skiatest::IsMetalContextType, \ 273 reporter, context_info, nullptr) 274 #define DEF_GPUTEST_FOR_D3D_CONTEXT(name, reporter, context_info) \ 275 DEF_GPUTEST_FOR_CONTEXTS(name, &skiatest::IsDirect3DContextType, \ 276 reporter, context_info, nullptr) 277 #define DEF_GPUTEST_FOR_DAWN_CONTEXT(name, reporter, context_info) \ 278 DEF_GPUTEST_FOR_CONTEXTS(name, &skiatest::IsDawnContextType, \ 279 reporter, context_info, nullptr) 280 281 #define REQUIRE_PDF_DOCUMENT(TEST_NAME, REPORTER) \ 282 do { \ 283 SkNullWStream testStream; \ 284 auto testDoc = SkPDF::MakeDocument(&testStream); \ 285 if (!testDoc) { \ 286 INFOF(REPORTER, "PDF disabled; %s test skipped.", #TEST_NAME); \ 287 return; \ 288 } \ 289 } while (false) 290 291 #endif 292