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 #ifndef PPAPI_TESTS_TEST_UTILS_H_ 6 #define PPAPI_TESTS_TEST_UTILS_H_ 7 8 #include <string> 9 10 #include "ppapi/c/pp_instance.h" 11 #include "ppapi/c/pp_stdint.h" 12 #include "ppapi/c/private/ppb_testing_private.h" 13 #include "ppapi/cpp/completion_callback.h" 14 #include "ppapi/cpp/message_loop.h" 15 #include "ppapi/utility/completion_callback_factory.h" 16 17 namespace pp { 18 class NetAddress; 19 } 20 21 // Timeout to wait for some action to complete. 22 extern const int kActionTimeoutMs; 23 24 const PPB_Testing_Private* GetTestingInterface(); 25 std::string ReportError(const char* method, int32_t error); 26 void PlatformSleep(int duration_ms); 27 bool GetLocalHostPort(PP_Instance instance, std::string* host, uint16_t* port); 28 29 uint16_t ConvertFromNetEndian16(uint16_t x); 30 uint16_t ConvertToNetEndian16(uint16_t x); 31 bool EqualNetAddress(const pp::NetAddress& addr1, const pp::NetAddress& addr2); 32 // Only returns the first address if there are more than one available. 33 bool ResolveHost(PP_Instance instance, 34 const std::string& host, 35 uint16_t port, 36 pp::NetAddress* addr); 37 bool ReplacePort(PP_Instance instance, 38 const pp::NetAddress& input_addr, 39 uint16_t port, 40 pp::NetAddress* output_addr); 41 uint16_t GetPort(const pp::NetAddress& addr); 42 43 // NestedEvent allows you to run a nested MessageLoop and wait for a particular 44 // event to complete. For example, you can use it to wait for a callback on a 45 // PPP interface, which will "Signal" the event and make the loop quit. 46 // "Wait()" will return immediately if it has already been signalled. Otherwise, 47 // it will run a nested message loop (using PPB_Testing.RunMessageLoop) and will 48 // return only after it has been signalled. 49 // Example: 50 // std::string TestFullscreen::TestNormalToFullscreen() { 51 // pp::Fullscreen screen_mode(instance); 52 // screen_mode.SetFullscreen(true); 53 // SimulateUserGesture(); 54 // // Let DidChangeView run in a nested message loop. 55 // nested_event_.Wait(); 56 // Pass(); 57 // } 58 // 59 // void TestFullscreen::DidChangeView(const pp::View& view) { 60 // nested_event_.Signal(); 61 // } 62 // 63 // All methods except Signal and PostSignal must be invoked on the main thread. 64 // It's OK to signal from a background thread, so you can (for example) Signal() 65 // from the Audio thread. 66 class NestedEvent { 67 public: 68 explicit NestedEvent(PP_Instance instance) 69 : instance_(instance), waiting_(false), signalled_(false) { 70 } 71 // Run a nested message loop and wait until Signal() is called. If Signal() 72 // has already been called, return immediately without running a nested loop. 73 void Wait(); 74 // Signal the NestedEvent. If Wait() has been called, quit the message loop. 75 // This can be called from any thread. 76 void Signal(); 77 // Signal the NestedEvent in |wait_ms| milliseconds. This can be called from 78 // any thread. 79 void PostSignal(int32_t wait_ms); 80 81 // Reset the NestedEvent so it can be used again. 82 void Reset(); 83 private: 84 void SignalOnMainThread(); 85 static void SignalThunk(void* async_event, int32_t result); 86 87 PP_Instance instance_; 88 bool waiting_; 89 bool signalled_; 90 // Disable copy and assign. 91 NestedEvent(const NestedEvent&); 92 NestedEvent& operator=(const NestedEvent&); 93 }; 94 95 enum CallbackType { PP_REQUIRED, PP_OPTIONAL, PP_BLOCKING }; 96 class TestCompletionCallback { 97 public: 98 class Delegate { 99 public: 100 virtual ~Delegate() {} 101 virtual void OnCallback(void* user_data, int32_t result) = 0; 102 }; 103 explicit TestCompletionCallback(PP_Instance instance); 104 // TODO(dmichael): Remove this constructor. 105 TestCompletionCallback(PP_Instance instance, bool force_async); 106 107 TestCompletionCallback(PP_Instance instance, CallbackType callback_type); 108 109 // Sets a Delegate instance. OnCallback() of this instance will be invoked 110 // when the completion callback is invoked. 111 // The delegate will be reset when Reset() or GetCallback() is called. 112 void SetDelegate(Delegate* delegate) { delegate_ = delegate; } 113 114 // Wait for a result, given the return from the call which took this callback 115 // as a parameter. If |result| is PP_OK_COMPLETIONPENDING, WaitForResult will 116 // block until its callback has been invoked (in some cases, this will already 117 // have happened, and WaitForCallback can return immediately). 118 // For any other values, WaitForResult will simply set its internal "result_" 119 // field. To retrieve the final result of the operation (i.e., the result 120 // the callback has run, if necessary), call result(). You can call result() 121 // as many times as necessary until a new pp::CompletionCallback is retrieved. 122 // 123 // In some cases, you may want to check that the callback was invoked in the 124 // expected way (i.e., if the callback was "Required", then it should be 125 // invoked asynchronously). Within the body of a test (where returning a non- 126 // empty string indicates test failure), you can use the 127 // CHECK_CALLBACK_BEHAVIOR(callback) macro. From within a helper function, 128 // you can use failed() and errors(). 129 // 130 // Example usage within a test: 131 // callback.WaitForResult(foo.DoSomething(callback)); 132 // CHECK_CALLBACK_BEHAVIOR(callback); 133 // ASSERT_EQ(PP_OK, callback.result()); 134 // 135 // Example usage within a helper function: 136 // void HelperFunction(std::string* error_message) { 137 // callback.WaitForResult(foo.DoSomething(callback)); 138 // if (callback.failed()) 139 // error_message->assign(callback.errors()); 140 // } 141 void WaitForResult(int32_t result); 142 143 // Used when you expect to receive either synchronous completion with PP_OK 144 // or a PP_ERROR_ABORTED asynchronously. 145 // Example usage: 146 // int32_t result = 0; 147 // { 148 // pp::URLLoader temp(instance_); 149 // result = temp.Open(request, callback); 150 // } 151 // callback.WaitForAbortResult(result); 152 // CHECK_CALLBACK_BEHAVIOR(callback); 153 void WaitForAbortResult(int32_t result); 154 155 // Retrieve a pp::CompletionCallback for use in testing. This Reset()s the 156 // TestCompletionCallback. 157 pp::CompletionCallback GetCallback(); 158 159 bool failed() { return !errors_.empty(); } 160 const std::string& errors() { return errors_; } 161 162 int32_t result() const { return result_; } 163 164 // Reset so that this callback can be used again. 165 void Reset(); 166 167 CallbackType callback_type() { return callback_type_; } 168 void set_target_loop(const pp::MessageLoop& loop) { target_loop_ = loop; } 169 static void Handler(void* user_data, int32_t result); 170 171 protected: 172 void RunMessageLoop(); 173 void QuitMessageLoop(); 174 175 // Used to check that WaitForResult is only called once for each usage of the 176 // callback. 177 bool wait_for_result_called_; 178 // Indicates whether we have already been invoked. 179 bool have_result_; 180 // The last result received (or PP_OK_COMPLETIONCALLBACK if none). 181 int32_t result_; 182 CallbackType callback_type_; 183 bool post_quit_task_; 184 std::string errors_; 185 PP_Instance instance_; 186 Delegate* delegate_; 187 pp::MessageLoop target_loop_; 188 }; 189 190 namespace internal { 191 192 template <typename OutputT, typename CallbackT> 193 class TestCompletionCallbackWithOutputBase { 194 public: 195 explicit TestCompletionCallbackWithOutputBase(PP_Instance instance) 196 : callback_(instance), 197 output_storage_() { 198 CallbackT::TraitsType::Initialize(&output_storage_); 199 } 200 201 TestCompletionCallbackWithOutputBase(PP_Instance instance, bool force_async) 202 : callback_(instance, force_async), 203 output_storage_() { 204 CallbackT::TraitsType::Initialize(&output_storage_); 205 } 206 207 TestCompletionCallbackWithOutputBase(PP_Instance instance, 208 CallbackType callback_type) 209 : callback_(instance, callback_type), 210 output_storage_() { 211 CallbackT::TraitsType::Initialize(&output_storage_); 212 } 213 214 CallbackT GetCallback(); 215 OutputT output() { 216 return CallbackT::TraitsType::StorageToPluginArg( 217 output_storage_); 218 } 219 220 // Delegate functions to TestCompletionCallback 221 void SetDelegate(TestCompletionCallback::Delegate* delegate) { 222 callback_.SetDelegate(delegate); 223 } 224 void WaitForResult(int32_t result) { callback_.WaitForResult(result); } 225 void WaitForAbortResult(int32_t result) { 226 callback_.WaitForAbortResult(result); 227 } 228 bool failed() { return callback_.failed(); } 229 const std::string& errors() { return callback_.errors(); } 230 int32_t result() const { return callback_.result(); } 231 void Reset() { 232 CallbackT::TraitsType::Initialize(&output_storage_); 233 return callback_.Reset(); 234 } 235 236 private: 237 TestCompletionCallback callback_; 238 typename CallbackT::OutputStorageType output_storage_; 239 }; 240 241 template <typename OutputT, typename CallbackT> 242 CallbackT 243 TestCompletionCallbackWithOutputBase<OutputT, CallbackT>::GetCallback() { 244 this->Reset(); 245 if (callback_.callback_type() == PP_BLOCKING) { 246 CallbackT cc(&output_storage_); 247 return cc; 248 } 249 250 callback_.set_target_loop(pp::MessageLoop::GetCurrent()); 251 CallbackT cc(&TestCompletionCallback::Handler, this, &output_storage_); 252 if (callback_.callback_type() == PP_OPTIONAL) 253 cc.set_flags(PP_COMPLETIONCALLBACK_FLAG_OPTIONAL); 254 return cc; 255 } 256 257 } // namespace internal 258 259 template <typename OutputT> 260 class TestCompletionCallbackWithOutput 261 : public internal::TestCompletionCallbackWithOutputBase< 262 OutputT, pp::CompletionCallbackWithOutput<OutputT> > { 263 public: 264 explicit TestCompletionCallbackWithOutput(PP_Instance instance) 265 : BaseType(instance) { 266 } 267 268 TestCompletionCallbackWithOutput(PP_Instance instance, bool force_async) 269 : BaseType(instance, force_async) { 270 } 271 272 TestCompletionCallbackWithOutput(PP_Instance instance, 273 CallbackType callback_type) 274 : BaseType(instance, callback_type) { 275 } 276 277 private: 278 typedef internal::TestCompletionCallbackWithOutputBase< 279 OutputT, pp::CompletionCallbackWithOutput<OutputT> > BaseType; 280 }; 281 282 template <typename OutputT> 283 class TestExtCompletionCallbackWithOutput 284 : public internal::TestCompletionCallbackWithOutputBase< 285 OutputT, pp::ext::ExtCompletionCallbackWithOutput<OutputT> > { 286 public: 287 explicit TestExtCompletionCallbackWithOutput(PP_Instance instance) 288 : BaseType(instance) { 289 } 290 291 TestExtCompletionCallbackWithOutput(PP_Instance instance, bool force_async) 292 : BaseType(instance, force_async) { 293 } 294 295 TestExtCompletionCallbackWithOutput(PP_Instance instance, 296 CallbackType callback_type) 297 : BaseType(instance, callback_type) { 298 } 299 300 private: 301 typedef internal::TestCompletionCallbackWithOutputBase< 302 OutputT, pp::ext::ExtCompletionCallbackWithOutput<OutputT> > BaseType; 303 }; 304 305 // Verifies that the callback didn't record any errors. If the callback is run 306 // in an unexpected way (e.g., if it's invoked asynchronously when the call 307 // should have blocked), this returns an appropriate error string. 308 #define CHECK_CALLBACK_BEHAVIOR(callback) \ 309 do { \ 310 if ((callback).failed()) \ 311 return MakeFailureMessage(__FILE__, __LINE__, \ 312 (callback).errors().c_str()); \ 313 } while (false) 314 315 /* 316 * A set of macros to use for platform detection. These were largely copied 317 * from chromium's build_config.h. 318 */ 319 #if defined(__APPLE__) 320 #define PPAPI_OS_MACOSX 1 321 #elif defined(ANDROID) 322 #define PPAPI_OS_ANDROID 1 323 #elif defined(__native_client__) 324 #define PPAPI_OS_NACL 1 325 #elif defined(__linux__) 326 #define PPAPI_OS_LINUX 1 327 #elif defined(_WIN32) 328 #define PPAPI_OS_WIN 1 329 #elif defined(__FreeBSD__) 330 #define PPAPI_OS_FREEBSD 1 331 #elif defined(__OpenBSD__) 332 #define PPAPI_OS_OPENBSD 1 333 #elif defined(__sun) 334 #define PPAPI_OS_SOLARIS 1 335 #else 336 #error Please add support for your platform in ppapi/tests/test_utils.h 337 #endif 338 339 /* These are used to determine POSIX-like implementations vs Windows. */ 340 #if defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__) || \ 341 defined(__OpenBSD__) || defined(__sun) || defined(__native_client__) 342 #define PPAPI_POSIX 1 343 #endif 344 345 #endif // PPAPI_TESTS_TEST_UTILS_H_ 346