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 ~TestFunctionDispatcherDelegate() override
{}
38 extensions::WindowController
* GetExtensionWindowController() const override
{
39 return browser_
->extension_window_controller();
42 WebContents
* GetAssociatedWebContents() const override
{ return NULL
; }
49 namespace extension_function_test_utils
{
51 base::Value
* ParseJSON(const std::string
& data
) {
52 return base::JSONReader::Read(data
);
55 base::ListValue
* ParseList(const std::string
& data
) {
56 base::Value
* result
= ParseJSON(data
);
57 base::ListValue
* list
= NULL
;
58 result
->GetAsList(&list
);
62 base::DictionaryValue
* ParseDictionary(
63 const std::string
& data
) {
64 base::Value
* result
= ParseJSON(data
);
65 base::DictionaryValue
* dict
= NULL
;
66 result
->GetAsDictionary(&dict
);
70 bool GetBoolean(const base::DictionaryValue
* val
, const std::string
& key
) {
72 if (!val
->GetBoolean(key
, &result
))
73 ADD_FAILURE() << key
<< " does not exist or is not a boolean.";
77 int GetInteger(const base::DictionaryValue
* val
, const std::string
& key
) {
79 if (!val
->GetInteger(key
, &result
))
80 ADD_FAILURE() << key
<< " does not exist or is not an integer.";
84 std::string
GetString(const base::DictionaryValue
* val
,
85 const std::string
& key
) {
87 if (!val
->GetString(key
, &result
))
88 ADD_FAILURE() << key
<< " does not exist or is not a string.";
92 base::DictionaryValue
* ToDictionary(base::Value
* val
) {
94 EXPECT_EQ(base::Value::TYPE_DICTIONARY
, val
->GetType());
95 return static_cast<base::DictionaryValue
*>(val
);
98 base::ListValue
* ToList(base::Value
* val
) {
100 EXPECT_EQ(base::Value::TYPE_LIST
, val
->GetType());
101 return static_cast<base::ListValue
*>(val
);
104 scoped_refptr
<Extension
> CreateEmptyExtensionWithLocation(
105 Manifest::Location location
) {
106 scoped_ptr
<base::DictionaryValue
> test_extension_value(
107 ParseDictionary("{\"name\": \"Test\", \"version\": \"1.0\"}"));
108 return CreateExtension(location
, test_extension_value
.get(), std::string());
111 scoped_refptr
<Extension
> CreateExtension(
112 base::DictionaryValue
* test_extension_value
) {
113 return CreateExtension(Manifest::INTERNAL
, test_extension_value
,
117 scoped_refptr
<Extension
> CreateExtension(
118 Manifest::Location location
,
119 base::DictionaryValue
* test_extension_value
,
120 const std::string
& id_input
) {
122 const base::FilePath test_extension_path
;
124 if (!id_input
.empty())
125 id
= crx_file::id_util::GenerateId(id_input
);
126 scoped_refptr
<Extension
> extension(Extension::Create(
129 *test_extension_value
,
133 EXPECT_TRUE(error
.empty()) << "Could not parse test extension " << error
;
137 bool HasPrivacySensitiveFields(base::DictionaryValue
* val
) {
139 if (val
->GetString(keys::kUrlKey
, &result
) ||
140 val
->GetString(keys::kTitleKey
, &result
) ||
141 val
->GetString(keys::kFaviconUrlKey
, &result
))
146 std::string
RunFunctionAndReturnError(UIThreadExtensionFunction
* function
,
147 const std::string
& args
,
149 return RunFunctionAndReturnError(function
, args
, browser
, NONE
);
151 std::string
RunFunctionAndReturnError(UIThreadExtensionFunction
* function
,
152 const std::string
& args
,
154 RunFunctionFlags flags
) {
155 scoped_refptr
<ExtensionFunction
> function_owner(function
);
156 // Without a callback the function will not generate a result.
157 function
->set_has_callback(true);
158 RunFunction(function
, args
, browser
, flags
);
159 EXPECT_FALSE(function
->GetResultList()) << "Did not expect a result";
160 return function
->GetError();
163 base::Value
* RunFunctionAndReturnSingleResult(
164 UIThreadExtensionFunction
* function
,
165 const std::string
& args
,
167 return RunFunctionAndReturnSingleResult(function
, args
, browser
, NONE
);
169 base::Value
* RunFunctionAndReturnSingleResult(
170 UIThreadExtensionFunction
* function
,
171 const std::string
& args
,
173 RunFunctionFlags flags
) {
174 scoped_refptr
<ExtensionFunction
> function_owner(function
);
175 // Without a callback the function will not generate a result.
176 function
->set_has_callback(true);
177 RunFunction(function
, args
, browser
, flags
);
178 EXPECT_TRUE(function
->GetError().empty()) << "Unexpected error: "
179 << function
->GetError();
180 const base::Value
* single_result
= NULL
;
181 if (function
->GetResultList() != NULL
&&
182 function
->GetResultList()->Get(0, &single_result
)) {
183 return single_result
->DeepCopy();
188 // This helps us be able to wait until an UIThreadExtensionFunction calls
190 class SendResponseDelegate
191 : public UIThreadExtensionFunction::DelegateForTests
{
193 SendResponseDelegate() : should_post_quit_(false) {}
195 virtual ~SendResponseDelegate() {}
197 void set_should_post_quit(bool should_quit
) {
198 should_post_quit_
= should_quit
;
202 return response_
.get() != NULL
;
206 EXPECT_TRUE(HasResponse());
207 return *response_
.get();
210 void OnSendResponse(UIThreadExtensionFunction
* function
,
212 bool bad_message
) override
{
213 ASSERT_FALSE(bad_message
);
214 ASSERT_FALSE(HasResponse());
215 response_
.reset(new bool);
216 *response_
= success
;
217 if (should_post_quit_
) {
218 base::MessageLoopForUI::current()->Quit();
223 scoped_ptr
<bool> response_
;
224 bool should_post_quit_
;
227 bool RunFunction(UIThreadExtensionFunction
* function
,
228 const std::string
& args
,
230 RunFunctionFlags flags
) {
231 scoped_ptr
<base::ListValue
> parsed_args(ParseList(args
));
232 EXPECT_TRUE(parsed_args
.get())
233 << "Could not parse extension function arguments: " << args
;
234 return RunFunction(function
, parsed_args
.Pass(), browser
, flags
);
237 bool RunFunction(UIThreadExtensionFunction
* function
,
238 scoped_ptr
<base::ListValue
> args
,
240 RunFunctionFlags flags
) {
241 TestFunctionDispatcherDelegate
dispatcher_delegate(browser
);
242 scoped_ptr
<extensions::ExtensionFunctionDispatcher
> dispatcher(
243 new extensions::ExtensionFunctionDispatcher(browser
->profile(),
244 &dispatcher_delegate
));
245 // TODO(yoz): The cast is a hack; these flags should be defined in
246 // only one place. See crbug.com/394840.
247 return extensions::api_test_utils::RunFunction(
252 static_cast<extensions::api_test_utils::RunFunctionFlags
>(flags
));
255 } // namespace extension_function_test_utils