Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(222)

Side by Side Diff: gm/gm_expectations.h

Issue 14284018: GM: specify that currently used checksums are CityHashes of SkBitmaps (Closed) Base URL: http://skia.googlecode.com/svn/trunk/
Patch Set: fix_mac_trybot Created 7 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | gm/gm_expectations.cpp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* 1 /*
2 * Copyright 2013 Google Inc. 2 * Copyright 2013 Google Inc.
3 * 3 *
4 * Use of this source code is governed by a BSD-style license that can be 4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file. 5 * found in the LICENSE file.
6 */ 6 */
7 #ifndef gm_expectations_DEFINED 7 #ifndef gm_expectations_DEFINED
8 #define gm_expectations_DEFINED 8 #define gm_expectations_DEFINED
9 9
10 #include <stdarg.h>
11 #include "gm.h" 10 #include "gm.h"
12 #include "SkBitmap.h" 11 #include "SkBitmap.h"
13 #include "SkBitmapHasher.h" 12 #include "SkBitmapHasher.h"
14 #include "SkData.h" 13 #include "SkData.h"
15 #include "SkImageDecoder.h"
16 #include "SkOSFile.h" 14 #include "SkOSFile.h"
17 #include "SkRefCnt.h" 15 #include "SkRefCnt.h"
18 #include "SkStream.h" 16 #include "SkStream.h"
19 #include "SkTArray.h" 17 #include "SkTArray.h"
20 18
21 #ifdef SK_BUILD_FOR_WIN 19 #ifdef SK_BUILD_FOR_WIN
22 // json includes xlocale which generates warning 4530 because we're compilin g without 20 // json includes xlocale which generates warning 4530 because we're compilin g without
23 // exceptions; see https://code.google.com/p/skia/issues/detail?id=1067 21 // exceptions; see https://code.google.com/p/skia/issues/detail?id=1067
24 #pragma warning(push) 22 #pragma warning(push)
25 #pragma warning(disable : 4530) 23 #pragma warning(disable : 4530)
26 #endif 24 #endif
27 #include "json/reader.h" 25 #include "json/reader.h"
28 #include "json/value.h" 26 #include "json/value.h"
29 #ifdef SK_BUILD_FOR_WIN 27 #ifdef SK_BUILD_FOR_WIN
30 #pragma warning(pop) 28 #pragma warning(pop)
31 #endif 29 #endif
32 30
33 #define DEBUGFAIL_SEE_STDERR SkDEBUGFAIL("see stderr for message")
34
35 const static char kJsonKey_ActualResults[] = "actual-results";
36 const static char kJsonKey_ActualResults_Failed[] = "failed";
37 const static char kJsonKey_ActualResults_FailureIgnored[]= "failure-ignored";
38 const static char kJsonKey_ActualResults_NoComparison[] = "no-comparison";
39 const static char kJsonKey_ActualResults_Succeeded[] = "succeeded";
40 const static char kJsonKey_ActualResults_AnyStatus_Checksum[] = "checksum";
41
42 const static char kJsonKey_ExpectedResults[] = "expected-results";
43 const static char kJsonKey_ExpectedResults_Checksums[] = "checksums";
44 const static char kJsonKey_ExpectedResults_IgnoreFailure[] = "ignore-failure";
45
46 namespace skiagm { 31 namespace skiagm {
47 32
48 // The actual type we use to represent a checksum is hidden in here. 33 // The actual type we use to represent a checksum is hidden in here.
49 typedef Json::UInt64 Checksum; 34 typedef Json::UInt64 Checksum;
50 static inline Json::Value asJsonValue(Checksum checksum) { 35 static inline Json::Value asJsonValue(Checksum checksum) {
51 return checksum; 36 return checksum;
52 } 37 }
53 static inline Checksum asChecksum(Json::Value jsonValue) { 38 static inline Checksum asChecksum(Json::Value jsonValue) {
54 return jsonValue.asUInt64(); 39 return jsonValue.asUInt64();
55 } 40 }
(...skipping 12 matching lines...) Expand all
68 const char suffix[]) { 53 const char suffix[]) {
69 SkString filename(path); 54 SkString filename(path);
70 if (filename.endsWith(SkPATH_SEPARATOR)) { 55 if (filename.endsWith(SkPATH_SEPARATOR)) {
71 filename.remove(filename.size() - 1, 1); 56 filename.remove(filename.size() - 1, 1);
72 } 57 }
73 filename.appendf("%c%s%s.%s", SkPATH_SEPARATOR, 58 filename.appendf("%c%s%s.%s", SkPATH_SEPARATOR,
74 name, renderModeDescriptor, suffix); 59 name, renderModeDescriptor, suffix);
75 return filename; 60 return filename;
76 } 61 }
77 62
63 Json::Value ActualResultAsJsonValue(const SkHashDigest& result);
64
65 Json::Value CreateJsonTree(Json::Value expectedResults,
66 Json::Value actualResultsFailed,
67 Json::Value actualResultsFailureIgnored,
68 Json::Value actualResultsNoComparison,
69 Json::Value actualResultsSucceeded);
70
78 /** 71 /**
79 * Test expectations (allowed image checksums, etc.) 72 * Test expectations (allowed image checksums, etc.)
80 */ 73 */
81 class Expectations { 74 class Expectations {
82 public: 75 public:
83 /** 76 /**
84 * No expectations at all. 77 * No expectations at all.
85 */ 78 */
86 Expectations(bool ignoreFailure=kDefaultIgnoreFailure) { 79 Expectations(bool ignoreFailure=kDefaultIgnoreFailure);
87 fIgnoreFailure = ignoreFailure;
88 }
89 80
90 /** 81 /**
91 * Expect exactly one image (appropriate for the case when we 82 * Expect exactly one image (appropriate for the case when we
92 * are comparing against a single PNG file). 83 * are comparing against a single PNG file).
93 */ 84 */
94 Expectations(const SkBitmap& bitmap, bool ignoreFailure=kDefaultIgnoreFa ilure) { 85 Expectations(const SkBitmap& bitmap, bool ignoreFailure=kDefaultIgnoreFa ilure);
95 fBitmap = bitmap;
96 fIgnoreFailure = ignoreFailure;
97 SkHashDigest digest;
98 // TODO(epoger): Better handling for error returned by ComputeDigest ()?
99 // For now, we just report a digest of 0 in error cases, like before .
100 if (!SkBitmapHasher::ComputeDigest(bitmap, &digest)) {
101 digest = 0;
102 }
103 fAllowedChecksums.push_back() = digest;
104 }
105 86
106 /** 87 /**
107 * Create Expectations from a JSON element as found within the 88 * Create Expectations from a JSON element as found within the
108 * kJsonKey_ExpectedResults section. 89 * kJsonKey_ExpectedResults section.
109 * 90 *
110 * It's fine if the jsonElement is null or empty; in that case, we just 91 * It's fine if the jsonElement is null or empty; in that case, we just
111 * don't have any expectations. 92 * don't have any expectations.
112 */ 93 */
113 Expectations(Json::Value jsonElement) { 94 Expectations(Json::Value jsonElement);
114 if (jsonElement.empty()) {
115 fIgnoreFailure = kDefaultIgnoreFailure;
116 } else {
117 Json::Value ignoreFailure = jsonElement[kJsonKey_ExpectedResults _IgnoreFailure];
118 if (ignoreFailure.isNull()) {
119 fIgnoreFailure = kDefaultIgnoreFailure;
120 } else if (!ignoreFailure.isBool()) {
121 gm_fprintf(stderr, "found non-boolean json value"
122 " for key '%s' in element '%s'\n",
123 kJsonKey_ExpectedResults_IgnoreFailure,
124 jsonElement.toStyledString().c_str());
125 DEBUGFAIL_SEE_STDERR;
126 fIgnoreFailure = kDefaultIgnoreFailure;
127 } else {
128 fIgnoreFailure = ignoreFailure.asBool();
129 }
130
131 Json::Value allowedChecksums = jsonElement[kJsonKey_ExpectedResu lts_Checksums];
132 if (allowedChecksums.isNull()) {
133 // ok, we'll just assume there aren't any expected checksums to compare against
134 } else if (!allowedChecksums.isArray()) {
135 gm_fprintf(stderr, "found non-array json value"
136 " for key '%s' in element '%s'\n",
137 kJsonKey_ExpectedResults_Checksums,
138 jsonElement.toStyledString().c_str());
139 DEBUGFAIL_SEE_STDERR;
140 } else {
141 for (Json::ArrayIndex i=0; i<allowedChecksums.size(); i++) {
142 Json::Value checksumElement = allowedChecksums[i];
143 if (!checksumElement.isIntegral()) {
144 gm_fprintf(stderr, "found non-integer checksum"
145 " in json element '%s'\n",
146 jsonElement.toStyledString().c_str());
147 DEBUGFAIL_SEE_STDERR;
148 } else {
149 fAllowedChecksums.push_back() = asChecksum(checksumE lement);
150 }
151 }
152 }
153 }
154 }
155 95
156 /** 96 /**
157 * Returns true iff we want to ignore failed expectations. 97 * Returns true iff we want to ignore failed expectations.
158 */ 98 */
159 bool ignoreFailure() const { return this->fIgnoreFailure; } 99 bool ignoreFailure() const { return this->fIgnoreFailure; }
160 100
161 /** 101 /**
162 * Returns true iff there are no allowed checksums. 102 * Returns true iff there are no allowed checksums.
163 */ 103 */
164 bool empty() const { return this->fAllowedChecksums.empty(); } 104 bool empty() const { return this->fAllowedBitmapCityhashes.empty(); }
165 105
166 /** 106 /**
167 * Returns true iff actualChecksum matches any allowedChecksum, 107 * Returns true iff actualChecksum matches any allowedChecksum,
168 * regardless of fIgnoreFailure. (The caller can check 108 * regardless of fIgnoreFailure. (The caller can check
169 * that separately.) 109 * that separately.)
170 */ 110 */
171 bool match(Checksum actualChecksum) const { 111 bool match(Checksum actualChecksum) const;
172 for (int i=0; i < this->fAllowedChecksums.count(); i++) {
173 Checksum allowedChecksum = this->fAllowedChecksums[i];
174 if (allowedChecksum == actualChecksum) {
175 return true;
176 }
177 }
178 return false;
179 }
180 112
181 /** 113 /**
182 * If this Expectation is based on a single SkBitmap, return a 114 * If this Expectation is based on a single SkBitmap, return a
183 * pointer to that SkBitmap. Otherwise (if the Expectation is 115 * pointer to that SkBitmap. Otherwise (if the Expectation is
184 * empty, or if it was based on a list of checksums rather 116 * empty, or if it was based on a list of checksums rather
185 * than a single bitmap), returns NULL. 117 * than a single bitmap), returns NULL.
186 */ 118 */
187 const SkBitmap *asBitmap() const { 119 const SkBitmap *asBitmap() const {
188 return (SkBitmap::kNo_Config == fBitmap.config()) ? NULL : &fBitmap; 120 return (SkBitmap::kNo_Config == fBitmap.config()) ? NULL : &fBitmap;
189 } 121 }
190 122
191 /** 123 /**
192 * Return a JSON representation of the allowed checksums. 124 * Return a JSON representation of the expectations.
193 * This does NOT include any information about whether to
194 * ignore failures.
195 */ 125 */
196 Json::Value allowedChecksumsAsJson() const { 126 Json::Value asJsonValue() const;
197 Json::Value allowedChecksumArray;
198 if (!this->fAllowedChecksums.empty()) {
199 for (int i=0; i < this->fAllowedChecksums.count(); i++) {
200 Checksum allowedChecksum = this->fAllowedChecksums[i];
201 allowedChecksumArray.append(asJsonValue(allowedChecksum));
202 }
203 }
204 return allowedChecksumArray;
205 }
206 127
207 private: 128 private:
208 const static bool kDefaultIgnoreFailure = false; 129 const static bool kDefaultIgnoreFailure = false;
209 130
210 SkTArray<Checksum> fAllowedChecksums; 131 SkTArray<Checksum> fAllowedBitmapCityhashes;
211 bool fIgnoreFailure; 132 bool fIgnoreFailure;
212 SkBitmap fBitmap; 133 SkBitmap fBitmap;
213 }; 134 };
214 135
215 /** 136 /**
216 * Abstract source of Expectations objects for individual tests. 137 * Abstract source of Expectations objects for individual tests.
217 */ 138 */
218 class ExpectationsSource : public SkRefCnt { 139 class ExpectationsSource : public SkRefCnt {
219 public: 140 public:
220 virtual Expectations get(const char *testName) = 0; 141 virtual Expectations get(const char *testName) = 0;
221 }; 142 };
222 143
223 /** 144 /**
224 * Return Expectations based on individual image files on disk. 145 * Return Expectations based on individual image files on disk.
225 */ 146 */
226 class IndividualImageExpectationsSource : public ExpectationsSource { 147 class IndividualImageExpectationsSource : public ExpectationsSource {
227 public: 148 public:
228 /** 149 /**
229 * Create an ExpectationsSource that will return Expectations based on 150 * Create an ExpectationsSource that will return Expectations based on
230 * image files found within rootDir. 151 * image files found within rootDir.
231 * 152 *
232 * rootDir: directory under which to look for image files 153 * rootDir: directory under which to look for image files
233 * (this string will be copied to storage within this object) 154 * (this string will be copied to storage within this object)
234 */ 155 */
235 IndividualImageExpectationsSource(const char *rootDir) : fRootDir(rootDi r) {} 156 IndividualImageExpectationsSource(const char *rootDir) : fRootDir(rootDi r) {}
236 157
237 Expectations get(const char *testName) SK_OVERRIDE { 158 Expectations get(const char *testName) SK_OVERRIDE ;
238 SkString path = make_filename(fRootDir.c_str(), "", testName,
239 "png");
240 SkBitmap referenceBitmap;
241 bool decodedReferenceBitmap =
242 SkImageDecoder::DecodeFile(path.c_str(), &referenceBitmap,
243 SkBitmap::kARGB_8888_Config,
244 SkImageDecoder::kDecodePixels_Mode,
245 NULL);
246 if (decodedReferenceBitmap) {
247 return Expectations(referenceBitmap);
248 } else {
249 return Expectations();
250 }
251 }
252 159
253 private: 160 private:
254 const SkString fRootDir; 161 const SkString fRootDir;
255 }; 162 };
256 163
257 /** 164 /**
258 * Return Expectations based on JSON summary file. 165 * Return Expectations based on JSON summary file.
259 */ 166 */
260 class JsonExpectationsSource : public ExpectationsSource { 167 class JsonExpectationsSource : public ExpectationsSource {
261 public: 168 public:
262 /** 169 /**
263 * Create an ExpectationsSource that will return Expectations based on 170 * Create an ExpectationsSource that will return Expectations based on
264 * a JSON file. 171 * a JSON file.
265 * 172 *
266 * jsonPath: path to JSON file to read 173 * jsonPath: path to JSON file to read
267 */ 174 */
268 JsonExpectationsSource(const char *jsonPath) { 175 JsonExpectationsSource(const char *jsonPath);
269 parse(jsonPath, &fJsonRoot);
270 fJsonExpectedResults = fJsonRoot[kJsonKey_ExpectedResults];
271 }
272 176
273 Expectations get(const char *testName) SK_OVERRIDE { 177 Expectations get(const char *testName) SK_OVERRIDE;
274 return Expectations(fJsonExpectedResults[testName]);
275 }
276 178
277 private: 179 private:
278 180
279 /** 181 /**
280 * Read as many bytes as possible (up to maxBytes) from the stream into 182 * Read as many bytes as possible (up to maxBytes) from the stream into
281 * an SkData object. 183 * an SkData object.
282 * 184 *
283 * If the returned SkData contains fewer than maxBytes, then EOF has bee n 185 * If the returned SkData contains fewer than maxBytes, then EOF has bee n
284 * reached and no more data would be available from subsequent calls. 186 * reached and no more data would be available from subsequent calls.
285 * (If EOF has already been reached, then this call will return an empty 187 * (If EOF has already been reached, then this call will return an empty
(...skipping 14 matching lines...) Expand all
300 * size_t bytesActuallyRead = dataRef.get()->size(); 202 * size_t bytesActuallyRead = dataRef.get()->size();
301 * // use the data... 203 * // use the data...
302 * } 204 * }
303 * } 205 * }
304 * // underlying buffer has been freed, thanks to auto unref 206 * // underlying buffer has been freed, thanks to auto unref
305 * 207 *
306 */ 208 */
307 // TODO(epoger): Move this, into SkStream.[cpp|h] as attempted in 209 // TODO(epoger): Move this, into SkStream.[cpp|h] as attempted in
308 // https://codereview.appspot.com/7300071 ? 210 // https://codereview.appspot.com/7300071 ?
309 // And maybe readFileIntoSkData() also? 211 // And maybe readFileIntoSkData() also?
310 static SkData* readIntoSkData(SkStream &stream, size_t maxBytes) { 212 static SkData* readIntoSkData(SkStream &stream, size_t maxBytes);
311 if (0 == maxBytes) {
312 return SkData::NewEmpty();
313 }
314 char* bufStart = reinterpret_cast<char *>(sk_malloc_throw(maxBytes)) ;
315 char* bufPtr = bufStart;
316 size_t bytesRemaining = maxBytes;
317 while (bytesRemaining > 0) {
318 size_t bytesReadThisTime = stream.read(bufPtr, bytesRemaining);
319 if (0 == bytesReadThisTime) {
320 break;
321 }
322 bytesRemaining -= bytesReadThisTime;
323 bufPtr += bytesReadThisTime;
324 }
325 return SkData::NewFromMalloc(bufStart, maxBytes - bytesRemaining);
326 }
327 213
328 /** 214 /**
329 * Wrapper around readIntoSkData for files: reads the entire file into 215 * Wrapper around readIntoSkData for files: reads the entire file into
330 * an SkData object. 216 * an SkData object.
331 */ 217 */
332 static SkData* readFileIntoSkData(SkFILEStream &stream) { 218 static SkData* readFileIntoSkData(SkFILEStream &stream) {
333 return readIntoSkData(stream, stream.getLength()); 219 return readIntoSkData(stream, stream.getLength());
334 } 220 }
335 221
336 /** 222 /**
337 * Read the file contents from jsonPath and parse them into jsonRoot. 223 * Read the file contents from jsonPath and parse them into jsonRoot.
338 * 224 *
339 * Returns true if successful. 225 * Returns true if successful.
340 */ 226 */
341 static bool parse(const char *jsonPath, Json::Value *jsonRoot) { 227 static bool parse(const char *jsonPath, Json::Value *jsonRoot);
342 SkFILEStream inFile(jsonPath);
343 if (!inFile.isValid()) {
344 gm_fprintf(stderr, "unable to read JSON file %s\n", jsonPath);
345 DEBUGFAIL_SEE_STDERR;
346 return false;
347 }
348
349 SkAutoDataUnref dataRef(readFileIntoSkData(inFile));
350 if (NULL == dataRef.get()) {
351 gm_fprintf(stderr, "error reading JSON file %s\n", jsonPath);
352 DEBUGFAIL_SEE_STDERR;
353 return false;
354 }
355
356 const char *bytes = reinterpret_cast<const char *>(dataRef.get()->da ta());
357 size_t size = dataRef.get()->size();
358 Json::Reader reader;
359 if (!reader.parse(bytes, bytes+size, *jsonRoot)) {
360 gm_fprintf(stderr, "error parsing JSON file %s\n", jsonPath);
361 DEBUGFAIL_SEE_STDERR;
362 return false;
363 }
364 return true;
365 }
366 228
367 Json::Value fJsonRoot; 229 Json::Value fJsonRoot;
368 Json::Value fJsonExpectedResults; 230 Json::Value fJsonExpectedResults;
369 }; 231 };
370 232
371 } 233 }
372 #endif 234 #endif
OLDNEW
« no previous file with comments | « no previous file | gm/gm_expectations.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698