Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(545)

Side by Side Diff: ios/chrome/browser/webp_transcode/webp_decoder_unittest.mm

Issue 2521253002: Move ImageFetcher to its own target. (Closed)
Patch Set: Cleanup Created 4 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 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 "ios/chrome/browser/webp_transcode/webp_decoder.h"
6
7 #import <CoreGraphics/CoreGraphics.h>
8 #import <Foundation/Foundation.h>
9 #include <stddef.h>
10 #include <stdint.h>
11
12 #include <memory>
13
14 #include "base/base_paths.h"
15 #include "base/files/file_path.h"
16 #include "base/ios/ios_util.h"
17 #include "base/logging.h"
18 #include "base/mac/scoped_cftyperef.h"
19 #include "base/mac/scoped_nsobject.h"
20 #include "base/macros.h"
21 #include "base/memory/ref_counted.h"
22 #include "base/path_service.h"
23 #include "base/strings/sys_string_conversions.h"
24 #include "build/build_config.h"
25 #include "testing/gmock/include/gmock/gmock.h"
26 #include "testing/gtest/include/gtest/gtest.h"
27
28 namespace webp_transcode {
29 namespace {
30
31 class WebpDecoderDelegate : public WebpDecoder::Delegate {
32 public:
33 WebpDecoderDelegate() : image_([[NSMutableData alloc] init]) {}
34
35 NSData* GetImage() const { return image_; }
36
37 // WebpDecoder::Delegate methods.
38 MOCK_METHOD1(OnFinishedDecoding, void(bool success));
39 MOCK_METHOD2(SetImageFeatures,
40 void(size_t total_size, WebpDecoder::DecodedImageFormat format));
41 void OnDataDecoded(NSData* data) override { [image_ appendData:data]; }
42
43 private:
44 virtual ~WebpDecoderDelegate() {}
45
46 base::scoped_nsobject<NSMutableData> image_;
47 };
48
49 class WebpDecoderTest : public testing::Test {
50 public:
51 WebpDecoderTest()
52 : delegate_(new WebpDecoderDelegate),
53 decoder_(new WebpDecoder(delegate_.get())) {}
54
55 NSData* LoadImage(const base::FilePath& filename) {
56 base::FilePath path;
57 PathService::Get(base::DIR_SOURCE_ROOT, &path);
58 path = path.AppendASCII("ios/chrome/test/data/webp_transcode")
59 .Append(filename);
60 return
61 [NSData dataWithContentsOfFile:base::SysUTF8ToNSString(path.value())];
62 }
63
64 std::vector<uint8_t>* DecompressData(NSData* data,
65 WebpDecoder::DecodedImageFormat format) {
66 base::ScopedCFTypeRef<CGDataProviderRef> provider(
67 CGDataProviderCreateWithCFData((CFDataRef)data));
68 base::ScopedCFTypeRef<CGImageRef> image;
69 switch (format) {
70 case WebpDecoder::JPEG:
71 image.reset(CGImageCreateWithJPEGDataProvider(
72 provider, nullptr, false, kCGRenderingIntentDefault));
73 break;
74 case WebpDecoder::PNG:
75 image.reset(CGImageCreateWithPNGDataProvider(
76 provider, nullptr, false, kCGRenderingIntentDefault));
77 break;
78 case WebpDecoder::TIFF:
79 ADD_FAILURE() << "Data already decompressed";
80 return nil;
81 case WebpDecoder::DECODED_FORMAT_COUNT:
82 ADD_FAILURE() << "Unknown format";
83 return nil;
84 }
85 size_t width = CGImageGetWidth(image);
86 size_t height = CGImageGetHeight(image);
87 base::ScopedCFTypeRef<CGColorSpaceRef> color_space(
88 CGColorSpaceCreateDeviceRGB());
89 size_t bytes_per_pixel = 4;
90 size_t bytes_per_row = bytes_per_pixel * width;
91 size_t bits_per_component = 8;
92 std::vector<uint8_t>* result =
93 new std::vector<uint8_t>(width * height * bytes_per_pixel, 0);
94 base::ScopedCFTypeRef<CGContextRef> context(CGBitmapContextCreate(
95 &result->front(), width, height, bits_per_component, bytes_per_row,
96 color_space, kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big));
97 CGContextDrawImage(context, CGRectMake(0, 0, width, height), image);
98 // Check that someting has been written in |result|.
99 std::vector<uint8_t> zeroes(width * height * bytes_per_pixel, 0);
100 EXPECT_NE(0, memcmp(&result->front(), &zeroes.front(), zeroes.size()))
101 << "Decompression failed.";
102 return result;
103 }
104
105 // Compares data, allowing an averaged absolute difference of 1.
106 bool CompareUncompressedData(const uint8_t* ptr_1,
107 const uint8_t* ptr_2,
108 size_t size) {
109 uint64_t difference = 0;
110 for (size_t i = 0; i < size; ++i) {
111 // Casting to int to avoid overflow.
112 int error = abs(int(ptr_1[i]) - int(ptr_2[i]));
113 EXPECT_GE(difference + error, difference)
114 << "Image difference too big (overflow).";
115 difference += error;
116 }
117 double average_difference = double(difference) / double(size);
118 DLOG(INFO) << "Average image difference: " << average_difference;
119 return average_difference < 1.5;
120 }
121
122 bool CheckCompressedImagesEqual(NSData* data_1,
123 NSData* data_2,
124 WebpDecoder::DecodedImageFormat format) {
125 std::unique_ptr<std::vector<uint8_t>> uncompressed_1(
126 DecompressData(data_1, format));
127 std::unique_ptr<std::vector<uint8_t>> uncompressed_2(
128 DecompressData(data_2, format));
129 if (uncompressed_1->size() != uncompressed_2->size()) {
130 DLOG(ERROR) << "Image sizes don't match";
131 return false;
132 }
133 return CompareUncompressedData(&uncompressed_1->front(),
134 &uncompressed_2->front(),
135 uncompressed_1->size());
136 }
137
138 bool CheckTiffImagesEqual(NSData* image_1, NSData* image_2) {
139 if ([image_1 length] != [image_2 length]) {
140 DLOG(ERROR) << "Image lengths don't match";
141 return false;
142 }
143 // Compare headers.
144 const size_t kHeaderSize = WebpDecoder::GetHeaderSize();
145 NSData* header_1 = [image_1 subdataWithRange:NSMakeRange(0, kHeaderSize)];
146 NSData* header_2 = [image_2 subdataWithRange:NSMakeRange(0, kHeaderSize)];
147 if (!header_1 || !header_2)
148 return false;
149 if (![header_1 isEqualToData:header_2]) {
150 DLOG(ERROR) << "Headers don't match.";
151 return false;
152 }
153 return CompareUncompressedData(
154 static_cast<const uint8_t*>([image_1 bytes]) + kHeaderSize,
155 static_cast<const uint8_t*>([image_2 bytes]) + kHeaderSize,
156 [image_1 length] - kHeaderSize);
157 }
158
159 protected:
160 scoped_refptr<WebpDecoderDelegate> delegate_;
161 scoped_refptr<WebpDecoder> decoder_;
162 };
163
164 } // namespace
165
166 TEST_F(WebpDecoderTest, DecodeToJpeg) {
167 // TODO(droger): This test fails on iOS 9 x64 devices. http://crbug.com/523235
168 #if defined(OS_IOS) && defined(ARCH_CPU_ARM64) && !TARGET_IPHONE_SIMULATOR
169 if (base::ios::IsRunningOnIOS9OrLater())
170 return;
171 #endif
172 // Load a WebP image from disk.
173 base::scoped_nsobject<NSData> webp_image(
174 [LoadImage(base::FilePath("test.webp")) retain]);
175 ASSERT_TRUE(webp_image != nil);
176 // Load reference image.
177 base::scoped_nsobject<NSData> jpg_image(
178 [LoadImage(base::FilePath("test.jpg")) retain]);
179 ASSERT_TRUE(jpg_image != nil);
180 // Convert to JPEG.
181 EXPECT_CALL(*delegate_, OnFinishedDecoding(true)).Times(1);
182 EXPECT_CALL(*delegate_, SetImageFeatures(testing::_, WebpDecoder::JPEG))
183 .Times(1);
184 decoder_->OnDataReceived(webp_image);
185 // Compare to reference image.
186 EXPECT_TRUE(CheckCompressedImagesEqual(jpg_image, delegate_->GetImage(),
187 WebpDecoder::JPEG));
188 }
189
190 TEST_F(WebpDecoderTest, DecodeToPng) {
191 // TODO(droger): This test fails on iOS 9 x64 devices. http://crbug.com/523235
192 #if defined(OS_IOS) && defined(ARCH_CPU_ARM64) && !TARGET_IPHONE_SIMULATOR
193 if (base::ios::IsRunningOnIOS9OrLater())
194 return;
195 #endif
196 // Load a WebP image from disk.
197 base::scoped_nsobject<NSData> webp_image(
198 [LoadImage(base::FilePath("test_alpha.webp")) retain]);
199 ASSERT_TRUE(webp_image != nil);
200 // Load reference image.
201 base::scoped_nsobject<NSData> png_image(
202 [LoadImage(base::FilePath("test_alpha.png")) retain]);
203 ASSERT_TRUE(png_image != nil);
204 // Convert to PNG.
205 EXPECT_CALL(*delegate_, OnFinishedDecoding(true)).Times(1);
206 EXPECT_CALL(*delegate_, SetImageFeatures(testing::_, WebpDecoder::PNG))
207 .Times(1);
208 decoder_->OnDataReceived(webp_image);
209 // Compare to reference image.
210 EXPECT_TRUE(CheckCompressedImagesEqual(png_image, delegate_->GetImage(),
211 WebpDecoder::PNG));
212 }
213
214 TEST_F(WebpDecoderTest, DecodeToTiff) {
215 // TODO(droger): This test fails on iOS 9 x64 devices. http://crbug.com/523235
216 #if defined(OS_IOS) && defined(ARCH_CPU_ARM64) && !TARGET_IPHONE_SIMULATOR
217 if (base::ios::IsRunningOnIOS9OrLater())
218 return;
219 #endif
220 // Load a WebP image from disk.
221 base::scoped_nsobject<NSData> webp_image(
222 [LoadImage(base::FilePath("test_small.webp")) retain]);
223 ASSERT_TRUE(webp_image != nil);
224 // Load reference image.
225 base::scoped_nsobject<NSData> tiff_image(
226 [LoadImage(base::FilePath("test_small.tiff")) retain]);
227 ASSERT_TRUE(tiff_image != nil);
228 // Convert to TIFF.
229 EXPECT_CALL(*delegate_, OnFinishedDecoding(true)).Times(1);
230 EXPECT_CALL(*delegate_,
231 SetImageFeatures([tiff_image length], WebpDecoder::TIFF))
232 .Times(1);
233 decoder_->OnDataReceived(webp_image);
234 // Compare to reference image.
235 EXPECT_TRUE(CheckTiffImagesEqual(tiff_image, delegate_->GetImage()));
236 }
237
238 TEST_F(WebpDecoderTest, StreamedDecode) {
239 // TODO(droger): This test fails on iOS 9 x64 devices. http://crbug.com/523235
240 #if defined(OS_IOS) && defined(ARCH_CPU_ARM64) && !TARGET_IPHONE_SIMULATOR
241 if (base::ios::IsRunningOnIOS9OrLater())
242 return;
243 #endif
244 // Load a WebP image from disk.
245 base::scoped_nsobject<NSData> webp_image(
246 [LoadImage(base::FilePath("test.webp")) retain]);
247 ASSERT_TRUE(webp_image != nil);
248 // Load reference image.
249 base::scoped_nsobject<NSData> jpg_image(
250 [LoadImage(base::FilePath("test.jpg")) retain]);
251 ASSERT_TRUE(jpg_image != nil);
252 // Convert to JPEG in chunks.
253 EXPECT_CALL(*delegate_, OnFinishedDecoding(true)).Times(1);
254 EXPECT_CALL(*delegate_, SetImageFeatures(testing::_, WebpDecoder::JPEG))
255 .Times(1);
256 const size_t kChunkSize = 10;
257 unsigned int num_chunks = 0;
258 while ([webp_image length] > kChunkSize) {
259 base::scoped_nsobject<NSData> chunk(
260 [[webp_image subdataWithRange:NSMakeRange(0, kChunkSize)] retain]);
261 decoder_->OnDataReceived(chunk);
262 webp_image.reset([[webp_image
263 subdataWithRange:NSMakeRange(kChunkSize, [webp_image length] -
264 kChunkSize)] retain]);
265 ++num_chunks;
266 }
267 if ([webp_image length] > 0u) {
268 decoder_->OnDataReceived(webp_image);
269 ++num_chunks;
270 }
271 ASSERT_GT(num_chunks, 3u) << "Not enough chunks";
272 // Compare to reference image.
273 EXPECT_TRUE(CheckCompressedImagesEqual(jpg_image, delegate_->GetImage(),
274 WebpDecoder::JPEG));
275 }
276
277 TEST_F(WebpDecoderTest, InvalidFormat) {
278 EXPECT_CALL(*delegate_, OnFinishedDecoding(false)).Times(1);
279 const char dummy_image[] = "(>'-')> <('-'<) ^('-')^ <('-'<) (>'-')>";
280 base::scoped_nsobject<NSData> data(
281 [[NSData alloc] initWithBytes:dummy_image length:arraysize(dummy_image)]);
282 decoder_->OnDataReceived(data);
283 EXPECT_EQ(0u, [delegate_->GetImage() length]);
284 }
285
286 TEST_F(WebpDecoderTest, DecodeAborted) {
287 EXPECT_CALL(*delegate_, OnFinishedDecoding(false)).Times(1);
288 decoder_->Stop();
289 EXPECT_EQ(0u, [delegate_->GetImage() length]);
290 }
291
292 } // namespace webp_transcode
OLDNEW
« no previous file with comments | « ios/chrome/browser/webp_transcode/webp_decoder.mm ('k') | ios/chrome/test/data/webp_transcode/OWNERS » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698