xref: /aosp_15_r20/external/skia/tests/Test.h (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
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