Coverage Report

Created: 2024-09-14 07:19

/src/skia/tests/Test.h
Line
Count
Source (jump to first uncovered line)
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 {
50
    Failure(const char* f, int l, const char* c, const SkString& m)
51
0
        : 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:
61
0
    virtual ~Reporter() {}
62
    virtual void bumpTestCount();
63
    virtual void reportFailed(const skiatest::Failure&) = 0;
64
    virtual bool allowExtendedTest() const;
65
    virtual bool verbose() const;
66
0
    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
     */
73
0
    void push(const SkString& message) {
74
0
        fContextStack.push_back(message);
75
0
    }
76
0
    void push(const std::string& message) {
77
0
        fContextStack.push_back(SkString(message));
78
0
    }
79
80
    /**
81
     * Remove additional context from failure assertions.
82
     */
83
0
    void pop() {
84
0
        fContextStack.pop_back();
85
0
    }
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:
100
0
    ReporterContext(Reporter* reporter, const SkString& message) : fReporter(reporter) {
101
0
        fReporter->push(message);
102
0
    }
103
0
    ReporterContext(Reporter* reporter, const std::string& message) : fReporter(reporter) {
104
0
        fReporter->push(message);
105
0
    }
106
0
    ~ReporterContext() {
107
0
        fReporter->pop();
108
0
    }
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 {
121
0
    static Test MakeCPU(const char* name, CPUTestProc proc) {
122
0
        return Test{name, TestType::kCPU, CtsEnforcement::kNever,
123
0
                    proc, nullptr, nullptr, nullptr, nullptr};
124
0
    }
125
126
0
    static Test MakeCPUSerial(const char* name, CPUTestProc proc) {
127
0
        return Test{name, TestType::kCPUSerial, CtsEnforcement::kNever,
128
0
                    proc, nullptr, nullptr, nullptr, nullptr};
129
0
    }
130
131
    static Test MakeGanesh(const char* name,
132
                           CtsEnforcement ctsEnforcement,
133
                           GaneshTestProc proc,
134
0
                           GaneshContextOptionsProc optionsProc = nullptr) {
135
0
        return Test{name, TestType::kGanesh, ctsEnforcement,
136
0
                    nullptr, proc, nullptr, optionsProc, nullptr};
137
0
    }
138
139
    static Test MakeGraphite(const char* name,
140
                             CtsEnforcement ctsEnforcement,
141
                             GraphiteTestProc proc,
142
0
                             GraphiteContextOptionsProc optionsProc = nullptr) {
143
0
        return Test{name, TestType::kGraphite, ctsEnforcement,
144
0
                    nullptr, nullptr, proc, nullptr, optionsProc};
145
0
    }
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
156
0
    void modifyGrContextOptions(GrContextOptions* options) {
157
0
        if (fGaneshContextOptionsProc) {
158
0
            (*fGaneshContextOptionsProc)(options);
159
0
        }
160
0
    }
161
162
0
    void modifyGraphiteContextOptions(skgpu::graphite::ContextOptions* options) {
163
0
        if (fGraphiteContextOptionsProc) {
164
0
            (*fGraphiteContextOptionsProc)(options);
165
0
        }
166
0
    }
167
168
0
    void cpu(skiatest::Reporter* r) const {
169
0
        SkASSERT(this->fTestType == TestType::kCPU ||
170
0
                 this->fTestType == TestType::kCPUSerial);
171
0
        TRACE_EVENT1("test_cpu", TRACE_FUNC, "name", this->fName/*these are static*/);
172
0
        this->fCPUProc(r);
173
0
    }
174
175
0
    void ganesh(skiatest::Reporter* r, const GrContextOptions& options) const {
176
0
        SkASSERT(this->fTestType == TestType::kGanesh);
177
0
        TRACE_EVENT1("test_ganesh", TRACE_FUNC, "name", this->fName/*these are static*/);
178
0
        this->fGaneshProc(r, options);
179
0
    }
180
181
0
    void graphite(skiatest::Reporter* r, const graphite::TestOptions& options) const {
182
0
        SkASSERT(this->fTestType == TestType::kGraphite);
183
0
        TRACE_EVENT1("test_graphite", TRACE_FUNC, "name", this->fName/*these are static*/);
184
0
        this->fGraphiteProc(r, options);
185
0
    }
186
187
private:
188
    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
0
            , 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