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 template <typename OutputT> 191 class TestCompletionCallbackWithOutput { 192 public: 193 explicit TestCompletionCallbackWithOutput(PP_Instance instance) 194 : callback_(instance), 195 output_storage_() { 196 pp::internal::CallbackOutputTraits<OutputT>::Initialize(&output_storage_); 197 } 198 199 TestCompletionCallbackWithOutput(PP_Instance instance, bool force_async) 200 : callback_(instance, force_async), 201 output_storage_() { 202 pp::internal::CallbackOutputTraits<OutputT>::Initialize(&output_storage_); 203 } 204 205 TestCompletionCallbackWithOutput(PP_Instance instance, 206 CallbackType callback_type) 207 : callback_(instance, callback_type), 208 output_storage_() { 209 pp::internal::CallbackOutputTraits<OutputT>::Initialize(&output_storage_); 210 } 211 212 pp::CompletionCallbackWithOutput<OutputT> GetCallback(); 213 OutputT output() { 214 return pp::internal::CallbackOutputTraits<OutputT>::StorageToPluginArg( 215 output_storage_); 216 } 217 218 // Delegate functions to TestCompletionCallback 219 void SetDelegate(TestCompletionCallback::Delegate* delegate) { 220 callback_.SetDelegate(delegate); 221 } 222 void WaitForResult(int32_t result) { callback_.WaitForResult(result); } 223 void WaitForAbortResult(int32_t result) { 224 callback_.WaitForAbortResult(result); 225 } 226 bool failed() { return callback_.failed(); } 227 const std::string& errors() { return callback_.errors(); } 228 int32_t result() const { return callback_.result(); } 229 void Reset() { 230 pp::internal::CallbackOutputTraits<OutputT>::Initialize(&output_storage_); 231 return callback_.Reset(); 232 } 233 234 private: 235 TestCompletionCallback callback_; 236 typename pp::CompletionCallbackWithOutput<OutputT>::OutputStorageType 237 output_storage_; 238 }; 239 240 template <typename OutputT> 241 pp::CompletionCallbackWithOutput<OutputT> 242 TestCompletionCallbackWithOutput<OutputT>::GetCallback() { 243 this->Reset(); 244 if (callback_.callback_type() == PP_BLOCKING) { 245 pp::CompletionCallbackWithOutput<OutputT> cc(&output_storage_); 246 return cc; 247 } 248 249 callback_.set_target_loop(pp::MessageLoop::GetCurrent()); 250 pp::CompletionCallbackWithOutput<OutputT> cc( 251 &TestCompletionCallback::Handler, 252 this, 253 &output_storage_); 254 if (callback_.callback_type() == PP_OPTIONAL) 255 cc.set_flags(PP_COMPLETIONCALLBACK_FLAG_OPTIONAL); 256 return cc; 257 } 258 259 // Verifies that the callback didn't record any errors. If the callback is run 260 // in an unexpected way (e.g., if it's invoked asynchronously when the call 261 // should have blocked), this returns an appropriate error string. 262 #define CHECK_CALLBACK_BEHAVIOR(callback) \ 263 do { \ 264 if ((callback).failed()) \ 265 return MakeFailureMessage(__FILE__, __LINE__, \ 266 (callback).errors().c_str()); \ 267 } while (false) 268 269 /* 270 * A set of macros to use for platform detection. These were largely copied 271 * from chromium's build_config.h. 272 */ 273 #if defined(__APPLE__) 274 #define PPAPI_OS_MACOSX 1 275 #elif defined(ANDROID) 276 #define PPAPI_OS_ANDROID 1 277 #elif defined(__native_client__) 278 #define PPAPI_OS_NACL 1 279 #elif defined(__linux__) 280 #define PPAPI_OS_LINUX 1 281 #elif defined(_WIN32) 282 #define PPAPI_OS_WIN 1 283 #elif defined(__FreeBSD__) 284 #define PPAPI_OS_FREEBSD 1 285 #elif defined(__OpenBSD__) 286 #define PPAPI_OS_OPENBSD 1 287 #elif defined(__sun) 288 #define PPAPI_OS_SOLARIS 1 289 #else 290 #error Please add support for your platform in ppapi/tests/test_utils.h 291 #endif 292 293 /* These are used to determine POSIX-like implementations vs Windows. */ 294 #if defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__) || \ 295 defined(__OpenBSD__) || defined(__sun) || defined(__native_client__) 296 #define PPAPI_POSIX 1 297 #endif 298 299 #endif // PPAPI_TESTS_TEST_UTILS_H_ 300