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/extensions/extension_function.h"
     14 #include "chrome/browser/extensions/extension_function_dispatcher.h"
     15 #include "chrome/browser/ui/browser.h"
     16 #include "chrome/common/extensions/extension.h"
     17 #include "chrome/test/base/ui_test_utils.h"
     18 #include "extensions/common/id_util.h"
     19 #include "testing/gtest/include/gtest/gtest.h"
     20 
     21 using content::WebContents;
     22 using extensions::Extension;
     23 using extensions::Manifest;
     24 namespace keys = extensions::tabs_constants;
     25 
     26 namespace {
     27 
     28 class TestFunctionDispatcherDelegate
     29     : public ExtensionFunctionDispatcher::Delegate {
     30  public:
     31   explicit TestFunctionDispatcherDelegate(Browser* browser) :
     32       browser_(browser) {}
     33   virtual ~TestFunctionDispatcherDelegate() {}
     34 
     35  private:
     36   virtual extensions::WindowController* GetExtensionWindowController()
     37       const OVERRIDE {
     38     return browser_->extension_window_controller();
     39   }
     40 
     41   virtual WebContents* GetAssociatedWebContents() const OVERRIDE {
     42     return NULL;
     43   }
     44 
     45   Browser* browser_;
     46 };
     47 
     48 }  // namespace
     49 
     50 namespace extension_function_test_utils {
     51 
     52 base::Value* ParseJSON(const std::string& data) {
     53   return base::JSONReader::Read(data);
     54 }
     55 
     56 base::ListValue* ParseList(const std::string& data) {
     57   scoped_ptr<base::Value> result(ParseJSON(data));
     58   if (result.get() && result->IsType(base::Value::TYPE_LIST))
     59     return static_cast<base::ListValue*>(result.release());
     60   else
     61     return NULL;
     62 }
     63 
     64 base::DictionaryValue* ParseDictionary(
     65     const std::string& data) {
     66   scoped_ptr<base::Value> result(ParseJSON(data));
     67   if (result.get() && result->IsType(base::Value::TYPE_DICTIONARY))
     68     return static_cast<base::DictionaryValue*>(result.release());
     69   else
     70     return NULL;
     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> CreateEmptyExtension() {
    107   return CreateEmptyExtensionWithLocation(Manifest::INTERNAL);
    108 }
    109 
    110 scoped_refptr<Extension> CreateEmptyExtensionWithLocation(
    111     Manifest::Location location) {
    112   scoped_ptr<base::DictionaryValue> test_extension_value(
    113       ParseDictionary("{\"name\": \"Test\", \"version\": \"1.0\"}"));
    114   return CreateExtension(location, test_extension_value.get(), std::string());
    115 }
    116 
    117 scoped_refptr<Extension> CreateEmptyExtension(
    118     const std::string& id_input) {
    119   scoped_ptr<base::DictionaryValue> test_extension_value(
    120       ParseDictionary("{\"name\": \"Test\", \"version\": \"1.0\"}"));
    121   return CreateExtension(Manifest::INTERNAL, test_extension_value.get(),
    122                          id_input);
    123 }
    124 
    125 scoped_refptr<Extension> CreateExtension(
    126     base::DictionaryValue* test_extension_value) {
    127   return CreateExtension(Manifest::INTERNAL, test_extension_value,
    128                          std::string());
    129 }
    130 
    131 scoped_refptr<Extension> CreateExtension(
    132     Manifest::Location location,
    133     base::DictionaryValue* test_extension_value,
    134     const std::string& id_input) {
    135   std::string error;
    136   const base::FilePath test_extension_path;
    137   std::string id;
    138   if (!id_input.empty())
    139     id = extensions::id_util::GenerateId(id_input);
    140   scoped_refptr<Extension> extension(Extension::Create(
    141       test_extension_path,
    142       location,
    143       *test_extension_value,
    144       Extension::NO_FLAGS,
    145       id,
    146       &error));
    147   EXPECT_TRUE(error.empty()) << "Could not parse test extension " << error;
    148   return extension;
    149 }
    150 
    151 bool HasPrivacySensitiveFields(base::DictionaryValue* val) {
    152   std::string result;
    153   if (val->GetString(keys::kUrlKey, &result) ||
    154       val->GetString(keys::kTitleKey, &result) ||
    155       val->GetString(keys::kFaviconUrlKey, &result))
    156     return true;
    157   return false;
    158 }
    159 
    160 std::string RunFunctionAndReturnError(UIThreadExtensionFunction* function,
    161                                       const std::string& args,
    162                                       Browser* browser) {
    163   return RunFunctionAndReturnError(function, args, browser, NONE);
    164 }
    165 std::string RunFunctionAndReturnError(UIThreadExtensionFunction* function,
    166                                       const std::string& args,
    167                                       Browser* browser,
    168                                       RunFunctionFlags flags) {
    169   scoped_refptr<ExtensionFunction> function_owner(function);
    170   // Without a callback the function will not generate a result.
    171   function->set_has_callback(true);
    172   RunFunction(function, args, browser, flags);
    173   EXPECT_FALSE(function->GetResultList()) << "Did not expect a result";
    174   return function->GetError();
    175 }
    176 
    177 base::Value* RunFunctionAndReturnSingleResult(
    178     UIThreadExtensionFunction* function,
    179     const std::string& args,
    180     Browser* browser) {
    181   return RunFunctionAndReturnSingleResult(function, args, browser, NONE);
    182 }
    183 base::Value* RunFunctionAndReturnSingleResult(
    184     UIThreadExtensionFunction* function,
    185     const std::string& args,
    186     Browser* browser,
    187     RunFunctionFlags flags) {
    188   scoped_refptr<ExtensionFunction> function_owner(function);
    189   // Without a callback the function will not generate a result.
    190   function->set_has_callback(true);
    191   RunFunction(function, args, browser, flags);
    192   EXPECT_TRUE(function->GetError().empty()) << "Unexpected error: "
    193       << function->GetError();
    194   const base::Value* single_result = NULL;
    195   if (function->GetResultList() != NULL &&
    196       function->GetResultList()->Get(0, &single_result)) {
    197     return single_result->DeepCopy();
    198   }
    199   return NULL;
    200 }
    201 
    202 // This helps us be able to wait until an AsyncExtensionFunction calls
    203 // SendResponse.
    204 class SendResponseDelegate
    205     : public UIThreadExtensionFunction::DelegateForTests {
    206  public:
    207   SendResponseDelegate() : should_post_quit_(false) {}
    208 
    209   virtual ~SendResponseDelegate() {}
    210 
    211   void set_should_post_quit(bool should_quit) {
    212     should_post_quit_ = should_quit;
    213   }
    214 
    215   bool HasResponse() {
    216     return response_.get() != NULL;
    217   }
    218 
    219   bool GetResponse() {
    220     EXPECT_TRUE(HasResponse());
    221     return *response_.get();
    222   }
    223 
    224   virtual void OnSendResponse(UIThreadExtensionFunction* function,
    225                               bool success,
    226                               bool bad_message) OVERRIDE {
    227     ASSERT_FALSE(bad_message);
    228     ASSERT_FALSE(HasResponse());
    229     response_.reset(new bool);
    230     *response_ = success;
    231     if (should_post_quit_) {
    232       base::MessageLoopForUI::current()->Quit();
    233     }
    234   }
    235 
    236  private:
    237   scoped_ptr<bool> response_;
    238   bool should_post_quit_;
    239 };
    240 
    241 bool RunFunction(UIThreadExtensionFunction* function,
    242                  const std::string& args,
    243                  Browser* browser,
    244                  RunFunctionFlags flags) {
    245   SendResponseDelegate response_delegate;
    246   function->set_test_delegate(&response_delegate);
    247   scoped_ptr<base::ListValue> parsed_args(ParseList(args));
    248   EXPECT_TRUE(parsed_args.get()) <<
    249       "Could not parse extension function arguments: " << args;
    250   function->SetArgs(parsed_args.get());
    251 
    252   TestFunctionDispatcherDelegate dispatcher_delegate(browser);
    253   ExtensionFunctionDispatcher dispatcher(
    254       browser->profile(), &dispatcher_delegate);
    255   function->set_dispatcher(dispatcher.AsWeakPtr());
    256 
    257   function->set_profile(browser->profile());
    258   function->set_include_incognito(flags & INCLUDE_INCOGNITO);
    259   function->Run();
    260 
    261   // If the RunImpl of |function| didn't already call SendResponse, run the
    262   // message loop until they do.
    263   if (!response_delegate.HasResponse()) {
    264     response_delegate.set_should_post_quit(true);
    265     content::RunMessageLoop();
    266   }
    267 
    268   EXPECT_TRUE(response_delegate.HasResponse());
    269   return response_delegate.GetResponse();
    270 }
    271 
    272 } // namespace extension_function_test_utils
    273