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