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 239 void RunWithGraphiteTestContexts(GraphiteTestFn*, 240 ContextTypeFilterFn* filter, 241 Reporter*, 242 const TestOptions&); 243 244 } // namespace graphite 245 246 /** Timer provides wall-clock duration since its creation. */ 247 class Timer { 248 public: 249 /** Starts the timer. */ 250 Timer(); 251 252 /** Nanoseconds since creation. */ 253 double elapsedNs() const; 254 255 /** Milliseconds since creation. */ 256 double elapsedMs() const; 257 258 /** Milliseconds since creation as an integer. 259 Behavior is undefined for durations longer than TimeUtils::MSecMax. 260 */ 261 TimeUtils::MSec elapsedMsInt() const; 262 private: 263 double fStartNanos; 264 }; 265 266 } // namespace skiatest 267 268 /* 269 Use the following macros to make use of the skiatest classes, e.g. 270 271 #include "tests/Test.h" 272 273 DEF_TEST(TestName, reporter) { 274 ... 275 REPORTER_ASSERT(reporter, x == 15); 276 ... 277 REPORTER_ASSERT(reporter, x == 15, "x should be 15"); 278 ... 279 if (x != 15) { 280 ERRORF(reporter, "x should be 15, but is %d", x); 281 return; 282 } 283 ... 284 } 285 */ 286 287 #define REPORTER_ASSERT(r, cond, ...) \ 288 do { \ 289 if (!(cond)) { \ 290 REPORT_FAILURE(r, #cond, SkStringPrintf(__VA_ARGS__)); \ 291 } \ 292 } while (0) 293 294 #define ERRORF(r, ...) \ 295 do { \ 296 REPORT_FAILURE(r, "", SkStringPrintf(__VA_ARGS__)); \ 297 } while (0) 298 299 #define INFOF(REPORTER, ...) \ 300 do { \ 301 if ((REPORTER)->verbose()) { \ 302 SkDebugf(__VA_ARGS__); \ 303 } \ 304 } while (0) 305 306 using skiatest::Test; 307 308 #define DEF_CONDITIONAL_TEST(name, reporter, condition) \ 309 static void test_##name(skiatest::Reporter*); \ 310 skiatest::TestRegistry name##TestRegistry(Test::MakeCPU(#name, test_##name), condition); \ 311 void test_##name(skiatest::Reporter* reporter) 312 313 #define DEF_TEST(name, reporter) DEF_CONDITIONAL_TEST(name, reporter, true) 314 315 #define DEF_TEST_DISABLED(name, reporter) DEF_CONDITIONAL_TEST(name, reporter, false) 316 317 #ifdef SK_BUILD_FOR_UNIX 318 #define UNIX_ONLY_TEST DEF_TEST 319 #else 320 #define UNIX_ONLY_TEST DEF_TEST_DISABLED 321 #endif 322 323 #define DEF_SERIAL_TEST(name, reporter) \ 324 static void test_##name(skiatest::Reporter*); \ 325 skiatest::TestRegistry name##TestRegistry(Test::MakeCPUSerial(#name, test_##name)); \ 326 void test_##name(skiatest::Reporter* reporter) 327 328 #define DEF_GRAPHITE_TEST(name, reporter, ctsEnforcement) \ 329 static void test_##name(skiatest::Reporter*); \ 330 static void test_graphite_##name(skiatest::Reporter* reporter, \ 331 const skiatest::graphite::TestOptions&) { \ 332 test_##name(reporter); \ 333 } \ 334 skiatest::TestRegistry name##TestRegistry(Test::MakeGraphite(#name, ctsEnforcement, \ 335 test_graphite_##name)); \ 336 void test_##name(skiatest::Reporter* reporter) 337 338 #define DEF_CONDITIONAL_GRAPHITE_TEST_FOR_CONTEXTS( \ 339 name, context_filter, reporter, graphite_ctx, test_ctx, opt_filter, cond, ctsEnforcement) \ 340 static void test_##name(skiatest::Reporter*, skgpu::graphite::Context*, \ 341 skiatest::graphite::GraphiteTestContext*); \ 342 static void test_graphite_contexts_##name(skiatest::Reporter* _reporter, \ 343 const skiatest::graphite::TestOptions& options) { \ 344 skiatest::graphite::RunWithGraphiteTestContexts(test_##name, context_filter, \ 345 _reporter, options); \ 346 } \ 347 skiatest::TestRegistry name##TestRegistry( \ 348 Test::MakeGraphite(#name, ctsEnforcement, test_graphite_contexts_##name, opt_filter), \ 349 cond); \ 350 void test_##name(skiatest::Reporter* reporter, skgpu::graphite::Context* graphite_ctx, \ 351 skiatest::graphite::GraphiteTestContext* test_ctx) 352 353 #define DEF_CONDITIONAL_GRAPHITE_TEST_FOR_ALL_CONTEXTS(name, reporter, graphite_ctx, \ 354 test_ctx, cond, ctsEnforcement) \ 355 DEF_CONDITIONAL_GRAPHITE_TEST_FOR_CONTEXTS(name, nullptr, reporter, graphite_ctx, test_ctx, \ 356 nullptr, cond, ctsEnforcement) 357 358 #define DEF_CONDITIONAL_GRAPHITE_TEST_FOR_RENDERING_CONTEXTS( \ 359 name, reporter, graphite_context, test_context, cond, ctsEnforcement) \ 360 DEF_CONDITIONAL_GRAPHITE_TEST_FOR_CONTEXTS(name, \ 361 skgpu::IsRenderingContext, \ 362 reporter, \ 363 graphite_context, \ 364 test_context, \ 365 nullptr, \ 366 cond, \ 367 ctsEnforcement) 368 369 #define DEF_GRAPHITE_TEST_FOR_CONTEXTS(name, context_filter, reporter, graphite_ctx, \ 370 test_ctx, ctsEnforcement) \ 371 DEF_CONDITIONAL_GRAPHITE_TEST_FOR_CONTEXTS(name, context_filter, reporter, graphite_ctx, \ 372 test_ctx, nullptr, true, ctsEnforcement) 373 374 #define DEF_GRAPHITE_TEST_FOR_ALL_CONTEXTS(name, reporter, graphite_ctx, ctsEnforcement) \ 375 DEF_CONDITIONAL_GRAPHITE_TEST_FOR_ALL_CONTEXTS(name, reporter, graphite_ctx, \ 376 /*anonymous test_ctx*/, true, ctsEnforcement) 377 378 #define DEF_GRAPHITE_TEST_FOR_RENDERING_CONTEXTS(name, reporter, graphite_context, ctsEnforcement) \ 379 DEF_CONDITIONAL_GRAPHITE_TEST_FOR_RENDERING_CONTEXTS( \ 380 name, reporter, graphite_context, /*anonymous test_ctx*/, true, ctsEnforcement) 381 382 #define DEF_GRAPHITE_TEST_FOR_VULKAN_CONTEXT(name, reporter, graphite_context, ctsEnforcement) \ 383 DEF_GRAPHITE_TEST_FOR_CONTEXTS(name, skiatest::IsVulkanContextType, reporter, \ 384 graphite_context, /*anonymous test_ctx*/, ctsEnforcement) 385 386 #define DEF_GRAPHITE_TEST_FOR_METAL_CONTEXT(name, reporter, graphite_context, test_context) \ 387 DEF_GRAPHITE_TEST_FOR_CONTEXTS(name, skiatest::IsMetalContextType, reporter, graphite_context, \ 388 test_context, CtsEnforcement::kNever) 389 390 #define DEF_GRAPHITE_TEST_FOR_DAWN_CONTEXT(name, reporter, graphite_context, test_context) \ 391 DEF_GRAPHITE_TEST_FOR_CONTEXTS(name, skiatest::IsDawnContextType, reporter, graphite_context, \ 392 test_context, CtsEnforcement::kNever) 393 394 #define DEF_GANESH_TEST(name, reporter, options, ctsEnforcement) \ 395 static void test_##name(skiatest::Reporter*, const GrContextOptions&); \ 396 skiatest::TestRegistry name##TestRegistry( \ 397 Test::MakeGanesh(#name, ctsEnforcement, test_##name, nullptr)); \ 398 void test_##name(skiatest::Reporter* reporter, const GrContextOptions& options) 399 400 #define DEF_CONDITIONAL_GANESH_TEST_FOR_CONTEXTS( \ 401 name, context_filter, reporter, context_info, options_filter, condition, ctsEnforcement) \ 402 static void test_##name(skiatest::Reporter*, const sk_gpu_test::ContextInfo&); \ 403 static void test_gpu_contexts_##name(skiatest::Reporter* reporter, \ 404 const GrContextOptions& options) { \ 405 skiatest::RunWithGaneshTestContexts(test_##name, context_filter, reporter, options); \ 406 } \ 407 skiatest::TestRegistry name##TestRegistry( \ 408 Test::MakeGanesh(#name, ctsEnforcement, test_gpu_contexts_##name, options_filter), \ 409 condition); \ 410 void test_##name(skiatest::Reporter* reporter, const sk_gpu_test::ContextInfo& context_info) 411 412 #define DEF_CONDITIONAL_GANESH_TEST_FOR_ALL_CONTEXTS( \ 413 name, reporter, context_info, condition, ctsEnforcement) \ 414 DEF_CONDITIONAL_GANESH_TEST_FOR_CONTEXTS( \ 415 name, nullptr, reporter, context_info, nullptr, condition, ctsEnforcement) 416 417 #define DEF_CONDITIONAL_GANESH_TEST_FOR_RENDERING_CONTEXTS( \ 418 name, reporter, context_info, condition, ctsEnforcement) \ 419 DEF_CONDITIONAL_GANESH_TEST_FOR_CONTEXTS(name, \ 420 skgpu::IsRenderingContext, \ 421 reporter, \ 422 context_info, \ 423 nullptr, \ 424 condition, \ 425 ctsEnforcement) 426 427 #define DEF_GANESH_TEST_FOR_CONTEXTS( \ 428 name, context_filter, reporter, context_info, options_filter, ctsEnforcement) \ 429 DEF_CONDITIONAL_GANESH_TEST_FOR_CONTEXTS( \ 430 name, context_filter, reporter, context_info, options_filter, true, ctsEnforcement) 431 432 #define DEF_GANESH_TEST_FOR_ALL_CONTEXTS(name, reporter, context_info, ctsEnforcement) \ 433 DEF_GANESH_TEST_FOR_CONTEXTS(name, nullptr, reporter, context_info, nullptr, ctsEnforcement) 434 435 #define DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(name, reporter, context_info, ctsEnforcement) \ 436 DEF_GANESH_TEST_FOR_CONTEXTS( \ 437 name, skgpu::IsRenderingContext, reporter, context_info, nullptr, ctsEnforcement) 438 439 #define DEF_GANESH_TEST_FOR_ALL_GL_CONTEXTS(name, reporter, context_info, ctsEnforcement) \ 440 DEF_GANESH_TEST_FOR_CONTEXTS( \ 441 name, skiatest::IsGLContextType, reporter, context_info, nullptr, ctsEnforcement) 442 443 #define DEF_GANESH_TEST_FOR_GL_CONTEXT(name, reporter, context_info, ctsEnforcement) \ 444 DEF_GANESH_TEST_FOR_CONTEXTS(name, \ 445 &skiatest::IsGLContextType, \ 446 reporter, \ 447 context_info, \ 448 nullptr, \ 449 ctsEnforcement) 450 451 #define DEF_GANESH_TEST_FOR_MOCK_CONTEXT(name, reporter, context_info) \ 452 DEF_GANESH_TEST_FOR_CONTEXTS(name, \ 453 &skiatest::IsMockContextType, \ 454 reporter, \ 455 context_info, \ 456 nullptr, \ 457 CtsEnforcement::kNever) 458 459 #define DEF_GANESH_TEST_FOR_VULKAN_CONTEXT(name, reporter, context_info, ctsEnforcement) \ 460 DEF_GANESH_TEST_FOR_CONTEXTS( \ 461 name, &skiatest::IsVulkanContextType, reporter, context_info, nullptr, ctsEnforcement) 462 463 #define DEF_GANESH_TEST_FOR_METAL_CONTEXT(name, reporter, context_info) \ 464 DEF_GANESH_TEST_FOR_CONTEXTS(name, \ 465 &skiatest::IsMetalContextType, \ 466 reporter, \ 467 context_info, \ 468 nullptr, \ 469 CtsEnforcement::kNever) 470 #define DEF_GANESH_TEST_FOR_D3D_CONTEXT(name, reporter, context_info) \ 471 DEF_GANESH_TEST_FOR_CONTEXTS(name, \ 472 &skiatest::IsDirect3DContextType, \ 473 reporter, \ 474 context_info, \ 475 nullptr, \ 476 CtsEnforcement::kNever) 477 478 #define DEF_GANESH_TEST_FOR_DAWN_CONTEXT(name, reporter, context_info) \ 479 DEF_GANESH_TEST_FOR_CONTEXTS(name, \ 480 &skiatest::IsDawnContextType, \ 481 reporter, \ 482 context_info, \ 483 nullptr, \ 484 CtsEnforcement::kNever) 485 486 #define REQUIRE_PDF_DOCUMENT(TEST_NAME, REPORTER) \ 487 do { \ 488 SkNullWStream testStream; \ 489 auto testDoc = SkPDF::MakeDocument(&testStream); \ 490 if (!testDoc) { \ 491 INFOF(REPORTER, "PDF disabled; %s test skipped.", #TEST_NAME); \ 492 return; \ 493 } \ 494 } while (false) 495 496 #endif 497