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