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
19namespace rtc {
20
21namespace {
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).
29class 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
98std::vector<std::string>* Logger::log_ = nullptr;
99int Logger::next_id_ = 0;
100
101// Append all the other args to the vector pointed to by the first arg.
102template <typename T>
103void VectorAppend(std::vector<T>* v) {}
104template <typename T, typename... Ts>
105void 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.
112template <typename... Ts>
113std::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
121TEST(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
130TEST(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
143TEST(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
160TEST(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
173TEST(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
191TEST(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
203TEST(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
220TEST(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
236TEST(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
254TEST(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
270TEST(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
288TEST(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
300TEST(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
317TEST(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
333TEST(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
351TEST(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
367TEST(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
385TEST(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
410TEST(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
440TEST(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
466TEST(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