Home | History | Annotate | Download | only in test
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "content/test/image_decoder_test.h"
      6 
      7 #include "base/file_util.h"
      8 #include "base/files/file_enumerator.h"
      9 #include "base/files/file_path.h"
     10 #include "base/md5.h"
     11 #include "base/memory/scoped_ptr.h"
     12 #include "base/path_service.h"
     13 #include "base/strings/string_util.h"
     14 #include "base/strings/utf_string_conversions.h"
     15 #include "third_party/WebKit/public/platform/WebData.h"
     16 #include "third_party/WebKit/public/platform/WebImage.h"
     17 #include "third_party/WebKit/public/platform/WebSize.h"
     18 #include "third_party/WebKit/public/web/WebImageDecoder.h"
     19 
     20 // Uncomment this to recalculate the MD5 sums; see header comments.
     21 // #define CALCULATE_MD5_SUMS
     22 
     23 namespace {
     24 
     25 const int kFirstFrameIndex = 0;
     26 
     27 // Determine if we should test with file specified by |path| based
     28 // on |file_selection| and the |threshold| for the file size.
     29 bool ShouldSkipFile(const base::FilePath& path,
     30                     ImageDecoderTestFileSelection file_selection,
     31                     const int64 threshold) {
     32   if (file_selection == TEST_ALL)
     33     return false;
     34 
     35   int64 image_size = 0;
     36   base::GetFileSize(path, &image_size);
     37   return (file_selection == TEST_SMALLER) == (image_size > threshold);
     38 }
     39 
     40 }  // namespace
     41 
     42 void ReadFileToVector(const base::FilePath& path, std::vector<char>* contents) {
     43   std::string raw_image_data;
     44   base::ReadFileToString(path, &raw_image_data);
     45   contents->resize(raw_image_data.size());
     46   memcpy(&contents->front(), raw_image_data.data(), raw_image_data.size());
     47 }
     48 
     49 base::FilePath GetMD5SumPath(const base::FilePath& path) {
     50   static const base::FilePath::StringType kDecodedDataExtension(
     51       FILE_PATH_LITERAL(".md5sum"));
     52   return base::FilePath(path.value() + kDecodedDataExtension);
     53 }
     54 
     55 #if defined(CALCULATE_MD5_SUMS)
     56 void SaveMD5Sum(const base::FilePath& path, const blink::WebImage& web_image) {
     57   // Calculate MD5 sum.
     58   base::MD5Digest digest;
     59   web_image.getSkBitmap().lockPixels();
     60   base::MD5Sum(web_image.getSkBitmap().getPixels(),
     61                web_image.getSkBitmap().width() *
     62                    web_image.getSkBitmap().height() * sizeof(uint32_t),
     63                &digest);
     64 
     65   // Write sum to disk.
     66   int bytes_written = base::WriteFile(
     67       path, reinterpret_cast<const char*>(&digest), sizeof digest);
     68   ASSERT_EQ(sizeof digest, bytes_written);
     69   web_image.getSkBitmap().unlockPixels();
     70 }
     71 #endif
     72 
     73 #if !defined(CALCULATE_MD5_SUMS)
     74 void VerifyImage(const blink::WebImageDecoder& decoder,
     75                  const base::FilePath& path,
     76                  const base::FilePath& md5_sum_path,
     77                  size_t frame_index) {
     78   // Make sure decoding can complete successfully.
     79   EXPECT_TRUE(decoder.isSizeAvailable()) << path.value();
     80   EXPECT_GE(decoder.frameCount(), frame_index) << path.value();
     81   EXPECT_TRUE(decoder.isFrameCompleteAtIndex(frame_index)) << path.value();
     82   EXPECT_FALSE(decoder.isFailed());
     83 
     84   // Calculate MD5 sum.
     85   base::MD5Digest actual_digest;
     86   blink::WebImage web_image = decoder.getFrameAtIndex(frame_index);
     87   web_image.getSkBitmap().lockPixels();
     88   base::MD5Sum(web_image.getSkBitmap().getPixels(),
     89                web_image.getSkBitmap().width() *
     90                    web_image.getSkBitmap().height() * sizeof(uint32_t),
     91                &actual_digest);
     92 
     93   // Read the MD5 sum off disk.
     94   std::string file_bytes;
     95   base::ReadFileToString(md5_sum_path, &file_bytes);
     96   base::MD5Digest expected_digest;
     97   ASSERT_EQ(sizeof expected_digest, file_bytes.size()) << path.value();
     98   memcpy(&expected_digest, file_bytes.data(), sizeof expected_digest);
     99 
    100   // Verify that the sums are the same.
    101   EXPECT_EQ(0, memcmp(&expected_digest, &actual_digest, sizeof actual_digest))
    102       << path.value();
    103   web_image.getSkBitmap().unlockPixels();
    104 }
    105 #endif
    106 
    107 void ImageDecoderTest::SetUp() {
    108   base::FilePath data_dir;
    109   ASSERT_TRUE(PathService::Get(base::DIR_SOURCE_ROOT, &data_dir));
    110   data_dir_ = data_dir.AppendASCII("webkit").AppendASCII("data").AppendASCII(
    111       format_ + "_decoder");
    112   if (!base::PathExists(data_dir_)) {
    113     const testing::TestInfo* const test_info =
    114         testing::UnitTest::GetInstance()->current_test_info();
    115     VLOG(0) << test_info->name()
    116             << " not running because test data wasn't found.";
    117     data_dir_.clear();
    118     return;
    119   }
    120 }
    121 
    122 std::vector<base::FilePath> ImageDecoderTest::GetImageFiles() const {
    123   std::string pattern = "*." + format_;
    124   base::FileEnumerator enumerator(data_dir_, false,
    125                                   base::FileEnumerator::FILES);
    126   std::vector<base::FilePath> image_files;
    127   for (base::FilePath next_file_name = enumerator.Next();
    128        !next_file_name.empty(); next_file_name = enumerator.Next()) {
    129     base::FilePath base_name = next_file_name.BaseName();
    130 #if defined(OS_WIN)
    131     std::string base_name_ascii = base::UTF16ToASCII(base_name.value());
    132 #else
    133     std::string base_name_ascii = base_name.value();
    134 #endif
    135     if (MatchPattern(base_name_ascii, pattern))
    136       image_files.push_back(next_file_name);
    137   }
    138 
    139   return image_files;
    140 }
    141 
    142 bool ImageDecoderTest::ShouldImageFail(const base::FilePath& path) const {
    143   const base::FilePath::StringType kBadSuffix(FILE_PATH_LITERAL(".bad."));
    144   return (path.value().length() > (kBadSuffix.length() + format_.length()) &&
    145           !path.value().compare(path.value().length() - format_.length() -
    146                                     kBadSuffix.length(),
    147                                 kBadSuffix.length(), kBadSuffix));
    148 }
    149 
    150 void ImageDecoderTest::TestDecoding(
    151     ImageDecoderTestFileSelection file_selection,
    152     const int64 threshold) {
    153   if (data_dir_.empty())
    154     return;
    155   const std::vector<base::FilePath> image_files(GetImageFiles());
    156   for (std::vector<base::FilePath>::const_iterator i = image_files.begin();
    157        i != image_files.end(); ++i) {
    158     if (!ShouldSkipFile(*i, file_selection, threshold))
    159       TestWebKitImageDecoder(*i, GetMD5SumPath(*i), kFirstFrameIndex);
    160   }
    161 }
    162 
    163 void ImageDecoderTest::TestWebKitImageDecoder(
    164     const base::FilePath& image_path,
    165     const base::FilePath& md5_sum_path,
    166     int desired_frame_index) const {
    167 #if defined(CALCULATE_MD5_SUMS)
    168   // If we're just calculating the MD5 sums, skip failing images quickly.
    169   if (ShouldImageFail(image_path))
    170     return;
    171 #endif
    172 
    173   std::vector<char> image_contents;
    174   ReadFileToVector(image_path, &image_contents);
    175   EXPECT_TRUE(image_contents.size());
    176   scoped_ptr<blink::WebImageDecoder> decoder(CreateWebKitImageDecoder());
    177   EXPECT_FALSE(decoder->isFailed());
    178 
    179 #if !defined(CALCULATE_MD5_SUMS)
    180   // Test chunking file into half.
    181   const int partial_size = image_contents.size()/2;
    182 
    183   blink::WebData partial_data(
    184     reinterpret_cast<const char*>(&(image_contents.at(0))), partial_size);
    185 
    186   // Make Sure the image decoder doesn't fail when we ask for the frame
    187   // buffer for this partial image.
    188   // NOTE: We can't check that frame 0 is non-NULL, because if this is an
    189   // ICO and we haven't yet supplied enough data to read the directory,
    190   // there is no framecount and thus no first frame.
    191   decoder->setData(const_cast<blink::WebData&>(partial_data), false);
    192   EXPECT_FALSE(decoder->isFailed()) << image_path.value();
    193 #endif
    194 
    195   // Make sure passing the complete image results in successful decoding.
    196   blink::WebData data(reinterpret_cast<const char*>(&(image_contents.at(0))),
    197     image_contents.size());
    198   decoder->setData(const_cast<blink::WebData&>(data), true);
    199   if (ShouldImageFail(image_path)) {
    200     EXPECT_FALSE(decoder->isFrameCompleteAtIndex(kFirstFrameIndex));
    201     EXPECT_TRUE(decoder->isFailed());
    202   } else {
    203     EXPECT_FALSE(decoder->isFailed()) << image_path.value();
    204 #if defined(CALCULATE_MD5_SUMS)
    205     SaveMD5Sum(md5_sum_path, decoder->getFrameAtIndex(desired_frame_index));
    206 #else
    207     VerifyImage(*decoder, image_path, md5_sum_path, desired_frame_index);
    208 #endif
    209   }
    210 }
    211