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