| 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 |