| 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_loading_tracker.h" | |
| 6 | |
| 7 #include "base/json/json_file_value_serializer.h" | |
| 8 #include "base/message_loop.h" | |
| 9 #include "base/path_service.h" | |
| 10 #include "chrome/common/chrome_notification_types.h" | |
| 11 #include "chrome/common/chrome_paths.h" | |
| 12 #include "chrome/common/extensions/extension.h" | |
| 13 #include "chrome/common/extensions/extension_constants.h" | |
| 14 #include "chrome/common/extensions/extension_icon_set.h" | |
| 15 #include "chrome/common/extensions/extension_resource.h" | |
| 16 #include "chrome/common/extensions/manifest.h" | |
| 17 #include "content/public/browser/notification_service.h" | |
| 18 #include "content/public/test/test_browser_thread.h" | |
| 19 #include "grit/component_extension_resources.h" | |
| 20 #include "testing/gtest/include/gtest/gtest.h" | |
| 21 #include "third_party/skia/include/core/SkBitmap.h" | |
| 22 #include "ui/gfx/image/image.h" | |
| 23 #include "ui/gfx/image/image_skia.h" | |
| 24 #include "ui/gfx/size.h" | |
| 25 | |
| 26 using content::BrowserThread; | |
| 27 using extensions::Extension; | |
| 28 using extensions::Manifest; | |
| 29 | |
| 30 class ImageLoadingTrackerTest : public testing::Test, | |
| 31 public ImageLoadingTracker::Observer { | |
| 32 public: | |
| 33 ImageLoadingTrackerTest() | |
| 34 : image_loaded_count_(0), | |
| 35 quit_in_image_loaded_(false), | |
| 36 ui_thread_(BrowserThread::UI, &ui_loop_), | |
| 37 file_thread_(BrowserThread::FILE), | |
| 38 io_thread_(BrowserThread::IO) { | |
| 39 } | |
| 40 | |
| 41 virtual void OnImageLoaded(const gfx::Image& image, | |
| 42 const std::string& extension_id, | |
| 43 int index) OVERRIDE { | |
| 44 image_loaded_count_++; | |
| 45 if (quit_in_image_loaded_) | |
| 46 MessageLoop::current()->Quit(); | |
| 47 image_ = image; | |
| 48 } | |
| 49 | |
| 50 void WaitForImageLoad() { | |
| 51 quit_in_image_loaded_ = true; | |
| 52 MessageLoop::current()->Run(); | |
| 53 quit_in_image_loaded_ = false; | |
| 54 } | |
| 55 | |
| 56 int image_loaded_count() { | |
| 57 int result = image_loaded_count_; | |
| 58 image_loaded_count_ = 0; | |
| 59 return result; | |
| 60 } | |
| 61 | |
| 62 scoped_refptr<Extension> CreateExtension(const char* name, | |
| 63 Manifest::Location location) { | |
| 64 // Create and load an extension. | |
| 65 base::FilePath test_file; | |
| 66 if (!PathService::Get(chrome::DIR_TEST_DATA, &test_file)) { | |
| 67 EXPECT_FALSE(true); | |
| 68 return NULL; | |
| 69 } | |
| 70 test_file = test_file.AppendASCII("extensions") | |
| 71 .AppendASCII(name); | |
| 72 int error_code = 0; | |
| 73 std::string error; | |
| 74 JSONFileValueSerializer serializer(test_file.AppendASCII("app.json")); | |
| 75 scoped_ptr<DictionaryValue> valid_value( | |
| 76 static_cast<DictionaryValue*>(serializer.Deserialize(&error_code, | |
| 77 &error))); | |
| 78 EXPECT_EQ(0, error_code) << error; | |
| 79 if (error_code != 0) | |
| 80 return NULL; | |
| 81 | |
| 82 EXPECT_TRUE(valid_value.get()); | |
| 83 if (!valid_value.get()) | |
| 84 return NULL; | |
| 85 | |
| 86 if (location == Manifest::COMPONENT) { | |
| 87 if (!PathService::Get(chrome::DIR_RESOURCES, &test_file)) { | |
| 88 EXPECT_FALSE(true); | |
| 89 return NULL; | |
| 90 } | |
| 91 test_file = test_file.AppendASCII(name); | |
| 92 } | |
| 93 return Extension::Create(test_file, location, *valid_value, | |
| 94 Extension::NO_FLAGS, &error); | |
| 95 } | |
| 96 | |
| 97 gfx::Image image_; | |
| 98 | |
| 99 private: | |
| 100 virtual void SetUp() { | |
| 101 file_thread_.Start(); | |
| 102 io_thread_.Start(); | |
| 103 } | |
| 104 | |
| 105 int image_loaded_count_; | |
| 106 bool quit_in_image_loaded_; | |
| 107 MessageLoop ui_loop_; | |
| 108 content::TestBrowserThread ui_thread_; | |
| 109 content::TestBrowserThread file_thread_; | |
| 110 content::TestBrowserThread io_thread_; | |
| 111 }; | |
| 112 | |
| 113 // Tests asking ImageLoadingTracker to cache pushes the result to the Extension. | |
| 114 TEST_F(ImageLoadingTrackerTest, Cache) { | |
| 115 scoped_refptr<Extension> extension(CreateExtension( | |
| 116 "image_loading_tracker", Manifest::INVALID_LOCATION)); | |
| 117 ASSERT_TRUE(extension.get() != NULL); | |
| 118 | |
| 119 ExtensionResource image_resource = | |
| 120 extension->GetIconResource(extension_misc::EXTENSION_ICON_SMALLISH, | |
| 121 ExtensionIconSet::MATCH_EXACTLY); | |
| 122 gfx::Size max_size(extension_misc::EXTENSION_ICON_SMALLISH, | |
| 123 extension_misc::EXTENSION_ICON_SMALLISH); | |
| 124 ImageLoadingTracker loader(this); | |
| 125 loader.LoadImage(extension.get(), | |
| 126 image_resource, | |
| 127 max_size, | |
| 128 ImageLoadingTracker::CACHE); | |
| 129 | |
| 130 // The image isn't cached, so we should not have received notification. | |
| 131 EXPECT_EQ(0, image_loaded_count()); | |
| 132 | |
| 133 WaitForImageLoad(); | |
| 134 | |
| 135 // We should have gotten the image. | |
| 136 EXPECT_EQ(1, image_loaded_count()); | |
| 137 | |
| 138 // Check that the image was loaded. | |
| 139 EXPECT_EQ(extension_misc::EXTENSION_ICON_SMALLISH, | |
| 140 image_.ToSkBitmap()->width()); | |
| 141 | |
| 142 // The image should be cached in the Extension. | |
| 143 EXPECT_TRUE(extension->HasCachedImage(image_resource, max_size)); | |
| 144 | |
| 145 // Make sure the image is in the extension. | |
| 146 EXPECT_EQ(extension_misc::EXTENSION_ICON_SMALLISH, | |
| 147 extension->GetCachedImage(image_resource, max_size).width()); | |
| 148 | |
| 149 // Ask the tracker for the image again, this should call us back immediately. | |
| 150 loader.LoadImage(extension.get(), | |
| 151 image_resource, | |
| 152 max_size, | |
| 153 ImageLoadingTracker::CACHE); | |
| 154 // We should have gotten the image. | |
| 155 EXPECT_EQ(1, image_loaded_count()); | |
| 156 | |
| 157 // Check that the image was loaded. | |
| 158 EXPECT_EQ(extension_misc::EXTENSION_ICON_SMALLISH, | |
| 159 image_.ToSkBitmap()->width()); | |
| 160 } | |
| 161 | |
| 162 // Tests deleting an extension while waiting for the image to load doesn't cause | |
| 163 // problems. | |
| 164 TEST_F(ImageLoadingTrackerTest, DeleteExtensionWhileWaitingForCache) { | |
| 165 scoped_refptr<Extension> extension(CreateExtension( | |
| 166 "image_loading_tracker", Manifest::INVALID_LOCATION)); | |
| 167 ASSERT_TRUE(extension.get() != NULL); | |
| 168 | |
| 169 ExtensionResource image_resource = | |
| 170 extension->GetIconResource(extension_misc::EXTENSION_ICON_SMALLISH, | |
| 171 ExtensionIconSet::MATCH_EXACTLY); | |
| 172 ImageLoadingTracker loader(this); | |
| 173 loader.LoadImage(extension.get(), | |
| 174 image_resource, | |
| 175 gfx::Size(extension_misc::EXTENSION_ICON_SMALLISH, | |
| 176 extension_misc::EXTENSION_ICON_SMALLISH), | |
| 177 ImageLoadingTracker::CACHE); | |
| 178 | |
| 179 // The image isn't cached, so we should not have received notification. | |
| 180 EXPECT_EQ(0, image_loaded_count()); | |
| 181 | |
| 182 // Send out notification the extension was uninstalled. | |
| 183 extensions::UnloadedExtensionInfo details(extension.get(), | |
| 184 extension_misc::UNLOAD_REASON_UNINSTALL); | |
| 185 content::NotificationService::current()->Notify( | |
| 186 chrome::NOTIFICATION_EXTENSION_UNLOADED, | |
| 187 content::NotificationService::AllSources(), | |
| 188 content::Details<extensions::UnloadedExtensionInfo>(&details)); | |
| 189 | |
| 190 // Chuck the extension, that way if anyone tries to access it we should crash | |
| 191 // or get valgrind errors. | |
| 192 extension = NULL; | |
| 193 | |
| 194 WaitForImageLoad(); | |
| 195 | |
| 196 // Even though we deleted the extension, we should still get the image. | |
| 197 // We should still have gotten the image. | |
| 198 EXPECT_EQ(1, image_loaded_count()); | |
| 199 | |
| 200 // Check that the image was loaded. | |
| 201 EXPECT_EQ(extension_misc::EXTENSION_ICON_SMALLISH, | |
| 202 image_.ToSkBitmap()->width()); | |
| 203 } | |
| 204 | |
| 205 // Tests loading multiple dimensions of the same image. | |
| 206 TEST_F(ImageLoadingTrackerTest, MultipleImages) { | |
| 207 scoped_refptr<Extension> extension(CreateExtension( | |
| 208 "image_loading_tracker", Manifest::INVALID_LOCATION)); | |
| 209 ASSERT_TRUE(extension.get() != NULL); | |
| 210 | |
| 211 std::vector<ImageLoadingTracker::ImageRepresentation> info_list; | |
| 212 int sizes[] = {extension_misc::EXTENSION_ICON_SMALLISH, | |
| 213 extension_misc::EXTENSION_ICON_BITTY}; | |
| 214 for (size_t i = 0; i < arraysize(sizes); ++i) { | |
| 215 ExtensionResource resource = | |
| 216 extension->GetIconResource(sizes[i], ExtensionIconSet::MATCH_EXACTLY); | |
| 217 info_list.push_back(ImageLoadingTracker::ImageRepresentation( | |
| 218 resource, | |
| 219 ImageLoadingTracker::ImageRepresentation::RESIZE_WHEN_LARGER, | |
| 220 gfx::Size(sizes[i], sizes[i]), | |
| 221 ui::SCALE_FACTOR_NONE)); | |
| 222 } | |
| 223 | |
| 224 ImageLoadingTracker loader(this); | |
| 225 loader.LoadImages(extension.get(), info_list, ImageLoadingTracker::CACHE); | |
| 226 | |
| 227 // The image isn't cached, so we should not have received notification. | |
| 228 EXPECT_EQ(0, image_loaded_count()); | |
| 229 | |
| 230 WaitForImageLoad(); | |
| 231 | |
| 232 // We should have gotten the image. | |
| 233 EXPECT_EQ(1, image_loaded_count()); | |
| 234 | |
| 235 // Check that all images were loaded. | |
| 236 std::vector<gfx::ImageSkiaRep> image_reps = | |
| 237 image_.ToImageSkia()->image_reps(); | |
| 238 ASSERT_EQ(2u, image_reps.size()); | |
| 239 const gfx::ImageSkiaRep* img_rep1 = &image_reps[0]; | |
| 240 const gfx::ImageSkiaRep* img_rep2 = &image_reps[1]; | |
| 241 if (img_rep1->pixel_width() > img_rep2->pixel_width()) { | |
| 242 std::swap(img_rep1, img_rep2); | |
| 243 } | |
| 244 EXPECT_EQ(extension_misc::EXTENSION_ICON_BITTY, | |
| 245 img_rep1->pixel_width()); | |
| 246 EXPECT_EQ(extension_misc::EXTENSION_ICON_SMALLISH, | |
| 247 img_rep2->pixel_width()); | |
| 248 } | |
| OLD | NEW |