• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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:
TestFunctionDispatcherDelegate(Browser * browser)33   explicit TestFunctionDispatcherDelegate(Browser* browser) :
34       browser_(browser) {}
~TestFunctionDispatcherDelegate()35   virtual ~TestFunctionDispatcherDelegate() {}
36 
37  private:
GetExtensionWindowController() const38   virtual extensions::WindowController* GetExtensionWindowController()
39       const OVERRIDE {
40     return browser_->extension_window_controller();
41   }
42 
GetAssociatedWebContents() const43   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 
ParseJSON(const std::string & data)54 base::Value* ParseJSON(const std::string& data) {
55   return base::JSONReader::Read(data);
56 }
57 
ParseList(const std::string & data)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 
ParseDictionary(const std::string & data)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 
GetBoolean(base::DictionaryValue * val,const std::string & key)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 
GetInteger(base::DictionaryValue * val,const std::string & key)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 
GetString(base::DictionaryValue * val,const std::string & key)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 
ToDictionary(base::Value * val)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 
ToList(base::Value * val)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 
CreateEmptyExtensionWithLocation(Manifest::Location location)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 
CreateExtension(base::DictionaryValue * test_extension_value)113 scoped_refptr<Extension> CreateExtension(
114     base::DictionaryValue* test_extension_value) {
115   return CreateExtension(Manifest::INTERNAL, test_extension_value,
116                          std::string());
117 }
118 
CreateExtension(Manifest::Location location,base::DictionaryValue * test_extension_value,const std::string & id_input)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 
HasPrivacySensitiveFields(base::DictionaryValue * val)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 
RunFunctionAndReturnError(UIThreadExtensionFunction * function,const std::string & args,Browser * browser)148 std::string RunFunctionAndReturnError(UIThreadExtensionFunction* function,
149                                       const std::string& args,
150                                       Browser* browser) {
151   return RunFunctionAndReturnError(function, args, browser, NONE);
152 }
RunFunctionAndReturnError(UIThreadExtensionFunction * function,const std::string & args,Browser * browser,RunFunctionFlags flags)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 
RunFunctionAndReturnSingleResult(UIThreadExtensionFunction * function,const std::string & args,Browser * browser)165 base::Value* RunFunctionAndReturnSingleResult(
166     UIThreadExtensionFunction* function,
167     const std::string& args,
168     Browser* browser) {
169   return RunFunctionAndReturnSingleResult(function, args, browser, NONE);
170 }
RunFunctionAndReturnSingleResult(UIThreadExtensionFunction * function,const std::string & args,Browser * browser,RunFunctionFlags flags)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:
SendResponseDelegate()195   SendResponseDelegate() : should_post_quit_(false) {}
196 
~SendResponseDelegate()197   virtual ~SendResponseDelegate() {}
198 
set_should_post_quit(bool should_quit)199   void set_should_post_quit(bool should_quit) {
200     should_post_quit_ = should_quit;
201   }
202 
HasResponse()203   bool HasResponse() {
204     return response_.get() != NULL;
205   }
206 
GetResponse()207   bool GetResponse() {
208     EXPECT_TRUE(HasResponse());
209     return *response_.get();
210   }
211 
OnSendResponse(UIThreadExtensionFunction * function,bool success,bool bad_message)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 
RunFunction(UIThreadExtensionFunction * function,const std::string & args,Browser * browser,RunFunctionFlags flags)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 
RunFunction(UIThreadExtensionFunction * function,scoped_ptr<base::ListValue> args,Browser * browser,RunFunctionFlags flags)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