Home | History | Annotate | Download | only in base
      1 /*
      2  *  Copyright 2015 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 <sstream>
     12 #include <string>
     13 #include <utility>
     14 #include <vector>
     15 
     16 #include "webrtc/base/gunit.h"
     17 #include "webrtc/base/optional.h"
     18 
     19 namespace rtc {
     20 
     21 namespace {
     22 
     23 // Class whose instances logs various method calls (constructor, destructor,
     24 // etc.). Each instance has a unique ID (a simple global sequence number) and
     25 // an origin ID. When a copy is made, the new object gets a fresh ID but copies
     26 // the origin ID from the original. When a new Logger is created from scratch,
     27 // it gets a fresh ID, and the origin ID is the same as the ID (default
     28 // constructor) or given as an argument (explicit constructor).
     29 class Logger {
     30  public:
     31   Logger() : id_(next_id_++), origin_(id_) { Log("default constructor"); }
     32   explicit Logger(int origin) : id_(next_id_++), origin_(origin) {
     33     Log("explicit constructor");
     34   }
     35   Logger(const Logger& other) : id_(next_id_++), origin_(other.origin_) {
     36     LogFrom("copy constructor", other);
     37   }
     38   Logger(Logger&& other) : id_(next_id_++), origin_(other.origin_) {
     39     LogFrom("move constructor", other);
     40   }
     41   ~Logger() { Log("destructor"); }
     42   Logger& operator=(const Logger& other) {
     43     origin_ = other.origin_;
     44     LogFrom("operator= copy", other);
     45     return *this;
     46   }
     47   Logger& operator=(Logger&& other) {
     48     origin_ = other.origin_;
     49     LogFrom("operator= move", other);
     50     return *this;
     51   }
     52   friend void swap(Logger& a, Logger& b) {
     53     using std::swap;
     54     swap(a.origin_, b.origin_);
     55     Log2("swap", a, b);
     56   }
     57   friend bool operator==(const Logger& a, const Logger& b) {
     58     Log2("operator==", a, b);
     59     return a.origin_ == b.origin_;
     60   }
     61   friend bool operator!=(const Logger& a, const Logger& b) {
     62     Log2("operator!=", a, b);
     63     return a.origin_ != b.origin_;
     64   }
     65   void Foo() { Log("Foo()"); }
     66   void Foo() const { Log("Foo() const"); }
     67   static rtc::scoped_ptr<std::vector<std::string>> Setup() {
     68     auto s = rtc_make_scoped_ptr(new std::vector<std::string>);
     69     Logger::log_ = s.get();
     70     Logger::next_id_ = 0;
     71     return s;
     72   }
     73 
     74  private:
     75   int id_;
     76   int origin_;
     77   static std::vector<std::string>* log_;
     78   static int next_id_;
     79   void Log(const char* msg) const {
     80     std::ostringstream oss;
     81     oss << id_ << ':' << origin_ << ". " << msg;
     82     log_->push_back(oss.str());
     83   }
     84   void LogFrom(const char* msg, const Logger& other) const {
     85     std::ostringstream oss;
     86     oss << id_ << ':' << origin_ << ". " << msg << " (from " << other.id_ << ':'
     87         << other.origin_ << ")";
     88     log_->push_back(oss.str());
     89   }
     90   static void Log2(const char* msg, const Logger& a, const Logger& b) {
     91     std::ostringstream oss;
     92     oss << msg << ' ' << a.id_ << ':' << a.origin_ << ", " << b.id_ << ':'
     93         << b.origin_;
     94     log_->push_back(oss.str());
     95   }
     96 };
     97 
     98 std::vector<std::string>* Logger::log_ = nullptr;
     99 int Logger::next_id_ = 0;
    100 
    101 // Append all the other args to the vector pointed to by the first arg.
    102 template <typename T>
    103 void VectorAppend(std::vector<T>* v) {}
    104 template <typename T, typename... Ts>
    105 void VectorAppend(std::vector<T>* v, const T& e, Ts... es) {
    106   v->push_back(e);
    107   VectorAppend(v, es...);
    108 }
    109 
    110 // Create a vector of strings. Because we're not allowed to use
    111 // std::initializer_list.
    112 template <typename... Ts>
    113 std::vector<std::string> V(Ts... es) {
    114   std::vector<std::string> strings;
    115   VectorAppend(&strings, static_cast<std::string>(es)...);
    116   return strings;
    117 }
    118 
    119 }  // namespace
    120 
    121 TEST(OptionalTest, TestConstructDefault) {
    122   auto log = Logger::Setup();
    123   {
    124     Optional<Logger> x;
    125     EXPECT_FALSE(x);
    126   }
    127   EXPECT_EQ(V("0:0. default constructor", "0:0. destructor"), *log);
    128 }
    129 
    130 TEST(OptionalTest, TestConstructCopyEmpty) {
    131   auto log = Logger::Setup();
    132   {
    133     Optional<Logger> x;
    134     EXPECT_FALSE(x);
    135     auto y = x;
    136     EXPECT_FALSE(y);
    137   }
    138   EXPECT_EQ(V("0:0. default constructor", "1:0. copy constructor (from 0:0)",
    139               "1:0. destructor", "0:0. destructor"),
    140             *log);
    141 }
    142 
    143 TEST(OptionalTest, TestConstructCopyFull) {
    144   auto log = Logger::Setup();
    145   {
    146     Logger a;
    147     Optional<Logger> x(a);
    148     EXPECT_TRUE(x);
    149     log->push_back("---");
    150     auto y = x;
    151     EXPECT_TRUE(y);
    152     log->push_back("---");
    153   }
    154   EXPECT_EQ(V("0:0. default constructor", "1:0. copy constructor (from 0:0)",
    155               "---", "2:0. copy constructor (from 1:0)", "---",
    156               "2:0. destructor", "1:0. destructor", "0:0. destructor"),
    157             *log);
    158 }
    159 
    160 TEST(OptionalTest, TestConstructMoveEmpty) {
    161   auto log = Logger::Setup();
    162   {
    163     Optional<Logger> x;
    164     EXPECT_FALSE(x);
    165     auto y = std::move(x);
    166     EXPECT_FALSE(y);
    167   }
    168   EXPECT_EQ(V("0:0. default constructor", "1:0. move constructor (from 0:0)",
    169               "1:0. destructor", "0:0. destructor"),
    170             *log);
    171 }
    172 
    173 TEST(OptionalTest, TestConstructMoveFull) {
    174   auto log = Logger::Setup();
    175   {
    176     Optional<Logger> x(Logger(17));
    177     EXPECT_TRUE(x);
    178     log->push_back("---");
    179     auto y = std::move(x);
    180     EXPECT_TRUE(x);
    181     EXPECT_TRUE(y);
    182     log->push_back("---");
    183   }
    184   EXPECT_EQ(
    185       V("0:17. explicit constructor", "1:17. move constructor (from 0:17)",
    186         "0:17. destructor", "---", "2:17. move constructor (from 1:17)", "---",
    187         "2:17. destructor", "1:17. destructor"),
    188       *log);
    189 }
    190 
    191 TEST(OptionalTest, TestCopyAssignToEmptyFromEmpty) {
    192   auto log = Logger::Setup();
    193   {
    194     Optional<Logger> x, y;
    195     x = y;
    196   }
    197   EXPECT_EQ(
    198       V("0:0. default constructor", "1:1. default constructor",
    199         "0:1. operator= copy (from 1:1)", "1:1. destructor", "0:1. destructor"),
    200       *log);
    201 }
    202 
    203 TEST(OptionalTest, TestCopyAssignToFullFromEmpty) {
    204   auto log = Logger::Setup();
    205   {
    206     Optional<Logger> x(Logger(17));
    207     Optional<Logger> y;
    208     log->push_back("---");
    209     x = y;
    210     log->push_back("---");
    211   }
    212   EXPECT_EQ(
    213       V("0:17. explicit constructor", "1:17. move constructor (from 0:17)",
    214         "0:17. destructor", "2:2. default constructor", "---",
    215         "1:2. operator= copy (from 2:2)", "---", "2:2. destructor",
    216         "1:2. destructor"),
    217       *log);
    218 }
    219 
    220 TEST(OptionalTest, TestCopyAssignToEmptyFromFull) {
    221   auto log = Logger::Setup();
    222   {
    223     Optional<Logger> x;
    224     Optional<Logger> y(Logger(17));
    225     log->push_back("---");
    226     x = y;
    227     log->push_back("---");
    228   }
    229   EXPECT_EQ(V("0:0. default constructor", "1:17. explicit constructor",
    230               "2:17. move constructor (from 1:17)", "1:17. destructor", "---",
    231               "0:17. operator= copy (from 2:17)", "---", "2:17. destructor",
    232               "0:17. destructor"),
    233             *log);
    234 }
    235 
    236 TEST(OptionalTest, TestCopyAssignToFullFromFull) {
    237   auto log = Logger::Setup();
    238   {
    239     Optional<Logger> x(Logger(17));
    240     Optional<Logger> y(Logger(42));
    241     log->push_back("---");
    242     x = y;
    243     log->push_back("---");
    244   }
    245   EXPECT_EQ(
    246       V("0:17. explicit constructor", "1:17. move constructor (from 0:17)",
    247         "0:17. destructor", "2:42. explicit constructor",
    248         "3:42. move constructor (from 2:42)", "2:42. destructor", "---",
    249         "1:42. operator= copy (from 3:42)", "---", "3:42. destructor",
    250         "1:42. destructor"),
    251       *log);
    252 }
    253 
    254 TEST(OptionalTest, TestCopyAssignToEmptyFromT) {
    255   auto log = Logger::Setup();
    256   {
    257     Optional<Logger> x;
    258     Logger y(17);
    259     log->push_back("---");
    260     x = Optional<Logger>(y);
    261     log->push_back("---");
    262   }
    263   EXPECT_EQ(V("0:0. default constructor", "1:17. explicit constructor", "---",
    264               "2:17. copy constructor (from 1:17)",
    265               "0:17. operator= move (from 2:17)", "2:17. destructor", "---",
    266               "1:17. destructor", "0:17. destructor"),
    267             *log);
    268 }
    269 
    270 TEST(OptionalTest, TestCopyAssignToFullFromT) {
    271   auto log = Logger::Setup();
    272   {
    273     Optional<Logger> x(Logger(17));
    274     Logger y(42);
    275     log->push_back("---");
    276     x = Optional<Logger>(y);
    277     log->push_back("---");
    278   }
    279   EXPECT_EQ(
    280       V("0:17. explicit constructor", "1:17. move constructor (from 0:17)",
    281         "0:17. destructor", "2:42. explicit constructor", "---",
    282         "3:42. copy constructor (from 2:42)",
    283         "1:42. operator= move (from 3:42)", "3:42. destructor", "---",
    284         "2:42. destructor", "1:42. destructor"),
    285       *log);
    286 }
    287 
    288 TEST(OptionalTest, TestMoveAssignToEmptyFromEmpty) {
    289   auto log = Logger::Setup();
    290   {
    291     Optional<Logger> x, y;
    292     x = std::move(y);
    293   }
    294   EXPECT_EQ(
    295       V("0:0. default constructor", "1:1. default constructor",
    296         "0:1. operator= move (from 1:1)", "1:1. destructor", "0:1. destructor"),
    297       *log);
    298 }
    299 
    300 TEST(OptionalTest, TestMoveAssignToFullFromEmpty) {
    301   auto log = Logger::Setup();
    302   {
    303     Optional<Logger> x(Logger(17));
    304     Optional<Logger> y;
    305     log->push_back("---");
    306     x = std::move(y);
    307     log->push_back("---");
    308   }
    309   EXPECT_EQ(
    310       V("0:17. explicit constructor", "1:17. move constructor (from 0:17)",
    311         "0:17. destructor", "2:2. default constructor", "---",
    312         "1:2. operator= move (from 2:2)", "---", "2:2. destructor",
    313         "1:2. destructor"),
    314       *log);
    315 }
    316 
    317 TEST(OptionalTest, TestMoveAssignToEmptyFromFull) {
    318   auto log = Logger::Setup();
    319   {
    320     Optional<Logger> x;
    321     Optional<Logger> y(Logger(17));
    322     log->push_back("---");
    323     x = std::move(y);
    324     log->push_back("---");
    325   }
    326   EXPECT_EQ(V("0:0. default constructor", "1:17. explicit constructor",
    327               "2:17. move constructor (from 1:17)", "1:17. destructor", "---",
    328               "0:17. operator= move (from 2:17)", "---", "2:17. destructor",
    329               "0:17. destructor"),
    330             *log);
    331 }
    332 
    333 TEST(OptionalTest, TestMoveAssignToFullFromFull) {
    334   auto log = Logger::Setup();
    335   {
    336     Optional<Logger> x(Logger(17));
    337     Optional<Logger> y(Logger(42));
    338     log->push_back("---");
    339     x = std::move(y);
    340     log->push_back("---");
    341   }
    342   EXPECT_EQ(
    343       V("0:17. explicit constructor", "1:17. move constructor (from 0:17)",
    344         "0:17. destructor", "2:42. explicit constructor",
    345         "3:42. move constructor (from 2:42)", "2:42. destructor", "---",
    346         "1:42. operator= move (from 3:42)", "---", "3:42. destructor",
    347         "1:42. destructor"),
    348       *log);
    349 }
    350 
    351 TEST(OptionalTest, TestMoveAssignToEmptyFromT) {
    352   auto log = Logger::Setup();
    353   {
    354     Optional<Logger> x;
    355     Logger y(17);
    356     log->push_back("---");
    357     x = Optional<Logger>(std::move(y));
    358     log->push_back("---");
    359   }
    360   EXPECT_EQ(V("0:0. default constructor", "1:17. explicit constructor", "---",
    361               "2:17. move constructor (from 1:17)",
    362               "0:17. operator= move (from 2:17)", "2:17. destructor", "---",
    363               "1:17. destructor", "0:17. destructor"),
    364             *log);
    365 }
    366 
    367 TEST(OptionalTest, TestMoveAssignToFullFromT) {
    368   auto log = Logger::Setup();
    369   {
    370     Optional<Logger> x(Logger(17));
    371     Logger y(42);
    372     log->push_back("---");
    373     x = Optional<Logger>(std::move(y));
    374     log->push_back("---");
    375   }
    376   EXPECT_EQ(
    377       V("0:17. explicit constructor", "1:17. move constructor (from 0:17)",
    378         "0:17. destructor", "2:42. explicit constructor", "---",
    379         "3:42. move constructor (from 2:42)",
    380         "1:42. operator= move (from 3:42)", "3:42. destructor", "---",
    381         "2:42. destructor", "1:42. destructor"),
    382       *log);
    383 }
    384 
    385 TEST(OptionalTest, TestDereference) {
    386   auto log = Logger::Setup();
    387   {
    388     Optional<Logger> x(Logger(42));
    389     const auto& y = x;
    390     log->push_back("---");
    391     x->Foo();
    392     y->Foo();
    393     std::move(x)->Foo();
    394     std::move(y)->Foo();
    395     log->push_back("---");
    396     (*x).Foo();
    397     (*y).Foo();
    398     (*std::move(x)).Foo();
    399     (*std::move(y)).Foo();
    400     log->push_back("---");
    401   }
    402   EXPECT_EQ(V("0:42. explicit constructor",
    403               "1:42. move constructor (from 0:42)", "0:42. destructor", "---",
    404               "1:42. Foo()", "1:42. Foo() const", "1:42. Foo()",
    405               "1:42. Foo() const", "---", "1:42. Foo()", "1:42. Foo() const",
    406               "1:42. Foo()", "1:42. Foo() const", "---", "1:42. destructor"),
    407             *log);
    408 }
    409 
    410 TEST(OptionalTest, TestDereferenceWithDefault) {
    411   auto log = Logger::Setup();
    412   {
    413     const Logger a(17), b(42);
    414     Optional<Logger> x(a);
    415     Optional<Logger> y;
    416     log->push_back("-1-");
    417     EXPECT_EQ(a, x.value_or(Logger(42)));
    418     log->push_back("-2-");
    419     EXPECT_EQ(b, y.value_or(Logger(42)));
    420     log->push_back("-3-");
    421     EXPECT_EQ(a, Optional<Logger>(Logger(17)).value_or(b));
    422     log->push_back("-4-");
    423     EXPECT_EQ(b, Optional<Logger>().value_or(b));
    424     log->push_back("-5-");
    425   }
    426   EXPECT_EQ(
    427       V("0:17. explicit constructor", "1:42. explicit constructor",
    428         "2:17. copy constructor (from 0:17)", "3:3. default constructor", "-1-",
    429         "4:42. explicit constructor", "operator== 0:17, 2:17",
    430         "4:42. destructor", "-2-", "5:42. explicit constructor",
    431         "operator== 1:42, 5:42", "5:42. destructor", "-3-",
    432         "6:17. explicit constructor", "7:17. move constructor (from 6:17)",
    433         "operator== 0:17, 7:17", "7:17. destructor", "6:17. destructor", "-4-",
    434         "8:8. default constructor", "operator== 1:42, 1:42", "8:8. destructor",
    435         "-5-", "3:3. destructor", "2:17. destructor", "1:42. destructor",
    436         "0:17. destructor"),
    437       *log);
    438 }
    439 
    440 TEST(OptionalTest, TestEquality) {
    441   auto log = Logger::Setup();
    442   {
    443     Logger a(17), b(42);
    444     Optional<Logger> ma1(a), ma2(a), mb(b), me1, me2;
    445     log->push_back("---");
    446     EXPECT_EQ(ma1, ma1);
    447     EXPECT_EQ(ma1, ma2);
    448     EXPECT_NE(ma1, mb);
    449     EXPECT_NE(ma1, me1);
    450     EXPECT_EQ(me1, me1);
    451     EXPECT_EQ(me1, me2);
    452     log->push_back("---");
    453   }
    454   EXPECT_EQ(V("0:17. explicit constructor", "1:42. explicit constructor",
    455               "2:17. copy constructor (from 0:17)",
    456               "3:17. copy constructor (from 0:17)",
    457               "4:42. copy constructor (from 1:42)", "5:5. default constructor",
    458               "6:6. default constructor", "---", "operator== 2:17, 2:17",
    459               "operator== 2:17, 3:17", "operator!= 2:17, 4:42", "---",
    460               "6:6. destructor", "5:5. destructor", "4:42. destructor",
    461               "3:17. destructor", "2:17. destructor", "1:42. destructor",
    462               "0:17. destructor"),
    463             *log);
    464 }
    465 
    466 TEST(OptionalTest, TestSwap) {
    467   auto log = Logger::Setup();
    468   {
    469     Logger a(17), b(42);
    470     Optional<Logger> x1(a), x2(b), y1(a), y2, z1, z2;
    471     log->push_back("---");
    472     swap(x1, x2);  // Swap full <-> full.
    473     swap(y1, y2);  // Swap full <-> empty.
    474     swap(z1, z2);  // Swap empty <-> empty.
    475     log->push_back("---");
    476   }
    477   EXPECT_EQ(V("0:17. explicit constructor", "1:42. explicit constructor",
    478               "2:17. copy constructor (from 0:17)",
    479               "3:42. copy constructor (from 1:42)",
    480               "4:17. copy constructor (from 0:17)", "5:5. default constructor",
    481               "6:6. default constructor", "7:7. default constructor", "---",
    482               "swap 2:42, 3:17", "swap 4:5, 5:17", "swap 6:7, 7:6", "---",
    483               "7:6. destructor", "6:7. destructor", "5:17. destructor",
    484               "4:5. destructor", "3:17. destructor", "2:42. destructor",
    485               "1:42. destructor", "0:17. destructor"),
    486             *log);
    487 }
    488 
    489 }  // namespace rtc
    490