1 // Copyright (c) 2012 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 "chrome/browser/extensions/image_loader.h"
7 #include "base/json/json_file_value_serializer.h"
8 #include "base/message_loop/message_loop.h"
9 #include "base/path_service.h"
10 #include "chrome/browser/chrome_notification_types.h"
11 #include "chrome/common/chrome_paths.h"
12 #include "content/public/browser/notification_service.h"
13 #include "content/public/test/test_browser_thread.h"
14 #include "extensions/common/constants.h"
15 #include "extensions/common/extension.h"
16 #include "extensions/common/extension_icon_set.h"
17 #include "extensions/common/extension_resource.h"
18 #include "extensions/common/manifest.h"
19 #include "extensions/common/manifest_handlers/icons_handler.h"
20 #include "testing/gtest/include/gtest/gtest.h"
21 #include "third_party/skia/include/core/SkBitmap.h"
22 #include "ui/file_manager/grit/file_manager_resources.h"
23 #include "ui/gfx/image/image.h"
24 #include "ui/gfx/image/image_family.h"
25 #include "ui/gfx/image/image_skia.h"
26 #include "ui/gfx/size.h"
28 using content::BrowserThread
;
29 using extensions::Extension
;
30 using extensions::ExtensionResource
;
31 using extensions::ImageLoader
;
32 using extensions::Manifest
;
33 using extensions::UnloadedExtensionInfo
;
35 class ImageLoaderTest
: public testing::Test
{
38 : image_loaded_count_(0),
39 quit_in_image_loaded_(false),
40 ui_thread_(BrowserThread::UI
, &ui_loop_
),
41 file_thread_(BrowserThread::FILE),
42 io_thread_(BrowserThread::IO
) {
45 void OnImageLoaded(const gfx::Image
& image
) {
46 image_loaded_count_
++;
47 if (quit_in_image_loaded_
)
48 base::MessageLoop::current()->Quit();
52 void OnImageFamilyLoaded(const gfx::ImageFamily
& image_family
) {
53 image_loaded_count_
++;
54 if (quit_in_image_loaded_
)
55 base::MessageLoop::current()->Quit();
56 image_family_
= image_family
;
59 void WaitForImageLoad() {
60 quit_in_image_loaded_
= true;
61 base::MessageLoop::current()->Run();
62 quit_in_image_loaded_
= false;
65 int image_loaded_count() {
66 int result
= image_loaded_count_
;
67 image_loaded_count_
= 0;
71 scoped_refptr
<Extension
> CreateExtension(const char* name
,
72 Manifest::Location location
) {
73 // Create and load an extension.
74 base::FilePath test_file
;
75 if (!PathService::Get(chrome::DIR_TEST_DATA
, &test_file
)) {
79 test_file
= test_file
.AppendASCII("extensions")
83 JSONFileValueSerializer
serializer(test_file
.AppendASCII("app.json"));
84 scoped_ptr
<base::DictionaryValue
> valid_value(
85 static_cast<base::DictionaryValue
*>(serializer
.Deserialize(&error_code
,
87 EXPECT_EQ(0, error_code
) << error
;
91 EXPECT_TRUE(valid_value
.get());
95 if (location
== Manifest::COMPONENT
) {
96 if (!PathService::Get(chrome::DIR_RESOURCES
, &test_file
)) {
100 test_file
= test_file
.AppendASCII(name
);
102 return Extension::Create(test_file
, location
, *valid_value
,
103 Extension::NO_FLAGS
, &error
);
107 gfx::ImageFamily image_family_
;
110 virtual void SetUp() OVERRIDE
{
111 testing::Test::SetUp();
112 file_thread_
.Start();
116 int image_loaded_count_
;
117 bool quit_in_image_loaded_
;
118 base::MessageLoop ui_loop_
;
119 content::TestBrowserThread ui_thread_
;
120 content::TestBrowserThread file_thread_
;
121 content::TestBrowserThread io_thread_
;
124 // Tests loading an image works correctly.
125 TEST_F(ImageLoaderTest
, LoadImage
) {
126 scoped_refptr
<Extension
> extension(CreateExtension(
127 "image_loading_tracker", Manifest::INVALID_LOCATION
));
128 ASSERT_TRUE(extension
.get() != NULL
);
130 ExtensionResource image_resource
= extensions::IconsInfo::GetIconResource(
132 extension_misc::EXTENSION_ICON_SMALLISH
,
133 ExtensionIconSet::MATCH_EXACTLY
);
134 gfx::Size
max_size(extension_misc::EXTENSION_ICON_SMALLISH
,
135 extension_misc::EXTENSION_ICON_SMALLISH
);
137 loader
.LoadImageAsync(extension
.get(),
140 base::Bind(&ImageLoaderTest::OnImageLoaded
,
141 base::Unretained(this)));
143 // The image isn't cached, so we should not have received notification.
144 EXPECT_EQ(0, image_loaded_count());
148 // We should have gotten the image.
149 EXPECT_EQ(1, image_loaded_count());
151 // Check that the image was loaded.
152 EXPECT_EQ(extension_misc::EXTENSION_ICON_SMALLISH
,
153 image_
.ToSkBitmap()->width());
156 // Tests deleting an extension while waiting for the image to load doesn't cause
158 TEST_F(ImageLoaderTest
, DeleteExtensionWhileWaitingForCache
) {
159 scoped_refptr
<Extension
> extension(CreateExtension(
160 "image_loading_tracker", Manifest::INVALID_LOCATION
));
161 ASSERT_TRUE(extension
.get() != NULL
);
163 ExtensionResource image_resource
= extensions::IconsInfo::GetIconResource(
165 extension_misc::EXTENSION_ICON_SMALLISH
,
166 ExtensionIconSet::MATCH_EXACTLY
);
167 gfx::Size
max_size(extension_misc::EXTENSION_ICON_SMALLISH
,
168 extension_misc::EXTENSION_ICON_SMALLISH
);
171 sizes
.insert(extension_misc::EXTENSION_ICON_SMALLISH
);
172 loader
.LoadImageAsync(extension
.get(),
175 base::Bind(&ImageLoaderTest::OnImageLoaded
,
176 base::Unretained(this)));
178 // The image isn't cached, so we should not have received notification.
179 EXPECT_EQ(0, image_loaded_count());
181 // Send out notification the extension was uninstalled.
182 UnloadedExtensionInfo
details(extension
.get(),
183 UnloadedExtensionInfo::REASON_UNINSTALL
);
184 content::NotificationService::current()->Notify(
185 chrome::NOTIFICATION_EXTENSION_UNLOADED_DEPRECATED
,
186 content::NotificationService::AllSources(),
187 content::Details
<UnloadedExtensionInfo
>(&details
));
189 // Chuck the extension, that way if anyone tries to access it we should crash
190 // or get valgrind errors.
195 // Even though we deleted the extension, we should still get the image.
196 // We should still have gotten the image.
197 EXPECT_EQ(1, image_loaded_count());
199 // Check that the image was loaded.
200 EXPECT_EQ(extension_misc::EXTENSION_ICON_SMALLISH
,
201 image_
.ToSkBitmap()->width());
204 // Tests loading multiple dimensions of the same image.
205 TEST_F(ImageLoaderTest
, MultipleImages
) {
206 scoped_refptr
<Extension
> extension(CreateExtension(
207 "image_loading_tracker", Manifest::INVALID_LOCATION
));
208 ASSERT_TRUE(extension
.get() != NULL
);
210 std::vector
<ImageLoader::ImageRepresentation
> info_list
;
211 int sizes
[] = {extension_misc::EXTENSION_ICON_BITTY
,
212 extension_misc::EXTENSION_ICON_SMALLISH
, };
213 for (size_t i
= 0; i
< arraysize(sizes
); ++i
) {
214 ExtensionResource resource
= extensions::IconsInfo::GetIconResource(
215 extension
.get(), sizes
[i
], ExtensionIconSet::MATCH_EXACTLY
);
216 info_list
.push_back(ImageLoader::ImageRepresentation(
218 ImageLoader::ImageRepresentation::RESIZE_WHEN_LARGER
,
219 gfx::Size(sizes
[i
], sizes
[i
]),
220 ui::SCALE_FACTOR_NONE
));
224 loader
.LoadImagesAsync(extension
.get(), info_list
,
225 base::Bind(&ImageLoaderTest::OnImageLoaded
,
226 base::Unretained(this)));
228 // The image isn't cached, so we should not have received notification.
229 EXPECT_EQ(0, image_loaded_count());
233 // We should have gotten the image.
234 EXPECT_EQ(1, image_loaded_count());
236 // Check that all images were loaded.
237 std::vector
<gfx::ImageSkiaRep
> image_reps
=
238 image_
.ToImageSkia()->image_reps();
239 ASSERT_EQ(2u, image_reps
.size());
241 const gfx::ImageSkiaRep
* img_rep1
= &image_reps
[0];
242 const gfx::ImageSkiaRep
* img_rep2
= &image_reps
[1];
243 EXPECT_EQ(extension_misc::EXTENSION_ICON_BITTY
,
244 img_rep1
->pixel_width());
245 EXPECT_EQ(extension_misc::EXTENSION_ICON_SMALLISH
,
246 img_rep2
->pixel_width());
249 // Tests loading multiple dimensions of the same image into an image family.
250 TEST_F(ImageLoaderTest
, LoadImageFamily
) {
251 scoped_refptr
<Extension
> extension(
252 CreateExtension("image_loading_tracker", Manifest::INVALID_LOCATION
));
253 ASSERT_TRUE(extension
.get() != NULL
);
255 std::vector
<ImageLoader::ImageRepresentation
> info_list
;
256 int sizes
[] = {extension_misc::EXTENSION_ICON_BITTY
,
257 extension_misc::EXTENSION_ICON_SMALLISH
, };
258 for (size_t i
= 0; i
< arraysize(sizes
); ++i
) {
259 ExtensionResource resource
= extensions::IconsInfo::GetIconResource(
260 extension
.get(), sizes
[i
], ExtensionIconSet::MATCH_EXACTLY
);
261 info_list
.push_back(ImageLoader::ImageRepresentation(
263 ImageLoader::ImageRepresentation::NEVER_RESIZE
,
264 gfx::Size(sizes
[i
], sizes
[i
]),
265 ui::SCALE_FACTOR_100P
));
268 // Add a second icon of 200P which should get grouped with the smaller icon's
270 ExtensionResource resource
= extensions::IconsInfo::GetIconResource(
272 extension_misc::EXTENSION_ICON_SMALLISH
,
273 ExtensionIconSet::MATCH_EXACTLY
);
274 info_list
.push_back(ImageLoader::ImageRepresentation(
276 ImageLoader::ImageRepresentation::NEVER_RESIZE
,
277 gfx::Size(extension_misc::EXTENSION_ICON_BITTY
,
278 extension_misc::EXTENSION_ICON_BITTY
),
279 ui::SCALE_FACTOR_200P
));
282 loader
.LoadImageFamilyAsync(extension
.get(),
284 base::Bind(&ImageLoaderTest::OnImageFamilyLoaded
,
285 base::Unretained(this)));
287 // The image isn't cached, so we should not have received notification.
288 EXPECT_EQ(0, image_loaded_count());
292 // We should have gotten the image.
293 EXPECT_EQ(1, image_loaded_count());
295 // Check that all images were loaded.
296 for (size_t i
= 0; i
< arraysize(sizes
); ++i
) {
297 const gfx::Image
* image
= image_family_
.GetBest(sizes
[i
], sizes
[i
]);
298 EXPECT_EQ(sizes
[i
], image
->Width());
301 // Check the smaller image has 2 representations of different scale factors.
302 std::vector
<gfx::ImageSkiaRep
> image_reps
=
303 image_family_
.GetBest(extension_misc::EXTENSION_ICON_BITTY
,
304 extension_misc::EXTENSION_ICON_BITTY
)
308 ASSERT_EQ(2u, image_reps
.size());
310 const gfx::ImageSkiaRep
* img_rep1
= &image_reps
[0];
311 const gfx::ImageSkiaRep
* img_rep2
= &image_reps
[1];
312 EXPECT_EQ(extension_misc::EXTENSION_ICON_BITTY
, img_rep1
->pixel_width());
313 EXPECT_EQ(1.0f
, img_rep1
->scale());
314 EXPECT_EQ(extension_misc::EXTENSION_ICON_SMALLISH
, img_rep2
->pixel_width());
315 EXPECT_EQ(2.0f
, img_rep2
->scale());
318 // Tests IsComponentExtensionResource function.
319 TEST_F(ImageLoaderTest
, IsComponentExtensionResource
) {
320 scoped_refptr
<Extension
> extension(CreateExtension(
321 "file_manager", Manifest::COMPONENT
));
322 ASSERT_TRUE(extension
.get() != NULL
);
324 ExtensionResource resource
= extensions::IconsInfo::GetIconResource(
326 extension_misc::EXTENSION_ICON_BITTY
,
327 ExtensionIconSet::MATCH_EXACTLY
);
329 #if defined(OS_CHROMEOS)
332 ImageLoader::IsComponentExtensionResource(extension
->path(),
333 resource
.relative_path(),
335 ASSERT_EQ(IDR_FILE_MANAGER_ICON_16
, resource_id
);