blob: 28493ddd9e9c26f5fa5d5596c8da53432902d527 [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.
commit-bot@chromium.org90c0fbd2014-05-09 03:18:41 +00006 *
7 * TODO(epoger): Combine this with tools/image_expectations.cpp, or eliminate one of the two.
epoger@google.com76c913d2013-04-26 15:06:44 +00008 */
9
10#include "gm_expectations.h"
11#include "SkBitmapHasher.h"
commit-bot@chromium.org90c0fbd2014-05-09 03:18:41 +000012#include "SkData.h"
epoger@google.com76c913d2013-04-26 15:06:44 +000013#include "SkImageDecoder.h"
14
15#define DEBUGFAIL_SEE_STDERR SkDEBUGFAIL("see stderr for message")
16
epoger@google.coma783f2b2013-07-08 17:51:58 +000017// See gm_json.py for descriptions of each of these JSON keys.
18// These constants must be kept in sync with the ones in that Python file!
epoger@google.com76c913d2013-04-26 15:06:44 +000019const static char kJsonKey_ActualResults[] = "actual-results";
20const static char kJsonKey_ActualResults_Failed[] = "failed";
21const static char kJsonKey_ActualResults_FailureIgnored[]= "failure-ignored";
22const static char kJsonKey_ActualResults_NoComparison[] = "no-comparison";
23const static char kJsonKey_ActualResults_Succeeded[] = "succeeded";
epoger@google.com76c913d2013-04-26 15:06:44 +000024const static char kJsonKey_ExpectedResults[] = "expected-results";
epoger@google.comd4993ff2013-05-24 14:33:28 +000025const static char kJsonKey_ExpectedResults_AllowedDigests[] = "allowed-digests";
26const static char kJsonKey_ExpectedResults_IgnoreFailure[] = "ignore-failure";
27
28// Types of result hashes we support in the JSON file.
29const static char kJsonKey_Hashtype_Bitmap_64bitMD5[] = "bitmap-64bitMD5";
30
epoger@google.com76c913d2013-04-26 15:06:44 +000031
32namespace skiagm {
scroggo@google.com6843bdb2013-05-08 19:14:23 +000033
epoger@google.com76c913d2013-04-26 15:06:44 +000034 Json::Value CreateJsonTree(Json::Value expectedResults,
35 Json::Value actualResultsFailed,
36 Json::Value actualResultsFailureIgnored,
37 Json::Value actualResultsNoComparison,
38 Json::Value actualResultsSucceeded) {
39 Json::Value actualResults;
40 actualResults[kJsonKey_ActualResults_Failed] = actualResultsFailed;
41 actualResults[kJsonKey_ActualResults_FailureIgnored] = actualResultsFailureIgnored;
42 actualResults[kJsonKey_ActualResults_NoComparison] = actualResultsNoComparison;
43 actualResults[kJsonKey_ActualResults_Succeeded] = actualResultsSucceeded;
44 Json::Value root;
45 root[kJsonKey_ActualResults] = actualResults;
46 root[kJsonKey_ExpectedResults] = expectedResults;
47 return root;
48 }
49
50
epoger@google.comd4993ff2013-05-24 14:33:28 +000051 // GmResultDigest class...
52
53 GmResultDigest::GmResultDigest(const SkBitmap &bitmap) {
54 fIsValid = SkBitmapHasher::ComputeDigest(bitmap, &fHashDigest);
55 }
56
57 GmResultDigest::GmResultDigest(const Json::Value &jsonTypeValuePair) {
58 fIsValid = false;
59 if (!jsonTypeValuePair.isArray()) {
commit-bot@chromium.org2b3a2042014-02-27 18:45:26 +000060 SkDebugf("found non-array json value when parsing GmResultDigest: %s\n",
61 jsonTypeValuePair.toStyledString().c_str());
epoger@google.comd4993ff2013-05-24 14:33:28 +000062 DEBUGFAIL_SEE_STDERR;
63 } else if (2 != jsonTypeValuePair.size()) {
commit-bot@chromium.org2b3a2042014-02-27 18:45:26 +000064 SkDebugf("found json array with wrong size when parsing GmResultDigest: %s\n",
65 jsonTypeValuePair.toStyledString().c_str());
epoger@google.comd4993ff2013-05-24 14:33:28 +000066 DEBUGFAIL_SEE_STDERR;
67 } else {
68 // TODO(epoger): The current implementation assumes that the
69 // result digest is always of type kJsonKey_Hashtype_Bitmap_64bitMD5
70 Json::Value jsonHashValue = jsonTypeValuePair[1];
71 if (!jsonHashValue.isIntegral()) {
commit-bot@chromium.org2b3a2042014-02-27 18:45:26 +000072 SkDebugf("found non-integer jsonHashValue when parsing GmResultDigest: %s\n",
73 jsonTypeValuePair.toStyledString().c_str());
epoger@google.comd4993ff2013-05-24 14:33:28 +000074 DEBUGFAIL_SEE_STDERR;
75 } else {
76 fHashDigest = jsonHashValue.asUInt64();
77 fIsValid = true;
78 }
79 }
80 }
81
82 bool GmResultDigest::isValid() const {
83 return fIsValid;
84 }
85
86 bool GmResultDigest::equals(const GmResultDigest &other) const {
87 // TODO(epoger): The current implementation assumes that this
88 // and other are always of type kJsonKey_Hashtype_Bitmap_64bitMD5
89 return (this->fIsValid && other.fIsValid && (this->fHashDigest == other.fHashDigest));
90 }
91
92 Json::Value GmResultDigest::asJsonTypeValuePair() const {
93 // TODO(epoger): The current implementation assumes that the
94 // result digest is always of type kJsonKey_Hashtype_Bitmap_64bitMD5
95 Json::Value jsonTypeValuePair;
96 if (fIsValid) {
97 jsonTypeValuePair.append(Json::Value(kJsonKey_Hashtype_Bitmap_64bitMD5));
98 jsonTypeValuePair.append(Json::UInt64(fHashDigest));
99 } else {
100 jsonTypeValuePair.append(Json::Value("INVALID"));
101 }
102 return jsonTypeValuePair;
103 }
104
epoger@google.com6f7f14d2013-06-19 18:28:31 +0000105 SkString GmResultDigest::getHashType() const {
106 // TODO(epoger): The current implementation assumes that the
107 // result digest is always of type kJsonKey_Hashtype_Bitmap_64bitMD5
108 return SkString(kJsonKey_Hashtype_Bitmap_64bitMD5);
109 }
110
111 SkString GmResultDigest::getDigestValue() const {
112 // TODO(epoger): The current implementation assumes that the
113 // result digest is always of type kJsonKey_Hashtype_Bitmap_64bitMD5
114 SkString retval;
115 retval.appendU64(fHashDigest);
116 return retval;
117 }
118
epoger@google.comd4993ff2013-05-24 14:33:28 +0000119
epoger@google.com76c913d2013-04-26 15:06:44 +0000120 // Expectations class...
121
122 Expectations::Expectations(bool ignoreFailure) {
123 fIgnoreFailure = ignoreFailure;
124 }
125
126 Expectations::Expectations(const SkBitmap& bitmap, bool ignoreFailure) {
127 fBitmap = bitmap;
128 fIgnoreFailure = ignoreFailure;
epoger@google.comd4993ff2013-05-24 14:33:28 +0000129 fAllowedResultDigests.push_back(GmResultDigest(bitmap));
epoger@google.com76c913d2013-04-26 15:06:44 +0000130 }
131
scroggo@google.com5187c432013-10-22 00:42:46 +0000132 Expectations::Expectations(const BitmapAndDigest& bitmapAndDigest) {
133 fBitmap = bitmapAndDigest.fBitmap;
134 fIgnoreFailure = false;
135 fAllowedResultDigests.push_back(bitmapAndDigest.fDigest);
136 }
137
epoger@google.com76c913d2013-04-26 15:06:44 +0000138 Expectations::Expectations(Json::Value jsonElement) {
139 if (jsonElement.empty()) {
140 fIgnoreFailure = kDefaultIgnoreFailure;
141 } else {
142 Json::Value ignoreFailure = jsonElement[kJsonKey_ExpectedResults_IgnoreFailure];
143 if (ignoreFailure.isNull()) {
144 fIgnoreFailure = kDefaultIgnoreFailure;
145 } else if (!ignoreFailure.isBool()) {
commit-bot@chromium.org2b3a2042014-02-27 18:45:26 +0000146 SkDebugf("found non-boolean json value for key '%s' in element '%s'\n",
147 kJsonKey_ExpectedResults_IgnoreFailure,
148 jsonElement.toStyledString().c_str());
epoger@google.com76c913d2013-04-26 15:06:44 +0000149 DEBUGFAIL_SEE_STDERR;
150 fIgnoreFailure = kDefaultIgnoreFailure;
151 } else {
152 fIgnoreFailure = ignoreFailure.asBool();
153 }
154
epoger@google.comd4993ff2013-05-24 14:33:28 +0000155 Json::Value allowedDigests = jsonElement[kJsonKey_ExpectedResults_AllowedDigests];
156 if (allowedDigests.isNull()) {
157 // ok, we'll just assume there aren't any AllowedDigests to compare against
158 } else if (!allowedDigests.isArray()) {
commit-bot@chromium.org2b3a2042014-02-27 18:45:26 +0000159 SkDebugf("found non-array json value for key '%s' in element '%s'\n",
160 kJsonKey_ExpectedResults_AllowedDigests,
161 jsonElement.toStyledString().c_str());
epoger@google.com76c913d2013-04-26 15:06:44 +0000162 DEBUGFAIL_SEE_STDERR;
163 } else {
epoger@google.comd4993ff2013-05-24 14:33:28 +0000164 for (Json::ArrayIndex i=0; i<allowedDigests.size(); i++) {
165 fAllowedResultDigests.push_back(GmResultDigest(allowedDigests[i]));
epoger@google.com76c913d2013-04-26 15:06:44 +0000166 }
167 }
168 }
169 }
170
epoger@google.comd4993ff2013-05-24 14:33:28 +0000171 bool Expectations::match(GmResultDigest actualGmResultDigest) const {
172 for (int i=0; i < this->fAllowedResultDigests.count(); i++) {
173 GmResultDigest allowedResultDigest = this->fAllowedResultDigests[i];
174 if (allowedResultDigest.equals(actualGmResultDigest)) {
epoger@google.com76c913d2013-04-26 15:06:44 +0000175 return true;
176 }
177 }
178 return false;
179 }
180
181 Json::Value Expectations::asJsonValue() const {
epoger@google.comd4993ff2013-05-24 14:33:28 +0000182 Json::Value allowedDigestArray;
183 if (!this->fAllowedResultDigests.empty()) {
184 for (int i=0; i < this->fAllowedResultDigests.count(); i++) {
185 allowedDigestArray.append(this->fAllowedResultDigests[i].asJsonTypeValuePair());
epoger@google.com76c913d2013-04-26 15:06:44 +0000186 }
187 }
188
epoger@google.comd4993ff2013-05-24 14:33:28 +0000189 Json::Value jsonExpectations;
190 jsonExpectations[kJsonKey_ExpectedResults_AllowedDigests] = allowedDigestArray;
191 jsonExpectations[kJsonKey_ExpectedResults_IgnoreFailure] = this->ignoreFailure();
192 return jsonExpectations;
epoger@google.com76c913d2013-04-26 15:06:44 +0000193 }
194
195
196 // IndividualImageExpectationsSource class...
197
commit-bot@chromium.org1d5bbb22013-10-14 14:15:28 +0000198 Expectations IndividualImageExpectationsSource::get(const char *testName) const {
scroggo@google.comccd7afb2013-05-28 16:45:07 +0000199 SkString path = SkOSPath::SkPathJoin(fRootDir.c_str(), testName);
epoger@google.com76c913d2013-04-26 15:06:44 +0000200 SkBitmap referenceBitmap;
201 bool decodedReferenceBitmap =
202 SkImageDecoder::DecodeFile(path.c_str(), &referenceBitmap,
203 SkBitmap::kARGB_8888_Config,
204 SkImageDecoder::kDecodePixels_Mode,
205 NULL);
206 if (decodedReferenceBitmap) {
207 return Expectations(referenceBitmap);
208 } else {
209 return Expectations();
210 }
211 }
212
213
214 // JsonExpectationsSource class...
215
216 JsonExpectationsSource::JsonExpectationsSource(const char *jsonPath) {
scroggo@google.com6843bdb2013-05-08 19:14:23 +0000217 Parse(jsonPath, &fJsonRoot);
epoger@google.com76c913d2013-04-26 15:06:44 +0000218 fJsonExpectedResults = fJsonRoot[kJsonKey_ExpectedResults];
219 }
220
commit-bot@chromium.org1d5bbb22013-10-14 14:15:28 +0000221 Expectations JsonExpectationsSource::get(const char *testName) const {
epoger@google.com76c913d2013-04-26 15:06:44 +0000222 return Expectations(fJsonExpectedResults[testName]);
223 }
224
scroggo@google.com6843bdb2013-05-08 19:14:23 +0000225 /*static*/ bool JsonExpectationsSource::Parse(const char *jsonPath, Json::Value *jsonRoot) {
commit-bot@chromium.org90c0fbd2014-05-09 03:18:41 +0000226 SkAutoDataUnref dataRef(SkData::NewFromFileName(jsonPath));
epoger@google.com76c913d2013-04-26 15:06:44 +0000227 if (NULL == dataRef.get()) {
commit-bot@chromium.org2b3a2042014-02-27 18:45:26 +0000228 SkDebugf("error reading JSON file %s\n", jsonPath);
epoger@google.com76c913d2013-04-26 15:06:44 +0000229 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)) {
commit-bot@chromium.org2b3a2042014-02-27 18:45:26 +0000237 SkDebugf("error parsing JSON file %s\n", jsonPath);
epoger@google.com76c913d2013-04-26 15:06:44 +0000238 DEBUGFAIL_SEE_STDERR;
239 return false;
240 }
241 return true;
242 }
243
244}