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 "SkJSONCPP.h"
     15 #include "SkOSFile.h"
     16 #include "SkRefCnt.h"
     17 #include "SkStream.h"
     18 #include "SkTArray.h"
     19 
     20 
     21 namespace skiagm {
     22 
     23     void gm_fprintf(FILE *stream, const char format[], ...);
     24 
     25     Json::Value CreateJsonTree(Json::Value expectedResults,
     26                                Json::Value actualResultsFailed,
     27                                Json::Value actualResultsFailureIgnored,
     28                                Json::Value actualResultsNoComparison,
     29                                Json::Value actualResultsSucceeded);
     30 
     31     /**
     32      * The digest of a GM test result.
     33      *
     34      * Currently, this is always a uint64_t hash digest of an SkBitmap...
     35      * but we will add other flavors soon.
     36      */
     37     class GmResultDigest {
     38     public:
     39         /**
     40          * Create a ResultDigest representing an actual image result.
     41          */
     42         explicit GmResultDigest(const SkBitmap &bitmap);
     43 
     44         /**
     45          * Create a ResultDigest representing an allowed result
     46          * checksum within JSON expectations file, in the form
     47          * ["bitmap-64bitMD5", 12345].
     48          */
     49         explicit GmResultDigest(const Json::Value &jsonTypeValuePair);
     50 
     51         /**
     52          * Returns true if this GmResultDigest was fully and successfully
     53          * created.
     54          */
     55         bool isValid() const;
     56 
     57         /**
     58          * Returns true if this and other GmResultDigest could
     59          * represent identical results.
     60          */
     61         bool equals(const GmResultDigest &other) const;
     62 
     63         /**
     64          * Returns a JSON type/value pair representing this result,
     65          * such as ["bitmap-64bitMD5", 12345].
     66          */
     67         Json::Value asJsonTypeValuePair() const;
     68 
     69         /**
     70          * Returns the hashtype, such as "bitmap-64bitMD5", as an SkString.
     71          */
     72         SkString getHashType() const;
     73 
     74         /**
     75          * Returns the hash digest value, such as "12345", as an SkString.
     76          */
     77         SkString getDigestValue() const;
     78 
     79     private:
     80         bool fIsValid; // always check this first--if it's false, other fields are meaningless
     81         uint64_t fHashDigest;
     82     };
     83 
     84     /**
     85      * Encapsulates an SkBitmap and its GmResultDigest, guaranteed to keep them in sync.
     86      */
     87     class BitmapAndDigest {
     88     public:
     89         explicit BitmapAndDigest(const SkBitmap &bitmap) : fBitmap(bitmap), fDigest(bitmap) {}
     90 
     91         const SkBitmap fBitmap;
     92         const GmResultDigest fDigest;
     93     };
     94 
     95     /**
     96      * Test expectations (allowed image results, etc.)
     97      */
     98     class Expectations {
     99     public:
    100         /**
    101          * No expectations at all.
    102          */
    103         explicit Expectations(bool ignoreFailure=kDefaultIgnoreFailure);
    104 
    105         /**
    106          * Expect exactly one image (appropriate for the case when we
    107          * are comparing against a single PNG file).
    108          */
    109         explicit Expectations(const SkBitmap& bitmap, bool ignoreFailure=kDefaultIgnoreFailure);
    110 
    111         /**
    112          * Expect exactly one image, whose digest has already been computed.
    113          */
    114         explicit Expectations(const BitmapAndDigest& bitmapAndDigest);
    115 
    116         /**
    117          * Create Expectations from a JSON element as found within the
    118          * kJsonKey_ExpectedResults section.
    119          *
    120          * It's fine if the jsonElement is null or empty; in that case, we just
    121          * don't have any expectations.
    122          */
    123         explicit Expectations(Json::Value jsonElement);
    124 
    125         /**
    126          * Returns true iff we want to ignore failed expectations.
    127          */
    128         bool ignoreFailure() const { return this->fIgnoreFailure; }
    129 
    130         /**
    131          * Override default setting of fIgnoreFailure.
    132          */
    133         void setIgnoreFailure(bool val) { this->fIgnoreFailure = val; }
    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) const = 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         explicit IndividualImageExpectationsSource(const char *rootDir) : fRootDir(rootDir) {}
    196 
    197         Expectations get(const char *testName) const 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         explicit JsonExpectationsSource(const char *jsonPath);
    215 
    216         Expectations get(const char *testName) const 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