Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / extensions / browser / image_loader_unittest.cc
blobf1f2aadd7e0eb8cfec78984220cd8245141c8438
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.
5 #include "extensions/browser/image_loader.h"
7 #include "base/files/file_path.h"
8 #include "base/json/json_file_value_serializer.h"
9 #include "base/message_loop/message_loop.h"
10 #include "base/path_service.h"
11 #include "base/strings/string_util.h"
12 #include "content/public/browser/notification_service.h"
13 #include "content/public/test/test_browser_context.h"
14 #include "content/public/test/test_browser_thread.h"
15 #include "extensions/browser/extension_registry.h"
16 #include "extensions/browser/extensions_browser_client.h"
17 #include "extensions/browser/extensions_test.h"
18 #include "extensions/common/constants.h"
19 #include "extensions/common/extension.h"
20 #include "extensions/common/extension_icon_set.h"
21 #include "extensions/common/extension_paths.h"
22 #include "extensions/common/extension_resource.h"
23 #include "extensions/common/manifest.h"
24 #include "extensions/common/manifest_handlers/icons_handler.h"
25 #include "testing/gtest/include/gtest/gtest.h"
26 #include "third_party/skia/include/core/SkBitmap.h"
27 #include "ui/gfx/geometry/size.h"
28 #include "ui/gfx/image/image.h"
29 #include "ui/gfx/image/image_family.h"
30 #include "ui/gfx/image/image_skia.h"
32 using content::BrowserThread;
33 using content::NotificationService;
35 namespace extensions {
37 class ImageLoaderTest : public ExtensionsTest {
38 public:
39 ImageLoaderTest()
40 : image_loaded_count_(0),
41 quit_in_image_loaded_(false),
42 ui_thread_(BrowserThread::UI, &ui_loop_),
43 file_thread_(BrowserThread::FILE),
44 io_thread_(BrowserThread::IO),
45 notification_service_(NotificationService::Create()) {}
47 void OnImageLoaded(const gfx::Image& image) {
48 image_loaded_count_++;
49 if (quit_in_image_loaded_)
50 base::MessageLoop::current()->Quit();
51 image_ = image;
54 void OnImageFamilyLoaded(const gfx::ImageFamily& image_family) {
55 image_loaded_count_++;
56 if (quit_in_image_loaded_)
57 base::MessageLoop::current()->Quit();
58 image_family_ = image_family;
61 void WaitForImageLoad() {
62 quit_in_image_loaded_ = true;
63 base::MessageLoop::current()->Run();
64 quit_in_image_loaded_ = false;
67 int image_loaded_count() {
68 int result = image_loaded_count_;
69 image_loaded_count_ = 0;
70 return result;
73 scoped_refptr<Extension> CreateExtension(const char* dir_name,
74 Manifest::Location location) {
75 // Create and load an extension.
76 base::FilePath extension_dir;
77 if (!PathService::Get(DIR_TEST_DATA, &extension_dir)) {
78 EXPECT_FALSE(true);
79 return NULL;
81 extension_dir = extension_dir.AppendASCII(dir_name);
82 int error_code = 0;
83 std::string error;
84 JSONFileValueDeserializer deserializer(
85 extension_dir.AppendASCII("manifest.json"));
86 scoped_ptr<base::DictionaryValue> valid_value(
87 static_cast<base::DictionaryValue*>(
88 deserializer.Deserialize(&error_code, &error)));
89 EXPECT_EQ(0, error_code) << error;
90 if (error_code != 0)
91 return NULL;
93 EXPECT_TRUE(valid_value.get());
94 if (!valid_value)
95 return NULL;
97 return Extension::Create(
98 extension_dir, location, *valid_value, Extension::NO_FLAGS, &error);
101 gfx::Image image_;
102 gfx::ImageFamily image_family_;
104 private:
105 void SetUp() override {
106 testing::Test::SetUp();
107 file_thread_.Start();
108 io_thread_.Start();
111 int image_loaded_count_;
112 bool quit_in_image_loaded_;
113 base::MessageLoop ui_loop_;
114 content::TestBrowserThread ui_thread_;
115 content::TestBrowserThread file_thread_;
116 content::TestBrowserThread io_thread_;
117 scoped_ptr<NotificationService> notification_service_;
120 // Tests loading an image works correctly.
121 TEST_F(ImageLoaderTest, LoadImage) {
122 scoped_refptr<Extension> extension(
123 CreateExtension("image_loader", Manifest::INVALID_LOCATION));
124 ASSERT_TRUE(extension.get() != NULL);
126 ExtensionResource image_resource =
127 IconsInfo::GetIconResource(extension.get(),
128 extension_misc::EXTENSION_ICON_SMALLISH,
129 ExtensionIconSet::MATCH_EXACTLY);
130 gfx::Size max_size(extension_misc::EXTENSION_ICON_SMALLISH,
131 extension_misc::EXTENSION_ICON_SMALLISH);
132 ImageLoader loader;
133 loader.LoadImageAsync(extension.get(),
134 image_resource,
135 max_size,
136 base::Bind(&ImageLoaderTest::OnImageLoaded,
137 base::Unretained(this)));
139 // The image isn't cached, so we should not have received notification.
140 EXPECT_EQ(0, image_loaded_count());
142 WaitForImageLoad();
144 // We should have gotten the image.
145 EXPECT_FALSE(image_.IsEmpty());
146 EXPECT_EQ(1, image_loaded_count());
148 // Check that the image was loaded.
149 EXPECT_EQ(extension_misc::EXTENSION_ICON_SMALLISH,
150 image_.ToSkBitmap()->width());
153 // Tests deleting an extension while waiting for the image to load doesn't cause
154 // problems.
155 TEST_F(ImageLoaderTest, DeleteExtensionWhileWaitingForCache) {
156 scoped_refptr<Extension> extension(
157 CreateExtension("image_loader", Manifest::INVALID_LOCATION));
158 ASSERT_TRUE(extension.get() != NULL);
160 ExtensionResource image_resource =
161 IconsInfo::GetIconResource(extension.get(),
162 extension_misc::EXTENSION_ICON_SMALLISH,
163 ExtensionIconSet::MATCH_EXACTLY);
164 gfx::Size max_size(extension_misc::EXTENSION_ICON_SMALLISH,
165 extension_misc::EXTENSION_ICON_SMALLISH);
166 ImageLoader loader;
167 std::set<int> sizes;
168 sizes.insert(extension_misc::EXTENSION_ICON_SMALLISH);
169 loader.LoadImageAsync(extension.get(),
170 image_resource,
171 max_size,
172 base::Bind(&ImageLoaderTest::OnImageLoaded,
173 base::Unretained(this)));
175 // The image isn't cached, so we should not have received notification.
176 EXPECT_EQ(0, image_loaded_count());
178 // Send out notification the extension was uninstalled.
179 ExtensionRegistry::Get(browser_context())->TriggerOnUnloaded(
180 extension.get(), UnloadedExtensionInfo::REASON_UNINSTALL);
182 // Chuck the extension, that way if anyone tries to access it we should crash
183 // or get valgrind errors.
184 extension = NULL;
186 WaitForImageLoad();
188 // Even though we deleted the extension, we should still get the image.
189 // We should still have gotten the image.
190 EXPECT_EQ(1, image_loaded_count());
192 // Check that the image was loaded.
193 EXPECT_EQ(extension_misc::EXTENSION_ICON_SMALLISH,
194 image_.ToSkBitmap()->width());
197 // Tests loading multiple dimensions of the same image.
198 TEST_F(ImageLoaderTest, MultipleImages) {
199 scoped_refptr<Extension> extension(
200 CreateExtension("image_loader", Manifest::INVALID_LOCATION));
201 ASSERT_TRUE(extension.get() != NULL);
203 std::vector<ImageLoader::ImageRepresentation> info_list;
204 int sizes[] = {extension_misc::EXTENSION_ICON_BITTY,
205 extension_misc::EXTENSION_ICON_SMALLISH, };
206 for (size_t i = 0; i < arraysize(sizes); ++i) {
207 ExtensionResource resource = IconsInfo::GetIconResource(
208 extension.get(), sizes[i], ExtensionIconSet::MATCH_EXACTLY);
209 info_list.push_back(ImageLoader::ImageRepresentation(
210 resource,
211 ImageLoader::ImageRepresentation::RESIZE_WHEN_LARGER,
212 gfx::Size(sizes[i], sizes[i]),
213 ui::SCALE_FACTOR_NONE));
216 ImageLoader loader;
217 loader.LoadImagesAsync(extension.get(), info_list,
218 base::Bind(&ImageLoaderTest::OnImageLoaded,
219 base::Unretained(this)));
221 // The image isn't cached, so we should not have received notification.
222 EXPECT_EQ(0, image_loaded_count());
224 WaitForImageLoad();
226 // We should have gotten the image.
227 EXPECT_EQ(1, image_loaded_count());
229 // Check that all images were loaded.
230 std::vector<gfx::ImageSkiaRep> image_reps =
231 image_.ToImageSkia()->image_reps();
232 ASSERT_EQ(2u, image_reps.size());
234 const gfx::ImageSkiaRep* img_rep1 = &image_reps[0];
235 const gfx::ImageSkiaRep* img_rep2 = &image_reps[1];
236 EXPECT_EQ(extension_misc::EXTENSION_ICON_BITTY,
237 img_rep1->pixel_width());
238 EXPECT_EQ(extension_misc::EXTENSION_ICON_SMALLISH,
239 img_rep2->pixel_width());
242 // Tests loading multiple dimensions of the same image into an image family.
243 TEST_F(ImageLoaderTest, LoadImageFamily) {
244 scoped_refptr<Extension> extension(
245 CreateExtension("image_loader", Manifest::INVALID_LOCATION));
246 ASSERT_TRUE(extension.get() != NULL);
248 std::vector<ImageLoader::ImageRepresentation> info_list;
249 int sizes[] = {extension_misc::EXTENSION_ICON_BITTY,
250 extension_misc::EXTENSION_ICON_SMALLISH, };
251 for (size_t i = 0; i < arraysize(sizes); ++i) {
252 ExtensionResource resource = IconsInfo::GetIconResource(
253 extension.get(), sizes[i], ExtensionIconSet::MATCH_EXACTLY);
254 info_list.push_back(ImageLoader::ImageRepresentation(
255 resource,
256 ImageLoader::ImageRepresentation::NEVER_RESIZE,
257 gfx::Size(sizes[i], sizes[i]),
258 ui::SCALE_FACTOR_100P));
261 // Add a second icon of 200P which should get grouped with the smaller icon's
262 // ImageSkia.
263 ExtensionResource resource =
264 IconsInfo::GetIconResource(extension.get(),
265 extension_misc::EXTENSION_ICON_SMALLISH,
266 ExtensionIconSet::MATCH_EXACTLY);
267 info_list.push_back(ImageLoader::ImageRepresentation(
268 resource,
269 ImageLoader::ImageRepresentation::NEVER_RESIZE,
270 gfx::Size(extension_misc::EXTENSION_ICON_BITTY,
271 extension_misc::EXTENSION_ICON_BITTY),
272 ui::SCALE_FACTOR_200P));
274 ImageLoader loader;
275 loader.LoadImageFamilyAsync(extension.get(),
276 info_list,
277 base::Bind(&ImageLoaderTest::OnImageFamilyLoaded,
278 base::Unretained(this)));
280 // The image isn't cached, so we should not have received notification.
281 EXPECT_EQ(0, image_loaded_count());
283 WaitForImageLoad();
285 // We should have gotten the image.
286 EXPECT_EQ(1, image_loaded_count());
288 // Check that all images were loaded.
289 for (size_t i = 0; i < arraysize(sizes); ++i) {
290 const gfx::Image* image = image_family_.GetBest(sizes[i], sizes[i]);
291 EXPECT_EQ(sizes[i], image->Width());
294 // Check the smaller image has 2 representations of different scale factors.
295 std::vector<gfx::ImageSkiaRep> image_reps =
296 image_family_.GetBest(extension_misc::EXTENSION_ICON_BITTY,
297 extension_misc::EXTENSION_ICON_BITTY)
298 ->ToImageSkia()
299 ->image_reps();
301 ASSERT_EQ(2u, image_reps.size());
303 const gfx::ImageSkiaRep* img_rep1 = &image_reps[0];
304 const gfx::ImageSkiaRep* img_rep2 = &image_reps[1];
305 EXPECT_EQ(extension_misc::EXTENSION_ICON_BITTY, img_rep1->pixel_width());
306 EXPECT_EQ(1.0f, img_rep1->scale());
307 EXPECT_EQ(extension_misc::EXTENSION_ICON_SMALLISH, img_rep2->pixel_width());
308 EXPECT_EQ(2.0f, img_rep2->scale());
311 } // namespace extensions