Home | History | Annotate | Download | only in declarative_content
      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/api/declarative_content/content_action.h"
      6 
      7 #include "base/base64.h"
      8 #include "base/run_loop.h"
      9 #include "base/test/values_test_util.h"
     10 #include "chrome/browser/extensions/extension_action.h"
     11 #include "chrome/browser/extensions/extension_action_manager.h"
     12 #include "chrome/browser/extensions/extension_service_test_base.h"
     13 #include "chrome/browser/extensions/extension_tab_util.h"
     14 #include "chrome/browser/extensions/test_extension_environment.h"
     15 #include "chrome/browser/extensions/test_extension_system.h"
     16 #include "chrome/test/base/testing_profile.h"
     17 #include "chrome/test/base/testing_profile.h"
     18 #include "content/public/browser/web_contents.h"
     19 #include "extensions/browser/extension_system.h"
     20 #include "extensions/common/extension.h"
     21 #include "extensions/common/extension_builder.h"
     22 #include "extensions/common/value_builder.h"
     23 #include "ipc/ipc_message_utils.h"
     24 #include "testing/gmock/include/gmock/gmock.h"
     25 #include "testing/gtest/include/gtest/gtest.h"
     26 #include "ui/gfx/image/image_skia.h"
     27 #include "ui/gfx/ipc/gfx_param_traits.h"
     28 
     29 namespace extensions {
     30 namespace {
     31 
     32 using base::test::ParseJson;
     33 using testing::HasSubstr;
     34 
     35 
     36 scoped_ptr<base::DictionaryValue> SimpleManifest() {
     37   return DictionaryBuilder()
     38       .Set("name", "extension")
     39       .Set("manifest_version", 2)
     40       .Set("version", "1.0")
     41       .Build();
     42 }
     43 
     44 class RequestContentScriptTest : public ExtensionServiceTestBase {
     45  public:
     46   RequestContentScriptTest()
     47       : extension_(ExtensionBuilder().SetManifest(SimpleManifest()).Build()) {};
     48 
     49   // TODO(rdevlin.cronin): This should be SetUp(), but an issues with invoking
     50   // InitializeEmptyExtensionService() within SetUp() means that we have to
     51   // call this manually within every test. This can be cleaned up once said
     52   // issue is fixed.
     53   virtual void Init() {
     54     InitializeEmptyExtensionService();
     55     static_cast<TestExtensionSystem*>(ExtensionSystem::Get(profile()))->
     56         SetReady();
     57     base::RunLoop().RunUntilIdle();
     58   }
     59 
     60   Profile* profile() { return profile_.get(); }
     61   Extension* extension() { return extension_.get(); }
     62 
     63  private:
     64   scoped_refptr<Extension> extension_;
     65 };
     66 
     67 TEST(DeclarativeContentActionTest, InvalidCreation) {
     68   TestExtensionEnvironment env;
     69   std::string error;
     70   bool bad_message = false;
     71   scoped_refptr<const ContentAction> result;
     72 
     73   // Test wrong data type passed.
     74   error.clear();
     75   result = ContentAction::Create(
     76       NULL, NULL, *ParseJson("[]"), &error, &bad_message);
     77   EXPECT_TRUE(bad_message);
     78   EXPECT_EQ("", error);
     79   EXPECT_FALSE(result.get());
     80 
     81   // Test missing instanceType element.
     82   error.clear();
     83   result = ContentAction::Create(
     84       NULL, NULL, *ParseJson("{}"), &error, &bad_message);
     85   EXPECT_TRUE(bad_message);
     86   EXPECT_EQ("", error);
     87   EXPECT_FALSE(result.get());
     88 
     89   // Test wrong instanceType element.
     90   error.clear();
     91   result = ContentAction::Create(NULL, NULL, *ParseJson(
     92       "{\n"
     93       "  \"instanceType\": \"declarativeContent.UnknownType\",\n"
     94       "}"),
     95                                  &error, &bad_message);
     96   EXPECT_THAT(error, HasSubstr("invalid instanceType"));
     97   EXPECT_FALSE(result.get());
     98 }
     99 
    100 TEST(DeclarativeContentActionTest, ShowPageActionWithoutPageAction) {
    101   TestExtensionEnvironment env;
    102 
    103   const Extension* extension = env.MakeExtension(base::DictionaryValue());
    104   std::string error;
    105   bool bad_message = false;
    106   scoped_refptr<const ContentAction> result = ContentAction::Create(
    107       NULL,
    108       extension,
    109       *ParseJson(
    110            "{\n"
    111            "  \"instanceType\": \"declarativeContent.ShowPageAction\",\n"
    112            "}"),
    113       &error,
    114       &bad_message);
    115   EXPECT_THAT(error, testing::HasSubstr("without a page action"));
    116   EXPECT_FALSE(bad_message);
    117   ASSERT_FALSE(result.get());
    118 }
    119 
    120 TEST(DeclarativeContentActionTest, ShowPageAction) {
    121   TestExtensionEnvironment env;
    122 
    123   const Extension* extension = env.MakeExtension(
    124       *ParseJson("{\"page_action\": { \"default_title\": \"Extension\" } }"));
    125   std::string error;
    126   bool bad_message = false;
    127   scoped_refptr<const ContentAction> result = ContentAction::Create(
    128       NULL,
    129       extension,
    130       *ParseJson(
    131            "{\n"
    132            "  \"instanceType\": \"declarativeContent.ShowPageAction\",\n"
    133            "}"),
    134       &error,
    135       &bad_message);
    136   EXPECT_EQ("", error);
    137   EXPECT_FALSE(bad_message);
    138   ASSERT_TRUE(result.get());
    139   EXPECT_EQ(ContentAction::ACTION_SHOW_PAGE_ACTION, result->GetType());
    140 
    141   ExtensionAction* page_action =
    142       ExtensionActionManager::Get(env.profile())->GetPageAction(*extension);
    143   scoped_ptr<content::WebContents> contents = env.MakeTab();
    144   const int tab_id = ExtensionTabUtil::GetTabId(contents.get());
    145   EXPECT_FALSE(page_action->GetIsVisible(tab_id));
    146   ContentAction::ApplyInfo apply_info = {
    147     env.profile(), contents.get()
    148   };
    149   result->Apply(extension->id(), base::Time(), &apply_info);
    150   EXPECT_TRUE(page_action->GetIsVisible(tab_id));
    151   result->Apply(extension->id(), base::Time(), &apply_info);
    152   EXPECT_TRUE(page_action->GetIsVisible(tab_id));
    153   result->Revert(extension->id(), base::Time(), &apply_info);
    154   EXPECT_TRUE(page_action->GetIsVisible(tab_id));
    155   result->Revert(extension->id(), base::Time(), &apply_info);
    156   EXPECT_FALSE(page_action->GetIsVisible(tab_id));
    157 }
    158 
    159 TEST(DeclarativeContentActionTest, SetIcon) {
    160   TestExtensionEnvironment env;
    161 
    162   // Simulate the process of passing ImageData to SetIcon::Create.
    163   SkBitmap bitmap;
    164   EXPECT_TRUE(bitmap.tryAllocN32Pixels(19, 19));
    165   bitmap.eraseARGB(0,0,0,0);
    166   uint32_t* pixels = bitmap.getAddr32(0, 0);
    167   for (int i = 0; i < 19 * 19; ++i)
    168     pixels[i] = i;
    169   IPC::Message bitmap_pickle;
    170   IPC::WriteParam(&bitmap_pickle, bitmap);
    171   std::string binary_data = std::string(
    172       static_cast<const char*>(bitmap_pickle.data()), bitmap_pickle.size());
    173   std::string data64;
    174   base::Base64Encode(binary_data, &data64);
    175 
    176   scoped_ptr<base::DictionaryValue> dict =
    177       DictionaryBuilder().Set("instanceType", "declarativeContent.SetIcon")
    178                          .Set("imageData",
    179                               DictionaryBuilder().Set("19", data64)).Build();
    180 
    181   const Extension* extension = env.MakeExtension(
    182       *ParseJson("{\"page_action\": { \"default_title\": \"Extension\" } }"));
    183   std::string error;
    184   bool bad_message = false;
    185   scoped_refptr<const ContentAction> result = ContentAction::Create(
    186       NULL,
    187       extension,
    188       *dict,
    189       &error,
    190       &bad_message);
    191   EXPECT_EQ("", error);
    192   EXPECT_FALSE(bad_message);
    193   ASSERT_TRUE(result.get());
    194   EXPECT_EQ(ContentAction::ACTION_SET_ICON, result->GetType());
    195 
    196   ExtensionAction* page_action =
    197       ExtensionActionManager::Get(env.profile())->GetPageAction(*extension);
    198   scoped_ptr<content::WebContents> contents = env.MakeTab();
    199   const int tab_id = ExtensionTabUtil::GetTabId(contents.get());
    200   EXPECT_FALSE(page_action->GetIsVisible(tab_id));
    201   ContentAction::ApplyInfo apply_info = {
    202     env.profile(), contents.get()
    203   };
    204 
    205   // The declarative icon shouldn't exist unless the content action is applied.
    206   EXPECT_TRUE(page_action->GetDeclarativeIcon(tab_id).bitmap()->empty());
    207   result->Apply(extension->id(), base::Time(), &apply_info);
    208   EXPECT_FALSE(page_action->GetDeclarativeIcon(tab_id).bitmap()->empty());
    209   result->Revert(extension->id(), base::Time(), &apply_info);
    210   EXPECT_TRUE(page_action->GetDeclarativeIcon(tab_id).bitmap()->empty());
    211 }
    212 
    213 TEST_F(RequestContentScriptTest, MissingScripts) {
    214   Init();
    215   std::string error;
    216   bool bad_message = false;
    217   scoped_refptr<const ContentAction> result = ContentAction::Create(
    218       profile(),
    219       extension(),
    220       *ParseJson(
    221           "{\n"
    222           "  \"instanceType\": \"declarativeContent.RequestContentScript\",\n"
    223           "  \"allFrames\": true,\n"
    224           "  \"matchAboutBlank\": true\n"
    225           "}"),
    226       &error,
    227       &bad_message);
    228   EXPECT_THAT(error, testing::HasSubstr("Missing parameter is required"));
    229   EXPECT_FALSE(bad_message);
    230   ASSERT_FALSE(result.get());
    231 }
    232 
    233 TEST_F(RequestContentScriptTest, CSS) {
    234   Init();
    235   std::string error;
    236   bool bad_message = false;
    237   scoped_refptr<const ContentAction> result = ContentAction::Create(
    238       profile(),
    239       extension(),
    240       *ParseJson(
    241           "{\n"
    242           "  \"instanceType\": \"declarativeContent.RequestContentScript\",\n"
    243           "  \"css\": [\"style.css\"]\n"
    244           "}"),
    245       &error,
    246       &bad_message);
    247   EXPECT_EQ("", error);
    248   EXPECT_FALSE(bad_message);
    249   ASSERT_TRUE(result.get());
    250   EXPECT_EQ(ContentAction::ACTION_REQUEST_CONTENT_SCRIPT, result->GetType());
    251 }
    252 
    253 TEST_F(RequestContentScriptTest, JS) {
    254   Init();
    255   std::string error;
    256   bool bad_message = false;
    257   scoped_refptr<const ContentAction> result = ContentAction::Create(
    258       profile(),
    259       extension(),
    260       *ParseJson(
    261           "{\n"
    262           "  \"instanceType\": \"declarativeContent.RequestContentScript\",\n"
    263           "  \"js\": [\"script.js\"]\n"
    264           "}"),
    265       &error,
    266       &bad_message);
    267   EXPECT_EQ("", error);
    268   EXPECT_FALSE(bad_message);
    269   ASSERT_TRUE(result.get());
    270   EXPECT_EQ(ContentAction::ACTION_REQUEST_CONTENT_SCRIPT, result->GetType());
    271 }
    272 
    273 TEST_F(RequestContentScriptTest, CSSBadType) {
    274   Init();
    275   std::string error;
    276   bool bad_message = false;
    277   scoped_refptr<const ContentAction> result = ContentAction::Create(
    278       profile(),
    279       extension(),
    280       *ParseJson(
    281           "{\n"
    282           "  \"instanceType\": \"declarativeContent.RequestContentScript\",\n"
    283           "  \"css\": \"style.css\"\n"
    284           "}"),
    285       &error,
    286       &bad_message);
    287   EXPECT_TRUE(bad_message);
    288   ASSERT_FALSE(result.get());
    289 }
    290 
    291 TEST_F(RequestContentScriptTest, JSBadType) {
    292   Init();
    293   std::string error;
    294   bool bad_message = false;
    295   scoped_refptr<const ContentAction> result = ContentAction::Create(
    296       profile(),
    297       extension(),
    298       *ParseJson(
    299           "{\n"
    300           "  \"instanceType\": \"declarativeContent.RequestContentScript\",\n"
    301           "  \"js\": \"script.js\"\n"
    302           "}"),
    303       &error,
    304       &bad_message);
    305   EXPECT_TRUE(bad_message);
    306   ASSERT_FALSE(result.get());
    307 }
    308 
    309 TEST_F(RequestContentScriptTest, AllFrames) {
    310   Init();
    311   std::string error;
    312   bool bad_message = false;
    313   scoped_refptr<const ContentAction> result = ContentAction::Create(
    314       profile(),
    315       extension(),
    316       *ParseJson(
    317           "{\n"
    318           "  \"instanceType\": \"declarativeContent.RequestContentScript\",\n"
    319           "  \"js\": [\"script.js\"],\n"
    320           "  \"allFrames\": true\n"
    321           "}"),
    322       &error,
    323       &bad_message);
    324   EXPECT_EQ("", error);
    325   EXPECT_FALSE(bad_message);
    326   ASSERT_TRUE(result.get());
    327   EXPECT_EQ(ContentAction::ACTION_REQUEST_CONTENT_SCRIPT, result->GetType());
    328 }
    329 
    330 TEST_F(RequestContentScriptTest, MatchAboutBlank) {
    331   Init();
    332   std::string error;
    333   bool bad_message = false;
    334   scoped_refptr<const ContentAction> result = ContentAction::Create(
    335       profile(),
    336       extension(),
    337       *ParseJson(
    338           "{\n"
    339           "  \"instanceType\": \"declarativeContent.RequestContentScript\",\n"
    340           "  \"js\": [\"script.js\"],\n"
    341           "  \"matchAboutBlank\": true\n"
    342           "}"),
    343       &error,
    344       &bad_message);
    345   EXPECT_EQ("", error);
    346   EXPECT_FALSE(bad_message);
    347   ASSERT_TRUE(result.get());
    348   EXPECT_EQ(ContentAction::ACTION_REQUEST_CONTENT_SCRIPT, result->GetType());
    349 }
    350 
    351 TEST_F(RequestContentScriptTest, AllFramesBadType) {
    352   Init();
    353   std::string error;
    354   bool bad_message = false;
    355   scoped_refptr<const ContentAction> result = ContentAction::Create(
    356       profile(),
    357       extension(),
    358       *ParseJson(
    359           "{\n"
    360           "  \"instanceType\": \"declarativeContent.RequestContentScript\",\n"
    361           "  \"js\": [\"script.js\"],\n"
    362           "  \"allFrames\": null\n"
    363           "}"),
    364       &error,
    365       &bad_message);
    366   EXPECT_TRUE(bad_message);
    367   ASSERT_FALSE(result.get());
    368 }
    369 
    370 TEST_F(RequestContentScriptTest, MatchAboutBlankBadType) {
    371   Init();
    372   std::string error;
    373   bool bad_message = false;
    374   scoped_refptr<const ContentAction> result = ContentAction::Create(
    375       profile(),
    376       extension(),
    377       *ParseJson(
    378           "{\n"
    379           "  \"instanceType\": \"declarativeContent.RequestContentScript\",\n"
    380           "  \"js\": [\"script.js\"],\n"
    381           "  \"matchAboutBlank\": null\n"
    382           "}"),
    383       &error,
    384       &bad_message);
    385   EXPECT_TRUE(bad_message);
    386   ASSERT_FALSE(result.get());
    387 }
    388 
    389 }  // namespace
    390 }  // namespace extensions
    391