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 "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" 22 23 using content::WebContents; 24 using extensions::Extension; 25 using extensions::Manifest; 26 namespace keys = extensions::tabs_constants; 27 28 namespace { 29 30 class TestFunctionDispatcherDelegate 31 : public extensions::ExtensionFunctionDispatcher::Delegate { 32 public: 33 explicit TestFunctionDispatcherDelegate(Browser* browser) : 34 browser_(browser) {} 35 virtual ~TestFunctionDispatcherDelegate() {} 36 37 private: 38 virtual extensions::WindowController* GetExtensionWindowController() 39 const OVERRIDE { 40 return browser_->extension_window_controller(); 41 } 42 43 virtual WebContents* GetAssociatedWebContents() const OVERRIDE { 44 return NULL; 45 } 46 47 Browser* browser_; 48 }; 49 50 } // namespace 51 52 namespace extension_function_test_utils { 53 54 base::Value* ParseJSON(const std::string& data) { 55 return base::JSONReader::Read(data); 56 } 57 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; 63 } 64 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; 71 } 72 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; 78 } 79 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; 85 } 86 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; 92 } 93 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); 98 } 99 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); 104 } 105 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()); 111 } 112 113 scoped_refptr<Extension> CreateExtension( 114 base::DictionaryValue* test_extension_value) { 115 return CreateExtension(Manifest::INTERNAL, test_extension_value, 116 std::string()); 117 } 118 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, 133 id, 134 &error)); 135 EXPECT_TRUE(error.empty()) << "Could not parse test extension " << error; 136 return extension; 137 } 138 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; 146 } 147 148 std::string RunFunctionAndReturnError(UIThreadExtensionFunction* function, 149 const std::string& args, 150 Browser* browser) { 151 return RunFunctionAndReturnError(function, args, browser, NONE); 152 } 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(); 163 } 164 165 base::Value* RunFunctionAndReturnSingleResult( 166 UIThreadExtensionFunction* function, 167 const std::string& args, 168 Browser* browser) { 169 return RunFunctionAndReturnSingleResult(function, args, browser, NONE); 170 } 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(); 186 } 187 return NULL; 188 } 189 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) {} 196 197 virtual ~SendResponseDelegate() {} 198 199 void set_should_post_quit(bool should_quit) { 200 should_post_quit_ = should_quit; 201 } 202 203 bool HasResponse() { 204 return response_.get() != NULL; 205 } 206 207 bool GetResponse() { 208 EXPECT_TRUE(HasResponse()); 209 return *response_.get(); 210 } 211 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(); 221 } 222 } 223 224 private: 225 scoped_ptr<bool> response_; 226 bool should_post_quit_; 227 }; 228 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); 237 } 238 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)); 255 } 256 257 } // namespace extension_function_test_utils 258