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 "include/private/base/SkNoncopyable.h" 13 #include "include/private/base/SkTArray.h" 14 #include "src/core/SkTraceEvent.h" 15 #include "tests/CtsEnforcement.h" 16 #include "tests/TestType.h" 17 #include "tools/Registry.h" 18 19 #if defined(SK_GANESH) || defined(SK_GRAPHITE) 20 namespace skgpu { enum class ContextType; } 21 #endif 22 23 #if defined(SK_GANESH) 24 #include "tools/gpu/GrContextFactory.h" // IWYU pragma: export (because it is used by a macro) 25 #else 26 namespace sk_gpu_test { class ContextInfo; } 27 #endif 28 29 #include <atomic> 30 #include <cstdint> 31 #include <string> 32 33 struct GrContextOptions; 34 35 namespace skgpu::graphite { 36 class Context; 37 struct ContextOptions; 38 } 39 40 namespace skiatest { 41 namespace graphite { 42 class GraphiteTestContext; 43 struct TestOptions; 44 } 45 46 SkString GetTmpDir(); 47 48 struct Failure { FailureFailure49 Failure(const char* f, int l, const char* c, const SkString& m) 50 : fileName(f), lineNo(l), condition(c), message(m) {} 51 const char* fileName; 52 int lineNo; 53 const char* condition; 54 SkString message; 55 SkString toString() const; 56 }; 57 58 class Reporter : SkNoncopyable { 59 public: ~Reporter()60 virtual ~Reporter() {} 61 virtual void bumpTestCount(); 62 virtual void reportFailed(const skiatest::Failure&) = 0; 63 virtual bool allowExtendedTest() const; 64 virtual bool verbose() const; stats()65 virtual void* stats() const { return nullptr; } 66 67 void reportFailedWithContext(const skiatest::Failure&); 68 69 /** 70 * Show additional context (e.g. subtest name) on failure assertions. 71 */ push(const SkString & message)72 void push(const SkString& message) { 73 fContextStack.push_back(message); 74 } push(const std::string & message)75 void push(const std::string& message) { 76 fContextStack.push_back(SkString(message)); 77 } 78 79 /** 80 * Remove additional context from failure assertions. 81 */ pop()82 void pop() { 83 fContextStack.pop_back(); 84 } 85 86 private: 87 skia_private::TArray<SkString> fContextStack; 88 }; 89 90 #define REPORT_FAILURE(reporter, cond, message) \ 91 reporter->reportFailedWithContext(skiatest::Failure(__FILE__, __LINE__, cond, message)) 92 93 /** 94 * Use this stack-allocated object to push and then automatically pop the context 95 * (e.g. subtest name) for a test. 96 */ 97 class ReporterContext : SkNoncopyable { 98 public: ReporterContext(Reporter * reporter,const SkString & message)99 ReporterContext(Reporter* reporter, const SkString& message) : fReporter(reporter) { 100 fReporter->push(message); 101 } ReporterContext(Reporter * reporter,const std::string & message)102 ReporterContext(Reporter* reporter, const std::string& message) : fReporter(reporter) { 103 fReporter->push(message); 104 } ~ReporterContext()105 ~ReporterContext() { 106 fReporter->pop(); 107 } 108 109 private: 110 Reporter* fReporter; 111 }; 112 113 using CPUTestProc = void (*)(Reporter*); 114 using GaneshTestProc = void (*)(Reporter*, const GrContextOptions&); 115 using GaneshContextOptionsProc = void (*)(GrContextOptions*); 116 using GraphiteTestProc = void (*)(Reporter*, const graphite::TestOptions&); 117 using GraphiteContextOptionsProc = void (*)(skgpu::graphite::ContextOptions*); 118 119 struct Test { MakeCPUTest120 static Test MakeCPU(const char* name, CPUTestProc proc) { 121 return Test{name, TestType::kCPU, CtsEnforcement::kNever, 122 proc, nullptr, nullptr, nullptr, nullptr}; 123 } 124 MakeCPUSerialTest125 static Test MakeCPUSerial(const char* name, CPUTestProc proc) { 126 return Test{name, TestType::kCPUSerial, CtsEnforcement::kNever, 127 proc, nullptr, nullptr, nullptr, nullptr}; 128 } 129 130 static Test MakeGanesh(const char* name, 131 CtsEnforcement ctsEnforcement, 132 GaneshTestProc proc, 133 GaneshContextOptionsProc optionsProc = nullptr) { 134 return Test{name, TestType::kGanesh, ctsEnforcement, 135 nullptr, proc, nullptr, optionsProc, nullptr}; 136 } 137 138 static Test MakeGraphite(const char* name, 139 CtsEnforcement ctsEnforcement, 140 GraphiteTestProc proc, 141 GraphiteContextOptionsProc optionsProc = nullptr) { 142 return Test{name, TestType::kGraphite, ctsEnforcement, 143 nullptr, nullptr, proc, nullptr, optionsProc}; 144 } 145 146 const char* fName; 147 TestType fTestType; 148 CtsEnforcement fCTSEnforcement; 149 CPUTestProc fCPUProc = nullptr; 150 GaneshTestProc fGaneshProc = nullptr; 151 GraphiteTestProc fGraphiteProc = nullptr; 152 GaneshContextOptionsProc fGaneshContextOptionsProc = nullptr; 153 GraphiteContextOptionsProc fGraphiteContextOptionsProc = nullptr; 154 modifyGrContextOptionsTest155 void modifyGrContextOptions(GrContextOptions* options) { 156 if (fGaneshContextOptionsProc) { 157 (*fGaneshContextOptionsProc)(options); 158 } 159 } 160 modifyGraphiteContextOptionsTest161 void modifyGraphiteContextOptions(skgpu::graphite::ContextOptions* options) { 162 if (fGraphiteContextOptionsProc) { 163 (*fGraphiteContextOptionsProc)(options); 164 } 165 } 166 cpuTest167 void cpu(skiatest::Reporter* r) const { 168 SkASSERT(this->fTestType == TestType::kCPU || 169 this->fTestType == TestType::kCPUSerial); 170 TRACE_EVENT1("test_cpu", TRACE_FUNC, "name", this->fName/*these are static*/); 171 this->fCPUProc(r); 172 } 173 ganeshTest174 void ganesh(skiatest::Reporter* r, const GrContextOptions& options) const { 175 SkASSERT(this->fTestType == TestType::kGanesh); 176 TRACE_EVENT1("test_ganesh", TRACE_FUNC, "name", this->fName/*these are static*/); 177 this->fGaneshProc(r, options); 178 } 179 graphiteTest180 void graphite(skiatest::Reporter* r, const graphite::TestOptions& options) const { 181 SkASSERT(this->fTestType == TestType::kGraphite); 182 TRACE_EVENT1("test_graphite", TRACE_FUNC, "name", this->fName/*these are static*/); 183 this->fGraphiteProc(r, options); 184 } 185 186 private: TestTest187 Test(const char* name, 188 TestType testType, 189 CtsEnforcement ctsEnforcement, 190 CPUTestProc cpuProc, 191 GaneshTestProc ganeshProc, 192 GraphiteTestProc graphiteProc, 193 GaneshContextOptionsProc ganeshOptionsProc, 194 GraphiteContextOptionsProc graphiteOptionsProc) 195 : fName(name) 196 , fTestType(testType) 197 , fCTSEnforcement(ctsEnforcement) 198 , fCPUProc(cpuProc) 199 , fGaneshProc(ganeshProc) 200 , fGraphiteProc(graphiteProc) 201 , fGaneshContextOptionsProc(ganeshOptionsProc) 202 , fGraphiteContextOptionsProc(graphiteOptionsProc) {} 203 }; 204 205 using TestRegistry = sk_tools::Registry<Test>; 206 207 #if defined(SK_GANESH) 208 using GpuContextType = skgpu::ContextType; 209 #else 210 using GpuContextType = nullptr_t; 211 #endif 212 213 typedef void GrContextTestFn(Reporter*, const sk_gpu_test::ContextInfo&); 214 typedef bool ContextTypeFilterFn(GpuContextType); 215 216 // We want to run the same test against potentially multiple Ganesh backends. Test runners should 217 // implement this function by calling the testFn with a fresh ContextInfo if that backend matches 218 // the provided filter. If filter is nullptr, then all compiled-in Ganesh backends should be used. 219 // The reporter and opts arguments are piped in from Test::run. 220 void RunWithGaneshTestContexts(GrContextTestFn* testFn, ContextTypeFilterFn* filter, 221 Reporter* reporter, const GrContextOptions& options); 222 223 // These context filters should be implemented by test runners and return true if the backend was 224 // compiled in (i.e. is supported) and matches the criteria indicated by the name of the filter. 225 extern bool IsGLContextType(GpuContextType); 226 extern bool IsVulkanContextType(GpuContextType); 227 extern bool IsMetalContextType(GpuContextType); 228 extern bool IsDawnContextType(GpuContextType); 229 extern bool IsDirect3DContextType(GpuContextType); 230 extern bool IsMockContextType(GpuContextType); 231 232 namespace graphite { 233 234 using GraphiteTestFn = void(Reporter*, 235 skgpu::graphite::Context*, 236 skiatest::graphite::GraphiteTestContext*); 237 238 void RunWithGraphiteTestContexts(GraphiteTestFn*, 239 ContextTypeFilterFn* filter, 240 Reporter*, 241 const TestOptions&); 242 243 } // namespace graphite 244 245 /** Timer provides wall-clock duration since its creation. */ 246 class Timer { 247 public: 248 /** Starts the timer. */ 249 Timer(); 250 251 /** Nanoseconds since creation. */ 252 double elapsedNs() const; 253 254 /** Milliseconds since creation. */ 255 double elapsedMs() const; 256 257 /** Milliseconds since creation as an integer. 258 Behavior is undefined for durations longer than SK_MSecMax. 259 */ 260 SkMSec elapsedMsInt() const; 261 private: 262 double fStartNanos; 263 }; 264 265 } // namespace skiatest 266 267 /* 268 Use the following macros to make use of the skiatest classes, e.g. 269 270 #include "tests/Test.h" 271 272 DEF_TEST(TestName, reporter) { 273 ... 274 REPORTER_ASSERT(reporter, x == 15); 275 ... 276 REPORTER_ASSERT(reporter, x == 15, "x should be 15"); 277 ... 278 if (x != 15) { 279 ERRORF(reporter, "x should be 15, but is %d", x); 280 return; 281 } 282 ... 283 } 284 */ 285 286 #define REPORTER_ASSERT(r, cond, ...) \ 287 do { \ 288 if (!(cond)) { \ 289 REPORT_FAILURE(r, #cond, SkStringPrintf(__VA_ARGS__)); \ 290 } \ 291 } while (0) 292 293 #define ERRORF(r, ...) \ 294 do { \ 295 REPORT_FAILURE(r, "", SkStringPrintf(__VA_ARGS__)); \ 296 } while (0) 297 298 #define INFOF(REPORTER, ...) \ 299 do { \ 300 if ((REPORTER)->verbose()) { \ 301 SkDebugf(__VA_ARGS__); \ 302 } \ 303 } while (0) 304 305 using skiatest::Test; 306 307 #define DEF_CONDITIONAL_TEST(name, reporter, condition) \ 308 static void test_##name(skiatest::Reporter*); \ 309 skiatest::TestRegistry name##TestRegistry(Test::MakeCPU(#name, test_##name), condition); \ 310 void test_##name(skiatest::Reporter* reporter) 311 312 #define DEF_TEST(name, reporter) DEF_CONDITIONAL_TEST(name, reporter, true) 313 314 #define DEF_TEST_DISABLED(name, reporter) DEF_CONDITIONAL_TEST(name, reporter, false) 315 316 #ifdef SK_BUILD_FOR_UNIX 317 #define UNIX_ONLY_TEST DEF_TEST 318 #else 319 #define UNIX_ONLY_TEST DEF_TEST_DISABLED 320 #endif 321 322 #define DEF_SERIAL_TEST(name, reporter) \ 323 static void test_##name(skiatest::Reporter*); \ 324 skiatest::TestRegistry name##TestRegistry(Test::MakeCPUSerial(#name, test_##name)); \ 325 void test_##name(skiatest::Reporter* reporter) 326 327 #define DEF_GRAPHITE_TEST(name, reporter, ctsEnforcement) \ 328 static void test_##name(skiatest::Reporter*); \ 329 static void test_graphite_##name(skiatest::Reporter* reporter, \ 330 const skiatest::graphite::TestOptions&) { \ 331 test_##name(reporter); \ 332 } \ 333 skiatest::TestRegistry name##TestRegistry(Test::MakeGraphite(#name, ctsEnforcement, \ 334 test_graphite_##name)); \ 335 void test_##name(skiatest::Reporter* reporter) 336 337 #define DEF_CONDITIONAL_GRAPHITE_TEST_FOR_CONTEXTS( \ 338 name, context_filter, reporter, graphite_ctx, test_ctx, opt_filter, cond, ctsEnforcement) \ 339 static void test_##name(skiatest::Reporter*, skgpu::graphite::Context*, \ 340 skiatest::graphite::GraphiteTestContext*); \ 341 static void test_graphite_contexts_##name(skiatest::Reporter* _reporter, \ 342 const skiatest::graphite::TestOptions& options) { \ 343 skiatest::graphite::RunWithGraphiteTestContexts(test_##name, context_filter, \ 344 _reporter, options); \ 345 } \ 346 skiatest::TestRegistry name##TestRegistry( \ 347 Test::MakeGraphite(#name, ctsEnforcement, test_graphite_contexts_##name, opt_filter), \ 348 cond); \ 349 void test_##name(skiatest::Reporter* reporter, skgpu::graphite::Context* graphite_ctx, \ 350 skiatest::graphite::GraphiteTestContext* test_ctx) 351 352 #define DEF_CONDITIONAL_GRAPHITE_TEST_FOR_ALL_CONTEXTS(name, reporter, graphite_ctx, \ 353 test_ctx, cond, ctsEnforcement) \ 354 DEF_CONDITIONAL_GRAPHITE_TEST_FOR_CONTEXTS(name, nullptr, reporter, graphite_ctx, test_ctx, \ 355 nullptr, cond, ctsEnforcement) 356 357 #define DEF_CONDITIONAL_GRAPHITE_TEST_FOR_RENDERING_CONTEXTS( \ 358 name, reporter, graphite_context, test_context, cond, ctsEnforcement) \ 359 DEF_CONDITIONAL_GRAPHITE_TEST_FOR_CONTEXTS(name, \ 360 skgpu::IsRenderingContext, \ 361 reporter, \ 362 graphite_context, \ 363 test_context, \ 364 nullptr, \ 365 cond, \ 366 ctsEnforcement) 367 368 #define DEF_GRAPHITE_TEST_FOR_CONTEXTS(name, context_filter, reporter, graphite_ctx, \ 369 test_ctx, ctsEnforcement) \ 370 DEF_CONDITIONAL_GRAPHITE_TEST_FOR_CONTEXTS(name, context_filter, reporter, graphite_ctx, \ 371 test_ctx, nullptr, true, ctsEnforcement) 372 373 #define DEF_GRAPHITE_TEST_FOR_ALL_CONTEXTS(name, reporter, graphite_ctx, ctsEnforcement) \ 374 DEF_CONDITIONAL_GRAPHITE_TEST_FOR_ALL_CONTEXTS(name, reporter, graphite_ctx, \ 375 /*anonymous test_ctx*/, true, ctsEnforcement) 376 377 #define DEF_GRAPHITE_TEST_FOR_RENDERING_CONTEXTS(name, reporter, graphite_context, ctsEnforcement) \ 378 DEF_CONDITIONAL_GRAPHITE_TEST_FOR_RENDERING_CONTEXTS( \ 379 name, reporter, graphite_context, /*anonymous test_ctx*/, true, ctsEnforcement) 380 381 #define DEF_GRAPHITE_TEST_FOR_VULKAN_CONTEXT(name, reporter, graphite_context, ctsEnforcement) \ 382 DEF_GRAPHITE_TEST_FOR_CONTEXTS(name, skiatest::IsVulkanContextType, reporter, \ 383 graphite_context, /*anonymous test_ctx*/, ctsEnforcement) 384 385 #define DEF_GRAPHITE_TEST_FOR_METAL_CONTEXT(name, reporter, graphite_context, test_context) \ 386 DEF_GRAPHITE_TEST_FOR_CONTEXTS(name, skiatest::IsMetalContextType, reporter, graphite_context, \ 387 test_context, CtsEnforcement::kNever) 388 389 #define DEF_GRAPHITE_TEST_FOR_DAWN_CONTEXT(name, reporter, graphite_context, test_context) \ 390 DEF_GRAPHITE_TEST_FOR_CONTEXTS(name, skiatest::IsDawnContextType, reporter, graphite_context, \ 391 test_context, CtsEnforcement::kNever) 392 393 #define DEF_GANESH_TEST(name, reporter, options, ctsEnforcement) \ 394 static void test_##name(skiatest::Reporter*, const GrContextOptions&); \ 395 skiatest::TestRegistry name##TestRegistry( \ 396 Test::MakeGanesh(#name, ctsEnforcement, test_##name, nullptr)); \ 397 void test_##name(skiatest::Reporter* reporter, const GrContextOptions& options) 398 399 #define DEF_CONDITIONAL_GANESH_TEST_FOR_CONTEXTS( \ 400 name, context_filter, reporter, context_info, options_filter, condition, ctsEnforcement) \ 401 static void test_##name(skiatest::Reporter*, const sk_gpu_test::ContextInfo&); \ 402 static void test_gpu_contexts_##name(skiatest::Reporter* reporter, \ 403 const GrContextOptions& options) { \ 404 skiatest::RunWithGaneshTestContexts(test_##name, context_filter, reporter, options); \ 405 } \ 406 skiatest::TestRegistry name##TestRegistry( \ 407 Test::MakeGanesh(#name, ctsEnforcement, test_gpu_contexts_##name, options_filter), \ 408 condition); \ 409 void test_##name(skiatest::Reporter* reporter, const sk_gpu_test::ContextInfo& context_info) 410 411 #define DEF_CONDITIONAL_GANESH_TEST_FOR_ALL_CONTEXTS( \ 412 name, reporter, context_info, condition, ctsEnforcement) \ 413 DEF_CONDITIONAL_GANESH_TEST_FOR_CONTEXTS( \ 414 name, nullptr, reporter, context_info, nullptr, condition, ctsEnforcement) 415 416 #define DEF_CONDITIONAL_GANESH_TEST_FOR_RENDERING_CONTEXTS( \ 417 name, reporter, context_info, condition, ctsEnforcement) \ 418 DEF_CONDITIONAL_GANESH_TEST_FOR_CONTEXTS(name, \ 419 skgpu::IsRenderingContext, \ 420 reporter, \ 421 context_info, \ 422 nullptr, \ 423 condition, \ 424 ctsEnforcement) 425 426 #define DEF_GANESH_TEST_FOR_CONTEXTS( \ 427 name, context_filter, reporter, context_info, options_filter, ctsEnforcement) \ 428 DEF_CONDITIONAL_GANESH_TEST_FOR_CONTEXTS( \ 429 name, context_filter, reporter, context_info, options_filter, true, ctsEnforcement) 430 431 #define DEF_GANESH_TEST_FOR_ALL_CONTEXTS(name, reporter, context_info, ctsEnforcement) \ 432 DEF_GANESH_TEST_FOR_CONTEXTS(name, nullptr, reporter, context_info, nullptr, ctsEnforcement) 433 434 #define DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(name, reporter, context_info, ctsEnforcement) \ 435 DEF_GANESH_TEST_FOR_CONTEXTS( \ 436 name, skgpu::IsRenderingContext, reporter, context_info, nullptr, ctsEnforcement) 437 438 #define DEF_GANESH_TEST_FOR_ALL_GL_CONTEXTS(name, reporter, context_info, ctsEnforcement) \ 439 DEF_GANESH_TEST_FOR_CONTEXTS( \ 440 name, skiatest::IsGLContextType, reporter, context_info, nullptr, ctsEnforcement) 441 442 #define DEF_GANESH_TEST_FOR_GL_CONTEXT(name, reporter, context_info, ctsEnforcement) \ 443 DEF_GANESH_TEST_FOR_CONTEXTS(name, \ 444 &skiatest::IsGLContextType, \ 445 reporter, \ 446 context_info, \ 447 nullptr, \ 448 ctsEnforcement) 449 450 #define DEF_GANESH_TEST_FOR_MOCK_CONTEXT(name, reporter, context_info) \ 451 DEF_GANESH_TEST_FOR_CONTEXTS(name, \ 452 &skiatest::IsMockContextType, \ 453 reporter, \ 454 context_info, \ 455 nullptr, \ 456 CtsEnforcement::kNever) 457 458 #define DEF_GANESH_TEST_FOR_VULKAN_CONTEXT(name, reporter, context_info, ctsEnforcement) \ 459 DEF_GANESH_TEST_FOR_CONTEXTS( \ 460 name, &skiatest::IsVulkanContextType, reporter, context_info, nullptr, ctsEnforcement) 461 462 #define DEF_GANESH_TEST_FOR_METAL_CONTEXT(name, reporter, context_info) \ 463 DEF_GANESH_TEST_FOR_CONTEXTS(name, \ 464 &skiatest::IsMetalContextType, \ 465 reporter, \ 466 context_info, \ 467 nullptr, \ 468 CtsEnforcement::kNever) 469 #define DEF_GANESH_TEST_FOR_D3D_CONTEXT(name, reporter, context_info) \ 470 DEF_GANESH_TEST_FOR_CONTEXTS(name, \ 471 &skiatest::IsDirect3DContextType, \ 472 reporter, \ 473 context_info, \ 474 nullptr, \ 475 CtsEnforcement::kNever) 476 477 #define DEF_GANESH_TEST_FOR_DAWN_CONTEXT(name, reporter, context_info) \ 478 DEF_GANESH_TEST_FOR_CONTEXTS(name, \ 479 &skiatest::IsDawnContextType, \ 480 reporter, \ 481 context_info, \ 482 nullptr, \ 483 CtsEnforcement::kNever) 484 485 #define REQUIRE_PDF_DOCUMENT(TEST_NAME, REPORTER) \ 486 do { \ 487 SkNullWStream testStream; \ 488 auto testDoc = SkPDF::MakeDocument(&testStream); \ 489 if (!testDoc) { \ 490 INFOF(REPORTER, "PDF disabled; %s test skipped.", #TEST_NAME); \ 491 return; \ 492 } \ 493 } while (false) 494 495 #endif 496