OLD | NEW |
(Empty) | |
| 1 // Copyright 2014 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 #include "components/enhanced_bookmarks/image_store.h" |
| 6 |
| 7 #import <UIKit/UIKit.h> |
| 8 |
| 9 #include "base/files/scoped_temp_dir.h" |
| 10 #include "base/mac/scoped_cftyperef.h" |
| 11 #include "components/enhanced_bookmarks/image_store_util.h" |
| 12 #include "components/enhanced_bookmarks/persistent_image_store.h" |
| 13 #include "components/enhanced_bookmarks/test_image_store.h" |
| 14 #include "testing/platform_test.h" |
| 15 #include "ui/gfx/geometry/size.h" |
| 16 #include "ui/gfx/image/image.h" |
| 17 #include "url/gurl.h" |
| 18 |
| 19 namespace { |
| 20 |
| 21 // Generates a gfx::Image with a random UIImage representation. Uses off-center |
| 22 // circle gradient to make all pixels slightly different in order to detect |
| 23 // small image alterations. |
| 24 gfx::Image GenerateRandomUIImage(gfx::Size& size, float scale) { |
| 25 UIGraphicsBeginImageContextWithOptions(CGSizeMake(size.width(), |
| 26 size.height()), |
| 27 YES, // opaque. |
| 28 scale); |
| 29 // Create the gradient's colors. |
| 30 CGFloat locations[] = { 0.0, 1.0 }; |
| 31 CGFloat components[] = { rand()/CGFloat(RAND_MAX), // Start color r |
| 32 rand()/CGFloat(RAND_MAX), // g |
| 33 rand()/CGFloat(RAND_MAX), // b |
| 34 1.0, // Alpha |
| 35 rand()/CGFloat(RAND_MAX), // End color r |
| 36 rand()/CGFloat(RAND_MAX), // g |
| 37 rand()/CGFloat(RAND_MAX), // b |
| 38 1.0 }; // Alpha |
| 39 CGPoint center = CGPointMake(size.width() / 3, size.height() / 3); |
| 40 CGFloat radius = MAX(size.width(), size.height()); |
| 41 |
| 42 base::ScopedCFTypeRef<CGColorSpaceRef> |
| 43 colorspace(CGColorSpaceCreateDeviceRGB()); |
| 44 base::ScopedCFTypeRef<CGGradientRef> |
| 45 gradient(CGGradientCreateWithColorComponents(colorspace, |
| 46 components, |
| 47 locations, |
| 48 arraysize(locations))); |
| 49 CGContextDrawRadialGradient(UIGraphicsGetCurrentContext(), |
| 50 gradient, |
| 51 center, |
| 52 0, |
| 53 center, |
| 54 radius, |
| 55 kCGGradientDrawsAfterEndLocation); |
| 56 UIImage* image = UIGraphicsGetImageFromCurrentImageContext(); |
| 57 UIGraphicsEndImageContext(); |
| 58 return gfx::Image([image retain]); |
| 59 } |
| 60 |
| 61 // Returns true if the two images are identical. |
| 62 bool CompareImages(const gfx::Image& image_1, const gfx::Image& image_2) { |
| 63 if (image_1.IsEmpty() && image_2.IsEmpty()) |
| 64 return true; |
| 65 if (image_1.IsEmpty() || image_2.IsEmpty()) |
| 66 return false; |
| 67 |
| 68 scoped_refptr<base::RefCountedMemory> image_1_bytes = |
| 69 enhanced_bookmarks::BytesForImage(image_1); |
| 70 scoped_refptr<base::RefCountedMemory> image_2_bytes = |
| 71 enhanced_bookmarks::BytesForImage(image_2); |
| 72 |
| 73 if (image_1_bytes->size() != image_2_bytes->size()) |
| 74 return false; |
| 75 |
| 76 return !memcmp(image_1_bytes->front(), |
| 77 image_2_bytes->front(), |
| 78 image_1_bytes->size()); |
| 79 } |
| 80 |
| 81 // Factory functions for creating instances of the implementations. |
| 82 template <class T> |
| 83 ImageStore* CreateStore(base::ScopedTempDir& folder); |
| 84 |
| 85 template <> |
| 86 ImageStore* CreateStore<TestImageStore>( |
| 87 base::ScopedTempDir& folder) { |
| 88 return new TestImageStore(); |
| 89 } |
| 90 |
| 91 template <> |
| 92 ImageStore* CreateStore<PersistentImageStore>( |
| 93 base::ScopedTempDir& folder) { |
| 94 return new PersistentImageStore(folder.path()); |
| 95 } |
| 96 |
| 97 // Methods to check if persistence is on or not. |
| 98 template <class T> bool ShouldPersist(); |
| 99 template <> bool ShouldPersist<TestImageStore>() { return false; } |
| 100 template <> bool ShouldPersist<PersistentImageStore>() { return true; } |
| 101 |
| 102 // Test fixture class template for the abstract API. |
| 103 template <class T> |
| 104 class ImageStoreUnitTestIOS : public PlatformTest { |
| 105 protected: |
| 106 ImageStoreUnitTestIOS() {} |
| 107 virtual ~ImageStoreUnitTestIOS() {} |
| 108 |
| 109 virtual void SetUp() OVERRIDE { |
| 110 bool success = temp_dir_.CreateUniqueTempDir(); |
| 111 ASSERT_TRUE(success); |
| 112 store_.reset(CreateStore<T>(temp_dir_)); |
| 113 } |
| 114 |
| 115 virtual void TearDown() OVERRIDE { |
| 116 if (store_ && use_persistent_store()) |
| 117 store_->ClearAll(); |
| 118 } |
| 119 |
| 120 bool use_persistent_store() const { return ShouldPersist<T>(); } |
| 121 void ResetStore() { store_.reset(CreateStore<T>(temp_dir_)); } |
| 122 |
| 123 // The directory the database is saved into. |
| 124 base::ScopedTempDir temp_dir_; |
| 125 // The object the fixture is testing, via its base interface. |
| 126 scoped_ptr<ImageStore> store_; |
| 127 |
| 128 private: |
| 129 DISALLOW_COPY_AND_ASSIGN(ImageStoreUnitTestIOS); |
| 130 }; |
| 131 |
| 132 // The list of implementations of the abstract API that are going to be tested. |
| 133 typedef testing::Types<TestImageStore, |
| 134 PersistentImageStore> Implementations; |
| 135 |
| 136 TYPED_TEST_CASE(ImageStoreUnitTestIOS, Implementations); |
| 137 |
| 138 TYPED_TEST(ImageStoreUnitTestIOS, StoringImagesPreservesScale) { |
| 139 CGFloat scales[] = { 0.0, 1.0, 2.0 }; |
| 140 gfx::Size image_size(42, 24); |
| 141 for (unsigned long i = 0; i < arraysize(scales); i++) { |
| 142 gfx::Image src_image(GenerateRandomUIImage(image_size, scales[i])); |
| 143 const GURL url("foo://bar"); |
| 144 const GURL image_url("a.jpg"); |
| 145 this->store_->Insert(url, image_url, src_image); |
| 146 std::pair<gfx::Image, GURL> image_info = this->store_->Get(url); |
| 147 |
| 148 EXPECT_EQ(image_url, image_info.second); |
| 149 EXPECT_TRUE(CompareImages(src_image, image_info.first)); |
| 150 } |
| 151 } |
| 152 |
| 153 } // namespace |
OLD | NEW |