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 "src/core/SkTraceEvent.h"
13 #include "tools/Registry.h"
14 #include "tools/gpu/GrContextFactory.h"
15
16 namespace skgpu { class Context; }
17
18 namespace skiatest {
19
20 SkString GetTmpDir();
21
22 struct Failure {
FailureFailure23 Failure(const char* f, int l, const char* c, const SkString& m)
24 : fileName(f), lineNo(l), condition(c), message(m) {}
25 const char* fileName;
26 int lineNo;
27 const char* condition;
28 SkString message;
29 SkString toString() const;
30 };
31
32 class Reporter : SkNoncopyable {
33 public:
~Reporter()34 virtual ~Reporter() {}
35 virtual void bumpTestCount();
36 virtual void reportFailed(const skiatest::Failure&) = 0;
37 virtual bool allowExtendedTest() const;
38 virtual bool verbose() const;
stats()39 virtual void* stats() const { return nullptr; }
40
41 void reportFailedWithContext(const skiatest::Failure&);
42
push(const SkString & message)43 void push(const SkString& message) {
44 fContextStack.push_back(message);
45 }
pop()46 void pop() {
47 fContextStack.pop_back();
48 }
49
50 private:
51 SkTArray<SkString> fContextStack;
52 };
53
54 #define REPORT_FAILURE(reporter, cond, message) \
55 reporter->reportFailedWithContext(skiatest::Failure(__FILE__, __LINE__, cond, message))
56
57 class ReporterContext : SkNoncopyable {
58 public:
ReporterContext(Reporter * reporter,const SkString & message)59 ReporterContext(Reporter* reporter, const SkString& message) : fReporter(reporter) {
60 fReporter->push(message);
61 }
~ReporterContext()62 ~ReporterContext() {
63 fReporter->pop();
64 }
65
66 private:
67 Reporter* fReporter;
68 };
69
70 typedef void (*TestProc)(skiatest::Reporter*, const GrContextOptions&);
71 typedef void (*ContextOptionsProc)(GrContextOptions*);
72
73 struct Test {
74 Test(const char* name,
75 bool needsGpu,
76 bool needsGraphite,
77 TestProc proc,
78 ContextOptionsProc optionsProc = nullptr)
fNameTest79 : fName(name)
80 , fNeedsGpu(needsGpu)
81 , fNeedsGraphite(needsGraphite)
82 , fProc(proc)
83 , fContextOptionsProc(optionsProc) {}
84 const char* fName;
85 bool fNeedsGpu;
86 bool fNeedsGraphite;
87 TestProc fProc;
88 ContextOptionsProc fContextOptionsProc;
89
modifyGrContextOptionsTest90 void modifyGrContextOptions(GrContextOptions* options) {
91 if (fContextOptionsProc) {
92 (*fContextOptionsProc)(options);
93 }
94 }
95
runTest96 void run(skiatest::Reporter* r, const GrContextOptions& options) const {
97 TRACE_EVENT1("test", TRACE_FUNC, "name", this->fName/*these are static*/);
98 this->fProc(r, options);
99 }
100 };
101
102 typedef sk_tools::Registry<Test> TestRegistry;
103
104 /*
105 Use the following macros to make use of the skiatest classes, e.g.
106
107 #include "tests/Test.h"
108
109 DEF_TEST(TestName, reporter) {
110 ...
111 REPORTER_ASSERT(reporter, x == 15);
112 ...
113 REPORTER_ASSERT(reporter, x == 15, "x should be 15");
114 ...
115 if (x != 15) {
116 ERRORF(reporter, "x should be 15, but is %d", x);
117 return;
118 }
119 ...
120 }
121 */
122
123 using GrContextFactoryContextType = sk_gpu_test::GrContextFactory::ContextType;
124
125 typedef void GrContextTestFn(Reporter*, const sk_gpu_test::ContextInfo&);
126 typedef bool GrContextTypeFilterFn(GrContextFactoryContextType);
127
128 extern bool IsGLContextType(GrContextFactoryContextType);
129 extern bool IsVulkanContextType(GrContextFactoryContextType);
130 extern bool IsMetalContextType(GrContextFactoryContextType);
131 extern bool IsDawnContextType(GrContextFactoryContextType);
132 extern bool IsDirect3DContextType(GrContextFactoryContextType);
133 extern bool IsRenderingGLContextType(GrContextFactoryContextType);
134 extern bool IsMockContextType(GrContextFactoryContextType);
135 void RunWithGPUTestContexts(GrContextTestFn*, GrContextTypeFilterFn*, Reporter*,
136 const GrContextOptions&);
137
138 namespace graphite {
139
140 typedef void GraphiteTestFn(Reporter*, skgpu::Context*);
141
142 void RunWithGraphiteTestContexts(GraphiteTestFn*, Reporter*);
143
144 } // namespace graphite
145
146 /** Timer provides wall-clock duration since its creation. */
147 class Timer {
148 public:
149 /** Starts the timer. */
150 Timer();
151
152 /** Nanoseconds since creation. */
153 double elapsedNs() const;
154
155 /** Milliseconds since creation. */
156 double elapsedMs() const;
157
158 /** Milliseconds since creation as an integer.
159 Behavior is undefined for durations longer than SK_MSecMax.
160 */
161 SkMSec elapsedMsInt() const;
162 private:
163 double fStartNanos;
164 };
165
166 } // namespace skiatest
167
reporter_string()168 static inline SkString reporter_string() { return {}; }
169 /// Prevent security warnings when using a non-literal string i.e. not a format string.
reporter_string(const char * s)170 static inline SkString reporter_string(const char* s) { return SkString(s); }
171 template<typename... Args>
reporter_string(const char * fmt,Args...args)172 static inline SkString reporter_string(const char* fmt, Args... args) {
173 return SkStringPrintf(fmt, std::forward<Args>(args)...);
174 }
175
176 #define REPORTER_ASSERT(r, cond, ...) \
177 do { \
178 if (!(cond)) { \
179 REPORT_FAILURE(r, #cond, reporter_string(__VA_ARGS__)); \
180 } \
181 } while (0)
182
183 #define ERRORF(r, ...) \
184 do { \
185 REPORT_FAILURE(r, "", reporter_string(__VA_ARGS__)); \
186 } while (0)
187
188 #define INFOF(REPORTER, ...) \
189 do { \
190 if ((REPORTER)->verbose()) { \
191 SkDebugf(__VA_ARGS__); \
192 } \
193 } while (0)
194
195 #define DEF_TEST(name, reporter) \
196 static void test_##name(skiatest::Reporter*, const GrContextOptions&); \
197 skiatest::TestRegistry name##TestRegistry( \
198 skiatest::Test(#name, /*gpu*/ false, /*graphite*/ false, test_##name)); \
199 void test_##name(skiatest::Reporter* reporter, const GrContextOptions&)
200
201 #define DEF_TEST_DISABLED(name, reporter) \
202 static void test_##name(skiatest::Reporter*, const GrContextOptions&); \
203 skiatest::TestRegistry name##TestRegistry( \
204 skiatest::Test(#name, /*gpu*/ false, /*graphite*/ false, test_##name)); \
205 void test_##name(skiatest::Reporter* reporter, const GrContextOptions&) { \
206 /* SkDebugf("Disabled:"#name "\n"); */ \
207 } \
208 void disabled_##name(skiatest::Reporter* reporter, const GrContextOptions&)
209
210 #ifdef SK_BUILD_FOR_UNIX
211 #define UNIX_ONLY_TEST DEF_TEST
212 #else
213 #define UNIX_ONLY_TEST DEF_TEST_DISABLED
214 #endif
215
216 #define DEF_GRAPHITE_TEST(name, reporter) \
217 static void test_##name(skiatest::Reporter*); \
218 static void test_graphite_##name(skiatest::Reporter* reporter, \
219 const GrContextOptions& /*unused*/) { \
220 test_##name(reporter); \
221 } \
222 skiatest::TestRegistry name##TestRegistry( \
223 skiatest::Test(#name, /*gpu*/ false, /*graphite*/ true, test_graphite_##name)); \
224 void test_##name(skiatest::Reporter* reporter)
225
226 #define DEF_GRAPHITE_TEST_FOR_CONTEXTS(name, reporter, graphite_context) \
227 static void test_##name(skiatest::Reporter*, skgpu::Context*); \
228 static void test_graphite_contexts_##name(skiatest::Reporter* _reporter, \
229 const GrContextOptions& /*unused*/) { \
230 skiatest::graphite::RunWithGraphiteTestContexts(test_##name, _reporter); \
231 } \
232 skiatest::TestRegistry name##TestRegistry( \
233 skiatest::Test(#name, /*gpu*/ false, /*graphite*/ true, \
234 test_graphite_contexts_##name)); \
235 void test_##name(skiatest::Reporter* reporter, skgpu::Context* graphite_context)
236
237 #define DEF_GPUTEST(name, reporter, options) \
238 static void test_##name(skiatest::Reporter*, const GrContextOptions&); \
239 skiatest::TestRegistry name##TestRegistry( \
240 skiatest::Test(#name, /*gpu*/ true, /*graphite*/ false, test_##name)); \
241 void test_##name(skiatest::Reporter* reporter, const GrContextOptions& options)
242
243 #define DEF_GPUTEST_FOR_CONTEXTS(name, context_filter, reporter, context_info, options_filter) \
244 static void test_##name(skiatest::Reporter*, const sk_gpu_test::ContextInfo&); \
245 static void test_gpu_contexts_##name(skiatest::Reporter* reporter, \
246 const GrContextOptions& options) { \
247 skiatest::RunWithGPUTestContexts(test_##name, context_filter, reporter, options); \
248 } \
249 skiatest::TestRegistry name##TestRegistry( \
250 skiatest::Test(#name, /*gpu*/ true, /*graphite*/ false, test_gpu_contexts_##name, options_filter)); \
251 void test_##name(skiatest::Reporter* reporter, const sk_gpu_test::ContextInfo& context_info)
252
253 #define DEF_GPUTEST_FOR_ALL_CONTEXTS(name, reporter, context_info) \
254 DEF_GPUTEST_FOR_CONTEXTS(name, nullptr, reporter, context_info, nullptr)
255
256 #define DEF_GPUTEST_FOR_RENDERING_CONTEXTS(name, reporter, context_info) \
257 DEF_GPUTEST_FOR_CONTEXTS(name, sk_gpu_test::GrContextFactory::IsRenderingContext, \
258 reporter, context_info, nullptr)
259 #define DEF_GPUTEST_FOR_ALL_GL_CONTEXTS(name, reporter, context_info) \
260 DEF_GPUTEST_FOR_CONTEXTS(name, &skiatest::IsGLContextType, \
261 reporter, context_info, nullptr)
262 #define DEF_GPUTEST_FOR_GL_RENDERING_CONTEXTS(name, reporter, context_info) \
263 DEF_GPUTEST_FOR_CONTEXTS(name, &skiatest::IsRenderingGLContextType, \
264 reporter, context_info, nullptr)
265 #define DEF_GPUTEST_FOR_MOCK_CONTEXT(name, reporter, context_info) \
266 DEF_GPUTEST_FOR_CONTEXTS(name, &skiatest::IsMockContextType, \
267 reporter, context_info, nullptr)
268 #define DEF_GPUTEST_FOR_VULKAN_CONTEXT(name, reporter, context_info) \
269 DEF_GPUTEST_FOR_CONTEXTS(name, &skiatest::IsVulkanContextType, \
270 reporter, context_info, nullptr)
271 #define DEF_GPUTEST_FOR_METAL_CONTEXT(name, reporter, context_info) \
272 DEF_GPUTEST_FOR_CONTEXTS(name, &skiatest::IsMetalContextType, \
273 reporter, context_info, nullptr)
274 #define DEF_GPUTEST_FOR_D3D_CONTEXT(name, reporter, context_info) \
275 DEF_GPUTEST_FOR_CONTEXTS(name, &skiatest::IsDirect3DContextType, \
276 reporter, context_info, nullptr)
277 #define DEF_GPUTEST_FOR_DAWN_CONTEXT(name, reporter, context_info) \
278 DEF_GPUTEST_FOR_CONTEXTS(name, &skiatest::IsDawnContextType, \
279 reporter, context_info, nullptr)
280
281 #define REQUIRE_PDF_DOCUMENT(TEST_NAME, REPORTER) \
282 do { \
283 SkNullWStream testStream; \
284 auto testDoc = SkPDF::MakeDocument(&testStream); \
285 if (!testDoc) { \
286 INFOF(REPORTER, "PDF disabled; %s test skipped.", #TEST_NAME); \
287 return; \
288 } \
289 } while (false)
290
291 #endif
292