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