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