1 // Copyright 2014 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 "extensions/browser/api_test_utils.h"
7 #include "base/json/json_reader.h"
8 #include "base/memory/scoped_ptr.h"
9 #include "base/values.h"
10 #include "components/crx_file/id_util.h"
11 #include "content/public/browser/browser_context.h"
12 #include "content/public/test/test_utils.h"
13 #include "extensions/browser/extension_function.h"
14 #include "extensions/browser/extension_function_dispatcher.h"
15 #include "extensions/common/extension_builder.h"
16 #include "testing/gtest/include/gtest/gtest.h"
18 using extensions::ExtensionFunctionDispatcher
;
22 scoped_ptr
<base::Value
> ParseJSON(const std::string
& data
) {
23 return base::JSONReader::Read(data
);
26 scoped_ptr
<base::ListValue
> ParseList(const std::string
& data
) {
27 return base::ListValue::From(ParseJSON(data
));
30 // This helps us be able to wait until an UIThreadExtensionFunction calls
32 class SendResponseDelegate
33 : public UIThreadExtensionFunction::DelegateForTests
{
35 SendResponseDelegate() : should_post_quit_(false) {}
37 virtual ~SendResponseDelegate() {}
39 void set_should_post_quit(bool should_quit
) {
40 should_post_quit_
= should_quit
;
43 bool HasResponse() { return response_
.get() != NULL
; }
46 EXPECT_TRUE(HasResponse());
47 return *response_
.get();
50 void OnSendResponse(UIThreadExtensionFunction
* function
,
52 bool bad_message
) override
{
53 ASSERT_FALSE(bad_message
);
54 ASSERT_FALSE(HasResponse());
55 response_
.reset(new bool);
57 if (should_post_quit_
) {
58 base::MessageLoopForUI::current()->Quit();
63 scoped_ptr
<bool> response_
;
64 bool should_post_quit_
;
69 namespace extensions
{
71 namespace api_test_utils
{
73 scoped_ptr
<base::DictionaryValue
> ParseDictionary(const std::string
& data
) {
74 return base::DictionaryValue::From(ParseJSON(data
));
77 bool GetBoolean(const base::DictionaryValue
* val
, const std::string
& key
) {
79 if (!val
->GetBoolean(key
, &result
))
80 ADD_FAILURE() << key
<< " does not exist or is not a boolean.";
84 int GetInteger(const base::DictionaryValue
* val
, const std::string
& key
) {
86 if (!val
->GetInteger(key
, &result
))
87 ADD_FAILURE() << key
<< " does not exist or is not an integer.";
91 std::string
GetString(const base::DictionaryValue
* val
,
92 const std::string
& key
) {
94 if (!val
->GetString(key
, &result
))
95 ADD_FAILURE() << key
<< " does not exist or is not a string.";
99 scoped_refptr
<Extension
> CreateExtension(
100 Manifest::Location location
,
101 base::DictionaryValue
* test_extension_value
,
102 const std::string
& id_input
) {
104 const base::FilePath test_extension_path
;
106 if (!id_input
.empty())
107 id
= crx_file::id_util::GenerateId(id_input
);
108 scoped_refptr
<Extension
> extension(
109 Extension::Create(test_extension_path
, location
, *test_extension_value
,
110 Extension::NO_FLAGS
, id
, &error
));
111 EXPECT_TRUE(error
.empty()) << "Could not parse test extension " << error
;
115 scoped_refptr
<Extension
> CreateExtension(
116 base::DictionaryValue
* test_extension_value
) {
117 return CreateExtension(Manifest::INTERNAL
, test_extension_value
,
121 scoped_refptr
<Extension
> CreateEmptyExtensionWithLocation(
122 Manifest::Location location
) {
123 scoped_ptr
<base::DictionaryValue
> test_extension_value
=
124 ParseDictionary("{\"name\": \"Test\", \"version\": \"1.0\"}");
125 return CreateExtension(location
, test_extension_value
.get(), std::string());
128 base::Value
* RunFunctionWithDelegateAndReturnSingleResult(
129 UIThreadExtensionFunction
* function
,
130 const std::string
& args
,
131 content::BrowserContext
* context
,
132 scoped_ptr
<extensions::ExtensionFunctionDispatcher
> dispatcher
) {
133 return RunFunctionWithDelegateAndReturnSingleResult(
134 function
, args
, context
, dispatcher
.Pass(), NONE
);
137 base::Value
* RunFunctionWithDelegateAndReturnSingleResult(
138 UIThreadExtensionFunction
* function
,
139 const std::string
& args
,
140 content::BrowserContext
* context
,
141 scoped_ptr
<extensions::ExtensionFunctionDispatcher
> dispatcher
,
142 RunFunctionFlags flags
) {
143 scoped_refptr
<ExtensionFunction
> function_owner(function
);
144 // Without a callback the function will not generate a result.
145 function
->set_has_callback(true);
146 RunFunction(function
, args
, context
, dispatcher
.Pass(), flags
);
147 EXPECT_TRUE(function
->GetError().empty())
148 << "Unexpected error: " << function
->GetError();
149 const base::Value
* single_result
= NULL
;
150 if (function
->GetResultList() != NULL
&&
151 function
->GetResultList()->Get(0, &single_result
)) {
152 return single_result
->DeepCopy();
157 base::Value
* RunFunctionAndReturnSingleResult(
158 UIThreadExtensionFunction
* function
,
159 const std::string
& args
,
160 content::BrowserContext
* context
) {
161 return RunFunctionAndReturnSingleResult(function
, args
, context
, NONE
);
164 base::Value
* RunFunctionAndReturnSingleResult(
165 UIThreadExtensionFunction
* function
,
166 const std::string
& args
,
167 content::BrowserContext
* context
,
168 RunFunctionFlags flags
) {
169 scoped_ptr
<ExtensionFunctionDispatcher
> dispatcher(
170 new ExtensionFunctionDispatcher(context
));
172 return RunFunctionWithDelegateAndReturnSingleResult(
173 function
, args
, context
, dispatcher
.Pass(), flags
);
176 std::string
RunFunctionAndReturnError(UIThreadExtensionFunction
* function
,
177 const std::string
& args
,
178 content::BrowserContext
* context
) {
179 return RunFunctionAndReturnError(function
, args
, context
, NONE
);
182 std::string
RunFunctionAndReturnError(UIThreadExtensionFunction
* function
,
183 const std::string
& args
,
184 content::BrowserContext
* context
,
185 RunFunctionFlags flags
) {
186 scoped_ptr
<ExtensionFunctionDispatcher
> dispatcher(
187 new ExtensionFunctionDispatcher(context
));
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
, context
, dispatcher
.Pass(), flags
);
192 EXPECT_FALSE(function
->GetResultList()) << "Did not expect a result";
193 return function
->GetError();
196 bool RunFunction(UIThreadExtensionFunction
* function
,
197 const std::string
& args
,
198 content::BrowserContext
* context
) {
199 scoped_ptr
<ExtensionFunctionDispatcher
> dispatcher(
200 new ExtensionFunctionDispatcher(context
));
201 return RunFunction(function
, args
, context
, dispatcher
.Pass(), NONE
);
204 bool RunFunction(UIThreadExtensionFunction
* function
,
205 const std::string
& args
,
206 content::BrowserContext
* context
,
207 scoped_ptr
<extensions::ExtensionFunctionDispatcher
> dispatcher
,
208 RunFunctionFlags flags
) {
209 scoped_ptr
<base::ListValue
> parsed_args
= ParseList(args
);
210 EXPECT_TRUE(parsed_args
.get())
211 << "Could not parse extension function arguments: " << args
;
213 function
, parsed_args
.Pass(), context
, dispatcher
.Pass(), flags
);
216 bool RunFunction(UIThreadExtensionFunction
* function
,
217 scoped_ptr
<base::ListValue
> args
,
218 content::BrowserContext
* context
,
219 scoped_ptr
<extensions::ExtensionFunctionDispatcher
> dispatcher
,
220 RunFunctionFlags flags
) {
221 SendResponseDelegate response_delegate
;
222 function
->set_test_delegate(&response_delegate
);
223 function
->SetArgs(args
.get());
226 function
->set_dispatcher(dispatcher
->AsWeakPtr());
228 function
->set_browser_context(context
);
229 function
->set_include_incognito(flags
& INCLUDE_INCOGNITO
);
230 function
->Run()->Execute();
232 // If the RunAsync of |function| didn't already call SendResponse, run the
233 // message loop until they do.
234 if (!response_delegate
.HasResponse()) {
235 response_delegate
.set_should_post_quit(true);
236 content::RunMessageLoop();
239 EXPECT_TRUE(response_delegate
.HasResponse());
240 return response_delegate
.GetResponse();
243 } // namespace api_test_utils
244 } // namespace extensions