OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2013 Google Inc. | 2 * Copyright 2013 Google Inc. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
6 */ | 6 */ |
7 | 7 |
8 #include "gm_expectations.h" | 8 #include "gm_expectations.h" |
9 #include "SkBitmapHasher.h" | 9 #include "SkBitmapHasher.h" |
10 #include "SkImageDecoder.h" | 10 #include "SkImageDecoder.h" |
11 | 11 |
12 #define DEBUGFAIL_SEE_STDERR SkDEBUGFAIL("see stderr for message") | 12 #define DEBUGFAIL_SEE_STDERR SkDEBUGFAIL("see stderr for message") |
13 | 13 |
14 // These constants must be kept in sync with the JSONKEY_ constants in | 14 // These constants must be kept in sync with the JSONKEY_ constants in |
15 // display_json_results.py ! | 15 // display_json_results.py ! |
16 const static char kJsonKey_ActualResults[] = "actual-results"; | 16 const static char kJsonKey_ActualResults[] = "actual-results"; |
17 const static char kJsonKey_ActualResults_Failed[] = "failed"; | 17 const static char kJsonKey_ActualResults_Failed[] = "failed"; |
18 const static char kJsonKey_ActualResults_FailureIgnored[]= "failure-ignored"; | 18 const static char kJsonKey_ActualResults_FailureIgnored[]= "failure-ignored"; |
19 const static char kJsonKey_ActualResults_NoComparison[] = "no-comparison"; | 19 const static char kJsonKey_ActualResults_NoComparison[] = "no-comparison"; |
20 const static char kJsonKey_ActualResults_Succeeded[] = "succeeded"; | 20 const static char kJsonKey_ActualResults_Succeeded[] = "succeeded"; |
21 const static char kJsonKey_ActualResults_AnyStatus_BitmapHash[] = "bitmap-64bit
MD5"; | |
22 | 21 |
23 const static char kJsonKey_ExpectedResults[] = "expected-results"; | 22 const static char kJsonKey_ExpectedResults[] = "expected-results"; |
24 const static char kJsonKey_ExpectedResults_AllowedBitmapHashes[] = "allowed-bitm
ap-64bitMD5s"; | 23 const static char kJsonKey_ExpectedResults_AllowedDigests[] = "allowed-digests"; |
25 const static char kJsonKey_ExpectedResults_IgnoreFailure[] = "ignore-f
ailure"; | 24 const static char kJsonKey_ExpectedResults_IgnoreFailure[] = "ignore-failure"; |
| 25 |
| 26 // Types of result hashes we support in the JSON file. |
| 27 const static char kJsonKey_Hashtype_Bitmap_64bitMD5[] = "bitmap-64bitMD5"; |
| 28 |
26 | 29 |
27 namespace skiagm { | 30 namespace skiagm { |
28 | 31 |
29 void gm_fprintf(FILE *stream, const char format[], ...) { | 32 void gm_fprintf(FILE *stream, const char format[], ...) { |
30 va_list args; | 33 va_list args; |
31 va_start(args, format); | 34 va_start(args, format); |
32 fprintf(stream, "GM: "); | 35 fprintf(stream, "GM: "); |
33 vfprintf(stream, format, args); | 36 vfprintf(stream, format, args); |
34 va_end(args); | 37 va_end(args); |
35 } | 38 } |
36 | 39 |
37 SkString SkPathJoin(const char *rootPath, const char *relativePath) { | 40 SkString SkPathJoin(const char *rootPath, const char *relativePath) { |
38 SkString result(rootPath); | 41 SkString result(rootPath); |
39 if (!result.endsWith(SkPATH_SEPARATOR)) { | 42 if (!result.endsWith(SkPATH_SEPARATOR)) { |
40 result.appendUnichar(SkPATH_SEPARATOR); | 43 result.appendUnichar(SkPATH_SEPARATOR); |
41 } | 44 } |
42 result.append(relativePath); | 45 result.append(relativePath); |
43 return result; | 46 return result; |
44 } | 47 } |
45 | 48 |
46 // TODO(epoger): This currently assumes that the result SkHashDigest was | |
47 // generated as an SkHashDigest of an SkBitmap. We'll need to allow for oth
er | |
48 // hash types to cover non-bitmaps. | |
49 Json::Value ActualResultAsJsonValue(const SkHashDigest& result) { | |
50 Json::Value jsonValue; | |
51 jsonValue[kJsonKey_ActualResults_AnyStatus_BitmapHash] = asJsonValue(res
ult); | |
52 return jsonValue; | |
53 } | |
54 | |
55 Json::Value CreateJsonTree(Json::Value expectedResults, | 49 Json::Value CreateJsonTree(Json::Value expectedResults, |
56 Json::Value actualResultsFailed, | 50 Json::Value actualResultsFailed, |
57 Json::Value actualResultsFailureIgnored, | 51 Json::Value actualResultsFailureIgnored, |
58 Json::Value actualResultsNoComparison, | 52 Json::Value actualResultsNoComparison, |
59 Json::Value actualResultsSucceeded) { | 53 Json::Value actualResultsSucceeded) { |
60 Json::Value actualResults; | 54 Json::Value actualResults; |
61 actualResults[kJsonKey_ActualResults_Failed] = actualResultsFailed; | 55 actualResults[kJsonKey_ActualResults_Failed] = actualResultsFailed; |
62 actualResults[kJsonKey_ActualResults_FailureIgnored] = actualResultsFail
ureIgnored; | 56 actualResults[kJsonKey_ActualResults_FailureIgnored] = actualResultsFail
ureIgnored; |
63 actualResults[kJsonKey_ActualResults_NoComparison] = actualResultsNoComp
arison; | 57 actualResults[kJsonKey_ActualResults_NoComparison] = actualResultsNoComp
arison; |
64 actualResults[kJsonKey_ActualResults_Succeeded] = actualResultsSucceeded
; | 58 actualResults[kJsonKey_ActualResults_Succeeded] = actualResultsSucceeded
; |
65 Json::Value root; | 59 Json::Value root; |
66 root[kJsonKey_ActualResults] = actualResults; | 60 root[kJsonKey_ActualResults] = actualResults; |
67 root[kJsonKey_ExpectedResults] = expectedResults; | 61 root[kJsonKey_ExpectedResults] = expectedResults; |
68 return root; | 62 return root; |
69 } | 63 } |
70 | 64 |
71 | 65 |
| 66 // GmResultDigest class... |
| 67 |
| 68 GmResultDigest::GmResultDigest(const SkBitmap &bitmap) { |
| 69 fIsValid = SkBitmapHasher::ComputeDigest(bitmap, &fHashDigest); |
| 70 } |
| 71 |
| 72 GmResultDigest::GmResultDigest(const Json::Value &jsonTypeValuePair) { |
| 73 fIsValid = false; |
| 74 if (!jsonTypeValuePair.isArray()) { |
| 75 gm_fprintf(stderr, "found non-array json value when parsing GmResult
Digest: %s\n", |
| 76 jsonTypeValuePair.toStyledString().c_str()); |
| 77 DEBUGFAIL_SEE_STDERR; |
| 78 } else if (2 != jsonTypeValuePair.size()) { |
| 79 gm_fprintf(stderr, "found json array with wrong size when parsing Gm
ResultDigest: %s\n", |
| 80 jsonTypeValuePair.toStyledString().c_str()); |
| 81 DEBUGFAIL_SEE_STDERR; |
| 82 } else { |
| 83 // TODO(epoger): The current implementation assumes that the |
| 84 // result digest is always of type kJsonKey_Hashtype_Bitmap_64bitMD5 |
| 85 Json::Value jsonHashValue = jsonTypeValuePair[1]; |
| 86 if (!jsonHashValue.isIntegral()) { |
| 87 gm_fprintf(stderr, |
| 88 "found non-integer jsonHashValue when parsing GmResul
tDigest: %s\n", |
| 89 jsonTypeValuePair.toStyledString().c_str()); |
| 90 DEBUGFAIL_SEE_STDERR; |
| 91 } else { |
| 92 fHashDigest = jsonHashValue.asUInt64(); |
| 93 fIsValid = true; |
| 94 } |
| 95 } |
| 96 } |
| 97 |
| 98 bool GmResultDigest::isValid() const { |
| 99 return fIsValid; |
| 100 } |
| 101 |
| 102 bool GmResultDigest::equals(const GmResultDigest &other) const { |
| 103 // TODO(epoger): The current implementation assumes that this |
| 104 // and other are always of type kJsonKey_Hashtype_Bitmap_64bitMD5 |
| 105 return (this->fIsValid && other.fIsValid && (this->fHashDigest == other.
fHashDigest)); |
| 106 } |
| 107 |
| 108 Json::Value GmResultDigest::asJsonTypeValuePair() const { |
| 109 // TODO(epoger): The current implementation assumes that the |
| 110 // result digest is always of type kJsonKey_Hashtype_Bitmap_64bitMD5 |
| 111 Json::Value jsonTypeValuePair; |
| 112 if (fIsValid) { |
| 113 jsonTypeValuePair.append(Json::Value(kJsonKey_Hashtype_Bitmap_64bitM
D5)); |
| 114 jsonTypeValuePair.append(Json::UInt64(fHashDigest)); |
| 115 } else { |
| 116 jsonTypeValuePair.append(Json::Value("INVALID")); |
| 117 } |
| 118 return jsonTypeValuePair; |
| 119 } |
| 120 |
| 121 |
72 // Expectations class... | 122 // Expectations class... |
73 | 123 |
74 Expectations::Expectations(bool ignoreFailure) { | 124 Expectations::Expectations(bool ignoreFailure) { |
75 fIgnoreFailure = ignoreFailure; | 125 fIgnoreFailure = ignoreFailure; |
76 } | 126 } |
77 | 127 |
78 Expectations::Expectations(const SkBitmap& bitmap, bool ignoreFailure) { | 128 Expectations::Expectations(const SkBitmap& bitmap, bool ignoreFailure) { |
79 fBitmap = bitmap; | 129 fBitmap = bitmap; |
80 fIgnoreFailure = ignoreFailure; | 130 fIgnoreFailure = ignoreFailure; |
81 SkHashDigest digest; | 131 fAllowedResultDigests.push_back(GmResultDigest(bitmap)); |
82 // TODO(epoger): Better handling for error returned by ComputeDigest()? | |
83 // For now, we just report a digest of 0 in error cases, like before. | |
84 if (!SkBitmapHasher::ComputeDigest(bitmap, &digest)) { | |
85 digest = 0; | |
86 } | |
87 fAllowedBitmapChecksums.push_back() = digest; | |
88 } | 132 } |
89 | 133 |
90 Expectations::Expectations(Json::Value jsonElement) { | 134 Expectations::Expectations(Json::Value jsonElement) { |
91 if (jsonElement.empty()) { | 135 if (jsonElement.empty()) { |
92 fIgnoreFailure = kDefaultIgnoreFailure; | 136 fIgnoreFailure = kDefaultIgnoreFailure; |
93 } else { | 137 } else { |
94 Json::Value ignoreFailure = jsonElement[kJsonKey_ExpectedResults_Ign
oreFailure]; | 138 Json::Value ignoreFailure = jsonElement[kJsonKey_ExpectedResults_Ign
oreFailure]; |
95 if (ignoreFailure.isNull()) { | 139 if (ignoreFailure.isNull()) { |
96 fIgnoreFailure = kDefaultIgnoreFailure; | 140 fIgnoreFailure = kDefaultIgnoreFailure; |
97 } else if (!ignoreFailure.isBool()) { | 141 } else if (!ignoreFailure.isBool()) { |
98 gm_fprintf(stderr, "found non-boolean json value" | 142 gm_fprintf(stderr, "found non-boolean json value" |
99 " for key '%s' in element '%s'\n", | 143 " for key '%s' in element '%s'\n", |
100 kJsonKey_ExpectedResults_IgnoreFailure, | 144 kJsonKey_ExpectedResults_IgnoreFailure, |
101 jsonElement.toStyledString().c_str()); | 145 jsonElement.toStyledString().c_str()); |
102 DEBUGFAIL_SEE_STDERR; | 146 DEBUGFAIL_SEE_STDERR; |
103 fIgnoreFailure = kDefaultIgnoreFailure; | 147 fIgnoreFailure = kDefaultIgnoreFailure; |
104 } else { | 148 } else { |
105 fIgnoreFailure = ignoreFailure.asBool(); | 149 fIgnoreFailure = ignoreFailure.asBool(); |
106 } | 150 } |
107 | 151 |
108 Json::Value allowedChecksums = | 152 Json::Value allowedDigests = jsonElement[kJsonKey_ExpectedResults_Al
lowedDigests]; |
109 jsonElement[kJsonKey_ExpectedResults_AllowedBitmapHashes]; | 153 if (allowedDigests.isNull()) { |
110 if (allowedChecksums.isNull()) { | 154 // ok, we'll just assume there aren't any AllowedDigests to comp
are against |
111 // ok, we'll just assume there aren't any expected checksums to
compare against | 155 } else if (!allowedDigests.isArray()) { |
112 } else if (!allowedChecksums.isArray()) { | |
113 gm_fprintf(stderr, "found non-array json value" | 156 gm_fprintf(stderr, "found non-array json value" |
114 " for key '%s' in element '%s'\n", | 157 " for key '%s' in element '%s'\n", |
115 kJsonKey_ExpectedResults_AllowedBitmapHashes, | 158 kJsonKey_ExpectedResults_AllowedDigests, |
116 jsonElement.toStyledString().c_str()); | 159 jsonElement.toStyledString().c_str()); |
117 DEBUGFAIL_SEE_STDERR; | 160 DEBUGFAIL_SEE_STDERR; |
118 } else { | 161 } else { |
119 for (Json::ArrayIndex i=0; i<allowedChecksums.size(); i++) { | 162 for (Json::ArrayIndex i=0; i<allowedDigests.size(); i++) { |
120 Json::Value checksumElement = allowedChecksums[i]; | 163 fAllowedResultDigests.push_back(GmResultDigest(allowedDigest
s[i])); |
121 if (!checksumElement.isIntegral()) { | |
122 gm_fprintf(stderr, "found non-integer checksum" | |
123 " in json element '%s'\n", | |
124 jsonElement.toStyledString().c_str()); | |
125 DEBUGFAIL_SEE_STDERR; | |
126 } else { | |
127 fAllowedBitmapChecksums.push_back() = asChecksum(checksu
mElement); | |
128 } | |
129 } | 164 } |
130 } | 165 } |
131 } | 166 } |
132 } | 167 } |
133 | 168 |
134 bool Expectations::match(Checksum actualChecksum) const { | 169 bool Expectations::match(GmResultDigest actualGmResultDigest) const { |
135 for (int i=0; i < this->fAllowedBitmapChecksums.count(); i++) { | 170 for (int i=0; i < this->fAllowedResultDigests.count(); i++) { |
136 Checksum allowedChecksum = this->fAllowedBitmapChecksums[i]; | 171 GmResultDigest allowedResultDigest = this->fAllowedResultDigests[i]; |
137 if (allowedChecksum == actualChecksum) { | 172 if (allowedResultDigest.equals(actualGmResultDigest)) { |
138 return true; | 173 return true; |
139 } | 174 } |
140 } | 175 } |
141 return false; | 176 return false; |
142 } | 177 } |
143 | 178 |
144 Json::Value Expectations::asJsonValue() const { | 179 Json::Value Expectations::asJsonValue() const { |
145 Json::Value allowedChecksumArray; | 180 Json::Value allowedDigestArray; |
146 if (!this->fAllowedBitmapChecksums.empty()) { | 181 if (!this->fAllowedResultDigests.empty()) { |
147 for (int i=0; i < this->fAllowedBitmapChecksums.count(); i++) { | 182 for (int i=0; i < this->fAllowedResultDigests.count(); i++) { |
148 Checksum allowedChecksum = this->fAllowedBitmapChecksums[i]; | 183 allowedDigestArray.append(this->fAllowedResultDigests[i].asJsonT
ypeValuePair()); |
149 allowedChecksumArray.append(Json::UInt64(allowedChecksum)); | |
150 } | 184 } |
151 } | 185 } |
152 | 186 |
153 Json::Value jsonValue; | 187 Json::Value jsonExpectations; |
154 jsonValue[kJsonKey_ExpectedResults_AllowedBitmapHashes] = allowedChecksu
mArray; | 188 jsonExpectations[kJsonKey_ExpectedResults_AllowedDigests] = allowedDiges
tArray; |
155 jsonValue[kJsonKey_ExpectedResults_IgnoreFailure] = this->ignoreFailure(
); | 189 jsonExpectations[kJsonKey_ExpectedResults_IgnoreFailure] = this->ignore
Failure(); |
156 return jsonValue; | 190 return jsonExpectations; |
157 } | 191 } |
158 | 192 |
159 | 193 |
160 // IndividualImageExpectationsSource class... | 194 // IndividualImageExpectationsSource class... |
161 | 195 |
162 Expectations IndividualImageExpectationsSource::get(const char *testName) { | 196 Expectations IndividualImageExpectationsSource::get(const char *testName) { |
163 SkString path = SkPathJoin(fRootDir.c_str(), testName); | 197 SkString path = SkPathJoin(fRootDir.c_str(), testName); |
164 SkBitmap referenceBitmap; | 198 SkBitmap referenceBitmap; |
165 bool decodedReferenceBitmap = | 199 bool decodedReferenceBitmap = |
166 SkImageDecoder::DecodeFile(path.c_str(), &referenceBitmap, | 200 SkImageDecoder::DecodeFile(path.c_str(), &referenceBitmap, |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
224 Json::Reader reader; | 258 Json::Reader reader; |
225 if (!reader.parse(bytes, bytes+size, *jsonRoot)) { | 259 if (!reader.parse(bytes, bytes+size, *jsonRoot)) { |
226 gm_fprintf(stderr, "error parsing JSON file %s\n", jsonPath); | 260 gm_fprintf(stderr, "error parsing JSON file %s\n", jsonPath); |
227 DEBUGFAIL_SEE_STDERR; | 261 DEBUGFAIL_SEE_STDERR; |
228 return false; | 262 return false; |
229 } | 263 } |
230 return true; | 264 return true; |
231 } | 265 } |
232 | 266 |
233 } | 267 } |
OLD | NEW |