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.
5 #include "chrome/browser/extensions/extension_function_test_utils.h"
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"
23 using content::WebContents
;
24 using extensions::Extension
;
25 using extensions::Manifest
;
26 namespace keys
= extensions::tabs_constants
;
30 class TestFunctionDispatcherDelegate
31 : public extensions::ExtensionFunctionDispatcher::Delegate
{
33 explicit TestFunctionDispatcherDelegate(Browser
* browser
) :
35 virtual ~TestFunctionDispatcherDelegate() {}
38 virtual extensions::WindowController
* GetExtensionWindowController()
40 return browser_
->extension_window_controller();
43 virtual WebContents
* GetAssociatedWebContents() const override
{
52 namespace extension_function_test_utils
{
54 base::Value
* ParseJSON(const std::string
& data
) {
55 return base::JSONReader::Read(data
);
58 base::ListValue
* ParseList(const std::string
& data
) {
59 base::Value
* result
= ParseJSON(data
);
60 base::ListValue
* list
= NULL
;
61 result
->GetAsList(&list
);
65 base::DictionaryValue
* ParseDictionary(
66 const std::string
& data
) {
67 base::Value
* result
= ParseJSON(data
);
68 base::DictionaryValue
* dict
= NULL
;
69 result
->GetAsDictionary(&dict
);
73 bool GetBoolean(base::DictionaryValue
* val
, const std::string
& key
) {
75 if (!val
->GetBoolean(key
, &result
))
76 ADD_FAILURE() << key
<< " does not exist or is not a boolean.";
80 int GetInteger(base::DictionaryValue
* val
, const std::string
& key
) {
82 if (!val
->GetInteger(key
, &result
))
83 ADD_FAILURE() << key
<< " does not exist or is not an integer.";
87 std::string
GetString(base::DictionaryValue
* val
, const std::string
& key
) {
89 if (!val
->GetString(key
, &result
))
90 ADD_FAILURE() << key
<< " does not exist or is not a string.";
94 base::DictionaryValue
* ToDictionary(base::Value
* val
) {
96 EXPECT_EQ(base::Value::TYPE_DICTIONARY
, val
->GetType());
97 return static_cast<base::DictionaryValue
*>(val
);
100 base::ListValue
* ToList(base::Value
* val
) {
102 EXPECT_EQ(base::Value::TYPE_LIST
, val
->GetType());
103 return static_cast<base::ListValue
*>(val
);
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());
113 scoped_refptr
<Extension
> CreateExtension(
114 base::DictionaryValue
* test_extension_value
) {
115 return CreateExtension(Manifest::INTERNAL
, test_extension_value
,
119 scoped_refptr
<Extension
> CreateExtension(
120 Manifest::Location location
,
121 base::DictionaryValue
* test_extension_value
,
122 const std::string
& id_input
) {
124 const base::FilePath test_extension_path
;
126 if (!id_input
.empty())
127 id
= crx_file::id_util::GenerateId(id_input
);
128 scoped_refptr
<Extension
> extension(Extension::Create(
131 *test_extension_value
,
135 EXPECT_TRUE(error
.empty()) << "Could not parse test extension " << error
;
139 bool HasPrivacySensitiveFields(base::DictionaryValue
* val
) {
141 if (val
->GetString(keys::kUrlKey
, &result
) ||
142 val
->GetString(keys::kTitleKey
, &result
) ||
143 val
->GetString(keys::kFaviconUrlKey
, &result
))
148 std::string
RunFunctionAndReturnError(UIThreadExtensionFunction
* function
,
149 const std::string
& args
,
151 return RunFunctionAndReturnError(function
, args
, browser
, NONE
);
153 std::string
RunFunctionAndReturnError(UIThreadExtensionFunction
* function
,
154 const std::string
& args
,
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();
165 base::Value
* RunFunctionAndReturnSingleResult(
166 UIThreadExtensionFunction
* function
,
167 const std::string
& args
,
169 return RunFunctionAndReturnSingleResult(function
, args
, browser
, NONE
);
171 base::Value
* RunFunctionAndReturnSingleResult(
172 UIThreadExtensionFunction
* function
,
173 const std::string
& args
,
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();
190 // This helps us be able to wait until an UIThreadExtensionFunction calls
192 class SendResponseDelegate
193 : public UIThreadExtensionFunction::DelegateForTests
{
195 SendResponseDelegate() : should_post_quit_(false) {}
197 virtual ~SendResponseDelegate() {}
199 void set_should_post_quit(bool should_quit
) {
200 should_post_quit_
= should_quit
;
204 return response_
.get() != NULL
;
208 EXPECT_TRUE(HasResponse());
209 return *response_
.get();
212 virtual void OnSendResponse(UIThreadExtensionFunction
* function
,
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();
225 scoped_ptr
<bool> response_
;
226 bool should_post_quit_
;
229 bool RunFunction(UIThreadExtensionFunction
* function
,
230 const std::string
& args
,
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
);
239 bool RunFunction(UIThreadExtensionFunction
* function
,
240 scoped_ptr
<base::ListValue
> args
,
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(
254 static_cast<extensions::api_test_utils::RunFunctionFlags
>(flags
));
257 } // namespace extension_function_test_utils