Home | History | Annotate | Download | only in extensions
      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/extension_function_test_utils.h"
      6 
      7 #include <string>
      8 
      9 #include "base/files/file_path.h"
     10 #include "base/json/json_reader.h"
     11 #include "base/values.h"
     12 #include "chrome/browser/extensions/api/tabs/tabs_constants.h"
     13 #include "chrome/browser/profiles/profile.h"
     14 #include "chrome/browser/ui/browser.h"
     15 #include "chrome/test/base/ui_test_utils.h"
     16 #include "components/crx_file/id_util.h"
     17 #include "extensions/browser/api_test_utils.h"
     18 #include "extensions/browser/extension_function.h"
     19 #include "extensions/browser/extension_function_dispatcher.h"
     20 #include "extensions/common/extension.h"
     21 #include "testing/gtest/include/gtest/gtest.h"
     22 
     23 using content::WebContents;
     24 using extensions::Extension;
     25 using extensions::Manifest;
     26 namespace keys = extensions::tabs_constants;
     27 
     28 namespace {
     29 
     30 class TestFunctionDispatcherDelegate
     31     : public extensions::ExtensionFunctionDispatcher::Delegate {
     32  public:
     33   explicit TestFunctionDispatcherDelegate(Browser* browser) :
     34       browser_(browser) {}
     35   virtual ~TestFunctionDispatcherDelegate() {}
     36 
     37  private:
     38   virtual extensions::WindowController* GetExtensionWindowController()
     39       const OVERRIDE {
     40     return browser_->extension_window_controller();
     41   }
     42 
     43   virtual WebContents* GetAssociatedWebContents() const OVERRIDE {
     44     return NULL;
     45   }
     46 
     47   Browser* browser_;
     48 };
     49 
     50 }  // namespace
     51 
     52 namespace extension_function_test_utils {
     53 
     54 base::Value* ParseJSON(const std::string& data) {
     55   return base::JSONReader::Read(data);
     56 }
     57 
     58 base::ListValue* ParseList(const std::string& data) {
     59   base::Value* result = ParseJSON(data);
     60   base::ListValue* list = NULL;
     61   result->GetAsList(&list);
     62   return list;
     63 }
     64 
     65 base::DictionaryValue* ParseDictionary(
     66     const std::string& data) {
     67   base::Value* result = ParseJSON(data);
     68   base::DictionaryValue* dict = NULL;
     69   result->GetAsDictionary(&dict);
     70   return dict;
     71 }
     72 
     73 bool GetBoolean(base::DictionaryValue* val, const std::string& key) {
     74   bool result = false;
     75   if (!val->GetBoolean(key, &result))
     76       ADD_FAILURE() << key << " does not exist or is not a boolean.";
     77   return result;
     78 }
     79 
     80 int GetInteger(base::DictionaryValue* val, const std::string& key) {
     81   int result = 0;
     82   if (!val->GetInteger(key, &result))
     83     ADD_FAILURE() << key << " does not exist or is not an integer.";
     84   return result;
     85 }
     86 
     87 std::string GetString(base::DictionaryValue* val, const std::string& key) {
     88   std::string result;
     89   if (!val->GetString(key, &result))
     90     ADD_FAILURE() << key << " does not exist or is not a string.";
     91   return result;
     92 }
     93 
     94 base::DictionaryValue* ToDictionary(base::Value* val) {
     95   EXPECT_TRUE(val);
     96   EXPECT_EQ(base::Value::TYPE_DICTIONARY, val->GetType());
     97   return static_cast<base::DictionaryValue*>(val);
     98 }
     99 
    100 base::ListValue* ToList(base::Value* val) {
    101   EXPECT_TRUE(val);
    102   EXPECT_EQ(base::Value::TYPE_LIST, val->GetType());
    103   return static_cast<base::ListValue*>(val);
    104 }
    105 
    106 scoped_refptr<Extension> CreateEmptyExtensionWithLocation(
    107     Manifest::Location location) {
    108   scoped_ptr<base::DictionaryValue> test_extension_value(
    109       ParseDictionary("{\"name\": \"Test\", \"version\": \"1.0\"}"));
    110   return CreateExtension(location, test_extension_value.get(), std::string());
    111 }
    112 
    113 scoped_refptr<Extension> CreateExtension(
    114     base::DictionaryValue* test_extension_value) {
    115   return CreateExtension(Manifest::INTERNAL, test_extension_value,
    116                          std::string());
    117 }
    118 
    119 scoped_refptr<Extension> CreateExtension(
    120     Manifest::Location location,
    121     base::DictionaryValue* test_extension_value,
    122     const std::string& id_input) {
    123   std::string error;
    124   const base::FilePath test_extension_path;
    125   std::string id;
    126   if (!id_input.empty())
    127     id = crx_file::id_util::GenerateId(id_input);
    128   scoped_refptr<Extension> extension(Extension::Create(
    129       test_extension_path,
    130       location,
    131       *test_extension_value,
    132       Extension::NO_FLAGS,
    133       id,
    134       &error));
    135   EXPECT_TRUE(error.empty()) << "Could not parse test extension " << error;
    136   return extension;
    137 }
    138 
    139 bool HasPrivacySensitiveFields(base::DictionaryValue* val) {
    140   std::string result;
    141   if (val->GetString(keys::kUrlKey, &result) ||
    142       val->GetString(keys::kTitleKey, &result) ||
    143       val->GetString(keys::kFaviconUrlKey, &result))
    144     return true;
    145   return false;
    146 }
    147 
    148 std::string RunFunctionAndReturnError(UIThreadExtensionFunction* function,
    149                                       const std::string& args,
    150                                       Browser* browser) {
    151   return RunFunctionAndReturnError(function, args, browser, NONE);
    152 }
    153 std::string RunFunctionAndReturnError(UIThreadExtensionFunction* function,
    154                                       const std::string& args,
    155                                       Browser* browser,
    156                                       RunFunctionFlags flags) {
    157   scoped_refptr<ExtensionFunction> function_owner(function);
    158   // Without a callback the function will not generate a result.
    159   function->set_has_callback(true);
    160   RunFunction(function, args, browser, flags);
    161   EXPECT_FALSE(function->GetResultList()) << "Did not expect a result";
    162   return function->GetError();
    163 }
    164 
    165 base::Value* RunFunctionAndReturnSingleResult(
    166     UIThreadExtensionFunction* function,
    167     const std::string& args,
    168     Browser* browser) {
    169   return RunFunctionAndReturnSingleResult(function, args, browser, NONE);
    170 }
    171 base::Value* RunFunctionAndReturnSingleResult(
    172     UIThreadExtensionFunction* function,
    173     const std::string& args,
    174     Browser* browser,
    175     RunFunctionFlags flags) {
    176   scoped_refptr<ExtensionFunction> function_owner(function);
    177   // Without a callback the function will not generate a result.
    178   function->set_has_callback(true);
    179   RunFunction(function, args, browser, flags);
    180   EXPECT_TRUE(function->GetError().empty()) << "Unexpected error: "
    181       << function->GetError();
    182   const base::Value* single_result = NULL;
    183   if (function->GetResultList() != NULL &&
    184       function->GetResultList()->Get(0, &single_result)) {
    185     return single_result->DeepCopy();
    186   }
    187   return NULL;
    188 }
    189 
    190 // This helps us be able to wait until an UIThreadExtensionFunction calls
    191 // SendResponse.
    192 class SendResponseDelegate
    193     : public UIThreadExtensionFunction::DelegateForTests {
    194  public:
    195   SendResponseDelegate() : should_post_quit_(false) {}
    196 
    197   virtual ~SendResponseDelegate() {}
    198 
    199   void set_should_post_quit(bool should_quit) {
    200     should_post_quit_ = should_quit;
    201   }
    202 
    203   bool HasResponse() {
    204     return response_.get() != NULL;
    205   }
    206 
    207   bool GetResponse() {
    208     EXPECT_TRUE(HasResponse());
    209     return *response_.get();
    210   }
    211 
    212   virtual void OnSendResponse(UIThreadExtensionFunction* function,
    213                               bool success,
    214                               bool bad_message) OVERRIDE {
    215     ASSERT_FALSE(bad_message);
    216     ASSERT_FALSE(HasResponse());
    217     response_.reset(new bool);
    218     *response_ = success;
    219     if (should_post_quit_) {
    220       base::MessageLoopForUI::current()->Quit();
    221     }
    222   }
    223 
    224  private:
    225   scoped_ptr<bool> response_;
    226   bool should_post_quit_;
    227 };
    228 
    229 bool RunFunction(UIThreadExtensionFunction* function,
    230                  const std::string& args,
    231                  Browser* browser,
    232                  RunFunctionFlags flags) {
    233   scoped_ptr<base::ListValue> parsed_args(ParseList(args));
    234   EXPECT_TRUE(parsed_args.get())
    235       << "Could not parse extension function arguments: " << args;
    236   return RunFunction(function, parsed_args.Pass(), browser, flags);
    237 }
    238 
    239 bool RunFunction(UIThreadExtensionFunction* function,
    240                  scoped_ptr<base::ListValue> args,
    241                  Browser* browser,
    242                  RunFunctionFlags flags) {
    243   TestFunctionDispatcherDelegate dispatcher_delegate(browser);
    244   scoped_ptr<extensions::ExtensionFunctionDispatcher> dispatcher(
    245       new extensions::ExtensionFunctionDispatcher(browser->profile(),
    246                                                   &dispatcher_delegate));
    247   // TODO(yoz): The cast is a hack; these flags should be defined in
    248   // only one place.  See crbug.com/394840.
    249   return extensions::api_test_utils::RunFunction(
    250       function,
    251       args.Pass(),
    252       browser->profile(),
    253       dispatcher.Pass(),
    254       static_cast<extensions::api_test_utils::RunFunctionFlags>(flags));
    255 }
    256 
    257 } // namespace extension_function_test_utils
    258