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