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