OLD | NEW |
1 // Copyright 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #import "ios/chrome/browser/snapshots/snapshot_cache.h" | 5 #import "ios/chrome/browser/snapshots/snapshot_cache.h" |
6 | 6 |
7 #import <Foundation/Foundation.h> | 7 #import <Foundation/Foundation.h> |
8 | 8 |
9 #include "base/files/file_path.h" | 9 #include "base/files/file_path.h" |
10 #include "base/files/file_util.h" | 10 #include "base/files/file_util.h" |
11 #include "base/format_macros.h" | 11 #include "base/format_macros.h" |
12 #include "base/location.h" | 12 #include "base/location.h" |
13 #include "base/mac/bind_objc_block.h" | 13 #include "base/mac/bind_objc_block.h" |
14 #include "base/mac/scoped_cftyperef.h" | 14 #include "base/mac/scoped_cftyperef.h" |
15 #include "base/mac/scoped_nsautorelease_pool.h" | |
16 #include "base/mac/scoped_nsobject.h" | |
17 #include "base/run_loop.h" | 15 #include "base/run_loop.h" |
18 #include "base/strings/sys_string_conversions.h" | 16 #include "base/strings/sys_string_conversions.h" |
19 #include "base/task_scheduler/task_scheduler.h" | 17 #include "base/task_scheduler/task_scheduler.h" |
20 #include "base/threading/sequenced_worker_pool.h" | 18 #include "base/threading/sequenced_worker_pool.h" |
21 #include "base/time/time.h" | 19 #include "base/time/time.h" |
22 #import "ios/chrome/browser/snapshots/snapshot_cache_internal.h" | 20 #import "ios/chrome/browser/snapshots/snapshot_cache_internal.h" |
23 #include "ios/web/public/test/test_web_thread_bundle.h" | 21 #include "ios/web/public/test/test_web_thread_bundle.h" |
24 #include "ios/web/public/web_thread.h" | 22 #include "ios/web/public/web_thread.h" |
25 #include "testing/gtest/include/gtest/gtest.h" | 23 #include "testing/gtest/include/gtest/gtest.h" |
26 #include "testing/gtest_mac.h" | 24 #include "testing/gtest_mac.h" |
27 #include "testing/platform_test.h" | 25 #include "testing/platform_test.h" |
28 | 26 |
| 27 #if !defined(__has_feature) || !__has_feature(objc_arc) |
| 28 #error "This file requires ARC support." |
| 29 #endif |
| 30 |
29 static const NSUInteger kSessionCount = 10; | 31 static const NSUInteger kSessionCount = 10; |
30 static const NSUInteger kSnapshotPixelSize = 8; | 32 static const NSUInteger kSnapshotPixelSize = 8; |
31 | 33 |
32 namespace { | 34 namespace { |
33 | 35 |
34 class SnapshotCacheTest : public PlatformTest { | 36 class SnapshotCacheTest : public PlatformTest { |
35 protected: | 37 protected: |
36 // Build an array of session names and an array of UIImages filled with | 38 // Build an array of session names and an array of UIImages filled with |
37 // random colors. | 39 // random colors. |
38 void SetUp() override { | 40 void SetUp() override { |
39 PlatformTest::SetUp(); | 41 PlatformTest::SetUp(); |
40 snapshotCache_.reset([[SnapshotCache alloc] init]); | 42 snapshotCache_ = [[SnapshotCache alloc] init]; |
41 testImages_.reset([[NSMutableArray alloc] initWithCapacity:kSessionCount]); | 43 testImages_ = [[NSMutableArray alloc] initWithCapacity:kSessionCount]; |
42 testSessions_.reset( | 44 testSessions_ = [[NSMutableArray alloc] initWithCapacity:kSessionCount]; |
43 [[NSMutableArray alloc] initWithCapacity:kSessionCount]); | |
44 | 45 |
45 CGFloat scale = [snapshotCache_ snapshotScaleForDevice]; | 46 CGFloat scale = [snapshotCache_ snapshotScaleForDevice]; |
46 UIGraphicsBeginImageContextWithOptions( | 47 UIGraphicsBeginImageContextWithOptions( |
47 CGSizeMake(kSnapshotPixelSize, kSnapshotPixelSize), NO, scale); | 48 CGSizeMake(kSnapshotPixelSize, kSnapshotPixelSize), NO, scale); |
48 CGContextRef context = UIGraphicsGetCurrentContext(); | 49 CGContextRef context = UIGraphicsGetCurrentContext(); |
49 srand(1); | 50 srand(1); |
50 | 51 |
51 for (NSUInteger i = 0; i < kSessionCount; ++i) { | 52 for (NSUInteger i = 0; i < kSessionCount; ++i) { |
52 UIImage* image = GenerateRandomImage(context); | 53 UIImage* image = GenerateRandomImage(context); |
53 [testImages_ addObject:image]; | 54 [testImages_ addObject:image]; |
54 [testSessions_ | 55 [testSessions_ |
55 addObject:[NSString stringWithFormat:@"SessionId-%" PRIuNS, i]]; | 56 addObject:[NSString stringWithFormat:@"SessionId-%" PRIuNS, i]]; |
56 } | 57 } |
57 | 58 |
58 UIGraphicsEndImageContext(); | 59 UIGraphicsEndImageContext(); |
59 | 60 |
60 ClearDumpedImages(); | 61 ClearDumpedImages(); |
61 } | 62 } |
62 | 63 |
63 void TearDown() override { | 64 void TearDown() override { |
64 ClearDumpedImages(); | 65 ClearDumpedImages(); |
65 [snapshotCache_ shutdown]; | 66 [snapshotCache_ shutdown]; |
66 snapshotCache_.reset(); | 67 snapshotCache_ = nil; |
67 PlatformTest::TearDown(); | 68 PlatformTest::TearDown(); |
68 } | 69 } |
69 | 70 |
70 SnapshotCache* GetSnapshotCache() { | 71 SnapshotCache* GetSnapshotCache() { return snapshotCache_; } |
71 return snapshotCache_.get(); | |
72 } | |
73 | 72 |
74 // Generates an image filled with a random color. | 73 // Generates an image filled with a random color. |
75 UIImage* GenerateRandomImage(CGContextRef context) { | 74 UIImage* GenerateRandomImage(CGContextRef context) { |
76 CGFloat r = rand() / CGFloat(RAND_MAX); | 75 CGFloat r = rand() / CGFloat(RAND_MAX); |
77 CGFloat g = rand() / CGFloat(RAND_MAX); | 76 CGFloat g = rand() / CGFloat(RAND_MAX); |
78 CGFloat b = rand() / CGFloat(RAND_MAX); | 77 CGFloat b = rand() / CGFloat(RAND_MAX); |
79 CGContextSetRGBStrokeColor(context, r, g, b, 1.0); | 78 CGContextSetRGBStrokeColor(context, r, g, b, 1.0); |
80 CGContextSetRGBFillColor(context, r, g, b, 1.0); | 79 CGContextSetRGBFillColor(context, r, g, b, 1.0); |
81 CGContextFillRect( | 80 CGContextFillRect( |
82 context, CGRectMake(0.0, 0.0, kSnapshotPixelSize, kSnapshotPixelSize)); | 81 context, CGRectMake(0.0, 0.0, kSnapshotPixelSize, kSnapshotPixelSize)); |
83 return UIGraphicsGetImageFromCurrentImageContext(); | 82 return UIGraphicsGetImageFromCurrentImageContext(); |
84 } | 83 } |
85 | 84 |
86 // Flushes all the runloops internally used by the snapshot cache. | 85 // Flushes all the runloops internally used by the snapshot cache. |
87 void FlushRunLoops() { | 86 void FlushRunLoops() { |
88 base::TaskScheduler::GetInstance()->FlushForTesting(); | 87 base::TaskScheduler::GetInstance()->FlushForTesting(); |
89 base::RunLoop().RunUntilIdle(); | 88 base::RunLoop().RunUntilIdle(); |
90 } | 89 } |
91 | 90 |
92 // This function removes the snapshots both from dictionary and from disk. | 91 // This function removes the snapshots both from dictionary and from disk. |
93 void ClearDumpedImages() { | 92 void ClearDumpedImages() { |
94 SnapshotCache* cache = GetSnapshotCache(); | 93 SnapshotCache* cache = GetSnapshotCache(); |
95 | 94 |
96 NSString* sessionID; | 95 NSString* sessionID; |
97 for (sessionID in testSessions_.get()) | 96 for (sessionID in testSessions_) |
98 [cache removeImageWithSessionID:sessionID]; | 97 [cache removeImageWithSessionID:sessionID]; |
99 | 98 |
100 FlushRunLoops(); | 99 FlushRunLoops(); |
101 // The above calls to -removeImageWithSessionID remove both the color | 100 // The above calls to -removeImageWithSessionID remove both the color |
102 // and grey snapshots for each sessionID, if they are on disk. However, | 101 // and grey snapshots for each sessionID, if they are on disk. However, |
103 // ensure we also get rid of the grey snapshots in memory. | 102 // ensure we also get rid of the grey snapshots in memory. |
104 [cache removeGreyCache]; | 103 [cache removeGreyCache]; |
105 | 104 |
106 __block BOOL foundImage = NO; | 105 __block BOOL foundImage = NO; |
107 __block NSUInteger numCallbacks = 0; | 106 __block NSUInteger numCallbacks = 0; |
108 for (sessionID in testSessions_.get()) { | 107 for (sessionID in testSessions_) { |
109 base::FilePath path([cache imagePathForSessionID:sessionID]); | 108 base::FilePath path([cache imagePathForSessionID:sessionID]); |
110 | 109 |
111 // Checks that the snapshot is not on disk. | 110 // Checks that the snapshot is not on disk. |
112 EXPECT_FALSE(base::PathExists(path)); | 111 EXPECT_FALSE(base::PathExists(path)); |
113 | 112 |
114 // Check that the snapshot is not in the dictionary. | 113 // Check that the snapshot is not in the dictionary. |
115 [cache retrieveImageForSessionID:sessionID | 114 [cache retrieveImageForSessionID:sessionID |
116 callback:^(UIImage* image) { | 115 callback:^(UIImage* image) { |
117 ++numCallbacks; | 116 ++numCallbacks; |
118 if (image) | 117 if (image) |
(...skipping 12 matching lines...) Expand all Loading... |
131 void LoadAllColorImagesIntoCache(bool waitForFilesOnDisk) { | 130 void LoadAllColorImagesIntoCache(bool waitForFilesOnDisk) { |
132 LoadColorImagesIntoCache(kSessionCount, waitForFilesOnDisk); | 131 LoadColorImagesIntoCache(kSessionCount, waitForFilesOnDisk); |
133 } | 132 } |
134 | 133 |
135 // Loads |count| color images into the cache. If |waitForFilesOnDisk| | 134 // Loads |count| color images into the cache. If |waitForFilesOnDisk| |
136 // is YES, will not return until the images have been written to disk. | 135 // is YES, will not return until the images have been written to disk. |
137 void LoadColorImagesIntoCache(NSUInteger count, bool waitForFilesOnDisk) { | 136 void LoadColorImagesIntoCache(NSUInteger count, bool waitForFilesOnDisk) { |
138 SnapshotCache* cache = GetSnapshotCache(); | 137 SnapshotCache* cache = GetSnapshotCache(); |
139 // Put color images in the cache. | 138 // Put color images in the cache. |
140 for (NSUInteger i = 0; i < count; ++i) { | 139 for (NSUInteger i = 0; i < count; ++i) { |
141 base::mac::ScopedNSAutoreleasePool pool; | 140 @autoreleasepool { |
142 UIImage* image = [testImages_ objectAtIndex:i]; | 141 UIImage* image = [testImages_ objectAtIndex:i]; |
143 NSString* sessionID = [testSessions_ objectAtIndex:i]; | 142 NSString* sessionID = [testSessions_ objectAtIndex:i]; |
144 [cache setImage:image withSessionID:sessionID]; | 143 [cache setImage:image withSessionID:sessionID]; |
| 144 } |
145 } | 145 } |
146 if (waitForFilesOnDisk) { | 146 if (waitForFilesOnDisk) { |
147 FlushRunLoops(); | 147 FlushRunLoops(); |
148 for (NSUInteger i = 0; i < count; ++i) { | 148 for (NSUInteger i = 0; i < count; ++i) { |
149 // Check that images are on the disk. | 149 // Check that images are on the disk. |
150 NSString* sessionID = [testSessions_ objectAtIndex:i]; | 150 NSString* sessionID = [testSessions_ objectAtIndex:i]; |
151 base::FilePath path([cache imagePathForSessionID:sessionID]); | 151 base::FilePath path([cache imagePathForSessionID:sessionID]); |
152 EXPECT_TRUE(base::PathExists(path)); | 152 EXPECT_TRUE(base::PathExists(path)); |
153 } | 153 } |
154 } | 154 } |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
198 // _performMemoryWarning is a private API and must not be compiled into | 198 // _performMemoryWarning is a private API and must not be compiled into |
199 // official builds. | 199 // official builds. |
200 #pragma clang diagnostic push | 200 #pragma clang diagnostic push |
201 #pragma clang diagnostic ignored "-Wundeclared-selector" | 201 #pragma clang diagnostic ignored "-Wundeclared-selector" |
202 [[UIApplication sharedApplication] | 202 [[UIApplication sharedApplication] |
203 performSelector:@selector(_performMemoryWarning)]; | 203 performSelector:@selector(_performMemoryWarning)]; |
204 #pragma clang diagnostic pop | 204 #pragma clang diagnostic pop |
205 } | 205 } |
206 | 206 |
207 web::TestWebThreadBundle thread_bundle_; | 207 web::TestWebThreadBundle thread_bundle_; |
208 base::scoped_nsobject<SnapshotCache> snapshotCache_; | 208 SnapshotCache* snapshotCache_; |
209 base::scoped_nsobject<NSMutableArray> testSessions_; | 209 NSMutableArray* testSessions_; |
210 base::scoped_nsobject<NSMutableArray> testImages_; | 210 NSMutableArray* testImages_; |
211 }; | 211 }; |
212 | 212 |
213 // This test simply put all the snapshots in the cache and then gets them back | 213 // This test simply put all the snapshots in the cache and then gets them back |
214 // As the snapshots are kept in memory, the same pointer can be retrieved. | 214 // As the snapshots are kept in memory, the same pointer can be retrieved. |
215 // This test also checks that images are correctly removed from the disk. | 215 // This test also checks that images are correctly removed from the disk. |
216 TEST_F(SnapshotCacheTest, Cache) { | 216 TEST_F(SnapshotCacheTest, Cache) { |
217 SnapshotCache* cache = GetSnapshotCache(); | 217 SnapshotCache* cache = GetSnapshotCache(); |
218 | 218 |
219 NSUInteger expectedCacheSize = MIN(kSessionCount, [cache lruCacheMaxSize]); | 219 NSUInteger expectedCacheSize = MIN(kSessionCount, [cache lruCacheMaxSize]); |
220 | 220 |
(...skipping 211 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
432 } | 432 } |
433 #endif // !TARGET_IPHONE_SIMULATOR | 433 #endif // !TARGET_IPHONE_SIMULATOR |
434 | 434 |
435 // Tests mostRecentGreyBlock, which is a block to be called when the most | 435 // Tests mostRecentGreyBlock, which is a block to be called when the most |
436 // recently requested grey image is finally loaded. | 436 // recently requested grey image is finally loaded. |
437 // The test requests three images be cached as grey images. Only the final | 437 // The test requests three images be cached as grey images. Only the final |
438 // callback of the three requests should be called. | 438 // callback of the three requests should be called. |
439 // Disabled due to the greyImage crash. b/8048597 | 439 // Disabled due to the greyImage crash. b/8048597 |
440 TEST_F(SnapshotCacheTest, MostRecentGreyBlock) { | 440 TEST_F(SnapshotCacheTest, MostRecentGreyBlock) { |
441 const NSUInteger kNumImages = 3; | 441 const NSUInteger kNumImages = 3; |
442 base::scoped_nsobject<NSMutableArray> sessionIDs( | 442 NSMutableArray* sessionIDs = |
443 [[NSMutableArray alloc] initWithCapacity:kNumImages]); | 443 [[NSMutableArray alloc] initWithCapacity:kNumImages]; |
444 [sessionIDs addObject:[testSessions_ objectAtIndex:0]]; | 444 [sessionIDs addObject:[testSessions_ objectAtIndex:0]]; |
445 [sessionIDs addObject:[testSessions_ objectAtIndex:1]]; | 445 [sessionIDs addObject:[testSessions_ objectAtIndex:1]]; |
446 [sessionIDs addObject:[testSessions_ objectAtIndex:2]]; | 446 [sessionIDs addObject:[testSessions_ objectAtIndex:2]]; |
447 | 447 |
448 SnapshotCache* cache = GetSnapshotCache(); | 448 SnapshotCache* cache = GetSnapshotCache(); |
449 | 449 |
450 // Put 3 images in the cache. | 450 // Put 3 images in the cache. |
451 LoadColorImagesIntoCache(kNumImages, true); | 451 LoadColorImagesIntoCache(kNumImages, true); |
452 // Make sure the color images are only on disk, to ensure the background | 452 // Make sure the color images are only on disk, to ensure the background |
453 // thread is slow enough to queue up the requests. | 453 // thread is slow enough to queue up the requests. |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
490 | 490 |
491 // Now convert every image into a grey image, on disk, in the background. | 491 // Now convert every image into a grey image, on disk, in the background. |
492 for (NSUInteger i = 0; i < kSessionCount; ++i) { | 492 for (NSUInteger i = 0; i < kSessionCount; ++i) { |
493 [cache saveGreyInBackgroundForSessionID:[testSessions_ objectAtIndex:i]]; | 493 [cache saveGreyInBackgroundForSessionID:[testSessions_ objectAtIndex:i]]; |
494 } | 494 } |
495 | 495 |
496 // Waits for the grey images for the sessions in |testSessions_| to be written | 496 // Waits for the grey images for the sessions in |testSessions_| to be written |
497 // to disk, which happens in a background thread. | 497 // to disk, which happens in a background thread. |
498 FlushRunLoops(); | 498 FlushRunLoops(); |
499 | 499 |
500 for (NSString* sessionID in testSessions_.get()) { | 500 for (NSString* sessionID in testSessions_) { |
501 base::FilePath path([cache greyImagePathForSessionID:sessionID]); | 501 base::FilePath path([cache greyImagePathForSessionID:sessionID]); |
502 EXPECT_TRUE(base::PathExists(path)); | 502 EXPECT_TRUE(base::PathExists(path)); |
503 base::DeleteFile(path, false); | 503 base::DeleteFile(path, false); |
504 } | 504 } |
505 } | 505 } |
506 | 506 |
507 // Verifies that image size and scale are preserved when writing and reading | 507 // Verifies that image size and scale are preserved when writing and reading |
508 // from disk. | 508 // from disk. |
509 TEST_F(SnapshotCacheTest, SizeAndScalePreservation) { | 509 TEST_F(SnapshotCacheTest, SizeAndScalePreservation) { |
510 SnapshotCache* cache = GetSnapshotCache(); | 510 SnapshotCache* cache = GetSnapshotCache(); |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
565 EXPECT_TRUE(base::PathExists(retinaFile)); | 565 EXPECT_TRUE(base::PathExists(retinaFile)); |
566 | 566 |
567 // Delete the image. | 567 // Delete the image. |
568 [cache removeImageWithSessionID:kSession]; | 568 [cache removeImageWithSessionID:kSession]; |
569 FlushRunLoops(); // ensure the file is removed. | 569 FlushRunLoops(); // ensure the file is removed. |
570 | 570 |
571 EXPECT_FALSE(base::PathExists(retinaFile)); | 571 EXPECT_FALSE(base::PathExists(retinaFile)); |
572 } | 572 } |
573 | 573 |
574 } // namespace | 574 } // namespace |
OLD | NEW |