Home | History | Annotate | Download | only in tests
      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