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/extensions/extension_function_dispatcher.h" 14 #include "chrome/browser/profiles/profile.h" 15 #include "chrome/browser/ui/browser.h" 16 #include "chrome/test/base/ui_test_utils.h" 17 #include "extensions/browser/extension_function.h" 18 #include "extensions/common/extension.h" 19 #include "extensions/common/id_util.h" 20 #include "testing/gtest/include/gtest/gtest.h" 21 22 using content::WebContents; 23 using extensions::Extension; 24 using extensions::Manifest; 25 namespace keys = extensions::tabs_constants; 26 27 namespace { 28 29 class TestFunctionDispatcherDelegate 30 : public 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 51 namespace extension_function_test_utils { 52 53 base::Value* ParseJSON(const std::string& data) { 54 return base::JSONReader::Read(data); 55 } 56 57 base::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 65 base::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 74 bool 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 81 int 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 88 std::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 95 base::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 101 base::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 107 scoped_refptr<Extension> CreateEmptyExtension() { 108 return CreateEmptyExtensionWithLocation(Manifest::INTERNAL); 109 } 110 111 scoped_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 118 scoped_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 126 scoped_refptr<Extension> CreateExtension( 127 base::DictionaryValue* test_extension_value) { 128 return CreateExtension(Manifest::INTERNAL, test_extension_value, 129 std::string()); 130 } 131 132 scoped_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 152 bool 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 161 std::string RunFunctionAndReturnError(UIThreadExtensionFunction* function, 162 const std::string& args, 163 Browser* browser) { 164 return RunFunctionAndReturnError(function, args, browser, NONE); 165 } 166 std::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 178 base::Value* RunFunctionAndReturnSingleResult( 179 UIThreadExtensionFunction* function, 180 const std::string& args, 181 Browser* browser) { 182 return RunFunctionAndReturnSingleResult(function, args, browser, NONE); 183 } 184 base::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. 205 class 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 242 bool 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 ExtensionFunctionDispatcher dispatcher( 255 browser->profile(), &dispatcher_delegate); 256 function->set_dispatcher(dispatcher.AsWeakPtr()); 257 258 function->set_context(browser->profile()); 259 function->set_include_incognito(flags & INCLUDE_INCOGNITO); 260 function->Run(); 261 262 // If the RunImpl 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