2
0
mirror of https://github.com/boostorg/hana.git synced 2026-02-02 08:52:11 +00:00
Files
hana/test/maybe.cpp
2015-04-10 13:17:51 -04:00

555 lines
16 KiB
C++

/*
@copyright Louis Dionne 2015
Distributed under the Boost Software License, Version 1.0.
(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
*/
#include <boost/hana/maybe.hpp>
#include <boost/hana/assert.hpp>
#include <boost/hana/bool.hpp>
#include <boost/hana/config.hpp>
#include <boost/hana/functional/always.hpp>
#include <boost/hana/functional/compose.hpp>
#include <boost/hana/tuple.hpp>
#include <boost/hana/type.hpp>
#include <laws/applicative.hpp>
#include <laws/base.hpp>
#include <laws/comparable.hpp>
#include <laws/foldable.hpp>
#include <laws/functor.hpp>
#include <laws/monad.hpp>
#include <laws/monad_plus.hpp>
#include <laws/orderable.hpp>
#include <laws/searchable.hpp>
#include <laws/traversable.hpp>
#include <test/identity.hpp>
#include <type_traits>
using namespace boost::hana;
template <typename ...>
using void_t = void;
template <typename T, typename = void>
struct has_type : std::false_type { };
template <typename T>
struct has_type<T, void_t<typename T::type>>
: std::true_type
{ };
struct undefined { };
using test::ct_eq;
using test::ct_ord;
int main() {
auto ords = make<Tuple>(
nothing, just(ct_ord<0>{}), just(ct_ord<1>{}), just(ct_ord<2>{})
);
(void)ords;
auto eqs = make<Tuple>(
nothing, just(ct_eq<0>{}), just(ct_eq<1>{}), just(ct_eq<2>{})
);
(void)eqs;
auto eq_values = make<Tuple>(ct_eq<0>{}, ct_eq<2>{}, ct_eq<3>{});
(void)eq_values;
auto predicates = make<Tuple>(
equal.to(ct_eq<0>{}), equal.to(ct_eq<2>{}), equal.to(ct_eq<3>{}),
always(false_), always(true_)
);
(void)predicates;
auto nested_eqs = make<Tuple>(
nothing, just(just(ct_eq<0>{})), just(nothing), just(just(ct_eq<2>{}))
);
(void)nested_eqs;
#if BOOST_HANA_TEST_PART == 1
//////////////////////////////////////////////////////////////////////////
// Maybe interface
//////////////////////////////////////////////////////////////////////////
{
test::_injection<0> f{};
test::ct_eq<2> x{};
test::ct_eq<3> y{};
// Interaction with Type (has a nested ::type)
{
struct T;
static_assert(std::is_same<decltype(just(type<T>))::type, T>{}, "");
static_assert(!has_type<decltype(nothing)>{}, "");
}
// maybe
{
BOOST_HANA_CONSTANT_CHECK(equal(maybe(x, undefined{}, nothing), x));
BOOST_HANA_CONSTANT_CHECK(equal(maybe(undefined{}, f, just(x)), f(x)));
}
// is_nothing
{
BOOST_HANA_CONSTANT_CHECK(is_nothing(nothing));
BOOST_HANA_CONSTANT_CHECK(not_(is_nothing(just(undefined{}))));
}
// is_just
{
BOOST_HANA_CONSTANT_CHECK(is_just(just(undefined{})));
BOOST_HANA_CONSTANT_CHECK(not_(is_just(nothing)));
}
// from_just
{
BOOST_HANA_CONSTANT_CHECK(equal(from_just(just(x)), x));
{
auto lvalue = just(test::ct_eq<3>{});
test::ct_eq<3>& ref = *lvalue;
BOOST_HANA_CONSTANT_CHECK(equal(
ref,
test::ct_eq<3>{}
));
auto const const_lvalue = just(test::ct_eq<3>{});
test::ct_eq<3> const& const_ref = *const_lvalue;
BOOST_HANA_CONSTANT_CHECK(equal(
const_ref,
test::ct_eq<3>{}
));
BOOST_HANA_CONSTANT_CHECK(equal(
*just(test::ct_eq<3>{}),
test::ct_eq<3>{}
));
}
{
struct object {
test::ct_eq<3> member;
};
auto lvalue = just(object{});
test::ct_eq<3>& ref = lvalue->member;
BOOST_HANA_CONSTANT_CHECK(equal(
ref,
test::ct_eq<3>{}
));
auto const const_lvalue = just(object{});
test::ct_eq<3> const& const_ref = const_lvalue->member;
BOOST_HANA_CONSTANT_CHECK(equal(
const_ref,
test::ct_eq<3>{}
));
BOOST_HANA_CONSTANT_CHECK(equal(
just(object{})->member,
test::ct_eq<3>{}
));
}
}
// from_maybe
{
BOOST_HANA_CONSTANT_CHECK(equal(from_maybe(x, nothing), x));
BOOST_HANA_CONSTANT_CHECK(equal(from_maybe(undefined{}, just(y)), y));
}
// only_when
{
BOOST_HANA_CONSTANT_CHECK(equal(
only_when(always(true_), f, x),
just(f(x))
));
BOOST_HANA_CONSTANT_CHECK(equal(
only_when(always(false_), f, x),
nothing
));
BOOST_HANA_CONSTANT_CHECK(equal(
only_when(always(false_), undefined{}, x),
nothing
));
}
// sfinae
{
test::_injection<0> f{};
BOOST_HANA_CONSTANT_CHECK(equal(
sfinae(f)(),
just(f())
));
BOOST_HANA_CONSTANT_CHECK(equal(
sfinae(f)(ct_eq<0>{}),
just(f(ct_eq<0>{}))
));
BOOST_HANA_CONSTANT_CHECK(equal(
sfinae(f)(ct_eq<0>{}, ct_eq<1>{}),
just(f(ct_eq<0>{}, ct_eq<1>{}))
));
BOOST_HANA_CONSTANT_CHECK(equal(
sfinae(undefined{})(),
nothing
));
BOOST_HANA_CONSTANT_CHECK(equal(
sfinae(undefined{})(ct_eq<0>{}),
nothing
));
BOOST_HANA_CONSTANT_CHECK(equal(
sfinae(undefined{})(ct_eq<0>{}, ct_eq<1>{}),
nothing
));
BOOST_HANA_CONSTEXPR_LAMBDA auto incr = sfinae([](auto x) -> decltype(x + 1) {
return x + 1;
});
BOOST_HANA_CONSTEXPR_CHECK(equal(
incr(1), just(2)
));
BOOST_HANA_CONSTANT_CHECK(equal(
incr(undefined{}), nothing
));
BOOST_HANA_CONSTEXPR_CHECK(equal(
bind(just(1), incr), just(2)
));
// using `sfinae` with a non-pod argument used to fail
sfinae(undefined{})(Tracked{1});
sfinae([t = Tracked{1}](auto) { return 1; })(Tracked{1});
}
// Make sure we do not instantiate rogue contructors when trying
// to copy a just.
{
auto expr = just(test::trap_construct{});
auto implicit_copy = expr; (void)implicit_copy;
decltype(expr) explicit_copy(expr); (void)explicit_copy;
}
// implicit and explicit construction of just
{
_just<int> j1{1}; (void)j1;
_just<int> j2 = {1}; (void)j2;
}
}
#elif BOOST_HANA_TEST_PART == 2
//////////////////////////////////////////////////////////////////////////
// Comparable
//////////////////////////////////////////////////////////////////////////
{
// equal
{
test::ct_eq<3> x{};
test::ct_eq<4> y{};
BOOST_HANA_CONSTANT_CHECK(equal(nothing, nothing));
BOOST_HANA_CONSTANT_CHECK(not_(equal(nothing, just(x))));
BOOST_HANA_CONSTANT_CHECK(not_(equal(just(x), nothing)));
BOOST_HANA_CONSTANT_CHECK(equal(just(x), just(x)));
BOOST_HANA_CONSTANT_CHECK(not_(equal(just(x), just(y))));
}
// laws
test::TestComparable<Maybe>{eqs};
}
#elif BOOST_HANA_TEST_PART == 3
//////////////////////////////////////////////////////////////////////////
// Orderable
//////////////////////////////////////////////////////////////////////////
{
// less
{
BOOST_HANA_CONSTANT_CHECK(less(
nothing,
just(undefined{})
));
BOOST_HANA_CONSTANT_CHECK(not_(less(
just(undefined{}),
nothing
)));
BOOST_HANA_CONSTANT_CHECK(not_(less(
nothing,
nothing
)));
BOOST_HANA_CONSTANT_CHECK(less(
just(ct_ord<3>{}),
just(ct_ord<4>{})
));
BOOST_HANA_CONSTANT_CHECK(not_(less(
just(ct_ord<3>{}),
just(ct_ord<3>{})
)));
BOOST_HANA_CONSTANT_CHECK(not_(less(
just(ct_ord<4>{}),
just(ct_ord<3>{})
)));
}
// laws
test::TestOrderable<Maybe>{ords};
}
#elif BOOST_HANA_TEST_PART == 4
//////////////////////////////////////////////////////////////////////////
// Functor
//////////////////////////////////////////////////////////////////////////
{
// transform
{
test::_injection<0> f{};
BOOST_HANA_CONSTANT_CHECK(equal(
transform(nothing, f),
nothing
));
BOOST_HANA_CONSTANT_CHECK(equal(
transform(just(ct_eq<3>{}), f),
just(f(ct_eq<3>{}))
));
}
// laws
test::TestFunctor<Maybe>{eqs, eq_values};
}
//////////////////////////////////////////////////////////////////////////
// Applicative
//////////////////////////////////////////////////////////////////////////
{
test::_injection<0> f{};
// ap
{
BOOST_HANA_CONSTANT_CHECK(equal(
ap(nothing, nothing),
nothing
));
BOOST_HANA_CONSTANT_CHECK(equal(
ap(just(f), nothing),
nothing
));
BOOST_HANA_CONSTANT_CHECK(equal(
ap(nothing, just(ct_eq<3>{})),
nothing
));
BOOST_HANA_CONSTANT_CHECK(equal(
ap(just(f), just(ct_eq<3>{})),
just(f(ct_eq<3>{}))
));
}
// lift
{
BOOST_HANA_CONSTANT_CHECK(equal(
lift<Maybe>(ct_eq<3>{}),
just(ct_eq<3>{})
));
}
// laws
test::TestApplicative<Maybe>{eqs};
}
//////////////////////////////////////////////////////////////////////////
// Monad
//////////////////////////////////////////////////////////////////////////
{
// flatten
{
BOOST_HANA_CONSTANT_CHECK(equal(
flatten(nothing),
nothing
));
BOOST_HANA_CONSTANT_CHECK(equal(
flatten(just(nothing)),
nothing
));
BOOST_HANA_CONSTANT_CHECK(equal(
flatten(just(just(ct_eq<4>{}))),
just(ct_eq<4>{})
));
}
// laws
test::TestMonad<Maybe>{eqs, nested_eqs};
}
//////////////////////////////////////////////////////////////////////////
// MonadPlus
//////////////////////////////////////////////////////////////////////////
{
// empty
{
BOOST_HANA_CONSTANT_CHECK(equal(
empty<Maybe>(),
nothing
));
}
// concat
{
auto rv_nothing = [] { return nothing; }; // rvalue nothing
BOOST_HANA_CONSTANT_CHECK(equal(
concat(rv_nothing(), nothing),
nothing
));
BOOST_HANA_CONSTANT_CHECK(equal(
concat(nothing, rv_nothing()),
nothing
));
BOOST_HANA_CONSTANT_CHECK(equal(
concat(rv_nothing(), rv_nothing()),
nothing
));
BOOST_HANA_CONSTANT_CHECK(equal(
concat(rv_nothing(), just(ct_eq<0>{})),
just(ct_eq<0>{})
));
BOOST_HANA_CONSTANT_CHECK(equal(
concat(just(ct_eq<0>{}), rv_nothing()),
just(ct_eq<0>{})
));
BOOST_HANA_CONSTANT_CHECK(equal(
concat(nothing, nothing), nothing
));
BOOST_HANA_CONSTANT_CHECK(equal(
concat(nothing, just(ct_eq<0>{})),
just(ct_eq<0>{})
));
BOOST_HANA_CONSTANT_CHECK(equal(
concat(just(ct_eq<0>{}), nothing),
just(ct_eq<0>{})
));
BOOST_HANA_CONSTANT_CHECK(equal(
concat(just(ct_eq<0>{}), just(ct_eq<1>{})),
just(ct_eq<0>{})
));
}
// laws
test::TestMonadPlus<Maybe>{eqs, predicates, eq_values};
}
#elif BOOST_HANA_TEST_PART == 5
//////////////////////////////////////////////////////////////////////////
// Traversable
//////////////////////////////////////////////////////////////////////////
{
test::_injection<0> f{};
auto applicative = test::identity;
using A = test::Identity;
// traverse
{
BOOST_HANA_CONSTANT_CHECK(equal(
traverse<A>(just(ct_eq<3>{}), compose(applicative, f)),
applicative(just(f(ct_eq<3>{})))
));
BOOST_HANA_CONSTANT_CHECK(equal(
traverse<A>(nothing, compose(applicative, f)),
applicative(nothing)
));
}
// laws
test::TestTraversable<Maybe>{};
}
//////////////////////////////////////////////////////////////////////////
// Searchable
//////////////////////////////////////////////////////////////////////////
{
test::ct_eq<2> x{};
test::ct_eq<3> y{};
// find_if
{
BOOST_HANA_CONSTANT_CHECK(equal(
find_if(just(x), equal.to(x)),
just(x)
));
BOOST_HANA_CONSTANT_CHECK(equal(
find_if(just(x), equal.to(y)),
nothing
));
BOOST_HANA_CONSTANT_CHECK(equal(
find_if(nothing, equal.to(x)),
nothing
));
// Previously, there was a bug that would make this fail.
auto non_const_nothing = nothing;
BOOST_HANA_CONSTANT_CHECK(equal(
find_if(non_const_nothing, equal.to(x)),
nothing
));
}
// any_of
{
BOOST_HANA_CONSTANT_CHECK(any_of(just(x), equal.to(x)));
BOOST_HANA_CONSTANT_CHECK(not_(any_of(just(x), equal.to(y))));
BOOST_HANA_CONSTANT_CHECK(not_(any_of(nothing, equal.to(x))));
}
// laws
test::TestSearchable<Maybe>{eqs, eq_values};
}
#elif BOOST_HANA_TEST_PART == 6
//////////////////////////////////////////////////////////////////////////
// Foldable
//////////////////////////////////////////////////////////////////////////
{
test::ct_eq<2> x{};
test::ct_eq<3> s{};
test::_injection<0> f{};
// fold.left
{
BOOST_HANA_CONSTANT_CHECK(equal(fold.left(just(x), s, f), f(s, x)));
BOOST_HANA_CONSTANT_CHECK(equal(fold.left(nothing, s, f), s));
}
// fold.right
{
BOOST_HANA_CONSTANT_CHECK(equal(fold.right(just(x), s, f), f(x, s)));
BOOST_HANA_CONSTANT_CHECK(equal(fold.right(nothing, s, f), s));
}
// unpack
{
BOOST_HANA_CONSTANT_CHECK(equal(unpack(nothing, f), f()));
BOOST_HANA_CONSTANT_CHECK(equal(unpack(just(x), f), f(x)));
// Previously, there was a bug that would make this fail.
auto non_const_nothing = nothing;
BOOST_HANA_CONSTANT_CHECK(equal(unpack(non_const_nothing, f), f()));
}
// laws
test::TestFoldable<Maybe>{eqs};
}
#endif
}