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