blob: f46a572458f4439a950c5e0d7af6cf6df87b1708 [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.coma783f2b2013-07-08 17:51:58 +000014// See gm_json.py for descriptions of each of these JSON keys.
15// These constants must be kept in sync with the ones in that Python file!
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.com76c913d2013-04-26 15:06:44 +000021const static char kJsonKey_ExpectedResults[] = "expected-results";
epoger@google.comd4993ff2013-05-24 14:33:28 +000022const static char kJsonKey_ExpectedResults_AllowedDigests[] = "allowed-digests";
23const static char kJsonKey_ExpectedResults_IgnoreFailure[] = "ignore-failure";
24
25// Types of result hashes we support in the JSON file.
26const static char kJsonKey_Hashtype_Bitmap_64bitMD5[] = "bitmap-64bitMD5";
27
epoger@google.com76c913d2013-04-26 15:06:44 +000028
29namespace skiagm {
scroggo@google.com6843bdb2013-05-08 19:14:23 +000030
epoger@google.com76c913d2013-04-26 15:06:44 +000031 Json::Value CreateJsonTree(Json::Value expectedResults,
32 Json::Value actualResultsFailed,
33 Json::Value actualResultsFailureIgnored,
34 Json::Value actualResultsNoComparison,
35 Json::Value actualResultsSucceeded) {
36 Json::Value actualResults;
37 actualResults[kJsonKey_ActualResults_Failed] = actualResultsFailed;
38 actualResults[kJsonKey_ActualResults_FailureIgnored] = actualResultsFailureIgnored;
39 actualResults[kJsonKey_ActualResults_NoComparison] = actualResultsNoComparison;
40 actualResults[kJsonKey_ActualResults_Succeeded] = actualResultsSucceeded;
41 Json::Value root;
42 root[kJsonKey_ActualResults] = actualResults;
43 root[kJsonKey_ExpectedResults] = expectedResults;
44 return root;
45 }
46
47
epoger@google.comd4993ff2013-05-24 14:33:28 +000048 // GmResultDigest class...
49
50 GmResultDigest::GmResultDigest(const SkBitmap &bitmap) {
51 fIsValid = SkBitmapHasher::ComputeDigest(bitmap, &fHashDigest);
52 }
53
54 GmResultDigest::GmResultDigest(const Json::Value &jsonTypeValuePair) {
55 fIsValid = false;
56 if (!jsonTypeValuePair.isArray()) {
commit-bot@chromium.org2b3a2042014-02-27 18:45:26 +000057 SkDebugf("found non-array json value when parsing GmResultDigest: %s\n",
58 jsonTypeValuePair.toStyledString().c_str());
epoger@google.comd4993ff2013-05-24 14:33:28 +000059 DEBUGFAIL_SEE_STDERR;
60 } else if (2 != jsonTypeValuePair.size()) {
commit-bot@chromium.org2b3a2042014-02-27 18:45:26 +000061 SkDebugf("found json array with wrong size when parsing GmResultDigest: %s\n",
62 jsonTypeValuePair.toStyledString().c_str());
epoger@google.comd4993ff2013-05-24 14:33:28 +000063 DEBUGFAIL_SEE_STDERR;
64 } else {
65 // TODO(epoger): The current implementation assumes that the
66 // result digest is always of type kJsonKey_Hashtype_Bitmap_64bitMD5
67 Json::Value jsonHashValue = jsonTypeValuePair[1];
68 if (!jsonHashValue.isIntegral()) {
commit-bot@chromium.org2b3a2042014-02-27 18:45:26 +000069 SkDebugf("found non-integer jsonHashValue when parsing GmResultDigest: %s\n",
70 jsonTypeValuePair.toStyledString().c_str());
epoger@google.comd4993ff2013-05-24 14:33:28 +000071 DEBUGFAIL_SEE_STDERR;
72 } else {
73 fHashDigest = jsonHashValue.asUInt64();
74 fIsValid = true;
75 }
76 }
77 }
78
79 bool GmResultDigest::isValid() const {
80 return fIsValid;
81 }
82
83 bool GmResultDigest::equals(const GmResultDigest &other) const {
84 // TODO(epoger): The current implementation assumes that this
85 // and other are always of type kJsonKey_Hashtype_Bitmap_64bitMD5
86 return (this->fIsValid && other.fIsValid && (this->fHashDigest == other.fHashDigest));
87 }
88
89 Json::Value GmResultDigest::asJsonTypeValuePair() const {
90 // TODO(epoger): The current implementation assumes that the
91 // result digest is always of type kJsonKey_Hashtype_Bitmap_64bitMD5
92 Json::Value jsonTypeValuePair;
93 if (fIsValid) {
94 jsonTypeValuePair.append(Json::Value(kJsonKey_Hashtype_Bitmap_64bitMD5));
95 jsonTypeValuePair.append(Json::UInt64(fHashDigest));
96 } else {
97 jsonTypeValuePair.append(Json::Value("INVALID"));
98 }
99 return jsonTypeValuePair;
100 }
101
epoger@google.com6f7f14d2013-06-19 18:28:31 +0000102 SkString GmResultDigest::getHashType() const {
103 // TODO(epoger): The current implementation assumes that the
104 // result digest is always of type kJsonKey_Hashtype_Bitmap_64bitMD5
105 return SkString(kJsonKey_Hashtype_Bitmap_64bitMD5);
106 }
107
108 SkString GmResultDigest::getDigestValue() const {
109 // TODO(epoger): The current implementation assumes that the
110 // result digest is always of type kJsonKey_Hashtype_Bitmap_64bitMD5
111 SkString retval;
112 retval.appendU64(fHashDigest);
113 return retval;
114 }
115
epoger@google.comd4993ff2013-05-24 14:33:28 +0000116
epoger@google.com76c913d2013-04-26 15:06:44 +0000117 // Expectations class...
118
119 Expectations::Expectations(bool ignoreFailure) {
120 fIgnoreFailure = ignoreFailure;
121 }
122
123 Expectations::Expectations(const SkBitmap& bitmap, bool ignoreFailure) {
124 fBitmap = bitmap;
125 fIgnoreFailure = ignoreFailure;
epoger@google.comd4993ff2013-05-24 14:33:28 +0000126 fAllowedResultDigests.push_back(GmResultDigest(bitmap));
epoger@google.com76c913d2013-04-26 15:06:44 +0000127 }
128
scroggo@google.com5187c432013-10-22 00:42:46 +0000129 Expectations::Expectations(const BitmapAndDigest& bitmapAndDigest) {
130 fBitmap = bitmapAndDigest.fBitmap;
131 fIgnoreFailure = false;
132 fAllowedResultDigests.push_back(bitmapAndDigest.fDigest);
133 }
134
epoger@google.com76c913d2013-04-26 15:06:44 +0000135 Expectations::Expectations(Json::Value jsonElement) {
136 if (jsonElement.empty()) {
137 fIgnoreFailure = kDefaultIgnoreFailure;
138 } else {
139 Json::Value ignoreFailure = jsonElement[kJsonKey_ExpectedResults_IgnoreFailure];
140 if (ignoreFailure.isNull()) {
141 fIgnoreFailure = kDefaultIgnoreFailure;
142 } else if (!ignoreFailure.isBool()) {
commit-bot@chromium.org2b3a2042014-02-27 18:45:26 +0000143 SkDebugf("found non-boolean json value for key '%s' in element '%s'\n",
144 kJsonKey_ExpectedResults_IgnoreFailure,
145 jsonElement.toStyledString().c_str());
epoger@google.com76c913d2013-04-26 15:06:44 +0000146 DEBUGFAIL_SEE_STDERR;
147 fIgnoreFailure = kDefaultIgnoreFailure;
148 } else {
149 fIgnoreFailure = ignoreFailure.asBool();
150 }
151
epoger@google.comd4993ff2013-05-24 14:33:28 +0000152 Json::Value allowedDigests = jsonElement[kJsonKey_ExpectedResults_AllowedDigests];
153 if (allowedDigests.isNull()) {
154 // ok, we'll just assume there aren't any AllowedDigests to compare against
155 } else if (!allowedDigests.isArray()) {
commit-bot@chromium.org2b3a2042014-02-27 18:45:26 +0000156 SkDebugf("found non-array json value for key '%s' in element '%s'\n",
157 kJsonKey_ExpectedResults_AllowedDigests,
158 jsonElement.toStyledString().c_str());
epoger@google.com76c913d2013-04-26 15:06:44 +0000159 DEBUGFAIL_SEE_STDERR;
160 } else {
epoger@google.comd4993ff2013-05-24 14:33:28 +0000161 for (Json::ArrayIndex i=0; i<allowedDigests.size(); i++) {
162 fAllowedResultDigests.push_back(GmResultDigest(allowedDigests[i]));
epoger@google.com76c913d2013-04-26 15:06:44 +0000163 }
164 }
165 }
166 }
167
epoger@google.comd4993ff2013-05-24 14:33:28 +0000168 bool Expectations::match(GmResultDigest actualGmResultDigest) const {
169 for (int i=0; i < this->fAllowedResultDigests.count(); i++) {
170 GmResultDigest allowedResultDigest = this->fAllowedResultDigests[i];
171 if (allowedResultDigest.equals(actualGmResultDigest)) {
epoger@google.com76c913d2013-04-26 15:06:44 +0000172 return true;
173 }
174 }
175 return false;
176 }
177
178 Json::Value Expectations::asJsonValue() const {
epoger@google.comd4993ff2013-05-24 14:33:28 +0000179 Json::Value allowedDigestArray;
180 if (!this->fAllowedResultDigests.empty()) {
181 for (int i=0; i < this->fAllowedResultDigests.count(); i++) {
182 allowedDigestArray.append(this->fAllowedResultDigests[i].asJsonTypeValuePair());
epoger@google.com76c913d2013-04-26 15:06:44 +0000183 }
184 }
185
epoger@google.comd4993ff2013-05-24 14:33:28 +0000186 Json::Value jsonExpectations;
187 jsonExpectations[kJsonKey_ExpectedResults_AllowedDigests] = allowedDigestArray;
188 jsonExpectations[kJsonKey_ExpectedResults_IgnoreFailure] = this->ignoreFailure();
189 return jsonExpectations;
epoger@google.com76c913d2013-04-26 15:06:44 +0000190 }
191
192
193 // IndividualImageExpectationsSource class...
194
commit-bot@chromium.org1d5bbb22013-10-14 14:15:28 +0000195 Expectations IndividualImageExpectationsSource::get(const char *testName) const {
scroggo@google.comccd7afb2013-05-28 16:45:07 +0000196 SkString path = SkOSPath::SkPathJoin(fRootDir.c_str(), testName);
epoger@google.com76c913d2013-04-26 15:06:44 +0000197 SkBitmap referenceBitmap;
198 bool decodedReferenceBitmap =
199 SkImageDecoder::DecodeFile(path.c_str(), &referenceBitmap,
200 SkBitmap::kARGB_8888_Config,
201 SkImageDecoder::kDecodePixels_Mode,
202 NULL);
203 if (decodedReferenceBitmap) {
204 return Expectations(referenceBitmap);
205 } else {
206 return Expectations();
207 }
208 }
209
210
211 // JsonExpectationsSource class...
212
213 JsonExpectationsSource::JsonExpectationsSource(const char *jsonPath) {
scroggo@google.com6843bdb2013-05-08 19:14:23 +0000214 Parse(jsonPath, &fJsonRoot);
epoger@google.com76c913d2013-04-26 15:06:44 +0000215 fJsonExpectedResults = fJsonRoot[kJsonKey_ExpectedResults];
216 }
217
commit-bot@chromium.org1d5bbb22013-10-14 14:15:28 +0000218 Expectations JsonExpectationsSource::get(const char *testName) const {
epoger@google.com76c913d2013-04-26 15:06:44 +0000219 return Expectations(fJsonExpectedResults[testName]);
220 }
221
scroggo@google.com6843bdb2013-05-08 19:14:23 +0000222 /*static*/ SkData* JsonExpectationsSource::ReadIntoSkData(SkStream &stream, size_t maxBytes) {
epoger@google.com76c913d2013-04-26 15:06:44 +0000223 if (0 == maxBytes) {
224 return SkData::NewEmpty();
225 }
226 char* bufStart = reinterpret_cast<char *>(sk_malloc_throw(maxBytes));
227 char* bufPtr = bufStart;
228 size_t bytesRemaining = maxBytes;
229 while (bytesRemaining > 0) {
230 size_t bytesReadThisTime = stream.read(bufPtr, bytesRemaining);
231 if (0 == bytesReadThisTime) {
232 break;
233 }
234 bytesRemaining -= bytesReadThisTime;
235 bufPtr += bytesReadThisTime;
236 }
237 return SkData::NewFromMalloc(bufStart, maxBytes - bytesRemaining);
238 }
239
scroggo@google.com6843bdb2013-05-08 19:14:23 +0000240 /*static*/ bool JsonExpectationsSource::Parse(const char *jsonPath, Json::Value *jsonRoot) {
epoger@google.com76c913d2013-04-26 15:06:44 +0000241 SkFILEStream inFile(jsonPath);
242 if (!inFile.isValid()) {
commit-bot@chromium.org2b3a2042014-02-27 18:45:26 +0000243 SkDebugf("unable to read JSON file %s\n", jsonPath);
epoger@google.com76c913d2013-04-26 15:06:44 +0000244 DEBUGFAIL_SEE_STDERR;
245 return false;
246 }
247
scroggo@google.com6843bdb2013-05-08 19:14:23 +0000248 SkAutoDataUnref dataRef(ReadFileIntoSkData(inFile));
epoger@google.com76c913d2013-04-26 15:06:44 +0000249 if (NULL == dataRef.get()) {
commit-bot@chromium.org2b3a2042014-02-27 18:45:26 +0000250 SkDebugf("error reading JSON file %s\n", jsonPath);
epoger@google.com76c913d2013-04-26 15:06:44 +0000251 DEBUGFAIL_SEE_STDERR;
252 return false;
253 }
254
255 const char *bytes = reinterpret_cast<const char *>(dataRef.get()->data());
256 size_t size = dataRef.get()->size();
257 Json::Reader reader;
258 if (!reader.parse(bytes, bytes+size, *jsonRoot)) {
commit-bot@chromium.org2b3a2042014-02-27 18:45:26 +0000259 SkDebugf("error parsing JSON file %s\n", jsonPath);
epoger@google.com76c913d2013-04-26 15:06:44 +0000260 DEBUGFAIL_SEE_STDERR;
261 return false;
262 }
263 return true;
264 }
265
266}