1 #include <catch2/catch.hpp> 2 3 #include "util/Util.h" 4 #include "util/Logger.h" 5 #include "util/AppleOrange.h" 6 #include "util/ThrowOnCopy.h" 7 8 #include "rapidcheck/detail/Variant.h" 9 10 using namespace rc; 11 using namespace rc::test; 12 using namespace rc::detail; 13 14 namespace { 15 16 template <std::size_t N> 17 struct X { X__anon05005cf40111::X18 X(const std::string &x) 19 : value(x) {} 20 21 // Put some extra junk here so that different types have different layout. 22 char extra[N]; 23 std::string value; 24 }; 25 26 template <std::size_t N> operator ==(const X<N> & x1,const X<N> & x2)27bool operator==(const X<N> &x1, const X<N> &x2) { 28 return x1.value == x2.value; 29 } 30 31 using A = X<5>; 32 using B = X<10>; 33 using C = X<15>; 34 35 using ABC = Variant<Logger, ThrowOnCopy, A, B, C>; 36 37 } // namespace 38 39 TEST_CASE("Variant") { 40 ABC va(A("A")); 41 ABC vb(B("B")); 42 ABC vc(C("C")); 43 44 SECTION("universal constructor") { 45 SECTION("rvalue") { 46 ABC v(Logger("foobar")); 47 REQUIRE(v.is<Logger>()); 48 REQUIRE(v.get<Logger>().id == "foobar"); 49 REQUIRE(v.get<Logger>().numberOf("copy") == 0); 50 } 51 52 SECTION("lvalue") { 53 Logger logger("foobar"); 54 ABC v(logger); 55 REQUIRE(v.is<Logger>()); 56 REQUIRE(v.get<Logger>().id == "foobar"); 57 REQUIRE(v.get<Logger>().numberOf("copy") == 1); 58 } 59 } 60 61 SECTION("value assignment") { 62 SECTION("from same type") { 63 SECTION("rvalue") { 64 ABC v(Logger("bar")); 65 v = Logger("foo"); 66 REQUIRE(v.is<Logger>()); 67 REQUIRE(v.get<Logger>().id == "foo"); 68 REQUIRE(v.get<Logger>().numberOf("copy") == 0); 69 REQUIRE(v.get<Logger>().numberOf("move") == 1); 70 REQUIRE(v.get<Logger>().numberOf("move assigned") == 1); 71 } 72 73 SECTION("lvalue") { 74 ABC v(Logger("bar")); 75 Logger foo("foo"); 76 v = foo; 77 REQUIRE(v.is<Logger>()); 78 REQUIRE(v.get<Logger>().id == "foo"); 79 REQUIRE(v.get<Logger>().numberOf("copy") == 1); 80 REQUIRE(v.get<Logger>().numberOf("copy assigned") == 1); 81 } 82 } 83 84 SECTION("from different type") { 85 SECTION("rvalue") { 86 ABC v(va); 87 v = Logger("foo"); 88 REQUIRE(v.is<Logger>()); 89 REQUIRE(v.get<Logger>().id == "foo"); 90 REQUIRE(v.get<Logger>().numberOf("copy") == 0); 91 REQUIRE(v.get<Logger>().numberOf("move") == 1); 92 REQUIRE(v.get<Logger>().numberOf("move constructed") == 1); 93 } 94 95 SECTION("lvalue") { 96 ABC v(va); 97 Logger foo("foo"); 98 v = foo; 99 REQUIRE(v.is<Logger>()); 100 REQUIRE(v.get<Logger>().id == "foo"); 101 REQUIRE(v.get<Logger>().numberOf("copy") == 1); 102 REQUIRE(v.get<Logger>().numberOf("copy constructed") == 1); 103 } 104 } 105 } 106 107 SECTION("copy constructor") { 108 ABC v1(Logger("foobar")); 109 ABC v2(v1); 110 REQUIRE(v2.is<Logger>()); 111 REQUIRE(v2.get<Logger>().id == "foobar"); 112 REQUIRE(v2.get<Logger>().numberOf("copy") == 1); 113 } 114 115 SECTION("move constructor") { 116 ABC v1(Logger("foobar")); 117 ABC v2(std::move(v1)); 118 REQUIRE(v2.is<Logger>()); 119 REQUIRE(v2.get<Logger>().id == "foobar"); 120 REQUIRE(v2.get<Logger>().numberOf("copy") == 0); 121 } 122 123 SECTION("copy assignment") { 124 SECTION("from same type") { 125 SECTION("assigns object") { 126 ABC v1(Logger("foo")); 127 ABC v2(Logger("bar")); 128 v2 = v1; 129 REQUIRE(v2.is<Logger>()); 130 REQUIRE(v2.get<Logger>().id == "foo"); 131 REQUIRE(v2.get<Logger>().numberOf("copy") == 1); 132 REQUIRE(v2.get<Logger>().numberOf("copy assigned") == 1); 133 } 134 135 SECTION("throwing leaves both values unchanged") { 136 ABC v1(ThrowOnCopy("foo")); 137 ABC v2(ThrowOnCopy("bar")); 138 try { 139 v1 = v2; 140 } catch (...) { 141 } 142 REQUIRE(v1.is<ThrowOnCopy>()); 143 REQUIRE(v1.get<ThrowOnCopy>().value == "foo"); 144 REQUIRE(v2.is<ThrowOnCopy>()); 145 REQUIRE(v2.get<ThrowOnCopy>().value == "bar"); 146 } 147 } 148 149 SECTION("from different type") { 150 SECTION("constructs object") { 151 ABC v1(Logger("foo")); 152 ABC v2(va); 153 v2 = v1; 154 REQUIRE(v2.is<Logger>()); 155 REQUIRE(v2.get<Logger>().id == "foo"); 156 REQUIRE(v2.get<Logger>().numberOf("copy") == 1); 157 REQUIRE(v2.get<Logger>().numberOf("copy constructed") == 1); 158 } 159 160 SECTION("self assignment leaves value unchanged") { 161 ABC v(Logger("foo")); 162 auto &ref = v; 163 v = ref; 164 REQUIRE(v.is<Logger>()); 165 REQUIRE(v.get<Logger>().id == "foo"); 166 } 167 168 SECTION("throwing leaves both values unchanged") { 169 ABC v1(A("foo")); 170 ABC v2(ThrowOnCopy("bar")); 171 try { 172 v1 = v2; 173 } catch (...) { 174 } 175 REQUIRE(v1.is<A>()); 176 REQUIRE(v1.get<A>().value == "foo"); 177 REQUIRE(v2.is<ThrowOnCopy>()); 178 REQUIRE(v2.get<ThrowOnCopy>().value == "bar"); 179 } 180 } 181 } 182 183 SECTION("move assignment") { 184 SECTION("from same type") { 185 ABC v1(Logger("foo")); 186 ABC v2(Logger("bar")); 187 v2 = std::move(v1); 188 REQUIRE(v2.is<Logger>()); 189 REQUIRE(v2.get<Logger>().id == "foo"); 190 REQUIRE(v2.get<Logger>().numberOf("copy") == 0); 191 REQUIRE(v2.get<Logger>().numberOf("move constructed") == 1); 192 REQUIRE(v2.get<Logger>().numberOf("move assigned") == 1); 193 } 194 195 SECTION("from different type") { 196 ABC v1(Logger("foo")); 197 ABC v2(va); 198 v2 = std::move(v1); 199 REQUIRE(v2.is<Logger>()); 200 REQUIRE(v2.get<Logger>().id == "foo"); 201 REQUIRE(v2.get<Logger>().numberOf("copy") == 0); 202 REQUIRE(v2.get<Logger>().numberOf("move constructed") == 2); 203 } 204 } 205 206 SECTION("is") { 207 SECTION("returns true if the value has the given type") { 208 REQUIRE(va.is<A>()); 209 REQUIRE(vb.is<B>()); 210 REQUIRE(vc.is<C>()); 211 } 212 213 SECTION("returns false if value does not have the given type") { 214 REQUIRE(!va.is<B>()); 215 REQUIRE(!va.is<C>()); 216 217 REQUIRE(!vb.is<A>()); 218 REQUIRE(!vb.is<C>()); 219 220 REQUIRE(!vc.is<A>()); 221 REQUIRE(!vc.is<B>()); 222 } 223 } 224 225 SECTION("get") { 226 SECTION("returns rvalue reference for rvalues") { 227 ABC v(Logger("foo")); 228 const auto logger = std::move(v).get<Logger>(); 229 REQUIRE(logger.numberOf("copy") == 0); 230 } 231 } 232 233 SECTION("match") { 234 A a("AAA"); 235 B b("BBB"); 236 C c("CCC"); 237 238 SECTION("returns true if the value has the given type") { 239 REQUIRE(va.match(a)); 240 REQUIRE(vb.match(b)); 241 REQUIRE(vc.match(c)); 242 } 243 244 SECTION("returns false if value does not have the given type") { 245 REQUIRE(!va.match(b)); 246 REQUIRE(!va.match(c)); 247 248 REQUIRE(!vb.match(a)); 249 REQUIRE(!vb.match(c)); 250 251 REQUIRE(!vc.match(a)); 252 REQUIRE(!vc.match(b)); 253 } 254 255 SECTION("leaves given value untouched if no match") { 256 A aa(a); 257 vb.match(aa); 258 vc.match(aa); 259 REQUIRE(a.value == aa.value); 260 261 B bb(b); 262 va.match(bb); 263 vc.match(bb); 264 REQUIRE(b.value == bb.value); 265 266 C cc(c); 267 va.match(cc); 268 vb.match(cc); 269 REQUIRE(c.value == cc.value); 270 } 271 272 SECTION("sets the value to the contained value on match") { 273 va.match(a); 274 REQUIRE(a.value == "A"); 275 vb.match(b); 276 REQUIRE(b.value == "B"); 277 vc.match(c); 278 REQUIRE(c.value == "C"); 279 } 280 } 281 282 SECTION("operator==/operator!=") { 283 SECTION("equals if contained values are equal") { 284 REQUIRE(ABC(A("a")) == ABC(A("a"))); 285 REQUIRE(ABC(B("b")) == ABC(B("b"))); 286 REQUIRE(ABC(C("c")) == ABC(C("c"))); 287 288 REQUIRE_FALSE(ABC(A("a")) != ABC(A("a"))); 289 REQUIRE_FALSE(ABC(B("b")) != ABC(B("b"))); 290 REQUIRE_FALSE(ABC(C("c")) != ABC(C("c"))); 291 } 292 293 SECTION("not equals if contained values are not equal") { 294 REQUIRE_FALSE(ABC(A("a")) == ABC(A("ax"))); 295 REQUIRE_FALSE(ABC(A("ax")) == ABC(A("a"))); 296 REQUIRE_FALSE(ABC(B("b")) == ABC(B("bx"))); 297 REQUIRE_FALSE(ABC(B("bx")) == ABC(B("b"))); 298 REQUIRE_FALSE(ABC(C("c")) == ABC(C("cx"))); 299 REQUIRE_FALSE(ABC(C("cx")) == ABC(C("c"))); 300 301 REQUIRE(ABC(A("a")) != ABC(A("ax"))); 302 REQUIRE(ABC(A("ax")) != ABC(A("a"))); 303 REQUIRE(ABC(B("b")) != ABC(B("bx"))); 304 REQUIRE(ABC(B("bx")) != ABC(B("b"))); 305 REQUIRE(ABC(C("c")) != ABC(C("cx"))); 306 REQUIRE(ABC(C("cx")) != ABC(C("c"))); 307 } 308 309 SECTION("not equals if contained values are not of same type") { 310 REQUIRE_FALSE(ABC(A("a")) == ABC(B("a"))); 311 REQUIRE_FALSE(ABC(B("a")) == ABC(A("a"))); 312 REQUIRE(ABC(A("a")) != ABC(B("a"))); 313 REQUIRE(ABC(B("a")) != ABC(A("a"))); 314 315 // Not even if types are normally equatable 316 using Orapple = Variant<Apple, Orange>; 317 REQUIRE_FALSE(Orapple(Apple("foo")) == Orapple(Orange("foo"))); 318 REQUIRE_FALSE(Orapple(Orange("foo")) == Orapple(Apple("foo"))); 319 REQUIRE(Orapple(Apple("foo")) != Orapple(Orange("foo"))); 320 REQUIRE(Orapple(Orange("foo")) != Orapple(Apple("foo"))); 321 } 322 } 323 324 SECTION("operator<<(std::ostream)") { 325 SECTION("uses the contained types implementations") { 326 Variant<std::string, int> v(std::string("foobar")); 327 std::ostringstream str; 328 str << v; 329 REQUIRE(str.str() == "foobar"); 330 331 std::ostringstream num; 332 v = 1337; 333 num << v; 334 REQUIRE(num.str() == "1337"); 335 } 336 } 337 } 338