|  | /* | 
|  | * Copyright 2011 Google Inc. | 
|  | * | 
|  | * Use of this source code is governed by a BSD-style license that can be | 
|  | * found in the LICENSE file. | 
|  | */ | 
|  | #ifndef skiatest_Test_DEFINED | 
|  | #define skiatest_Test_DEFINED | 
|  |  | 
|  | #include "include/core/SkString.h" | 
|  | #include "include/core/SkTypes.h" | 
|  | #include "src/core/SkClipOpPriv.h" | 
|  | #include "src/core/SkTraceEvent.h" | 
|  | #include "tools/Registry.h" | 
|  | #include "tools/gpu/GrContextFactory.h" | 
|  |  | 
|  | namespace skiatest { | 
|  |  | 
|  | SkString GetTmpDir(); | 
|  |  | 
|  | struct Failure { | 
|  | Failure(const char* f, int l, const char* c, const SkString& m) | 
|  | : fileName(f), lineNo(l), condition(c), message(m) {} | 
|  | const char* fileName; | 
|  | int lineNo; | 
|  | const char* condition; | 
|  | SkString message; | 
|  | SkString toString() const; | 
|  | }; | 
|  |  | 
|  | class Reporter : SkNoncopyable { | 
|  | public: | 
|  | virtual ~Reporter() {} | 
|  | virtual void bumpTestCount(); | 
|  | virtual void reportFailed(const skiatest::Failure&) = 0; | 
|  | virtual bool allowExtendedTest() const; | 
|  | virtual bool verbose() const; | 
|  | virtual void* stats() const { return nullptr; } | 
|  |  | 
|  | void reportFailedWithContext(const skiatest::Failure&); | 
|  |  | 
|  | void push(const SkString& message) { | 
|  | fContextStack.push_back(message); | 
|  | } | 
|  | void pop() { | 
|  | fContextStack.pop_back(); | 
|  | } | 
|  |  | 
|  | private: | 
|  | SkTArray<SkString> fContextStack; | 
|  | }; | 
|  |  | 
|  | #define REPORT_FAILURE(reporter, cond, message) \ | 
|  | reporter->reportFailedWithContext(skiatest::Failure(__FILE__, __LINE__, cond, message)) | 
|  |  | 
|  | class ReporterContext : SkNoncopyable { | 
|  | public: | 
|  | ReporterContext(Reporter* reporter, const SkString& message) : fReporter(reporter) { | 
|  | fReporter->push(message); | 
|  | } | 
|  | ~ReporterContext() { | 
|  | fReporter->pop(); | 
|  | } | 
|  |  | 
|  | private: | 
|  | Reporter* fReporter; | 
|  | }; | 
|  |  | 
|  | typedef void (*TestProc)(skiatest::Reporter*, const GrContextOptions&); | 
|  | typedef void (*ContextOptionsProc)(GrContextOptions*); | 
|  |  | 
|  | struct Test { | 
|  | Test(const char* n, bool g, TestProc p, ContextOptionsProc optionsProc = nullptr) | 
|  | : name(n), needsGpu(g), proc(p), fContextOptionsProc(optionsProc) {} | 
|  | const char* name; | 
|  | bool needsGpu; | 
|  | TestProc proc; | 
|  | ContextOptionsProc fContextOptionsProc; | 
|  |  | 
|  | void modifyGrContextOptions(GrContextOptions* options) { | 
|  | if (fContextOptionsProc) { | 
|  | (*fContextOptionsProc)(options); | 
|  | } | 
|  | } | 
|  |  | 
|  | void run(skiatest::Reporter* r, const GrContextOptions& options) const { | 
|  | TRACE_EVENT1("test", TRACE_FUNC, "name", this->name/*these are static*/); | 
|  | this->proc(r, options); | 
|  | } | 
|  | }; | 
|  |  | 
|  | typedef sk_tools::Registry<Test> TestRegistry; | 
|  |  | 
|  | /* | 
|  | Use the following macros to make use of the skiatest classes, e.g. | 
|  |  | 
|  | #include "tests/Test.h" | 
|  |  | 
|  | DEF_TEST(TestName, reporter) { | 
|  | ... | 
|  | REPORTER_ASSERT(reporter, x == 15); | 
|  | ... | 
|  | REPORTER_ASSERT(reporter, x == 15, "x should be 15"); | 
|  | ... | 
|  | if (x != 15) { | 
|  | ERRORF(reporter, "x should be 15, but is %d", x); | 
|  | return; | 
|  | } | 
|  | ... | 
|  | } | 
|  | */ | 
|  |  | 
|  | using GrContextFactoryContextType = sk_gpu_test::GrContextFactory::ContextType; | 
|  |  | 
|  | typedef void GrContextTestFn(Reporter*, const sk_gpu_test::ContextInfo&); | 
|  | typedef bool GrContextTypeFilterFn(GrContextFactoryContextType); | 
|  |  | 
|  | extern bool IsGLContextType(GrContextFactoryContextType); | 
|  | extern bool IsVulkanContextType(GrContextFactoryContextType); | 
|  | extern bool IsMetalContextType(GrContextFactoryContextType); | 
|  | extern bool IsDawnContextType(GrContextFactoryContextType); | 
|  | extern bool IsDirect3DContextType(GrContextFactoryContextType); | 
|  | extern bool IsRenderingGLContextType(GrContextFactoryContextType); | 
|  | extern bool IsRenderingGLOrMetalContextType(GrContextFactoryContextType); | 
|  | extern bool IsMockContextType(GrContextFactoryContextType); | 
|  | void RunWithGPUTestContexts(GrContextTestFn*, GrContextTypeFilterFn*, Reporter*, | 
|  | const GrContextOptions&); | 
|  |  | 
|  | /** Timer provides wall-clock duration since its creation. */ | 
|  | class Timer { | 
|  | public: | 
|  | /** Starts the timer. */ | 
|  | Timer(); | 
|  |  | 
|  | /** Nanoseconds since creation. */ | 
|  | double elapsedNs() const; | 
|  |  | 
|  | /** Milliseconds since creation. */ | 
|  | double elapsedMs() const; | 
|  |  | 
|  | /** Milliseconds since creation as an integer. | 
|  | Behavior is undefined for durations longer than SK_MSecMax. | 
|  | */ | 
|  | SkMSec elapsedMsInt() const; | 
|  | private: | 
|  | double fStartNanos; | 
|  | }; | 
|  |  | 
|  | }  // namespace skiatest | 
|  |  | 
|  | static inline SkString reporter_string() { return {}; } | 
|  | /// Prevent security warnings when using a non-literal string i.e. not a format string. | 
|  | static inline SkString reporter_string(const char* s) { return SkString(s); } | 
|  | template<typename... Args> | 
|  | static inline SkString reporter_string(const char* fmt, Args... args)  { | 
|  | return SkStringPrintf(fmt, std::forward<Args>(args)...); | 
|  | } | 
|  |  | 
|  | #define REPORTER_ASSERT(r, cond, ...)                               \ | 
|  | do {                                                            \ | 
|  | if (!(cond)) {                                              \ | 
|  | REPORT_FAILURE(r, #cond, reporter_string(__VA_ARGS__)); \ | 
|  | }                                                           \ | 
|  | } while (0) | 
|  |  | 
|  | #define ERRORF(r, ...)                                       \ | 
|  | do {                                                     \ | 
|  | REPORT_FAILURE(r, "", reporter_string(__VA_ARGS__)); \ | 
|  | } while (0) | 
|  |  | 
|  | #define INFOF(REPORTER, ...)         \ | 
|  | do {                             \ | 
|  | if ((REPORTER)->verbose()) { \ | 
|  | SkDebugf(__VA_ARGS__);   \ | 
|  | }                            \ | 
|  | } while (0) | 
|  |  | 
|  | #define DEF_TEST(name, reporter)                                                          \ | 
|  | static void test_##name(skiatest::Reporter*, const GrContextOptions&);                \ | 
|  | skiatest::TestRegistry name##TestRegistry(skiatest::Test(#name, false, test_##name)); \ | 
|  | void test_##name(skiatest::Reporter* reporter, const GrContextOptions&) | 
|  |  | 
|  | #define DEF_GPUTEST(name, reporter, options)                                             \ | 
|  | static void test_##name(skiatest::Reporter*, const GrContextOptions&);               \ | 
|  | skiatest::TestRegistry name##TestRegistry(skiatest::Test(#name, true, test_##name)); \ | 
|  | void test_##name(skiatest::Reporter* reporter, const GrContextOptions& options) | 
|  |  | 
|  | #define DEF_GPUTEST_FOR_CONTEXTS(name, context_filter, reporter, context_info, options_filter)  \ | 
|  | static void test_##name(skiatest::Reporter*, const sk_gpu_test::ContextInfo& context_info); \ | 
|  | static void test_gpu_contexts_##name(skiatest::Reporter* reporter,                          \ | 
|  | const GrContextOptions& options) {                     \ | 
|  | skiatest::RunWithGPUTestContexts(test_##name, context_filter, reporter, options);       \ | 
|  | }                                                                                           \ | 
|  | skiatest::TestRegistry name##TestRegistry(                                                  \ | 
|  | skiatest::Test(#name, true, test_gpu_contexts_##name, options_filter));             \ | 
|  | void test_##name(skiatest::Reporter* reporter, const sk_gpu_test::ContextInfo& context_info) | 
|  |  | 
|  | #define DEF_GPUTEST_FOR_ALL_CONTEXTS(name, reporter, context_info)                          \ | 
|  | DEF_GPUTEST_FOR_CONTEXTS(name, nullptr, reporter, context_info, nullptr) | 
|  |  | 
|  | #define DEF_GPUTEST_FOR_RENDERING_CONTEXTS(name, reporter, context_info)                    \ | 
|  | DEF_GPUTEST_FOR_CONTEXTS(name, sk_gpu_test::GrContextFactory::IsRenderingContext,   \ | 
|  | reporter, context_info, nullptr) | 
|  | #define DEF_GPUTEST_FOR_ALL_GL_CONTEXTS(name, reporter, context_info)                       \ | 
|  | DEF_GPUTEST_FOR_CONTEXTS(name, &skiatest::IsGLContextType,                          \ | 
|  | reporter, context_info, nullptr) | 
|  | #define DEF_GPUTEST_FOR_GL_RENDERING_CONTEXTS(name, reporter, context_info)                 \ | 
|  | DEF_GPUTEST_FOR_CONTEXTS(name, &skiatest::IsRenderingGLContextType,                 \ | 
|  | reporter, context_info, nullptr) | 
|  | #define DEF_GPUTEST_FOR_MOCK_CONTEXT(name, reporter, context_info)                          \ | 
|  | DEF_GPUTEST_FOR_CONTEXTS(name, &skiatest::IsMockContextType,                        \ | 
|  | reporter, context_info, nullptr) | 
|  | #define DEF_GPUTEST_FOR_VULKAN_CONTEXT(name, reporter, context_info)                        \ | 
|  | DEF_GPUTEST_FOR_CONTEXTS(name, &skiatest::IsVulkanContextType,                      \ | 
|  | reporter, context_info, nullptr) | 
|  | #define DEF_GPUTEST_FOR_METAL_CONTEXT(name, reporter, context_info)                         \ | 
|  | DEF_GPUTEST_FOR_CONTEXTS(name, &skiatest::IsMetalContextType,                       \ | 
|  | reporter, context_info, nullptr) | 
|  | #define DEF_GPUTEST_FOR_D3D_CONTEXT(name, reporter, context_info)                           \ | 
|  | DEF_GPUTEST_FOR_CONTEXTS(name, &skiatest::IsDirect3DContextType,                        \ | 
|  | reporter, context_info, nullptr) | 
|  | #define DEF_GPUTEST_FOR_DAWN_CONTEXT(name, reporter, context_info)                          \ | 
|  | DEF_GPUTEST_FOR_CONTEXTS(name, &skiatest::IsDawnContextType,                            \ | 
|  | reporter, context_info, nullptr) | 
|  |  | 
|  | #define REQUIRE_PDF_DOCUMENT(TEST_NAME, REPORTER)                          \ | 
|  | do {                                                                   \ | 
|  | SkNullWStream testStream;                                          \ | 
|  | auto testDoc = SkPDF::MakeDocument(&testStream);                   \ | 
|  | if (!testDoc) {                                                    \ | 
|  | INFOF(REPORTER, "PDF disabled; %s test skipped.", #TEST_NAME); \ | 
|  | return;                                                        \ | 
|  | }                                                                  \ | 
|  | } while (false) | 
|  |  | 
|  | #endif |