Adding instrumentation to locate the source of jankiness
[chromium-blink-merge.git] / chrome / browser / extensions / extension_function_test_utils.cc
blob1d3b84a52bbc7a6784d50b6bea3f15dd8ab1aebd
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"
7 #include <string>
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;
28 namespace {
30 class TestFunctionDispatcherDelegate
31 : public extensions::ExtensionFunctionDispatcher::Delegate {
32 public:
33 explicit TestFunctionDispatcherDelegate(Browser* browser) :
34 browser_(browser) {}
35 virtual ~TestFunctionDispatcherDelegate() {}
37 private:
38 virtual extensions::WindowController* GetExtensionWindowController()
39 const override {
40 return browser_->extension_window_controller();
43 virtual WebContents* GetAssociatedWebContents() const override {
44 return NULL;
47 Browser* browser_;
50 } // namespace
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);
62 return 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);
70 return dict;
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;
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;
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;
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);
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);
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,
116 std::string());
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,
134 &error));
135 EXPECT_TRUE(error.empty()) << "Could not parse test extension " << error;
136 return extension;
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;
148 std::string RunFunctionAndReturnError(UIThreadExtensionFunction* function,
149 const std::string& args,
150 Browser* browser) {
151 return RunFunctionAndReturnError(function, args, browser, NONE);
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();
165 base::Value* RunFunctionAndReturnSingleResult(
166 UIThreadExtensionFunction* function,
167 const std::string& args,
168 Browser* browser) {
169 return RunFunctionAndReturnSingleResult(function, args, browser, NONE);
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();
187 return NULL;
190 // This helps us be able to wait until an UIThreadExtensionFunction calls
191 // SendResponse.
192 class SendResponseDelegate
193 : public UIThreadExtensionFunction::DelegateForTests {
194 public:
195 SendResponseDelegate() : should_post_quit_(false) {}
197 virtual ~SendResponseDelegate() {}
199 void set_should_post_quit(bool should_quit) {
200 should_post_quit_ = should_quit;
203 bool HasResponse() {
204 return response_.get() != NULL;
207 bool GetResponse() {
208 EXPECT_TRUE(HasResponse());
209 return *response_.get();
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();
224 private:
225 scoped_ptr<bool> response_;
226 bool should_post_quit_;
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);
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));
257 } // namespace extension_function_test_utils