OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2012 The Chromium Authors. All rights reserved. | |
Paweł Hajdan Jr.
2015/01/30 12:24:29
nit: 2015
| |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #import "ios/chrome/browser/snapshots/snapshot_cache.h" | |
6 | |
7 #import <Foundation/Foundation.h> | |
8 | |
9 #include "base/files/file_path.h" | |
10 #include "base/files/file_util.h" | |
11 #include "base/format_macros.h" | |
12 #include "base/location.h" | |
13 #include "base/mac/bind_objc_block.h" | |
14 #include "base/mac/scoped_nsautorelease_pool.h" | |
15 #include "base/strings/sys_string_conversions.h" | |
16 #import "base/test/ios/wait_util.h" | |
17 #include "base/time/time.h" | |
18 #include "ios/chrome/browser/ui/ui_util.h" | |
19 #include "ios/web/public/test/test_web_thread.h" | |
20 #include "ios/web/public/web_thread.h" | |
21 #include "testing/gtest/include/gtest/gtest.h" | |
22 #include "testing/gtest_mac.h" | |
23 #include "testing/platform_test.h" | |
24 | |
25 static const NSUInteger kSessionCount = 10; | |
26 static const NSUInteger kSnapshotPixelSize = 8; | |
27 | |
28 // Promote some implementation methods to public. | |
29 @interface SnapshotCache (Testing) | |
30 - (base::FilePath)imagePathForSessionID:(NSString*)sessionID; | |
31 - (base::FilePath)greyImagePathForSessionID:(NSString*)sessionID; | |
32 - (void)handleLowMemory; | |
33 @end | |
34 | |
35 @interface SnapshotCache (TestingAdditions) | |
36 - (void)flushOperationQueue; | |
37 - (BOOL)hasImageInMemory:(NSString*)sessionID; | |
38 - (BOOL)hasGreyImageInMemory:(NSString*)sessionID; | |
39 @end | |
40 | |
41 @implementation SnapshotCache (TestingAdditions) | |
42 - (void)flushOperationQueue { | |
43 dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); | |
44 web::WebThread::PostBlockingPoolSequencedTask( | |
45 "SnapshotCacheSequenceToken", FROM_HERE, | |
46 base::BindBlock(^{ | |
47 dispatch_semaphore_signal(semaphore); | |
48 })); | |
49 dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); | |
50 dispatch_release(semaphore); | |
51 } | |
52 - (BOOL)hasImageInMemory:(NSString*)sessionID { | |
53 return [imageDictionary_ objectForKey:sessionID] != nil; | |
54 } | |
55 - (BOOL)hasGreyImageInMemory:(NSString*)sessionID { | |
56 return [greyImageDictionary_ objectForKey:sessionID] != nil; | |
57 } | |
58 @end | |
59 | |
60 namespace { | |
61 | |
62 class SnapshotCacheTest : public PlatformTest { | |
63 protected: | |
64 // Build an array of session names and an array of UIImages filled with | |
65 // random colors. | |
66 void SetUp() override { | |
67 file_thread_.reset(new web::TestWebThread(web::WebThread::FILE)); | |
68 file_thread_->Start(); | |
69 testImages_.reset([[NSMutableArray alloc] initWithCapacity:kSessionCount]); | |
70 testSessions_.reset( | |
71 [[NSMutableArray alloc] initWithCapacity:kSessionCount]); | |
72 | |
73 CGFloat scale = [SnapshotCache snapshotScaleForDevice]; | |
74 UIGraphicsBeginImageContextWithOptions( | |
75 CGSizeMake(kSnapshotPixelSize, kSnapshotPixelSize), NO, scale); | |
76 CGContextRef context = UIGraphicsGetCurrentContext(); | |
77 srand(1); | |
78 | |
79 for (NSUInteger i = 0; i < kSessionCount; ++i) { | |
80 UIImage* image = GenerateRandomImage(context); | |
81 [testImages_ addObject:image]; | |
82 [testSessions_ | |
83 addObject:[NSString stringWithFormat:@"SessionId-%" PRIuNS, i]]; | |
84 } | |
85 | |
86 UIGraphicsEndImageContext(); | |
87 } | |
88 | |
89 // Generates an image filled with a random color. | |
90 UIImage* GenerateRandomImage(CGContextRef context) { | |
91 CGFloat r = rand() / CGFloat(RAND_MAX); | |
92 CGFloat g = rand() / CGFloat(RAND_MAX); | |
93 CGFloat b = rand() / CGFloat(RAND_MAX); | |
94 CGContextSetRGBStrokeColor(context, r, g, b, 1.0); | |
95 CGContextSetRGBFillColor(context, r, g, b, 1.0); | |
96 CGContextFillRect( | |
97 context, CGRectMake(0.0, 0.0, kSnapshotPixelSize, kSnapshotPixelSize)); | |
98 return UIGraphicsGetImageFromCurrentImageContext(); | |
99 } | |
100 | |
101 // This function removes the snapshots both from dictionary and from disk. | |
102 void ClearDumpedImages() { | |
103 SnapshotCache* cache = [SnapshotCache sharedInstance]; | |
104 | |
105 NSString* sessionID; | |
106 for (sessionID in testSessions_.get()) | |
107 [cache removeImageWithSessionID:sessionID]; | |
108 | |
109 [cache flushOperationQueue]; | |
110 // The above calls to -removeImageWithSessionID remove both the color | |
111 // and grey snapshots for each sessionID, if they are on disk. However, | |
112 // ensure we also get rid of the grey snapshots in memory. | |
113 [cache removeGreyCache]; | |
114 | |
115 __block BOOL foundImage = NO; | |
116 __block NSUInteger numCallbacks = 0; | |
117 for (sessionID in testSessions_.get()) { | |
118 base::FilePath path([cache imagePathForSessionID:sessionID]); | |
119 | |
120 // Checks that the snapshot is not on disk. | |
121 EXPECT_FALSE(base::PathExists(path)); | |
122 | |
123 // Check that the snapshot is not in the dictionary. | |
124 [cache retrieveImageForSessionID:sessionID | |
125 callback:^(UIImage* image) { | |
126 numCallbacks++; | |
127 if (image) | |
128 foundImage = YES; | |
129 }]; | |
130 } | |
131 | |
132 // Spin the main message loop until all of the callbacks run. Time out | |
133 // after a while to avoid waiting forever. | |
134 NSUInteger expectedNumCallbacks = [testSessions_ count]; | |
135 NSTimeInterval kTimeoutSec = 3; | |
Paweł Hajdan Jr.
2015/01/30 12:24:29
I strongly second Nico's comment about using base/
| |
136 base::WaitUntilCondition(^bool() { | |
137 return numCallbacks >= expectedNumCallbacks; | |
138 }, nullptr, base::TimeDelta::FromSecondsD(kTimeoutSec)); | |
139 | |
140 // Expect that all the callbacks ran and that none retrieved an image. | |
141 EXPECT_EQ(expectedNumCallbacks, numCallbacks); | |
142 EXPECT_FALSE(foundImage); | |
143 } | |
144 | |
145 // Loads kSessionCount color images into the cache. If |waitForFilesOnDisk| | |
146 // is YES, will not return until the images have been written to disk. | |
147 void LoadAllColorImagesIntoCache(bool waitForFilesOnDisk) { | |
148 LoadColorImagesIntoCache(kSessionCount, waitForFilesOnDisk); | |
149 } | |
150 | |
151 // Loads |count| color images into the cache. If |waitForFilesOnDisk| | |
152 // is YES, will not return until the images have been written to disk. | |
153 void LoadColorImagesIntoCache(NSUInteger count, bool waitForFilesOnDisk) { | |
154 SnapshotCache* cache = [SnapshotCache sharedInstance]; | |
155 // Put color images in the cache. | |
156 for (NSUInteger i = 0; i < count; ++i) { | |
157 base::mac::ScopedNSAutoreleasePool pool; | |
158 UIImage* image = [testImages_ objectAtIndex:i]; | |
159 NSString* sessionID = [testSessions_ objectAtIndex:i]; | |
160 [cache setImage:image withSessionID:sessionID]; | |
161 } | |
162 if (waitForFilesOnDisk) { | |
163 [cache flushOperationQueue]; | |
164 for (NSUInteger i = 0; i < count; ++i) { | |
165 // Check that images are on the disk. | |
166 NSString* sessionID = [testSessions_ objectAtIndex:i]; | |
167 base::FilePath path([cache imagePathForSessionID:sessionID]); | |
168 EXPECT_TRUE(base::PathExists(path)); | |
169 } | |
170 } | |
171 } | |
172 | |
173 // Waits for the grey images for the sessions in |testSessions_| to be written | |
174 // to disk, which happens in a background thread. | |
175 void WaitForAllGreyImagesOnDisk() { | |
176 SnapshotCache* cache = [SnapshotCache sharedInstance]; | |
177 NSString* sessionID; | |
178 NSTimeInterval kTimeoutSec = 3; | |
179 for (sessionID in testSessions_.get()) { | |
180 base::FilePath path([cache greyImagePathForSessionID:sessionID]); | |
181 base::WaitUntilCondition(^bool() { | |
182 return base::PathExists(path); | |
183 }, nullptr, base::TimeDelta::FromSecondsD(kTimeoutSec)); | |
184 } | |
185 } | |
186 | |
187 // Waits for the first |count| grey images for sessions in |testSessions_| | |
188 // to be placed in the cache. | |
189 void WaitForGreyImagesInCache(NSUInteger count) { | |
190 SnapshotCache* cache = [SnapshotCache sharedInstance]; | |
191 NSTimeInterval kTimeoutSec = 3; | |
192 for (NSUInteger i = 0; i < count; i++) { | |
193 base::WaitUntilCondition(^bool() { | |
194 return [cache hasGreyImageInMemory:testSessions_[i]]; | |
195 }, nullptr, base::TimeDelta::FromSecondsD(kTimeoutSec)); | |
196 } | |
197 } | |
198 | |
199 // Guesses the order of the color channels in the image. | |
200 // Supports RGB, BGR, RGBA, BGRA, ARGB, ABGR. | |
201 // Returns the position of each channel between 0 and 3. | |
202 void ComputeColorComponents(CGImageRef cgImage, | |
203 int* red, | |
204 int* green, | |
205 int* blue) { | |
206 CGBitmapInfo bitmapInfo = CGImageGetBitmapInfo(cgImage); | |
207 CGImageAlphaInfo alphaInfo = CGImageGetAlphaInfo(cgImage); | |
208 int byteOrder = bitmapInfo & kCGBitmapByteOrderMask; | |
209 | |
210 *red = 0; | |
211 *green = 1; | |
212 *blue = 2; | |
213 | |
214 if (alphaInfo == kCGImageAlphaLast || | |
215 alphaInfo == kCGImageAlphaPremultipliedLast || | |
216 alphaInfo == kCGImageAlphaNoneSkipLast) { | |
217 *red = 1; | |
218 *green = 2; | |
219 *blue = 3; | |
220 } | |
221 | |
222 if (byteOrder != kCGBitmapByteOrder32Host) { | |
223 int lastChannel = (CGImageGetBitsPerPixel(cgImage) == 24) ? 2 : 3; | |
224 *red = lastChannel - *red; | |
225 *green = lastChannel - *green; | |
226 *blue = lastChannel - *blue; | |
227 } | |
228 } | |
229 | |
230 const char* GetPixelData(CGImageRef cgImage) { | |
231 CFDataRef data = CGDataProviderCopyData(CGImageGetDataProvider(cgImage)); | |
232 return reinterpret_cast<const char*>(CFDataGetBytePtr(data)); | |
233 } | |
234 | |
235 base::scoped_nsobject<NSMutableArray> testSessions_; | |
236 base::scoped_nsobject<NSMutableArray> testImages_; | |
237 scoped_ptr<web::TestWebThread> file_thread_; | |
238 }; | |
239 | |
240 // This test simply put all the snapshots in the cache and then gets them back | |
241 // As the snapshots are kept in memory, the same pointer can be retrieved. | |
242 // This test also checks that images are correctly removed from the disk. | |
243 TEST_F(SnapshotCacheTest, Cache) { | |
244 // Don't run on tablets because color snapshots are not cached so this test | |
245 // can't compare the UIImage pointers directly. | |
246 if (IsIPadIdiom()) { | |
247 return; | |
248 } | |
249 | |
250 ClearDumpedImages(); | |
251 | |
252 SnapshotCache* cache = [SnapshotCache sharedInstance]; | |
253 | |
254 // Put all images in the cache. | |
255 for (NSUInteger i = 0; i < kSessionCount; ++i) { | |
256 UIImage* image = [testImages_ objectAtIndex:i]; | |
257 NSString* sessionID = [testSessions_ objectAtIndex:i]; | |
258 [cache setImage:image withSessionID:sessionID]; | |
259 } | |
260 | |
261 // Get images back. | |
262 __block NSUInteger numberOfCallbacks = 0; | |
263 for (NSUInteger i = 0; i < kSessionCount; ++i) { | |
264 NSString* sessionID = [testSessions_ objectAtIndex:i]; | |
265 UIImage* expectedImage = [testImages_ objectAtIndex:i]; | |
266 EXPECT_TRUE(expectedImage != nil); | |
267 [cache retrieveImageForSessionID:sessionID | |
268 callback:^(UIImage* image) { | |
269 // Images have not been removed from the | |
270 // dictionnary. We expect the same pointer. | |
271 EXPECT_EQ(expectedImage, image); | |
272 ++numberOfCallbacks; | |
273 }]; | |
274 } | |
275 EXPECT_EQ(kSessionCount, numberOfCallbacks); | |
276 | |
277 ClearDumpedImages(); | |
278 } | |
279 | |
280 // This test puts all the snapshots in the cache and flushes them to disk. | |
281 // The snapshots are then reloaded from the disk, and the colors are compared. | |
282 TEST_F(SnapshotCacheTest, SaveToDisk) { | |
283 ClearDumpedImages(); | |
284 | |
285 SnapshotCache* cache = [SnapshotCache sharedInstance]; | |
286 | |
287 // Put all images in the cache. | |
288 for (NSUInteger i = 0; i < kSessionCount; ++i) { | |
289 UIImage* image = [testImages_ objectAtIndex:i]; | |
290 NSString* sessionID = [testSessions_ objectAtIndex:i]; | |
291 [cache setImage:image withSessionID:sessionID]; | |
292 } | |
293 [cache flushOperationQueue]; | |
294 | |
295 for (NSUInteger i = 0; i < kSessionCount; ++i) { | |
296 // Check that images are on the disk. | |
297 NSString* sessionID = [testSessions_ objectAtIndex:i]; | |
298 | |
299 base::FilePath path([cache imagePathForSessionID:sessionID]); | |
300 EXPECT_TRUE(base::PathExists(path)); | |
301 | |
302 // Check image colors by comparing the first pixel against the reference | |
303 // image. | |
304 UIImage* image = | |
305 [UIImage imageWithContentsOfFile:base::SysUTF8ToNSString(path.value())]; | |
306 CGImageRef cgImage = [image CGImage]; | |
307 const char* pixels = GetPixelData(cgImage); | |
308 EXPECT_TRUE(pixels); | |
309 | |
310 UIImage* referenceImage = [testImages_ objectAtIndex:i]; | |
311 CGImageRef referenceCgImage = [referenceImage CGImage]; | |
312 const char* referencePixels = GetPixelData(referenceCgImage); | |
313 EXPECT_TRUE(referencePixels); | |
314 | |
315 if (pixels != nil && referencePixels != nil) { | |
316 // Color components may not be in the same order, | |
317 // because of writing to disk and reloading. | |
318 int red, green, blue; | |
319 ComputeColorComponents(cgImage, &red, &green, &blue); | |
320 | |
321 int referenceRed, referenceGreen, referenceBlue; | |
322 ComputeColorComponents(referenceCgImage, &referenceRed, &referenceGreen, | |
323 &referenceBlue); | |
324 | |
325 // Colors may not be exactly the same (compression or rounding errors) | |
326 // thus a small difference is allowed. | |
327 EXPECT_NEAR(referencePixels[referenceRed], pixels[red], 1); | |
328 EXPECT_NEAR(referencePixels[referenceGreen], pixels[green], 1); | |
329 EXPECT_NEAR(referencePixels[referenceBlue], pixels[blue], 1); | |
330 } | |
331 } | |
332 | |
333 ClearDumpedImages(); | |
334 } | |
335 | |
336 TEST_F(SnapshotCacheTest, PurgeTest) { | |
337 ClearDumpedImages(); | |
338 | |
339 SnapshotCache* cache = [SnapshotCache sharedInstance]; | |
340 | |
341 // Put all images in the cache. | |
342 for (NSUInteger i = 0; i < kSessionCount; ++i) { | |
343 UIImage* image = [testImages_ objectAtIndex:i]; | |
344 NSString* sessionID = [testSessions_ objectAtIndex:i]; | |
345 [cache setImage:image withSessionID:sessionID]; | |
346 } | |
347 | |
348 NSMutableSet* liveSessions = [NSMutableSet setWithCapacity:1]; | |
349 [liveSessions addObject:[testSessions_ objectAtIndex:0]]; | |
350 | |
351 // Purge the cache. | |
352 [cache purgeCacheOlderThan:(base::Time::Now() - base::TimeDelta::FromHours(1)) | |
353 keeping:liveSessions]; | |
354 [cache flushOperationQueue]; | |
355 | |
356 // Check that nothing has been deleted. | |
357 for (NSUInteger i = 0; i < kSessionCount; ++i) { | |
358 // Check that images are on the disk. | |
359 NSString* sessionID = [testSessions_ objectAtIndex:i]; | |
360 | |
361 base::FilePath path([cache imagePathForSessionID:sessionID]); | |
362 EXPECT_TRUE(base::PathExists(path)); | |
363 } | |
364 | |
365 // Purge the cache. | |
366 [cache purgeCacheOlderThan:base::Time::Now() keeping:liveSessions]; | |
367 [cache flushOperationQueue]; | |
368 | |
369 // Check that the file have been deleted. | |
370 for (NSUInteger i = 0; i < kSessionCount; ++i) { | |
371 // Check that images are on the disk. | |
372 NSString* sessionID = [testSessions_ objectAtIndex:i]; | |
373 | |
374 base::FilePath path([cache imagePathForSessionID:sessionID]); | |
375 if (i == 0) | |
376 EXPECT_TRUE(base::PathExists(path)); | |
377 else | |
378 EXPECT_FALSE(base::PathExists(path)); | |
379 } | |
380 ClearDumpedImages(); | |
381 } | |
382 | |
383 // Loads the color images into the cache, and pins two of them. Ensures that | |
384 // only the two pinned IDs remain in memory after a call to -handleLowMemory. | |
385 TEST_F(SnapshotCacheTest, testHandleLowMemory) { | |
386 ClearDumpedImages(); | |
387 LoadAllColorImagesIntoCache(true); | |
388 | |
389 SnapshotCache* cache = [SnapshotCache sharedInstance]; | |
390 | |
391 NSString* firstPinnedID = [testSessions_ objectAtIndex:4]; | |
392 NSString* secondPinnedID = [testSessions_ objectAtIndex:6]; | |
393 NSMutableSet* set = [NSMutableSet set]; | |
394 [set addObject:firstPinnedID]; | |
395 [set addObject:secondPinnedID]; | |
396 cache.pinnedIDs = set; | |
397 | |
398 [cache handleLowMemory]; | |
399 | |
400 BOOL expectedValue = YES; | |
401 if (IsIPadIdiom()) { | |
402 expectedValue = NO; | |
403 } | |
404 EXPECT_EQ(expectedValue, [cache hasImageInMemory:firstPinnedID]); | |
405 EXPECT_EQ(expectedValue, [cache hasImageInMemory:secondPinnedID]); | |
406 | |
407 NSString* notPinnedID = [testSessions_ objectAtIndex:2]; | |
408 EXPECT_FALSE([cache hasImageInMemory:notPinnedID]); | |
409 | |
410 // Wait for the final image to be pulled off disk. | |
411 [cache flushOperationQueue]; | |
412 ClearDumpedImages(); | |
413 } | |
414 | |
415 // Tests that createGreyCache creates the grey snapshots in the background, | |
416 // from color images in the in-memory cache. When the grey images are all | |
417 // loaded into memory, tests that the request to retrieve the grey snapshot | |
418 // calls the callback immediately. | |
419 // Disabled on simulators because it sometimes crashes. crbug/421425 | |
420 #if !TARGET_IPHONE_SIMULATOR | |
421 TEST_F(SnapshotCacheTest, testCreateGreyCache) { | |
422 ClearDumpedImages(); | |
423 LoadAllColorImagesIntoCache(true); | |
424 | |
425 // Request the creation of a grey image cache for all images. | |
426 SnapshotCache* cache = [SnapshotCache sharedInstance]; | |
427 [cache createGreyCache:testSessions_]; | |
428 | |
429 // Wait for them to be put into the grey image cache. | |
430 WaitForGreyImagesInCache(kSessionCount); | |
431 | |
432 __block NSUInteger numberOfCallbacks = 0; | |
433 for (NSUInteger i = 0; i < kSessionCount; ++i) { | |
434 NSString* sessionID = [testSessions_ objectAtIndex:i]; | |
435 [cache retrieveGreyImageForSessionID:sessionID | |
436 callback:^(UIImage* image) { | |
437 EXPECT_TRUE(image); | |
438 ++numberOfCallbacks; | |
439 }]; | |
440 } | |
441 | |
442 EXPECT_EQ(numberOfCallbacks, kSessionCount); | |
443 ClearDumpedImages(); | |
444 } | |
445 | |
446 // Same as previous test, except that all the color images are on disk, | |
447 // rather than in memory. | |
448 // Disabled due to the greyImage crash. b/8048597 | |
449 TEST_F(SnapshotCacheTest, testCreateGreyCacheFromDisk) { | |
450 ClearDumpedImages(); | |
451 LoadAllColorImagesIntoCache(true); | |
452 | |
453 // Remove color images from in-memory cache. | |
454 SnapshotCache* cache = [SnapshotCache sharedInstance]; | |
455 [cache handleLowMemory]; | |
456 | |
457 // Request the creation of a grey image cache for all images. | |
458 [cache createGreyCache:testSessions_]; | |
459 | |
460 // Wait for them to be put into the grey image cache. | |
461 WaitForGreyImagesInCache(kSessionCount); | |
462 | |
463 __block NSUInteger numberOfCallbacks = 0; | |
464 for (NSUInteger i = 0; i < kSessionCount; ++i) { | |
465 NSString* sessionID = [testSessions_ objectAtIndex:i]; | |
466 [cache retrieveGreyImageForSessionID:sessionID | |
467 callback:^(UIImage* image) { | |
468 EXPECT_TRUE(image); | |
469 ++numberOfCallbacks; | |
470 }]; | |
471 } | |
472 | |
473 EXPECT_EQ(numberOfCallbacks, kSessionCount); | |
474 ClearDumpedImages(); | |
475 } | |
476 #endif // !TARGET_IPHONE_SIMULATOR | |
477 | |
478 // Tests mostRecentGreyBlock, which is a block to be called when the most | |
479 // recently requested grey image is finally loaded. | |
480 // The test requests three images be cached as grey images. Only the final | |
481 // callback of the three requests should be called. | |
482 // Disabled due to the greyImage crash. b/8048597 | |
483 TEST_F(SnapshotCacheTest, testMostRecentGreyBlock) { | |
484 ClearDumpedImages(); | |
485 | |
486 const NSUInteger kNumImages = 3; | |
487 base::scoped_nsobject<NSMutableArray> sessionIDs( | |
488 [[NSMutableArray alloc] initWithCapacity:kNumImages]); | |
489 [sessionIDs addObject:[testSessions_ objectAtIndex:0]]; | |
490 [sessionIDs addObject:[testSessions_ objectAtIndex:1]]; | |
491 [sessionIDs addObject:[testSessions_ objectAtIndex:2]]; | |
492 | |
493 SnapshotCache* cache = [SnapshotCache sharedInstance]; | |
494 | |
495 // Put 3 images in the cache. | |
496 LoadColorImagesIntoCache(kNumImages, true); | |
497 // Make sure the color images are only on disk, to ensure the background | |
498 // thread is slow enough to queue up the requests. | |
499 [cache handleLowMemory]; | |
500 | |
501 // Enable the grey image cache. | |
502 [cache createGreyCache:sessionIDs]; | |
503 | |
504 // Request the grey versions | |
505 __block BOOL firstCallbackCalled = NO; | |
506 __block BOOL secondCallbackCalled = NO; | |
507 __block BOOL thirdCallbackCalled = NO; | |
508 [cache greyImageForSessionID:[testSessions_ objectAtIndex:0] | |
509 callback:^(UIImage*) { | |
510 firstCallbackCalled = YES; | |
511 }]; | |
512 [cache greyImageForSessionID:[testSessions_ objectAtIndex:1] | |
513 callback:^(UIImage*) { | |
514 secondCallbackCalled = YES; | |
515 }]; | |
516 [cache greyImageForSessionID:[testSessions_ objectAtIndex:2] | |
517 callback:^(UIImage*) { | |
518 thirdCallbackCalled = YES; | |
519 }]; | |
520 | |
521 // Wait for them to be loaded. | |
522 WaitForGreyImagesInCache(kNumImages); | |
523 | |
524 EXPECT_FALSE(firstCallbackCalled); | |
525 EXPECT_FALSE(secondCallbackCalled); | |
526 EXPECT_TRUE(thirdCallbackCalled); | |
527 | |
528 ClearDumpedImages(); | |
529 } | |
530 | |
531 // Test the function used to save a grey copy of a color snapshot fully on a | |
532 // background thread when the application is backgrounded. | |
533 // Disabled due to the greyImage crash. b/8048597 | |
534 TEST_F(SnapshotCacheTest, testGreyImageAllInBackground) { | |
535 ClearDumpedImages(); | |
536 LoadAllColorImagesIntoCache(true); | |
537 | |
538 SnapshotCache* cache = [SnapshotCache sharedInstance]; | |
539 | |
540 // Now convert every image into a grey image, on disk, in the background. | |
541 for (NSUInteger i = 0; i < kSessionCount; ++i) { | |
542 [cache saveGreyInBackgroundForSessionID:[testSessions_ objectAtIndex:i]]; | |
543 } | |
544 | |
545 WaitForAllGreyImagesOnDisk(); | |
546 | |
547 for (NSUInteger i = 0; i < kSessionCount; ++i) { | |
548 base::FilePath greyImagePath( | |
549 [cache greyImagePathForSessionID:[testSessions_ objectAtIndex:i]]); | |
550 EXPECT_TRUE(base::PathExists(greyImagePath)); | |
551 base::DeleteFile(greyImagePath, false); | |
552 } | |
553 | |
554 ClearDumpedImages(); | |
555 } | |
556 | |
557 // Verifies that image size and scale are preserved when writing and reading | |
558 // from disk. | |
559 TEST_F(SnapshotCacheTest, TestSizeAndScalePreservation) { | |
560 // Create an image with the expected snapshot scale. | |
561 CGFloat scale = [SnapshotCache snapshotScaleForDevice]; | |
562 UIGraphicsBeginImageContextWithOptions( | |
563 CGSizeMake(kSnapshotPixelSize, kSnapshotPixelSize), NO, scale); | |
564 CGContextRef context = UIGraphicsGetCurrentContext(); | |
565 UIImage* image = GenerateRandomImage(context); | |
566 UIGraphicsEndImageContext(); | |
567 | |
568 // Add the image to the cache then call handle low memory to ensure the image | |
569 // is read from disk instead of the in-memory cache. | |
570 SnapshotCache* cache = [SnapshotCache sharedInstance]; | |
571 NSString* const kSession = @"foo"; | |
572 [cache setImage:image withSessionID:kSession]; | |
573 [cache flushOperationQueue]; // ensure the file is written to disk. | |
574 [cache handleLowMemory]; | |
575 | |
576 // Retrive the image and have the callback verify the size and scale. | |
577 __block BOOL callbackComplete = NO; | |
578 [cache retrieveImageForSessionID:kSession | |
579 callback:^(UIImage* imageFromDisk) { | |
580 EXPECT_EQ(image.size.width, | |
581 imageFromDisk.size.width); | |
582 EXPECT_EQ(image.size.height, | |
583 imageFromDisk.size.height); | |
584 EXPECT_EQ(image.scale, imageFromDisk.scale); | |
585 callbackComplete = YES; | |
586 }]; | |
587 | |
588 // Spin the main message loop until the callback is run. Time out after a | |
589 // a while to avoid waiting forever. | |
590 const NSTimeInterval kTimeoutSec = 3; | |
591 base::WaitUntilCondition(^bool() { | |
592 return callbackComplete; | |
593 }, nullptr, base::TimeDelta::FromSecondsD(kTimeoutSec)); | |
594 EXPECT_TRUE(callbackComplete); | |
595 } | |
596 | |
597 // Verifies that retina-scale images are deleted properly. | |
598 TEST_F(SnapshotCacheTest, TestDeleteRetinaImages) { | |
599 if ([SnapshotCache snapshotScaleForDevice] != 2.0) { | |
600 return; | |
601 } | |
602 | |
603 // Create an image with retina scale. | |
604 UIGraphicsBeginImageContextWithOptions( | |
605 CGSizeMake(kSnapshotPixelSize, kSnapshotPixelSize), NO, 2.0); | |
606 CGContextRef context = UIGraphicsGetCurrentContext(); | |
607 UIImage* image = GenerateRandomImage(context); | |
608 UIGraphicsEndImageContext(); | |
609 | |
610 // Add the image to the cache then call handle low memory to ensure the image | |
611 // is read from disk instead of the in-memory cache. | |
612 SnapshotCache* cache = [SnapshotCache sharedInstance]; | |
613 NSString* const kSession = @"foo"; | |
614 [cache setImage:image withSessionID:kSession]; | |
615 [cache flushOperationQueue]; // ensure the file is written to disk. | |
616 [cache handleLowMemory]; | |
617 | |
618 // Verify the file was writted with @2x in the file name. | |
619 base::FilePath retinaFile = [cache imagePathForSessionID:kSession]; | |
620 EXPECT_TRUE(base::PathExists(retinaFile)); | |
621 | |
622 // Delete the image. | |
623 [cache removeImageWithSessionID:kSession]; | |
624 [cache flushOperationQueue]; // ensure the file is removed. | |
625 | |
626 EXPECT_FALSE(base::PathExists(retinaFile)); | |
627 } | |
628 | |
629 } // namespace | |
OLD | NEW |