blob: db6abdf404b6fd0c3827947d3b8c9bb0eea490e4 [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 }
epoger@google.com76c913d2013-04-26 15:06:44 +000049
epoger@google.comd4993ff2013-05-24 14:33:28 +000050 // GmResultDigest class...
51
52 GmResultDigest::GmResultDigest(const SkBitmap &bitmap) {
53 fIsValid = SkBitmapHasher::ComputeDigest(bitmap, &fHashDigest);
54 }
55
56 GmResultDigest::GmResultDigest(const Json::Value &jsonTypeValuePair) {
57 fIsValid = false;
58 if (!jsonTypeValuePair.isArray()) {
commit-bot@chromium.org2b3a2042014-02-27 18:45:26 +000059 SkDebugf("found non-array json value when parsing GmResultDigest: %s\n",
60 jsonTypeValuePair.toStyledString().c_str());
epoger@google.comd4993ff2013-05-24 14:33:28 +000061 DEBUGFAIL_SEE_STDERR;
62 } else if (2 != jsonTypeValuePair.size()) {
commit-bot@chromium.org2b3a2042014-02-27 18:45:26 +000063 SkDebugf("found json array with wrong size when parsing GmResultDigest: %s\n",
64 jsonTypeValuePair.toStyledString().c_str());
epoger@google.comd4993ff2013-05-24 14:33:28 +000065 DEBUGFAIL_SEE_STDERR;
66 } else {
67 // TODO(epoger): The current implementation assumes that the
68 // result digest is always of type kJsonKey_Hashtype_Bitmap_64bitMD5
69 Json::Value jsonHashValue = jsonTypeValuePair[1];
70 if (!jsonHashValue.isIntegral()) {
commit-bot@chromium.org2b3a2042014-02-27 18:45:26 +000071 SkDebugf("found non-integer jsonHashValue when parsing GmResultDigest: %s\n",
72 jsonTypeValuePair.toStyledString().c_str());
epoger@google.comd4993ff2013-05-24 14:33:28 +000073 DEBUGFAIL_SEE_STDERR;
74 } else {
75 fHashDigest = jsonHashValue.asUInt64();
76 fIsValid = true;
77 }
78 }
79 }
80
81 bool GmResultDigest::isValid() const {
82 return fIsValid;
83 }
84
85 bool GmResultDigest::equals(const GmResultDigest &other) const {
86 // TODO(epoger): The current implementation assumes that this
87 // and other are always of type kJsonKey_Hashtype_Bitmap_64bitMD5
88 return (this->fIsValid && other.fIsValid && (this->fHashDigest == other.fHashDigest));
89 }
90
91 Json::Value GmResultDigest::asJsonTypeValuePair() const {
92 // TODO(epoger): The current implementation assumes that the
93 // result digest is always of type kJsonKey_Hashtype_Bitmap_64bitMD5
94 Json::Value jsonTypeValuePair;
95 if (fIsValid) {
96 jsonTypeValuePair.append(Json::Value(kJsonKey_Hashtype_Bitmap_64bitMD5));
97 jsonTypeValuePair.append(Json::UInt64(fHashDigest));
98 } else {
99 jsonTypeValuePair.append(Json::Value("INVALID"));
100 }
101 return jsonTypeValuePair;
102 }
103
epoger@google.com6f7f14d2013-06-19 18:28:31 +0000104 SkString GmResultDigest::getHashType() const {
105 // TODO(epoger): The current implementation assumes that the
106 // result digest is always of type kJsonKey_Hashtype_Bitmap_64bitMD5
107 return SkString(kJsonKey_Hashtype_Bitmap_64bitMD5);
108 }
109
110 SkString GmResultDigest::getDigestValue() const {
111 // TODO(epoger): The current implementation assumes that the
112 // result digest is always of type kJsonKey_Hashtype_Bitmap_64bitMD5
113 SkString retval;
114 retval.appendU64(fHashDigest);
115 return retval;
116 }
117
epoger@google.comd4993ff2013-05-24 14:33:28 +0000118
epoger@google.com76c913d2013-04-26 15:06:44 +0000119 // Expectations class...
120
121 Expectations::Expectations(bool ignoreFailure) {
122 fIgnoreFailure = ignoreFailure;
123 }
124
125 Expectations::Expectations(const SkBitmap& bitmap, bool ignoreFailure) {
126 fBitmap = bitmap;
127 fIgnoreFailure = ignoreFailure;
epoger@google.comd4993ff2013-05-24 14:33:28 +0000128 fAllowedResultDigests.push_back(GmResultDigest(bitmap));
epoger@google.com76c913d2013-04-26 15:06:44 +0000129 }
130
scroggo@google.com5187c432013-10-22 00:42:46 +0000131 Expectations::Expectations(const BitmapAndDigest& bitmapAndDigest) {
132 fBitmap = bitmapAndDigest.fBitmap;
133 fIgnoreFailure = false;
134 fAllowedResultDigests.push_back(bitmapAndDigest.fDigest);
135 }
136
epoger@google.com76c913d2013-04-26 15:06:44 +0000137 Expectations::Expectations(Json::Value jsonElement) {
138 if (jsonElement.empty()) {
139 fIgnoreFailure = kDefaultIgnoreFailure;
140 } else {
141 Json::Value ignoreFailure = jsonElement[kJsonKey_ExpectedResults_IgnoreFailure];
142 if (ignoreFailure.isNull()) {
143 fIgnoreFailure = kDefaultIgnoreFailure;
144 } else if (!ignoreFailure.isBool()) {
commit-bot@chromium.org2b3a2042014-02-27 18:45:26 +0000145 SkDebugf("found non-boolean json value for key '%s' in element '%s'\n",
146 kJsonKey_ExpectedResults_IgnoreFailure,
147 jsonElement.toStyledString().c_str());
epoger@google.com76c913d2013-04-26 15:06:44 +0000148 DEBUGFAIL_SEE_STDERR;
149 fIgnoreFailure = kDefaultIgnoreFailure;
150 } else {
151 fIgnoreFailure = ignoreFailure.asBool();
152 }
153
epoger@google.comd4993ff2013-05-24 14:33:28 +0000154 Json::Value allowedDigests = jsonElement[kJsonKey_ExpectedResults_AllowedDigests];
155 if (allowedDigests.isNull()) {
156 // ok, we'll just assume there aren't any AllowedDigests to compare against
157 } else if (!allowedDigests.isArray()) {
commit-bot@chromium.org2b3a2042014-02-27 18:45:26 +0000158 SkDebugf("found non-array json value for key '%s' in element '%s'\n",
159 kJsonKey_ExpectedResults_AllowedDigests,
160 jsonElement.toStyledString().c_str());
epoger@google.com76c913d2013-04-26 15:06:44 +0000161 DEBUGFAIL_SEE_STDERR;
162 } else {
epoger@google.comd4993ff2013-05-24 14:33:28 +0000163 for (Json::ArrayIndex i=0; i<allowedDigests.size(); i++) {
164 fAllowedResultDigests.push_back(GmResultDigest(allowedDigests[i]));
epoger@google.com76c913d2013-04-26 15:06:44 +0000165 }
166 }
167 }
168 }
169
epoger@google.comd4993ff2013-05-24 14:33:28 +0000170 bool Expectations::match(GmResultDigest actualGmResultDigest) const {
171 for (int i=0; i < this->fAllowedResultDigests.count(); i++) {
172 GmResultDigest allowedResultDigest = this->fAllowedResultDigests[i];
173 if (allowedResultDigest.equals(actualGmResultDigest)) {
epoger@google.com76c913d2013-04-26 15:06:44 +0000174 return true;
175 }
176 }
177 return false;
178 }
179
180 Json::Value Expectations::asJsonValue() const {
epoger@google.comd4993ff2013-05-24 14:33:28 +0000181 Json::Value allowedDigestArray;
182 if (!this->fAllowedResultDigests.empty()) {
183 for (int i=0; i < this->fAllowedResultDigests.count(); i++) {
184 allowedDigestArray.append(this->fAllowedResultDigests[i].asJsonTypeValuePair());
epoger@google.com76c913d2013-04-26 15:06:44 +0000185 }
186 }
187
epoger@google.comd4993ff2013-05-24 14:33:28 +0000188 Json::Value jsonExpectations;
189 jsonExpectations[kJsonKey_ExpectedResults_AllowedDigests] = allowedDigestArray;
190 jsonExpectations[kJsonKey_ExpectedResults_IgnoreFailure] = this->ignoreFailure();
191 return jsonExpectations;
epoger@google.com76c913d2013-04-26 15:06:44 +0000192 }
epoger@google.com76c913d2013-04-26 15:06:44 +0000193
194 // IndividualImageExpectationsSource class...
195
commit-bot@chromium.org1d5bbb22013-10-14 14:15:28 +0000196 Expectations IndividualImageExpectationsSource::get(const char *testName) const {
tfarinaa8e2e152014-07-28 19:26:58 -0700197 SkString path = SkOSPath::Join(fRootDir.c_str(), testName);
epoger@google.com76c913d2013-04-26 15:06:44 +0000198 SkBitmap referenceBitmap;
199 bool decodedReferenceBitmap =
reedbfefc7c2014-06-12 17:40:00 -0700200 SkImageDecoder::DecodeFile(path.c_str(), &referenceBitmap, kN32_SkColorType,
201 SkImageDecoder::kDecodePixels_Mode, NULL);
epoger@google.com76c913d2013-04-26 15:06:44 +0000202 if (decodedReferenceBitmap) {
203 return Expectations(referenceBitmap);
204 } else {
205 return Expectations();
206 }
207 }
208
209
210 // JsonExpectationsSource class...
211
212 JsonExpectationsSource::JsonExpectationsSource(const char *jsonPath) {
scroggo@google.com6843bdb2013-05-08 19:14:23 +0000213 Parse(jsonPath, &fJsonRoot);
epoger@google.com76c913d2013-04-26 15:06:44 +0000214 fJsonExpectedResults = fJsonRoot[kJsonKey_ExpectedResults];
215 }
216
commit-bot@chromium.org1d5bbb22013-10-14 14:15:28 +0000217 Expectations JsonExpectationsSource::get(const char *testName) const {
epoger@google.com76c913d2013-04-26 15:06:44 +0000218 return Expectations(fJsonExpectedResults[testName]);
219 }
220
scroggo@google.com6843bdb2013-05-08 19:14:23 +0000221 /*static*/ bool JsonExpectationsSource::Parse(const char *jsonPath, Json::Value *jsonRoot) {
commit-bot@chromium.org90c0fbd2014-05-09 03:18:41 +0000222 SkAutoDataUnref dataRef(SkData::NewFromFileName(jsonPath));
epoger@google.com76c913d2013-04-26 15:06:44 +0000223 if (NULL == dataRef.get()) {
commit-bot@chromium.org2b3a2042014-02-27 18:45:26 +0000224 SkDebugf("error reading JSON file %s\n", jsonPath);
epoger@google.com76c913d2013-04-26 15:06:44 +0000225 DEBUGFAIL_SEE_STDERR;
226 return false;
227 }
228
229 const char *bytes = reinterpret_cast<const char *>(dataRef.get()->data());
230 size_t size = dataRef.get()->size();
231 Json::Reader reader;
232 if (!reader.parse(bytes, bytes+size, *jsonRoot)) {
commit-bot@chromium.org2b3a2042014-02-27 18:45:26 +0000233 SkDebugf("error parsing JSON file %s\n", jsonPath);
epoger@google.com76c913d2013-04-26 15:06:44 +0000234 DEBUGFAIL_SEE_STDERR;
235 return false;
236 }
237 return true;
238 }
epoger@google.com76c913d2013-04-26 15:06:44 +0000239}