Home | History | Annotate | Download | only in tools
      1 /*
      2  * Copyright 2014 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 
      8 #ifndef image_expectations_DEFINED
      9 #define image_expectations_DEFINED
     10 
     11 #include "SkBitmap.h"
     12 #include "SkJSONCPP.h"
     13 #include "SkOSFile.h"
     14 
     15 namespace sk_tools {
     16 
     17     /**
     18      * The digest of an image (either an image we have generated locally, or an image expectation).
     19      *
     20      * Currently, this is always a uint64_t hash digest of an SkBitmap.
     21      */
     22     class ImageDigest {
     23     public:
     24         /**
     25          * Create an ImageDigest of a bitmap.
     26          *
     27          * Computes the hash of the bitmap lazily, since that is an expensive operation.
     28          *
     29          * @param bitmap image to get the digest of
     30          */
     31         explicit ImageDigest(const SkBitmap &bitmap);
     32 
     33         /**
     34          * Create an ImageDigest using a hashType/hashValue pair.
     35          *
     36          * @param hashType the algorithm used to generate the hash; for now, only
     37          *     kJsonValue_Image_ChecksumAlgorithm_Bitmap64bitMD5 is allowed.
     38          * @param hashValue the value generated by the hash algorithm for a particular image.
     39          */
     40         explicit ImageDigest(const SkString &hashType, uint64_t hashValue);
     41 
     42         /**
     43          * Returns true iff this and other ImageDigest represent identical images.
     44          */
     45         bool equals(ImageDigest &other);
     46 
     47         /**
     48          * Returns the hash digest type as an SkString.
     49          *
     50          * For now, this always returns kJsonValue_Image_ChecksumAlgorithm_Bitmap64bitMD5 .
     51          */
     52         SkString getHashType();
     53 
     54         /**
     55          * Returns the hash digest value as a uint64_t.
     56          *
     57          * Since the hash is computed lazily, this may take some time, and it may modify
     58          * some fields on this object.
     59          */
     60         uint64_t getHashValue();
     61 
     62     private:
     63         const SkBitmap fBitmap;
     64         uint64_t fHashValue;
     65         bool fComputedHashValue;
     66     };
     67 
     68     /**
     69      * Container that holds a reference to an SkBitmap and its ImageDigest.
     70      */
     71     class BitmapAndDigest {
     72     public:
     73         explicit BitmapAndDigest(const SkBitmap &bitmap);
     74 
     75         const SkBitmap *getBitmapPtr() const;
     76 
     77         /**
     78          * Returns a pointer to the ImageDigest.
     79          *
     80          * Since the hash is computed lazily within the ImageDigest object, we cannot mandate
     81          * that it be held const.
     82          */
     83         ImageDigest *getImageDigestPtr();
     84     private:
     85         const SkBitmap fBitmap;
     86         ImageDigest fImageDigest;
     87     };
     88 
     89     /**
     90      * Expected test result: expected image (if any), and whether we want to ignore failures on
     91      * this test or not.
     92      *
     93      * This is just an ImageDigest (or lack thereof, if there is no expectation) and a boolean
     94      * telling us whether to ignore failures.
     95      */
     96     class Expectation {
     97     public:
     98         /**
     99          * No expectation at all.
    100          */
    101         explicit Expectation(bool ignoreFailure=kDefaultIgnoreFailure);
    102 
    103         /**
    104          * Expect an image, passed as hashType/hashValue.
    105          */
    106         explicit Expectation(const SkString &hashType, uint64_t hashValue,
    107                              bool ignoreFailure=kDefaultIgnoreFailure);
    108 
    109         /**
    110          * Expect an image, passed as a bitmap.
    111          */
    112         explicit Expectation(const SkBitmap& bitmap,
    113                              bool ignoreFailure=kDefaultIgnoreFailure);
    114 
    115         /**
    116          * Returns true iff we want to ignore failed expectations.
    117          */
    118         bool ignoreFailure() const;
    119 
    120         /**
    121          * Returns true iff there are no allowed results.
    122          */
    123         bool empty() const;
    124 
    125         /**
    126          * Returns true iff we are expecting a particular image, and imageDigest matches it.
    127          *
    128          * If empty() returns true, this will return false.
    129          *
    130          * If this expectation DOES contain an image, and imageDigest doesn't match it,
    131          * this method will return false regardless of what ignoreFailure() would return.
    132          * (The caller can check that separately.)
    133          */
    134         bool matches(ImageDigest &imageDigest);
    135 
    136     private:
    137         static const bool kDefaultIgnoreFailure = false;
    138 
    139         const bool fIsEmpty;
    140         const bool fIgnoreFailure;
    141         ImageDigest fImageDigest;  // cannot be const, because it computes its hash lazily
    142     };
    143 
    144     /**
    145      * Collects ImageDigests of actually rendered images, perhaps comparing to expectations.
    146      */
    147     class ImageResultsAndExpectations {
    148     public:
    149         /**
    150          * Adds expectations from a JSON file, returning true if successful.
    151          *
    152          * If the file exists but is empty, it succeeds, and there will be no expectations.
    153          * If the file does not exist, this will fail.
    154          *
    155          * Reasoning:
    156          * Generating expectations the first time can be a tricky chicken-and-egg
    157          * proposition.  "I need actual results to turn into expectations... but the only
    158          * way to get actual results is to run the tool, and the tool won't run without
    159          * expectations!"
    160          * We could make the tool run even if there is no expectations file at all, but it's
    161          * better for the tool to fail if the expectations file is not found--that will tell us
    162          * quickly if files are not being copied around as they should be.
    163          * Creating an empty file is an easy way to break the chicken-and-egg cycle and generate
    164          * the first real expectations.
    165          */
    166         bool readExpectationsFile(const char *jsonPath);
    167 
    168         /**
    169          * Adds this image to the summary of results.
    170          *
    171          * @param sourceName name of the source file that generated this result
    172          * @param fileName relative path to the image output file on local disk
    173          * @param digest description of the image's contents
    174          * @param tileNumber if not NULL, pointer to tile number
    175          */
    176         void add(const char *sourceName, const char *fileName, ImageDigest &digest,
    177                  const int *tileNumber=NULL);
    178 
    179         /**
    180          * Adds a key/value pair to the descriptions dict within the summary of results.
    181          *
    182          * @param key key within the descriptions dict
    183          * @param value value to associate with that key
    184          */
    185         void addDescription(const char *key, const char *value);
    186 
    187         /**
    188          * Adds the image base Google Storage URL to the summary of results.
    189          *
    190          * @param imageBaseGSUrl the image base Google Storage URL
    191          */
    192         void setImageBaseGSUrl(const char *imageBaseGSUrl);
    193 
    194         /**
    195          * Returns the Expectation for this test.
    196          *
    197          * @param sourceName name of the source file that generated this result
    198          * @param tileNumber if not NULL, pointer to tile number
    199          *
    200          * TODO(stephana): To make this work for GMs, we will need to add parameters for
    201          * config, and maybe renderMode/builder?
    202          */
    203         Expectation getExpectation(const char *sourceName, const int *tileNumber=NULL);
    204 
    205         /**
    206          * Writes the summary (as constructed so far) to a file.
    207          *
    208          * @param filename path to write the summary to
    209          */
    210         void writeToFile(const char *filename) const;
    211 
    212     private:
    213 
    214         /**
    215          * Read the file contents from filePtr and parse them into jsonRoot.
    216          *
    217          * It is up to the caller to close filePtr after this is done.
    218          *
    219          * Returns true if successful.
    220          */
    221         static bool Parse(SkFILE* filePtr, Json::Value *jsonRoot);
    222 
    223         Json::Value fActualResults;
    224         Json::Value fDescriptions;
    225         Json::Value fExpectedJsonRoot;
    226         Json::Value fExpectedResults;
    227         Json::Value fImageBaseGSUrl;
    228     };
    229 
    230 } // namespace sk_tools
    231 
    232 #endif  // image_expectations_DEFINED
    233