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