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