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 #include "base/files/scoped_temp_dir.h" 8 #include "base/strings/string_number_conversions.h" 9 #include "components/enhanced_bookmarks/image_store_util.h" 10 #include "components/enhanced_bookmarks/persistent_image_store.h" 11 #include "components/enhanced_bookmarks/test_image_store.h" 12 #include "testing/platform_test.h" 13 #include "third_party/skia/include/core/SkBitmap.h" 14 #include "url/gurl.h" 15 16 namespace { 17 18 gfx::Image CreateImage(int width, int height, int a, int r, int g, int b) { 19 SkBitmap bitmap; 20 bitmap.allocN32Pixels(width, height); 21 bitmap.eraseARGB(a, r, g, b); 22 gfx::Image image(gfx::Image::CreateFrom1xBitmap(bitmap)); 23 24 #if defined(OS_IOS) 25 // Make sure the image has a kImageRepCocoaTouch. 26 image.ToUIImage(); 27 #endif // defined(OS_IOS) 28 29 return image; 30 } 31 32 gfx::Image GenerateWhiteImage() { 33 return CreateImage(42, 24, 255, 255, 255, 255); 34 } 35 36 gfx::Image GenerateBlackImage(int width, int height) { 37 return CreateImage(width, height, 255, 0, 0, 0); 38 } 39 40 gfx::Image GenerateBlackImage() { 41 return GenerateBlackImage(42, 24); 42 } 43 44 // Returns true if the two images are identical. 45 bool CompareImages(const gfx::Image& image_1, const gfx::Image& image_2) { 46 if (image_1.IsEmpty() && image_2.IsEmpty()) 47 return true; 48 49 if (image_1.IsEmpty() || image_2.IsEmpty()) 50 return false; 51 52 scoped_refptr<base::RefCountedMemory> image_1_bytes = 53 enhanced_bookmarks::BytesForImage(image_1); 54 scoped_refptr<base::RefCountedMemory> image_2_bytes = 55 enhanced_bookmarks::BytesForImage(image_2); 56 57 if (image_1_bytes->size() != image_2_bytes->size()) 58 return false; 59 60 return !memcmp(image_1_bytes->front(), 61 image_2_bytes->front(), 62 image_1_bytes->size()); 63 } 64 65 // Factory functions for creating instances of the implementations. 66 template <class T> 67 ImageStore* CreateStore(base::ScopedTempDir& folder); 68 69 template <> 70 ImageStore* CreateStore<TestImageStore>( 71 base::ScopedTempDir& folder) { 72 return new TestImageStore(); 73 } 74 75 template <> 76 ImageStore* CreateStore<PersistentImageStore>( 77 base::ScopedTempDir& folder) { 78 return new PersistentImageStore(folder.path()); 79 } 80 81 // Methods to check if persistence is on or not. 82 template <class T> bool ShouldPersist(); 83 template <> bool ShouldPersist<TestImageStore>() { return false; } 84 template <> bool ShouldPersist<PersistentImageStore>() { return true; } 85 86 // Test fixture class template for the abstract API. 87 template <class T> 88 class ImageStoreUnitTest : public PlatformTest { 89 protected: 90 ImageStoreUnitTest() {} 91 virtual ~ImageStoreUnitTest() {} 92 93 virtual void SetUp() OVERRIDE { 94 bool success = tempDir_.CreateUniqueTempDir(); 95 ASSERT_TRUE(success); 96 store_.reset(CreateStore<T>(tempDir_)); 97 } 98 99 virtual void TearDown() OVERRIDE { 100 if (store_ && use_persistent_store()) 101 store_->ClearAll(); 102 } 103 104 bool use_persistent_store() const { return ShouldPersist<T>(); } 105 void ResetStore() { store_.reset(CreateStore<T>(tempDir_)); } 106 107 // The directory the database is saved into. 108 base::ScopedTempDir tempDir_; 109 // The object the fixture is testing, via its base interface. 110 scoped_ptr<ImageStore> store_; 111 112 private: 113 DISALLOW_COPY_AND_ASSIGN(ImageStoreUnitTest); 114 }; 115 116 // The list of implementations of the abstract API that are going to be tested. 117 typedef testing::Types<TestImageStore, 118 PersistentImageStore> Implementations; 119 120 TYPED_TEST_CASE(ImageStoreUnitTest, Implementations); 121 122 // All those tests are run on all the implementations. 123 TYPED_TEST(ImageStoreUnitTest, StartsEmpty) { 124 std::set<GURL> all_urls; 125 this->store_->GetAllPageUrls(&all_urls); 126 EXPECT_EQ(0u, all_urls.size()); 127 } 128 129 TYPED_TEST(ImageStoreUnitTest, StoreOne) { 130 this->store_->Insert(GURL("foo://bar"), GURL("a.jpg"), GenerateBlackImage()); 131 132 std::set<GURL> all_urls; 133 this->store_->GetAllPageUrls(&all_urls); 134 EXPECT_EQ(1u, all_urls.size()); 135 EXPECT_EQ(GURL("foo://bar"), *all_urls.begin()); 136 EXPECT_TRUE(this->store_->HasKey(GURL("foo://bar"))); 137 } 138 139 TYPED_TEST(ImageStoreUnitTest, Retrieve) { 140 gfx::Image src_image = GenerateBlackImage(42, 24); 141 const GURL url("foo://bar"); 142 const GURL image_url("a.jpg"); 143 this->store_->Insert(url, image_url, src_image); 144 145 std::pair<gfx::Image, GURL> image_info = this->store_->Get(url); 146 gfx::Size size = this->store_->GetSize(url); 147 148 EXPECT_EQ(size.width(), 42); 149 EXPECT_EQ(size.height(), 24); 150 EXPECT_EQ(image_url, image_info.second); 151 EXPECT_TRUE(CompareImages(src_image, image_info.first)); 152 } 153 154 TYPED_TEST(ImageStoreUnitTest, Erase) { 155 gfx::Image src_image = GenerateBlackImage(); 156 const GURL url("foo://bar"); 157 const GURL image_url("a.jpg"); 158 this->store_->Insert(url, image_url, src_image); 159 this->store_->Erase(url); 160 161 EXPECT_FALSE(this->store_->HasKey(url)); 162 std::set<GURL> all_urls; 163 this->store_->GetAllPageUrls(&all_urls); 164 EXPECT_EQ(0u, all_urls.size()); 165 } 166 167 TYPED_TEST(ImageStoreUnitTest, ClearAll) { 168 const GURL url_foo("http://foo"); 169 this->store_->Insert(url_foo, GURL("foo.jpg"), GenerateBlackImage()); 170 const GURL url_bar("http://bar"); 171 this->store_->Insert(url_foo, GURL("bar.jpg"), GenerateWhiteImage()); 172 173 this->store_->ClearAll(); 174 175 EXPECT_FALSE(this->store_->HasKey(url_foo)); 176 EXPECT_FALSE(this->store_->HasKey(url_bar)); 177 std::set<GURL> all_urls; 178 this->store_->GetAllPageUrls(&all_urls); 179 EXPECT_EQ(0u, all_urls.size()); 180 } 181 182 TYPED_TEST(ImageStoreUnitTest, Update) { 183 gfx::Image src_image1 = GenerateWhiteImage(); 184 gfx::Image src_image2 = GenerateBlackImage(); 185 const GURL url("foo://bar"); 186 const GURL image_url1("1.jpg"); 187 this->store_->Insert(url, image_url1, src_image1); 188 189 const GURL image_url2("2.jpg"); 190 this->store_->Insert(url, image_url2, src_image2); 191 192 std::pair<gfx::Image, GURL> image_info = this->store_->Get(url); 193 194 EXPECT_TRUE(this->store_->HasKey(url)); 195 std::set<GURL> all_urls; 196 this->store_->GetAllPageUrls(&all_urls); 197 EXPECT_EQ(1u, all_urls.size()); 198 EXPECT_EQ(image_url2, image_info.second); 199 EXPECT_TRUE(CompareImages(src_image2, image_info.first)); 200 } 201 202 TYPED_TEST(ImageStoreUnitTest, Persistence) { 203 gfx::Image src_image = GenerateBlackImage(); 204 const GURL url("foo://bar"); 205 const GURL image_url("a.jpg"); 206 this->store_->Insert(url, image_url, src_image); 207 208 this->ResetStore(); 209 if (this->use_persistent_store()) { 210 std::set<GURL> all_urls; 211 this->store_->GetAllPageUrls(&all_urls); 212 EXPECT_EQ(1u, all_urls.size()); 213 EXPECT_EQ(GURL("foo://bar"), *all_urls.begin()); 214 EXPECT_TRUE(this->store_->HasKey(GURL("foo://bar"))); 215 std::pair<gfx::Image, GURL> image_info = this->store_->Get(url); 216 217 EXPECT_EQ(image_url, image_info.second); 218 EXPECT_TRUE(CompareImages(src_image, image_info.first)); 219 } else { 220 std::set<GURL> all_urls; 221 this->store_->GetAllPageUrls(&all_urls); 222 EXPECT_EQ(0u, all_urls.size()); 223 EXPECT_FALSE(this->store_->HasKey(GURL("foo://bar"))); 224 } 225 } 226 227 TYPED_TEST(ImageStoreUnitTest, GetSize) { 228 gfx::Image src_image = GenerateBlackImage(); 229 const GURL url("foo://bar"); 230 const GURL image_url("a.jpg"); 231 232 int64 size = 0; 233 if (this->use_persistent_store()) { 234 // File shouldn't exist before we actually start using it since we do lazy 235 // initialization. 236 EXPECT_EQ(this->store_->GetStoreSizeInBytes(), -1); 237 } else { 238 EXPECT_LE(this->store_->GetStoreSizeInBytes(), 1024); 239 } 240 for (int i = 0; i < 100; ++i) { 241 this->store_->Insert( 242 GURL(url.spec() + '/' + base::IntToString(i)), image_url, src_image); 243 EXPECT_GE(this->store_->GetStoreSizeInBytes(), size); 244 size = this->store_->GetStoreSizeInBytes(); 245 } 246 247 if (this->use_persistent_store()) { 248 EXPECT_GE(this->store_->GetStoreSizeInBytes(), 90 * 1024); // 90kb 249 EXPECT_LE(this->store_->GetStoreSizeInBytes(), 200 * 1024); // 200kb 250 } else { 251 EXPECT_GE(this->store_->GetStoreSizeInBytes(), 400 * 1024); // 400kb 252 EXPECT_LE(this->store_->GetStoreSizeInBytes(), 500 * 1024); // 500kb 253 } 254 } 255 256 } // namespace 257