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 "third_party/WebKit/public/platform/WebData.h"
     15 #include "third_party/WebKit/public/platform/WebImage.h"
     16 #include "third_party/WebKit/public/platform/WebSize.h"
     17 #include "third_party/WebKit/public/web/WebImageDecoder.h"
     18 
     19 using base::Time;
     20 
     21 namespace {
     22 
     23 const int kFirstFrameIndex = 0;
     24 
     25 // Determine if we should test with file specified by |path| based
     26 // on |file_selection| and the |threshold| for the file size.
     27 bool ShouldSkipFile(const base::FilePath& path,
     28                     ImageDecoderTestFileSelection file_selection,
     29                     const int64 threshold) {
     30   if (file_selection == TEST_ALL)
     31     return false;
     32 
     33   int64 image_size = 0;
     34   file_util::GetFileSize(path, &image_size);
     35   return (file_selection == TEST_SMALLER) == (image_size > threshold);
     36 }
     37 
     38 }  // namespace
     39 
     40 void ReadFileToVector(const base::FilePath& path, std::vector<char>* contents) {
     41   std::string raw_image_data;
     42   file_util::ReadFileToString(path, &raw_image_data);
     43   contents->resize(raw_image_data.size());
     44   memcpy(&contents->at(0), raw_image_data.data(), raw_image_data.size());
     45 }
     46 
     47 base::FilePath GetMD5SumPath(const base::FilePath& path) {
     48   static const base::FilePath::StringType kDecodedDataExtension(
     49       FILE_PATH_LITERAL(".md5sum"));
     50   return base::FilePath(path.value() + kDecodedDataExtension);
     51 }
     52 
     53 #if defined(CALCULATE_MD5_SUMS)
     54 void SaveMD5Sum(const base::FilePath& path, const WebKit::WebImage& web_image) {
     55   // Calculate MD5 sum.
     56   base::MD5Digest digest;
     57   web_image.getSkBitmap().lockPixels();
     58   base::MD5Sum(web_image.getSkBitmap().getPixels(),
     59          web_image.getSkBitmap().width() * web_image.getSkBitmap().height() *
     60          sizeof(uint32_t),
     61          &digest);
     62 
     63   // Write sum to disk.
     64   int bytes_written = file_util::WriteFile(path,
     65       reinterpret_cast<const char*>(&digest), sizeof digest);
     66   ASSERT_EQ(sizeof digest, bytes_written);
     67   web_image.getSkBitmap().unlockPixels();
     68 }
     69 #endif
     70 
     71 #if !defined(CALCULATE_MD5_SUMS)
     72 void VerifyImage(const WebKit::WebImageDecoder& decoder,
     73                  const base::FilePath& path,
     74                  const base::FilePath& md5_sum_path,
     75                  size_t frame_index) {
     76   // Make sure decoding can complete successfully.
     77   EXPECT_TRUE(decoder.isSizeAvailable()) << path.value();
     78   EXPECT_GE(decoder.frameCount(), frame_index) << path.value();
     79   EXPECT_TRUE(decoder.isFrameCompleteAtIndex(frame_index)) << path.value();
     80   EXPECT_FALSE(decoder.isFailed());
     81 
     82   // Calculate MD5 sum.
     83   base::MD5Digest actual_digest;
     84   WebKit::WebImage web_image = decoder.getFrameAtIndex(frame_index);
     85   web_image.getSkBitmap().lockPixels();
     86   base::MD5Sum(web_image.getSkBitmap().getPixels(),
     87          web_image.getSkBitmap().width() * web_image.getSkBitmap().height() *
     88          sizeof(uint32_t),
     89          &actual_digest);
     90 
     91   // Read the MD5 sum off disk.
     92   std::string file_bytes;
     93   file_util::ReadFileToString(md5_sum_path, &file_bytes);
     94   base::MD5Digest expected_digest;
     95   ASSERT_EQ(sizeof expected_digest, file_bytes.size()) << path.value();
     96   memcpy(&expected_digest, file_bytes.data(), sizeof expected_digest);
     97 
     98   // Verify that the sums are the same.
     99   EXPECT_EQ(0,
    100             memcmp(&expected_digest, &actual_digest, sizeof(base::MD5Digest)))
    101     << path.value();
    102   web_image.getSkBitmap().unlockPixels();
    103 }
    104 #endif
    105 
    106 void ImageDecoderTest::SetUp() {
    107   base::FilePath data_dir;
    108   ASSERT_TRUE(PathService::Get(base::DIR_SOURCE_ROOT, &data_dir));
    109   data_dir_ = data_dir.AppendASCII("webkit").
    110                        AppendASCII("data").
    111                        AppendASCII(format_ + "_decoder");
    112   if (!base::PathExists(data_dir_)) {
    113     const testing::TestInfo* const test_info =
    114         testing::UnitTest::GetInstance()->current_test_info();
    115     LOG(INFO) << 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 
    125   base::FileEnumerator enumerator(data_dir_,
    126                                   false,
    127                                   base::FileEnumerator::FILES);
    128 
    129   std::vector<base::FilePath> image_files;
    130   base::FilePath next_file_name;
    131   while (!(next_file_name = enumerator.Next()).empty()) {
    132     base::FilePath base_name = next_file_name.BaseName();
    133 #if defined(OS_WIN)
    134     std::string base_name_ascii = WideToASCII(base_name.value());
    135 #else
    136     std::string base_name_ascii = base_name.value();
    137 #endif
    138     if (!MatchPattern(base_name_ascii, pattern))
    139       continue;
    140     image_files.push_back(next_file_name);
    141   }
    142 
    143   return image_files;
    144 }
    145 
    146 bool ImageDecoderTest::ShouldImageFail(const base::FilePath& path) const {
    147   const base::FilePath::StringType kBadSuffix(FILE_PATH_LITERAL(".bad."));
    148   return (path.value().length() > (kBadSuffix.length() + format_.length()) &&
    149           !path.value().compare(path.value().length() - format_.length() -
    150                                     kBadSuffix.length(),
    151                                 kBadSuffix.length(), kBadSuffix));
    152 }
    153 
    154 void ImageDecoderTest::TestDecoding(
    155     ImageDecoderTestFileSelection file_selection,
    156     const int64 threshold) {
    157   if (data_dir_.empty())
    158     return;
    159   const std::vector<base::FilePath> image_files(GetImageFiles());
    160   for (std::vector<base::FilePath>::const_iterator i = image_files.begin();
    161        i != image_files.end(); ++i) {
    162     if (ShouldSkipFile(*i, file_selection, threshold))
    163       continue;
    164     const base::FilePath md5_sum_path(GetMD5SumPath(*i));
    165     TestWebKitImageDecoder(*i, md5_sum_path, kFirstFrameIndex);
    166   }
    167 }
    168 
    169 void  ImageDecoderTest::TestWebKitImageDecoder(const base::FilePath& image_path,
    170   const base::FilePath& md5_sum_path, int desired_frame_index) const {
    171   bool should_test_chunking = true;
    172   bool should_test_failed_images = true;
    173 #ifdef CALCULATE_MD5_SUMS
    174     // Do not test anything just get the md5 sums.
    175     should_test_chunking = false;
    176     should_test_failed_images = false;
    177 #endif
    178 
    179   std::vector<char> image_contents;
    180   ReadFileToVector(image_path, &image_contents);
    181   EXPECT_TRUE(image_contents.size());
    182   scoped_ptr<WebKit::WebImageDecoder> decoder(CreateWebKitImageDecoder());
    183   EXPECT_FALSE(decoder->isFailed());
    184 
    185   if (should_test_chunking) {
    186     // Test chunking file into half.
    187     const int partial_size = image_contents.size()/2;
    188 
    189     WebKit::WebData partial_data(
    190       reinterpret_cast<const char*>(&(image_contents.at(0))), partial_size);
    191 
    192     // Make Sure the image decoder doesn't fail when we ask for the frame
    193     // buffer for this partial image.
    194     // NOTE: We can't check that frame 0 is non-NULL, because if this is an
    195     // ICO and we haven't yet supplied enough data to read the directory,
    196     // there is no framecount and thus no first frame.
    197     decoder->setData(const_cast<WebKit::WebData&>(partial_data), false);
    198     EXPECT_FALSE(decoder->isFailed()) << image_path.value();
    199   }
    200 
    201   // Make sure passing the complete image results in successful decoding.
    202   WebKit::WebData data(reinterpret_cast<const char*>(&(image_contents.at(0))),
    203     image_contents.size());
    204   decoder->setData(const_cast<WebKit::WebData&>(data), true);
    205 
    206   if (should_test_failed_images) {
    207     if (ShouldImageFail(image_path)) {
    208       EXPECT_FALSE(decoder->isFrameCompleteAtIndex(kFirstFrameIndex));
    209       EXPECT_TRUE(decoder->isFailed());
    210          return;
    211     }
    212   }
    213 
    214   EXPECT_FALSE(decoder->isFailed()) << image_path.value();
    215 
    216 #ifdef CALCULATE_MD5_SUMS
    217   // Since WebImage does not expose get data by frame, get the size
    218   // through decoder and pass it to fromData so that the closest
    219   // image dats to the size is returned.
    220   WebKit::WebSize size(decoder->getImage(desired_frame_index).size());
    221   const WebKit::WebImage& image = WebKit::WebImage::fromData(data, size);
    222   SaveMD5Sum(md5_sum_path, image);
    223 #else
    224   VerifyImage(*decoder, image_path, md5_sum_path, desired_frame_index);
    225 #endif
    226 }
    227