Upstream version 6.35.121.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / extensions / image_loader_unittest.cc
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.
4
5 #include "chrome/browser/extensions/image_loader.h"
6
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 "chrome/common/extensions/extension_constants.h"
13 #include "chrome/common/extensions/extension_icon_set.h"
14 #include "chrome/common/extensions/manifest_handlers/icons_handler.h"
15 #include "content/public/browser/notification_service.h"
16 #include "content/public/test/test_browser_thread.h"
17 #include "extensions/common/extension.h"
18 #include "extensions/common/extension_resource.h"
19 #include "extensions/common/manifest.h"
20 #include "grit/component_extension_resources.h"
21 #include "testing/gtest/include/gtest/gtest.h"
22 #include "third_party/skia/include/core/SkBitmap.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"
27
28 using content::BrowserThread;
29 using extensions::Extension;
30 using extensions::ExtensionResource;
31 using extensions::ImageLoader;
32 using extensions::Manifest;
33 using extensions::UnloadedExtensionInfo;
34
35 class ImageLoaderTest : public testing::Test {
36  public:
37   ImageLoaderTest()
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) {
43   }
44
45   void OnImageLoaded(const gfx::Image& image) {
46     image_loaded_count_++;
47     if (quit_in_image_loaded_)
48       base::MessageLoop::current()->Quit();
49     image_ = image;
50   }
51
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;
57   }
58
59   void WaitForImageLoad() {
60     quit_in_image_loaded_ = true;
61     base::MessageLoop::current()->Run();
62     quit_in_image_loaded_ = false;
63   }
64
65   int image_loaded_count() {
66     int result = image_loaded_count_;
67     image_loaded_count_ = 0;
68     return result;
69   }
70
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)) {
76       EXPECT_FALSE(true);
77       return NULL;
78     }
79     test_file = test_file.AppendASCII("extensions")
80                          .AppendASCII(name);
81     int error_code = 0;
82     std::string error;
83     JSONFileValueSerializer serializer(test_file.AppendASCII("app.json"));
84     scoped_ptr<base::DictionaryValue> valid_value(
85         static_cast<base::DictionaryValue*>(serializer.Deserialize(&error_code,
86                                                                    &error)));
87     EXPECT_EQ(0, error_code) << error;
88     if (error_code != 0)
89       return NULL;
90
91     EXPECT_TRUE(valid_value.get());
92     if (!valid_value)
93       return NULL;
94
95     if (location == Manifest::COMPONENT) {
96       if (!PathService::Get(chrome::DIR_RESOURCES, &test_file)) {
97         EXPECT_FALSE(true);
98         return NULL;
99       }
100       test_file = test_file.AppendASCII(name);
101     }
102     return Extension::Create(test_file, location, *valid_value,
103                              Extension::NO_FLAGS, &error);
104   }
105
106   gfx::Image image_;
107   gfx::ImageFamily image_family_;
108
109  private:
110   virtual void SetUp() OVERRIDE {
111     testing::Test::SetUp();
112     file_thread_.Start();
113     io_thread_.Start();
114   }
115
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_;
122 };
123
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);
129
130   ExtensionResource image_resource = extensions::IconsInfo::GetIconResource(
131       extension.get(),
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);
136   ImageLoader loader;
137   loader.LoadImageAsync(extension.get(),
138                         image_resource,
139                         max_size,
140                         base::Bind(&ImageLoaderTest::OnImageLoaded,
141                                    base::Unretained(this)));
142
143   // The image isn't cached, so we should not have received notification.
144   EXPECT_EQ(0, image_loaded_count());
145
146   WaitForImageLoad();
147
148   // We should have gotten the image.
149   EXPECT_EQ(1, image_loaded_count());
150
151   // Check that the image was loaded.
152   EXPECT_EQ(extension_misc::EXTENSION_ICON_SMALLISH,
153             image_.ToSkBitmap()->width());
154 }
155
156 // Tests deleting an extension while waiting for the image to load doesn't cause
157 // problems.
158 TEST_F(ImageLoaderTest, DeleteExtensionWhileWaitingForCache) {
159   scoped_refptr<Extension> extension(CreateExtension(
160       "image_loading_tracker", Manifest::INVALID_LOCATION));
161   ASSERT_TRUE(extension.get() != NULL);
162
163   ExtensionResource image_resource = extensions::IconsInfo::GetIconResource(
164       extension.get(),
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);
169   ImageLoader loader;
170   std::set<int> sizes;
171   sizes.insert(extension_misc::EXTENSION_ICON_SMALLISH);
172   loader.LoadImageAsync(extension.get(),
173                         image_resource,
174                         max_size,
175                         base::Bind(&ImageLoaderTest::OnImageLoaded,
176                                    base::Unretained(this)));
177
178   // The image isn't cached, so we should not have received notification.
179   EXPECT_EQ(0, image_loaded_count());
180
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));
188
189   // Chuck the extension, that way if anyone tries to access it we should crash
190   // or get valgrind errors.
191   extension = NULL;
192
193   WaitForImageLoad();
194
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());
198
199   // Check that the image was loaded.
200   EXPECT_EQ(extension_misc::EXTENSION_ICON_SMALLISH,
201             image_.ToSkBitmap()->width());
202 }
203
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);
209
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(
217         resource,
218         ImageLoader::ImageRepresentation::RESIZE_WHEN_LARGER,
219         gfx::Size(sizes[i], sizes[i]),
220         ui::SCALE_FACTOR_NONE));
221   }
222
223   ImageLoader loader;
224   loader.LoadImagesAsync(extension.get(), info_list,
225                          base::Bind(&ImageLoaderTest::OnImageLoaded,
226                                     base::Unretained(this)));
227
228   // The image isn't cached, so we should not have received notification.
229   EXPECT_EQ(0, image_loaded_count());
230
231   WaitForImageLoad();
232
233   // We should have gotten the image.
234   EXPECT_EQ(1, image_loaded_count());
235
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());
240
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());
247 }
248
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);
254
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(
262         resource,
263         ImageLoader::ImageRepresentation::NEVER_RESIZE,
264         gfx::Size(sizes[i], sizes[i]),
265         ui::SCALE_FACTOR_100P));
266   }
267
268   // Add a second icon of 200P which should get grouped with the smaller icon's
269   // ImageSkia.
270   ExtensionResource resource = extensions::IconsInfo::GetIconResource(
271       extension.get(),
272       extension_misc::EXTENSION_ICON_SMALLISH,
273       ExtensionIconSet::MATCH_EXACTLY);
274   info_list.push_back(ImageLoader::ImageRepresentation(
275       resource,
276       ImageLoader::ImageRepresentation::NEVER_RESIZE,
277       gfx::Size(extension_misc::EXTENSION_ICON_BITTY,
278                 extension_misc::EXTENSION_ICON_BITTY),
279       ui::SCALE_FACTOR_200P));
280
281   ImageLoader loader;
282   loader.LoadImageFamilyAsync(extension.get(),
283                               info_list,
284                               base::Bind(&ImageLoaderTest::OnImageFamilyLoaded,
285                                          base::Unretained(this)));
286
287   // The image isn't cached, so we should not have received notification.
288   EXPECT_EQ(0, image_loaded_count());
289
290   WaitForImageLoad();
291
292   // We should have gotten the image.
293   EXPECT_EQ(1, image_loaded_count());
294
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());
299   }
300
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)
305           ->ToImageSkia()
306           ->image_reps();
307
308   ASSERT_EQ(2u, image_reps.size());
309
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());
316 }
317
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);
323
324   ExtensionResource resource = extensions::IconsInfo::GetIconResource(
325       extension.get(),
326       extension_misc::EXTENSION_ICON_BITTY,
327       ExtensionIconSet::MATCH_EXACTLY);
328
329 #if defined(OS_CHROMEOS)
330   int resource_id;
331   ASSERT_EQ(true,
332             ImageLoader::IsComponentExtensionResource(extension->path(),
333                                                       resource.relative_path(),
334                                                       &resource_id));
335   ASSERT_EQ(IDR_FILE_MANAGER_ICON_16, resource_id);
336 #endif
337 }