OLD | NEW |
| (Empty) |
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 "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" | |
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 } | |
OLD | NEW |