Home | History | Annotate | Download | only in base
      1 /*
      2  *  Copyright 2012 The WebRTC Project Authors. All rights reserved.
      3  *
      4  *  Use of this source code is governed by a BSD-style license
      5  *  that can be found in the LICENSE file in the root of the source
      6  *  tree. An additional intellectual property rights grant can be found
      7  *  in the file PATENTS.  All contributing project authors may
      8  *  be found in the AUTHORS file in the root of the source tree.
      9  */
     10 
     11 #include "webrtc/base/sigslot.h"
     12 
     13 #include "webrtc/base/gunit.h"
     14 
     15 // This function, when passed a has_slots or signalx, will break the build if
     16 // its threading requirement is not single threaded
     17 static bool TemplateIsST(const sigslot::single_threaded* p) {
     18   return true;
     19 }
     20 // This function, when passed a has_slots or signalx, will break the build if
     21 // its threading requirement is not multi threaded
     22 static bool TemplateIsMT(const sigslot::multi_threaded_local* p) {
     23   return true;
     24 }
     25 
     26 class SigslotDefault : public testing::Test, public sigslot::has_slots<> {
     27  protected:
     28   sigslot::signal0<> signal_;
     29 };
     30 
     31 template<class slot_policy = sigslot::single_threaded,
     32          class signal_policy = sigslot::single_threaded>
     33 class SigslotReceiver : public sigslot::has_slots<slot_policy> {
     34  public:
     35   SigslotReceiver() : signal_(NULL), signal_count_(0) {
     36   }
     37   ~SigslotReceiver() {
     38   }
     39 
     40   void Connect(sigslot::signal0<signal_policy>* signal) {
     41     if (!signal) return;
     42     Disconnect();
     43     signal_ = signal;
     44     signal->connect(this,
     45                     &SigslotReceiver<slot_policy, signal_policy>::OnSignal);
     46   }
     47   void Disconnect() {
     48     if (!signal_) return;
     49     signal_->disconnect(this);
     50     signal_ = NULL;
     51   }
     52   void OnSignal() {
     53     ++signal_count_;
     54   }
     55   int signal_count() { return signal_count_; }
     56 
     57  private:
     58   sigslot::signal0<signal_policy>* signal_;
     59   int signal_count_;
     60 };
     61 
     62 template<class slot_policy = sigslot::single_threaded,
     63          class mt_signal_policy = sigslot::multi_threaded_local>
     64 class SigslotSlotTest : public testing::Test {
     65  protected:
     66   SigslotSlotTest() {
     67     mt_signal_policy mt_policy;
     68     TemplateIsMT(&mt_policy);
     69   }
     70 
     71   virtual void SetUp() {
     72     Connect();
     73   }
     74   virtual void TearDown() {
     75     Disconnect();
     76   }
     77 
     78   void Disconnect() {
     79     st_receiver_.Disconnect();
     80     mt_receiver_.Disconnect();
     81   }
     82 
     83   void Connect() {
     84     st_receiver_.Connect(&SignalSTLoopback);
     85     mt_receiver_.Connect(&SignalMTLoopback);
     86   }
     87 
     88   int st_loop_back_count() { return st_receiver_.signal_count(); }
     89   int mt_loop_back_count() { return mt_receiver_.signal_count(); }
     90 
     91   sigslot::signal0<> SignalSTLoopback;
     92   SigslotReceiver<slot_policy, sigslot::single_threaded> st_receiver_;
     93   sigslot::signal0<mt_signal_policy> SignalMTLoopback;
     94   SigslotReceiver<slot_policy, mt_signal_policy> mt_receiver_;
     95 };
     96 
     97 typedef SigslotSlotTest<> SigslotSTSlotTest;
     98 typedef SigslotSlotTest<sigslot::multi_threaded_local,
     99                         sigslot::multi_threaded_local> SigslotMTSlotTest;
    100 
    101 class multi_threaded_local_fake : public sigslot::multi_threaded_local {
    102  public:
    103   multi_threaded_local_fake() : lock_count_(0), unlock_count_(0) {
    104   }
    105 
    106   virtual void lock() {
    107     ++lock_count_;
    108   }
    109   virtual void unlock() {
    110     ++unlock_count_;
    111   }
    112 
    113   int lock_count() { return lock_count_; }
    114 
    115   bool InCriticalSection() { return lock_count_ != unlock_count_; }
    116 
    117  protected:
    118   int lock_count_;
    119   int unlock_count_;
    120 };
    121 
    122 typedef SigslotSlotTest<multi_threaded_local_fake,
    123                         multi_threaded_local_fake> SigslotMTLockBase;
    124 
    125 class SigslotMTLockTest : public SigslotMTLockBase {
    126  protected:
    127   SigslotMTLockTest() {}
    128 
    129   virtual void SetUp() {
    130     EXPECT_EQ(0, SlotLockCount());
    131     SigslotMTLockBase::SetUp();
    132     // Connects to two signals (ST and MT). However,
    133     // SlotLockCount() only gets the count for the
    134     // MT signal (there are two separate SigslotReceiver which
    135     // keep track of their own count).
    136     EXPECT_EQ(1, SlotLockCount());
    137   }
    138   virtual void TearDown() {
    139     const int previous_lock_count = SlotLockCount();
    140     SigslotMTLockBase::TearDown();
    141     // Disconnects from two signals. Note analogous to SetUp().
    142     EXPECT_EQ(previous_lock_count + 1, SlotLockCount());
    143   }
    144 
    145   int SlotLockCount() { return mt_receiver_.lock_count(); }
    146   void Signal() { SignalMTLoopback(); }
    147   int SignalLockCount() { return SignalMTLoopback.lock_count(); }
    148   int signal_count() { return mt_loop_back_count(); }
    149   bool InCriticalSection() { return SignalMTLoopback.InCriticalSection(); }
    150 };
    151 
    152 // This test will always succeed. However, if the default template instantiation
    153 // changes from single threaded to multi threaded it will break the build here.
    154 TEST_F(SigslotDefault, DefaultIsST) {
    155   EXPECT_TRUE(TemplateIsST(this));
    156   EXPECT_TRUE(TemplateIsST(&signal_));
    157 }
    158 
    159 // ST slot, ST signal
    160 TEST_F(SigslotSTSlotTest, STLoopbackTest) {
    161   SignalSTLoopback();
    162   EXPECT_EQ(1, st_loop_back_count());
    163   EXPECT_EQ(0, mt_loop_back_count());
    164 }
    165 
    166 // ST slot, MT signal
    167 TEST_F(SigslotSTSlotTest, MTLoopbackTest) {
    168   SignalMTLoopback();
    169   EXPECT_EQ(1, mt_loop_back_count());
    170   EXPECT_EQ(0, st_loop_back_count());
    171 }
    172 
    173 // ST slot, both ST and MT (separate) signal
    174 TEST_F(SigslotSTSlotTest, AllLoopbackTest) {
    175   SignalSTLoopback();
    176   SignalMTLoopback();
    177   EXPECT_EQ(1, mt_loop_back_count());
    178   EXPECT_EQ(1, st_loop_back_count());
    179 }
    180 
    181 TEST_F(SigslotSTSlotTest, Reconnect) {
    182   SignalSTLoopback();
    183   SignalMTLoopback();
    184   EXPECT_EQ(1, mt_loop_back_count());
    185   EXPECT_EQ(1, st_loop_back_count());
    186   Disconnect();
    187   SignalSTLoopback();
    188   SignalMTLoopback();
    189   EXPECT_EQ(1, mt_loop_back_count());
    190   EXPECT_EQ(1, st_loop_back_count());
    191   Connect();
    192   SignalSTLoopback();
    193   SignalMTLoopback();
    194   EXPECT_EQ(2, mt_loop_back_count());
    195   EXPECT_EQ(2, st_loop_back_count());
    196 }
    197 
    198 // MT slot, ST signal
    199 TEST_F(SigslotMTSlotTest, STLoopbackTest) {
    200   SignalSTLoopback();
    201   EXPECT_EQ(1, st_loop_back_count());
    202   EXPECT_EQ(0, mt_loop_back_count());
    203 }
    204 
    205 // MT slot, MT signal
    206 TEST_F(SigslotMTSlotTest, MTLoopbackTest) {
    207   SignalMTLoopback();
    208   EXPECT_EQ(1, mt_loop_back_count());
    209   EXPECT_EQ(0, st_loop_back_count());
    210 }
    211 
    212 // MT slot, both ST and MT (separate) signal
    213 TEST_F(SigslotMTSlotTest, AllLoopbackTest) {
    214   SignalMTLoopback();
    215   SignalSTLoopback();
    216   EXPECT_EQ(1, st_loop_back_count());
    217   EXPECT_EQ(1, mt_loop_back_count());
    218 }
    219 
    220 // Test that locks are acquired and released correctly.
    221 TEST_F(SigslotMTLockTest, LockSanity) {
    222   const int lock_count = SignalLockCount();
    223   Signal();
    224   EXPECT_FALSE(InCriticalSection());
    225   EXPECT_EQ(lock_count + 1, SignalLockCount());
    226   EXPECT_EQ(1, signal_count());
    227 }
    228 
    229 // Destroy signal and slot in different orders.
    230 TEST(DestructionOrder, SignalFirst) {
    231   sigslot::signal0<>* signal = new sigslot::signal0<>;
    232   SigslotReceiver<>* receiver = new SigslotReceiver<>();
    233   receiver->Connect(signal);
    234   (*signal)();
    235   EXPECT_EQ(1, receiver->signal_count());
    236   delete signal;
    237   delete receiver;
    238 }
    239 
    240 TEST(DestructionOrder, SlotFirst) {
    241   sigslot::signal0<>* signal = new sigslot::signal0<>;
    242   SigslotReceiver<>* receiver = new SigslotReceiver<>();
    243   receiver->Connect(signal);
    244   (*signal)();
    245   EXPECT_EQ(1, receiver->signal_count());
    246 
    247   delete receiver;
    248   (*signal)();
    249   delete signal;
    250 }
    251