summaryrefslogtreecommitdiffstats
path: root/ppapi/tests/test_utils.h
blob: ab87dd3e47bff4076099a96b924d058247fb788b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef PPAPI_TESTS_TEST_UTILS_H_
#define PPAPI_TESTS_TEST_UTILS_H_

#include <string>

#include "ppapi/c/dev/ppb_testing_dev.h"
#include "ppapi/c/pp_instance.h"
#include "ppapi/c/pp_stdint.h"
#include "ppapi/cpp/completion_callback.h"
#include "ppapi/utility/completion_callback_factory.h"

// Timeout to wait for some action to complete.
extern const int kActionTimeoutMs;

const PPB_Testing_Dev* GetTestingInterface();
std::string ReportError(const char* method, int32_t error);
void PlatformSleep(int duration_ms);
bool GetLocalHostPort(PP_Instance instance, std::string* host, uint16_t* port);

// NestedEvent allows you to run a nested MessageLoop and wait for a particular
// event to complete. For example, you can use it to wait for a callback on a
// PPP interface, which will "Signal" the event and make the loop quit.
// "Wait()" will return immediately if it has already been signalled. Otherwise,
// it will run a nested message loop (using PPB_Testing.RunMessageLoop) and will
// return only after it has been signalled.
// Example:
//  std::string TestFullscreen::TestNormalToFullscreen() {
//    pp::Fullscreen screen_mode(instance);
//    screen_mode.SetFullscreen(true);
//    SimulateUserGesture();
//    // Let DidChangeView run in a nested message loop.
//    nested_event_.Wait();
//    Pass();
//  }
//
//  void TestFullscreen::DidChangeView(const pp::View& view) {
//    nested_event_.Signal();
//  }
class NestedEvent {
 public:
  explicit NestedEvent(PP_Instance instance)
      : instance_(instance), waiting_(false), signalled_(false) {
  }
  // Run a nested message loop and wait until Signal() is called. If Signal()
  // has already been called, return immediately without running a nested loop.
  void Wait();
  // Signal the NestedEvent. If Wait() has been called, quit the message loop.
  void Signal();
  // Reset the NestedEvent so it can be used again.
  void Reset();
 private:
  PP_Instance instance_;
  bool waiting_;
  bool signalled_;
  // Disable copy and assign.
  NestedEvent(const NestedEvent&);
  NestedEvent& operator=(const NestedEvent&);
};

enum CallbackType { PP_REQUIRED, PP_OPTIONAL, PP_BLOCKING };
class TestCompletionCallback {
 public:
  class Delegate {
   public:
    virtual ~Delegate() {}
    virtual void OnCallback(void* user_data, int32_t result) = 0;
  };
  explicit TestCompletionCallback(PP_Instance instance);
  // TODO(dmichael): Remove this constructor.
  TestCompletionCallback(PP_Instance instance, bool force_async);

  TestCompletionCallback(PP_Instance instance, CallbackType callback_type);

  // Sets a Delegate instance. OnCallback() of this instance will be invoked
  // when the completion callback is invoked.
  // The delegate will be reset when Reset() or GetCallback() is called.
  void SetDelegate(Delegate* delegate) { delegate_ = delegate; }

  // Waits for the callback to be called and returns the
  // result. Returns immediately if the callback was previously called
  // and the result wasn't returned (i.e. each result value received
  // by the callback is returned by WaitForResult() once and only
  // once). DEPRECATED: Please use the one below.
  // TODO(dmichael): Remove this one when all the tests are updated.
  int32_t WaitForResult();

  // Wait for a result, given the return from the call which took this callback
  // as a parameter. If |result| is PP_OK_COMPLETIONPENDING, WaitForResult will
  // block until its callback has been invoked (in some cases, this will already
  // have happened, and WaitForCallback can return immediately).
  // For any other values, WaitForResult will simply set its internal "result_"
  // field. To retrieve the final result of the operation (i.e., the result
  // the callback has run, if necessary), call result(). You can call result()
  // as many times as necessary until a new pp::CompletionCallback is retrieved.
  //
  // In some cases, you may want to check that the callback was invoked in the
  // expected way (i.e., if the callback was "Required", then it should be
  // invoked asynchronously). Within the body of a test (where returning a non-
  // empty string indicates test failure), you can use the
  // CHECK_CALLBACK_BEHAVIOR(callback) macro. From within a helper function,
  // you can use failed() and errors().
  //
  // Example usage within a test:
  //  callback.WaitForResult(foo.DoSomething(callback));
  //  CHECK_CALLBACK_BEHAVIOR(callback);
  //  ASSERT_EQ(PP_OK, callback.result());
  //
  // Example usage within a helper function:
  //  void HelperFunction(std::string* error_message) {
  //    callback.WaitForResult(foo.DoSomething(callback));
  //    if (callback.failed())
  //      error_message->assign(callback.errors());
  //  }
  void WaitForResult(int32_t result);

  // Used when you expect to receive either synchronous completion with PP_OK
  // or a PP_ERROR_ABORTED asynchronously.
  //  Example usage:
  //  int32_t result = 0;
  //  {
  //    pp::URLLoader temp(instance_);
  //    result = temp.Open(request, callback);
  //  }
  //  callback.WaitForAbortResult(result);
  //  CHECK_CALLBACK_BEHAVIOR(callback);
  void WaitForAbortResult(int32_t result);

  // Retrieve a pp::CompletionCallback for use in testing. This Reset()s the
  // TestCompletionCallback.
  pp::CompletionCallback GetCallback();
  operator pp::CompletionCallback() {
    return GetCallback();
  }

  // TODO(dmichael): Remove run_count when all tests are updated. Most cases
  //                 that use this can simply use CHECK_CALLBACK_BEHAVIOR.
  unsigned run_count() const { return run_count_; }
  // TODO(dmichael): Remove this; tests should use Reset() instead.
  void reset_run_count() { run_count_ = 0; }

  bool failed() { return !errors_.empty(); }
  const std::string& errors() { return errors_; }

  int32_t result() const { return result_; }

  // Reset so that this callback can be used again.
  void Reset();

 private:
  static void Handler(void* user_data, int32_t result);

  // Used to check that WaitForResult is only called once for each usage of the
  // callback.
  bool wait_for_result_called_;
  // Indicates whether we have already been invoked.
  bool have_result_;
  // The last result received (or PP_OK_COMPLETIONCALLBACK if none).
  int32_t result_;
  CallbackType callback_type_;
  bool post_quit_task_;
  std::string errors_;
  unsigned run_count_;
  PP_Instance instance_;
  Delegate* delegate_;
};

// Verifies that the callback didn't record any errors. If the callback is run
// in an unexpected way (e.g., if it's invoked asynchronously when the call
// should have blocked), this returns an appropriate error string.
#define CHECK_CALLBACK_BEHAVIOR(callback) \
do { \
  if ((callback).failed()) \
    return (callback).errors(); \
} while (false)

/*
 * A set of macros to use for platform detection. These were largely copied
 * from chromium's build_config.h.
 */
#if defined(__APPLE__)
#define PPAPI_OS_MACOSX 1
#elif defined(ANDROID)
#define PPAPI_OS_ANDROID 1
#elif defined(__native_client__)
#define PPAPI_OS_NACL 1
#elif defined(__linux__)
#define PPAPI_OS_LINUX 1
#elif defined(_WIN32)
#define PPAPI_OS_WIN 1
#elif defined(__FreeBSD__)
#define PPAPI_OS_FREEBSD 1
#elif defined(__OpenBSD__)
#define PPAPI_OS_OPENBSD 1
#elif defined(__sun)
#define PPAPI_OS_SOLARIS 1
#else
#error Please add support for your platform in ppapi/tests/test_utils.h
#endif

/* These are used to determine POSIX-like implementations vs Windows. */
#if defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__) || \
    defined(__OpenBSD__) || defined(__sun) || defined(__native_client__)
#define PPAPI_POSIX 1
#endif

#endif  // PPAPI_TESTS_TEST_UTILS_H_