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. 4 5 #include "chrome/browser/extensions/bookmark_app_helper.h" 6 7 #include "base/strings/utf_string_conversions.h" 8 #include "chrome/browser/extensions/extension_service.h" 9 #include "chrome/browser/extensions/extension_service_test_base.h" 10 #include "chrome/common/extensions/manifest_handlers/app_launch_info.h" 11 #include "chrome/test/base/testing_profile.h" 12 #include "content/public/browser/render_process_host.h" 13 #include "content/public/browser/web_contents.h" 14 #include "content/public/test/web_contents_tester.h" 15 #include "extensions/browser/extension_registry.h" 16 #include "extensions/common/constants.h" 17 #include "extensions/common/extension_icon_set.h" 18 #include "extensions/common/manifest_handlers/icons_handler.h" 19 #include "testing/gtest/include/gtest/gtest.h" 20 #include "third_party/skia/include/core/SkBitmap.h" 21 #include "ui/gfx/skia_util.h" 22 23 namespace { 24 25 const char kAppUrl[] = "http://www.chromium.org"; 26 const char kAppTitle[] = "Test title"; 27 const char kAlternativeAppTitle[] = "Different test title"; 28 const char kAppDescription[] = "Test description"; 29 30 const int kIconSizeTiny = extension_misc::EXTENSION_ICON_BITTY; 31 const int kIconSizeSmall = extension_misc::EXTENSION_ICON_SMALL; 32 const int kIconSizeMedium = extension_misc::EXTENSION_ICON_MEDIUM; 33 const int kIconSizeLarge = extension_misc::EXTENSION_ICON_LARGE; 34 35 class BookmarkAppHelperTest : public testing::Test { 36 public: 37 BookmarkAppHelperTest() {} 38 virtual ~BookmarkAppHelperTest() {} 39 40 private: 41 DISALLOW_COPY_AND_ASSIGN(BookmarkAppHelperTest); 42 }; 43 44 class BookmarkAppHelperExtensionServiceTest 45 : public extensions::ExtensionServiceTestBase { 46 public: 47 BookmarkAppHelperExtensionServiceTest() {} 48 virtual ~BookmarkAppHelperExtensionServiceTest() {} 49 50 virtual void SetUp() OVERRIDE { 51 extensions::ExtensionServiceTestBase::SetUp(); 52 InitializeEmptyExtensionService(); 53 service_->Init(); 54 EXPECT_EQ(0u, service_->extensions()->size()); 55 } 56 57 virtual void TearDown() OVERRIDE { 58 ExtensionServiceTestBase::TearDown(); 59 for (content::RenderProcessHost::iterator i( 60 content::RenderProcessHost::AllHostsIterator()); 61 !i.IsAtEnd(); 62 i.Advance()) { 63 content::RenderProcessHost* host = i.GetCurrentValue(); 64 if (Profile::FromBrowserContext(host->GetBrowserContext()) == 65 profile_.get()) 66 host->Cleanup(); 67 } 68 } 69 70 private: 71 DISALLOW_COPY_AND_ASSIGN(BookmarkAppHelperExtensionServiceTest); 72 }; 73 74 SkBitmap CreateSquareBitmapWithColor(int size, SkColor color) { 75 SkBitmap bitmap; 76 bitmap.allocN32Pixels(size, size); 77 bitmap.eraseColor(color); 78 return bitmap; 79 } 80 81 void ValidateBitmapSizeAndColor(SkBitmap bitmap, int size, SkColor color) { 82 // Obtain pixel lock to access pixels. 83 SkAutoLockPixels lock(bitmap); 84 EXPECT_EQ(color, bitmap.getColor(0, 0)); 85 EXPECT_EQ(size, bitmap.width()); 86 EXPECT_EQ(size, bitmap.height()); 87 } 88 89 WebApplicationInfo::IconInfo CreateIconInfoWithBitmap(int size, SkColor color) { 90 WebApplicationInfo::IconInfo icon_info; 91 icon_info.width = size; 92 icon_info.height = size; 93 icon_info.data = CreateSquareBitmapWithColor(size, color); 94 return icon_info; 95 } 96 97 void ValidateWebApplicationInfo(base::Closure callback, 98 const WebApplicationInfo& expected, 99 const WebApplicationInfo& actual) { 100 EXPECT_EQ(expected.title, actual.title); 101 EXPECT_EQ(expected.description, actual.description); 102 EXPECT_EQ(expected.app_url, actual.app_url); 103 EXPECT_EQ(expected.icons.size(), actual.icons.size()); 104 for (size_t i = 0; i < expected.icons.size(); ++i) { 105 EXPECT_EQ(expected.icons[i].width, actual.icons[i].width); 106 EXPECT_EQ(expected.icons[i].height, actual.icons[i].height); 107 EXPECT_EQ(expected.icons[i].url, actual.icons[i].url); 108 EXPECT_TRUE( 109 gfx::BitmapsAreEqual(expected.icons[i].data, actual.icons[i].data)); 110 } 111 callback.Run(); 112 } 113 114 } // namespace 115 116 namespace extensions { 117 118 class TestBookmarkAppHelper : public BookmarkAppHelper { 119 public: 120 TestBookmarkAppHelper(ExtensionService* service, 121 WebApplicationInfo web_app_info, 122 content::WebContents* contents) 123 : BookmarkAppHelper(service, web_app_info, contents) {} 124 125 virtual ~TestBookmarkAppHelper() {} 126 127 void CreationComplete(const extensions::Extension* extension, 128 const WebApplicationInfo& web_app_info) { 129 extension_ = extension; 130 } 131 132 void CompleteIconDownload( 133 bool success, 134 const std::map<GURL, std::vector<SkBitmap> >& bitmaps) { 135 BookmarkAppHelper::OnIconsDownloaded(success, bitmaps); 136 } 137 138 const Extension* extension() { return extension_; } 139 140 private: 141 const Extension* extension_; 142 143 DISALLOW_COPY_AND_ASSIGN(TestBookmarkAppHelper); 144 }; 145 146 TEST_F(BookmarkAppHelperExtensionServiceTest, CreateBookmarkApp) { 147 WebApplicationInfo web_app_info; 148 web_app_info.app_url = GURL(kAppUrl); 149 web_app_info.title = base::UTF8ToUTF16(kAppTitle); 150 web_app_info.description = base::UTF8ToUTF16(kAppDescription); 151 152 scoped_ptr<content::WebContents> contents( 153 content::WebContentsTester::CreateTestWebContents(profile_.get(), NULL)); 154 TestBookmarkAppHelper helper(service_, web_app_info, contents.get()); 155 helper.Create(base::Bind(&TestBookmarkAppHelper::CreationComplete, 156 base::Unretained(&helper))); 157 158 std::map<GURL, std::vector<SkBitmap> > icon_map; 159 icon_map[GURL(kAppUrl)].push_back( 160 CreateSquareBitmapWithColor(kIconSizeSmall, SK_ColorRED)); 161 helper.CompleteIconDownload(true, icon_map); 162 163 base::RunLoop().RunUntilIdle(); 164 EXPECT_TRUE(helper.extension()); 165 const Extension* extension = 166 service_->GetInstalledExtension(helper.extension()->id()); 167 EXPECT_TRUE(extension); 168 EXPECT_EQ(1u, service_->extensions()->size()); 169 EXPECT_TRUE(extension->from_bookmark()); 170 EXPECT_EQ(kAppTitle, extension->name()); 171 EXPECT_EQ(kAppDescription, extension->description()); 172 EXPECT_EQ(GURL(kAppUrl), AppLaunchInfo::GetLaunchWebURL(extension)); 173 EXPECT_FALSE( 174 IconsInfo::GetIconResource( 175 extension, kIconSizeSmall, ExtensionIconSet::MATCH_EXACTLY).empty()); 176 } 177 178 TEST_F(BookmarkAppHelperExtensionServiceTest, CreateBookmarkAppNoContents) { 179 WebApplicationInfo web_app_info; 180 web_app_info.app_url = GURL(kAppUrl); 181 web_app_info.title = base::UTF8ToUTF16(kAppTitle); 182 web_app_info.description = base::UTF8ToUTF16(kAppDescription); 183 web_app_info.icons.push_back( 184 CreateIconInfoWithBitmap(kIconSizeTiny, SK_ColorRED)); 185 186 TestBookmarkAppHelper helper(service_, web_app_info, NULL); 187 helper.Create(base::Bind(&TestBookmarkAppHelper::CreationComplete, 188 base::Unretained(&helper))); 189 190 base::RunLoop().RunUntilIdle(); 191 EXPECT_TRUE(helper.extension()); 192 const Extension* extension = 193 service_->GetInstalledExtension(helper.extension()->id()); 194 EXPECT_TRUE(extension); 195 EXPECT_EQ(1u, service_->extensions()->size()); 196 EXPECT_TRUE(extension->from_bookmark()); 197 EXPECT_EQ(kAppTitle, extension->name()); 198 EXPECT_EQ(kAppDescription, extension->description()); 199 EXPECT_EQ(GURL(kAppUrl), AppLaunchInfo::GetLaunchWebURL(extension)); 200 EXPECT_FALSE( 201 IconsInfo::GetIconResource( 202 extension, kIconSizeTiny, ExtensionIconSet::MATCH_EXACTLY).empty()); 203 EXPECT_FALSE( 204 IconsInfo::GetIconResource( 205 extension, kIconSizeSmall, ExtensionIconSet::MATCH_EXACTLY).empty()); 206 EXPECT_FALSE( 207 IconsInfo::GetIconResource(extension, 208 kIconSizeSmall * 2, 209 ExtensionIconSet::MATCH_EXACTLY).empty()); 210 EXPECT_FALSE( 211 IconsInfo::GetIconResource( 212 extension, kIconSizeMedium, ExtensionIconSet::MATCH_EXACTLY).empty()); 213 EXPECT_FALSE( 214 IconsInfo::GetIconResource(extension, 215 kIconSizeMedium * 2, 216 ExtensionIconSet::MATCH_EXACTLY).empty()); 217 } 218 219 TEST_F(BookmarkAppHelperExtensionServiceTest, CreateAndUpdateBookmarkApp) { 220 EXPECT_EQ(0u, registry()->enabled_extensions().size()); 221 WebApplicationInfo web_app_info; 222 web_app_info.app_url = GURL(kAppUrl); 223 web_app_info.title = base::UTF8ToUTF16(kAppTitle); 224 web_app_info.description = base::UTF8ToUTF16(kAppDescription); 225 web_app_info.icons.push_back( 226 CreateIconInfoWithBitmap(kIconSizeSmall, SK_ColorRED)); 227 228 extensions::CreateOrUpdateBookmarkApp(service_, web_app_info); 229 base::RunLoop().RunUntilIdle(); 230 231 { 232 EXPECT_EQ(1u, registry()->enabled_extensions().size()); 233 const Extension* extension = service_->extensions()->begin()->get(); 234 EXPECT_TRUE(extension->from_bookmark()); 235 EXPECT_EQ(kAppTitle, extension->name()); 236 EXPECT_EQ(kAppDescription, extension->description()); 237 EXPECT_EQ(GURL(kAppUrl), AppLaunchInfo::GetLaunchWebURL(extension)); 238 EXPECT_FALSE(extensions::IconsInfo::GetIconResource( 239 extension, kIconSizeSmall, ExtensionIconSet::MATCH_EXACTLY) 240 .empty()); 241 } 242 243 web_app_info.title = base::UTF8ToUTF16(kAlternativeAppTitle); 244 web_app_info.icons[0] = CreateIconInfoWithBitmap(kIconSizeLarge, SK_ColorRED); 245 246 extensions::CreateOrUpdateBookmarkApp(service_, web_app_info); 247 base::RunLoop().RunUntilIdle(); 248 249 { 250 EXPECT_EQ(1u, registry()->enabled_extensions().size()); 251 const Extension* extension = service_->extensions()->begin()->get(); 252 EXPECT_TRUE(extension->from_bookmark()); 253 EXPECT_EQ(kAlternativeAppTitle, extension->name()); 254 EXPECT_EQ(kAppDescription, extension->description()); 255 EXPECT_EQ(GURL(kAppUrl), AppLaunchInfo::GetLaunchWebURL(extension)); 256 EXPECT_TRUE(extensions::IconsInfo::GetIconResource( 257 extension, kIconSizeSmall, ExtensionIconSet::MATCH_EXACTLY) 258 .empty()); 259 EXPECT_FALSE(extensions::IconsInfo::GetIconResource( 260 extension, kIconSizeLarge, ExtensionIconSet::MATCH_EXACTLY) 261 .empty()); 262 } 263 } 264 265 TEST_F(BookmarkAppHelperExtensionServiceTest, GetWebApplicationInfo) { 266 WebApplicationInfo web_app_info; 267 web_app_info.app_url = GURL(kAppUrl); 268 web_app_info.title = base::UTF8ToUTF16(kAppTitle); 269 web_app_info.description = base::UTF8ToUTF16(kAppDescription); 270 271 web_app_info.icons.push_back( 272 CreateIconInfoWithBitmap(kIconSizeSmall, SK_ColorRED)); 273 web_app_info.icons.push_back( 274 CreateIconInfoWithBitmap(kIconSizeLarge, SK_ColorRED)); 275 276 extensions::CreateOrUpdateBookmarkApp(service_, web_app_info); 277 base::RunLoop().RunUntilIdle(); 278 279 EXPECT_EQ(1u, registry()->enabled_extensions().size()); 280 base::RunLoop run_loop; 281 extensions::GetWebApplicationInfoFromApp( 282 profile_.get(), 283 service_->extensions()->begin()->get(), 284 base::Bind( 285 &ValidateWebApplicationInfo, run_loop.QuitClosure(), web_app_info)); 286 run_loop.Run(); 287 } 288 289 TEST_F(BookmarkAppHelperTest, ConstrainBitmapsToSizes) { 290 std::set<int> desired_sizes; 291 desired_sizes.insert(16); 292 desired_sizes.insert(32); 293 desired_sizes.insert(128); 294 desired_sizes.insert(256); 295 296 { 297 std::vector<SkBitmap> bitmaps; 298 bitmaps.push_back(CreateSquareBitmapWithColor(16, SK_ColorRED)); 299 bitmaps.push_back(CreateSquareBitmapWithColor(32, SK_ColorGREEN)); 300 bitmaps.push_back(CreateSquareBitmapWithColor(48, SK_ColorBLUE)); 301 bitmaps.push_back(CreateSquareBitmapWithColor(144, SK_ColorYELLOW)); 302 303 std::map<int, SkBitmap> results( 304 BookmarkAppHelper::ConstrainBitmapsToSizes(bitmaps, desired_sizes)); 305 306 EXPECT_EQ(3u, results.size()); 307 ValidateBitmapSizeAndColor(results[16], 16, SK_ColorRED); 308 ValidateBitmapSizeAndColor(results[32], 32, SK_ColorGREEN); 309 ValidateBitmapSizeAndColor(results[128], 128, SK_ColorYELLOW); 310 } 311 { 312 std::vector<SkBitmap> bitmaps; 313 bitmaps.push_back(CreateSquareBitmapWithColor(512, SK_ColorRED)); 314 bitmaps.push_back(CreateSquareBitmapWithColor(18, SK_ColorGREEN)); 315 bitmaps.push_back(CreateSquareBitmapWithColor(33, SK_ColorBLUE)); 316 bitmaps.push_back(CreateSquareBitmapWithColor(17, SK_ColorYELLOW)); 317 318 std::map<int, SkBitmap> results( 319 BookmarkAppHelper::ConstrainBitmapsToSizes(bitmaps, desired_sizes)); 320 321 EXPECT_EQ(3u, results.size()); 322 ValidateBitmapSizeAndColor(results[16], 16, SK_ColorYELLOW); 323 ValidateBitmapSizeAndColor(results[32], 32, SK_ColorBLUE); 324 ValidateBitmapSizeAndColor(results[256], 256, SK_ColorRED); 325 } 326 } 327 328 TEST_F(BookmarkAppHelperTest, IsValidBookmarkAppUrl) { 329 EXPECT_TRUE(IsValidBookmarkAppUrl(GURL("https://www.chromium.org"))); 330 EXPECT_TRUE(IsValidBookmarkAppUrl(GURL("http://www.chromium.org/path"))); 331 EXPECT_FALSE(IsValidBookmarkAppUrl(GURL("ftp://www.chromium.org"))); 332 EXPECT_FALSE(IsValidBookmarkAppUrl(GURL("chrome://flags"))); 333 } 334 335 } // namespace extensions 336