From 55c7cd14582323b4403bed88bd02e2f62d2a3169 Mon Sep 17 00:00:00 2001 From: Lee Clagett Date: Mon, 10 Sep 2018 21:25:15 -0400 Subject: Adding expect - a value-or-error implementation --- tests/unit_tests/expect.cpp | 915 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 915 insertions(+) create mode 100644 tests/unit_tests/expect.cpp (limited to 'tests/unit_tests/expect.cpp') diff --git a/tests/unit_tests/expect.cpp b/tests/unit_tests/expect.cpp new file mode 100644 index 000000000..efa843496 --- /dev/null +++ b/tests/unit_tests/expect.cpp @@ -0,0 +1,915 @@ +// Copyright (c) 2018, The Monero Project +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, are +// permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this list of +// conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, this list +// of conditions and the following disclaimer in the documentation and/or other +// materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its contributors may be +// used to endorse or promote products derived from this software without specific +// prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include + +#include +#include +#include +#include +#include + +#include "common/expect.h" + +namespace +{ + struct move_only; + struct throw_construct; + struct throw_copies; + struct throw_moves; + + struct move_only + { + move_only() = default; + move_only(move_only const&) = delete; + move_only(move_only&&) = default; + ~move_only() = default; + move_only& operator=(move_only const&) = delete; + move_only& operator=(move_only&&) = default; + }; + + struct throw_construct + { + throw_construct() {} + throw_construct(int) {} + throw_construct(throw_construct const&) = default; + throw_construct(throw_construct&&) = default; + ~throw_construct() = default; + throw_construct& operator=(throw_construct const&) = default; + throw_construct& operator=(throw_construct&&) = default; + }; + + struct throw_copies + { + throw_copies() noexcept {} + throw_copies(throw_copies const&) {} + throw_copies(throw_copies&&) = default; + ~throw_copies() = default; + throw_copies& operator=(throw_copies const&) { return *this; } + throw_copies& operator=(throw_copies&&) = default; + bool operator==(throw_copies const&) noexcept { return true; } + bool operator==(throw_moves const&) noexcept { return true; } + }; + + struct throw_moves + { + throw_moves() noexcept {} + throw_moves(throw_moves const&) = default; + throw_moves(throw_moves&&) {} + ~throw_moves() = default; + throw_moves& operator=(throw_moves const&) = default; + throw_moves& operator=(throw_moves&&) { return *this; } + bool operator==(throw_moves const&) { return true; } + bool operator==(throw_copies const&) { return true; } + }; + + template + void construction_bench() + { + EXPECT_TRUE(std::is_copy_constructible>()); + EXPECT_TRUE(std::is_move_constructible>()); + EXPECT_TRUE(std::is_copy_assignable>()); + EXPECT_TRUE(std::is_move_assignable>()); + EXPECT_TRUE(std::is_destructible>()); + } + + template + void noexcept_bench() + { + EXPECT_TRUE(std::is_nothrow_copy_constructible>()); + EXPECT_TRUE(std::is_nothrow_move_constructible>()); + EXPECT_TRUE(std::is_nothrow_copy_assignable>()); + EXPECT_TRUE(std::is_nothrow_move_assignable>()); + EXPECT_TRUE(std::is_nothrow_destructible>()); + + EXPECT_TRUE(noexcept(bool(std::declval>()))); + EXPECT_TRUE(noexcept(std::declval>().has_error())); + EXPECT_TRUE(noexcept(std::declval>().error())); + EXPECT_TRUE(noexcept(std::declval>().equal(std::declval>()))); + EXPECT_TRUE(noexcept(std::declval>() == std::declval>())); + EXPECT_TRUE(noexcept(std::declval>() != std::declval>())); + } + + template + void conversion_bench() + { + EXPECT_TRUE((std::is_convertible>())); + EXPECT_TRUE((std::is_convertible>())); + EXPECT_TRUE((std::is_convertible>())); + EXPECT_TRUE((std::is_convertible>())); + + EXPECT_TRUE((std::is_constructible, std::error_code>())); + EXPECT_TRUE((std::is_constructible, std::error_code&&>())); + EXPECT_TRUE((std::is_constructible, std::error_code&>())); + EXPECT_TRUE((std::is_constructible, std::error_code const&>())); + } +} + + +TEST(Expect, Constructions) +{ + construction_bench(); + construction_bench(); + + EXPECT_TRUE(std::is_constructible>()); + + EXPECT_TRUE((std::is_constructible, expect>())); + + EXPECT_TRUE(std::is_move_constructible>()); + EXPECT_TRUE(std::is_move_assignable>()); +} + +TEST(Expect, Conversions) +{ + struct implicit { implicit(int) {} }; + struct explicit_only { explicit explicit_only(int) {} }; + + conversion_bench(); + conversion_bench(); + + EXPECT_TRUE((std::is_convertible>())); + EXPECT_TRUE((std::is_convertible>())); + EXPECT_TRUE((std::is_convertible>())); + EXPECT_TRUE((std::is_convertible>())); + EXPECT_TRUE((std::is_convertible, expect>())); + EXPECT_TRUE((std::is_convertible&&, expect>())); + EXPECT_TRUE((std::is_convertible&, expect>())); + EXPECT_TRUE((std::is_convertible const&, expect>())); + EXPECT_TRUE((std::is_convertible, expect>())); + EXPECT_TRUE((std::is_convertible&&, expect>())); + EXPECT_TRUE((std::is_convertible&, expect>())); + EXPECT_TRUE((std::is_convertible const&, expect>())); + EXPECT_TRUE(!(std::is_convertible, expect>())); + EXPECT_TRUE(!(std::is_convertible&&, expect>())); + EXPECT_TRUE(!(std::is_convertible&, expect>())); + EXPECT_TRUE(!(std::is_convertible const&, expect>())); + + EXPECT_TRUE((std::is_constructible, int>())); + EXPECT_TRUE((std::is_constructible, int&&>())); + EXPECT_TRUE((std::is_constructible, int&>())); + EXPECT_TRUE((std::is_constructible, int const&>())); + EXPECT_TRUE((std::is_constructible, expect>())); + EXPECT_TRUE((std::is_constructible, expect&&>())); + EXPECT_TRUE((std::is_constructible, expect&>())); + EXPECT_TRUE((std::is_constructible, expect const&>())); + EXPECT_TRUE((std::is_constructible, expect>())); + EXPECT_TRUE((std::is_constructible, expect&&>())); + EXPECT_TRUE((std::is_constructible, expect&>())); + EXPECT_TRUE((std::is_constructible, expect const&>())); + EXPECT_TRUE(!(std::is_constructible, expect>())); + EXPECT_TRUE(!(std::is_constructible, expect&&>())); + EXPECT_TRUE(!(std::is_constructible, expect&>())); + EXPECT_TRUE(!(std::is_constructible, expect const&>())); + + EXPECT_EQ(expect{expect{100}}.value(), 100); + + expect val1{std::string{}}; + expect val2{"foo"}; + + EXPECT_EQ(val1.value(), std::string{}); + EXPECT_EQ(val2.value(), std::string{"foo"}); + + const expect val3{val2}; + + EXPECT_EQ(val1.value(), std::string{}); + EXPECT_EQ(val2.value(), std::string{"foo"}); + EXPECT_EQ(val3.value(), std::string{"foo"}); + + val1 = val2; + + EXPECT_EQ(val1.value(), "foo"); + EXPECT_EQ(val2.value(), std::string{"foo"}); + EXPECT_EQ(val3.value(), "foo"); +} + +TEST(Expect, NoExcept) +{ + noexcept_bench(); + noexcept_bench(); + + EXPECT_TRUE(std::is_nothrow_constructible>()); + + EXPECT_TRUE((std::is_nothrow_constructible, int>())); + EXPECT_TRUE((std::is_nothrow_constructible, expect>())); + EXPECT_TRUE((std::is_nothrow_constructible, expect&&>())); + EXPECT_TRUE((std::is_nothrow_constructible, expect&>())); + EXPECT_TRUE((std::is_nothrow_constructible, expect const&>())); + + EXPECT_TRUE(noexcept(expect{std::declval&&>()})); + EXPECT_TRUE(noexcept(expect{std::declval const&>()})); + EXPECT_TRUE(noexcept(std::declval>().has_value())); + EXPECT_TRUE(noexcept(*std::declval>())); + EXPECT_TRUE(noexcept(std::declval>().equal(std::declval>()))); + EXPECT_TRUE(noexcept(std::declval>().equal(std::declval>()))); + EXPECT_TRUE(noexcept(std::declval>().equal(0))); + EXPECT_TRUE(noexcept(std::declval>() == std::declval>())); + EXPECT_TRUE(noexcept(std::declval>() == std::declval>())); + EXPECT_TRUE(noexcept(std::declval>() == 0)); + EXPECT_TRUE(noexcept(0 == std::declval>())); + EXPECT_TRUE(noexcept(std::declval>() != std::declval>())); + EXPECT_TRUE(noexcept(std::declval>() != std::declval>())); + EXPECT_TRUE(noexcept(std::declval>() != 0)); + EXPECT_TRUE(noexcept(0 != std::declval>())); + + EXPECT_TRUE((std::is_nothrow_constructible, std::error_code>())); + EXPECT_TRUE((std::is_nothrow_constructible, std::error_code&&>())); + EXPECT_TRUE((std::is_nothrow_constructible, std::error_code&>())); + EXPECT_TRUE((std::is_nothrow_constructible, std::error_code const&>())); + EXPECT_TRUE((std::is_nothrow_constructible, throw_construct>())); + EXPECT_TRUE((std::is_nothrow_constructible, throw_construct&&>())); + EXPECT_TRUE((std::is_nothrow_constructible, throw_construct&>())); + EXPECT_TRUE((std::is_nothrow_constructible, throw_construct const&>())); + EXPECT_TRUE(!(std::is_nothrow_constructible, expect>())); + EXPECT_TRUE(!(std::is_nothrow_constructible, expect&&>())); + EXPECT_TRUE(!(std::is_nothrow_constructible, expect&>())); + EXPECT_TRUE(!(std::is_nothrow_constructible, expect const&>())); + EXPECT_TRUE(std::is_nothrow_copy_constructible>()); + EXPECT_TRUE(std::is_nothrow_move_constructible>()); + EXPECT_TRUE(std::is_nothrow_copy_assignable>()); + EXPECT_TRUE(std::is_nothrow_move_assignable>()); + EXPECT_TRUE(std::is_nothrow_destructible>()); + + EXPECT_TRUE((std::is_nothrow_constructible, std::error_code>())); + EXPECT_TRUE((std::is_nothrow_constructible, std::error_code&&>())); + EXPECT_TRUE((std::is_nothrow_constructible, std::error_code&>())); + EXPECT_TRUE((std::is_nothrow_constructible, std::error_code const&>())); + EXPECT_TRUE((std::is_nothrow_constructible, throw_copies>())); + EXPECT_TRUE((std::is_nothrow_constructible, throw_copies&&>())); + EXPECT_TRUE(!(std::is_nothrow_constructible, throw_copies&>())); + EXPECT_TRUE(!(std::is_nothrow_constructible, throw_copies const&>())); + EXPECT_TRUE(!std::is_nothrow_copy_constructible>()); + EXPECT_TRUE(std::is_nothrow_move_constructible>()); + EXPECT_TRUE(!std::is_nothrow_copy_assignable>()); + EXPECT_TRUE(std::is_nothrow_move_assignable>()); + EXPECT_TRUE(std::is_nothrow_destructible>()); + EXPECT_TRUE(noexcept(std::declval>().equal(std::declval>()))); + EXPECT_TRUE(noexcept(std::declval>().equal(std::declval()))); + EXPECT_TRUE(noexcept(std::declval>() == std::declval>())); + EXPECT_TRUE(noexcept(std::declval>() == std::declval())); + EXPECT_TRUE(noexcept(std::declval() == std::declval>())); + EXPECT_TRUE(noexcept(std::declval>() != std::declval>())); + EXPECT_TRUE(noexcept(std::declval>() != std::declval())); + EXPECT_TRUE(noexcept(std::declval() != std::declval>())); + EXPECT_TRUE(noexcept(std::declval>().equal(std::declval>()))); + EXPECT_TRUE(noexcept(std::declval>().equal(std::declval()))); + EXPECT_TRUE(noexcept(std::declval>() == std::declval>())); + EXPECT_TRUE(noexcept(std::declval>() == std::declval())); + EXPECT_TRUE(noexcept(std::declval() == std::declval>())); + EXPECT_TRUE(noexcept(std::declval>() != std::declval>())); + EXPECT_TRUE(noexcept(std::declval>() != std::declval())); + EXPECT_TRUE(noexcept(std::declval() != std::declval>())); + + EXPECT_TRUE((std::is_nothrow_constructible, std::error_code>())); + EXPECT_TRUE((std::is_nothrow_constructible, std::error_code&&>())); + EXPECT_TRUE((std::is_nothrow_constructible, std::error_code&>())); + EXPECT_TRUE((std::is_nothrow_constructible, std::error_code const&>())); + EXPECT_TRUE(!(std::is_nothrow_constructible, throw_moves>())); + EXPECT_TRUE(!(std::is_nothrow_constructible, throw_moves&&>())); + EXPECT_TRUE(!(std::is_nothrow_constructible, throw_moves&>())); + EXPECT_TRUE(!(std::is_nothrow_constructible, throw_moves const&>())); + EXPECT_TRUE(std::is_nothrow_copy_constructible>()); + EXPECT_TRUE(!std::is_nothrow_move_constructible>()); + EXPECT_TRUE(std::is_nothrow_copy_assignable>()); + EXPECT_TRUE(!std::is_nothrow_move_assignable>()); + EXPECT_TRUE(std::is_nothrow_destructible>()); + EXPECT_TRUE(!noexcept(std::declval>().equal(std::declval>()))); + EXPECT_TRUE(!noexcept(std::declval>().equal(std::declval()))); + EXPECT_TRUE(!noexcept(std::declval>() == std::declval>())); + EXPECT_TRUE(!noexcept(std::declval>() == std::declval())); + EXPECT_TRUE(!noexcept(std::declval() == std::declval>())); + EXPECT_TRUE(!noexcept(std::declval>() != std::declval>())); + EXPECT_TRUE(!noexcept(std::declval>() != std::declval())); + EXPECT_TRUE(!noexcept(std::declval() != std::declval>())); + EXPECT_TRUE(!noexcept(std::declval>().equal(std::declval>()))); + EXPECT_TRUE(!noexcept(std::declval>().equal(std::declval()))); + EXPECT_TRUE(!noexcept(std::declval>() == std::declval>())); + EXPECT_TRUE(!noexcept(std::declval>() == std::declval())); + EXPECT_TRUE(!noexcept(std::declval() == std::declval>())); + EXPECT_TRUE(!noexcept(std::declval>() != std::declval>())); + EXPECT_TRUE(!noexcept(std::declval>() != std::declval())); + EXPECT_TRUE(!noexcept(std::declval() != std::declval>())); +} + +TEST(Expect, Trivial) +{ + EXPECT_TRUE(std::is_trivially_copy_constructible>()); + EXPECT_TRUE(std::is_trivially_move_constructible>()); + EXPECT_TRUE(std::is_trivially_destructible>()); +} + +TEST(Expect, Assignment) +{ + expect val1{std::string{}}; + expect val2{"foobar"}; + + ASSERT_TRUE(val1.has_value()); + ASSERT_TRUE(val2.has_value()); + EXPECT_TRUE(bool(val1)); + EXPECT_TRUE(bool(val2)); + EXPECT_TRUE(!val1.has_error()); + EXPECT_TRUE(!val2.has_error()); + EXPECT_EQ(val1.value(), std::string{}); + EXPECT_TRUE(*val1 == std::string{}); + EXPECT_TRUE(boost::equals(val1->c_str(), "")); + EXPECT_TRUE(val2.value() == "foobar"); + EXPECT_TRUE(*val2 == "foobar"); + EXPECT_TRUE(boost::equals(val2->c_str(), "foobar")); + EXPECT_EQ(val1.error(), std::error_code{}); + EXPECT_EQ(val2.error(), std::error_code{}); + EXPECT_TRUE(!val1.equal(std::error_code{})); + EXPECT_TRUE(!val2.equal(std::error_code{})); + EXPECT_TRUE(!(val1 == std::error_code{})); + EXPECT_TRUE(!(std::error_code{} == val1)); + EXPECT_TRUE(!(val2 == std::error_code{})); + EXPECT_TRUE(!(std::error_code{} == val2)); + EXPECT_TRUE(val1 != std::error_code{}); + EXPECT_TRUE(std::error_code{} != val1); + EXPECT_TRUE(val2 != std::error_code{}); + EXPECT_TRUE(std::error_code{} != val2); + EXPECT_TRUE(!val1.matches(std::error_condition{})); + EXPECT_TRUE(!val2.matches(std::error_condition{})); + + val1 = std::move(val2); + + ASSERT_TRUE(val1.has_value()); + ASSERT_TRUE(val2.has_value()); + EXPECT_TRUE(bool(val1)); + EXPECT_TRUE(bool(val2)); + EXPECT_TRUE(!val1.has_error()); + EXPECT_TRUE(!val2.has_error()); + EXPECT_EQ(val1.value(), "foobar"); + EXPECT_TRUE(*val1 == "foobar"); + EXPECT_TRUE(boost::equals(val1->c_str(), "foobar")); + EXPECT_EQ(val2.value(), std::string{}); + EXPECT_TRUE(*val2 == std::string{}); + EXPECT_TRUE(boost::equals(val2->c_str(), "")); + EXPECT_EQ(val1.error(), std::error_code{}); + EXPECT_EQ(val2.error(), std::error_code{}); + EXPECT_TRUE(!val1.equal(std::error_code{})); + EXPECT_TRUE(!val2.equal(std::error_code{})); + EXPECT_TRUE(!(val1 == std::error_code{})); + EXPECT_TRUE(!(std::error_code{} == val1)); + EXPECT_TRUE(!(val2 == std::error_code{})); + EXPECT_TRUE(!(std::error_code{} == val2)); + EXPECT_TRUE(val1 != std::error_code{}); + EXPECT_TRUE(std::error_code{} != val1); + EXPECT_TRUE(val2 != std::error_code{}); + EXPECT_TRUE(std::error_code{} != val2); + EXPECT_TRUE(!val1.matches(std::error_condition{})); + EXPECT_TRUE(!val2.matches(std::error_condition{})); + + val2 = val1; + + ASSERT_TRUE(val1.has_value()); + ASSERT_TRUE(val2.has_value()); + EXPECT_TRUE(bool(val1)); + EXPECT_TRUE(bool(val2)); + EXPECT_TRUE(!val1.has_error()); + EXPECT_TRUE(!val2.has_error()); + EXPECT_EQ(val1.value(), "foobar"); + EXPECT_TRUE(*val1 == "foobar"); + EXPECT_TRUE(boost::equals(val1->c_str(), "foobar")); + EXPECT_EQ(val2.value(), "foobar"); + EXPECT_TRUE(*val2 == "foobar"); + EXPECT_TRUE(boost::equals(val2->c_str(), "foobar")); + EXPECT_EQ(val1.error(), std::error_code{}); + EXPECT_EQ(val2.error(), std::error_code{}); + EXPECT_TRUE(!val1.equal(std::error_code{})); + EXPECT_TRUE(!val2.equal(std::error_code{})); + EXPECT_TRUE(!(val1 == std::error_code{})); + EXPECT_TRUE(!(std::error_code{} == val1)); + EXPECT_TRUE(!(val2 == std::error_code{})); + EXPECT_TRUE(!(std::error_code{} == val2)); + EXPECT_TRUE(val1 != std::error_code{}); + EXPECT_TRUE(std::error_code{} != val1); + EXPECT_TRUE(val2 != std::error_code{}); + EXPECT_TRUE(std::error_code{} != val2); + EXPECT_TRUE(!val1.matches(std::error_condition{})); + EXPECT_TRUE(!val2.matches(std::error_condition{})); + + val1 = make_error_code(common_error::kInvalidArgument); + + ASSERT_TRUE(val1.has_error()); + ASSERT_TRUE(val2.has_value()); + EXPECT_TRUE(!val1); + EXPECT_TRUE(bool(val2)); + EXPECT_TRUE(!val1.has_value()); + EXPECT_TRUE(!val2.has_error()); + EXPECT_EQ(val1.error(), common_error::kInvalidArgument); + EXPECT_TRUE(val1 == common_error::kInvalidArgument); + EXPECT_TRUE(common_error::kInvalidArgument == val1); + EXPECT_STREQ(val2.value().c_str(), "foobar"); + EXPECT_TRUE(*val2 == "foobar"); + EXPECT_TRUE(boost::equals(val2->c_str(), "foobar")); + EXPECT_NE(val1.error(), std::error_code{}); + EXPECT_EQ(val2.error(), std::error_code{}); + EXPECT_TRUE(val1.equal(common_error::kInvalidArgument)); + EXPECT_TRUE(!val2.equal(std::error_code{})); + EXPECT_TRUE(!(val1 == std::error_code{})); + EXPECT_TRUE(!(std::error_code{} == val1)); + EXPECT_TRUE(!(val2 == std::error_code{})); + EXPECT_TRUE(!(std::error_code{} == val2)); + EXPECT_TRUE(val1 != std::error_code{}); + EXPECT_TRUE(std::error_code{} != val1); + EXPECT_TRUE(val2 != std::error_code{}); + EXPECT_TRUE(std::error_code{} != val2); + EXPECT_TRUE(val1.matches(std::errc::invalid_argument)); + EXPECT_TRUE(!val1.matches(std::error_condition{})); + EXPECT_TRUE(!val2.matches(std::error_condition{})); + + val2 = val1; + + ASSERT_TRUE(val1.has_error()); + ASSERT_TRUE(val2.has_error()); + EXPECT_TRUE(!val1); + EXPECT_TRUE(!val2); + EXPECT_TRUE(!val1.has_value()); + EXPECT_TRUE(!val2.has_value()); + EXPECT_EQ(val1.error(), common_error::kInvalidArgument); + EXPECT_TRUE(val1 == common_error::kInvalidArgument); + EXPECT_TRUE(common_error::kInvalidArgument == val1); + EXPECT_EQ(val2.error(), common_error::kInvalidArgument); + EXPECT_TRUE(val2 == common_error::kInvalidArgument); + EXPECT_TRUE(common_error::kInvalidArgument == val2); + EXPECT_NE(val1.error(), std::error_code{}); + EXPECT_NE(val2.error(), std::error_code{}); + EXPECT_TRUE(val1.equal(common_error::kInvalidArgument)); + EXPECT_TRUE(val2.equal(common_error::kInvalidArgument)); + EXPECT_TRUE(!(val1 == std::error_code{})); + EXPECT_TRUE(!(std::error_code{} == val1)); + EXPECT_TRUE(!(val2 == std::error_code{})); + EXPECT_TRUE(!(std::error_code{} == val2)); + EXPECT_TRUE(val1 != std::error_code{}); + EXPECT_TRUE(std::error_code{} != val1); + EXPECT_TRUE(val2 != std::error_code{}); + EXPECT_TRUE(std::error_code{} != val2); + EXPECT_TRUE(val1.matches(std::errc::invalid_argument)); + EXPECT_TRUE(val2.matches(std::errc::invalid_argument)); + EXPECT_TRUE(!val1.matches(std::error_condition{})); + EXPECT_TRUE(!val2.matches(std::error_condition{})); + + val1 = std::string{"barfoo"}; + + ASSERT_TRUE(val1.has_value()); + ASSERT_TRUE(val2.has_error()); + EXPECT_TRUE(bool(val1)); + EXPECT_TRUE(!val2); + EXPECT_TRUE(!val1.has_error()); + EXPECT_TRUE(!val2.has_value()); + EXPECT_STREQ(val1.value().c_str(), "barfoo"); + EXPECT_TRUE(*val1 == "barfoo"); + EXPECT_TRUE(boost::equals(val1->c_str(), "barfoo")); + EXPECT_EQ(val2.error(), common_error::kInvalidArgument); + EXPECT_TRUE(val2 == common_error::kInvalidArgument); + EXPECT_TRUE(common_error::kInvalidArgument == val2); + EXPECT_EQ(val1.error(), std::error_code{}); + EXPECT_NE(val2.error(), std::error_code{}); + EXPECT_TRUE(!val1.equal(std::error_code{})); + EXPECT_TRUE(val2.equal(common_error::kInvalidArgument)); + EXPECT_TRUE(!(val1 == std::error_code{})); + EXPECT_TRUE(!(std::error_code{} == val1)); + EXPECT_TRUE(!(val2 == std::error_code{})); + EXPECT_TRUE(!(std::error_code{} == val2)); + EXPECT_TRUE(val1 != std::error_code{}); + EXPECT_TRUE(std::error_code{} != val1); + EXPECT_TRUE(val2 != std::error_code{}); + EXPECT_TRUE(std::error_code{} != val2); + EXPECT_TRUE(val2.matches(std::errc::invalid_argument)); + EXPECT_TRUE(!val1.matches(std::error_condition{})); + EXPECT_TRUE(!val2.matches(std::error_condition{})); + + val2 = val1; + + ASSERT_TRUE(val1.has_value()); + ASSERT_TRUE(val2.has_value()); + EXPECT_TRUE(bool(val1)); + EXPECT_TRUE(bool(val2)); + EXPECT_TRUE(!val1.has_error()); + EXPECT_TRUE(!val2.has_error()); + EXPECT_EQ(val1.value(), "barfoo"); + EXPECT_TRUE(*val1 == "barfoo"); + EXPECT_TRUE(boost::equals(val1->c_str(), "barfoo")); + EXPECT_EQ(val2.value(), "barfoo"); + EXPECT_TRUE(*val2 == "barfoo"); + EXPECT_TRUE(boost::equals(val2->c_str(), "barfoo")); + EXPECT_EQ(val1.error(), std::error_code{}); + EXPECT_EQ(val2.error(), std::error_code{}); + EXPECT_TRUE(!val1.equal(std::error_code{})); + EXPECT_TRUE(!val2.equal(std::error_code{})); + EXPECT_TRUE(!(val1 == std::error_code{})); + EXPECT_TRUE(!(std::error_code{} == val1)); + EXPECT_TRUE(!(val2 == std::error_code{})); + EXPECT_TRUE(!(std::error_code{} == val2)); + EXPECT_TRUE(val1 != std::error_code{}); + EXPECT_TRUE(std::error_code{} != val1); + EXPECT_TRUE(val2 != std::error_code{}); + EXPECT_TRUE(std::error_code{} != val2); + EXPECT_TRUE(!val1.matches(std::error_condition{})); + EXPECT_TRUE(!val2.matches(std::error_condition{})); +} + +TEST(Expect, AssignmentThrowsOnMove) +{ + struct construct_error {}; + struct assignment_error {}; + + struct throw_on_move { + std::string msg; + + throw_on_move(const char* msg) : msg(msg) {} + throw_on_move(throw_on_move&&) { + throw construct_error{}; + } + throw_on_move(throw_on_move const&) = default; + ~throw_on_move() = default; + throw_on_move& operator=(throw_on_move&&) { + throw assignment_error{}; + } + throw_on_move& operator=(throw_on_move const&) = default; + }; + + expect val1{expect{"foobar"}}; + expect val2{common_error::kInvalidArgument}; + + ASSERT_TRUE(val1.has_value()); + ASSERT_TRUE(val2.has_error()); + EXPECT_TRUE(!val1.has_error()); + EXPECT_TRUE(!val2.has_value()); + EXPECT_STREQ(val1->msg.c_str(), "foobar"); + EXPECT_EQ(val2.error(), common_error::kInvalidArgument); + + EXPECT_THROW(val2 = std::move(val1), construct_error); + + ASSERT_TRUE(val1.has_value()); + ASSERT_TRUE(val2.has_error()); + EXPECT_TRUE(!val1.has_error()); + EXPECT_TRUE(!val2.has_value()); + EXPECT_STREQ(val1->msg.c_str(), "foobar"); + EXPECT_EQ(val2.error(), common_error::kInvalidArgument); + + EXPECT_THROW(val1 = expect{"barfoo"}, assignment_error); + + ASSERT_TRUE(val1.has_value()); + ASSERT_TRUE(val2.has_error()); + EXPECT_TRUE(!val1.has_error()); + EXPECT_TRUE(!val2.has_value()); + EXPECT_STREQ(val1->msg.c_str(), "foobar"); + EXPECT_EQ(val2.error(), common_error::kInvalidArgument); + + EXPECT_NO_THROW(val2 = val1); + + ASSERT_TRUE(val1.has_value()); + ASSERT_TRUE(val2.has_value()); + EXPECT_TRUE(!val1.has_error()); + EXPECT_TRUE(!val2.has_error()); + EXPECT_STREQ(val1->msg.c_str(), "foobar"); + EXPECT_STREQ(val2->msg.c_str(), "foobar"); +} + +TEST(Expect, EqualWithStrings) +{ + expect val1{std::string{}}; + expect val2{"barfoo"}; + expect val3{boost::string_ref{}}; + + EXPECT_TRUE(!val1.equal(val2)); + EXPECT_TRUE(val1.equal(val3)); + EXPECT_TRUE(!val2.equal(val1)); + EXPECT_TRUE(!val2.equal(val3)); + EXPECT_TRUE(val3.equal(val1)); + EXPECT_TRUE(!val3.equal(val2)); + EXPECT_TRUE(!(val1 == val2)); + EXPECT_TRUE(!(val2 == val1)); + EXPECT_TRUE(val1 == val3); + EXPECT_TRUE(val3 == val1); + EXPECT_TRUE(!(val2 == val3)); + EXPECT_TRUE(!(val3 == val2)); + EXPECT_TRUE(val1 != val2); + EXPECT_TRUE(val2 != val1); + EXPECT_TRUE(!(val1 != val3)); + EXPECT_TRUE(!(val3 != val1)); + EXPECT_TRUE(val2 != val3); + EXPECT_TRUE(val3 != val2); + + EXPECT_TRUE(val1.equal("")); + EXPECT_TRUE(val2.equal("barfoo")); + EXPECT_TRUE(val3.equal("")); + EXPECT_TRUE(!val1.equal(std::error_code{})); + EXPECT_TRUE(!val2.equal(std::error_code{})); + EXPECT_TRUE(!val3.equal(std::error_code{})); + EXPECT_TRUE(val1 == ""); + EXPECT_TRUE("" == val1); + EXPECT_TRUE(val2 == "barfoo"); + EXPECT_TRUE("barfoo" == val2); + EXPECT_TRUE(val3 == ""); + EXPECT_TRUE("" == val3); + EXPECT_TRUE(!(val1 != "")); + EXPECT_TRUE(!("" != val1)); + EXPECT_TRUE(!(val2 != "barfoo")); + EXPECT_TRUE(!("barfoo" != val2)); + EXPECT_TRUE(!(val3 != "")); + EXPECT_TRUE(!("" != val3)); + EXPECT_TRUE(!(val1 == std::error_code{})); + EXPECT_TRUE(!(std::error_code{} == val1)); + EXPECT_TRUE(!(val2 == std::error_code{})); + EXPECT_TRUE(!(std::error_code{} == val2)); + EXPECT_TRUE(!(val3 == std::error_code{})); + EXPECT_TRUE(!(std::error_code{} == val3)); + EXPECT_TRUE(val1 != std::error_code{}); + EXPECT_TRUE(std::error_code{} != val1); + EXPECT_TRUE(val2 != std::error_code{}); + EXPECT_TRUE(std::error_code{} != val2); + EXPECT_TRUE(val3 != std::error_code{}); + EXPECT_TRUE(std::error_code{} != val3); + EXPECT_TRUE(!val1.matches(std::error_condition{})); + EXPECT_TRUE(!val2.matches(std::error_condition{})); + EXPECT_TRUE(!val3.matches(std::error_condition{})); + + val2 = make_error_code(common_error::kInvalidArgument); + + EXPECT_TRUE(!val1.equal(val2)); + EXPECT_TRUE(val1.equal(val3)); + EXPECT_TRUE(!val2.equal(val1)); + EXPECT_TRUE(!val2.equal(val3)); + EXPECT_TRUE(val3.equal(val1)); + EXPECT_TRUE(!val3.equal(val2)); + EXPECT_TRUE(!(val1 == val2)); + EXPECT_TRUE(!(val2 == val1)); + EXPECT_TRUE(val1 == val3); + EXPECT_TRUE(val3 == val1); + EXPECT_TRUE(!(val2 == val3)); + EXPECT_TRUE(!(val3 == val2)); + EXPECT_TRUE(val1 != val2); + EXPECT_TRUE(val2 != val1); + EXPECT_TRUE(!(val1 != val3)); + EXPECT_TRUE(!(val3 != val1)); + EXPECT_TRUE(val2 != val3); + EXPECT_TRUE(val3 != val2); + + EXPECT_TRUE(!val1.equal(common_error::kInvalidArgument)); + EXPECT_TRUE(val2.equal(common_error::kInvalidArgument)); + EXPECT_TRUE(!val3.equal(common_error::kInvalidArgument)); + EXPECT_TRUE(val2 == common_error::kInvalidArgument); + EXPECT_TRUE(common_error::kInvalidArgument == val2); + EXPECT_TRUE(!(val2 != common_error::kInvalidArgument)); + EXPECT_TRUE(!(common_error::kInvalidArgument != val2)); + EXPECT_TRUE(val2.matches(std::errc::invalid_argument)); + EXPECT_TRUE(!val2.matches(std::error_condition{})); + + val1 = expect{"barfoo"}; + + EXPECT_TRUE(!val1.equal(val2)); + EXPECT_TRUE(!val1.equal(val3)); + EXPECT_TRUE(!val2.equal(val1)); + EXPECT_TRUE(!val2.equal(val3)); + EXPECT_TRUE(!val3.equal(val1)); + EXPECT_TRUE(!val3.equal(val2)); + EXPECT_TRUE(!(val1 == val2)); + EXPECT_TRUE(!(val2 == val1)); + EXPECT_TRUE(!(val1 == val3)); + EXPECT_TRUE(!(val3 == val1)); + EXPECT_TRUE(!(val2 == val3)); + EXPECT_TRUE(!(val3 == val2)); + EXPECT_TRUE(val1 != val2); + EXPECT_TRUE(val2 != val1); + EXPECT_TRUE(val1 != val3); + EXPECT_TRUE(val3 != val1); + EXPECT_TRUE(val2 != val3); + EXPECT_TRUE(val3 != val2); + + EXPECT_TRUE(val1.equal("barfoo")); + EXPECT_TRUE(val1 == "barfoo"); + EXPECT_TRUE("barfoo" == val1); + EXPECT_TRUE(!(val1 != "barfoo")); + EXPECT_TRUE(!("barfoo" != val1)); + EXPECT_TRUE(!val1.equal(common_error::kInvalidArgument)); + EXPECT_TRUE(!(val1 == common_error::kInvalidArgument)); + EXPECT_TRUE(!(common_error::kInvalidArgument == val1)); + EXPECT_TRUE(!(val1 == std::error_code{})); + EXPECT_TRUE(!(std::error_code{} == val1)); + EXPECT_TRUE(!val1.matches(std::error_condition{})); + EXPECT_TRUE(!val1.matches(std::errc::invalid_argument)); +} + +TEST(Expect, EqualWithVoid) +{ + const expect val1; + expect val2; + + EXPECT_TRUE(val1.equal(val2)); + EXPECT_TRUE(val2.equal(val1)); + EXPECT_TRUE(!val1.equal(std::error_code{})); + EXPECT_TRUE(!val2.equal(std::error_code{})); + EXPECT_TRUE(val1 == val2); + EXPECT_TRUE(val2 == val1); + EXPECT_TRUE(!(val1 == std::error_code{})); + EXPECT_TRUE(!(std::error_code{} == val1)); + EXPECT_TRUE(!(val2 == std::error_code{})); + EXPECT_TRUE(!(std::error_code{} == val2)); + EXPECT_TRUE(!(val1 != val2)); + EXPECT_TRUE(!(val2 != val1)); + EXPECT_TRUE(val1 != std::error_code{}); + EXPECT_TRUE(std::error_code{} != val1); + EXPECT_TRUE(!(val2 == std::error_code{})); + EXPECT_TRUE(!(std::error_code{} == val2)); + + val2 = make_error_code(common_error::kInvalidArgument); + + EXPECT_TRUE(!val1.equal(val2)); + EXPECT_TRUE(!val2.equal(val1)); + EXPECT_TRUE(!val1.equal(common_error::kInvalidArgument)); + EXPECT_TRUE(val2.equal(common_error::kInvalidArgument)); + EXPECT_TRUE(!val2.equal(std::error_code{})); + EXPECT_TRUE(!(val1 == val2)); + EXPECT_TRUE(!(val2 == val1)); + EXPECT_TRUE(val2 == common_error::kInvalidArgument); + EXPECT_TRUE(common_error::kInvalidArgument == val2); + EXPECT_TRUE(!(val2 == std::error_code{})); + EXPECT_TRUE(!(std::error_code{} == val2)); + EXPECT_TRUE(val1 != val2); + EXPECT_TRUE(val2 != val1); + EXPECT_TRUE(!(val2 != common_error::kInvalidArgument)); + EXPECT_TRUE(!(common_error::kInvalidArgument != val2)); + EXPECT_TRUE(val2 != std::error_code{}); + EXPECT_TRUE(std::error_code{} != val2); +} + +TEST(Expect, EqualNoCopies) +{ + struct copy_error {}; + + struct throw_on_copy { + throw_on_copy() = default; + throw_on_copy(int) noexcept {} + throw_on_copy(throw_on_copy const&) { + throw copy_error{}; + } + ~throw_on_copy() = default; + throw_on_copy& operator=(throw_on_copy const&) { + throw copy_error{}; + } + + bool operator==(throw_on_copy const&) const noexcept { return true; } + }; + + expect val1{expect{0}}; + expect val2{expect{0}}; + + EXPECT_TRUE(val1.equal(val2)); + EXPECT_TRUE(val2.equal(val1)); + EXPECT_TRUE(val1 == val2); + EXPECT_TRUE(val2 == val1); + EXPECT_TRUE(!(val1 != val2)); + EXPECT_TRUE(!(val2 != val1)); + + EXPECT_TRUE(val1.equal(throw_on_copy{})); + EXPECT_TRUE(val1 == throw_on_copy{}); + EXPECT_TRUE(throw_on_copy{} == val1); + EXPECT_TRUE(!(val1 != throw_on_copy{})); + EXPECT_TRUE(!(throw_on_copy{} != val1)); + + throw_on_copy val3; + + EXPECT_TRUE(val1.equal(val3)); + EXPECT_TRUE(val1 == val3); + EXPECT_TRUE(val3 == val1); + EXPECT_TRUE(!(val1 != val3)); + EXPECT_TRUE(!(val3 != val1)); + + expect val4{common_error::kInvalidArgument}; + + EXPECT_TRUE(!val4.equal(throw_on_copy{})); + EXPECT_TRUE(!(val4 == throw_on_copy{})); + EXPECT_TRUE(!(throw_on_copy{} == val4)); + EXPECT_TRUE(val4 != throw_on_copy{}); + EXPECT_TRUE(throw_on_copy{} != val4); + EXPECT_TRUE(!val4.equal(val3)); + EXPECT_TRUE(!(val4 == val3)); + EXPECT_TRUE(!(val3 == val4)); + EXPECT_TRUE(val4 != val3); + EXPECT_TRUE(val3 != val4); +} + +TEST(Expect, Macros) { + EXPECT_TRUE( + [] () -> ::common_error { + MONERO_PRECOND(true); + return {common_error::kInvalidErrorCode}; + } () == common_error::kInvalidErrorCode + ); + EXPECT_TRUE( + [] () -> ::common_error { + MONERO_PRECOND(false); + return {common_error::kInvalidErrorCode}; + } () == common_error::kInvalidArgument + ); + EXPECT_TRUE( + [] () -> std::error_code { + MONERO_PRECOND(true); + return {common_error::kInvalidErrorCode}; + } () == common_error::kInvalidErrorCode + ); + EXPECT_TRUE( + [] () -> std::error_code { + MONERO_PRECOND(false); + return {common_error::kInvalidErrorCode}; + } () == common_error::kInvalidArgument + ); + EXPECT_TRUE( + [] () -> expect { + MONERO_PRECOND(true); + return {common_error::kInvalidErrorCode}; + } () == common_error::kInvalidErrorCode + ); + EXPECT_TRUE( + [] () -> expect { + MONERO_PRECOND(false); + return {common_error::kInvalidErrorCode}; + } () == common_error::kInvalidArgument + ); + EXPECT_TRUE( + [] () -> expect { + MONERO_PRECOND(true); + return {common_error::kInvalidErrorCode}; + } () == common_error::kInvalidErrorCode + ); + EXPECT_TRUE( + [] () -> expect { + MONERO_PRECOND(false); + return {common_error::kInvalidErrorCode}; + } () == common_error::kInvalidArgument + ); + + EXPECT_TRUE( + [] () -> std::error_code { + MONERO_CHECK(expect{}); + return {common_error::kInvalidErrorCode}; + } () == common_error::kInvalidErrorCode + ); + EXPECT_TRUE( + [] () -> std::error_code { + MONERO_CHECK(expect{common_error::kInvalidArgument}); + return {common_error::kInvalidErrorCode}; + } () == common_error::kInvalidArgument + ); + EXPECT_TRUE( + [] () -> expect { + MONERO_CHECK(expect{}); + return {common_error::kInvalidErrorCode}; + } () == common_error::kInvalidErrorCode + ); + EXPECT_TRUE( + [] () -> expect { + MONERO_CHECK(expect{common_error::kInvalidArgument}); + return {common_error::kInvalidErrorCode}; + } () == common_error::kInvalidArgument + ); + EXPECT_TRUE( + [] () -> expect { + MONERO_CHECK(expect{}); + return {common_error::kInvalidErrorCode}; + } () == common_error::kInvalidErrorCode + ); + EXPECT_TRUE( + [] () -> expect { + MONERO_CHECK(expect{common_error::kInvalidArgument}); + return {common_error::kInvalidErrorCode}; + } () == common_error::kInvalidArgument + ); + + EXPECT_NO_THROW(MONERO_UNWRAP(success())); + EXPECT_NO_THROW(MONERO_UNWRAP(expect{})); + EXPECT_NO_THROW(MONERO_UNWRAP(expect{0})); + EXPECT_THROW( + MONERO_UNWRAP(expect{common_error::kInvalidArgument}), std::system_error + ); + EXPECT_THROW( + MONERO_UNWRAP(expect{common_error::kInvalidArgument}), std::system_error + ); +} + -- cgit v1.2.3