blob: a92ceb323fe4da69fd65eed036de9ba74947f2b4 [file] [log] [blame]
epoger@google.com76c913d2013-04-26 15:06:44 +00001/*
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
8#include "gm_expectations.h"
9#include "SkBitmapHasher.h"
10#include "SkImageDecoder.h"
11
12#define DEBUGFAIL_SEE_STDERR SkDEBUGFAIL("see stderr for message")
13
epoger@google.com26515ba2013-05-14 18:58:12 +000014// These constants must be kept in sync with the JSONKEY_ constants in
15// confirm_no_failures_in_json.py !
epoger@google.com76c913d2013-04-26 15:06:44 +000016const static char kJsonKey_ActualResults[] = "actual-results";
17const static char kJsonKey_ActualResults_Failed[] = "failed";
18const static char kJsonKey_ActualResults_FailureIgnored[]= "failure-ignored";
19const static char kJsonKey_ActualResults_NoComparison[] = "no-comparison";
20const static char kJsonKey_ActualResults_Succeeded[] = "succeeded";
epoger@google.com366a7702013-05-07 15:51:54 +000021const static char kJsonKey_ActualResults_AnyStatus_BitmapHash[] = "bitmap-64bitMD5";
epoger@google.com76c913d2013-04-26 15:06:44 +000022
23const static char kJsonKey_ExpectedResults[] = "expected-results";
epoger@google.com366a7702013-05-07 15:51:54 +000024const static char kJsonKey_ExpectedResults_AllowedBitmapHashes[] = "allowed-bitmap-64bitMD5s";
epoger@google.com76c913d2013-04-26 15:06:44 +000025const static char kJsonKey_ExpectedResults_IgnoreFailure[] = "ignore-failure";
26
27namespace skiagm {
28
scroggo@google.com6843bdb2013-05-08 19:14:23 +000029 void gm_fprintf(FILE *stream, const char format[], ...) {
30 va_list args;
31 va_start(args, format);
32 fprintf(stream, "GM: ");
33 vfprintf(stream, format, args);
34 va_end(args);
35 }
36
epoger@google.comce057fe2013-05-14 15:17:46 +000037 SkString SkPathJoin(const char *rootPath, const char *relativePath) {
38 SkString result(rootPath);
39 if (!result.endsWith(SkPATH_SEPARATOR)) {
40 result.appendUnichar(SkPATH_SEPARATOR);
41 }
42 result.append(relativePath);
43 return result;
44 }
45
scroggo@google.com6843bdb2013-05-08 19:14:23 +000046 SkString make_filename(const char path[],
47 const char renderModeDescriptor[],
48 const char *name,
49 const char suffix[]) {
epoger@google.comce057fe2013-05-14 15:17:46 +000050 SkString filename(name);
51 filename.append(renderModeDescriptor);
52 filename.appendUnichar('.');
53 filename.append(suffix);
54 return SkPathJoin(path, filename.c_str());
scroggo@google.com6843bdb2013-05-08 19:14:23 +000055 }
56
epoger@google.com76c913d2013-04-26 15:06:44 +000057 // TODO(epoger): This currently assumes that the result SkHashDigest was
epoger@google.com366a7702013-05-07 15:51:54 +000058 // generated as an SkHashDigest of an SkBitmap. We'll need to allow for other
59 // hash types to cover non-bitmaps.
epoger@google.com76c913d2013-04-26 15:06:44 +000060 Json::Value ActualResultAsJsonValue(const SkHashDigest& result) {
61 Json::Value jsonValue;
epoger@google.com366a7702013-05-07 15:51:54 +000062 jsonValue[kJsonKey_ActualResults_AnyStatus_BitmapHash] = asJsonValue(result);
epoger@google.com76c913d2013-04-26 15:06:44 +000063 return jsonValue;
64 }
65
66 Json::Value CreateJsonTree(Json::Value expectedResults,
67 Json::Value actualResultsFailed,
68 Json::Value actualResultsFailureIgnored,
69 Json::Value actualResultsNoComparison,
70 Json::Value actualResultsSucceeded) {
71 Json::Value actualResults;
72 actualResults[kJsonKey_ActualResults_Failed] = actualResultsFailed;
73 actualResults[kJsonKey_ActualResults_FailureIgnored] = actualResultsFailureIgnored;
74 actualResults[kJsonKey_ActualResults_NoComparison] = actualResultsNoComparison;
75 actualResults[kJsonKey_ActualResults_Succeeded] = actualResultsSucceeded;
76 Json::Value root;
77 root[kJsonKey_ActualResults] = actualResults;
78 root[kJsonKey_ExpectedResults] = expectedResults;
79 return root;
80 }
81
82
83 // Expectations class...
84
85 Expectations::Expectations(bool ignoreFailure) {
86 fIgnoreFailure = ignoreFailure;
87 }
88
89 Expectations::Expectations(const SkBitmap& bitmap, bool ignoreFailure) {
90 fBitmap = bitmap;
91 fIgnoreFailure = ignoreFailure;
92 SkHashDigest digest;
93 // TODO(epoger): Better handling for error returned by ComputeDigest()?
94 // For now, we just report a digest of 0 in error cases, like before.
95 if (!SkBitmapHasher::ComputeDigest(bitmap, &digest)) {
96 digest = 0;
97 }
epoger@google.com366a7702013-05-07 15:51:54 +000098 fAllowedBitmapChecksums.push_back() = digest;
epoger@google.com76c913d2013-04-26 15:06:44 +000099 }
100
101 Expectations::Expectations(Json::Value jsonElement) {
102 if (jsonElement.empty()) {
103 fIgnoreFailure = kDefaultIgnoreFailure;
104 } else {
105 Json::Value ignoreFailure = jsonElement[kJsonKey_ExpectedResults_IgnoreFailure];
106 if (ignoreFailure.isNull()) {
107 fIgnoreFailure = kDefaultIgnoreFailure;
108 } else if (!ignoreFailure.isBool()) {
109 gm_fprintf(stderr, "found non-boolean json value"
110 " for key '%s' in element '%s'\n",
111 kJsonKey_ExpectedResults_IgnoreFailure,
112 jsonElement.toStyledString().c_str());
113 DEBUGFAIL_SEE_STDERR;
114 fIgnoreFailure = kDefaultIgnoreFailure;
115 } else {
116 fIgnoreFailure = ignoreFailure.asBool();
117 }
118
119 Json::Value allowedChecksums =
epoger@google.com366a7702013-05-07 15:51:54 +0000120 jsonElement[kJsonKey_ExpectedResults_AllowedBitmapHashes];
epoger@google.com76c913d2013-04-26 15:06:44 +0000121 if (allowedChecksums.isNull()) {
122 // ok, we'll just assume there aren't any expected checksums to compare against
123 } else if (!allowedChecksums.isArray()) {
124 gm_fprintf(stderr, "found non-array json value"
125 " for key '%s' in element '%s'\n",
epoger@google.com366a7702013-05-07 15:51:54 +0000126 kJsonKey_ExpectedResults_AllowedBitmapHashes,
epoger@google.com76c913d2013-04-26 15:06:44 +0000127 jsonElement.toStyledString().c_str());
128 DEBUGFAIL_SEE_STDERR;
129 } else {
130 for (Json::ArrayIndex i=0; i<allowedChecksums.size(); i++) {
131 Json::Value checksumElement = allowedChecksums[i];
132 if (!checksumElement.isIntegral()) {
133 gm_fprintf(stderr, "found non-integer checksum"
134 " in json element '%s'\n",
135 jsonElement.toStyledString().c_str());
136 DEBUGFAIL_SEE_STDERR;
137 } else {
epoger@google.com366a7702013-05-07 15:51:54 +0000138 fAllowedBitmapChecksums.push_back() = asChecksum(checksumElement);
epoger@google.com76c913d2013-04-26 15:06:44 +0000139 }
140 }
141 }
142 }
143 }
144
145 bool Expectations::match(Checksum actualChecksum) const {
epoger@google.com366a7702013-05-07 15:51:54 +0000146 for (int i=0; i < this->fAllowedBitmapChecksums.count(); i++) {
147 Checksum allowedChecksum = this->fAllowedBitmapChecksums[i];
epoger@google.com76c913d2013-04-26 15:06:44 +0000148 if (allowedChecksum == actualChecksum) {
149 return true;
150 }
151 }
152 return false;
153 }
154
155 Json::Value Expectations::asJsonValue() const {
156 Json::Value allowedChecksumArray;
epoger@google.com366a7702013-05-07 15:51:54 +0000157 if (!this->fAllowedBitmapChecksums.empty()) {
158 for (int i=0; i < this->fAllowedBitmapChecksums.count(); i++) {
159 Checksum allowedChecksum = this->fAllowedBitmapChecksums[i];
epoger@google.com76c913d2013-04-26 15:06:44 +0000160 allowedChecksumArray.append(Json::UInt64(allowedChecksum));
161 }
162 }
163
164 Json::Value jsonValue;
epoger@google.com366a7702013-05-07 15:51:54 +0000165 jsonValue[kJsonKey_ExpectedResults_AllowedBitmapHashes] = allowedChecksumArray;
epoger@google.com76c913d2013-04-26 15:06:44 +0000166 jsonValue[kJsonKey_ExpectedResults_IgnoreFailure] = this->ignoreFailure();
167 return jsonValue;
168 }
169
170
171 // IndividualImageExpectationsSource class...
172
173 Expectations IndividualImageExpectationsSource::get(const char *testName) {
epoger@google.comce057fe2013-05-14 15:17:46 +0000174 SkString path = SkPathJoin(fRootDir.c_str(), testName);
epoger@google.com76c913d2013-04-26 15:06:44 +0000175 SkBitmap referenceBitmap;
176 bool decodedReferenceBitmap =
177 SkImageDecoder::DecodeFile(path.c_str(), &referenceBitmap,
178 SkBitmap::kARGB_8888_Config,
179 SkImageDecoder::kDecodePixels_Mode,
180 NULL);
181 if (decodedReferenceBitmap) {
182 return Expectations(referenceBitmap);
183 } else {
184 return Expectations();
185 }
186 }
187
188
189 // JsonExpectationsSource class...
190
191 JsonExpectationsSource::JsonExpectationsSource(const char *jsonPath) {
scroggo@google.com6843bdb2013-05-08 19:14:23 +0000192 Parse(jsonPath, &fJsonRoot);
epoger@google.com76c913d2013-04-26 15:06:44 +0000193 fJsonExpectedResults = fJsonRoot[kJsonKey_ExpectedResults];
194 }
195
196 Expectations JsonExpectationsSource::get(const char *testName) {
197 return Expectations(fJsonExpectedResults[testName]);
198 }
199
scroggo@google.com6843bdb2013-05-08 19:14:23 +0000200 /*static*/ SkData* JsonExpectationsSource::ReadIntoSkData(SkStream &stream, size_t maxBytes) {
epoger@google.com76c913d2013-04-26 15:06:44 +0000201 if (0 == maxBytes) {
202 return SkData::NewEmpty();
203 }
204 char* bufStart = reinterpret_cast<char *>(sk_malloc_throw(maxBytes));
205 char* bufPtr = bufStart;
206 size_t bytesRemaining = maxBytes;
207 while (bytesRemaining > 0) {
208 size_t bytesReadThisTime = stream.read(bufPtr, bytesRemaining);
209 if (0 == bytesReadThisTime) {
210 break;
211 }
212 bytesRemaining -= bytesReadThisTime;
213 bufPtr += bytesReadThisTime;
214 }
215 return SkData::NewFromMalloc(bufStart, maxBytes - bytesRemaining);
216 }
217
scroggo@google.com6843bdb2013-05-08 19:14:23 +0000218 /*static*/ bool JsonExpectationsSource::Parse(const char *jsonPath, Json::Value *jsonRoot) {
epoger@google.com76c913d2013-04-26 15:06:44 +0000219 SkFILEStream inFile(jsonPath);
220 if (!inFile.isValid()) {
221 gm_fprintf(stderr, "unable to read JSON file %s\n", jsonPath);
222 DEBUGFAIL_SEE_STDERR;
223 return false;
224 }
225
scroggo@google.com6843bdb2013-05-08 19:14:23 +0000226 SkAutoDataUnref dataRef(ReadFileIntoSkData(inFile));
epoger@google.com76c913d2013-04-26 15:06:44 +0000227 if (NULL == dataRef.get()) {
228 gm_fprintf(stderr, "error reading JSON file %s\n", jsonPath);
229 DEBUGFAIL_SEE_STDERR;
230 return false;
231 }
232
233 const char *bytes = reinterpret_cast<const char *>(dataRef.get()->data());
234 size_t size = dataRef.get()->size();
235 Json::Reader reader;
236 if (!reader.parse(bytes, bytes+size, *jsonRoot)) {
237 gm_fprintf(stderr, "error parsing JSON file %s\n", jsonPath);
238 DEBUGFAIL_SEE_STDERR;
239 return false;
240 }
241 return true;
242 }
243
244}