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:
NestedEvent(PP_Instance instance)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:
~Delegate()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.
SetDelegate(Delegate * delegate)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
failed()159 bool failed() { return !errors_.empty(); }
errors()160 const std::string& errors() { return errors_; }
161
result()162 int32_t result() const { return result_; }
163
164 // Reset so that this callback can be used again.
165 void Reset();
166
callback_type()167 CallbackType callback_type() { return callback_type_; }
set_target_loop(const pp::MessageLoop & loop)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:
TestCompletionCallbackWithOutputBase(PP_Instance instance)195 explicit TestCompletionCallbackWithOutputBase(PP_Instance instance)
196 : callback_(instance),
197 output_storage_() {
198 CallbackT::TraitsType::Initialize(&output_storage_);
199 }
200
TestCompletionCallbackWithOutputBase(PP_Instance instance,bool force_async)201 TestCompletionCallbackWithOutputBase(PP_Instance instance, bool force_async)
202 : callback_(instance, force_async),
203 output_storage_() {
204 CallbackT::TraitsType::Initialize(&output_storage_);
205 }
206
TestCompletionCallbackWithOutputBase(PP_Instance instance,CallbackType callback_type)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();
output()215 OutputT output() {
216 return CallbackT::TraitsType::StorageToPluginArg(
217 output_storage_);
218 }
219
220 // Delegate functions to TestCompletionCallback
SetDelegate(TestCompletionCallback::Delegate * delegate)221 void SetDelegate(TestCompletionCallback::Delegate* delegate) {
222 callback_.SetDelegate(delegate);
223 }
WaitForResult(int32_t result)224 void WaitForResult(int32_t result) { callback_.WaitForResult(result); }
WaitForAbortResult(int32_t result)225 void WaitForAbortResult(int32_t result) {
226 callback_.WaitForAbortResult(result);
227 }
failed()228 bool failed() { return callback_.failed(); }
errors()229 const std::string& errors() { return callback_.errors(); }
result()230 int32_t result() const { return callback_.result(); }
Reset()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
GetCallback()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:
TestCompletionCallbackWithOutput(PP_Instance instance)264 explicit TestCompletionCallbackWithOutput(PP_Instance instance)
265 : BaseType(instance) {
266 }
267
TestCompletionCallbackWithOutput(PP_Instance instance,bool force_async)268 TestCompletionCallbackWithOutput(PP_Instance instance, bool force_async)
269 : BaseType(instance, force_async) {
270 }
271
TestCompletionCallbackWithOutput(PP_Instance instance,CallbackType callback_type)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:
TestExtCompletionCallbackWithOutput(PP_Instance instance)287 explicit TestExtCompletionCallbackWithOutput(PP_Instance instance)
288 : BaseType(instance) {
289 }
290
TestExtCompletionCallbackWithOutput(PP_Instance instance,bool force_async)291 TestExtCompletionCallbackWithOutput(PP_Instance instance, bool force_async)
292 : BaseType(instance, force_async) {
293 }
294
TestExtCompletionCallbackWithOutput(PP_Instance instance,CallbackType callback_type)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