osrm-backend/test/t/variant.cpp
Siarhei Fedartsou 4138954338 Squashed 'third_party/variant/' changes from 5aab5df0d..a2a485834
a2a485834 Update CHANGELOG
82f95612e Merge pull request #180 from mapbox/lightmare-move-out
c0e7ac6fd Merge pull request #181 from lightmare/revive-result-type
d13e61784 Revert "visitor - revive using explicit return type when provided"
0ebf09dea revive using visitor::result_type when available
b1076bbee visitor - revive using explicit return type when provided
2e3947578 properly forward through variant::visit
b09c7e121 travis: force compiling all tests
0ce49d837 add test case for issue #180 discovered by @artemp
8fc03c4d9 Remove clang 3.7 and gcc47 builds
f6e57e9c2 Merge branch 'move-out' of https://github.com/lightmare/variant into lightmare-move-out
94c8ccf54 fix expected compilation error messages
6d21f7704 perfect forwarding in apply_visitor
d960916fc implement match on rvalue
8b9eeb238 test matching unwrapped rvalue with lambda expression
77a24b9c0 Merge remote-tracking branch 'upstream/move-out' into move-out
4ce01e1c2 clang - self-assignment is a compile time error
c94634bbd Merge pull request #172 from mapbox/self-assignment
3dcac646f updated move assignment as suggested in https://github.com/mapbox/variant/pull/172#discussion_r328043024
b36c78e12 Just use `assert(this!=&other)` in move assignment operator (https://stackoverflow.com/questions/9322174/move-assignment-operator-and-if-this-rhs)
767bc18f3 Improve self-assignment/move checks to have one return path.
94fc9377e Revert "disable -Wself-assign-overloaded (-Werror) in self-assignment test"
da2b171b7 Revert "don't fail old compilers"
7918a4847 don't fail old compilers
ad85832b8 disable -Wself-assign-overloaded (-Werror) in self-assignment test
4da455725 add self-assignment checks in copy and move assignment operator= (ref #164)
cb02ad487 update CHANGELOG for variant v1.1.6 release [skip ci]
a4f87dc69 fix version number
ff14f222a update CHANGELOG
0305fdb2a Merge pull request #171 from mapbox/jrex-mute-clang-analyzer
2fef61f08 Moved to in-class initialization
52df2765e update CHANGELOG in preparation for v1.1.6 release
63854e5c9 Add explicit initialization of data to mute clang static analyzer warnings in Xcode (10.2).
0f734f01e Merge pull request #167 from mapbox/clang++4
5a5ecca5b Run ASAN builda in isolated VM via `sudo : required`
c1a14e7d9 update mason + update clang++ to 4.0.1
fe0a0666f update mason
11a36a9f1 steady .. downgrade clang++ to 4.0.0
f31bcfb4b try fixing travis via upgrading clang++ from 3.9.1 -> 4.0.1
502e32b8b fix Makefile
a64062576 use `ls -lah` as `du -h --apparent-size` is not universally supported.
ef3856c85 report actual file size not allocated size.
256ddd555 Merge pull request #160 from mlogan/master
9c81bef8c Fix the noexcept specifications for move assignment and conversion.
5eee328d6 Merge pull request #165 from nick70/master
0888a8e92 Fix README.md issues
859a8c933 Merge pull request #163 from MaxRis/master
215d64585 Removes deprecated static_visitor to avoid msvc C4996 compiler warning
237f83cad Merge pull request #162 from mapbox/variant_alternative
835ebc193 add `variant_size` helper
30560e19e fix preprocessor logic
8b1de3147 add compile index in range check for __type_pack_element branch.
ae1931413 add optimized 'variant_alternative' implementation usinh built-in `__type_pack_element` when available (clang++)
3ffef950b add `variant_alternative_t`
3449d00cf alternative implementation of `variant_alternative`
4b98c485c add lost test check + remove stderr
43357808c add intial `variant_alternative` implementation (#161 http://en.cppreference.com/w/cpp/utility/variant/variant_alternative)
ba3085a5e use full sha1
75bb549d2 update CHANGELOG (git log <tag1>...<tag2> --pretty=format:'* %s [view commit](http://github.com/mapbox/variant/commit/%H)' --reverse)
6497bce68 add <sha1> to CHANGELOG entries.
555436f71 add CHANGELOG.md skeleton
b78b51548 Merge pull request #154 from ricardocosme/forwarding_reference_make_visitor
f0b50062b Add copy assignment and move assignment operators.
9f991da78 Use forwarding reference in make_visitor and visitor
266f68d9f Merge pull request #153 from ricardocosme/boost-build
04a6797a6 - Add auxiliar rule exe-test.
bd0a2d559 - Use of the module 'os' to get BOOST_DIR. - Add macro SINGLE_THREADED to single threading mode. - Define single threading mode as default. - Add lambda_overload_test and hashable_test.
561a09dd0 - Remove the use of boost libraries. - Add default build.
b2471ffc7 - Add a project mapbox_variant. - Use of the 'os' module to capture CXX_STD. - Common configs moved to project. - Built targets moved to 'out' directory.
624720759 add test for ref #147 + https://github.com/mapbox/variant/pull/147
e01b7bf33 Merge branch 'BlueSolei-master'
195367cfc Merge branch 'master' of https://github.com/BlueSolei/variant into BlueSolei-master
ea106db54 recursive_wrapper test - avoid constructing new functor in recursive calls, call itself via `this` pointer.
7a541ba10 recursive_wrapper fail to compile when used with 2 classes which are base and derived #146
291121f6a Merge pull request #144 from narizhny/Casts
51fccd755 Add static_variant_cast, dynamic_variant_cast
550ac2f15 Merge pull request #143 from tomhughes/catch
a064940e2 REQUIRE_THROWS etc take an expression not a block
f9c265d7e Update bundled Catch to v1.9.0
5778eede1 Fixes example: rvalue variant matching
cdb9faf0f Simplifies result_of_* and let them handle rvalue refs
c5dac859a Failing Test Case: std::move-ing out of variant
916139a2e Merge pull request #141 from mapbox/match-otherwise
3d807d316 Merge pull request #138 from mapbox/sizeof
9ac8978f5 Adds a test for polymorphic lambdas in match, resolves #140
c839c666c add missing <limits>
35487cd39 Make `type_index_t` configurable at compile time via `MAPBOX_VARIANT_MINIMIZE_SIZE` and `MAPBOX_VARIANT_OPTIMIZE_FOR_SPEED`. Default is `unsigned int`. (ref #138)
3f6fd131e Add compile time check to disallow array types as alternatives.
fa8e124a2 Ensure internal index type is capable of holding all alternatives (ref #138)
05ee9aca1 use `mapbox::util::type_index_t` (#19)
9eec1fd48 make type used for `type_index` configurable via `type_index_t` typdef + use `unsigned int` by default. This addresses `sizeof` discrepancies between boost/std/mapbox variants (ref #19)
d2588a8f1 Trivial missing comma in README example code
05b7612aa Merge pull request #135 from mapbox/llvm-3.9.1
61f8acea1 upgrade mason
f5fb4661e upgrade to llvm 3.9.1
5baa948fa fix gyp build
4923eb527 osx: test that will support both latest (10.12) and oldest with c++11 support: 10.7
18a8055fe Merge pull request #134 from lightmare/warnings
5141d8d21 remove useless and/or dubious compiler flags
a9707c3de Merge pull request #133 from mapbox/Werror
a80beaafc disable -Wparentheses for older gcc
c8ec829ff drop -Wstack-protector which gives unhelpful warnings
7b409402c upgrade libstdc++ for coverage build
b43398619 Add -pthread
904dcaee6 limit some flags to clang++
1023f2d9a try without pthreads
886377de0 fortification flags + -pthreads for linux where needed
cf9a53499 build in both release and debug on travis
539d71274 fix conversion warnings
253047f53 enable -Werror, suppress warnings from non variant headers using isystem
18919174d Merge pull request #132 from lightmare/avoid-tuple-instantiation
4febf973c avoid expensive instantiation of tuple constructor in noexcept
6317a0b74 re-enable older compilers, trim excess
4fe5ced5d more sanitizer options
d1bb6e546 -fsanitize=cfi and -fsanitize=safe-stack
20d693ed9 fix LDFLAGS
9b2de4546 test with clang++ sanitizers and flto
702826365 disable clang++ 3.9, will work on getting working in a branch
e07a533a8 fix clang++ PATH
84eeb54c9 test clang++ via mason
a760cea8d upgrade mason
b9c58d631 upgrade boost to 1.62.0
c81b475b4 makefile improvements
ce2eea644 travis: fix addons
efa75df27 test with clang 3.9 and g++-6
cb5635ba2 add package.json for publishing to npm
02bd1ac4c Merge pull request #129 from daniel-j-h/docs
ed84def12 Merge pull request #128 from daniel-j-h/match
3c17c37ae Merge pull request #126 from daniel-j-h/hashable
d0266436b Adds Documentation for Readme, resolves #98
720c23736 Implements Pattern Matching for Sum Types via `.match` Member Function.
97d0379f0 Makes variant<Ts...> hashable iff Ts... are hashable, closes #125
9a115c5eb Merge branch 'daniel-j-h-lambda-visitor'
4d462f27b Adds C++14 SFINAE Test
2275a6197 Removes ::type Usage
d09188640 Provides Convenient Lambda Overload Visitor Interface, resolves #113.
a5a79a594 Fix #122 by adding an extra compile check in universal ctor (via @lightmare) + test case
9b46167f5 nicer stderr
84a426a31 Merge pull request #120 from mapbox/types
173a74579 add `struct adapted_variant_tag;`
e5818212a expose `using types = std::tuple<Types...>;` - useful for adapting variant to `boost::spirit` (QI,Karma,X3)
aaddee927 Update README
8e2f69641 Merge pull request #116 from lightmare/disjunction
2c7ddecdb use C++17 disjunction for no-references and one-convertible tests
388376ac9 Merge pull request #114 from mapbox/strict-conversions
075d9636f comment out code
8be6a2aa8 update tests
71ac8fdf9 Re-implement type matching logic to reject ambigious conversions
c511b2f34 add test for b3a002d185afac295486e2ebd6b84c78a2267ba0 (ref #112)
b3a002d18 fix value_traits to be able to match T, T& and T const& to the direct type stored in variant (ref #112)
b5728ad76 update .mason pkgs
eedafd31f use local HAS_EXCEPTIONS #define (__EXCEPTIONS is g++/clang specific macro)
372d7c88f c++ apply formatting
20e44accb Merge pull request #110 from mapbox/110-get_unchecked
37acc5a7c uncomment tests ref #82
adf0e02bc variant - yield return type of mapbox::util::get<T> automatically and make interface consistent (addresses #82)
bb8c2d203 Merge branch '111-which-constexpr'
dca3d967c Merge branch 'master' into 111-which-constexpr
74ce146d9 add static which<T>() function to get a contained types' which value
48d60445c remove unused internal metafunctions
434dab048 Add get_unchecked<T>() to enable use with exceptions disabled
2f8a4a381 Merge pull request #109 from mapbox/darwin-build-flags
33e27ec4c Update README.md
55579f03f Fix building with GCC (g++-5.2.0) on OS X (Darwin) (ref #108)
8bdad6b6d Update README.md
7f7470fee Jamroot - add missing include directory ./test/include for auto_cpu_timer.hpp
4368d7529 remove expected error string - current implementation emits compiler specific error message e.g
c6ae1ea0a `is<T>()` - add specialisation for recursive_wrapper<T> + update tests (ref #102)
04dc3a46b Install boost with mason; eliminate boost::timer dependency
9b2fc858c Remove Xcode 6 from CI matrix
1bc46e525 Merge pull request #101 from mapbox/include
390229a59 fix compilation
bfe0f19dd update remaining `<variant.hpp>` to `<mapbox/variant.hpp>`
343831611 ammend include dir
a606e9024 fix typo
9bd902536 Merge branch 'master' into include
7e4a01189 Add include directory
13c631a62 Update README.md
f00b24bf6 move headers into include/mapbox folder - closes #99
35ca16c74 issue warning `-Wweak-vtables` so this issue is not forgotten (https://github.com/mapbox/variant/issues/95)
82bb901b6 run coverage with clang 3.5 - fix clang 3.8 build
5f6ed7149 remove invalid option for llvm-cov
f034d5571 fix clang 3.8 compile, try 3.9
b0ee4729b fix coverage to avoid warning: unit.gcno:version '402*', prefer '406*'
3f025adbf remove erroneous `;` ref #96

git-subtree-dir: third_party/variant
git-subtree-split: a2a4858345423a760eca300ec42acad1ad123aa3
2024-05-24 18:17:51 +02:00

552 lines
18 KiB
C++

#include "catch.hpp"
#include <mapbox/variant.hpp>
#include <mapbox/variant_io.hpp>
#include <algorithm>
#include <cstdint>
#include <functional>
#include <iterator>
#include <limits>
#include <memory>
#include <ostream>
#include <sstream>
#include <string>
// Hack to make nullptr work with Catch
namespace std {
template <class C, class T>
std::basic_ostream<C, T>& operator<<(std::basic_ostream<C, T>& os, std::nullptr_t)
{
return os << (void*)nullptr;
}
}
TEST_CASE("variant can be moved into vector", "[variant]")
{
using variant_type = mapbox::util::variant<bool, std::string>;
variant_type v(std::string("test"));
std::vector<variant_type> vec;
vec.emplace_back(std::move(v));
REQUIRE(v.get<std::string>() != std::string("test"));
REQUIRE(vec.at(0).get<std::string>() == std::string("test"));
}
TEST_CASE("variant should support built-in types", "[variant]")
{
SECTION("bool")
{
mapbox::util::variant<bool> v(true);
REQUIRE(v.valid());
REQUIRE(v.is<bool>());
REQUIRE(v.which() == 0);
REQUIRE(v.get<bool>() == true);
v.set<bool>(false);
REQUIRE(v.get<bool>() == false);
v = true;
REQUIRE(v == mapbox::util::variant<bool>(true));
}
SECTION("nullptr")
{
using value_type = std::nullptr_t;
mapbox::util::variant<value_type> v(nullptr);
REQUIRE(v.valid());
REQUIRE(v.is<value_type>());
REQUIRE(v.which() == 0);
REQUIRE(v.get<value_type>() == nullptr);
REQUIRE(v == mapbox::util::variant<value_type>(nullptr));
}
SECTION("unique_ptr")
{
using value_type = std::unique_ptr<std::string>;
mapbox::util::variant<value_type> v(value_type(new std::string("hello")));
REQUIRE(v.valid());
REQUIRE(v.is<value_type>());
REQUIRE(v.which() == 0);
REQUIRE(*v.get<value_type>().get() == *value_type(new std::string("hello")).get());
REQUIRE(*v.get<value_type>() == "hello");
}
SECTION("string")
{
using value_type = std::string;
mapbox::util::variant<value_type> v(value_type("hello"));
REQUIRE(v.valid());
REQUIRE(v.is<value_type>());
REQUIRE(v.which() == 0);
REQUIRE(v.get<value_type>() == value_type("hello"));
v.set<value_type>(value_type("there"));
REQUIRE(v.get<value_type>() == value_type("there"));
v = value_type("variant");
REQUIRE(v == mapbox::util::variant<value_type>(value_type("variant")));
}
SECTION("size_t")
{
using value_type = std::size_t;
mapbox::util::variant<value_type> v(std::numeric_limits<value_type>::max());
REQUIRE(v.valid());
REQUIRE(v.is<value_type>());
REQUIRE(v.which() == 0);
REQUIRE(v.get<value_type>() == std::numeric_limits<value_type>::max());
v.set<value_type>(value_type(0));
REQUIRE(v.get<value_type>() == value_type(0));
v = value_type(1);
REQUIRE(v == mapbox::util::variant<value_type>(value_type(1)));
}
SECTION("int8_t")
{
using value_type = std::int8_t;
mapbox::util::variant<value_type> v(std::numeric_limits<value_type>::max());
REQUIRE(v.valid());
REQUIRE(v.is<value_type>());
REQUIRE(v.which() == 0);
REQUIRE(v.get<value_type>() == std::numeric_limits<value_type>::max());
v.set<value_type>(0);
REQUIRE(v.get<value_type>() == value_type(0));
v = value_type(1);
REQUIRE(v == mapbox::util::variant<value_type>(value_type(1)));
}
SECTION("int16_t")
{
using value_type = std::int16_t;
mapbox::util::variant<value_type> v(std::numeric_limits<value_type>::max());
REQUIRE(v.valid());
REQUIRE(v.is<value_type>());
REQUIRE(v.which() == 0);
REQUIRE(v.get<value_type>() == std::numeric_limits<value_type>::max());
v.set<value_type>(0);
REQUIRE(v.get<value_type>() == value_type(0));
v = value_type(1);
REQUIRE(v == mapbox::util::variant<value_type>(value_type(1)));
}
SECTION("int32_t")
{
using value_type = std::int32_t;
mapbox::util::variant<value_type> v(std::numeric_limits<value_type>::max());
REQUIRE(v.valid());
REQUIRE(v.is<value_type>());
REQUIRE(v.which() == 0);
REQUIRE(v.get<value_type>() == std::numeric_limits<value_type>::max());
v.set<value_type>(0);
REQUIRE(v.get<value_type>() == value_type(0));
v = value_type(1);
REQUIRE(v == mapbox::util::variant<value_type>(value_type(1)));
}
SECTION("int64_t")
{
using value_type = std::int64_t;
mapbox::util::variant<value_type> v(std::numeric_limits<value_type>::max());
REQUIRE(v.valid());
REQUIRE(v.is<value_type>());
REQUIRE(v.which() == 0);
REQUIRE(v.get<value_type>() == std::numeric_limits<value_type>::max());
v.set<value_type>(0);
REQUIRE(v.get<value_type>() == value_type(0));
v = value_type(1);
REQUIRE(v == mapbox::util::variant<value_type>(value_type(1)));
}
}
struct MissionInteger
{
using value_type = uint64_t;
value_type val_;
public:
MissionInteger(uint64_t val) : val_(val) {}
bool operator==(MissionInteger const& rhs) const
{
return (val_ == rhs.get());
}
uint64_t get() const
{
return val_;
}
};
std::ostream& operator<<(std::ostream& os, MissionInteger const& rhs)
{
os << rhs.get();
return os;
}
TEST_CASE("variant should support custom types", "[variant]")
{
// http://www.missionintegers.com/integer/34838300
mapbox::util::variant<MissionInteger> v(MissionInteger(34838300));
REQUIRE(v.valid());
REQUIRE(v.is<MissionInteger>());
REQUIRE(v.which() == 0);
REQUIRE(v.get<MissionInteger>() == MissionInteger(34838300));
REQUIRE(v.get<MissionInteger>().get() == MissionInteger::value_type(34838300));
// TODO: should both of the set usages below compile?
v.set<MissionInteger>(MissionInteger::value_type(0));
v.set<MissionInteger>(MissionInteger(0));
REQUIRE(v.get<MissionInteger>().get() == MissionInteger::value_type(0));
v = MissionInteger(1);
REQUIRE(v == mapbox::util::variant<MissionInteger>(MissionInteger(1)));
}
TEST_CASE("variant::which() returns zero based index of stored type", "[variant]")
{
using variant_type = mapbox::util::variant<bool, std::string, std::uint64_t, std::int64_t, double, float>;
// which() returns index in forward order
REQUIRE(0 == variant_type(true).which());
REQUIRE(1 == variant_type(std::string("test")).which());
REQUIRE(2 == variant_type(std::uint64_t(0)).which());
REQUIRE(3 == variant_type(std::int64_t(0)).which());
REQUIRE(4 == variant_type(double(0.0)).which());
REQUIRE(5 == variant_type(float(0.0)).which());
}
TEST_CASE("get with wrong type (here: double) should throw", "[variant]")
{
using variant_type = mapbox::util::variant<int, double>;
variant_type var = 5;
REQUIRE(var.is<int>());
REQUIRE_FALSE(var.is<double>());
REQUIRE(var.get<int>() == 5);
REQUIRE_THROWS_AS(var.get<double>(),
mapbox::util::bad_variant_access&);
}
TEST_CASE("get with wrong type (here: int) should throw", "[variant]")
{
using variant_type = mapbox::util::variant<int, double>;
variant_type var = 5.0;
REQUIRE(var.is<double>());
REQUIRE_FALSE(var.is<int>());
REQUIRE(var.get<double>() == 5.0);
REQUIRE(mapbox::util::get<double>(var) == 5.0);
REQUIRE_THROWS_AS(var.get<int>(),
mapbox::util::bad_variant_access&);
REQUIRE_THROWS_AS(mapbox::util::get<int>(var),
mapbox::util::bad_variant_access&);
}
TEST_CASE("get on const varint with wrong type (here: int) should throw", "[variant]")
{
using variant_type = mapbox::util::variant<int, double>;
const variant_type var = 5.0;
REQUIRE(var.is<double>());
REQUIRE_FALSE(var.is<int>());
REQUIRE(var.get<double>() == 5.0);
REQUIRE(mapbox::util::get<double>(var) == 5.0);
REQUIRE_THROWS_AS(var.get<int>(),
mapbox::util::bad_variant_access&);
REQUIRE_THROWS_AS(mapbox::util::get<int>(var),
mapbox::util::bad_variant_access&);
}
TEST_CASE("get with any type should throw if not initialized", "[variant]")
{
mapbox::util::variant<int, double> var{mapbox::util::no_init()};
REQUIRE_THROWS_AS(var.get<int>(),
mapbox::util::bad_variant_access&);
REQUIRE_THROWS_AS(var.get<double>(),
mapbox::util::bad_variant_access&);
}
TEST_CASE("no_init variant can be copied and moved from", "[variant]")
{
using variant_type = mapbox::util::variant<int, double>;
variant_type v1{mapbox::util::no_init()};
variant_type v2{42};
variant_type v3{23};
REQUIRE(v2.get<int>() == 42);
v2 = v1;
REQUIRE_THROWS_AS(v2.get<int>(),
mapbox::util::bad_variant_access&);
REQUIRE(v3.get<int>() == 23);
v3 = std::move(v1);
REQUIRE_THROWS_AS(v3.get<int>(),
mapbox::util::bad_variant_access&);
}
TEST_CASE("no_init variant can be copied and moved to", "[variant]")
{
using variant_type = mapbox::util::variant<int, double>;
variant_type v1{42};
variant_type v2{mapbox::util::no_init()};
variant_type v3{mapbox::util::no_init()};
REQUIRE_THROWS_AS(v2.get<int>(),
mapbox::util::bad_variant_access&);
REQUIRE(v1.get<int>() == 42);
v2 = v1;
REQUIRE(v2.get<int>() == 42);
REQUIRE(v1.get<int>() == 42);
REQUIRE_THROWS_AS(v3.get<int>(),
mapbox::util::bad_variant_access&);
v3 = std::move(v1);
REQUIRE(v3.get<int>() == 42);
}
TEST_CASE("implicit conversion", "[variant][implicit conversion]")
{
using variant_type = mapbox::util::variant<int>;
variant_type var(5.0); // converted to int
REQUIRE(var.get<int>() == 5);
var = 6.0; // works for operator=, too
REQUIRE(var.get<int>() == 6);
}
TEST_CASE("implicit conversion to first type in variant type list", "[variant][implicit conversion]")
{
using variant_type = mapbox::util::variant<long, char>;
variant_type var = 5l; // converted to long
REQUIRE(var.get<long>() == 5);
REQUIRE_THROWS_AS(var.get<char>(),
mapbox::util::bad_variant_access&);
}
TEST_CASE("implicit conversion to unsigned char", "[variant][implicit conversion]")
{
using variant_type = mapbox::util::variant<unsigned char>;
variant_type var = 100.0;
CHECK(var.get<unsigned char>() == static_cast<unsigned char>(100.0));
CHECK(var.get<unsigned char>() == static_cast<unsigned char>(static_cast<unsigned int>(100.0)));
}
struct dummy
{
};
TEST_CASE("implicit conversion to a suitable type", "[variant][implicit conversion]")
{
using mapbox::util::variant;
CHECK_NOTHROW((variant<dummy, float, std::string>(123)).get<float>());
CHECK_NOTHROW((variant<dummy, float, std::string>("foo")).get<std::string>());
}
TEST_CASE("value_traits for non-convertible type", "[variant::detail]")
{
namespace detail = mapbox::util::detail;
using target_type = detail::value_traits<dummy, int>::target_type;
CHECK((std::is_same<target_type, void>::value) == true);
}
TEST_CASE("Type indexing should work with variants with duplicated types", "[variant::detail]")
{
// Index is in reverse order
REQUIRE((mapbox::util::detail::value_traits<bool, bool, int, double, std::string>::index == 3));
REQUIRE((mapbox::util::detail::value_traits<bool, bool, int, double, int>::index == 3));
REQUIRE((mapbox::util::detail::value_traits<int, bool, int, double, std::string>::index == 2));
REQUIRE((mapbox::util::detail::value_traits<int, bool, int, double, int>::index == 2));
REQUIRE((mapbox::util::detail::value_traits<double, bool, int, double, std::string>::index == 1));
REQUIRE((mapbox::util::detail::value_traits<bool, bool, int, bool, std::string>::index == 3));
REQUIRE((mapbox::util::detail::value_traits<std::string, bool, int, double, std::string>::index == 0));
REQUIRE((mapbox::util::detail::value_traits<dummy, bool, int, double, std::string>::index == mapbox::util::detail::invalid_value));
REQUIRE((mapbox::util::detail::value_traits<std::vector<int>, bool, int, double, std::string>::index == mapbox::util::detail::invalid_value));
}
TEST_CASE("variant default constructor", "[variant][default constructor]")
{
// By default variant is initialised with (default constructed) first type in template parameters pack
// As a result first type in Types... must be default constructable
// NOTE: index in reverse order -> index = N - 1
using variant_type = mapbox::util::variant<int, double, std::string>;
REQUIRE(variant_type{}.which() == 0);
REQUIRE(variant_type{}.valid());
REQUIRE_FALSE(variant_type{mapbox::util::no_init()}.valid());
}
TEST_CASE("variant printer", "[visitor][unary visitor][printer]")
{
using variant_type = mapbox::util::variant<int, double, std::string>;
std::vector<variant_type> var = {2.1, 123, "foo", 456};
std::stringstream out;
std::copy(var.begin(), var.end(), std::ostream_iterator<variant_type>(out, ","));
out << var[2];
REQUIRE(out.str() == "2.1,123,foo,456,foo");
}
TEST_CASE("swapping variants should do the right thing", "[variant]")
{
using variant_type = mapbox::util::variant<int, double, std::string>;
variant_type a = 7;
variant_type b = 3;
variant_type c = 3.141;
variant_type d = "foo";
variant_type e = "a long string that is longer than small string optimization";
using std::swap;
swap(a, b);
REQUIRE(a.get<int>() == 3);
REQUIRE(a.which() == 0);
REQUIRE(b.get<int>() == 7);
REQUIRE(b.which() == 0);
swap(b, c);
REQUIRE(b.get<double>() == Approx(3.141));
REQUIRE(b.which() == 1);
REQUIRE(c.get<int>() == 7);
REQUIRE(c.which() == 0);
swap(b, d);
REQUIRE(b.get<std::string>() == "foo");
REQUIRE(b.which() == 2);
REQUIRE(d.get<double>() == Approx(3.141));
REQUIRE(d.which() == 1);
swap(b, e);
REQUIRE(b.get<std::string>() == "a long string that is longer than small string optimization");
REQUIRE(b.which() == 2);
REQUIRE(e.get<std::string>() == "foo");
REQUIRE(e.which() == 2);
}
TEST_CASE("variant should work with equality operators")
{
using variant_type = mapbox::util::variant<int, std::string>;
variant_type a{1};
variant_type b{1};
variant_type c{2};
variant_type s{"foo"};
REQUIRE(a == a);
REQUIRE(a == b);
REQUIRE_FALSE(a == c);
REQUIRE_FALSE(a == s);
REQUIRE_FALSE(c == s);
REQUIRE_FALSE(a != a);
REQUIRE_FALSE(a != b);
REQUIRE(a != c);
REQUIRE(a != s);
REQUIRE(c != s);
}
TEST_CASE("variant should work with comparison operators")
{
using variant_type = mapbox::util::variant<int, std::string>;
variant_type a{1};
variant_type b{1};
variant_type c{2};
variant_type s{"foo"};
variant_type t{"bar"};
REQUIRE_FALSE(a < a);
REQUIRE_FALSE(a < b);
REQUIRE(a < c);
REQUIRE(a < s);
REQUIRE(c < s);
REQUIRE(t < s);
REQUIRE_FALSE(a > a);
REQUIRE_FALSE(a > b);
REQUIRE_FALSE(a > c);
REQUIRE_FALSE(a > s);
REQUIRE_FALSE(c > s);
REQUIRE_FALSE(t > s);
REQUIRE(a <= a);
REQUIRE(a <= b);
REQUIRE(a <= c);
REQUIRE(a <= s);
REQUIRE(c <= s);
REQUIRE(t <= s);
REQUIRE(a >= a);
REQUIRE(a >= b);
REQUIRE_FALSE(a >= c);
REQUIRE_FALSE(a >= s);
REQUIRE_FALSE(c >= s);
REQUIRE_FALSE(t >= s);
}
TEST_CASE("storing reference wrappers works")
{
using variant_type = mapbox::util::variant<std::reference_wrapper<int>, std::reference_wrapper<double>>;
int a = 1;
variant_type v{std::ref(a)};
REQUIRE(v.get<int>() == 1);
REQUIRE(mapbox::util::get<int>(v) == 1);
REQUIRE_THROWS_AS(v.get<double>(),
mapbox::util::bad_variant_access&);
REQUIRE_THROWS_AS(mapbox::util::get<double>(v),
mapbox::util::bad_variant_access&);
a = 2;
REQUIRE(v.get<int>() == 2);
v.get<int>() = 3;
REQUIRE(a == 3);
double b = 3.141;
v = std::ref(b);
REQUIRE(v.get<double>() == Approx(3.141));
REQUIRE(mapbox::util::get<double>(v) == Approx(3.141));
REQUIRE_THROWS_AS(v.get<int>(),
mapbox::util::bad_variant_access&);
REQUIRE_THROWS_AS(mapbox::util::get<int>(v),
mapbox::util::bad_variant_access&);
b = 2.718;
REQUIRE(v.get<double>() == Approx(2.718));
a = 3;
REQUIRE(v.get<double>() == Approx(2.718));
v.get<double>() = 4.1;
REQUIRE(b == Approx(4.1));
REQUIRE_THROWS_AS(v.get<int>() = 4,
mapbox::util::bad_variant_access&);
}
TEST_CASE("storing reference wrappers to consts works")
{
using variant_type = mapbox::util::variant<std::reference_wrapper<int const>, std::reference_wrapper<double const>>;
int a = 1;
variant_type v{std::cref(a)};
REQUIRE(v.get<int const>() == 1);
REQUIRE(v.get<int>() == 1);
REQUIRE(mapbox::util::get<int const>(v) == 1);
REQUIRE(mapbox::util::get<int>(v) == 1);
REQUIRE_THROWS_AS(v.get<double const>(),
mapbox::util::bad_variant_access&);
REQUIRE_THROWS_AS(mapbox::util::get<double const>(v),
mapbox::util::bad_variant_access&);
double b = 3.141;
v = std::cref(b);
REQUIRE(v.get<double const>() == Approx(3.141));
REQUIRE(mapbox::util::get<double const>(v) == Approx(3.141));
REQUIRE_THROWS_AS(v.get<int const>(),
mapbox::util::bad_variant_access&);
REQUIRE_THROWS_AS(mapbox::util::get<int const>(v),
mapbox::util::bad_variant_access&);
}
TEST_CASE("recursive wrapper")
{
using variant_type = mapbox::util::variant<mapbox::util::recursive_wrapper<int>>;
variant_type v(1);
REQUIRE(v.is<int>());
REQUIRE(v.get<int>() == 1);
}
TEST_CASE("variant : direct_type helper should match T, references (T&) and const references (T const&) to the original type T)")
{
using value = mapbox::util::variant<bool, std::uint64_t>;
std::uint64_t u(1234);
REQUIRE(value(u).is<std::uint64_t>()); // matches T
std::uint64_t& ur(u);
REQUIRE(value(ur).is<std::uint64_t>()); // matches T&
std::uint64_t const& ucr(u);
REQUIRE(value(ucr).is<std::uint64_t>()); // matches T const&
}