Home | History | Annotate | Download | only in gm
      1 /*
      2  * Copyright 2013 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 gm_expectations_DEFINED
      8 #define gm_expectations_DEFINED
      9 
     10 #include "gm.h"
     11 #include "SkBitmap.h"
     12 #include "SkBitmapHasher.h"
     13 #include "SkData.h"
     14 #include "SkOSFile.h"
     15 #include "SkRefCnt.h"
     16 #include "SkStream.h"
     17 #include "SkTArray.h"
     18 
     19 #ifdef SK_BUILD_FOR_WIN
     20     // json includes xlocale which generates warning 4530 because we're compiling without
     21     // exceptions; see https://code.google.com/p/skia/issues/detail?id=1067
     22     #pragma warning(push)
     23     #pragma warning(disable : 4530)
     24 #endif
     25 #include "json/reader.h"
     26 #include "json/value.h"
     27 #ifdef SK_BUILD_FOR_WIN
     28     #pragma warning(pop)
     29 #endif
     30 
     31 namespace skiagm {
     32 
     33     void gm_fprintf(FILE *stream, const char format[], ...);
     34 
     35     Json::Value CreateJsonTree(Json::Value expectedResults,
     36                                Json::Value actualResultsFailed,
     37                                Json::Value actualResultsFailureIgnored,
     38                                Json::Value actualResultsNoComparison,
     39                                Json::Value actualResultsSucceeded);
     40 
     41     /**
     42      * The digest of a GM test result.
     43      *
     44      * Currently, this is always a uint64_t hash digest of an SkBitmap...
     45      * but we will add other flavors soon.
     46      */
     47     class GmResultDigest {
     48     public:
     49         /**
     50          * Create a ResultDigest representing an actual image result.
     51          */
     52         GmResultDigest(const SkBitmap &bitmap);
     53 
     54         /**
     55          * Create a ResultDigest representing an allowed result
     56          * checksum within JSON expectations file, in the form
     57          * ["bitmap-64bitMD5", 12345].
     58          */
     59         GmResultDigest(const Json::Value &jsonTypeValuePair);
     60 
     61         /**
     62          * Returns true if this GmResultDigest was fully and successfully
     63          * created.
     64          */
     65         bool isValid() const;
     66 
     67         /**
     68          * Returns true if this and other GmResultDigest could
     69          * represent identical results.
     70          */
     71         bool equals(const GmResultDigest &other) const;
     72 
     73         /**
     74          * Returns a JSON type/value pair representing this result,
     75          * such as ["bitmap-64bitMD5", 12345].
     76          */
     77         Json::Value asJsonTypeValuePair() const;
     78 
     79         /**
     80          * Returns the hashtype, such as "bitmap-64bitMD5", as an SkString.
     81          */
     82         SkString getHashType() const;
     83 
     84         /**
     85          * Returns the hash digest value, such as "12345", as an SkString.
     86          */
     87         SkString getDigestValue() const;
     88 
     89     private:
     90         bool fIsValid; // always check this first--if it's false, other fields are meaningless
     91         uint64_t fHashDigest;
     92     };
     93 
     94     /**
     95      * Encapsulates an SkBitmap and its GmResultDigest, guaranteed to keep them in sync.
     96      */
     97     class BitmapAndDigest {
     98     public:
     99         BitmapAndDigest(const SkBitmap &bitmap) : fBitmap(bitmap), fDigest(bitmap) {}
    100 
    101         const SkBitmap fBitmap;
    102         const GmResultDigest fDigest;
    103     };
    104 
    105     /**
    106      * Test expectations (allowed image results, etc.)
    107      */
    108     class Expectations {
    109     public:
    110         /**
    111          * No expectations at all.
    112          */
    113         Expectations(bool ignoreFailure=kDefaultIgnoreFailure);
    114 
    115         /**
    116          * Expect exactly one image (appropriate for the case when we
    117          * are comparing against a single PNG file).
    118          */
    119         Expectations(const SkBitmap& bitmap, bool ignoreFailure=kDefaultIgnoreFailure);
    120 
    121         /**
    122          * Create Expectations from a JSON element as found within the
    123          * kJsonKey_ExpectedResults section.
    124          *
    125          * It's fine if the jsonElement is null or empty; in that case, we just
    126          * don't have any expectations.
    127          */
    128         Expectations(Json::Value jsonElement);
    129 
    130         /**
    131          * Returns true iff we want to ignore failed expectations.
    132          */
    133         bool ignoreFailure() const { return this->fIgnoreFailure; }
    134 
    135         /**
    136          * Returns true iff there are no allowed results.
    137          */
    138         bool empty() const { return this->fAllowedResultDigests.empty(); }
    139 
    140         /**
    141          * Returns true iff resultDigest matches any allowed result,
    142          * regardless of fIgnoreFailure.  (The caller can check
    143          * that separately.)
    144          */
    145         bool match(GmResultDigest resultDigest) const;
    146 
    147         /**
    148          * If this Expectation is based on a single SkBitmap, return a
    149          * pointer to that SkBitmap. Otherwise (if the Expectation is
    150          * empty, or if it was based on a list of checksums rather
    151          * than a single bitmap), returns NULL.
    152          */
    153         const SkBitmap *asBitmap() const {
    154             return (SkBitmap::kNo_Config == fBitmap.config()) ? NULL : &fBitmap;
    155         }
    156 
    157         /**
    158          * Return a JSON representation of the expectations.
    159          */
    160         Json::Value asJsonValue() const;
    161 
    162     private:
    163         const static bool kDefaultIgnoreFailure = false;
    164 
    165         SkTArray<GmResultDigest> fAllowedResultDigests;
    166         bool fIgnoreFailure;
    167         SkBitmap fBitmap;
    168     };
    169 
    170     /**
    171      * Abstract source of Expectations objects for individual tests.
    172      */
    173     class ExpectationsSource : public SkRefCnt {
    174     public:
    175         SK_DECLARE_INST_COUNT(ExpectationsSource)
    176 
    177         virtual Expectations get(const char *testName) = 0;
    178 
    179     private:
    180         typedef SkRefCnt INHERITED;
    181     };
    182 
    183     /**
    184      * Return Expectations based on individual image files on disk.
    185      */
    186     class IndividualImageExpectationsSource : public ExpectationsSource {
    187     public:
    188         /**
    189          * Create an ExpectationsSource that will return Expectations based on
    190          * image files found within rootDir.
    191          *
    192          * rootDir: directory under which to look for image files
    193          *          (this string will be copied to storage within this object)
    194          */
    195         IndividualImageExpectationsSource(const char *rootDir) : fRootDir(rootDir) {}
    196 
    197         Expectations get(const char *testName) SK_OVERRIDE ;
    198 
    199     private:
    200         const SkString fRootDir;
    201     };
    202 
    203     /**
    204      * Return Expectations based on JSON summary file.
    205      */
    206     class JsonExpectationsSource : public ExpectationsSource {
    207     public:
    208         /**
    209          * Create an ExpectationsSource that will return Expectations based on
    210          * a JSON file.
    211          *
    212          * jsonPath: path to JSON file to read
    213          */
    214         JsonExpectationsSource(const char *jsonPath);
    215 
    216         Expectations get(const char *testName) SK_OVERRIDE;
    217 
    218     private:
    219 
    220         /**
    221          * Read as many bytes as possible (up to maxBytes) from the stream into
    222          * an SkData object.
    223          *
    224          * If the returned SkData contains fewer than maxBytes, then EOF has been
    225          * reached and no more data would be available from subsequent calls.
    226          * (If EOF has already been reached, then this call will return an empty
    227          * SkData object immediately.)
    228          *
    229          * If there are fewer than maxBytes bytes available to read from the
    230          * stream, but the stream has not been closed yet, this call will block
    231          * until there are enough bytes to read or the stream has been closed.
    232          *
    233          * It is up to the caller to call unref() on the returned SkData object
    234          * once the data is no longer needed, so that the underlying buffer will
    235          * be freed.  For example:
    236          *
    237          * {
    238          *   size_t maxBytes = 256;
    239          *   SkAutoDataUnref dataRef(readIntoSkData(stream, maxBytes));
    240          *   if (NULL != dataRef.get()) {
    241          *     size_t bytesActuallyRead = dataRef.get()->size();
    242          *     // use the data...
    243          *   }
    244          * }
    245          * // underlying buffer has been freed, thanks to auto unref
    246          *
    247          */
    248         // TODO(epoger): Move this, into SkStream.[cpp|h] as attempted in
    249         // https://codereview.appspot.com/7300071 ?
    250         // And maybe ReadFileIntoSkData() also?
    251         static SkData* ReadIntoSkData(SkStream &stream, size_t maxBytes);
    252 
    253         /**
    254          * Wrapper around ReadIntoSkData for files: reads the entire file into
    255          * an SkData object.
    256          */
    257         static SkData* ReadFileIntoSkData(SkFILEStream &stream) {
    258             return ReadIntoSkData(stream, stream.getLength());
    259         }
    260 
    261         /**
    262          * Read the file contents from jsonPath and parse them into jsonRoot.
    263          *
    264          * Returns true if successful.
    265          */
    266         static bool Parse(const char *jsonPath, Json::Value *jsonRoot);
    267 
    268         Json::Value fJsonRoot;
    269         Json::Value fJsonExpectedResults;
    270     };
    271 
    272 }
    273 #endif
    274