blob: d2d629e8d3d6f61c0c72497d0415742ea710a5c1 [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
commit-bot@chromium.org25c10662014-05-16 17:56:43 +000034#ifdef SK_BUILD_JSON_WRITER
epoger@google.com76c913d2013-04-26 15:06:44 +000035 Json::Value CreateJsonTree(Json::Value expectedResults,
36 Json::Value actualResultsFailed,
37 Json::Value actualResultsFailureIgnored,
38 Json::Value actualResultsNoComparison,
39 Json::Value actualResultsSucceeded) {
40 Json::Value actualResults;
41 actualResults[kJsonKey_ActualResults_Failed] = actualResultsFailed;
42 actualResults[kJsonKey_ActualResults_FailureIgnored] = actualResultsFailureIgnored;
43 actualResults[kJsonKey_ActualResults_NoComparison] = actualResultsNoComparison;
44 actualResults[kJsonKey_ActualResults_Succeeded] = actualResultsSucceeded;
45 Json::Value root;
46 root[kJsonKey_ActualResults] = actualResults;
47 root[kJsonKey_ExpectedResults] = expectedResults;
48 return root;
49 }
commit-bot@chromium.org25c10662014-05-16 17:56:43 +000050#endif
epoger@google.com76c913d2013-04-26 15:06:44 +000051
epoger@google.comd4993ff2013-05-24 14:33:28 +000052 // GmResultDigest class...
53
54 GmResultDigest::GmResultDigest(const SkBitmap &bitmap) {
55 fIsValid = SkBitmapHasher::ComputeDigest(bitmap, &fHashDigest);
56 }
57
commit-bot@chromium.org25c10662014-05-16 17:56:43 +000058#ifdef SK_BUILD_JSON_WRITER
epoger@google.comd4993ff2013-05-24 14:33:28 +000059 GmResultDigest::GmResultDigest(const Json::Value &jsonTypeValuePair) {
60 fIsValid = false;
61 if (!jsonTypeValuePair.isArray()) {
commit-bot@chromium.org2b3a2042014-02-27 18:45:26 +000062 SkDebugf("found non-array json value when parsing GmResultDigest: %s\n",
63 jsonTypeValuePair.toStyledString().c_str());
epoger@google.comd4993ff2013-05-24 14:33:28 +000064 DEBUGFAIL_SEE_STDERR;
65 } else if (2 != jsonTypeValuePair.size()) {
commit-bot@chromium.org2b3a2042014-02-27 18:45:26 +000066 SkDebugf("found json array with wrong size when parsing GmResultDigest: %s\n",
67 jsonTypeValuePair.toStyledString().c_str());
epoger@google.comd4993ff2013-05-24 14:33:28 +000068 DEBUGFAIL_SEE_STDERR;
69 } else {
70 // TODO(epoger): The current implementation assumes that the
71 // result digest is always of type kJsonKey_Hashtype_Bitmap_64bitMD5
72 Json::Value jsonHashValue = jsonTypeValuePair[1];
73 if (!jsonHashValue.isIntegral()) {
commit-bot@chromium.org2b3a2042014-02-27 18:45:26 +000074 SkDebugf("found non-integer jsonHashValue when parsing GmResultDigest: %s\n",
75 jsonTypeValuePair.toStyledString().c_str());
epoger@google.comd4993ff2013-05-24 14:33:28 +000076 DEBUGFAIL_SEE_STDERR;
77 } else {
78 fHashDigest = jsonHashValue.asUInt64();
79 fIsValid = true;
80 }
81 }
82 }
commit-bot@chromium.org25c10662014-05-16 17:56:43 +000083#endif
epoger@google.comd4993ff2013-05-24 14:33:28 +000084
85 bool GmResultDigest::isValid() const {
86 return fIsValid;
87 }
88
89 bool GmResultDigest::equals(const GmResultDigest &other) const {
90 // TODO(epoger): The current implementation assumes that this
91 // and other are always of type kJsonKey_Hashtype_Bitmap_64bitMD5
92 return (this->fIsValid && other.fIsValid && (this->fHashDigest == other.fHashDigest));
93 }
94
commit-bot@chromium.org25c10662014-05-16 17:56:43 +000095#ifdef SK_BUILD_JSON_WRITER
epoger@google.comd4993ff2013-05-24 14:33:28 +000096 Json::Value GmResultDigest::asJsonTypeValuePair() const {
97 // TODO(epoger): The current implementation assumes that the
98 // result digest is always of type kJsonKey_Hashtype_Bitmap_64bitMD5
99 Json::Value jsonTypeValuePair;
100 if (fIsValid) {
101 jsonTypeValuePair.append(Json::Value(kJsonKey_Hashtype_Bitmap_64bitMD5));
102 jsonTypeValuePair.append(Json::UInt64(fHashDigest));
103 } else {
104 jsonTypeValuePair.append(Json::Value("INVALID"));
105 }
106 return jsonTypeValuePair;
107 }
commit-bot@chromium.org25c10662014-05-16 17:56:43 +0000108#endif
epoger@google.comd4993ff2013-05-24 14:33:28 +0000109
epoger@google.com6f7f14d2013-06-19 18:28:31 +0000110 SkString GmResultDigest::getHashType() const {
111 // TODO(epoger): The current implementation assumes that the
112 // result digest is always of type kJsonKey_Hashtype_Bitmap_64bitMD5
113 return SkString(kJsonKey_Hashtype_Bitmap_64bitMD5);
114 }
115
116 SkString GmResultDigest::getDigestValue() const {
117 // TODO(epoger): The current implementation assumes that the
118 // result digest is always of type kJsonKey_Hashtype_Bitmap_64bitMD5
119 SkString retval;
120 retval.appendU64(fHashDigest);
121 return retval;
122 }
123
epoger@google.comd4993ff2013-05-24 14:33:28 +0000124
epoger@google.com76c913d2013-04-26 15:06:44 +0000125 // Expectations class...
126
127 Expectations::Expectations(bool ignoreFailure) {
128 fIgnoreFailure = ignoreFailure;
129 }
130
131 Expectations::Expectations(const SkBitmap& bitmap, bool ignoreFailure) {
132 fBitmap = bitmap;
133 fIgnoreFailure = ignoreFailure;
epoger@google.comd4993ff2013-05-24 14:33:28 +0000134 fAllowedResultDigests.push_back(GmResultDigest(bitmap));
epoger@google.com76c913d2013-04-26 15:06:44 +0000135 }
136
scroggo@google.com5187c432013-10-22 00:42:46 +0000137 Expectations::Expectations(const BitmapAndDigest& bitmapAndDigest) {
138 fBitmap = bitmapAndDigest.fBitmap;
139 fIgnoreFailure = false;
140 fAllowedResultDigests.push_back(bitmapAndDigest.fDigest);
141 }
142
commit-bot@chromium.org25c10662014-05-16 17:56:43 +0000143#ifdef SK_BUILD_JSON_WRITER
epoger@google.com76c913d2013-04-26 15:06:44 +0000144 Expectations::Expectations(Json::Value jsonElement) {
145 if (jsonElement.empty()) {
146 fIgnoreFailure = kDefaultIgnoreFailure;
147 } else {
148 Json::Value ignoreFailure = jsonElement[kJsonKey_ExpectedResults_IgnoreFailure];
149 if (ignoreFailure.isNull()) {
150 fIgnoreFailure = kDefaultIgnoreFailure;
151 } else if (!ignoreFailure.isBool()) {
commit-bot@chromium.org2b3a2042014-02-27 18:45:26 +0000152 SkDebugf("found non-boolean json value for key '%s' in element '%s'\n",
153 kJsonKey_ExpectedResults_IgnoreFailure,
154 jsonElement.toStyledString().c_str());
epoger@google.com76c913d2013-04-26 15:06:44 +0000155 DEBUGFAIL_SEE_STDERR;
156 fIgnoreFailure = kDefaultIgnoreFailure;
157 } else {
158 fIgnoreFailure = ignoreFailure.asBool();
159 }
160
epoger@google.comd4993ff2013-05-24 14:33:28 +0000161 Json::Value allowedDigests = jsonElement[kJsonKey_ExpectedResults_AllowedDigests];
162 if (allowedDigests.isNull()) {
163 // ok, we'll just assume there aren't any AllowedDigests to compare against
164 } else if (!allowedDigests.isArray()) {
commit-bot@chromium.org2b3a2042014-02-27 18:45:26 +0000165 SkDebugf("found non-array json value for key '%s' in element '%s'\n",
166 kJsonKey_ExpectedResults_AllowedDigests,
167 jsonElement.toStyledString().c_str());
epoger@google.com76c913d2013-04-26 15:06:44 +0000168 DEBUGFAIL_SEE_STDERR;
169 } else {
epoger@google.comd4993ff2013-05-24 14:33:28 +0000170 for (Json::ArrayIndex i=0; i<allowedDigests.size(); i++) {
171 fAllowedResultDigests.push_back(GmResultDigest(allowedDigests[i]));
epoger@google.com76c913d2013-04-26 15:06:44 +0000172 }
173 }
174 }
175 }
commit-bot@chromium.org25c10662014-05-16 17:56:43 +0000176#endif
epoger@google.com76c913d2013-04-26 15:06:44 +0000177
epoger@google.comd4993ff2013-05-24 14:33:28 +0000178 bool Expectations::match(GmResultDigest actualGmResultDigest) const {
179 for (int i=0; i < this->fAllowedResultDigests.count(); i++) {
180 GmResultDigest allowedResultDigest = this->fAllowedResultDigests[i];
181 if (allowedResultDigest.equals(actualGmResultDigest)) {
epoger@google.com76c913d2013-04-26 15:06:44 +0000182 return true;
183 }
184 }
185 return false;
186 }
187
commit-bot@chromium.org25c10662014-05-16 17:56:43 +0000188#ifdef SK_BUILD_JSON_WRITER
epoger@google.com76c913d2013-04-26 15:06:44 +0000189 Json::Value Expectations::asJsonValue() const {
epoger@google.comd4993ff2013-05-24 14:33:28 +0000190 Json::Value allowedDigestArray;
191 if (!this->fAllowedResultDigests.empty()) {
192 for (int i=0; i < this->fAllowedResultDigests.count(); i++) {
193 allowedDigestArray.append(this->fAllowedResultDigests[i].asJsonTypeValuePair());
epoger@google.com76c913d2013-04-26 15:06:44 +0000194 }
195 }
196
epoger@google.comd4993ff2013-05-24 14:33:28 +0000197 Json::Value jsonExpectations;
198 jsonExpectations[kJsonKey_ExpectedResults_AllowedDigests] = allowedDigestArray;
199 jsonExpectations[kJsonKey_ExpectedResults_IgnoreFailure] = this->ignoreFailure();
200 return jsonExpectations;
epoger@google.com76c913d2013-04-26 15:06:44 +0000201 }
commit-bot@chromium.org25c10662014-05-16 17:56:43 +0000202#endif
epoger@google.com76c913d2013-04-26 15:06:44 +0000203
204 // IndividualImageExpectationsSource class...
205
commit-bot@chromium.org1d5bbb22013-10-14 14:15:28 +0000206 Expectations IndividualImageExpectationsSource::get(const char *testName) const {
scroggo@google.comccd7afb2013-05-28 16:45:07 +0000207 SkString path = SkOSPath::SkPathJoin(fRootDir.c_str(), testName);
epoger@google.com76c913d2013-04-26 15:06:44 +0000208 SkBitmap referenceBitmap;
209 bool decodedReferenceBitmap =
210 SkImageDecoder::DecodeFile(path.c_str(), &referenceBitmap,
211 SkBitmap::kARGB_8888_Config,
212 SkImageDecoder::kDecodePixels_Mode,
213 NULL);
214 if (decodedReferenceBitmap) {
215 return Expectations(referenceBitmap);
216 } else {
217 return Expectations();
218 }
219 }
220
221
commit-bot@chromium.org25c10662014-05-16 17:56:43 +0000222#ifdef SK_BUILD_JSON_WRITER
epoger@google.com76c913d2013-04-26 15:06:44 +0000223 // JsonExpectationsSource class...
224
225 JsonExpectationsSource::JsonExpectationsSource(const char *jsonPath) {
scroggo@google.com6843bdb2013-05-08 19:14:23 +0000226 Parse(jsonPath, &fJsonRoot);
epoger@google.com76c913d2013-04-26 15:06:44 +0000227 fJsonExpectedResults = fJsonRoot[kJsonKey_ExpectedResults];
228 }
229
commit-bot@chromium.org1d5bbb22013-10-14 14:15:28 +0000230 Expectations JsonExpectationsSource::get(const char *testName) const {
epoger@google.com76c913d2013-04-26 15:06:44 +0000231 return Expectations(fJsonExpectedResults[testName]);
232 }
233
scroggo@google.com6843bdb2013-05-08 19:14:23 +0000234 /*static*/ bool JsonExpectationsSource::Parse(const char *jsonPath, Json::Value *jsonRoot) {
commit-bot@chromium.org90c0fbd2014-05-09 03:18:41 +0000235 SkAutoDataUnref dataRef(SkData::NewFromFileName(jsonPath));
epoger@google.com76c913d2013-04-26 15:06:44 +0000236 if (NULL == dataRef.get()) {
commit-bot@chromium.org2b3a2042014-02-27 18:45:26 +0000237 SkDebugf("error reading JSON file %s\n", jsonPath);
epoger@google.com76c913d2013-04-26 15:06:44 +0000238 DEBUGFAIL_SEE_STDERR;
239 return false;
240 }
241
242 const char *bytes = reinterpret_cast<const char *>(dataRef.get()->data());
243 size_t size = dataRef.get()->size();
244 Json::Reader reader;
245 if (!reader.parse(bytes, bytes+size, *jsonRoot)) {
commit-bot@chromium.org2b3a2042014-02-27 18:45:26 +0000246 SkDebugf("error parsing JSON file %s\n", jsonPath);
epoger@google.com76c913d2013-04-26 15:06:44 +0000247 DEBUGFAIL_SEE_STDERR;
248 return false;
249 }
250 return true;
251 }
commit-bot@chromium.org25c10662014-05-16 17:56:43 +0000252#endif
epoger@google.com76c913d2013-04-26 15:06:44 +0000253}