diff options
Diffstat (limited to 'tests/unit_tests')
-rw-r--r-- | tests/unit_tests/CMakeLists.txt | 1 | ||||
-rw-r--r-- | tests/unit_tests/bulletproofs.cpp | 32 | ||||
-rw-r--r-- | tests/unit_tests/epee_utils.cpp | 57 | ||||
-rw-r--r-- | tests/unit_tests/expect.cpp | 915 |
4 files changed, 1004 insertions, 1 deletions
diff --git a/tests/unit_tests/CMakeLists.txt b/tests/unit_tests/CMakeLists.txt index 741bb1882..d6bcbde46 100644 --- a/tests/unit_tests/CMakeLists.txt +++ b/tests/unit_tests/CMakeLists.txt @@ -47,6 +47,7 @@ set(unit_tests_sources epee_boosted_tcp_server.cpp epee_levin_protocol_handler_async.cpp epee_utils.cpp + expect.cpp fee.cpp json_serialization.cpp get_xtype_from_string.cpp diff --git a/tests/unit_tests/bulletproofs.cpp b/tests/unit_tests/bulletproofs.cpp index 45075c63d..ac6eaca0b 100644 --- a/tests/unit_tests/bulletproofs.cpp +++ b/tests/unit_tests/bulletproofs.cpp @@ -34,6 +34,8 @@ #include "ringct/rctOps.h" #include "ringct/rctSigs.h" #include "ringct/bulletproofs.h" +#include "cryptonote_basic/blobdatatype.h" +#include "cryptonote_basic/cryptonote_format_utils.h" #include "device/device.hpp" #include "misc_log_ex.h" @@ -244,3 +246,33 @@ TEST(bulletproofs, invalid_torsion) proof.T2 = org_T2; } } + +TEST(bulletproof, weight_equal) +{ + static const char *tx_hex = "02000102000b849b08f2b70b9891019707a8081bc7040d9f0b55d3019669afc83528a6e18454cf13ca392a581098c067df30e66dee8aaddf14c61a8f020002775faa070d3b3ab1d9de66deb402f635aca2580191bce277c26fef7c00cb3f3500025c9c10a978bfe085d42a7b73980f53eab4cbfde73d8023e21978ec8a467375e22101a340cd8bc95636a0ba6ffe5ebfda5eb637d44ad73c32150a469008cb870d22aa03d0cca632f376c5417327569d497d42f09386c5dd4b5efecd9dd20719861ef5aed810e70d824e8e77189c35e6d79993eeeea77b219106df29dd9e77370e7f2fb5ead175064ba8a59397a3ce6804bde23b4d90039c5ad4d1282bc23f791221bc185d70b30d84dda556348a3b9af09513946a03c190b9c53fbeb970a286b1ff8d462630ef0a2737ff40f238461e8ed3eedb8f2a01492abcb96e116ae9d51c4b35e9ba2f3bbe78228618f17a5708c0e30a47b7ed15d4a20ded508f9daddd92e07c6e74167cdf0100000099c4e562de6abd309b4cc26ab41aac39eb0eb252468f79bc5369eae8ba7f94ef2d795fb6b61a0e69e6a95dd3e257615188e80bc1c90c5f571028bb9d2b99c13d41a1e1a770e592ae7a9cda9014f6d4f3233d30f062b774a7241b6e0bb0b83b4a3e36200234a288fcf65cf8a35dfd7710dc5ece5d7abb5ec58451f1cbd41513b1bb6190c609c25e2a2b94eadfe22e8a9eb28ea3d16fa49cb1eb4d7f5c3706b50e7ae60cedf6af2c3e8dc8f96113c029749ae2b266090cc2e6650cf0a869f6c20b0792987702834ff278516dccbd3cff94a6ff36361178a302b37a62c9134b50739228430306ff2bc6a6d282d4cfa9bf6b92486f0e0dd594f2334296e248514c28436b3e86f9d527a8b1ed9f6ed09fa48514364df41d50cb3d376b71b3585cad9de30c465302ae91818ce42eb77e26a31242b4f1255f455df49409197a6d0e468f2c2d781684bb697a785ac77d41950901e9b67a2a4d6a3ec05fffec9e3a0313c972120ac3f5e01f1bc595438d7e07ff6de4ede96915a8696bcbaf449fae978565eceaebe2c3bd2f8315c535ff25fa8924fc2d49e0cb7ecc1c3fd72ce821513fa113078fda233e1588022c6267ba2f78a8a4f9ac8c7ea2dc4dca464902f46fb92702db8d26afa628f2aa182c2b34768a2b0581e7196ce041e73924af51d713db75093bf292e4263be8fc08a0b2f531e1a10ce79b95ab1fab726478cea8e79e0313ffc895069938ecf7ed14a037577f4f461ae6cde9bae6ade8a1d9e46040321b250d7ff9f3612b278757717596040dc58e7f68687b72c1ba71f36daeeb7ebdcbfd77d3518dff7d0fee252887ee38db33dffd714924d5823c539288d581eba17053beb273a13ca6f43132da705308bdc53c80c45e347bffb5c1fae7907369598660ce2c70d34083fec197b914c3b77f50e57ec54d89d0031df92a1241d40f9ea3ed14008ecc339323118ad22adca5c56687f854bc5fd47a3223016eee46e7d94b31a101df22d87b1404bbceaaaab2a8bde72aa318d3364e8926119d792cad21e51faf0cbd5ea0bbe939c5bcfbaa489dfda38aa124f3fc007b9e58f55ad8acd25d17a40bd4c1c17e03610fecb789702b0b8a4aa3a79028a7292212c550dec72f2c356f02bc0f2a0513ae07892143b8aa5ab30e9f6d71eeb3df2ea64a839b5b857000db043bf506a26953a909116b10cdce03a27d549db2f51f9a341c721bb0e442b5d0034038fbb0cd2ef27fb48f5acbd6b4104af18a98a1692d10d59884fcd2eb4641000ac32df57b5dcf387c4c097e5e7e702b2f07cdb18a69d5c69a5f7e135a9f8e020670758a1e4d955878de2f93181adfddd8cff4d20365c4663e870ff09d6b15065bbd81555d6aeb92e07ebbeae426cd0ab982a03ffeec31627ae140cd1e78f60ab6a55811d9d4051d50050c9e920e0b11c526530e613e0d3f925271f90ef0990e3df2c46170153e553a0035c0e8e87d957f40f072fd6b1ff30ee7aca3af88c40f1c255b3546dba9d23f352c729a0466729918336560df233843734e7dad57960f8d5592a299f6b762efdbd37aa0ff5310c940d03622023146a042079c8097fe01606594ab3578d0c0a90f8088d5c93504896ed80e809d22bf9483bf62398feb06099904cc23480b27709845ef1e26059d4730aeb5c2bb34c2ff34bff3c1a1c10a5898584fac078225bd435541fd2f4244e14118c8a08af7a3027d41b7af62420d12ba05466f905fe49882db44994180a1a549acfec42549254feda65aa6ee0c0e35e5a7525ae373ea0053fd536d4b6605ee833a0fa85e863807c30f02b46fde0305864da7d10f60b44ec1c2944a45de27912a39cebdc0ae18034397e4f5cfaf0ebe9ea5b225e80075f1bf6ac2211b7512870cc556e685a2464bf91100b36e5d0ea64af85d92d2aa1c2625e5bcbe93352a92dec8d735e54a2e6dfba6a91cc7c40e5c883d932769ce2d57b21ba898a2437ae6a39cfda1f3adefab0241548ad88104cbf113df4d1a243a5ae639b75169ae60b2c0dd1091a994e2a4d6d3536e3f4405a723c50ba4e9f822a2de189fd8158b0aa94c4b6255e5d4b504f789e4036d4206e8afd25693198f7bb3b04c23a6dc83f09260ae7c83726d4d524e7f9f851c39f5"; + cryptonote::blobdata bd; + ASSERT_TRUE(epee::string_tools::parse_hexstr_to_binbuff(std::string(tx_hex), bd)); + cryptonote::transaction tx; + crypto::hash tx_hash, tx_prefix_hash; + ASSERT_TRUE(parse_and_validate_tx_from_blob(bd, tx, tx_hash, tx_prefix_hash)); + ASSERT_TRUE(tx.version == 2); + ASSERT_TRUE(rct::is_rct_bulletproof(tx.rct_signatures.type)); + const uint64_t tx_size = bd.size(); + const uint64_t tx_weight = cryptonote::get_transaction_weight(tx); + ASSERT_TRUE(tx_weight == tx_size); // it has two outputs, <= 2 makes weight == size +} + +TEST(bulletproof, weight_more) +{ + static const char *tx_hex = "02000102000be98714944aeb01c006c80cbd0aaa04e5023e9003fa089669afc83528a6e18454cf13ca392a581098c067df30e66dee8aaddf14c61a8f040002377a0483ad63d58e7667a8325349c89e41e9ad5dce5aef30204fd4a6dc8eb7a100022a518afc3d690a992150646c559a24add698c98e87e732244cf2855cb7d0cff10002485a8de9d099c96fce8f26ad320cd627a6bb188f719c380517861c031aa65011000218ebf7b40a5ba25fb98ad7c6543239c2a3343b9e7cfd5140280e587c8f930f0d2101b330267408724dcf7fc2902e7d74a7962995e7905cc5d043fa1c8c6379e0eccd03e089bb498d0fffca61afd0d61f4875e8b32fa63f8729c654bba5f167199b7b518433680242640504c7568d273b2a74fe2d204dbb97eea4724ee5a2cf19eb3349ec3a2602a244de2a33c62bbfaa0b4cb85bf36863f765b237138929e43462e4bf19684d0924fd73c30bee474f0e927e8eb84dd6cc987acaf41e19e2f1e07381bd95e0f504964c8d10793972e88d64683a4a3960a9645735a76cc62d99e7a87b62c3cb590ca9dc27f91e9103c1b55ece5d5a932a04c99bf019463455b5d78397bd2295be075af5ae9bf0e43e724e11f83f336ca3c1bd9601c7fd6642795e8618b5c5b9d0045a6766daf2118f994b418504c6939b94c72e875423989ea7069d73e8d02f7b0bd9c1c7eb2289eaeda5fabd8142ee0ebafcbe101c58e99034d0c9ca34a703180e1dd7000e9f11cb4bcbe11f0c0041a0cc30f5b8b3bd7f2ace0266dd0282aea17f088c88e98a22f764e32507d1c900ef50b1157b49dbfda2fd9a2ea3be5182fb10fa590b464907049d88ff9c33fbe6d8b05898abf196dd097e1009d9bd1a1997830100000006ccdcc8aa53e183578656540fa393e6d9f96c07497b9dd009b48e8f990a75be18f5f37a47ff07f3c4d6427626afc5d24897ad31a98d01cc44476fba41f6bc3dc3de91d2655130090393e3ebcb7f436470edefff5aa11fa1016fecccf1824a5cdd66ea51dcd8f0193a6e507309d6a13680605febb971c3df4cceac5078be996c0d686c72627696e6961447145143e23cae2c97686524c0587b6cce7b05851b087d658a795bd22de18c0f68e824e1673c47f4b7f4ba7d4bedd95f46ffc22d9409087a58a80088679d3775e46f75dc6dc48f485a2c35a8dd60e7dabe29f656cbaad8d25a5e01d165fa9df29acd6e2471c4880d3129fd110066788de9c979f03d9c2e46ab80bf0dbd24ac6aaba2db0d723e1ba3a002efd2aebf245a2fd53767fa490244396284826b64a4a3f069f21047486a27c5ebdf802c23d8d276b9c83fa2e329aefb953ad34f382975204706c14249a496791cd3d20f4bd98d8f6325f5e7d7aa2d1f8b23361434f74584136cf1ead94365a6ce134159141fa4c68660a99ad90caa8c711abe5411dffa7132f8ce71dba63619e1410380c56766c79ff8e433eb806f49bca6f1bcb0c66dfd61c3133e7c095a11abd068b6a5774a02a5825cbd82a408d5580ee4dbe9a4ba07282f5a764279ad27f7ac27e7cccb3c76b5dd64be7bbdf3ecc4abcc29bc561e81cbc502ed3a4ce277b567a6eb09dfd8454c4d4e8c038b9dd6042a0515b0d1dfbb45585e79ca5705a22fcb3c67bc0261cc0cec6998354448e83fa7ff8706178e14a482e73719df33c9d753757131f3560391be2dd6c40391e3e7882ea07bb23c4d2d157349965082e1447e94849fde224452f6c98efa44f6438b731859fac8f49761e4447e8d34275e7dd9ae01d8550dcc75284715e026d25e9c444265fb4fee3f783ff2a2a5c414714a57525738884bbdbd8d997dbbcafcafd8e283b524bef0ded141160f47ce352b2104257b312d12594de45a0241d9753ec19e2f8603b5fc8682d72bf1de51d7f4caa7026989a7e46b9dd41075ad480df9de6a952e8562e548e3576e9c9230cb2cd0ee7f955e2d29240d7fa55b8e0b0b6c92823d9636592c460af670bb0b8714ca626497c68403793fe8495a7542c60587d117e3adb3644e62053817fa600910e2dfad97b2a7492ac6fa13c0a9a03e0ce12c3d12a09a4e22b9d0d74b9d431d53252fcbd06cb119d128646042eef81002fc6e9ff5006e06247f40f0391ad095c0d50a78863c975edbf0498e58ba7e6e0505d5eaa4d8ba2aa3f40e728f1a6aef6b2f9f5705cc3d2591bb5b878c258b4107857dc6ee75d591ea7af7b16196cd6c979a0bf819db39658491889c83a41c2c0035116fcac23ac45144731592ea0e3a11c335a278b2a6798d46828c8590b92701468e9d9c3560ed58c3ab861995aca439ee49ecf4a5b0ad160a12bd23a437f90c383095e85a95bb441bcb8dc1752e805e85d1ee0f6967ce95dcd888efa7ac440813c78b11d56d2a1b870c59d36430b10cd28bc693c4f64e769acfbcff27d8e904e0ca7e73aab5439de571b66f91fe9c05264e070aa223b68e5de763d838985e0ec0e8ac0dd0b1f6eb1e145c4473f9edda5732b1f9d3627423b5c60e055377bd044ff30017d25b3d26b5590b53d8aeaf10ce73d86fe4c40fa14e6f710f72c7da0600e7fc495a75a875d1aeee246b70cf24a8a85fba2d31f96faa42ece112b9030987ce0e735ab51eb4222a48bc51ab69d644bda77fb2aa0cd3a0477a2a2d92510103dbd58ee1c28eb20cfb31f5268f4a70a431ff4aedbfdfc59ea6709283a51902202effba960da6170b1a25c26a52890da54757c93156d250540590266eed8c00647270cb302cff7cbe4a8ed27da21dbaa303d1aea0eb152e1f6fd24dbdfaea0c5b0f5d6acb6724cf711ec3194a94f52f8cce13e1e3d1d7758d3d7e3cd37fd1011265199eb4126975687ce958dd1a75b6a71cf397fb618003e85af842dc3ff50a134411bbe18a1dea4beeb1e8d1ca5ac67f7f6ce2bbdeb2efcf6dcfdef64b360d4fb1849947800a3595e0a8029b631a06508b5d9f4f6e6a1be110524e5584f209b9db1651ddc8571102a58e7823dcf026f89d59ca213b6c6e32088d6c4967b20b28ffe86aed6c11d6aa0072691ff133d7bbc6d013629faebadc087c0f4f84d106677013893be4ca55018fbafcc2cee8be4ad0bcf1ad8762ec0c285e8c414bb204"; + cryptonote::blobdata bd; + ASSERT_TRUE(epee::string_tools::parse_hexstr_to_binbuff(std::string(tx_hex), bd)); + cryptonote::transaction tx; + crypto::hash tx_hash, tx_prefix_hash; + ASSERT_TRUE(parse_and_validate_tx_from_blob(bd, tx, tx_hash, tx_prefix_hash)); + ASSERT_TRUE(tx.version == 2); + ASSERT_TRUE(rct::is_rct_bulletproof(tx.rct_signatures.type)); + const uint64_t tx_size = bd.size(); + const uint64_t tx_weight = cryptonote::get_transaction_weight(tx); + ASSERT_TRUE(tx_weight > tx_size); // it has four outputs, > 2 makes weight > size +} diff --git a/tests/unit_tests/epee_utils.cpp b/tests/unit_tests/epee_utils.cpp index 3474000d8..c2b0b7647 100644 --- a/tests/unit_tests/epee_utils.cpp +++ b/tests/unit_tests/epee_utils.cpp @@ -166,12 +166,17 @@ TEST(Span, Traits) TEST(Span, MutableConstruction) { struct no_conversion{}; + struct inherited : no_conversion {}; EXPECT_TRUE(std::is_constructible<epee::span<char>>()); EXPECT_TRUE((std::is_constructible<epee::span<char>, char*, std::size_t>())); EXPECT_FALSE((std::is_constructible<epee::span<char>, const char*, std::size_t>())); EXPECT_FALSE((std::is_constructible<epee::span<char>, unsigned char*, std::size_t>())); + EXPECT_TRUE(std::is_constructible<epee::span<no_conversion>>()); + EXPECT_TRUE((std::is_constructible<epee::span<no_conversion>, no_conversion*, std::size_t>())); + EXPECT_FALSE((std::is_constructible<epee::span<no_conversion>, inherited*, std::size_t>())); + EXPECT_TRUE((can_construct<epee::span<char>, std::nullptr_t>())); EXPECT_TRUE((can_construct<epee::span<char>, char(&)[1]>())); @@ -193,12 +198,19 @@ TEST(Span, MutableConstruction) TEST(Span, ImmutableConstruction) { struct no_conversion{}; + struct inherited : no_conversion {}; EXPECT_TRUE(std::is_constructible<epee::span<const char>>()); EXPECT_TRUE((std::is_constructible<epee::span<const char>, char*, std::size_t>())); EXPECT_TRUE((std::is_constructible<epee::span<const char>, const char*, std::size_t>())); EXPECT_FALSE((std::is_constructible<epee::span<const char>, unsigned char*, std::size_t>())); + EXPECT_TRUE(std::is_constructible<epee::span<const no_conversion>>()); + EXPECT_TRUE((std::is_constructible<epee::span<const no_conversion>, const no_conversion*, std::size_t>())); + EXPECT_TRUE((std::is_constructible<epee::span<const no_conversion>, no_conversion*, std::size_t>())); + EXPECT_FALSE((std::is_constructible<epee::span<const no_conversion>, const inherited*, std::size_t>())); + EXPECT_FALSE((std::is_constructible<epee::span<const no_conversion>, inherited*, std::size_t>())); + EXPECT_FALSE((can_construct<epee::span<const char>, std::string>())); EXPECT_FALSE((can_construct<epee::span<const char>, std::vector<char>>())); EXPECT_FALSE((can_construct<epee::span<const char>, const std::vector<char>>())); @@ -231,7 +243,6 @@ TEST(Span, NoExcept) const epee::span<char> clvalue(data); EXPECT_TRUE(noexcept(epee::span<char>())); EXPECT_TRUE(noexcept(epee::span<char>(nullptr))); - EXPECT_TRUE(noexcept(epee::span<char>(nullptr, 0))); EXPECT_TRUE(noexcept(epee::span<char>(data))); EXPECT_TRUE(noexcept(epee::span<char>(lvalue))); EXPECT_TRUE(noexcept(epee::span<char>(clvalue))); @@ -284,6 +295,25 @@ TEST(Span, Writing) EXPECT_TRUE(boost::range::equal(expected, span)); } +TEST(Span, RemovePrefix) +{ + const std::array<unsigned, 4> expected{0, 1, 2, 3}; + auto span = epee::to_span(expected); + + EXPECT_EQ(expected.begin(), span.begin()); + EXPECT_EQ(expected.end(), span.end()); + + EXPECT_EQ(2u, span.remove_prefix(2)); + EXPECT_EQ(expected.begin() + 2, span.begin()); + EXPECT_EQ(expected.end(), span.end()); + + EXPECT_EQ(2u, span.remove_prefix(3)); + EXPECT_EQ(span.begin(), span.end()); + EXPECT_EQ(expected.end(), span.begin()); + + EXPECT_EQ(0u, span.remove_prefix(100)); +} + TEST(Span, ToByteSpan) { const char expected[] = {56, 44, 11, 5}; @@ -318,6 +348,30 @@ TEST(Span, AsByteSpan) ); } +TEST(Span, AsMutByteSpan) +{ + struct some_pod { char value[4]; }; + some_pod actual {}; + + auto span = epee::as_mut_byte_span(actual); + boost::range::iota(span, 1); + EXPECT_TRUE( + boost::range::equal( + std::array<unsigned char, 4>{{1, 2, 3, 4}}, actual.value + ) + ); +} + +TEST(Span, ToMutSpan) +{ + std::vector<unsigned> mut; + mut.resize(4); + + auto span = epee::to_mut_span(mut); + boost::range::iota(span, 1); + EXPECT_EQ((std::vector<unsigned>{1, 2, 3, 4}), mut); +} + TEST(ToHex, String) { EXPECT_TRUE(epee::to_hex::string(nullptr).empty()); @@ -330,6 +384,7 @@ TEST(ToHex, String) EXPECT_EQ( std_to_hex(all_bytes), epee::to_hex::string(epee::to_span(all_bytes)) ); + } TEST(ToHex, Array) 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 <gtest/gtest.h> + +#include <boost/algorithm/string/predicate.hpp> +#include <boost/utility/string_ref.hpp> +#include <string> +#include <system_error> +#include <type_traits> + +#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<typename T> + void construction_bench() + { + EXPECT_TRUE(std::is_copy_constructible<expect<T>>()); + EXPECT_TRUE(std::is_move_constructible<expect<T>>()); + EXPECT_TRUE(std::is_copy_assignable<expect<T>>()); + EXPECT_TRUE(std::is_move_assignable<expect<T>>()); + EXPECT_TRUE(std::is_destructible<expect<T>>()); + } + + template<typename T> + void noexcept_bench() + { + EXPECT_TRUE(std::is_nothrow_copy_constructible<expect<T>>()); + EXPECT_TRUE(std::is_nothrow_move_constructible<expect<T>>()); + EXPECT_TRUE(std::is_nothrow_copy_assignable<expect<T>>()); + EXPECT_TRUE(std::is_nothrow_move_assignable<expect<T>>()); + EXPECT_TRUE(std::is_nothrow_destructible<expect<T>>()); + + EXPECT_TRUE(noexcept(bool(std::declval<expect<T>>()))); + EXPECT_TRUE(noexcept(std::declval<expect<T>>().has_error())); + EXPECT_TRUE(noexcept(std::declval<expect<T>>().error())); + EXPECT_TRUE(noexcept(std::declval<expect<T>>().equal(std::declval<expect<T>>()))); + EXPECT_TRUE(noexcept(std::declval<expect<T>>() == std::declval<expect<T>>())); + EXPECT_TRUE(noexcept(std::declval<expect<T>>() != std::declval<expect<T>>())); + } + + template<typename T> + void conversion_bench() + { + EXPECT_TRUE((std::is_convertible<std::error_code, expect<T>>())); + EXPECT_TRUE((std::is_convertible<std::error_code&&, expect<T>>())); + EXPECT_TRUE((std::is_convertible<std::error_code&, expect<T>>())); + EXPECT_TRUE((std::is_convertible<std::error_code const&, expect<T>>())); + + EXPECT_TRUE((std::is_constructible<expect<T>, std::error_code>())); + EXPECT_TRUE((std::is_constructible<expect<T>, std::error_code&&>())); + EXPECT_TRUE((std::is_constructible<expect<T>, std::error_code&>())); + EXPECT_TRUE((std::is_constructible<expect<T>, std::error_code const&>())); + } +} + + +TEST(Expect, Constructions) +{ + construction_bench<void>(); + construction_bench<int>(); + + EXPECT_TRUE(std::is_constructible<expect<void>>()); + + EXPECT_TRUE((std::is_constructible<expect<throw_construct>, expect<int>>())); + + EXPECT_TRUE(std::is_move_constructible<expect<move_only>>()); + EXPECT_TRUE(std::is_move_assignable<expect<move_only>>()); +} + +TEST(Expect, Conversions) +{ + struct implicit { implicit(int) {} }; + struct explicit_only { explicit explicit_only(int) {} }; + + conversion_bench<void>(); + conversion_bench<int>(); + + EXPECT_TRUE((std::is_convertible<int, expect<int>>())); + EXPECT_TRUE((std::is_convertible<int&&, expect<int>>())); + EXPECT_TRUE((std::is_convertible<int&, expect<int>>())); + EXPECT_TRUE((std::is_convertible<int const, expect<int>>())); + EXPECT_TRUE((std::is_convertible<expect<unsigned>, expect<int>>())); + EXPECT_TRUE((std::is_convertible<expect<unsigned>&&, expect<int>>())); + EXPECT_TRUE((std::is_convertible<expect<unsigned>&, expect<int>>())); + EXPECT_TRUE((std::is_convertible<expect<unsigned> const&, expect<int>>())); + EXPECT_TRUE((std::is_convertible<expect<int>, expect<implicit>>())); + EXPECT_TRUE((std::is_convertible<expect<int>&&, expect<implicit>>())); + EXPECT_TRUE((std::is_convertible<expect<int>&, expect<implicit>>())); + EXPECT_TRUE((std::is_convertible<expect<int> const&, expect<implicit>>())); + EXPECT_TRUE(!(std::is_convertible<expect<int>, expect<explicit_only>>())); + EXPECT_TRUE(!(std::is_convertible<expect<int>&&, expect<explicit_only>>())); + EXPECT_TRUE(!(std::is_convertible<expect<int>&, expect<explicit_only>>())); + EXPECT_TRUE(!(std::is_convertible<expect<int> const&, expect<explicit_only>>())); + + EXPECT_TRUE((std::is_constructible<expect<int>, int>())); + EXPECT_TRUE((std::is_constructible<expect<int>, int&&>())); + EXPECT_TRUE((std::is_constructible<expect<int>, int&>())); + EXPECT_TRUE((std::is_constructible<expect<int>, int const&>())); + EXPECT_TRUE((std::is_constructible<expect<int>, expect<unsigned>>())); + EXPECT_TRUE((std::is_constructible<expect<int>, expect<unsigned>&&>())); + EXPECT_TRUE((std::is_constructible<expect<int>, expect<unsigned>&>())); + EXPECT_TRUE((std::is_constructible<expect<int>, expect<unsigned> const&>())); + EXPECT_TRUE((std::is_constructible<expect<implicit>, expect<int>>())); + EXPECT_TRUE((std::is_constructible<expect<implicit>, expect<int>&&>())); + EXPECT_TRUE((std::is_constructible<expect<implicit>, expect<int>&>())); + EXPECT_TRUE((std::is_constructible<expect<implicit>, expect<int> const&>())); + EXPECT_TRUE(!(std::is_constructible<expect<explicit_only>, expect<int>>())); + EXPECT_TRUE(!(std::is_constructible<expect<explicit_only>, expect<int>&&>())); + EXPECT_TRUE(!(std::is_constructible<expect<explicit_only>, expect<int>&>())); + EXPECT_TRUE(!(std::is_constructible<expect<explicit_only>, expect<int> const&>())); + + EXPECT_EQ(expect<int>{expect<short>{100}}.value(), 100); + + expect<std::string> val1{std::string{}}; + expect<const char*> val2{"foo"}; + + EXPECT_EQ(val1.value(), std::string{}); + EXPECT_EQ(val2.value(), std::string{"foo"}); + + const expect<std::string> 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<void>(); + noexcept_bench<int>(); + + EXPECT_TRUE(std::is_nothrow_constructible<expect<void>>()); + + EXPECT_TRUE((std::is_nothrow_constructible<expect<int>, int>())); + EXPECT_TRUE((std::is_nothrow_constructible<expect<int>, expect<unsigned>>())); + EXPECT_TRUE((std::is_nothrow_constructible<expect<int>, expect<unsigned>&&>())); + EXPECT_TRUE((std::is_nothrow_constructible<expect<int>, expect<unsigned>&>())); + EXPECT_TRUE((std::is_nothrow_constructible<expect<int>, expect<unsigned> const&>())); + + EXPECT_TRUE(noexcept(expect<int>{std::declval<expect<unsigned>&&>()})); + EXPECT_TRUE(noexcept(expect<int>{std::declval<expect<unsigned> const&>()})); + EXPECT_TRUE(noexcept(std::declval<expect<int>>().has_value())); + EXPECT_TRUE(noexcept(*std::declval<expect<int>>())); + EXPECT_TRUE(noexcept(std::declval<expect<int>>().equal(std::declval<expect<unsigned>>()))); + EXPECT_TRUE(noexcept(std::declval<expect<unsigned>>().equal(std::declval<expect<int>>()))); + EXPECT_TRUE(noexcept(std::declval<expect<int>>().equal(0))); + EXPECT_TRUE(noexcept(std::declval<expect<int>>() == std::declval<expect<unsigned>>())); + EXPECT_TRUE(noexcept(std::declval<expect<unsigned>>() == std::declval<expect<int>>())); + EXPECT_TRUE(noexcept(std::declval<expect<int>>() == 0)); + EXPECT_TRUE(noexcept(0 == std::declval<expect<int>>())); + EXPECT_TRUE(noexcept(std::declval<expect<int>>() != std::declval<expect<unsigned>>())); + EXPECT_TRUE(noexcept(std::declval<expect<unsigned>>() != std::declval<expect<int>>())); + EXPECT_TRUE(noexcept(std::declval<expect<int>>() != 0)); + EXPECT_TRUE(noexcept(0 != std::declval<expect<int>>())); + + EXPECT_TRUE((std::is_nothrow_constructible<expect<throw_construct>, std::error_code>())); + EXPECT_TRUE((std::is_nothrow_constructible<expect<throw_construct>, std::error_code&&>())); + EXPECT_TRUE((std::is_nothrow_constructible<expect<throw_construct>, std::error_code&>())); + EXPECT_TRUE((std::is_nothrow_constructible<expect<throw_construct>, std::error_code const&>())); + EXPECT_TRUE((std::is_nothrow_constructible<expect<throw_construct>, throw_construct>())); + EXPECT_TRUE((std::is_nothrow_constructible<expect<throw_construct>, throw_construct&&>())); + EXPECT_TRUE((std::is_nothrow_constructible<expect<throw_construct>, throw_construct&>())); + EXPECT_TRUE((std::is_nothrow_constructible<expect<throw_construct>, throw_construct const&>())); + EXPECT_TRUE(!(std::is_nothrow_constructible<expect<throw_construct>, expect<int>>())); + EXPECT_TRUE(!(std::is_nothrow_constructible<expect<throw_construct>, expect<int>&&>())); + EXPECT_TRUE(!(std::is_nothrow_constructible<expect<throw_construct>, expect<int>&>())); + EXPECT_TRUE(!(std::is_nothrow_constructible<expect<throw_construct>, expect<int> const&>())); + EXPECT_TRUE(std::is_nothrow_copy_constructible<expect<throw_construct>>()); + EXPECT_TRUE(std::is_nothrow_move_constructible<expect<throw_construct>>()); + EXPECT_TRUE(std::is_nothrow_copy_assignable<expect<throw_construct>>()); + EXPECT_TRUE(std::is_nothrow_move_assignable<expect<throw_construct>>()); + EXPECT_TRUE(std::is_nothrow_destructible<expect<throw_construct>>()); + + EXPECT_TRUE((std::is_nothrow_constructible<expect<throw_copies>, std::error_code>())); + EXPECT_TRUE((std::is_nothrow_constructible<expect<throw_copies>, std::error_code&&>())); + EXPECT_TRUE((std::is_nothrow_constructible<expect<throw_copies>, std::error_code&>())); + EXPECT_TRUE((std::is_nothrow_constructible<expect<throw_copies>, std::error_code const&>())); + EXPECT_TRUE((std::is_nothrow_constructible<expect<throw_copies>, throw_copies>())); + EXPECT_TRUE((std::is_nothrow_constructible<expect<throw_copies>, throw_copies&&>())); + EXPECT_TRUE(!(std::is_nothrow_constructible<expect<throw_copies>, throw_copies&>())); + EXPECT_TRUE(!(std::is_nothrow_constructible<expect<throw_copies>, throw_copies const&>())); + EXPECT_TRUE(!std::is_nothrow_copy_constructible<expect<throw_copies>>()); + EXPECT_TRUE(std::is_nothrow_move_constructible<expect<throw_copies>>()); + EXPECT_TRUE(!std::is_nothrow_copy_assignable<expect<throw_copies>>()); + EXPECT_TRUE(std::is_nothrow_move_assignable<expect<throw_copies>>()); + EXPECT_TRUE(std::is_nothrow_destructible<expect<throw_copies>>()); + EXPECT_TRUE(noexcept(std::declval<expect<throw_copies>>().equal(std::declval<expect<throw_copies>>()))); + EXPECT_TRUE(noexcept(std::declval<expect<throw_copies>>().equal(std::declval<throw_copies>()))); + EXPECT_TRUE(noexcept(std::declval<expect<throw_copies>>() == std::declval<expect<throw_copies>>())); + EXPECT_TRUE(noexcept(std::declval<expect<throw_copies>>() == std::declval<throw_copies>())); + EXPECT_TRUE(noexcept(std::declval<throw_copies>() == std::declval<expect<throw_copies>>())); + EXPECT_TRUE(noexcept(std::declval<expect<throw_copies>>() != std::declval<expect<throw_copies>>())); + EXPECT_TRUE(noexcept(std::declval<expect<throw_copies>>() != std::declval<throw_copies>())); + EXPECT_TRUE(noexcept(std::declval<throw_copies>() != std::declval<expect<throw_copies>>())); + EXPECT_TRUE(noexcept(std::declval<expect<throw_copies>>().equal(std::declval<expect<throw_moves>>()))); + EXPECT_TRUE(noexcept(std::declval<expect<throw_copies>>().equal(std::declval<throw_moves>()))); + EXPECT_TRUE(noexcept(std::declval<expect<throw_copies>>() == std::declval<expect<throw_moves>>())); + EXPECT_TRUE(noexcept(std::declval<expect<throw_copies>>() == std::declval<throw_moves>())); + EXPECT_TRUE(noexcept(std::declval<throw_moves>() == std::declval<expect<throw_copies>>())); + EXPECT_TRUE(noexcept(std::declval<expect<throw_copies>>() != std::declval<expect<throw_moves>>())); + EXPECT_TRUE(noexcept(std::declval<expect<throw_copies>>() != std::declval<throw_moves>())); + EXPECT_TRUE(noexcept(std::declval<throw_moves>() != std::declval<expect<throw_copies>>())); + + EXPECT_TRUE((std::is_nothrow_constructible<expect<throw_moves>, std::error_code>())); + EXPECT_TRUE((std::is_nothrow_constructible<expect<throw_moves>, std::error_code&&>())); + EXPECT_TRUE((std::is_nothrow_constructible<expect<throw_moves>, std::error_code&>())); + EXPECT_TRUE((std::is_nothrow_constructible<expect<throw_moves>, std::error_code const&>())); + EXPECT_TRUE(!(std::is_nothrow_constructible<expect<throw_moves>, throw_moves>())); + EXPECT_TRUE(!(std::is_nothrow_constructible<expect<throw_moves>, throw_moves&&>())); + EXPECT_TRUE(!(std::is_nothrow_constructible<expect<throw_moves>, throw_moves&>())); + EXPECT_TRUE(!(std::is_nothrow_constructible<expect<throw_moves>, throw_moves const&>())); + EXPECT_TRUE(std::is_nothrow_copy_constructible<expect<throw_moves>>()); + EXPECT_TRUE(!std::is_nothrow_move_constructible<expect<throw_moves>>()); + EXPECT_TRUE(std::is_nothrow_copy_assignable<expect<throw_moves>>()); + EXPECT_TRUE(!std::is_nothrow_move_assignable<expect<throw_moves>>()); + EXPECT_TRUE(std::is_nothrow_destructible<expect<throw_copies>>()); + EXPECT_TRUE(!noexcept(std::declval<expect<throw_moves>>().equal(std::declval<expect<throw_moves>>()))); + EXPECT_TRUE(!noexcept(std::declval<expect<throw_moves>>().equal(std::declval<throw_moves>()))); + EXPECT_TRUE(!noexcept(std::declval<expect<throw_moves>>() == std::declval<expect<throw_moves>>())); + EXPECT_TRUE(!noexcept(std::declval<expect<throw_moves>>() == std::declval<throw_moves>())); + EXPECT_TRUE(!noexcept(std::declval<throw_moves>() == std::declval<expect<throw_moves>>())); + EXPECT_TRUE(!noexcept(std::declval<expect<throw_moves>>() != std::declval<expect<throw_moves>>())); + EXPECT_TRUE(!noexcept(std::declval<expect<throw_moves>>() != std::declval<throw_moves>())); + EXPECT_TRUE(!noexcept(std::declval<throw_moves>() != std::declval<expect<throw_moves>>())); + EXPECT_TRUE(!noexcept(std::declval<expect<throw_moves>>().equal(std::declval<expect<throw_copies>>()))); + EXPECT_TRUE(!noexcept(std::declval<expect<throw_moves>>().equal(std::declval<throw_copies>()))); + EXPECT_TRUE(!noexcept(std::declval<expect<throw_moves>>() == std::declval<expect<throw_copies>>())); + EXPECT_TRUE(!noexcept(std::declval<expect<throw_moves>>() == std::declval<throw_copies>())); + EXPECT_TRUE(!noexcept(std::declval<throw_copies>() == std::declval<expect<throw_moves>>())); + EXPECT_TRUE(!noexcept(std::declval<expect<throw_moves>>() != std::declval<expect<throw_copies>>())); + EXPECT_TRUE(!noexcept(std::declval<expect<throw_moves>>() != std::declval<throw_copies>())); + EXPECT_TRUE(!noexcept(std::declval<throw_copies>() != std::declval<expect<throw_moves>>())); +} + +TEST(Expect, Trivial) +{ + EXPECT_TRUE(std::is_trivially_copy_constructible<expect<void>>()); + EXPECT_TRUE(std::is_trivially_move_constructible<expect<void>>()); + EXPECT_TRUE(std::is_trivially_destructible<expect<void>>()); +} + +TEST(Expect, Assignment) +{ + expect<std::string> val1{std::string{}}; + expect<std::string> 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<throw_on_move> val1{expect<const char*>{"foobar"}}; + expect<throw_on_move> 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<const char*>{"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<std::string> val1{std::string{}}; + expect<std::string> val2{"barfoo"}; + expect<boost::string_ref> 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<std::string>{"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<void> val1; + expect<void> 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<throw_on_copy> val1{expect<int>{0}}; + expect<throw_on_copy> val2{expect<int>{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<throw_on_copy> 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<void> { + MONERO_PRECOND(true); + return {common_error::kInvalidErrorCode}; + } () == common_error::kInvalidErrorCode + ); + EXPECT_TRUE( + [] () -> expect<void> { + MONERO_PRECOND(false); + return {common_error::kInvalidErrorCode}; + } () == common_error::kInvalidArgument + ); + EXPECT_TRUE( + [] () -> expect<int> { + MONERO_PRECOND(true); + return {common_error::kInvalidErrorCode}; + } () == common_error::kInvalidErrorCode + ); + EXPECT_TRUE( + [] () -> expect<int> { + MONERO_PRECOND(false); + return {common_error::kInvalidErrorCode}; + } () == common_error::kInvalidArgument + ); + + EXPECT_TRUE( + [] () -> std::error_code { + MONERO_CHECK(expect<void>{}); + return {common_error::kInvalidErrorCode}; + } () == common_error::kInvalidErrorCode + ); + EXPECT_TRUE( + [] () -> std::error_code { + MONERO_CHECK(expect<void>{common_error::kInvalidArgument}); + return {common_error::kInvalidErrorCode}; + } () == common_error::kInvalidArgument + ); + EXPECT_TRUE( + [] () -> expect<void> { + MONERO_CHECK(expect<void>{}); + return {common_error::kInvalidErrorCode}; + } () == common_error::kInvalidErrorCode + ); + EXPECT_TRUE( + [] () -> expect<void> { + MONERO_CHECK(expect<void>{common_error::kInvalidArgument}); + return {common_error::kInvalidErrorCode}; + } () == common_error::kInvalidArgument + ); + EXPECT_TRUE( + [] () -> expect<int> { + MONERO_CHECK(expect<void>{}); + return {common_error::kInvalidErrorCode}; + } () == common_error::kInvalidErrorCode + ); + EXPECT_TRUE( + [] () -> expect<int> { + MONERO_CHECK(expect<void>{common_error::kInvalidArgument}); + return {common_error::kInvalidErrorCode}; + } () == common_error::kInvalidArgument + ); + + EXPECT_NO_THROW(MONERO_UNWRAP(success())); + EXPECT_NO_THROW(MONERO_UNWRAP(expect<void>{})); + EXPECT_NO_THROW(MONERO_UNWRAP(expect<int>{0})); + EXPECT_THROW( + MONERO_UNWRAP(expect<void>{common_error::kInvalidArgument}), std::system_error + ); + EXPECT_THROW( + MONERO_UNWRAP(expect<int>{common_error::kInvalidArgument}), std::system_error + ); +} + |