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