1 #include <catch2/catch.hpp>
2 
3 #include "rapidcheck/detail/Any.h"
4 
5 #include "util/Util.h"
6 #include "util/Predictable.h"
7 
8 using namespace rc;
9 using namespace rc::detail;
10 
11 namespace {
12 
13 enum class InitType { Value, Move, Copy, Dead };
14 
operator <<(std::ostream & os,InitType itype)15 std::ostream &operator<<(std::ostream &os, InitType itype) {
16   switch (itype) {
17   case InitType::Value:
18     os << "Value";
19     break;
20   case InitType::Move:
21     os << "Moved";
22     break;
23   case InitType::Copy:
24     os << "Copied";
25     break;
26   case InitType::Dead:
27     os << "Dead";
28     break;
29   }
30 
31   return os;
32 }
33 
34 template <typename T>
35 struct InitTracker {
36   InitType itype;
37   T value;
38 
InitTracker__anon32dc71a70111::InitTracker39   InitTracker(T v)
40       : itype(InitType::Value)
41       , value(v) {}
InitTracker__anon32dc71a70111::InitTracker42   InitTracker(const InitTracker<T> &other)
43       : itype(InitType::Copy)
44       , value(other.value) {}
InitTracker__anon32dc71a70111::InitTracker45   InitTracker(InitTracker<T> &&other)
46       : itype(InitType::Move)
47       , value(std::move(other.value)) {
48     other.itype = InitType::Dead;
49   }
50 };
51 
52 template <typename T>
show(const InitTracker<T> & value,std::ostream & os)53 void show(const InitTracker<T> &value, std::ostream &os) {
54   os << "[" << value.itype << "]";
55   if (value.itype != InitType::Dead) {
56     os << ": ";
57     rc::show(value.value, os);
58   }
59 }
60 
61 using StringTracker = InitTracker<std::string>;
62 
63 } // namespace
64 
65 TEST_CASE("Any") {
66   StringTracker x("foobar");
67   REQUIRE(x.itype == InitType::Value);
68 
69   SECTION("of") {
70     SECTION("allows move") {
71       Any any = Any::of(std::move(x));
72       auto &valueRef = any.get<StringTracker>();
73       REQUIRE(valueRef.itype == InitType::Move);
74     }
75 
76     SECTION("allows copy") {
77       Any any = Any::of(x);
78       auto &valueRef = any.get<StringTracker>();
79       REQUIRE(valueRef.itype == InitType::Copy);
80     }
81   }
82 
83   SECTION("reset") {
84     SECTION("turns this into null any") {
85       Any any = Any::of("foobar");
86       any.reset();
87       REQUIRE(!any);
88     }
89   }
90 
91   SECTION("get") {
92     SECTION("returns a reference to the value") {
93       Any anystr = Any::of(std::string("foobar"));
94       REQUIRE(anystr.get<std::string>() == "foobar");
95       anystr.get<std::string>()[0] = 'b';
96       REQUIRE(anystr.get<std::string>() == "boobar");
97 
98       Any anyint = Any::of(static_cast<int>(100));
99       REQUIRE(anyint.get<int>() == 100);
100       anyint.get<int>()++;
101       REQUIRE(anyint.get<int>() == 101);
102     }
103 
104     SECTION("works as a move source") {
105       std::string str("foobar");
106       Any any = Any::of(str);
107       std::string dest(std::move(any.get<std::string>()));
108       REQUIRE(str == dest);
109     }
110   }
111 
112   SECTION("showType") {
113     SECTION("returns a pair of the typename and value as strings") {
114       std::string str("foobar");
115       Any any = Any::of(str);
116 
117       std::ostringstream ss;
118       any.showType(ss);
119 
120       REQUIRE(ss.str() == typeToString<decltype(str)>());
121     }
122 
123     SECTION("outputs nothing for null Any values") {
124       Any any;
125       std::ostringstream ss;
126       any.showType(ss);
127       REQUIRE(ss.str().empty());
128     }
129   }
130 
131   SECTION("showValue") {
132     SECTION("returns a pair of the typename and value as strings") {
133       std::string str("foobar");
134       Any any = Any::of(str);
135 
136       std::ostringstream ss;
137       any.showValue(ss);
138 
139       REQUIRE(ss.str() == toString(str));
140     }
141 
142     SECTION("outputs nothing for null Any values") {
143       Any any;
144       std::ostringstream ss;
145       any.showValue(ss);
146       REQUIRE(ss.str().empty());
147     }
148   }
149 
150   SECTION("operator bool()") {
151     SECTION("returns false for null Any") {
152       Any any;
153       REQUIRE(!any);
154     }
155 
156     SECTION("returns true for non-null Any") {
157       Any any = Any::of(1337);
158       REQUIRE(any);
159     }
160   }
161 
162   SECTION("move constructor") {
163     SECTION("if not null") {
164       std::string str("foobar");
165       Any from = Any::of(str);
166       auto addr = &from.get<std::string>();
167       Any to(std::move(from));
168 
169       SECTION("value is equal to original") {
170         REQUIRE(to.get<std::string>() == str);
171       }
172       SECTION("original is reset") { REQUIRE(!from); }
173       SECTION("addr is the same as original") {
174         REQUIRE(&to.get<std::string>() == addr);
175       }
176     }
177 
178     SECTION("if from is null, to is also null") {
179       Any from;
180       Any to(std::move(from));
181       REQUIRE(!to);
182     }
183   }
184 
185   SECTION("move assignment operator") {
186     SECTION("if not null") {
187       std::string str("foobar");
188       Any from = Any::of(str);
189       auto addr = &from.get<std::string>();
190       Any to;
191       to = std::move(from);
192 
193       SECTION("value is equal to original") {
194         REQUIRE(to.get<std::string>() == str);
195       }
196       SECTION("original is reset") { REQUIRE(!from); }
197       SECTION("addr is the same as original") {
198         REQUIRE(&to.get<std::string>() == addr);
199       }
200     }
201 
202     SECTION("if from is null, to is also null") {
203       Any from;
204       Any to;
205       to = std::move(from);
206       REQUIRE(!to);
207     }
208   }
209 }
210