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