1// Copyright 2014 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 "extensions/browser/api_test_utils.h" 6 7#include "base/json/json_reader.h" 8#include "base/memory/scoped_ptr.h" 9#include "base/values.h" 10#include "content/public/browser/browser_context.h" 11#include "content/public/test/test_utils.h" 12#include "extensions/browser/extension_function.h" 13#include "extensions/browser/extension_function_dispatcher.h" 14#include "extensions/common/extension_builder.h" 15#include "testing/gtest/include/gtest/gtest.h" 16 17using extensions::ExtensionFunctionDispatcher; 18 19namespace { 20 21class TestFunctionDispatcherDelegate 22 : public ExtensionFunctionDispatcher::Delegate { 23 public: 24 TestFunctionDispatcherDelegate() {} 25 virtual ~TestFunctionDispatcherDelegate() {} 26 27 // NULL implementation. 28 private: 29 DISALLOW_COPY_AND_ASSIGN(TestFunctionDispatcherDelegate); 30}; 31 32base::Value* ParseJSON(const std::string& data) { 33 return base::JSONReader::Read(data); 34} 35 36base::ListValue* ParseList(const std::string& data) { 37 base::Value* result = ParseJSON(data); 38 base::ListValue* list = NULL; 39 result->GetAsList(&list); 40 return list; 41} 42 43// This helps us be able to wait until an UIThreadExtensionFunction calls 44// SendResponse. 45class SendResponseDelegate 46 : public UIThreadExtensionFunction::DelegateForTests { 47 public: 48 SendResponseDelegate() : should_post_quit_(false) {} 49 50 virtual ~SendResponseDelegate() {} 51 52 void set_should_post_quit(bool should_quit) { 53 should_post_quit_ = should_quit; 54 } 55 56 bool HasResponse() { return response_.get() != NULL; } 57 58 bool GetResponse() { 59 EXPECT_TRUE(HasResponse()); 60 return *response_.get(); 61 } 62 63 virtual void OnSendResponse(UIThreadExtensionFunction* function, 64 bool success, 65 bool bad_message) OVERRIDE { 66 ASSERT_FALSE(bad_message); 67 ASSERT_FALSE(HasResponse()); 68 response_.reset(new bool); 69 *response_ = success; 70 if (should_post_quit_) { 71 base::MessageLoopForUI::current()->Quit(); 72 } 73 } 74 75 private: 76 scoped_ptr<bool> response_; 77 bool should_post_quit_; 78}; 79 80} // namespace 81 82namespace extensions { 83 84namespace api_test_utils { 85 86base::Value* RunFunctionWithDelegateAndReturnSingleResult( 87 UIThreadExtensionFunction* function, 88 const std::string& args, 89 content::BrowserContext* context, 90 scoped_ptr<extensions::ExtensionFunctionDispatcher> dispatcher) { 91 return RunFunctionWithDelegateAndReturnSingleResult( 92 function, args, context, dispatcher.Pass(), NONE); 93} 94 95base::Value* RunFunctionWithDelegateAndReturnSingleResult( 96 UIThreadExtensionFunction* function, 97 const std::string& args, 98 content::BrowserContext* context, 99 scoped_ptr<extensions::ExtensionFunctionDispatcher> dispatcher, 100 RunFunctionFlags flags) { 101 scoped_refptr<ExtensionFunction> function_owner(function); 102 // Without a callback the function will not generate a result. 103 function->set_has_callback(true); 104 RunFunction(function, args, context, dispatcher.Pass(), flags); 105 EXPECT_TRUE(function->GetError().empty()) 106 << "Unexpected error: " << function->GetError(); 107 const base::Value* single_result = NULL; 108 if (function->GetResultList() != NULL && 109 function->GetResultList()->Get(0, &single_result)) { 110 return single_result->DeepCopy(); 111 } 112 return NULL; 113} 114 115base::Value* RunFunctionAndReturnSingleResult( 116 UIThreadExtensionFunction* function, 117 const std::string& args, 118 content::BrowserContext* context) { 119 return RunFunctionAndReturnSingleResult(function, args, context, NONE); 120} 121 122base::Value* RunFunctionAndReturnSingleResult( 123 UIThreadExtensionFunction* function, 124 const std::string& args, 125 content::BrowserContext* context, 126 RunFunctionFlags flags) { 127 TestFunctionDispatcherDelegate delegate; 128 scoped_ptr<ExtensionFunctionDispatcher> dispatcher( 129 new ExtensionFunctionDispatcher(context, &delegate)); 130 131 return RunFunctionWithDelegateAndReturnSingleResult( 132 function, args, context, dispatcher.Pass(), flags); 133} 134 135std::string RunFunctionAndReturnError(UIThreadExtensionFunction* function, 136 const std::string& args, 137 content::BrowserContext* context) { 138 return RunFunctionAndReturnError(function, args, context, NONE); 139} 140 141std::string RunFunctionAndReturnError(UIThreadExtensionFunction* function, 142 const std::string& args, 143 content::BrowserContext* context, 144 RunFunctionFlags flags) { 145 TestFunctionDispatcherDelegate delegate; 146 scoped_ptr<ExtensionFunctionDispatcher> dispatcher( 147 new ExtensionFunctionDispatcher(context, &delegate)); 148 scoped_refptr<ExtensionFunction> function_owner(function); 149 // Without a callback the function will not generate a result. 150 function->set_has_callback(true); 151 RunFunction(function, args, context, dispatcher.Pass(), flags); 152 EXPECT_FALSE(function->GetResultList()) << "Did not expect a result"; 153 return function->GetError(); 154} 155 156bool RunFunction(UIThreadExtensionFunction* function, 157 const std::string& args, 158 content::BrowserContext* context) { 159 TestFunctionDispatcherDelegate delegate; 160 scoped_ptr<ExtensionFunctionDispatcher> dispatcher( 161 new ExtensionFunctionDispatcher(context, &delegate)); 162 return RunFunction(function, args, context, dispatcher.Pass(), NONE); 163} 164 165bool RunFunction(UIThreadExtensionFunction* function, 166 const std::string& args, 167 content::BrowserContext* context, 168 scoped_ptr<extensions::ExtensionFunctionDispatcher> dispatcher, 169 RunFunctionFlags flags) { 170 scoped_ptr<base::ListValue> parsed_args(ParseList(args)); 171 EXPECT_TRUE(parsed_args.get()) 172 << "Could not parse extension function arguments: " << args; 173 return RunFunction( 174 function, parsed_args.Pass(), context, dispatcher.Pass(), flags); 175} 176 177bool RunFunction(UIThreadExtensionFunction* function, 178 scoped_ptr<base::ListValue> args, 179 content::BrowserContext* context, 180 scoped_ptr<extensions::ExtensionFunctionDispatcher> dispatcher, 181 RunFunctionFlags flags) { 182 SendResponseDelegate response_delegate; 183 function->set_test_delegate(&response_delegate); 184 function->SetArgs(args.get()); 185 186 CHECK(dispatcher); 187 function->set_dispatcher(dispatcher->AsWeakPtr()); 188 189 function->set_browser_context(context); 190 function->set_include_incognito(flags & INCLUDE_INCOGNITO); 191 function->Run()->Execute(); 192 193 // If the RunAsync of |function| didn't already call SendResponse, run the 194 // message loop until they do. 195 if (!response_delegate.HasResponse()) { 196 response_delegate.set_should_post_quit(true); 197 content::RunMessageLoop(); 198 } 199 200 EXPECT_TRUE(response_delegate.HasResponse()); 201 return response_delegate.GetResponse(); 202} 203 204} // namespace api_test_utils 205} // namespace extensions 206