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

Unified Diff: ios/chrome/browser/snapshots/snapshot_cache_unittest.mm

Issue 862693003: Upstream //ios/chrome/browser/snapshots (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 11 months 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 side-by-side diff with in-line comments
Download patch
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..ac44cd673c02d5eaf59a7e29c99f9810ea6cc6de
--- /dev/null
+++ b/ios/chrome/browser/snapshots/snapshot_cache_unittest.mm
@@ -0,0 +1,629 @@
+// Copyright 2012 The Chromium Authors. All rights reserved.
Paweł Hajdan Jr. 2015/01/30 12:24:29 nit: 2015
+// 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/strings/sys_string_conversions.h"
+#import "base/test/ios/wait_util.h"
+#include "base/time/time.h"
+#include "ios/chrome/browser/ui/ui_util.h"
+#include "ios/web/public/test/test_web_thread.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)
+- (void)flushOperationQueue;
+- (BOOL)hasImageInMemory:(NSString*)sessionID;
+- (BOOL)hasGreyImageInMemory:(NSString*)sessionID;
+@end
+
+@implementation SnapshotCache (TestingAdditions)
+- (void)flushOperationQueue {
+ dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
+ web::WebThread::PostBlockingPoolSequencedTask(
+ "SnapshotCacheSequenceToken", FROM_HERE,
+ base::BindBlock(^{
+ dispatch_semaphore_signal(semaphore);
+ }));
+ dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
+ dispatch_release(semaphore);
+}
+- (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 {
+ file_thread_.reset(new web::TestWebThread(web::WebThread::FILE));
+ file_thread_->Start();
+ 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();
+ }
+
+ // 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();
+ }
+
+ // 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];
+
+ [cache flushOperationQueue];
+ // 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([cache 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;
+ }];
+ }
+
+ // Spin the main message loop until all of the callbacks run. Time out
+ // after a while to avoid waiting forever.
+ NSUInteger expectedNumCallbacks = [testSessions_ count];
+ NSTimeInterval kTimeoutSec = 3;
Paweł Hajdan Jr. 2015/01/30 12:24:29 I strongly second Nico's comment about using base/
+ base::WaitUntilCondition(^bool() {
+ return numCallbacks >= expectedNumCallbacks;
+ }, nullptr, base::TimeDelta::FromSecondsD(kTimeoutSec));
+
+ // Expect that all the callbacks ran and that none retrieved an image.
+ EXPECT_EQ(expectedNumCallbacks, 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) {
+ [cache flushOperationQueue];
+ for (NSUInteger i = 0; i < count; ++i) {
+ // Check that images are on the disk.
+ NSString* sessionID = [testSessions_ objectAtIndex:i];
+ base::FilePath path([cache imagePathForSessionID:sessionID]);
+ EXPECT_TRUE(base::PathExists(path));
+ }
+ }
+ }
+
+ // Waits for the grey images for the sessions in |testSessions_| to be written
+ // to disk, which happens in a background thread.
+ void WaitForAllGreyImagesOnDisk() {
+ SnapshotCache* cache = [SnapshotCache sharedInstance];
+ NSString* sessionID;
+ NSTimeInterval kTimeoutSec = 3;
+ for (sessionID in testSessions_.get()) {
+ base::FilePath path([cache greyImagePathForSessionID:sessionID]);
+ base::WaitUntilCondition(^bool() {
+ return base::PathExists(path);
+ }, nullptr, base::TimeDelta::FromSecondsD(kTimeoutSec));
+ }
+ }
+
+ // 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];
+ NSTimeInterval kTimeoutSec = 3;
+ for (NSUInteger i = 0; i < count; i++) {
+ base::WaitUntilCondition(^bool() {
+ return [cache hasGreyImageInMemory:testSessions_[i]];
+ }, nullptr, base::TimeDelta::FromSecondsD(kTimeoutSec));
+ }
+ }
+
+ // 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));
+ }
+
+ base::scoped_nsobject<NSMutableArray> testSessions_;
+ base::scoped_nsobject<NSMutableArray> testImages_;
+ scoped_ptr<web::TestWebThread> file_thread_;
+};
+
+// 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;
+ }
+
+ ClearDumpedImages();
+
+ 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);
+
+ ClearDumpedImages();
+}
+
+// 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) {
+ ClearDumpedImages();
+
+ 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];
+ }
+ [cache flushOperationQueue];
+
+ for (NSUInteger i = 0; i < kSessionCount; ++i) {
+ // Check that images are on the disk.
+ NSString* sessionID = [testSessions_ objectAtIndex:i];
+
+ base::FilePath path([cache 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);
+ }
+ }
+
+ ClearDumpedImages();
+}
+
+TEST_F(SnapshotCacheTest, PurgeTest) {
+ ClearDumpedImages();
+
+ 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];
+ [cache flushOperationQueue];
+
+ // 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([cache imagePathForSessionID:sessionID]);
+ EXPECT_TRUE(base::PathExists(path));
+ }
+
+ // Purge the cache.
+ [cache purgeCacheOlderThan:base::Time::Now() keeping:liveSessions];
+ [cache flushOperationQueue];
+
+ // 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([cache imagePathForSessionID:sessionID]);
+ if (i == 0)
+ EXPECT_TRUE(base::PathExists(path));
+ else
+ EXPECT_FALSE(base::PathExists(path));
+ }
+ ClearDumpedImages();
+}
+
+// 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, testHandleLowMemory) {
+ ClearDumpedImages();
+ 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.
+ [cache flushOperationQueue];
+ ClearDumpedImages();
+}
+
+// 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, testCreateGreyCache) {
+ ClearDumpedImages();
+ 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);
+ ClearDumpedImages();
+}
+
+// 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, testCreateGreyCacheFromDisk) {
+ ClearDumpedImages();
+ 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);
+ ClearDumpedImages();
+}
+#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, testMostRecentGreyBlock) {
+ ClearDumpedImages();
+
+ 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);
+
+ ClearDumpedImages();
+}
+
+// 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, testGreyImageAllInBackground) {
+ ClearDumpedImages();
+ 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]];
+ }
+
+ WaitForAllGreyImagesOnDisk();
+
+ for (NSUInteger i = 0; i < kSessionCount; ++i) {
+ base::FilePath greyImagePath(
+ [cache greyImagePathForSessionID:[testSessions_ objectAtIndex:i]]);
+ EXPECT_TRUE(base::PathExists(greyImagePath));
+ base::DeleteFile(greyImagePath, false);
+ }
+
+ ClearDumpedImages();
+}
+
+// Verifies that image size and scale are preserved when writing and reading
+// from disk.
+TEST_F(SnapshotCacheTest, TestSizeAndScalePreservation) {
+ // 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];
+ [cache flushOperationQueue]; // 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;
+ }];
+
+ // Spin the main message loop until the callback is run. Time out after a
+ // a while to avoid waiting forever.
+ const NSTimeInterval kTimeoutSec = 3;
+ base::WaitUntilCondition(^bool() {
+ return callbackComplete;
+ }, nullptr, base::TimeDelta::FromSecondsD(kTimeoutSec));
+ EXPECT_TRUE(callbackComplete);
+}
+
+// Verifies that retina-scale images are deleted properly.
+TEST_F(SnapshotCacheTest, TestDeleteRetinaImages) {
+ 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];
+ [cache flushOperationQueue]; // ensure the file is written to disk.
+ [cache handleLowMemory];
+
+ // Verify the file was writted with @2x in the file name.
+ base::FilePath retinaFile = [cache imagePathForSessionID:kSession];
+ EXPECT_TRUE(base::PathExists(retinaFile));
+
+ // Delete the image.
+ [cache removeImageWithSessionID:kSession];
+ [cache flushOperationQueue]; // ensure the file is removed.
+
+ EXPECT_FALSE(base::PathExists(retinaFile));
+}
+
+} // namespace

Powered by Google App Engine
This is Rietveld 408576698