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