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