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. 4 5#include "chrome/browser/extensions/extension_function_test_utils.h" 6 7#include <string> 8 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 "extensions/browser/extension_function.h" 17#include "extensions/browser/extension_function_dispatcher.h" 18#include "extensions/common/extension.h" 19#include "extensions/common/id_util.h" 20#include "testing/gtest/include/gtest/gtest.h" 21 22using content::WebContents; 23using extensions::Extension; 24using extensions::Manifest; 25namespace keys = extensions::tabs_constants; 26 27namespace { 28 29class TestFunctionDispatcherDelegate 30 : public extensions::ExtensionFunctionDispatcher::Delegate { 31 public: 32 explicit TestFunctionDispatcherDelegate(Browser* browser) : 33 browser_(browser) {} 34 virtual ~TestFunctionDispatcherDelegate() {} 35 36 private: 37 virtual extensions::WindowController* GetExtensionWindowController() 38 const OVERRIDE { 39 return browser_->extension_window_controller(); 40 } 41 42 virtual WebContents* GetAssociatedWebContents() const OVERRIDE { 43 return NULL; 44 } 45 46 Browser* browser_; 47}; 48 49} // namespace 50 51namespace extension_function_test_utils { 52 53base::Value* ParseJSON(const std::string& data) { 54 return base::JSONReader::Read(data); 55} 56 57base::ListValue* ParseList(const std::string& data) { 58 scoped_ptr<base::Value> result(ParseJSON(data)); 59 if (result.get() && result->IsType(base::Value::TYPE_LIST)) 60 return static_cast<base::ListValue*>(result.release()); 61 else 62 return NULL; 63} 64 65base::DictionaryValue* ParseDictionary( 66 const std::string& data) { 67 scoped_ptr<base::Value> result(ParseJSON(data)); 68 if (result.get() && result->IsType(base::Value::TYPE_DICTIONARY)) 69 return static_cast<base::DictionaryValue*>(result.release()); 70 else 71 return NULL; 72} 73 74bool GetBoolean(base::DictionaryValue* val, const std::string& key) { 75 bool result = false; 76 if (!val->GetBoolean(key, &result)) 77 ADD_FAILURE() << key << " does not exist or is not a boolean."; 78 return result; 79} 80 81int GetInteger(base::DictionaryValue* val, const std::string& key) { 82 int result = 0; 83 if (!val->GetInteger(key, &result)) 84 ADD_FAILURE() << key << " does not exist or is not an integer."; 85 return result; 86} 87 88std::string GetString(base::DictionaryValue* val, const std::string& key) { 89 std::string result; 90 if (!val->GetString(key, &result)) 91 ADD_FAILURE() << key << " does not exist or is not a string."; 92 return result; 93} 94 95base::DictionaryValue* ToDictionary(base::Value* val) { 96 EXPECT_TRUE(val); 97 EXPECT_EQ(base::Value::TYPE_DICTIONARY, val->GetType()); 98 return static_cast<base::DictionaryValue*>(val); 99} 100 101base::ListValue* ToList(base::Value* val) { 102 EXPECT_TRUE(val); 103 EXPECT_EQ(base::Value::TYPE_LIST, val->GetType()); 104 return static_cast<base::ListValue*>(val); 105} 106 107scoped_refptr<Extension> CreateEmptyExtension() { 108 return CreateEmptyExtensionWithLocation(Manifest::INTERNAL); 109} 110 111scoped_refptr<Extension> CreateEmptyExtensionWithLocation( 112 Manifest::Location location) { 113 scoped_ptr<base::DictionaryValue> test_extension_value( 114 ParseDictionary("{\"name\": \"Test\", \"version\": \"1.0\"}")); 115 return CreateExtension(location, test_extension_value.get(), std::string()); 116} 117 118scoped_refptr<Extension> CreateEmptyExtension( 119 const std::string& id_input) { 120 scoped_ptr<base::DictionaryValue> test_extension_value( 121 ParseDictionary("{\"name\": \"Test\", \"version\": \"1.0\"}")); 122 return CreateExtension(Manifest::INTERNAL, test_extension_value.get(), 123 id_input); 124} 125 126scoped_refptr<Extension> CreateExtension( 127 base::DictionaryValue* test_extension_value) { 128 return CreateExtension(Manifest::INTERNAL, test_extension_value, 129 std::string()); 130} 131 132scoped_refptr<Extension> CreateExtension( 133 Manifest::Location location, 134 base::DictionaryValue* test_extension_value, 135 const std::string& id_input) { 136 std::string error; 137 const base::FilePath test_extension_path; 138 std::string id; 139 if (!id_input.empty()) 140 id = extensions::id_util::GenerateId(id_input); 141 scoped_refptr<Extension> extension(Extension::Create( 142 test_extension_path, 143 location, 144 *test_extension_value, 145 Extension::NO_FLAGS, 146 id, 147 &error)); 148 EXPECT_TRUE(error.empty()) << "Could not parse test extension " << error; 149 return extension; 150} 151 152bool HasPrivacySensitiveFields(base::DictionaryValue* val) { 153 std::string result; 154 if (val->GetString(keys::kUrlKey, &result) || 155 val->GetString(keys::kTitleKey, &result) || 156 val->GetString(keys::kFaviconUrlKey, &result)) 157 return true; 158 return false; 159} 160 161std::string RunFunctionAndReturnError(UIThreadExtensionFunction* function, 162 const std::string& args, 163 Browser* browser) { 164 return RunFunctionAndReturnError(function, args, browser, NONE); 165} 166std::string RunFunctionAndReturnError(UIThreadExtensionFunction* function, 167 const std::string& args, 168 Browser* browser, 169 RunFunctionFlags flags) { 170 scoped_refptr<ExtensionFunction> function_owner(function); 171 // Without a callback the function will not generate a result. 172 function->set_has_callback(true); 173 RunFunction(function, args, browser, flags); 174 EXPECT_FALSE(function->GetResultList()) << "Did not expect a result"; 175 return function->GetError(); 176} 177 178base::Value* RunFunctionAndReturnSingleResult( 179 UIThreadExtensionFunction* function, 180 const std::string& args, 181 Browser* browser) { 182 return RunFunctionAndReturnSingleResult(function, args, browser, NONE); 183} 184base::Value* RunFunctionAndReturnSingleResult( 185 UIThreadExtensionFunction* function, 186 const std::string& args, 187 Browser* browser, 188 RunFunctionFlags flags) { 189 scoped_refptr<ExtensionFunction> function_owner(function); 190 // Without a callback the function will not generate a result. 191 function->set_has_callback(true); 192 RunFunction(function, args, browser, flags); 193 EXPECT_TRUE(function->GetError().empty()) << "Unexpected error: " 194 << function->GetError(); 195 const base::Value* single_result = NULL; 196 if (function->GetResultList() != NULL && 197 function->GetResultList()->Get(0, &single_result)) { 198 return single_result->DeepCopy(); 199 } 200 return NULL; 201} 202 203// This helps us be able to wait until an UIThreadExtensionFunction calls 204// SendResponse. 205class SendResponseDelegate 206 : public UIThreadExtensionFunction::DelegateForTests { 207 public: 208 SendResponseDelegate() : should_post_quit_(false) {} 209 210 virtual ~SendResponseDelegate() {} 211 212 void set_should_post_quit(bool should_quit) { 213 should_post_quit_ = should_quit; 214 } 215 216 bool HasResponse() { 217 return response_.get() != NULL; 218 } 219 220 bool GetResponse() { 221 EXPECT_TRUE(HasResponse()); 222 return *response_.get(); 223 } 224 225 virtual void OnSendResponse(UIThreadExtensionFunction* function, 226 bool success, 227 bool bad_message) OVERRIDE { 228 ASSERT_FALSE(bad_message); 229 ASSERT_FALSE(HasResponse()); 230 response_.reset(new bool); 231 *response_ = success; 232 if (should_post_quit_) { 233 base::MessageLoopForUI::current()->Quit(); 234 } 235 } 236 237 private: 238 scoped_ptr<bool> response_; 239 bool should_post_quit_; 240}; 241 242bool RunFunction(UIThreadExtensionFunction* function, 243 const std::string& args, 244 Browser* browser, 245 RunFunctionFlags flags) { 246 SendResponseDelegate response_delegate; 247 function->set_test_delegate(&response_delegate); 248 scoped_ptr<base::ListValue> parsed_args(ParseList(args)); 249 EXPECT_TRUE(parsed_args.get()) << 250 "Could not parse extension function arguments: " << args; 251 function->SetArgs(parsed_args.get()); 252 253 TestFunctionDispatcherDelegate dispatcher_delegate(browser); 254 extensions::ExtensionFunctionDispatcher dispatcher(browser->profile(), 255 &dispatcher_delegate); 256 function->set_dispatcher(dispatcher.AsWeakPtr()); 257 258 function->set_browser_context(browser->profile()); 259 function->set_include_incognito(flags & INCLUDE_INCOGNITO); 260 function->Run()->Execute(); 261 262 // If the RunAsync of |function| didn't already call SendResponse, run the 263 // message loop until they do. 264 if (!response_delegate.HasResponse()) { 265 response_delegate.set_should_post_quit(true); 266 content::RunMessageLoop(); 267 } 268 269 EXPECT_TRUE(response_delegate.HasResponse()); 270 return response_delegate.GetResponse(); 271} 272 273} // namespace extension_function_test_utils 274