• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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