blob: 4cf8a32a52b384c1b77c51398c3660063165f8b8 [file] [log] [blame]
[email protected]8809f1442012-01-20 21:21:471// Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]637bf322011-10-01 20:46:322// 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
[email protected]57999812013-02-24 05:40:529#include "base/files/file_path.h"
[email protected]637bf322011-10-01 20:46:3210#include "base/json/json_reader.h"
11#include "base/values.h"
[email protected]37bb5822012-09-10 15:09:5712#include "chrome/browser/extensions/api/tabs/tabs_constants.h"
[email protected]21a40082013-10-28 21:19:2313#include "chrome/browser/profiles/profile.h"
[email protected]637bf322011-10-01 20:46:3214#include "chrome/browser/ui/browser.h"
[email protected]d8c8749b92011-11-16 22:31:3215#include "chrome/test/base/ui_test_utils.h"
[email protected]e49e10142014-07-23 06:52:4116#include "extensions/browser/api_test_utils.h"
[email protected]14c3571a2013-11-13 00:18:4417#include "extensions/browser/extension_function.h"
[email protected]0b9de032014-03-15 05:47:0118#include "extensions/browser/extension_function_dispatcher.h"
[email protected]e4452d32013-11-15 23:07:4119#include "extensions/common/extension.h"
[email protected]993da5e2013-03-23 21:25:1620#include "extensions/common/id_util.h"
[email protected]637bf322011-10-01 20:46:3221#include "testing/gtest/include/gtest/gtest.h"
22
[email protected]ea049a02011-12-25 21:37:0923using content::WebContents;
[email protected]1c321ee2012-05-21 03:02:3424using extensions::Extension;
[email protected]1d5e58b2013-01-31 08:41:4025using extensions::Manifest;
[email protected]37bb5822012-09-10 15:09:5726namespace keys = extensions::tabs_constants;
[email protected]ea049a02011-12-25 21:37:0927
[email protected]4e3ce3b2011-10-14 23:25:1728namespace {
29
30class TestFunctionDispatcherDelegate
[email protected]1a0436892014-04-01 00:38:2531 : public extensions::ExtensionFunctionDispatcher::Delegate {
[email protected]4e3ce3b2011-10-14 23:25:1732 public:
33 explicit TestFunctionDispatcherDelegate(Browser* browser) :
34 browser_(browser) {}
35 virtual ~TestFunctionDispatcherDelegate() {}
36
37 private:
[email protected]44f4b132012-07-17 20:36:5738 virtual extensions::WindowController* GetExtensionWindowController()
[email protected]b51f3562012-05-05 22:01:4339 const OVERRIDE {
40 return browser_->extension_window_controller();
[email protected]4e3ce3b2011-10-14 23:25:1741 }
42
[email protected]ea049a02011-12-25 21:37:0943 virtual WebContents* GetAssociatedWebContents() const OVERRIDE {
[email protected]4e3ce3b2011-10-14 23:25:1744 return NULL;
45 }
46
47 Browser* browser_;
48};
49
50} // namespace
51
[email protected]637bf322011-10-01 20:46:3252namespace extension_function_test_utils {
53
54base::Value* ParseJSON(const std::string& data) {
[email protected]cd5785752012-04-11 00:15:4155 return base::JSONReader::Read(data);
[email protected]637bf322011-10-01 20:46:3256}
57
58base::ListValue* ParseList(const std::string& data) {
[email protected]e49e10142014-07-23 06:52:4159 base::Value* result = ParseJSON(data);
60 base::ListValue* list = NULL;
61 result->GetAsList(&list);
62 return list;
[email protected]637bf322011-10-01 20:46:3263}
64
65base::DictionaryValue* ParseDictionary(
66 const std::string& data) {
[email protected]e49e10142014-07-23 06:52:4167 base::Value* result = ParseJSON(data);
68 base::DictionaryValue* dict = NULL;
69 result->GetAsDictionary(&dict);
70 return dict;
[email protected]637bf322011-10-01 20:46:3271}
72
73bool 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
80int 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
87std::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
94base::DictionaryValue* ToDictionary(base::Value* val) {
[email protected]8ce80ea62011-10-18 18:00:1895 EXPECT_TRUE(val);
96 EXPECT_EQ(base::Value::TYPE_DICTIONARY, val->GetType());
[email protected]637bf322011-10-01 20:46:3297 return static_cast<base::DictionaryValue*>(val);
98}
99
[email protected]008ff7fb2011-12-19 08:51:17100base::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
[email protected]4e3ce3b2011-10-14 23:25:17106scoped_refptr<Extension> CreateEmptyExtension() {
[email protected]1d5e58b2013-01-31 08:41:40107 return CreateEmptyExtensionWithLocation(Manifest::INTERNAL);
[email protected]6d2d55b2012-05-05 21:33:43108}
109
110scoped_refptr<Extension> CreateEmptyExtensionWithLocation(
[email protected]1d5e58b2013-01-31 08:41:40111 Manifest::Location location) {
[email protected]4e3ce3b2011-10-14 23:25:17112 scoped_ptr<base::DictionaryValue> test_extension_value(
113 ParseDictionary("{\"name\": \"Test\", \"version\": \"1.0\"}"));
[email protected]09426852012-09-11 22:39:07114 return CreateExtension(location, test_extension_value.get(), std::string());
115}
116
117scoped_refptr<Extension> CreateEmptyExtension(
118 const std::string& id_input) {
119 scoped_ptr<base::DictionaryValue> test_extension_value(
120 ParseDictionary("{\"name\": \"Test\", \"version\": \"1.0\"}"));
[email protected]1d5e58b2013-01-31 08:41:40121 return CreateExtension(Manifest::INTERNAL, test_extension_value.get(),
[email protected]09426852012-09-11 22:39:07122 id_input);
[email protected]37bb5822012-09-10 15:09:57123}
124
125scoped_refptr<Extension> CreateExtension(
126 base::DictionaryValue* test_extension_value) {
[email protected]1d5e58b2013-01-31 08:41:40127 return CreateExtension(Manifest::INTERNAL, test_extension_value,
[email protected]09426852012-09-11 22:39:07128 std::string());
[email protected]37bb5822012-09-10 15:09:57129}
130
131scoped_refptr<Extension> CreateExtension(
[email protected]1d5e58b2013-01-31 08:41:40132 Manifest::Location location,
[email protected]09426852012-09-11 22:39:07133 base::DictionaryValue* test_extension_value,
134 const std::string& id_input) {
[email protected]37bb5822012-09-10 15:09:57135 std::string error;
[email protected]650b2d52013-02-10 03:41:45136 const base::FilePath test_extension_path;
[email protected]09426852012-09-11 22:39:07137 std::string id;
138 if (!id_input.empty())
[email protected]993da5e2013-03-23 21:25:16139 id = extensions::id_util::GenerateId(id_input);
[email protected]4e3ce3b2011-10-14 23:25:17140 scoped_refptr<Extension> extension(Extension::Create(
141 test_extension_path,
[email protected]6d2d55b2012-05-05 21:33:43142 location,
[email protected]37bb5822012-09-10 15:09:57143 *test_extension_value,
[email protected]4e3ce3b2011-10-14 23:25:17144 Extension::NO_FLAGS,
[email protected]09426852012-09-11 22:39:07145 id,
[email protected]4e3ce3b2011-10-14 23:25:17146 &error));
[email protected]8ce80ea62011-10-18 18:00:18147 EXPECT_TRUE(error.empty()) << "Could not parse test extension " << error;
[email protected]4e3ce3b2011-10-14 23:25:17148 return extension;
149}
150
[email protected]37bb5822012-09-10 15:09:57151bool 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
[email protected]637bf322011-10-01 20:46:32160std::string RunFunctionAndReturnError(UIThreadExtensionFunction* function,
161 const std::string& args,
162 Browser* browser) {
163 return RunFunctionAndReturnError(function, args, browser, NONE);
164}
165std::string RunFunctionAndReturnError(UIThreadExtensionFunction* function,
166 const std::string& args,
167 Browser* browser,
168 RunFunctionFlags flags) {
169 scoped_refptr<ExtensionFunction> function_owner(function);
[email protected]61165fd2012-07-24 01:12:23170 // Without a callback the function will not generate a result.
171 function->set_has_callback(true);
[email protected]637bf322011-10-01 20:46:32172 RunFunction(function, args, browser, flags);
[email protected]07ff5fd2012-07-12 22:39:09173 EXPECT_FALSE(function->GetResultList()) << "Did not expect a result";
[email protected]637bf322011-10-01 20:46:32174 return function->GetError();
175}
176
[email protected]07ff5fd2012-07-12 22:39:09177base::Value* RunFunctionAndReturnSingleResult(
178 UIThreadExtensionFunction* function,
179 const std::string& args,
180 Browser* browser) {
181 return RunFunctionAndReturnSingleResult(function, args, browser, NONE);
[email protected]637bf322011-10-01 20:46:32182}
[email protected]07ff5fd2012-07-12 22:39:09183base::Value* RunFunctionAndReturnSingleResult(
184 UIThreadExtensionFunction* function,
185 const std::string& args,
186 Browser* browser,
187 RunFunctionFlags flags) {
[email protected]637bf322011-10-01 20:46:32188 scoped_refptr<ExtensionFunction> function_owner(function);
[email protected]61165fd2012-07-24 01:12:23189 // Without a callback the function will not generate a result.
190 function->set_has_callback(true);
[email protected]637bf322011-10-01 20:46:32191 RunFunction(function, args, browser, flags);
[email protected]8ce80ea62011-10-18 18:00:18192 EXPECT_TRUE(function->GetError().empty()) << "Unexpected error: "
193 << function->GetError();
[email protected]5d30f92bf2012-08-03 08:43:37194 const base::Value* single_result = NULL;
[email protected]07ff5fd2012-07-12 22:39:09195 if (function->GetResultList() != NULL &&
196 function->GetResultList()->Get(0, &single_result)) {
197 return single_result->DeepCopy();
198 }
199 return NULL;
[email protected]637bf322011-10-01 20:46:32200}
201
[email protected]4bf2b052013-09-30 21:05:41202// This helps us be able to wait until an UIThreadExtensionFunction calls
[email protected]d8c8749b92011-11-16 22:31:32203// SendResponse.
[email protected]bdfc03e2011-11-22 00:20:33204class SendResponseDelegate
205 : public UIThreadExtensionFunction::DelegateForTests {
[email protected]d8c8749b92011-11-16 22:31:32206 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
[email protected]bdfc03e2011-11-22 00:20:33224 virtual void OnSendResponse(UIThreadExtensionFunction* function,
[email protected]ca6df682012-04-10 23:00:20225 bool success,
[email protected]49aeab62013-02-07 02:53:11226 bool bad_message) OVERRIDE {
[email protected]ca6df682012-04-10 23:00:20227 ASSERT_FALSE(bad_message);
[email protected]d8c8749b92011-11-16 22:31:32228 ASSERT_FALSE(HasResponse());
229 response_.reset(new bool);
230 *response_ = success;
231 if (should_post_quit_) {
[email protected]b3a25092013-05-28 22:08:16232 base::MessageLoopForUI::current()->Quit();
[email protected]d8c8749b92011-11-16 22:31:32233 }
234 }
235
236 private:
237 scoped_ptr<bool> response_;
238 bool should_post_quit_;
239};
240
[email protected]bdfc03e2011-11-22 00:20:33241bool RunFunction(UIThreadExtensionFunction* function,
242 const std::string& args,
243 Browser* browser,
244 RunFunctionFlags flags) {
[email protected]fc672e12014-08-16 08:16:15245 scoped_ptr<base::ListValue> parsed_args(ParseList(args));
246 EXPECT_TRUE(parsed_args.get())
247 << "Could not parse extension function arguments: " << args;
248 return RunFunction(function, parsed_args.Pass(), browser, flags);
249}
250
251bool RunFunction(UIThreadExtensionFunction* function,
252 scoped_ptr<base::ListValue> args,
253 Browser* browser,
254 RunFunctionFlags flags) {
[email protected]bdfc03e2011-11-22 00:20:33255 TestFunctionDispatcherDelegate dispatcher_delegate(browser);
[email protected]e49e10142014-07-23 06:52:41256 scoped_ptr<extensions::ExtensionFunctionDispatcher> dispatcher(
257 new extensions::ExtensionFunctionDispatcher(browser->profile(),
258 &dispatcher_delegate));
259 // TODO(yoz): The cast is a hack; these flags should be defined in
260 // only one place. See crbug.com/394840.
261 return extensions::api_test_utils::RunFunction(
262 function,
[email protected]fc672e12014-08-16 08:16:15263 args.Pass(),
[email protected]e49e10142014-07-23 06:52:41264 browser->profile(),
265 dispatcher.Pass(),
266 static_cast<extensions::api_test_utils::RunFunctionFlags>(flags));
[email protected]d8c8749b92011-11-16 22:31:32267}
268
[email protected]637bf322011-10-01 20:46:32269} // namespace extension_function_test_utils