Index: ios/chrome/browser/snapshots/snapshot_cache_unittest.mm |
diff --git a/ios/chrome/browser/snapshots/snapshot_cache_unittest.mm b/ios/chrome/browser/snapshots/snapshot_cache_unittest.mm |
new file mode 100644 |
index 0000000000000000000000000000000000000000..728bbcc6ff61b6ee7a573a67b961d5b256325ace |
--- /dev/null |
+++ b/ios/chrome/browser/snapshots/snapshot_cache_unittest.mm |
@@ -0,0 +1,587 @@ |
+// Copyright 2012 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#import "ios/chrome/browser/snapshots/snapshot_cache.h" |
+ |
+#import <Foundation/Foundation.h> |
+ |
+#include "base/files/file_path.h" |
+#include "base/files/file_util.h" |
+#include "base/format_macros.h" |
+#include "base/location.h" |
+#include "base/mac/bind_objc_block.h" |
+#include "base/mac/scoped_nsautorelease_pool.h" |
+#include "base/ios/ios_util.h" |
+#include "base/run_loop.h" |
+#include "base/strings/sys_string_conversions.h" |
+#include "base/time/time.h" |
+#include "ios/chrome/browser/ui/ui_util.h" |
+#include "ios/web/public/test/test_web_thread_bundle.h" |
+#include "ios/web/public/web_thread.h" |
+#include "testing/gtest/include/gtest/gtest.h" |
+#include "testing/gtest_mac.h" |
+#include "testing/platform_test.h" |
+ |
+static const NSUInteger kSessionCount = 10; |
+static const NSUInteger kSnapshotPixelSize = 8; |
+ |
+// Promote some implementation methods to public. |
+@interface SnapshotCache (Testing) |
++ (base::FilePath)imagePathForSessionID:(NSString*)sessionID; |
++ (base::FilePath)greyImagePathForSessionID:(NSString*)sessionID; |
+- (void)handleLowMemory; |
+@end |
+ |
+@interface SnapshotCache (TestingAdditions) |
+- (BOOL)hasImageInMemory:(NSString*)sessionID; |
+- (BOOL)hasGreyImageInMemory:(NSString*)sessionID; |
+@end |
+ |
+@implementation SnapshotCache (TestingAdditions) |
+- (BOOL)hasImageInMemory:(NSString*)sessionID { |
+ return [imageDictionary_ objectForKey:sessionID] != nil; |
+} |
+- (BOOL)hasGreyImageInMemory:(NSString*)sessionID { |
+ return [greyImageDictionary_ objectForKey:sessionID] != nil; |
+} |
+@end |
+ |
+namespace { |
+ |
+class SnapshotCacheTest : public PlatformTest { |
+ protected: |
+ // Build an array of session names and an array of UIImages filled with |
+ // random colors. |
+ void SetUp() override { |
+ PlatformTest::SetUp(); |
+ testImages_.reset([[NSMutableArray alloc] initWithCapacity:kSessionCount]); |
+ testSessions_.reset( |
+ [[NSMutableArray alloc] initWithCapacity:kSessionCount]); |
+ |
+ CGFloat scale = [SnapshotCache snapshotScaleForDevice]; |
+ UIGraphicsBeginImageContextWithOptions( |
+ CGSizeMake(kSnapshotPixelSize, kSnapshotPixelSize), NO, scale); |
+ CGContextRef context = UIGraphicsGetCurrentContext(); |
+ srand(1); |
+ |
+ for (NSUInteger i = 0; i < kSessionCount; ++i) { |
+ UIImage* image = GenerateRandomImage(context); |
+ [testImages_ addObject:image]; |
+ [testSessions_ |
+ addObject:[NSString stringWithFormat:@"SessionId-%" PRIuNS, i]]; |
+ } |
+ |
+ UIGraphicsEndImageContext(); |
+ |
+ ClearDumpedImages(); |
+ } |
+ |
+ void TearDown() override { |
+ ClearDumpedImages(); |
+ PlatformTest::TearDown(); |
+ } |
+ |
+ // Generates an image filled with a random color. |
+ UIImage* GenerateRandomImage(CGContextRef context) { |
+ CGFloat r = rand() / CGFloat(RAND_MAX); |
+ CGFloat g = rand() / CGFloat(RAND_MAX); |
+ CGFloat b = rand() / CGFloat(RAND_MAX); |
+ CGContextSetRGBStrokeColor(context, r, g, b, 1.0); |
+ CGContextSetRGBFillColor(context, r, g, b, 1.0); |
+ CGContextFillRect( |
+ context, CGRectMake(0.0, 0.0, kSnapshotPixelSize, kSnapshotPixelSize)); |
+ return UIGraphicsGetImageFromCurrentImageContext(); |
+ } |
+ |
+ // Flushes all the runloops internally used by the snapshot cache. |
+ void FlushRunLoops() { |
+ base::RunLoop().RunUntilIdle(); |
+ web::WebThread::GetBlockingPool()->FlushForTesting(); |
+ base::RunLoop().RunUntilIdle(); |
+ } |
+ |
+ // This function removes the snapshots both from dictionary and from disk. |
+ void ClearDumpedImages() { |
+ SnapshotCache* cache = [SnapshotCache sharedInstance]; |
+ |
+ NSString* sessionID; |
+ for (sessionID in testSessions_.get()) |
+ [cache removeImageWithSessionID:sessionID]; |
+ |
+ FlushRunLoops(); |
+ // The above calls to -removeImageWithSessionID remove both the color |
+ // and grey snapshots for each sessionID, if they are on disk. However, |
+ // ensure we also get rid of the grey snapshots in memory. |
+ [cache removeGreyCache]; |
+ |
+ __block BOOL foundImage = NO; |
+ __block NSUInteger numCallbacks = 0; |
+ for (sessionID in testSessions_.get()) { |
+ base::FilePath path([SnapshotCache imagePathForSessionID:sessionID]); |
+ |
+ // Checks that the snapshot is not on disk. |
+ EXPECT_FALSE(base::PathExists(path)); |
+ |
+ // Check that the snapshot is not in the dictionary. |
+ [cache retrieveImageForSessionID:sessionID |
+ callback:^(UIImage* image) { |
+ ++numCallbacks; |
+ if (image) |
+ foundImage = YES; |
+ }]; |
+ } |
+ |
+ // Expect that all the callbacks ran and that none retrieved an image. |
+ FlushRunLoops(); |
+ EXPECT_EQ([testSessions_ count], numCallbacks); |
+ EXPECT_FALSE(foundImage); |
+ } |
+ |
+ // Loads kSessionCount color images into the cache. If |waitForFilesOnDisk| |
+ // is YES, will not return until the images have been written to disk. |
+ void LoadAllColorImagesIntoCache(bool waitForFilesOnDisk) { |
+ LoadColorImagesIntoCache(kSessionCount, waitForFilesOnDisk); |
+ } |
+ |
+ // Loads |count| color images into the cache. If |waitForFilesOnDisk| |
+ // is YES, will not return until the images have been written to disk. |
+ void LoadColorImagesIntoCache(NSUInteger count, bool waitForFilesOnDisk) { |
+ SnapshotCache* cache = [SnapshotCache sharedInstance]; |
+ // Put color images in the cache. |
+ for (NSUInteger i = 0; i < count; ++i) { |
+ base::mac::ScopedNSAutoreleasePool pool; |
+ UIImage* image = [testImages_ objectAtIndex:i]; |
+ NSString* sessionID = [testSessions_ objectAtIndex:i]; |
+ [cache setImage:image withSessionID:sessionID]; |
+ } |
+ if (waitForFilesOnDisk) { |
+ FlushRunLoops(); |
+ for (NSUInteger i = 0; i < count; ++i) { |
+ // Check that images are on the disk. |
+ NSString* sessionID = [testSessions_ objectAtIndex:i]; |
+ base::FilePath path([SnapshotCache imagePathForSessionID:sessionID]); |
+ EXPECT_TRUE(base::PathExists(path)); |
+ } |
+ } |
+ } |
+ |
+ // Waits for the first |count| grey images for sessions in |testSessions_| |
+ // to be placed in the cache. |
+ void WaitForGreyImagesInCache(NSUInteger count) { |
+ SnapshotCache* cache = [SnapshotCache sharedInstance]; |
+ FlushRunLoops(); |
+ for (NSUInteger i = 0; i < count; i++) |
+ EXPECT_TRUE([cache hasGreyImageInMemory:testSessions_[i]]); |
+ } |
+ |
+ // Guesses the order of the color channels in the image. |
+ // Supports RGB, BGR, RGBA, BGRA, ARGB, ABGR. |
+ // Returns the position of each channel between 0 and 3. |
+ void ComputeColorComponents(CGImageRef cgImage, |
+ int* red, |
+ int* green, |
+ int* blue) { |
+ CGBitmapInfo bitmapInfo = CGImageGetBitmapInfo(cgImage); |
+ CGImageAlphaInfo alphaInfo = CGImageGetAlphaInfo(cgImage); |
+ int byteOrder = bitmapInfo & kCGBitmapByteOrderMask; |
+ |
+ *red = 0; |
+ *green = 1; |
+ *blue = 2; |
+ |
+ if (alphaInfo == kCGImageAlphaLast || |
+ alphaInfo == kCGImageAlphaPremultipliedLast || |
+ alphaInfo == kCGImageAlphaNoneSkipLast) { |
+ *red = 1; |
+ *green = 2; |
+ *blue = 3; |
+ } |
+ |
+ if (byteOrder != kCGBitmapByteOrder32Host) { |
+ int lastChannel = (CGImageGetBitsPerPixel(cgImage) == 24) ? 2 : 3; |
+ *red = lastChannel - *red; |
+ *green = lastChannel - *green; |
+ *blue = lastChannel - *blue; |
+ } |
+ } |
+ |
+ const char* GetPixelData(CGImageRef cgImage) { |
+ CFDataRef data = CGDataProviderCopyData(CGImageGetDataProvider(cgImage)); |
+ return reinterpret_cast<const char*>(CFDataGetBytePtr(data)); |
+ } |
+ |
+ web::TestWebThreadBundle thread_bundle_; |
+ base::scoped_nsobject<NSMutableArray> testSessions_; |
+ base::scoped_nsobject<NSMutableArray> testImages_; |
+}; |
+ |
+// This test simply put all the snapshots in the cache and then gets them back |
+// As the snapshots are kept in memory, the same pointer can be retrieved. |
+// This test also checks that images are correctly removed from the disk. |
+TEST_F(SnapshotCacheTest, Cache) { |
+ // Don't run on tablets because color snapshots are not cached so this test |
+ // can't compare the UIImage pointers directly. |
+ if (IsIPadIdiom()) { |
+ return; |
+ } |
+ |
+ SnapshotCache* cache = [SnapshotCache sharedInstance]; |
+ |
+ // Put all images in the cache. |
+ for (NSUInteger i = 0; i < kSessionCount; ++i) { |
+ UIImage* image = [testImages_ objectAtIndex:i]; |
+ NSString* sessionID = [testSessions_ objectAtIndex:i]; |
+ [cache setImage:image withSessionID:sessionID]; |
+ } |
+ |
+ // Get images back. |
+ __block NSUInteger numberOfCallbacks = 0; |
+ for (NSUInteger i = 0; i < kSessionCount; ++i) { |
+ NSString* sessionID = [testSessions_ objectAtIndex:i]; |
+ UIImage* expectedImage = [testImages_ objectAtIndex:i]; |
+ EXPECT_TRUE(expectedImage != nil); |
+ [cache retrieveImageForSessionID:sessionID |
+ callback:^(UIImage* image) { |
+ // Images have not been removed from the |
+ // dictionnary. We expect the same pointer. |
+ EXPECT_EQ(expectedImage, image); |
+ ++numberOfCallbacks; |
+ }]; |
+ } |
+ EXPECT_EQ(kSessionCount, numberOfCallbacks); |
+} |
+ |
+// This test puts all the snapshots in the cache and flushes them to disk. |
+// The snapshots are then reloaded from the disk, and the colors are compared. |
+TEST_F(SnapshotCacheTest, SaveToDisk) { |
+ SnapshotCache* cache = [SnapshotCache sharedInstance]; |
+ |
+ // Put all images in the cache. |
+ for (NSUInteger i = 0; i < kSessionCount; ++i) { |
+ UIImage* image = [testImages_ objectAtIndex:i]; |
+ NSString* sessionID = [testSessions_ objectAtIndex:i]; |
+ [cache setImage:image withSessionID:sessionID]; |
+ } |
+ FlushRunLoops(); |
+ |
+ for (NSUInteger i = 0; i < kSessionCount; ++i) { |
+ // Check that images are on the disk. |
+ NSString* sessionID = [testSessions_ objectAtIndex:i]; |
+ |
+ base::FilePath path([SnapshotCache imagePathForSessionID:sessionID]); |
+ EXPECT_TRUE(base::PathExists(path)); |
+ |
+ // Check image colors by comparing the first pixel against the reference |
+ // image. |
+ UIImage* image = |
+ [UIImage imageWithContentsOfFile:base::SysUTF8ToNSString(path.value())]; |
+ CGImageRef cgImage = [image CGImage]; |
+ const char* pixels = GetPixelData(cgImage); |
+ EXPECT_TRUE(pixels); |
+ |
+ UIImage* referenceImage = [testImages_ objectAtIndex:i]; |
+ CGImageRef referenceCgImage = [referenceImage CGImage]; |
+ const char* referencePixels = GetPixelData(referenceCgImage); |
+ EXPECT_TRUE(referencePixels); |
+ |
+ if (pixels != nil && referencePixels != nil) { |
+ // Color components may not be in the same order, |
+ // because of writing to disk and reloading. |
+ int red, green, blue; |
+ ComputeColorComponents(cgImage, &red, &green, &blue); |
+ |
+ int referenceRed, referenceGreen, referenceBlue; |
+ ComputeColorComponents(referenceCgImage, &referenceRed, &referenceGreen, |
+ &referenceBlue); |
+ |
+ // Colors may not be exactly the same (compression or rounding errors) |
+ // thus a small difference is allowed. |
+ EXPECT_NEAR(referencePixels[referenceRed], pixels[red], 1); |
+ EXPECT_NEAR(referencePixels[referenceGreen], pixels[green], 1); |
+ EXPECT_NEAR(referencePixels[referenceBlue], pixels[blue], 1); |
+ } |
+ } |
+} |
+ |
+TEST_F(SnapshotCacheTest, Purge) { |
+ SnapshotCache* cache = [SnapshotCache sharedInstance]; |
+ |
+ // Put all images in the cache. |
+ for (NSUInteger i = 0; i < kSessionCount; ++i) { |
+ UIImage* image = [testImages_ objectAtIndex:i]; |
+ NSString* sessionID = [testSessions_ objectAtIndex:i]; |
+ [cache setImage:image withSessionID:sessionID]; |
+ } |
+ |
+ NSMutableSet* liveSessions = [NSMutableSet setWithCapacity:1]; |
+ [liveSessions addObject:[testSessions_ objectAtIndex:0]]; |
+ |
+ // Purge the cache. |
+ [cache purgeCacheOlderThan:(base::Time::Now() - base::TimeDelta::FromHours(1)) |
+ keeping:liveSessions]; |
+ FlushRunLoops(); |
+ |
+ // Check that nothing has been deleted. |
+ for (NSUInteger i = 0; i < kSessionCount; ++i) { |
+ // Check that images are on the disk. |
+ NSString* sessionID = [testSessions_ objectAtIndex:i]; |
+ |
+ base::FilePath path([SnapshotCache imagePathForSessionID:sessionID]); |
+ EXPECT_TRUE(base::PathExists(path)); |
+ } |
+ |
+ // Purge the cache. |
+ [cache purgeCacheOlderThan:base::Time::Now() keeping:liveSessions]; |
+ FlushRunLoops(); |
+ |
+ // Check that the file have been deleted. |
+ for (NSUInteger i = 0; i < kSessionCount; ++i) { |
+ // Check that images are on the disk. |
+ NSString* sessionID = [testSessions_ objectAtIndex:i]; |
+ |
+ base::FilePath path([SnapshotCache imagePathForSessionID:sessionID]); |
+ if (i == 0) |
+ EXPECT_TRUE(base::PathExists(path)); |
+ else |
+ EXPECT_FALSE(base::PathExists(path)); |
+ } |
+} |
+ |
+// Loads the color images into the cache, and pins two of them. Ensures that |
+// only the two pinned IDs remain in memory after a call to -handleLowMemory. |
+TEST_F(SnapshotCacheTest, HandleLowMemory) { |
+// TODO(droger): This test fails on iPad iOS8 device: http://crbug.com/455209 |
+#if !TARGET_IPHONE_SIMULATOR |
+ if (IsIPadIdiom() && base::ios::IsRunningOnIOS8OrLater()) { |
+ LOG(WARNING) << "Test disabled on iPad iOS8 device."; |
+ return; |
+ } |
+#endif |
+ |
+ LoadAllColorImagesIntoCache(true); |
+ |
+ SnapshotCache* cache = [SnapshotCache sharedInstance]; |
+ |
+ NSString* firstPinnedID = [testSessions_ objectAtIndex:4]; |
+ NSString* secondPinnedID = [testSessions_ objectAtIndex:6]; |
+ NSMutableSet* set = [NSMutableSet set]; |
+ [set addObject:firstPinnedID]; |
+ [set addObject:secondPinnedID]; |
+ cache.pinnedIDs = set; |
+ |
+ [cache handleLowMemory]; |
+ |
+ BOOL expectedValue = YES; |
+ if (IsIPadIdiom()) { |
+ expectedValue = NO; |
+ } |
+ EXPECT_EQ(expectedValue, [cache hasImageInMemory:firstPinnedID]); |
+ EXPECT_EQ(expectedValue, [cache hasImageInMemory:secondPinnedID]); |
+ |
+ NSString* notPinnedID = [testSessions_ objectAtIndex:2]; |
+ EXPECT_FALSE([cache hasImageInMemory:notPinnedID]); |
+ |
+ // Wait for the final image to be pulled off disk. |
+ FlushRunLoops(); |
+} |
+ |
+// Tests that createGreyCache creates the grey snapshots in the background, |
+// from color images in the in-memory cache. When the grey images are all |
+// loaded into memory, tests that the request to retrieve the grey snapshot |
+// calls the callback immediately. |
+// Disabled on simulators because it sometimes crashes. crbug/421425 |
+#if !TARGET_IPHONE_SIMULATOR |
+TEST_F(SnapshotCacheTest, CreateGreyCache) { |
+ LoadAllColorImagesIntoCache(true); |
+ |
+ // Request the creation of a grey image cache for all images. |
+ SnapshotCache* cache = [SnapshotCache sharedInstance]; |
+ [cache createGreyCache:testSessions_]; |
+ |
+ // Wait for them to be put into the grey image cache. |
+ WaitForGreyImagesInCache(kSessionCount); |
+ |
+ __block NSUInteger numberOfCallbacks = 0; |
+ for (NSUInteger i = 0; i < kSessionCount; ++i) { |
+ NSString* sessionID = [testSessions_ objectAtIndex:i]; |
+ [cache retrieveGreyImageForSessionID:sessionID |
+ callback:^(UIImage* image) { |
+ EXPECT_TRUE(image); |
+ ++numberOfCallbacks; |
+ }]; |
+ } |
+ |
+ EXPECT_EQ(numberOfCallbacks, kSessionCount); |
+} |
+ |
+// Same as previous test, except that all the color images are on disk, |
+// rather than in memory. |
+// Disabled due to the greyImage crash. b/8048597 |
+TEST_F(SnapshotCacheTest, CreateGreyCacheFromDisk) { |
+ LoadAllColorImagesIntoCache(true); |
+ |
+ // Remove color images from in-memory cache. |
+ SnapshotCache* cache = [SnapshotCache sharedInstance]; |
+ [cache handleLowMemory]; |
+ |
+ // Request the creation of a grey image cache for all images. |
+ [cache createGreyCache:testSessions_]; |
+ |
+ // Wait for them to be put into the grey image cache. |
+ WaitForGreyImagesInCache(kSessionCount); |
+ |
+ __block NSUInteger numberOfCallbacks = 0; |
+ for (NSUInteger i = 0; i < kSessionCount; ++i) { |
+ NSString* sessionID = [testSessions_ objectAtIndex:i]; |
+ [cache retrieveGreyImageForSessionID:sessionID |
+ callback:^(UIImage* image) { |
+ EXPECT_TRUE(image); |
+ ++numberOfCallbacks; |
+ }]; |
+ } |
+ |
+ EXPECT_EQ(numberOfCallbacks, kSessionCount); |
+} |
+#endif // !TARGET_IPHONE_SIMULATOR |
+ |
+// Tests mostRecentGreyBlock, which is a block to be called when the most |
+// recently requested grey image is finally loaded. |
+// The test requests three images be cached as grey images. Only the final |
+// callback of the three requests should be called. |
+// Disabled due to the greyImage crash. b/8048597 |
+TEST_F(SnapshotCacheTest, MostRecentGreyBlock) { |
+ const NSUInteger kNumImages = 3; |
+ base::scoped_nsobject<NSMutableArray> sessionIDs( |
+ [[NSMutableArray alloc] initWithCapacity:kNumImages]); |
+ [sessionIDs addObject:[testSessions_ objectAtIndex:0]]; |
+ [sessionIDs addObject:[testSessions_ objectAtIndex:1]]; |
+ [sessionIDs addObject:[testSessions_ objectAtIndex:2]]; |
+ |
+ SnapshotCache* cache = [SnapshotCache sharedInstance]; |
+ |
+ // Put 3 images in the cache. |
+ LoadColorImagesIntoCache(kNumImages, true); |
+ // Make sure the color images are only on disk, to ensure the background |
+ // thread is slow enough to queue up the requests. |
+ [cache handleLowMemory]; |
+ |
+ // Enable the grey image cache. |
+ [cache createGreyCache:sessionIDs]; |
+ |
+ // Request the grey versions |
+ __block BOOL firstCallbackCalled = NO; |
+ __block BOOL secondCallbackCalled = NO; |
+ __block BOOL thirdCallbackCalled = NO; |
+ [cache greyImageForSessionID:[testSessions_ objectAtIndex:0] |
+ callback:^(UIImage*) { |
+ firstCallbackCalled = YES; |
+ }]; |
+ [cache greyImageForSessionID:[testSessions_ objectAtIndex:1] |
+ callback:^(UIImage*) { |
+ secondCallbackCalled = YES; |
+ }]; |
+ [cache greyImageForSessionID:[testSessions_ objectAtIndex:2] |
+ callback:^(UIImage*) { |
+ thirdCallbackCalled = YES; |
+ }]; |
+ |
+ // Wait for them to be loaded. |
+ WaitForGreyImagesInCache(kNumImages); |
+ |
+ EXPECT_FALSE(firstCallbackCalled); |
+ EXPECT_FALSE(secondCallbackCalled); |
+ EXPECT_TRUE(thirdCallbackCalled); |
+} |
+ |
+// Test the function used to save a grey copy of a color snapshot fully on a |
+// background thread when the application is backgrounded. |
+// Disabled due to the greyImage crash. b/8048597 |
+TEST_F(SnapshotCacheTest, GreyImageAllInBackground) { |
+ LoadAllColorImagesIntoCache(true); |
+ |
+ SnapshotCache* cache = [SnapshotCache sharedInstance]; |
+ |
+ // Now convert every image into a grey image, on disk, in the background. |
+ for (NSUInteger i = 0; i < kSessionCount; ++i) { |
+ [cache saveGreyInBackgroundForSessionID:[testSessions_ objectAtIndex:i]]; |
+ } |
+ |
+ // Waits for the grey images for the sessions in |testSessions_| to be written |
+ // to disk, which happens in a background thread. |
+ FlushRunLoops(); |
+ |
+ for (NSString* sessionID in testSessions_.get()) { |
+ base::FilePath path([SnapshotCache greyImagePathForSessionID:sessionID]); |
+ EXPECT_TRUE(base::PathExists(path)); |
+ base::DeleteFile(path, false); |
+ } |
+} |
+ |
+// Verifies that image size and scale are preserved when writing and reading |
+// from disk. |
+TEST_F(SnapshotCacheTest, SizeAndScalePreservation) { |
+ // Create an image with the expected snapshot scale. |
+ CGFloat scale = [SnapshotCache snapshotScaleForDevice]; |
+ UIGraphicsBeginImageContextWithOptions( |
+ CGSizeMake(kSnapshotPixelSize, kSnapshotPixelSize), NO, scale); |
+ CGContextRef context = UIGraphicsGetCurrentContext(); |
+ UIImage* image = GenerateRandomImage(context); |
+ UIGraphicsEndImageContext(); |
+ |
+ // Add the image to the cache then call handle low memory to ensure the image |
+ // is read from disk instead of the in-memory cache. |
+ SnapshotCache* cache = [SnapshotCache sharedInstance]; |
+ NSString* const kSession = @"foo"; |
+ [cache setImage:image withSessionID:kSession]; |
+ FlushRunLoops(); // ensure the file is written to disk. |
+ [cache handleLowMemory]; |
+ |
+ // Retrive the image and have the callback verify the size and scale. |
+ __block BOOL callbackComplete = NO; |
+ [cache retrieveImageForSessionID:kSession |
+ callback:^(UIImage* imageFromDisk) { |
+ EXPECT_EQ(image.size.width, |
+ imageFromDisk.size.width); |
+ EXPECT_EQ(image.size.height, |
+ imageFromDisk.size.height); |
+ EXPECT_EQ(image.scale, imageFromDisk.scale); |
+ callbackComplete = YES; |
+ }]; |
+ FlushRunLoops(); |
+ EXPECT_TRUE(callbackComplete); |
+} |
+ |
+// Verifies that retina-scale images are deleted properly. |
+TEST_F(SnapshotCacheTest, DeleteRetinaImages) { |
+ if ([SnapshotCache snapshotScaleForDevice] != 2.0) { |
+ return; |
+ } |
+ |
+ // Create an image with retina scale. |
+ UIGraphicsBeginImageContextWithOptions( |
+ CGSizeMake(kSnapshotPixelSize, kSnapshotPixelSize), NO, 2.0); |
+ CGContextRef context = UIGraphicsGetCurrentContext(); |
+ UIImage* image = GenerateRandomImage(context); |
+ UIGraphicsEndImageContext(); |
+ |
+ // Add the image to the cache then call handle low memory to ensure the image |
+ // is read from disk instead of the in-memory cache. |
+ SnapshotCache* cache = [SnapshotCache sharedInstance]; |
+ NSString* const kSession = @"foo"; |
+ [cache setImage:image withSessionID:kSession]; |
+ FlushRunLoops(); // ensure the file is written to disk. |
+ [cache handleLowMemory]; |
+ |
+ // Verify the file was writted with @2x in the file name. |
+ base::FilePath retinaFile = [SnapshotCache imagePathForSessionID:kSession]; |
+ EXPECT_TRUE(base::PathExists(retinaFile)); |
+ |
+ // Delete the image. |
+ [cache removeImageWithSessionID:kSession]; |
+ FlushRunLoops(); // ensure the file is removed. |
+ |
+ EXPECT_FALSE(base::PathExists(retinaFile)); |
+} |
+ |
+} // namespace |