OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2011 Google Inc. | 2 * Copyright 2011 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 "SkBitmap.h" | 9 #include "SkBitmap.h" |
10 #include "SkColorPriv.h" | 10 #include "SkColorPriv.h" |
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
86 if (dot != NULL) { | 86 if (dot != NULL) { |
87 int32_t index = SkToS32(dot - cstyleDst); | 87 int32_t index = SkToS32(dot - cstyleDst); |
88 dst->remove(index, dst->size() - index); | 88 dst->remove(index, dst->size() - index); |
89 } | 89 } |
90 dst->append(suffix); | 90 dst->append(suffix); |
91 } | 91 } |
92 } | 92 } |
93 | 93 |
94 // Store the names of the filenames to report later which ones failed, succeeded
, and were | 94 // Store the names of the filenames to report later which ones failed, succeeded
, and were |
95 // invalid. | 95 // invalid. |
| 96 // FIXME: Add more arrays, for more specific types of errors, and make the outpu
t simpler. |
| 97 // If each array holds one type of error, the output can change from: |
| 98 // |
| 99 // Failures: |
| 100 // <image> failed for such and such reason |
| 101 // <image> failed for some different reason |
| 102 // |
| 103 // to: |
| 104 // |
| 105 // Such and such failures: |
| 106 // <image> |
| 107 // |
| 108 // Different reason failures: |
| 109 // <image> |
| 110 // |
96 static SkTArray<SkString, false> gInvalidStreams; | 111 static SkTArray<SkString, false> gInvalidStreams; |
97 static SkTArray<SkString, false> gMissingCodecs; | 112 static SkTArray<SkString, false> gMissingCodecs; |
98 static SkTArray<SkString, false> gDecodeFailures; | 113 static SkTArray<SkString, false> gDecodeFailures; |
99 static SkTArray<SkString, false> gEncodeFailures; | 114 static SkTArray<SkString, false> gEncodeFailures; |
100 static SkTArray<SkString, false> gSuccessfulDecodes; | 115 static SkTArray<SkString, false> gSuccessfulDecodes; |
101 static SkTArray<SkString, false> gSuccessfulSubsetDecodes; | 116 static SkTArray<SkString, false> gSuccessfulSubsetDecodes; |
102 static SkTArray<SkString, false> gFailedSubsetDecodes; | 117 static SkTArray<SkString, false> gFailedSubsetDecodes; |
103 // Files/subsets that do not have expectations. Not reported as a failure of the
test so | 118 // Files/subsets that do not have expectations. Not reported as a failure of the
test so |
104 // the bots will not turn red with each new image test. | 119 // the bots will not turn red with each new image test. |
105 static SkTArray<SkString, false> gMissingExpectations; | 120 static SkTArray<SkString, false> gMissingExpectations; |
106 static SkTArray<SkString, false> gMissingSubsetExpectations; | 121 static SkTArray<SkString, false> gMissingSubsetExpectations; |
| 122 // For files that are expected to fail. |
| 123 static SkTArray<SkString, false> gKnownFailures; |
| 124 static SkTArray<SkString, false> gKnownSubsetFailures; |
107 | 125 |
108 static SkBitmap::Config gPrefConfig(SkBitmap::kNo_Config); | 126 static SkBitmap::Config gPrefConfig(SkBitmap::kNo_Config); |
109 | 127 |
110 // Expections read from a file specified by readExpectationsPath. The expectatio
ns must have been | 128 // Expections read from a file specified by readExpectationsPath. The expectatio
ns must have been |
111 // previously written using createExpectationsPath. | 129 // previously written using createExpectationsPath. |
112 SkAutoTUnref<skiagm::JsonExpectationsSource> gJsonExpectations; | 130 SkAutoTUnref<skiagm::JsonExpectationsSource> gJsonExpectations; |
113 | 131 |
114 static bool write_bitmap(const char outName[], const SkBitmap& bm) { | 132 static bool write_bitmap(const char outName[], const SkBitmap& bm) { |
115 if (SkImageEncoder::EncodeFile(outName, bm, SkImageEncoder::kPNG_Type, 100))
{ | 133 if (SkImageEncoder::EncodeFile(outName, bm, SkImageEncoder::kPNG_Type, 100))
{ |
116 return true; | 134 return true; |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
181 static void write_expectations(const SkBitmap& bitmap, const char* filename) { | 199 static void write_expectations(const SkBitmap& bitmap, const char* filename) { |
182 if (!FLAGS_createExpectationsPath.isEmpty()) { | 200 if (!FLAGS_createExpectationsPath.isEmpty()) { |
183 // Creates an Expectations object, and add it to the list to write. | 201 // Creates an Expectations object, and add it to the list to write. |
184 skiagm::Expectations expectation(bitmap); | 202 skiagm::Expectations expectation(bitmap); |
185 Json::Value value = expectation.asJsonValue(); | 203 Json::Value value = expectation.asJsonValue(); |
186 gExpectationsToWrite[filename] = value; | 204 gExpectationsToWrite[filename] = value; |
187 } | 205 } |
188 } | 206 } |
189 | 207 |
190 /** | 208 /** |
191 * Return true if this filename is a known failure, and therefore a failure | |
192 * to decode should be ignored. | |
193 */ | |
194 static bool expect_to_fail(const char* filename) { | |
195 if (NULL == gJsonExpectations.get()) { | |
196 return false; | |
197 } | |
198 skiagm::Expectations jsExpectations = gJsonExpectations->get(filename); | |
199 return jsExpectations.ignoreFailure(); | |
200 } | |
201 | |
202 /** | |
203 * Compare against an expectation for this filename, if there is one. | 209 * Compare against an expectation for this filename, if there is one. |
204 * @param digest GmResultDigest, computed from the decoded bitmap, to compare t
o the | 210 * @param digest GmResultDigest, computed from the decoded bitmap, to compare t
o the |
205 * expectation. | 211 * expectation. |
206 * @param filename String used to find the expected value. | 212 * @param filename String used to find the expected value. |
207 * @param failureArray Array to add a failure message to on failure. | 213 * @param failureArray Array to add a failure message to on failure. |
208 * @param missingArray Array to add missing expectation to on failure. | 214 * @param missingArray Array to add failure message to when missing image |
| 215 * expectation. |
| 216 * @param ignoreArray Array to add failure message to when the image does not m
atch |
| 217 * the expectation, but this is a failure we can ignore. |
209 * @return bool True in any of these cases: | 218 * @return bool True in any of these cases: |
210 * - the bitmap matches the expectation. | 219 * - the bitmap matches the expectation. |
211 * False in any of these cases: | 220 * False in any of these cases: |
212 * - there is no expectations file. | 221 * - there is no expectations file. |
213 * - there is an expectations file, but no expectation for this
bitmap. | 222 * - there is an expectations file, but no expectation for this
bitmap. |
214 * - there is an expectation for this bitmap, but it did not ma
tch. | 223 * - there is an expectation for this bitmap, but it did not ma
tch. |
215 * - expectation could not be computed from the bitmap. | 224 * - expectation could not be computed from the bitmap. |
216 */ | 225 */ |
217 static bool compare_to_expectations_if_necessary(const skiagm::GmResultDigest& d
igest, | 226 static bool compare_to_expectations_if_necessary(const skiagm::GmResultDigest& d
igest, |
218 const char* filename, | 227 const char* filename, |
219 SkTArray<SkString, false>* fail
ureArray, | 228 SkTArray<SkString, false>* fail
ureArray, |
220 SkTArray<SkString, false>* miss
ingArray) { | 229 SkTArray<SkString, false>* miss
ingArray, |
| 230 SkTArray<SkString, false>* igno
reArray) { |
221 if (!digest.isValid()) { | 231 if (!digest.isValid()) { |
222 if (failureArray != NULL) { | 232 if (failureArray != NULL) { |
223 failureArray->push_back().printf("decoded %s, but could not create a
GmResultDigest.", | 233 failureArray->push_back().printf("decoded %s, but could not create a
GmResultDigest.", |
224 filename); | 234 filename); |
225 } | 235 } |
226 return false; | 236 return false; |
227 } | 237 } |
228 | 238 |
229 if (NULL == gJsonExpectations.get()) { | 239 if (NULL == gJsonExpectations.get()) { |
230 return false; | 240 return false; |
231 } | 241 } |
232 | 242 |
233 skiagm::Expectations jsExpectation = gJsonExpectations->get(filename); | 243 skiagm::Expectations jsExpectation = gJsonExpectations->get(filename); |
234 if (jsExpectation.empty()) { | 244 if (jsExpectation.empty()) { |
235 if (missingArray != NULL) { | 245 if (missingArray != NULL) { |
236 missingArray->push_back().printf("decoded %s, but could not find exp
ectation.", | 246 missingArray->push_back().printf("decoded %s, but could not find exp
ectation.", |
237 filename); | 247 filename); |
238 } | 248 } |
239 return false; | 249 return false; |
240 } | 250 } |
241 | 251 |
242 if (jsExpectation.match(digest)) { | 252 if (jsExpectation.match(digest)) { |
243 return true; | 253 return true; |
244 } | 254 } |
245 | 255 |
246 if (failureArray != NULL) { | 256 if (jsExpectation.ignoreFailure()) { |
| 257 ignoreArray->push_back().printf("%s does not match expectation, but this
is known.", |
| 258 filename); |
| 259 } else if (failureArray != NULL) { |
247 failureArray->push_back().printf("decoded %s, but the result does not ma
tch " | 260 failureArray->push_back().printf("decoded %s, but the result does not ma
tch " |
248 "expectations.", | 261 "expectations.", |
249 filename); | 262 filename); |
250 } | 263 } |
251 return false; | 264 return false; |
252 } | 265 } |
253 | 266 |
254 /** | 267 /** |
255 * Helper function to write a bitmap subset to a file. Only called if subsets w
ere created | 268 * Helper function to write a bitmap subset to a file. Only called if subsets w
ere created |
256 * and a writePath was provided. Creates a subdirectory called 'subsets' and wr
ites a PNG to | 269 * and a writePath was provided. Creates a subdirectory called 'subsets' and wr
ites a PNG to |
(...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
403 codec->setSkipWritingZeroes(FLAGS_skip); | 416 codec->setSkipWritingZeroes(FLAGS_skip); |
404 codec->setSampleSize(FLAGS_sampleSize); | 417 codec->setSampleSize(FLAGS_sampleSize); |
405 stream.rewind(); | 418 stream.rewind(); |
406 | 419 |
407 // Create a string representing just the filename itself, for use in json ex
pectations. | 420 // Create a string representing just the filename itself, for use in json ex
pectations. |
408 SkString basename = SkOSPath::SkBasename(srcPath); | 421 SkString basename = SkOSPath::SkBasename(srcPath); |
409 const char* filename = basename.c_str(); | 422 const char* filename = basename.c_str(); |
410 | 423 |
411 if (!codec->decode(&stream, &bitmap, gPrefConfig, | 424 if (!codec->decode(&stream, &bitmap, gPrefConfig, |
412 SkImageDecoder::kDecodePixels_Mode)) { | 425 SkImageDecoder::kDecodePixels_Mode)) { |
413 if (expect_to_fail(filename)) { | 426 if (NULL != gJsonExpectations.get()) { |
414 gSuccessfulDecodes.push_back().appendf( | 427 skiagm::Expectations jsExpectations = gJsonExpectations->get(filenam
e); |
415 "failed to decode %s, which is a known failure.", srcPath); | 428 if (jsExpectations.ignoreFailure()) { |
416 } else { | 429 // This is a known failure. |
417 gDecodeFailures.push_back().set(srcPath); | 430 gKnownFailures.push_back().appendf( |
| 431 "failed to decode %s, which is a known failure.", srcPath); |
| 432 return; |
| 433 } |
| 434 if (jsExpectations.empty()) { |
| 435 // This is a failure, but it is a new file. Mark it as missing,
with |
| 436 // a note that it should be marked failing. |
| 437 gMissingExpectations.push_back().appendf( |
| 438 "new file %s (with no expectations) FAILED to decode.", srcP
ath); |
| 439 return; |
| 440 } |
418 } | 441 } |
| 442 |
| 443 // If there was a failure, and either there was no expectations file, or |
| 444 // the expectations file listed a valid expectation, report the failure. |
| 445 gDecodeFailures.push_back().set(srcPath); |
419 return; | 446 return; |
420 } | 447 } |
421 | 448 |
422 // Test decoding just the bounds. The bounds should always match. | 449 // Test decoding just the bounds. The bounds should always match. |
423 { | 450 { |
424 stream.rewind(); | 451 stream.rewind(); |
425 SkBitmap dim; | 452 SkBitmap dim; |
426 if (!codec->decode(&stream, &dim, SkImageDecoder::kDecodeBounds_Mode)) { | 453 if (!codec->decode(&stream, &dim, SkImageDecoder::kDecodeBounds_Mode)) { |
427 SkString failure = SkStringPrintf("failed to decode bounds for %s",
srcPath); | 454 SkString failure = SkStringPrintf("failed to decode bounds for %s",
srcPath); |
428 gDecodeFailures.push_back() = failure; | 455 gDecodeFailures.push_back() = failure; |
429 } else { | 456 } else { |
430 // Now check that the bounds match: | 457 // Now check that the bounds match: |
431 if (dim.width() != bitmap.width() || dim.height() != bitmap.height()
) { | 458 if (dim.width() != bitmap.width() || dim.height() != bitmap.height()
) { |
432 SkString failure = SkStringPrintf("bounds do not match for %s",
srcPath); | 459 SkString failure = SkStringPrintf("bounds do not match for %s",
srcPath); |
433 gDecodeFailures.push_back() = failure; | 460 gDecodeFailures.push_back() = failure; |
434 } | 461 } |
435 } | 462 } |
436 } | 463 } |
437 | 464 |
438 skiagm::GmResultDigest digest(bitmap); | 465 skiagm::GmResultDigest digest(bitmap); |
439 if (compare_to_expectations_if_necessary(digest, filename, | 466 if (compare_to_expectations_if_necessary(digest, filename, |
440 &gDecodeFailures, | 467 &gDecodeFailures, |
441 &gMissingExpectations)) { | 468 &gMissingExpectations, |
| 469 &gKnownFailures)) { |
442 gSuccessfulDecodes.push_back().printf("%s [%d %d]", srcPath, bitmap.widt
h(), | 470 gSuccessfulDecodes.push_back().printf("%s [%d %d]", srcPath, bitmap.widt
h(), |
443 bitmap.height()); | 471 bitmap.height()); |
444 } else if (!FLAGS_mismatchPath.isEmpty()) { | 472 } else if (!FLAGS_mismatchPath.isEmpty()) { |
445 SkString outPath; | 473 SkString outPath; |
446 make_outname(&outPath, FLAGS_mismatchPath[0], srcPath, ".png"); | 474 make_outname(&outPath, FLAGS_mismatchPath[0], srcPath, ".png"); |
447 if (write_bitmap(outPath.c_str(), bitmap)) { | 475 if (write_bitmap(outPath.c_str(), bitmap)) { |
448 gSuccessfulDecodes.push_back().appendf("\twrote %s", outPath.c_str()
); | 476 gSuccessfulDecodes.push_back().appendf("\twrote %s", outPath.c_str()
); |
449 } else { | 477 } else { |
450 gEncodeFailures.push_back().set(outPath); | 478 gEncodeFailures.push_back().set(outPath); |
451 } | 479 } |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
484 // FIXME: Come up with a more representative set of rectangles. | 512 // FIXME: Come up with a more representative set of rectangles. |
485 SkIRect rect = generate_random_rect(&rand, width, height); | 513 SkIRect rect = generate_random_rect(&rand, width, height); |
486 SkString subsetDim = SkStringPrintf("[%d,%d,%d,%d]", rect.fLeft,
rect.fTop, | 514 SkString subsetDim = SkStringPrintf("[%d,%d,%d,%d]", rect.fLeft,
rect.fTop, |
487 rect.fRight, rect.fBottom); | 515 rect.fRight, rect.fBottom); |
488 if (codec->decodeSubset(&bitmapFromDecodeSubset, rect, gPrefConf
ig)) { | 516 if (codec->decodeSubset(&bitmapFromDecodeSubset, rect, gPrefConf
ig)) { |
489 SkString subsetName = SkStringPrintf("%s_%s", filename, subs
etDim.c_str()); | 517 SkString subsetName = SkStringPrintf("%s_%s", filename, subs
etDim.c_str()); |
490 skiagm::GmResultDigest subsetDigest(bitmapFromDecodeSubset); | 518 skiagm::GmResultDigest subsetDigest(bitmapFromDecodeSubset); |
491 if (compare_to_expectations_if_necessary(subsetDigest, | 519 if (compare_to_expectations_if_necessary(subsetDigest, |
492 subsetName.c_str(), | 520 subsetName.c_str(), |
493 &gFailedSubsetDecod
es, | 521 &gFailedSubsetDecod
es, |
494 &gMissingSubsetExpe
ctations)) { | 522 &gMissingSubsetExpe
ctations, |
| 523 &gKnownSubsetFailur
es)) { |
495 gSuccessfulSubsetDecodes.push_back().printf("Decoded sub
set %s from %s", | 524 gSuccessfulSubsetDecodes.push_back().printf("Decoded sub
set %s from %s", |
496 subsetDim.c_str(),
srcPath); | 525 subsetDim.c_str(),
srcPath); |
497 } else if (!FLAGS_mismatchPath.isEmpty()) { | 526 } else if (!FLAGS_mismatchPath.isEmpty()) { |
498 write_subset(FLAGS_mismatchPath[0], filename, subsetDim.
c_str(), | 527 write_subset(FLAGS_mismatchPath[0], filename, subsetDim.
c_str(), |
499 &bitmapFromDecodeSubset, rect, bitmap); | 528 &bitmapFromDecodeSubset, rect, bitmap); |
500 } | 529 } |
501 | 530 |
502 write_expectations(bitmapFromDecodeSubset, subsetName.c_str(
)); | 531 write_expectations(bitmapFromDecodeSubset, subsetName.c_str(
)); |
503 if (writePath != NULL) { | 532 if (writePath != NULL) { |
504 write_subset(writePath->c_str(), filename, subsetDim.c_s
tr(), | 533 write_subset(writePath->c_str(), filename, subsetDim.c_s
tr(), |
(...skipping 202 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
707 failed |= print_strings("Missing codec", gMissingCodecs); | 736 failed |= print_strings("Missing codec", gMissingCodecs); |
708 failed |= print_strings("Failed to decode", gDecodeFailures); | 737 failed |= print_strings("Failed to decode", gDecodeFailures); |
709 failed |= print_strings("Failed to encode", gEncodeFailures); | 738 failed |= print_strings("Failed to encode", gEncodeFailures); |
710 print_strings("Decoded", gSuccessfulDecodes); | 739 print_strings("Decoded", gSuccessfulDecodes); |
711 print_strings("Missing expectations", gMissingExpectations); | 740 print_strings("Missing expectations", gMissingExpectations); |
712 | 741 |
713 if (FLAGS_testSubsetDecoding) { | 742 if (FLAGS_testSubsetDecoding) { |
714 failed |= print_strings("Failed subset decodes", gFailedSubsetDecodes); | 743 failed |= print_strings("Failed subset decodes", gFailedSubsetDecodes); |
715 print_strings("Decoded subsets", gSuccessfulSubsetDecodes); | 744 print_strings("Decoded subsets", gSuccessfulSubsetDecodes); |
716 print_strings("Missing subset expectations", gMissingSubsetExpectations)
; | 745 print_strings("Missing subset expectations", gMissingSubsetExpectations)
; |
| 746 print_strings("Known subset failures", gKnownSubsetFailures); |
717 } | 747 } |
718 | 748 |
| 749 print_strings("Known failures", gKnownFailures); |
| 750 |
719 return failed ? -1 : 0; | 751 return failed ? -1 : 0; |
720 } | 752 } |
721 | 753 |
722 #if !defined SK_BUILD_FOR_IOS | 754 #if !defined SK_BUILD_FOR_IOS |
723 int main(int argc, char * const argv[]) { | 755 int main(int argc, char * const argv[]) { |
724 return tool_main(argc, (char**) argv); | 756 return tool_main(argc, (char**) argv); |
725 } | 757 } |
726 #endif | 758 #endif |
OLD | NEW |