aboutsummaryrefslogtreecommitdiff
path: root/tests/unit_tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests/unit_tests')
-rw-r--r--tests/unit_tests/CMakeLists.txt21
-rw-r--r--tests/unit_tests/account.cpp71
-rw-r--r--tests/unit_tests/address_from_url.cpp2
-rw-r--r--tests/unit_tests/aligned.cpp107
-rw-r--r--tests/unit_tests/ban.cpp10
-rw-r--r--tests/unit_tests/block_reward.cpp84
-rw-r--r--tests/unit_tests/blockchain_db.cpp2
-rw-r--r--tests/unit_tests/bulletproofs.cpp207
-rw-r--r--tests/unit_tests/crypto.cpp23
-rw-r--r--tests/unit_tests/device.cpp131
-rw-r--r--tests/unit_tests/epee_levin_protocol_handler_async.cpp1
-rw-r--r--tests/unit_tests/epee_utils.cpp89
-rw-r--r--tests/unit_tests/expect.cpp915
-rw-r--r--tests/unit_tests/fee.cpp54
-rw-r--r--tests/unit_tests/hardfork.cpp45
-rw-r--r--tests/unit_tests/is_hdd.cpp17
-rw-r--r--tests/unit_tests/json_serialization.cpp217
-rw-r--r--tests/unit_tests/keccak.cpp150
-rw-r--r--tests/unit_tests/main.cpp4
-rw-r--r--tests/unit_tests/mlocker.cpp195
-rw-r--r--tests/unit_tests/mnemonics.cpp30
-rw-r--r--tests/unit_tests/multiexp.cpp254
-rw-r--r--tests/unit_tests/multisig.cpp158
-rw-r--r--tests/unit_tests/notify.cpp79
-rw-r--r--tests/unit_tests/random.cpp47
-rw-r--r--tests/unit_tests/ringct.cpp63
-rw-r--r--tests/unit_tests/ringdb.cpp60
-rw-r--r--tests/unit_tests/serialization.cpp7
-rw-r--r--tests/unit_tests/test_notifier.cpp54
-rw-r--r--tests/unit_tests/test_tx_utils.cpp84
-rw-r--r--tests/unit_tests/threadpool.cpp146
-rw-r--r--tests/unit_tests/wipeable_string.cpp211
32 files changed, 3322 insertions, 216 deletions
diff --git a/tests/unit_tests/CMakeLists.txt b/tests/unit_tests/CMakeLists.txt
index 8cc074bb2..7687e3c52 100644
--- a/tests/unit_tests/CMakeLists.txt
+++ b/tests/unit_tests/CMakeLists.txt
@@ -27,6 +27,7 @@
# THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
set(unit_tests_sources
+ account.cpp
apply_permutation.cpp
address_from_url.cpp
ban.cpp
@@ -41,20 +42,28 @@ set(unit_tests_sources
command_line.cpp
crypto.cpp
decompose_amount_into_digits.cpp
+ device.cpp
dns_resolver.cpp
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
hashchain.cpp
http.cpp
+ keccak.cpp
main.cpp
memwipe.cpp
+ mlocker.cpp
mnemonics.cpp
mul_div.cpp
+ multiexp.cpp
multisig.cpp
+ notify.cpp
parse_amount.cpp
+ random.cpp
serialization.cpp
sha256.cpp
slow_memmem.cpp
@@ -62,6 +71,7 @@ set(unit_tests_sources
test_tx_utils.cpp
test_peerlist.cpp
test_protocol_pack.cpp
+ threadpool.cpp
hardfork.cpp
unbound.cpp
uri.cpp
@@ -69,7 +79,10 @@ set(unit_tests_sources
ringct.cpp
output_selection.cpp
vercmp.cpp
- ringdb.cpp)
+ ringdb.cpp
+ wipeable_string.cpp
+ is_hdd.cpp
+ aligned.cpp)
set(unit_tests_headers
unit_tests_utils.h)
@@ -84,10 +97,10 @@ target_link_libraries(unit_tests
cryptonote_core
blockchain_db
rpc
+ serialization
wallet
p2p
version
- epee
${Boost_CHRONO_LIBRARY}
${Boost_THREAD_LIBRARY}
${GTEST_LIBRARIES}
@@ -111,3 +124,7 @@ SET_PROPERTY(SOURCE memwipe.cpp PROPERTY COMPILE_FLAGS -Ofast)
add_test(
NAME unit_tests
COMMAND unit_tests --data-dir "${TEST_DATA_DIR}")
+
+add_executable(test_notifier test_notifier.cpp)
+target_link_libraries(test_notifier ${EXTRA_LIBRARIES})
+set_property(TARGET test_notifier PROPERTY FOLDER "tests")
diff --git a/tests/unit_tests/account.cpp b/tests/unit_tests/account.cpp
new file mode 100644
index 000000000..113622b5e
--- /dev/null
+++ b/tests/unit_tests/account.cpp
@@ -0,0 +1,71 @@
+// Copyright (c) 2014-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 "cryptonote_basic/account.h"
+
+TEST(account, encrypt_keys)
+{
+ cryptonote::keypair recovery_key = cryptonote::keypair::generate(hw::get_device("default"));
+ cryptonote::account_base account;
+ crypto::secret_key key = account.generate(recovery_key.sec);
+ const cryptonote::account_keys keys = account.get_keys();
+
+ ASSERT_EQ(account.get_keys().m_account_address, keys.m_account_address);
+ ASSERT_EQ(account.get_keys().m_spend_secret_key, keys.m_spend_secret_key);
+ ASSERT_EQ(account.get_keys().m_view_secret_key, keys.m_view_secret_key);
+ ASSERT_EQ(account.get_keys().m_multisig_keys, keys.m_multisig_keys);
+
+ crypto::chacha_key chacha_key;
+ crypto::generate_chacha_key(&recovery_key, sizeof(recovery_key), chacha_key, 1);
+
+ account.encrypt_keys(chacha_key);
+
+ ASSERT_EQ(account.get_keys().m_account_address, keys.m_account_address);
+ ASSERT_NE(account.get_keys().m_spend_secret_key, keys.m_spend_secret_key);
+ ASSERT_NE(account.get_keys().m_view_secret_key, keys.m_view_secret_key);
+
+ account.decrypt_viewkey(chacha_key);
+
+ ASSERT_EQ(account.get_keys().m_account_address, keys.m_account_address);
+ ASSERT_NE(account.get_keys().m_spend_secret_key, keys.m_spend_secret_key);
+ ASSERT_EQ(account.get_keys().m_view_secret_key, keys.m_view_secret_key);
+
+ account.encrypt_viewkey(chacha_key);
+
+ ASSERT_EQ(account.get_keys().m_account_address, keys.m_account_address);
+ ASSERT_NE(account.get_keys().m_spend_secret_key, keys.m_spend_secret_key);
+ ASSERT_NE(account.get_keys().m_view_secret_key, keys.m_view_secret_key);
+
+ account.decrypt_keys(chacha_key);
+
+ ASSERT_EQ(account.get_keys().m_account_address, keys.m_account_address);
+ ASSERT_EQ(account.get_keys().m_spend_secret_key, keys.m_spend_secret_key);
+ ASSERT_EQ(account.get_keys().m_view_secret_key, keys.m_view_secret_key);
+}
diff --git a/tests/unit_tests/address_from_url.cpp b/tests/unit_tests/address_from_url.cpp
index f174738fd..f6c0ad105 100644
--- a/tests/unit_tests/address_from_url.cpp
+++ b/tests/unit_tests/address_from_url.cpp
@@ -109,7 +109,7 @@ TEST(AddressFromURL, Failure)
{
bool dnssec_result = false;
- std::vector<std::string> addresses = tools::dns_utils::addresses_from_url("example.invalid", dnssec_result);
+ std::vector<std::string> addresses = tools::dns_utils::addresses_from_url("example.veryinvalid", dnssec_result);
// for a non-existing domain such as "example.invalid", the non-existence is proved with NSEC records
ASSERT_TRUE(dnssec_result);
diff --git a/tests/unit_tests/aligned.cpp b/tests/unit_tests/aligned.cpp
new file mode 100644
index 000000000..2b733faf2
--- /dev/null
+++ b/tests/unit_tests/aligned.cpp
@@ -0,0 +1,107 @@
+// 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 "common/aligned.h"
+
+TEST(aligned, large_null) { ASSERT_TRUE(aligned_malloc((size_t)-1, 1) == NULL); }
+TEST(aligned, free_null) { aligned_free(NULL); }
+TEST(aligned, zero) { void *ptr = aligned_malloc(0, 1); ASSERT_TRUE(ptr); aligned_free(ptr); }
+TEST(aligned, aligned1) { void *ptr = aligned_malloc(1, 1); ASSERT_TRUE(ptr); aligned_free(ptr); }
+TEST(aligned, aligned4096) { void *ptr = aligned_malloc(1, 4096); ASSERT_TRUE(ptr && ((uintptr_t)ptr & 4095) == 0); aligned_free(ptr); }
+TEST(aligned, aligned8) { void *ptr = aligned_malloc(1, 8); ASSERT_TRUE(ptr && ((uintptr_t)ptr & 7) == 0); aligned_free(ptr); }
+TEST(aligned, realloc_null) { void *ptr = aligned_realloc(NULL, 1, 4096); ASSERT_TRUE(ptr && ((uintptr_t)ptr & 4095) == 0); aligned_free(ptr); }
+TEST(aligned, realloc_diff_align) { void *ptr = aligned_malloc(1, 4096); ASSERT_TRUE(!aligned_realloc(ptr, 1, 2048)); aligned_free(ptr); }
+TEST(aligned, realloc_same) { void *ptr = aligned_malloc(1, 4096), *ptr2 = aligned_realloc(ptr, 1, 4096); ASSERT_TRUE(ptr == ptr2); aligned_free(ptr2); }
+TEST(aligned, realloc_larger) { void *ptr = aligned_malloc(1, 4096), *ptr2 = aligned_realloc(ptr, 2, 4096); ASSERT_TRUE(ptr != ptr2); aligned_free(ptr2); }
+TEST(aligned, realloc_zero) { void *ptr = aligned_malloc(1, 4096), *ptr2 = aligned_realloc(ptr, 0, 4096); ASSERT_TRUE(ptr && !ptr2); }
+
+TEST(aligned, contents_larger)
+{
+ unsigned char *ptr = (unsigned char*)aligned_malloc(50, 256);
+ ASSERT_TRUE(ptr);
+ for (int n = 0; n < 50; ++n)
+ ptr[n] = n;
+ unsigned char *ptr2 = (unsigned char*)aligned_realloc(ptr, 51, 256);
+ for (int n = 0; n < 50; ++n)
+ {
+ ASSERT_TRUE(ptr2[n] == n);
+ }
+ aligned_free(ptr2);
+}
+
+TEST(aligned, contents_same)
+{
+ unsigned char *ptr = (unsigned char*)aligned_malloc(50, 256);
+ ASSERT_TRUE(ptr);
+ for (int n = 0; n < 50; ++n)
+ ptr[n] = n;
+ unsigned char *ptr2 = (unsigned char*)aligned_realloc(ptr, 50, 256);
+ for (int n = 0; n < 50; ++n)
+ {
+ ASSERT_TRUE(ptr2[n] == n);
+ }
+ aligned_free(ptr2);
+}
+
+TEST(aligned, contents_smaller)
+{
+ unsigned char *ptr = (unsigned char*)aligned_malloc(50, 256);
+ ASSERT_TRUE(ptr);
+ for (int n = 0; n < 50; ++n)
+ ptr[n] = n;
+ unsigned char *ptr2 = (unsigned char*)aligned_realloc(ptr, 49, 256);
+ for (int n = 0; n < 49; ++n)
+ {
+ ASSERT_TRUE(ptr2[n] == n);
+ }
+ aligned_free(ptr2);
+}
+
+TEST(aligned, alignment)
+{
+ static const size_t good_alignments[] = {1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192};
+ for (size_t a = 0; a <= 8192; ++a)
+ {
+ bool good = false;
+ for (const auto t: good_alignments) if (a == t) good = true;
+ void *ptr = aligned_malloc(1, a);
+ if (good)
+ {
+ ASSERT_TRUE(ptr != NULL);
+ aligned_free(ptr);
+ }
+ else
+ {
+ ASSERT_TRUE(ptr == NULL);
+ }
+ }
+
+ ASSERT_TRUE(aligned_malloc(1, ~0) == NULL);
+}
diff --git a/tests/unit_tests/ban.cpp b/tests/unit_tests/ban.cpp
index 15bc0bce3..e3dbdaef1 100644
--- a/tests/unit_tests/ban.cpp
+++ b/tests/unit_tests/ban.cpp
@@ -55,7 +55,7 @@ public:
bool have_block(const crypto::hash& id) const {return true;}
void get_blockchain_top(uint64_t& height, crypto::hash& top_id)const{height=0;top_id=crypto::null_hash;}
bool handle_incoming_tx(const cryptonote::blobdata& tx_blob, cryptonote::tx_verification_context& tvc, bool keeped_by_block, bool relayed, bool do_not_relay) { return true; }
- bool handle_incoming_txs(const std::list<cryptonote::blobdata>& tx_blob, std::vector<cryptonote::tx_verification_context>& tvc, bool keeped_by_block, bool relayed, bool do_not_relay) { return true; }
+ bool handle_incoming_txs(const std::vector<cryptonote::blobdata>& tx_blob, std::vector<cryptonote::tx_verification_context>& tvc, bool keeped_by_block, bool relayed, bool do_not_relay) { return true; }
bool handle_incoming_block(const cryptonote::blobdata& block_blob, cryptonote::block_verification_context& bvc, bool update_miner_blocktemplate = true) { return true; }
void pause_mine(){}
void resume_mine(){}
@@ -65,7 +65,7 @@ public:
cryptonote::blockchain_storage &get_blockchain_storage() { throw std::runtime_error("Called invalid member function: please never call get_blockchain_storage on the TESTING class test_core."); }
bool get_test_drop_download() const {return true;}
bool get_test_drop_download_height() const {return true;}
- bool prepare_handle_incoming_blocks(const std::list<cryptonote::block_complete_entry> &blocks) { return true; }
+ bool prepare_handle_incoming_blocks(const std::vector<cryptonote::block_complete_entry> &blocks) { return true; }
bool cleanup_handle_incoming_blocks(bool force_sync = false) { return true; }
uint64_t get_target_blockchain_height() const { return 1; }
size_t get_block_sync_size(uint64_t height) const { return BLOCKS_SYNCHRONIZING_DEFAULT_COUNT; }
@@ -73,8 +73,8 @@ public:
cryptonote::network_type get_nettype() const { return cryptonote::MAINNET; }
bool get_pool_transaction(const crypto::hash& id, cryptonote::blobdata& tx_blob) const { return false; }
bool pool_has_tx(const crypto::hash &txid) const { return false; }
- bool get_blocks(uint64_t start_offset, size_t count, std::list<std::pair<cryptonote::blobdata, cryptonote::block>>& blocks, std::list<cryptonote::blobdata>& txs) const { return false; }
- bool get_transactions(const std::vector<crypto::hash>& txs_ids, std::list<cryptonote::transaction>& txs, std::list<crypto::hash>& missed_txs) const { return false; }
+ bool get_blocks(uint64_t start_offset, size_t count, std::vector<std::pair<cryptonote::blobdata, cryptonote::block>>& blocks, std::vector<cryptonote::blobdata>& txs) const { return false; }
+ bool get_transactions(const std::vector<crypto::hash>& txs_ids, std::vector<cryptonote::transaction>& txs, std::vector<crypto::hash>& missed_txs) const { return false; }
bool get_block_by_hash(const crypto::hash &h, cryptonote::block &blk, bool *orphan = NULL) const { return false; }
uint8_t get_ideal_hard_fork_version() const { return 0; }
uint8_t get_ideal_hard_fork_version(uint64_t height) const { return 0; }
@@ -82,7 +82,7 @@ public:
uint64_t get_earliest_ideal_height_for_version(uint8_t version) const { return 0; }
cryptonote::difficulty_type get_block_cumulative_difficulty(uint64_t height) const { return 0; }
bool fluffy_blocks_enabled() const { return false; }
- uint64_t prevalidate_block_hashes(uint64_t height, const std::list<crypto::hash> &hashes) { return 0; }
+ uint64_t prevalidate_block_hashes(uint64_t height, const std::vector<crypto::hash> &hashes) { return 0; }
void stop() {}
};
diff --git a/tests/unit_tests/block_reward.cpp b/tests/unit_tests/block_reward.cpp
index ca863ded9..a897e4140 100644
--- a/tests/unit_tests/block_reward.cpp
+++ b/tests/unit_tests/block_reward.cpp
@@ -40,14 +40,14 @@ namespace
class block_reward_and_already_generated_coins : public ::testing::Test
{
protected:
- static const size_t current_block_size = CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V1 / 2;
+ static const size_t current_block_weight = CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V1 / 2;
bool m_block_not_too_big;
uint64_t m_block_reward;
};
#define TEST_ALREADY_GENERATED_COINS(already_generated_coins, expected_reward) \
- m_block_not_too_big = get_block_reward(0, current_block_size, already_generated_coins, m_block_reward,1); \
+ m_block_not_too_big = get_block_reward(0, current_block_weight, already_generated_coins, m_block_reward,1); \
ASSERT_TRUE(m_block_not_too_big); \
ASSERT_EQ(m_block_reward, expected_reward);
@@ -74,7 +74,7 @@ namespace
}
//--------------------------------------------------------------------------------------------------------------------
- class block_reward_and_current_block_size : public ::testing::Test
+ class block_reward_and_current_block_weight : public ::testing::Test
{
protected:
virtual void SetUp()
@@ -84,9 +84,9 @@ namespace
ASSERT_LT(CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V1, m_standard_block_reward);
}
- void do_test(size_t median_block_size, size_t current_block_size)
+ void do_test(size_t median_block_weight, size_t current_block_weight)
{
- m_block_not_too_big = get_block_reward(median_block_size, current_block_size, already_generated_coins, m_block_reward, 1);
+ m_block_not_too_big = get_block_reward(median_block_weight, current_block_weight, already_generated_coins, m_block_reward, 1);
}
static const uint64_t already_generated_coins = 0;
@@ -96,28 +96,28 @@ namespace
uint64_t m_standard_block_reward;
};
- TEST_F(block_reward_and_current_block_size, handles_block_size_less_relevance_level)
+ TEST_F(block_reward_and_current_block_weight, handles_block_weight_less_relevance_level)
{
do_test(0, CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V1 - 1);
ASSERT_TRUE(m_block_not_too_big);
ASSERT_EQ(m_block_reward, m_standard_block_reward);
}
- TEST_F(block_reward_and_current_block_size, handles_block_size_eq_relevance_level)
+ TEST_F(block_reward_and_current_block_weight, handles_block_weight_eq_relevance_level)
{
do_test(0, CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V1);
ASSERT_TRUE(m_block_not_too_big);
ASSERT_EQ(m_block_reward, m_standard_block_reward);
}
- TEST_F(block_reward_and_current_block_size, handles_block_size_gt_relevance_level)
+ TEST_F(block_reward_and_current_block_weight, handles_block_weight_gt_relevance_level)
{
do_test(0, CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V1 + 1);
ASSERT_TRUE(m_block_not_too_big);
ASSERT_LT(m_block_reward, m_standard_block_reward);
}
- TEST_F(block_reward_and_current_block_size, handles_block_size_less_2_relevance_level)
+ TEST_F(block_reward_and_current_block_weight, handles_block_weight_less_2_relevance_level)
{
do_test(0, 2 * CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V1 - 1);
ASSERT_TRUE(m_block_not_too_big);
@@ -125,21 +125,21 @@ namespace
ASSERT_LT(0, m_block_reward);
}
- TEST_F(block_reward_and_current_block_size, handles_block_size_eq_2_relevance_level)
+ TEST_F(block_reward_and_current_block_weight, handles_block_weight_eq_2_relevance_level)
{
do_test(0, 2 * CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V1);
ASSERT_TRUE(m_block_not_too_big);
ASSERT_EQ(0, m_block_reward);
}
- TEST_F(block_reward_and_current_block_size, handles_block_size_gt_2_relevance_level)
+ TEST_F(block_reward_and_current_block_weight, handles_block_weight_gt_2_relevance_level)
{
do_test(0, 2 * CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V1 + 1);
ASSERT_FALSE(m_block_not_too_big);
}
#ifdef __x86_64__ // For 64-bit systems only, because block size is limited to size_t.
- TEST_F(block_reward_and_current_block_size, fails_on_huge_median_size)
+ TEST_F(block_reward_and_current_block_weight, fails_on_huge_median_size)
{
#if !defined(NDEBUG)
size_t huge_size = std::numeric_limits<uint32_t>::max() + UINT64_C(2);
@@ -147,7 +147,7 @@ namespace
#endif
}
- TEST_F(block_reward_and_current_block_size, fails_on_huge_block_size)
+ TEST_F(block_reward_and_current_block_weight, fails_on_huge_block_weight)
{
#if !defined(NDEBUG)
size_t huge_size = std::numeric_limits<uint32_t>::max() + UINT64_C(2);
@@ -157,94 +157,94 @@ namespace
#endif // __x86_64__
//--------------------------------------------------------------------------------------------------------------------
- class block_reward_and_last_block_sizes : public ::testing::Test
+ class block_reward_and_last_block_weights : public ::testing::Test
{
protected:
virtual void SetUp()
{
- m_last_block_sizes.push_back(3 * CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V1);
- m_last_block_sizes.push_back(5 * CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V1);
- m_last_block_sizes.push_back(7 * CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V1);
- m_last_block_sizes.push_back(11 * CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V1);
- m_last_block_sizes.push_back(13 * CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V1);
+ m_last_block_weights.push_back(3 * CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V1);
+ m_last_block_weights.push_back(5 * CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V1);
+ m_last_block_weights.push_back(7 * CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V1);
+ m_last_block_weights.push_back(11 * CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V1);
+ m_last_block_weights.push_back(13 * CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V1);
- m_last_block_sizes_median = 7 * CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V1;
+ m_last_block_weights_median = 7 * CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V1;
- m_block_not_too_big = get_block_reward(epee::misc_utils::median(m_last_block_sizes), 0, already_generated_coins, m_standard_block_reward, 1);
+ m_block_not_too_big = get_block_reward(epee::misc_utils::median(m_last_block_weights), 0, already_generated_coins, m_standard_block_reward, 1);
ASSERT_TRUE(m_block_not_too_big);
ASSERT_LT(CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V1, m_standard_block_reward);
}
- void do_test(size_t current_block_size)
+ void do_test(size_t current_block_weight)
{
- m_block_not_too_big = get_block_reward(epee::misc_utils::median(m_last_block_sizes), current_block_size, already_generated_coins, m_block_reward, 1);
+ m_block_not_too_big = get_block_reward(epee::misc_utils::median(m_last_block_weights), current_block_weight, already_generated_coins, m_block_reward, 1);
}
static const uint64_t already_generated_coins = 0;
- std::vector<size_t> m_last_block_sizes;
- uint64_t m_last_block_sizes_median;
+ std::vector<size_t> m_last_block_weights;
+ uint64_t m_last_block_weights_median;
bool m_block_not_too_big;
uint64_t m_block_reward;
uint64_t m_standard_block_reward;
};
- TEST_F(block_reward_and_last_block_sizes, handles_block_size_less_median)
+ TEST_F(block_reward_and_last_block_weights, handles_block_weight_less_median)
{
- do_test(m_last_block_sizes_median - 1);
+ do_test(m_last_block_weights_median - 1);
ASSERT_TRUE(m_block_not_too_big);
ASSERT_EQ(m_block_reward, m_standard_block_reward);
}
- TEST_F(block_reward_and_last_block_sizes, handles_block_size_eq_median)
+ TEST_F(block_reward_and_last_block_weights, handles_block_weight_eq_median)
{
- do_test(m_last_block_sizes_median);
+ do_test(m_last_block_weights_median);
ASSERT_TRUE(m_block_not_too_big);
ASSERT_EQ(m_block_reward, m_standard_block_reward);
}
- TEST_F(block_reward_and_last_block_sizes, handles_block_size_gt_median)
+ TEST_F(block_reward_and_last_block_weights, handles_block_weight_gt_median)
{
- do_test(m_last_block_sizes_median + 1);
+ do_test(m_last_block_weights_median + 1);
ASSERT_TRUE(m_block_not_too_big);
ASSERT_LT(m_block_reward, m_standard_block_reward);
}
- TEST_F(block_reward_and_last_block_sizes, handles_block_size_less_2_medians)
+ TEST_F(block_reward_and_last_block_weights, handles_block_weight_less_2_medians)
{
- do_test(2 * m_last_block_sizes_median - 1);
+ do_test(2 * m_last_block_weights_median - 1);
ASSERT_TRUE(m_block_not_too_big);
ASSERT_LT(m_block_reward, m_standard_block_reward);
ASSERT_LT(0, m_block_reward);
}
- TEST_F(block_reward_and_last_block_sizes, handles_block_size_eq_2_medians)
+ TEST_F(block_reward_and_last_block_weights, handles_block_weight_eq_2_medians)
{
- do_test(2 * m_last_block_sizes_median);
+ do_test(2 * m_last_block_weights_median);
ASSERT_TRUE(m_block_not_too_big);
ASSERT_EQ(0, m_block_reward);
}
- TEST_F(block_reward_and_last_block_sizes, handles_block_size_gt_2_medians)
+ TEST_F(block_reward_and_last_block_weights, handles_block_weight_gt_2_medians)
{
- do_test(2 * m_last_block_sizes_median + 1);
+ do_test(2 * m_last_block_weights_median + 1);
ASSERT_FALSE(m_block_not_too_big);
}
- TEST_F(block_reward_and_last_block_sizes, calculates_correctly)
+ TEST_F(block_reward_and_last_block_weights, calculates_correctly)
{
- ASSERT_EQ(0, m_last_block_sizes_median % 8);
+ ASSERT_EQ(0, m_last_block_weights_median % 8);
- do_test(m_last_block_sizes_median * 9 / 8);
+ do_test(m_last_block_weights_median * 9 / 8);
ASSERT_TRUE(m_block_not_too_big);
ASSERT_EQ(m_block_reward, m_standard_block_reward * 63 / 64);
// 3/2 = 12/8
- do_test(m_last_block_sizes_median * 3 / 2);
+ do_test(m_last_block_weights_median * 3 / 2);
ASSERT_TRUE(m_block_not_too_big);
ASSERT_EQ(m_block_reward, m_standard_block_reward * 3 / 4);
- do_test(m_last_block_sizes_median * 15 / 8);
+ do_test(m_last_block_weights_median * 15 / 8);
ASSERT_TRUE(m_block_not_too_big);
ASSERT_EQ(m_block_reward, m_standard_block_reward * 15 / 64);
}
diff --git a/tests/unit_tests/blockchain_db.cpp b/tests/unit_tests/blockchain_db.cpp
index 3a62fba69..7e7ce9bf7 100644
--- a/tests/unit_tests/blockchain_db.cpp
+++ b/tests/unit_tests/blockchain_db.cpp
@@ -319,7 +319,7 @@ TYPED_TEST(BlockchainDBTest, RetrieveBlockData)
ASSERT_NO_THROW(this->m_db->add_block(this->m_blocks[0], t_sizes[0], t_diffs[0], t_coins[0], this->m_txs[0]));
- ASSERT_EQ(t_sizes[0], this->m_db->get_block_size(0));
+ ASSERT_EQ(t_sizes[0], this->m_db->get_block_weight(0));
ASSERT_EQ(t_diffs[0], this->m_db->get_block_cumulative_difficulty(0));
ASSERT_EQ(t_diffs[0], this->m_db->get_block_difficulty(0));
ASSERT_EQ(t_coins[0], this->m_db->get_block_already_generated_coins(0));
diff --git a/tests/unit_tests/bulletproofs.cpp b/tests/unit_tests/bulletproofs.cpp
index 00595a4c7..ac6eaca0b 100644
--- a/tests/unit_tests/bulletproofs.cpp
+++ b/tests/unit_tests/bulletproofs.cpp
@@ -30,8 +30,14 @@
#include "gtest/gtest.h"
+#include "string_tools.h"
#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"
TEST(bulletproofs, valid_zero)
{
@@ -54,6 +60,108 @@ TEST(bulletproofs, valid_random)
}
}
+TEST(bulletproofs, valid_multi_random)
+{
+ for (int n = 0; n < 8; ++n)
+ {
+ size_t outputs = 2 + n;
+ std::vector<uint64_t> amounts;
+ rct::keyV gamma;
+ for (size_t i = 0; i < outputs; ++i)
+ {
+ amounts.push_back(crypto::rand<uint64_t>());
+ gamma.push_back(rct::skGen());
+ }
+ rct::Bulletproof proof = bulletproof_PROVE(amounts, gamma);
+ ASSERT_TRUE(rct::bulletproof_VERIFY(proof));
+ }
+}
+
+TEST(bulletproofs, multi_splitting)
+{
+ rct::ctkeyV sc, pc;
+ rct::ctkey sctmp, pctmp;
+ std::vector<unsigned int> index;
+ std::vector<uint64_t> inamounts, outamounts;
+
+ std::tie(sctmp, pctmp) = rct::ctskpkGen(6000);
+ sc.push_back(sctmp);
+ pc.push_back(pctmp);
+ inamounts.push_back(6000);
+ index.push_back(1);
+
+ std::tie(sctmp, pctmp) = rct::ctskpkGen(7000);
+ sc.push_back(sctmp);
+ pc.push_back(pctmp);
+ inamounts.push_back(7000);
+ index.push_back(1);
+
+ const int mixin = 3, max_outputs = 16;
+
+ for (int n_outputs = 1; n_outputs <= max_outputs; ++n_outputs)
+ {
+ std::vector<uint64_t> outamounts;
+ rct::keyV amount_keys;
+ rct::keyV destinations;
+ rct::key Sk, Pk;
+ uint64_t available = 6000 + 7000;
+ uint64_t amount;
+ rct::ctkeyM mixRing(sc.size());
+
+ //add output
+ for (size_t i = 0; i < n_outputs; ++i)
+ {
+ amount = rct::randXmrAmount(available);
+ outamounts.push_back(amount);
+ amount_keys.push_back(rct::hash_to_scalar(rct::zero()));
+ rct::skpkGen(Sk, Pk);
+ destinations.push_back(Pk);
+ available -= amount;
+ }
+
+ for (size_t i = 0; i < sc.size(); ++i)
+ {
+ for (size_t j = 0; j <= mixin; ++j)
+ {
+ if (j == 1)
+ mixRing[i].push_back(pc[i]);
+ else
+ mixRing[i].push_back({rct::scalarmultBase(rct::skGen()), rct::scalarmultBase(rct::skGen())});
+ }
+ }
+
+ rct::ctkeyV outSk;
+ rct::rctSig s = rct::genRctSimple(rct::zero(), sc, destinations, inamounts, outamounts, available, mixRing, amount_keys, NULL, NULL, index, outSk, rct::RangeProofPaddedBulletproof, hw::get_device("default"));
+ ASSERT_TRUE(rct::verRctSimple(s));
+ for (size_t i = 0; i < n_outputs; ++i)
+ {
+ rct::key mask;
+ rct::decodeRctSimple(s, amount_keys[i], i, mask, hw::get_device("default"));
+ ASSERT_TRUE(mask == outSk[i].mask);
+ }
+ }
+}
+
+TEST(bulletproofs, valid_aggregated)
+{
+ static const size_t N_PROOFS = 8;
+ std::vector<rct::Bulletproof> proofs(N_PROOFS);
+ for (size_t n = 0; n < N_PROOFS; ++n)
+ {
+ size_t outputs = 2 + n;
+ std::vector<uint64_t> amounts;
+ rct::keyV gamma;
+ for (size_t i = 0; i < outputs; ++i)
+ {
+ amounts.push_back(crypto::rand<uint64_t>());
+ gamma.push_back(rct::skGen());
+ }
+ proofs[n] = bulletproof_PROVE(amounts, gamma);
+ }
+ ASSERT_TRUE(rct::bulletproof_VERIFY(proofs));
+}
+
+
TEST(bulletproofs, invalid_8)
{
rct::key invalid_amount = rct::zero();
@@ -69,3 +177,102 @@ TEST(bulletproofs, invalid_31)
rct::Bulletproof proof = bulletproof_PROVE(invalid_amount, rct::skGen());
ASSERT_FALSE(rct::bulletproof_VERIFY(proof));
}
+
+TEST(bulletproofs, invalid_gamma_0)
+{
+ rct::key invalid_amount = rct::zero();
+ invalid_amount[8] = 1;
+ rct::key gamma = rct::zero();
+ rct::Bulletproof proof = bulletproof_PROVE(invalid_amount, gamma);
+ ASSERT_FALSE(rct::bulletproof_VERIFY(proof));
+}
+
+static const char * const torsion_elements[] =
+{
+ "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa",
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc85",
+ "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f",
+ "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc05",
+ "0000000000000000000000000000000000000000000000000000000000000080",
+ "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a",
+};
+
+TEST(bulletproofs, invalid_torsion)
+{
+ rct::Bulletproof proof = bulletproof_PROVE(7329838943733, rct::skGen());
+ ASSERT_TRUE(rct::bulletproof_VERIFY(proof));
+ for (const auto &xs: torsion_elements)
+ {
+ rct::key x;
+ ASSERT_TRUE(epee::string_tools::hex_to_pod(xs, x));
+ ASSERT_FALSE(rct::isInMainSubgroup(x));
+ for (auto &k: proof.V)
+ {
+ const rct::key org_k = k;
+ rct::addKeys(k, org_k, x);
+ ASSERT_FALSE(rct::bulletproof_VERIFY(proof));
+ k = org_k;
+ }
+ for (auto &k: proof.L)
+ {
+ const rct::key org_k = k;
+ rct::addKeys(k, org_k, x);
+ ASSERT_FALSE(rct::bulletproof_VERIFY(proof));
+ k = org_k;
+ }
+ for (auto &k: proof.R)
+ {
+ const rct::key org_k = k;
+ rct::addKeys(k, org_k, x);
+ ASSERT_FALSE(rct::bulletproof_VERIFY(proof));
+ k = org_k;
+ }
+ const rct::key org_A = proof.A;
+ rct::addKeys(proof.A, org_A, x);
+ ASSERT_FALSE(rct::bulletproof_VERIFY(proof));
+ proof.A = org_A;
+ const rct::key org_S = proof.S;
+ rct::addKeys(proof.S, org_S, x);
+ ASSERT_FALSE(rct::bulletproof_VERIFY(proof));
+ proof.S = org_S;
+ const rct::key org_T1 = proof.T1;
+ rct::addKeys(proof.T1, org_T1, x);
+ ASSERT_FALSE(rct::bulletproof_VERIFY(proof));
+ proof.T1 = org_T1;
+ const rct::key org_T2 = proof.T2;
+ rct::addKeys(proof.T2, org_T2, x);
+ ASSERT_FALSE(rct::bulletproof_VERIFY(proof));
+ 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/crypto.cpp b/tests/unit_tests/crypto.cpp
index 4bed06173..29fa88f9d 100644
--- a/tests/unit_tests/crypto.cpp
+++ b/tests/unit_tests/crypto.cpp
@@ -73,3 +73,26 @@ TEST(Crypto, Ostream)
EXPECT_TRUE(is_formatted<crypto::key_derivation>());
EXPECT_TRUE(is_formatted<crypto::key_image>());
}
+
+TEST(Crypto, null_keys)
+{
+ char zero[32];
+ memset(zero, 0, 32);
+ ASSERT_EQ(memcmp(crypto::null_skey.data, zero, 32), 0);
+ ASSERT_EQ(memcmp(crypto::null_pkey.data, zero, 32), 0);
+}
+
+TEST(Crypto, verify_32)
+{
+ // all bytes are treated the same, so we can brute force just one byte
+ unsigned char k0[32] = {0}, k1[32] = {0};
+ for (unsigned int i0 = 0; i0 < 256; ++i0)
+ {
+ k0[0] = i0;
+ for (unsigned int i1 = 0; i1 < 256; ++i1)
+ {
+ k1[0] = i1;
+ ASSERT_EQ(!crypto_verify_32(k0, k1), i0 == i1);
+ }
+ }
+}
diff --git a/tests/unit_tests/device.cpp b/tests/unit_tests/device.cpp
new file mode 100644
index 000000000..50ccec9fa
--- /dev/null
+++ b/tests/unit_tests/device.cpp
@@ -0,0 +1,131 @@
+// 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 "ringct/rctOps.h"
+#include "device/device_default.hpp"
+
+TEST(device, name)
+{
+ hw::core::device_default dev;
+ ASSERT_TRUE(dev.set_name("test"));
+ ASSERT_EQ(dev.get_name(), "test");
+}
+
+/*
+TEST(device, locking)
+{
+ hw::core::device_default dev;
+ ASSERT_TRUE(dev.try_lock());
+ ASSERT_FALSE(dev.try_lock());
+ dev.unlock();
+ ASSERT_TRUE(dev.try_lock());
+ dev.unlock();
+ dev.lock();
+ ASSERT_FALSE(dev.try_lock());
+ dev.unlock();
+ ASSERT_TRUE(dev.try_lock());
+ dev.unlock();
+}
+*/
+
+TEST(device, open_close)
+{
+ hw::core::device_default dev;
+ crypto::secret_key key;
+ ASSERT_TRUE(dev.open_tx(key));
+ ASSERT_TRUE(dev.close_tx());
+}
+
+TEST(device, ops)
+{
+ hw::core::device_default dev;
+ rct::key resd, res;
+ crypto::key_derivation derd, der;
+ rct::key sk, pk;
+ crypto::secret_key sk0, sk1;
+ crypto::public_key pk0, pk1;
+ crypto::ec_scalar ressc0, ressc1;
+ crypto::key_image ki0, ki1;
+
+ rct::skpkGen(sk, pk);
+ rct::scalarmultBase((rct::key&)pk0, (rct::key&)sk0);
+ rct::scalarmultBase((rct::key&)pk1, (rct::key&)sk1);
+
+ dev.scalarmultKey(resd, pk, sk);
+ rct::scalarmultKey(res, pk, sk);
+ ASSERT_EQ(resd, res);
+
+ dev.scalarmultBase(resd, sk);
+ rct::scalarmultBase(res, sk);
+ ASSERT_EQ(resd, res);
+
+ dev.sc_secret_add((crypto::secret_key&)resd, sk0, sk1);
+ sc_add((unsigned char*)&res, (unsigned char*)&sk0, (unsigned char*)&sk1);
+ ASSERT_EQ(resd, res);
+
+ dev.generate_key_derivation(pk0, sk0, derd);
+ crypto::generate_key_derivation(pk0, sk0, der);
+ ASSERT_FALSE(memcmp(&derd, &der, sizeof(der)));
+
+ dev.derivation_to_scalar(der, 0, ressc0);
+ crypto::derivation_to_scalar(der, 0, ressc1);
+ ASSERT_FALSE(memcmp(&ressc0, &ressc1, sizeof(ressc1)));
+
+ dev.derive_secret_key(der, 0, rct::rct2sk(sk), sk0);
+ crypto::derive_secret_key(der, 0, rct::rct2sk(sk), sk1);
+ ASSERT_EQ(sk0, sk1);
+
+ dev.derive_public_key(der, 0, rct::rct2pk(pk), pk0);
+ crypto::derive_public_key(der, 0, rct::rct2pk(pk), pk1);
+ ASSERT_EQ(pk0, pk1);
+
+ dev.secret_key_to_public_key(rct::rct2sk(sk), pk0);
+ crypto::secret_key_to_public_key(rct::rct2sk(sk), pk1);
+ ASSERT_EQ(pk0, pk1);
+
+ dev.generate_key_image(pk0, sk0, ki0);
+ crypto::generate_key_image(pk0, sk0, ki1);
+ ASSERT_EQ(ki0, ki1);
+}
+
+TEST(device, ecdh)
+{
+ hw::core::device_default dev;
+ rct::ecdhTuple tuple, tuple2;
+ rct::key key = rct::skGen();
+ tuple.mask = rct::skGen();
+ tuple.amount = rct::skGen();
+ tuple.senderPk = rct::pkGen();
+ tuple2 = tuple;
+ dev.ecdhEncode(tuple, key);
+ dev.ecdhDecode(tuple, key);
+ ASSERT_EQ(tuple2.mask, tuple.mask);
+ ASSERT_EQ(tuple2.amount, tuple.amount);
+ ASSERT_EQ(tuple2.senderPk, tuple.senderPk);
+}
diff --git a/tests/unit_tests/epee_levin_protocol_handler_async.cpp b/tests/unit_tests/epee_levin_protocol_handler_async.cpp
index 38a8360d7..72d8f3205 100644
--- a/tests/unit_tests/epee_levin_protocol_handler_async.cpp
+++ b/tests/unit_tests/epee_levin_protocol_handler_async.cpp
@@ -150,6 +150,7 @@ namespace
}
virtual bool close() { /*std::cout << "test_connection::close()" << std::endl; */return true; }
+ virtual bool send_done() { /*std::cout << "test_connection::send_done()" << std::endl; */return true; }
virtual bool call_run_once_service_io() { std::cout << "test_connection::call_run_once_service_io()" << std::endl; return true; }
virtual bool request_callback() { std::cout << "test_connection::request_callback()" << std::endl; return true; }
virtual boost::asio::io_service& get_io_service() { std::cout << "test_connection::get_io_service()" << std::endl; return m_io_service; }
diff --git a/tests/unit_tests/epee_utils.cpp b/tests/unit_tests/epee_utils.cpp
index 3969f50f6..c2b0b7647 100644
--- a/tests/unit_tests/epee_utils.cpp
+++ b/tests/unit_tests/epee_utils.cpp
@@ -45,6 +45,7 @@
#include "boost/archive/portable_binary_oarchive.hpp"
#include "hex.h"
#include "net/net_utils_base.h"
+#include "net/local_ip.h"
#include "p2p/net_peerlist_boost_serialization.h"
#include "span.h"
#include "string_tools.h"
@@ -165,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]>()));
@@ -192,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>>()));
@@ -230,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)));
@@ -283,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};
@@ -317,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());
@@ -329,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)
@@ -648,3 +704,34 @@ TEST(NetUtils, NetworkAddress)
EXPECT_THROW(address1.as<epee::net_utils::ipv4_network_address>(), std::bad_cast);
EXPECT_NO_THROW(address1.as<custom_address>());
}
+
+static bool is_local(const char *s)
+{
+ uint32_t ip;
+ CHECK_AND_ASSERT_THROW_MES(epee::string_tools::get_ip_int32_from_string(ip, s), std::string("Invalid IP address: ") + s);
+ return epee::net_utils::is_ip_local(ip);
+}
+
+TEST(NetUtils, PrivateRanges)
+{
+ ASSERT_EQ(is_local("10.0.0.0"), true);
+ ASSERT_EQ(is_local("10.255.0.0"), true);
+ ASSERT_EQ(is_local("127.0.0.0"), false); // loopback is not considered local
+ ASSERT_EQ(is_local("192.167.255.255"), false);
+ ASSERT_EQ(is_local("192.168.0.0"), true);
+ ASSERT_EQ(is_local("192.168.255.255"), true);
+ ASSERT_EQ(is_local("192.169.0.0"), false);
+ ASSERT_EQ(is_local("172.0.0.0"), false);
+ ASSERT_EQ(is_local("172.15.255.255"), false);
+ ASSERT_EQ(is_local("172.16.0.0"), true);
+ ASSERT_EQ(is_local("172.16.255.255"), true);
+ ASSERT_EQ(is_local("172.31.255.255"), true);
+ ASSERT_EQ(is_local("172.32.0.0"), false);
+ ASSERT_EQ(is_local("0.0.0.0"), false);
+ ASSERT_EQ(is_local("255.255.255.254"), false);
+ ASSERT_EQ(is_local("11.255.255.255"), false);
+ ASSERT_EQ(is_local("0.0.0.10"), false);
+ ASSERT_EQ(is_local("0.0.168.192"), false);
+ ASSERT_EQ(is_local("0.0.30.172"), false);
+ ASSERT_EQ(is_local("0.0.30.127"), false);
+}
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
+ );
+}
+
diff --git a/tests/unit_tests/fee.cpp b/tests/unit_tests/fee.cpp
index c5589ab96..8ccb38fc9 100644
--- a/tests/unit_tests/fee.cpp
+++ b/tests/unit_tests/fee.cpp
@@ -58,46 +58,46 @@ namespace
TEST_F(fee, 10xmr)
{
// CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2 and lower are clamped
- ASSERT_EQ(Blockchain::get_dynamic_per_kb_fee(10000000000000, CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2, 3), clamp_fee(2000000000));
- ASSERT_EQ(Blockchain::get_dynamic_per_kb_fee(10000000000000, CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2 / 2, 3), clamp_fee(2000000000));
- ASSERT_EQ(Blockchain::get_dynamic_per_kb_fee(10000000000000, CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2 / 100, 3), clamp_fee(2000000000));
- ASSERT_EQ(Blockchain::get_dynamic_per_kb_fee(10000000000000, 1, 3), 2000000000);
+ ASSERT_EQ(Blockchain::get_dynamic_base_fee(10000000000000, CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2, 3), clamp_fee(2000000000));
+ ASSERT_EQ(Blockchain::get_dynamic_base_fee(10000000000000, CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2 / 2, 3), clamp_fee(2000000000));
+ ASSERT_EQ(Blockchain::get_dynamic_base_fee(10000000000000, CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2 / 100, 3), clamp_fee(2000000000));
+ ASSERT_EQ(Blockchain::get_dynamic_base_fee(10000000000000, 1, 3), 2000000000);
// higher is inverse proportional
- ASSERT_EQ(Blockchain::get_dynamic_per_kb_fee(10000000000000, CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2 * 2, 3), clamp_fee(2000000000 / 2));
- ASSERT_EQ(Blockchain::get_dynamic_per_kb_fee(10000000000000, CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2 * 10, 3), clamp_fee(2000000000 / 10));
- ASSERT_EQ(Blockchain::get_dynamic_per_kb_fee(10000000000000, CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2 * 1000, 3), clamp_fee(2000000000 / 1000));
- ASSERT_EQ(Blockchain::get_dynamic_per_kb_fee(10000000000000, CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2 * 20000ull, 3), clamp_fee(2000000000 / 20000));
+ ASSERT_EQ(Blockchain::get_dynamic_base_fee(10000000000000, CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2 * 2, 3), clamp_fee(2000000000 / 2));
+ ASSERT_EQ(Blockchain::get_dynamic_base_fee(10000000000000, CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2 * 10, 3), clamp_fee(2000000000 / 10));
+ ASSERT_EQ(Blockchain::get_dynamic_base_fee(10000000000000, CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2 * 1000, 3), clamp_fee(2000000000 / 1000));
+ ASSERT_EQ(Blockchain::get_dynamic_base_fee(10000000000000, CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2 * 20000ull, 3), clamp_fee(2000000000 / 20000));
}
TEST_F(fee, 1xmr)
{
// CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2 and lower are clamped
- ASSERT_EQ(Blockchain::get_dynamic_per_kb_fee(1000000000000, CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2, 3), clamp_fee(200000000));
- ASSERT_EQ(Blockchain::get_dynamic_per_kb_fee(1000000000000, CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2 / 2, 3), clamp_fee(200000000));
- ASSERT_EQ(Blockchain::get_dynamic_per_kb_fee(1000000000000, CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2 / 100, 3), clamp_fee(200000000));
- ASSERT_EQ(Blockchain::get_dynamic_per_kb_fee(1000000000000, 1, 3), 200000000);
+ ASSERT_EQ(Blockchain::get_dynamic_base_fee(1000000000000, CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2, 3), clamp_fee(200000000));
+ ASSERT_EQ(Blockchain::get_dynamic_base_fee(1000000000000, CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2 / 2, 3), clamp_fee(200000000));
+ ASSERT_EQ(Blockchain::get_dynamic_base_fee(1000000000000, CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2 / 100, 3), clamp_fee(200000000));
+ ASSERT_EQ(Blockchain::get_dynamic_base_fee(1000000000000, 1, 3), 200000000);
// higher is inverse proportional
- ASSERT_EQ(Blockchain::get_dynamic_per_kb_fee(1000000000000, CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2 * 2, 3), clamp_fee(200000000 / 2));
- ASSERT_EQ(Blockchain::get_dynamic_per_kb_fee(1000000000000, CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2 * 10, 3), clamp_fee(200000000 / 10));
- ASSERT_EQ(Blockchain::get_dynamic_per_kb_fee(1000000000000, CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2 * 1000, 3), clamp_fee(200000000 / 1000));
- ASSERT_EQ(Blockchain::get_dynamic_per_kb_fee(1000000000000, CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2 * 20000ull, 3), clamp_fee(200000000 / 20000));
+ ASSERT_EQ(Blockchain::get_dynamic_base_fee(1000000000000, CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2 * 2, 3), clamp_fee(200000000 / 2));
+ ASSERT_EQ(Blockchain::get_dynamic_base_fee(1000000000000, CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2 * 10, 3), clamp_fee(200000000 / 10));
+ ASSERT_EQ(Blockchain::get_dynamic_base_fee(1000000000000, CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2 * 1000, 3), clamp_fee(200000000 / 1000));
+ ASSERT_EQ(Blockchain::get_dynamic_base_fee(1000000000000, CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2 * 20000ull, 3), clamp_fee(200000000 / 20000));
}
TEST_F(fee, dot3xmr)
{
// CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2 and lower are clamped
- ASSERT_EQ(Blockchain::get_dynamic_per_kb_fee(300000000000, CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2, 3), clamp_fee(60000000));
- ASSERT_EQ(Blockchain::get_dynamic_per_kb_fee(300000000000, CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2 / 2, 3), clamp_fee(60000000));
- ASSERT_EQ(Blockchain::get_dynamic_per_kb_fee(300000000000, CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2 / 100, 3), clamp_fee(60000000));
- ASSERT_EQ(Blockchain::get_dynamic_per_kb_fee(300000000000, 1, 3), 60000000);
+ ASSERT_EQ(Blockchain::get_dynamic_base_fee(300000000000, CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2, 3), clamp_fee(60000000));
+ ASSERT_EQ(Blockchain::get_dynamic_base_fee(300000000000, CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2 / 2, 3), clamp_fee(60000000));
+ ASSERT_EQ(Blockchain::get_dynamic_base_fee(300000000000, CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2 / 100, 3), clamp_fee(60000000));
+ ASSERT_EQ(Blockchain::get_dynamic_base_fee(300000000000, 1, 3), 60000000);
// higher is inverse proportional
- ASSERT_EQ(Blockchain::get_dynamic_per_kb_fee(300000000000, CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2 * 2, 3), clamp_fee(60000000 / 2));
- ASSERT_EQ(Blockchain::get_dynamic_per_kb_fee(300000000000, CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2 * 10, 3), clamp_fee(60000000 / 10));
- ASSERT_EQ(Blockchain::get_dynamic_per_kb_fee(300000000000, CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2 * 1000, 3), clamp_fee(60000000 / 1000));
- ASSERT_EQ(Blockchain::get_dynamic_per_kb_fee(300000000000, CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2 * 20000ull, 3), clamp_fee(60000000 / 20000));
+ ASSERT_EQ(Blockchain::get_dynamic_base_fee(300000000000, CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2 * 2, 3), clamp_fee(60000000 / 2));
+ ASSERT_EQ(Blockchain::get_dynamic_base_fee(300000000000, CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2 * 10, 3), clamp_fee(60000000 / 10));
+ ASSERT_EQ(Blockchain::get_dynamic_base_fee(300000000000, CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2 * 1000, 3), clamp_fee(60000000 / 1000));
+ ASSERT_EQ(Blockchain::get_dynamic_base_fee(300000000000, CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2 * 20000ull, 3), clamp_fee(60000000 / 20000));
}
static bool is_more_or_less(double x, double y)
@@ -116,7 +116,7 @@ namespace
600000000000ull, // .6 monero, minimum reward per block at 2min
300000000000ull, // .3 monero, minimum reward per block at 1min
};
- static const uint64_t median_block_sizes[] = {
+ static const uint64_t median_block_weights[] = {
CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2,
CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2 * 2,
CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2 * 10,
@@ -127,9 +127,9 @@ namespace
for (uint64_t block_reward: block_rewards)
{
- for (uint64_t median_block_size: median_block_sizes)
+ for (uint64_t median_block_weight: median_block_weights)
{
- ASSERT_TRUE(is_more_or_less(Blockchain::get_dynamic_per_kb_fee(block_reward, median_block_size, 3) * (median_block_size / 1024.) * MAX_MULTIPLIER / (double)block_reward, 1.992 * 1000 / 1024));
+ ASSERT_TRUE(is_more_or_less(Blockchain::get_dynamic_base_fee(block_reward, median_block_weight, 3) * (median_block_weight / 1024.) * MAX_MULTIPLIER / (double)block_reward, 1.992 * 1000 / 1024));
}
}
}
diff --git a/tests/unit_tests/hardfork.cpp b/tests/unit_tests/hardfork.cpp
index 913ebe84a..47177db1c 100644
--- a/tests/unit_tests/hardfork.cpp
+++ b/tests/unit_tests/hardfork.cpp
@@ -50,6 +50,7 @@ public:
virtual void safesyncmode(const bool onoff) {}
virtual void reset() {}
virtual std::vector<std::string> get_filenames() const { return std::vector<std::string>(); }
+ virtual bool remove_data_file(const std::string& folder) const { return true; }
virtual std::string get_db_name() const { return std::string(); }
virtual bool lock() { return true; }
virtual void unlock() { }
@@ -69,8 +70,9 @@ public:
virtual uint64_t get_block_height(const crypto::hash& h) const { return 0; }
virtual block_header get_block_header(const crypto::hash& h) const { return block_header(); }
virtual uint64_t get_block_timestamp(const uint64_t& height) const { return 0; }
+ virtual std::vector<uint64_t> get_block_cumulative_rct_outputs(const std::vector<uint64_t> &heights) const { return {}; }
virtual uint64_t get_top_block_timestamp() const { return 0; }
- virtual size_t get_block_size(const uint64_t& height) const { return 128; }
+ virtual size_t get_block_weight(const uint64_t& height) const { return 128; }
virtual difficulty_type get_block_cumulative_difficulty(const uint64_t& height) const { return 10; }
virtual difficulty_type get_block_difficulty(const uint64_t& height) const { return 0; }
virtual uint64_t get_block_already_generated_coins(const uint64_t& height) const { return 10000000000; }
@@ -91,7 +93,6 @@ public:
virtual uint64_t get_num_outputs(const uint64_t& amount) const { return 1; }
virtual uint64_t get_indexing_base() const { return 0; }
virtual output_data_t get_output_key(const uint64_t& amount, const uint64_t& index) { return output_data_t(); }
- virtual output_data_t get_output_key(const uint64_t& global_index) const { return output_data_t(); }
virtual tx_out_index get_output_tx_and_index_from_global(const uint64_t& index) const { return tx_out_index(); }
virtual tx_out_index get_output_tx_and_index(const uint64_t& amount, const uint64_t& index) const { return tx_out_index(); }
virtual void get_output_tx_and_index(const uint64_t& amount, const std::vector<uint64_t> &offsets, std::vector<tx_out_index> &indices) const {}
@@ -124,13 +125,15 @@ public:
virtual void remove_txpool_tx(const crypto::hash& txid) {}
virtual bool get_txpool_tx_meta(const crypto::hash& txid, txpool_tx_meta_t &meta) const { return false; }
virtual bool get_txpool_tx_blob(const crypto::hash& txid, cryptonote::blobdata &bd) const { return false; }
+ virtual uint64_t get_database_size() const { return 0; }
virtual cryptonote::blobdata get_txpool_tx_blob(const crypto::hash& txid) const { return ""; }
virtual bool for_all_txpool_txes(std::function<bool(const crypto::hash&, const txpool_tx_meta_t&, const cryptonote::blobdata*)>, bool include_blob = false, bool include_unrelayed_txes = false) const { return false; }
virtual void add_block( const block& blk
- , const size_t& block_size
+ , size_t block_weight
, const difficulty_type& cumulative_difficulty
, const uint64_t& coins_generated
+ , uint64_t num_rct_outs
, const crypto::hash& blk_hash
) {
blocks.push_back(blk);
@@ -183,20 +186,20 @@ TEST(major, Only)
ASSERT_FALSE(hf.add(mkblock(0, 2), 0));
ASSERT_FALSE(hf.add(mkblock(2, 2), 0));
ASSERT_TRUE(hf.add(mkblock(1, 2), 0));
- db.add_block(mkblock(1, 1), 0, 0, 0, crypto::hash());
+ db.add_block(mkblock(1, 1), 0, 0, 0, 0, crypto::hash());
// block height 1, only version 1 is accepted
ASSERT_FALSE(hf.add(mkblock(0, 2), 1));
ASSERT_FALSE(hf.add(mkblock(2, 2), 1));
ASSERT_TRUE(hf.add(mkblock(1, 2), 1));
- db.add_block(mkblock(1, 1), 0, 0, 0, crypto::hash());
+ db.add_block(mkblock(1, 1), 0, 0, 0, 0, crypto::hash());
// block height 2, only version 2 is accepted
ASSERT_FALSE(hf.add(mkblock(0, 2), 2));
ASSERT_FALSE(hf.add(mkblock(1, 2), 2));
ASSERT_FALSE(hf.add(mkblock(3, 2), 2));
ASSERT_TRUE(hf.add(mkblock(2, 2), 2));
- db.add_block(mkblock(2, 1), 0, 0, 0, crypto::hash());
+ db.add_block(mkblock(2, 1), 0, 0, 0, 0, crypto::hash());
}
TEST(empty_hardforks, Success)
@@ -210,7 +213,7 @@ TEST(empty_hardforks, Success)
ASSERT_TRUE(hf.get_state(time(NULL) + 3600*24*400) == HardFork::Ready);
for (uint64_t h = 0; h <= 10; ++h) {
- db.add_block(mkblock(hf, h, 1), 0, 0, 0, crypto::hash());
+ db.add_block(mkblock(hf, h, 1), 0, 0, 0, 0, crypto::hash());
ASSERT_TRUE(hf.add(db.get_block_from_height(h), h));
}
ASSERT_EQ(hf.get(0), 1);
@@ -244,14 +247,14 @@ TEST(check_for_height, Success)
for (uint64_t h = 0; h <= 4; ++h) {
ASSERT_TRUE(hf.check_for_height(mkblock(1, 1), h));
ASSERT_FALSE(hf.check_for_height(mkblock(2, 2), h)); // block version is too high
- db.add_block(mkblock(hf, h, 1), 0, 0, 0, crypto::hash());
+ db.add_block(mkblock(hf, h, 1), 0, 0, 0, 0, crypto::hash());
ASSERT_TRUE(hf.add(db.get_block_from_height(h), h));
}
for (uint64_t h = 5; h <= 10; ++h) {
ASSERT_FALSE(hf.check_for_height(mkblock(1, 1), h)); // block version is too low
ASSERT_TRUE(hf.check_for_height(mkblock(2, 2), h));
- db.add_block(mkblock(hf, h, 2), 0, 0, 0, crypto::hash());
+ db.add_block(mkblock(hf, h, 2), 0, 0, 0, 0, crypto::hash());
ASSERT_TRUE(hf.add(db.get_block_from_height(h), h));
}
}
@@ -268,19 +271,19 @@ TEST(get, next_version)
for (uint64_t h = 0; h <= 4; ++h) {
ASSERT_EQ(2, hf.get_next_version());
- db.add_block(mkblock(hf, h, 1), 0, 0, 0, crypto::hash());
+ db.add_block(mkblock(hf, h, 1), 0, 0, 0, 0, crypto::hash());
ASSERT_TRUE(hf.add(db.get_block_from_height(h), h));
}
for (uint64_t h = 5; h <= 9; ++h) {
ASSERT_EQ(4, hf.get_next_version());
- db.add_block(mkblock(hf, h, 2), 0, 0, 0, crypto::hash());
+ db.add_block(mkblock(hf, h, 2), 0, 0, 0, 0, crypto::hash());
ASSERT_TRUE(hf.add(db.get_block_from_height(h), h));
}
for (uint64_t h = 10; h <= 15; ++h) {
ASSERT_EQ(4, hf.get_next_version());
- db.add_block(mkblock(hf, h, 4), 0, 0, 0, crypto::hash());
+ db.add_block(mkblock(hf, h, 4), 0, 0, 0, 0, crypto::hash());
ASSERT_TRUE(hf.add(db.get_block_from_height(h), h));
}
}
@@ -321,7 +324,7 @@ TEST(steps_asap, Success)
hf.init();
for (uint64_t h = 0; h < 10; ++h) {
- db.add_block(mkblock(hf, h, 9), 0, 0, 0, crypto::hash());
+ db.add_block(mkblock(hf, h, 9), 0, 0, 0, 0, crypto::hash());
ASSERT_TRUE(hf.add(db.get_block_from_height(h), h));
}
@@ -348,7 +351,7 @@ TEST(steps_1, Success)
hf.init();
for (uint64_t h = 0 ; h < 10; ++h) {
- db.add_block(mkblock(hf, h, h+1), 0, 0, 0, crypto::hash());
+ db.add_block(mkblock(hf, h, h+1), 0, 0, 0, 0, crypto::hash());
ASSERT_TRUE(hf.add(db.get_block_from_height(h), h));
}
@@ -373,7 +376,7 @@ TEST(reorganize, Same)
// index 0 1 2 3 4 5 6 7 8 9
static const uint8_t block_versions[] = { 1, 1, 4, 4, 7, 7, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9 };
for (uint64_t h = 0; h < 20; ++h) {
- db.add_block(mkblock(hf, h, block_versions[h]), 0, 0, 0, crypto::hash());
+ db.add_block(mkblock(hf, h, block_versions[h]), 0, 0, 0, 0, crypto::hash());
ASSERT_TRUE(hf.add(db.get_block_from_height(h), h));
}
@@ -404,7 +407,7 @@ TEST(reorganize, Changed)
static const uint8_t block_versions[] = { 1, 1, 4, 4, 7, 7, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9 };
static const uint8_t expected_versions[] = { 1, 1, 1, 1, 1, 1, 4, 4, 7, 7, 9, 9, 9, 9, 9, 9 };
for (uint64_t h = 0; h < 16; ++h) {
- db.add_block(mkblock(hf, h, block_versions[h]), 0, 0, 0, crypto::hash());
+ db.add_block(mkblock(hf, h, block_versions[h]), 0, 0, 0, 0, crypto::hash());
ASSERT_TRUE (hf.add(db.get_block_from_height(h), h));
}
@@ -424,7 +427,7 @@ TEST(reorganize, Changed)
ASSERT_EQ(db.height(), 3);
hf.reorganize_from_block_height(2);
for (uint64_t h = 3; h < 16; ++h) {
- db.add_block(mkblock(hf, h, block_versions_new[h]), 0, 0, 0, crypto::hash());
+ db.add_block(mkblock(hf, h, block_versions_new[h]), 0, 0, 0, 0, crypto::hash());
bool ret = hf.add(db.get_block_from_height(h), h);
ASSERT_EQ (ret, h < 15);
}
@@ -448,7 +451,7 @@ TEST(voting, threshold)
for (uint64_t h = 0; h <= 8; ++h) {
uint8_t v = 1 + !!(h % 8);
- db.add_block(mkblock(hf, h, v), 0, 0, 0, crypto::hash());
+ db.add_block(mkblock(hf, h, v), 0, 0, 0, 0, crypto::hash());
bool ret = hf.add(db.get_block_from_height(h), h);
if (h >= 8 && threshold == 87) {
// for threshold 87, we reach the treshold at height 7, so from height 8, hard fork to version 2, but 8 tries to add 1
@@ -482,7 +485,7 @@ TEST(voting, different_thresholds)
static const uint8_t expected_versions[] = { 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4 };
for (uint64_t h = 0; h < sizeof(block_versions) / sizeof(block_versions[0]); ++h) {
- db.add_block(mkblock(hf, h, block_versions[h]), 0, 0, 0, crypto::hash());
+ db.add_block(mkblock(hf, h, block_versions[h]), 0, 0, 0, 0, crypto::hash());
bool ret = hf.add(db.get_block_from_height(h), h);
ASSERT_EQ(ret, true);
}
@@ -536,7 +539,7 @@ TEST(voting, info)
ASSERT_EQ(expected_thresholds[h], threshold);
ASSERT_EQ(4, voting);
- db.add_block(mkblock(hf, h, block_versions[h]), 0, 0, 0, crypto::hash());
+ db.add_block(mkblock(hf, h, block_versions[h]), 0, 0, 0, 0, crypto::hash());
ASSERT_TRUE(hf.add(db.get_block_from_height(h), h));
}
}
@@ -599,7 +602,7 @@ TEST(reorganize, changed)
#define ADD(v, h, a) \
do { \
cryptonote::block b = mkblock(hf, h, v); \
- db.add_block(b, 0, 0, 0, crypto::hash()); \
+ db.add_block(b, 0, 0, 0, 0, crypto::hash()); \
ASSERT_##a(hf.add(b, h)); \
} while(0)
#define ADD_TRUE(v, h) ADD(v, h, TRUE)
diff --git a/tests/unit_tests/is_hdd.cpp b/tests/unit_tests/is_hdd.cpp
new file mode 100644
index 000000000..040af4f47
--- /dev/null
+++ b/tests/unit_tests/is_hdd.cpp
@@ -0,0 +1,17 @@
+#include "common/util.h"
+#include <string>
+#include <gtest/gtest.h>
+
+#if defined(__GLIBC__)
+TEST(is_hdd, linux_os_root)
+{
+ std::string path = "/";
+ EXPECT_TRUE(tools::is_hdd(path.c_str()) != boost::none);
+}
+#else
+TEST(is_hdd, unknown_os)
+{
+ std::string path = "";
+ EXPECT_FALSE(tools::is_hdd(path.c_str()) != boost::none);
+}
+#endif
diff --git a/tests/unit_tests/json_serialization.cpp b/tests/unit_tests/json_serialization.cpp
new file mode 100644
index 000000000..234cb2c33
--- /dev/null
+++ b/tests/unit_tests/json_serialization.cpp
@@ -0,0 +1,217 @@
+
+#include <boost/optional/optional.hpp>
+#include <boost/range/adaptor/indexed.hpp>
+#include <gtest/gtest.h>
+#include <rapidjson/document.h>
+#include <vector>
+
+#include "crypto/hash.h"
+#include "cryptonote_basic/account.h"
+#include "cryptonote_basic/cryptonote_basic.h"
+#include "cryptonote_basic/cryptonote_format_utils.h"
+#include "cryptonote_core/cryptonote_tx_utils.h"
+#include "serialization/json_object.h"
+
+
+namespace
+{
+ cryptonote::transaction
+ make_miner_transaction(cryptonote::account_public_address const& to)
+ {
+ cryptonote::transaction tx{};
+ if (!cryptonote::construct_miner_tx(0, 0, 5000, 500, 500, to, tx))
+ throw std::runtime_error{"transaction construction error"};
+
+ crypto::hash id{0};
+ if (!cryptonote::get_transaction_hash(tx, id))
+ throw std::runtime_error{"could not get transaction hash"};
+
+ return tx;
+ }
+
+ cryptonote::transaction
+ make_transaction(
+ cryptonote::account_keys const& from,
+ std::vector<cryptonote::transaction> const& sources,
+ std::vector<cryptonote::account_public_address> const& destinations,
+ bool rct,
+ bool bulletproof)
+ {
+ std::uint64_t source_amount = 0;
+ std::vector<cryptonote::tx_source_entry> actual_sources;
+ for (auto const& source : sources)
+ {
+ std::vector<cryptonote::tx_extra_field> extra_fields;
+ if (!cryptonote::parse_tx_extra(source.extra, extra_fields))
+ throw std::runtime_error{"invalid transaction"};
+
+ cryptonote::tx_extra_pub_key key_field{};
+ if (!cryptonote::find_tx_extra_field_by_type(extra_fields, key_field))
+ throw std::runtime_error{"invalid transaction"};
+
+ for (auto const& input : boost::adaptors::index(source.vout))
+ {
+ source_amount += input.value().amount;
+ auto const& key = boost::get<cryptonote::txout_to_key>(input.value().target);
+
+ actual_sources.push_back(
+ {{}, 0, key_field.pub_key, {}, std::size_t(input.index()), input.value().amount, rct, rct::identity()}
+ );
+
+ for (unsigned ring = 0; ring < 10; ++ring)
+ actual_sources.back().push_output(input.index(), key.key, input.value().amount);
+ }
+ }
+
+ std::vector<cryptonote::tx_destination_entry> to;
+ for (auto const& destination : destinations)
+ to.push_back({(source_amount / destinations.size()), destination, false});
+
+ cryptonote::transaction tx{};
+
+ crypto::secret_key tx_key{};
+ std::vector<crypto::secret_key> extra_keys{};
+
+ std::unordered_map<crypto::public_key, cryptonote::subaddress_index> subaddresses;
+ subaddresses[from.m_account_address.m_spend_public_key] = {0,0};
+
+ if (!cryptonote::construct_tx_and_get_tx_key(from, subaddresses, actual_sources, to, boost::none, {}, tx, 0, tx_key, extra_keys, rct, bulletproof ? rct::RangeProofBulletproof : rct::RangeProofBorromean))
+ throw std::runtime_error{"transaction construction error"};
+
+ return tx;
+ }
+} // anonymous
+
+TEST(JsonSerialization, MinerTransaction)
+{
+ cryptonote::account_base acct;
+ acct.generate();
+ const auto miner_tx = make_miner_transaction(acct.get_keys().m_account_address);
+
+ crypto::hash tx_hash{};
+ ASSERT_TRUE(cryptonote::get_transaction_hash(miner_tx, tx_hash));
+
+ rapidjson::Document doc;
+ cryptonote::json::toJsonValue(doc, miner_tx, doc);
+
+ cryptonote::transaction miner_tx_copy;
+ cryptonote::json::fromJsonValue(doc, miner_tx_copy);
+
+ crypto::hash tx_copy_hash{};
+ ASSERT_TRUE(cryptonote::get_transaction_hash(miner_tx_copy, tx_copy_hash));
+ EXPECT_EQ(tx_hash, tx_copy_hash);
+
+ cryptonote::blobdata tx_bytes{};
+ cryptonote::blobdata tx_copy_bytes{};
+
+ ASSERT_TRUE(cryptonote::t_serializable_object_to_blob(miner_tx, tx_bytes));
+ ASSERT_TRUE(cryptonote::t_serializable_object_to_blob(miner_tx_copy, tx_copy_bytes));
+
+ EXPECT_EQ(tx_bytes, tx_copy_bytes);
+}
+
+TEST(JsonSerialization, RegularTransaction)
+{
+ cryptonote::account_base acct1;
+ acct1.generate();
+
+ cryptonote::account_base acct2;
+ acct2.generate();
+
+ const auto miner_tx = make_miner_transaction(acct1.get_keys().m_account_address);
+ const auto tx = make_transaction(
+ acct1.get_keys(), {miner_tx}, {acct2.get_keys().m_account_address}, false, false
+ );
+
+ crypto::hash tx_hash{};
+ ASSERT_TRUE(cryptonote::get_transaction_hash(tx, tx_hash));
+
+ rapidjson::Document doc;
+ cryptonote::json::toJsonValue(doc, tx, doc);
+
+ cryptonote::transaction tx_copy;
+ cryptonote::json::fromJsonValue(doc, tx_copy);
+
+ crypto::hash tx_copy_hash{};
+ ASSERT_TRUE(cryptonote::get_transaction_hash(tx_copy, tx_copy_hash));
+ EXPECT_EQ(tx_hash, tx_copy_hash);
+
+ cryptonote::blobdata tx_bytes{};
+ cryptonote::blobdata tx_copy_bytes{};
+
+ ASSERT_TRUE(cryptonote::t_serializable_object_to_blob(tx, tx_bytes));
+ ASSERT_TRUE(cryptonote::t_serializable_object_to_blob(tx_copy, tx_copy_bytes));
+
+ EXPECT_EQ(tx_bytes, tx_copy_bytes);
+}
+
+TEST(JsonSerialization, RingctTransaction)
+{
+ cryptonote::account_base acct1;
+ acct1.generate();
+
+ cryptonote::account_base acct2;
+ acct2.generate();
+
+ const auto miner_tx = make_miner_transaction(acct1.get_keys().m_account_address);
+ const auto tx = make_transaction(
+ acct1.get_keys(), {miner_tx}, {acct2.get_keys().m_account_address}, true, false
+ );
+
+ crypto::hash tx_hash{};
+ ASSERT_TRUE(cryptonote::get_transaction_hash(tx, tx_hash));
+
+ rapidjson::Document doc;
+ cryptonote::json::toJsonValue(doc, tx, doc);
+
+ cryptonote::transaction tx_copy;
+ cryptonote::json::fromJsonValue(doc, tx_copy);
+
+ crypto::hash tx_copy_hash{};
+ ASSERT_TRUE(cryptonote::get_transaction_hash(tx_copy, tx_copy_hash));
+ EXPECT_EQ(tx_hash, tx_copy_hash);
+
+ cryptonote::blobdata tx_bytes{};
+ cryptonote::blobdata tx_copy_bytes{};
+
+ ASSERT_TRUE(cryptonote::t_serializable_object_to_blob(tx, tx_bytes));
+ ASSERT_TRUE(cryptonote::t_serializable_object_to_blob(tx_copy, tx_copy_bytes));
+
+ EXPECT_EQ(tx_bytes, tx_copy_bytes);
+}
+
+TEST(JsonSerialization, BulletproofTransaction)
+{
+ cryptonote::account_base acct1;
+ acct1.generate();
+
+ cryptonote::account_base acct2;
+ acct2.generate();
+
+ const auto miner_tx = make_miner_transaction(acct1.get_keys().m_account_address);
+ const auto tx = make_transaction(
+ acct1.get_keys(), {miner_tx}, {acct2.get_keys().m_account_address}, true, true
+ );
+
+ crypto::hash tx_hash{};
+ ASSERT_TRUE(cryptonote::get_transaction_hash(tx, tx_hash));
+
+ rapidjson::Document doc;
+ cryptonote::json::toJsonValue(doc, tx, doc);
+
+ cryptonote::transaction tx_copy;
+ cryptonote::json::fromJsonValue(doc, tx_copy);
+
+ crypto::hash tx_copy_hash{};
+ ASSERT_TRUE(cryptonote::get_transaction_hash(tx_copy, tx_copy_hash));
+ EXPECT_EQ(tx_hash, tx_copy_hash);
+
+ cryptonote::blobdata tx_bytes{};
+ cryptonote::blobdata tx_copy_bytes{};
+
+ ASSERT_TRUE(cryptonote::t_serializable_object_to_blob(tx, tx_bytes));
+ ASSERT_TRUE(cryptonote::t_serializable_object_to_blob(tx_copy, tx_copy_bytes));
+
+ EXPECT_EQ(tx_bytes, tx_copy_bytes);
+}
+
diff --git a/tests/unit_tests/keccak.cpp b/tests/unit_tests/keccak.cpp
new file mode 100644
index 000000000..4276b0e1d
--- /dev/null
+++ b/tests/unit_tests/keccak.cpp
@@ -0,0 +1,150 @@
+// 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"
+
+extern "C" {
+#include "crypto/keccak.h"
+}
+
+#define KECCAK_BLOCKLEN 136
+
+#define TEST_KECCAK(sz, chunks) \
+ std::string data; \
+ data.resize(sz); \
+ for (size_t i = 0; i < sz; ++i) \
+ data[i] = i * 17; \
+ uint8_t md0[32], md1[32]; \
+ keccak((const uint8_t*)data.data(), data.size(), md0, 32); \
+ KECCAK_CTX ctx; \
+ keccak_init(&ctx); \
+ size_t offset = 0; \
+ for (size_t i = 0; i < sizeof(chunks) / sizeof(chunks[0]); ++i) \
+ { \
+ ASSERT_TRUE(offset + chunks[i] <= data.size()); \
+ keccak_update(&ctx, (const uint8_t*)data.data() + offset, chunks[i]); \
+ offset += chunks[i]; \
+ } \
+ ASSERT_TRUE(offset == data.size()); \
+ keccak_finish(&ctx, md1); \
+ ASSERT_EQ(memcmp(md0, md1, 32), 0);
+
+TEST(keccak, )
+{
+}
+
+TEST(keccak, 0_and_0)
+{
+ static const size_t chunks[] = {0};
+ TEST_KECCAK(0, chunks);
+}
+
+TEST(keccak, 1_and_1)
+{
+ static const size_t chunks[] = {1};
+ TEST_KECCAK(1, chunks);
+}
+
+TEST(keccak, 1_and_0_1_0)
+{
+ static const size_t chunks[] = {0, 1, 0};
+ TEST_KECCAK(1, chunks);
+}
+
+TEST(keccak, 2_and_1_1)
+{
+ static const size_t chunks[] = {1, 1};
+ TEST_KECCAK(2, chunks);
+}
+
+TEST(keccak, 4_and_0_0_1_0_2_1_0)
+{
+ static const size_t chunks[] = {0, 0, 1, 0, 2, 1, 0};
+ TEST_KECCAK(4, chunks);
+}
+
+TEST(keccak, 15_and_1_14)
+{
+ static const size_t chunks[] = {1, 14};
+ TEST_KECCAK(15, chunks);
+}
+
+TEST(keccak, 135_and_134_1)
+{
+ static const size_t chunks[] = {134, 1};
+ TEST_KECCAK(135, chunks);
+}
+
+TEST(keccak, 135_and_135_0)
+{
+ static const size_t chunks[] = {135, 0};
+ TEST_KECCAK(135, chunks);
+}
+
+TEST(keccak, 135_and_0_135)
+{
+ static const size_t chunks[] = {0, 135};
+ TEST_KECCAK(135, chunks);
+}
+
+TEST(keccak, 136_and_135_1)
+{
+ static const size_t chunks[] = {135, 1};
+ TEST_KECCAK(136, chunks);
+}
+
+TEST(keccak, 136_and_136_0)
+{
+ static const size_t chunks[] = {136, 0};
+ TEST_KECCAK(136, chunks);
+}
+
+TEST(keccak, 136_and_0_136)
+{
+ static const size_t chunks[] = {0, 136};
+ TEST_KECCAK(136, chunks);
+}
+
+TEST(keccak, 136_and_136)
+{
+ static const size_t chunks[] = {136};
+ TEST_KECCAK(136, chunks);
+}
+
+TEST(keccak, 137_and_136_1)
+{
+ static const size_t chunks[] = {136, 1};
+ TEST_KECCAK(137, chunks);
+}
+
+TEST(keccak, 137_and_1_136)
+{
+ static const size_t chunks[] = {1, 136};
+ TEST_KECCAK(137, chunks);
+}
+
diff --git a/tests/unit_tests/main.cpp b/tests/unit_tests/main.cpp
index 13b62cbb4..f7251a09e 100644
--- a/tests/unit_tests/main.cpp
+++ b/tests/unit_tests/main.cpp
@@ -53,6 +53,8 @@ namespace cryptonote { template class t_cryptonote_protocol_handler<cryptonote::
int main(int argc, char** argv)
{
+ TRY_ENTRY();
+
tools::on_startup();
epee::string_tools::set_module_name_and_folder(argv[0]);
mlog_configure(mlog_get_default_log_path("unit_tests.log"), true);
@@ -76,5 +78,7 @@ int main(int argc, char** argv)
unit_test::data_dir = command_line::get_arg(vm, arg_data_dir);
+ CATCH_ENTRY_L0("main", 1);
+
return RUN_ALL_TESTS();
}
diff --git a/tests/unit_tests/mlocker.cpp b/tests/unit_tests/mlocker.cpp
new file mode 100644
index 000000000..c97dc2c1d
--- /dev/null
+++ b/tests/unit_tests/mlocker.cpp
@@ -0,0 +1,195 @@
+// 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 "misc_log_ex.h"
+#include "mlocker.h"
+
+#if defined __GNUC__ && !defined _WIN32
+#define HAVE_MLOCK 1
+#endif
+
+#ifdef HAVE_MLOCK
+
+#define BASE(data) (char*)(((uintptr_t)(data.get() + page_size - 1)) / page_size * page_size)
+
+TEST(mlocker, distinct_1)
+{
+ const size_t page_size = epee::mlocker::get_page_size();
+ ASSERT_TRUE(page_size > 0);
+ const size_t base_pages = epee::mlocker::get_num_locked_pages();
+ const size_t base_objects = epee::mlocker::get_num_locked_objects();
+ std::unique_ptr<char[]> data{new char[8 * page_size]};
+ std::shared_ptr<epee::mlocker> m0{new epee::mlocker(BASE(data), 1)};
+ std::shared_ptr<epee::mlocker> m1{new epee::mlocker(BASE(data) + 2 * page_size, 1)};
+ std::shared_ptr<epee::mlocker> m2{new epee::mlocker(BASE(data) + 3 * page_size, 1)};
+ ASSERT_EQ(epee::mlocker::get_num_locked_pages(), base_pages + 3);
+ ASSERT_EQ(epee::mlocker::get_num_locked_objects(), base_objects + 3);
+ m0 = NULL;
+ m1 = NULL;
+ m2 = NULL;
+ ASSERT_EQ(epee::mlocker::get_num_locked_pages(), base_pages + 0);
+ ASSERT_EQ(epee::mlocker::get_num_locked_objects(), base_objects + 0);
+}
+
+TEST(mlocker, distinct_full_page)
+{
+ const size_t page_size = epee::mlocker::get_page_size();
+ ASSERT_TRUE(page_size > 0);
+ const size_t base_pages = epee::mlocker::get_num_locked_pages();
+ const size_t base_objects = epee::mlocker::get_num_locked_objects();
+ std::unique_ptr<char[]> data{new char[8 * page_size]};
+ std::shared_ptr<epee::mlocker> m0{new epee::mlocker(BASE(data), page_size)};
+ std::shared_ptr<epee::mlocker> m1{new epee::mlocker(BASE(data) + 2 * page_size, page_size)};
+ std::shared_ptr<epee::mlocker> m2{new epee::mlocker(BASE(data) + 3 * page_size, page_size)};
+ ASSERT_EQ(epee::mlocker::get_num_locked_pages(), base_pages + 3);
+ ASSERT_EQ(epee::mlocker::get_num_locked_objects(), base_objects + 3);
+ m0 = NULL;
+ m1 = NULL;
+ m2 = NULL;
+ ASSERT_EQ(epee::mlocker::get_num_locked_pages(), base_pages + 0);
+ ASSERT_EQ(epee::mlocker::get_num_locked_objects(), base_objects + 0);
+}
+
+TEST(mlocker, identical)
+{
+ const size_t page_size = epee::mlocker::get_page_size();
+ ASSERT_TRUE(page_size >= 32);
+ const size_t base_pages = epee::mlocker::get_num_locked_pages();
+ const size_t base_objects = epee::mlocker::get_num_locked_objects();
+ std::unique_ptr<char[]> data{new char[8 * page_size]};
+ std::shared_ptr<epee::mlocker> m0{new epee::mlocker(BASE(data) + page_size, 32)};
+ std::shared_ptr<epee::mlocker> m1{new epee::mlocker(BASE(data) + page_size, 32)};
+ std::shared_ptr<epee::mlocker> m2{new epee::mlocker(BASE(data) + page_size, 32)};
+ ASSERT_EQ(epee::mlocker::get_num_locked_pages(), base_pages + 1);
+ ASSERT_EQ(epee::mlocker::get_num_locked_objects(), base_objects + 3);
+ m1 = NULL;
+ ASSERT_EQ(epee::mlocker::get_num_locked_pages(), base_pages + 1);
+ ASSERT_EQ(epee::mlocker::get_num_locked_objects(), base_objects + 2);
+ m0 = NULL;
+ m2 = NULL;
+ ASSERT_EQ(epee::mlocker::get_num_locked_pages(), base_pages + 0);
+ ASSERT_EQ(epee::mlocker::get_num_locked_objects(), base_objects + 0);
+}
+
+TEST(mlocker, overlapping_small)
+{
+ const size_t page_size = epee::mlocker::get_page_size();
+ ASSERT_TRUE(page_size >= 64);
+ const size_t base_pages = epee::mlocker::get_num_locked_pages();
+ const size_t base_objects = epee::mlocker::get_num_locked_objects();
+ std::unique_ptr<char[]> data{new char[8 * page_size]};
+ std::shared_ptr<epee::mlocker> m0{new epee::mlocker(BASE(data), 32)};
+ std::shared_ptr<epee::mlocker> m1{new epee::mlocker(BASE(data) + 16, 32)};
+ std::shared_ptr<epee::mlocker> m2{new epee::mlocker(BASE(data) + 8, 32)};
+ ASSERT_EQ(epee::mlocker::get_num_locked_pages(), base_pages + 1);
+ ASSERT_EQ(epee::mlocker::get_num_locked_objects(), base_objects + 3);
+ m1 = NULL;
+ ASSERT_EQ(epee::mlocker::get_num_locked_pages(), base_pages + 1);
+ ASSERT_EQ(epee::mlocker::get_num_locked_objects(), base_objects + 2);
+ m2 = NULL;
+ m0 = NULL;
+ ASSERT_EQ(epee::mlocker::get_num_locked_pages(), base_pages + 0);
+ ASSERT_EQ(epee::mlocker::get_num_locked_objects(), base_objects + 0);
+}
+
+TEST(mlocker, multi_page)
+{
+ const size_t page_size = epee::mlocker::get_page_size();
+ ASSERT_TRUE(page_size > 0);
+ const size_t base_pages = epee::mlocker::get_num_locked_pages();
+ const size_t base_objects = epee::mlocker::get_num_locked_objects();
+ std::unique_ptr<char[]> data{new char[8 * page_size]};
+ std::shared_ptr<epee::mlocker> m0{new epee::mlocker(BASE(data) + page_size, page_size * 3)};
+ ASSERT_EQ(epee::mlocker::get_num_locked_pages(), base_pages + 3);
+ ASSERT_EQ(epee::mlocker::get_num_locked_objects(), base_objects + 1);
+ std::shared_ptr<epee::mlocker> m1{new epee::mlocker(BASE(data) + page_size * 7, page_size)};
+ ASSERT_EQ(epee::mlocker::get_num_locked_pages(), base_pages + 4);
+ ASSERT_EQ(epee::mlocker::get_num_locked_objects(), base_objects + 2);
+ m0 = NULL;
+ ASSERT_EQ(epee::mlocker::get_num_locked_pages(), base_pages + 1);
+ ASSERT_EQ(epee::mlocker::get_num_locked_objects(), base_objects + 1);
+ m1 = NULL;
+ ASSERT_EQ(epee::mlocker::get_num_locked_pages(), base_pages + 0);
+ ASSERT_EQ(epee::mlocker::get_num_locked_objects(), base_objects + 0);
+}
+
+TEST(mlocker, cross_page)
+{
+ const size_t page_size = epee::mlocker::get_page_size();
+ ASSERT_TRUE(page_size > 32);
+ const size_t base_pages = epee::mlocker::get_num_locked_pages();
+ const size_t base_objects = epee::mlocker::get_num_locked_objects();
+ std::unique_ptr<char[]> data{new char[2 * page_size]};
+ std::shared_ptr<epee::mlocker> m0{new epee::mlocker(BASE(data) + page_size - 1, 2)};
+ ASSERT_EQ(epee::mlocker::get_num_locked_pages(), base_pages + 2);
+ ASSERT_EQ(epee::mlocker::get_num_locked_objects(), base_objects + 1);
+ m0 = NULL;
+ ASSERT_EQ(epee::mlocker::get_num_locked_pages(), base_pages + 0);
+ ASSERT_EQ(epee::mlocker::get_num_locked_objects(), base_objects + 0);
+}
+
+TEST(mlocker, redundant)
+{
+ const size_t page_size = epee::mlocker::get_page_size();
+ ASSERT_TRUE(page_size > 0);
+ const size_t base_pages = epee::mlocker::get_num_locked_pages();
+ const size_t base_objects = epee::mlocker::get_num_locked_objects();
+ std::unique_ptr<char[]> data{new char[2 * page_size]};
+ ASSERT_EQ(epee::mlocker::get_num_locked_pages(), base_pages + 0);
+ ASSERT_EQ(epee::mlocker::get_num_locked_objects(), base_objects + 0);
+ std::shared_ptr<epee::mlocker> m0{new epee::mlocker(BASE(data), 32)};
+ ASSERT_EQ(epee::mlocker::get_num_locked_pages(), base_pages + 1);
+ ASSERT_EQ(epee::mlocker::get_num_locked_objects(), base_objects + 1);
+ std::shared_ptr<epee::mlocker> m1{new epee::mlocker(BASE(data), 32)};
+ ASSERT_EQ(epee::mlocker::get_num_locked_pages(), base_pages + 1);
+ ASSERT_EQ(epee::mlocker::get_num_locked_objects(), base_objects + 2);
+ m1 = NULL;
+ ASSERT_EQ(epee::mlocker::get_num_locked_pages(), base_pages + 1);
+ ASSERT_EQ(epee::mlocker::get_num_locked_objects(), base_objects + 1);
+ m0 = NULL;
+ ASSERT_EQ(epee::mlocker::get_num_locked_pages(), base_pages + 0);
+ ASSERT_EQ(epee::mlocker::get_num_locked_objects(), base_objects + 0);
+}
+
+TEST(mlocker, mlocked)
+{
+ const size_t base_pages = epee::mlocker::get_num_locked_pages();
+ const size_t base_objects = epee::mlocker::get_num_locked_objects();
+ {
+ struct Foo { uint64_t u; };
+ epee::mlocked<Foo> l;
+ ASSERT_EQ(epee::mlocker::get_num_locked_pages(), base_pages + 1);
+ ASSERT_EQ(epee::mlocker::get_num_locked_objects(), base_objects + 1);
+ }
+ ASSERT_EQ(epee::mlocker::get_num_locked_pages(), base_pages + 0);
+ ASSERT_EQ(epee::mlocker::get_num_locked_objects(), base_objects + 0);
+}
+
+#endif
diff --git a/tests/unit_tests/mnemonics.cpp b/tests/unit_tests/mnemonics.cpp
index 8fa3192b9..0b74a6b94 100644
--- a/tests/unit_tests/mnemonics.cpp
+++ b/tests/unit_tests/mnemonics.cpp
@@ -27,6 +27,8 @@
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "gtest/gtest.h"
+#include "wipeable_string.h"
+#include "mnemonics/language_base.h"
#include "mnemonics/electrum-words.h"
#include "crypto/crypto.h"
#include <stdlib.h>
@@ -74,14 +76,16 @@ namespace
void test_language(const Language::Base &language)
{
const std::vector<std::string> &word_list = language.get_word_list();
- std::string seed = "", return_seed = "";
+ epee::wipeable_string w_seed = "", w_return_seed = "";
+ std::string seed, return_seed;
// Generate a random seed without checksum
crypto::secret_key randkey;
for (size_t ii = 0; ii < sizeof(randkey); ++ii)
{
randkey.data[ii] = rand();
}
- crypto::ElectrumWords::bytes_to_words(randkey, seed, language.get_language_name());
+ crypto::ElectrumWords::bytes_to_words(randkey, w_seed, language.get_language_name());
+ seed = std::string(w_seed.data(), w_seed.size());
// remove the checksum word
const char *space = strrchr(seed.c_str(), ' ');
ASSERT_TRUE(space != NULL);
@@ -103,7 +107,8 @@ namespace
ASSERT_STREQ(language.get_language_name().c_str(), language_name.c_str());
// Convert the secret key back to seed
- crypto::ElectrumWords::bytes_to_words(key, return_seed, language.get_language_name());
+ crypto::ElectrumWords::bytes_to_words(key, w_return_seed, language.get_language_name());
+ return_seed = std::string(w_return_seed.data(), w_return_seed.size());
ASSERT_EQ(true, res);
std::cout << "Returned seed:\n";
std::cout << return_seed << std::endl;
@@ -126,8 +131,9 @@ namespace
std::cout << "Detected language: " << language_name << std::endl;
ASSERT_STREQ(language.get_language_name().c_str(), language_name.c_str());
- return_seed = "";
- crypto::ElectrumWords::bytes_to_words(key, return_seed, language.get_language_name());
+ w_return_seed = "";
+ crypto::ElectrumWords::bytes_to_words(key, w_return_seed, language.get_language_name());
+ return_seed = std::string(w_return_seed.data(), w_return_seed.size());
ASSERT_EQ(true, res);
std::cout << "Returned seed:\n";
std::cout << return_seed << std::endl;
@@ -202,3 +208,17 @@ TEST(mnemonics, language_detection_with_bad_checksum)
ASSERT_EQ(true, res);
ASSERT_STREQ(language_name.c_str(), "Português");
}
+
+TEST(mnemonics, utf8prefix)
+{
+ ASSERT_TRUE(Language::utf8prefix(epee::wipeable_string("foo"), 0) == "");
+ ASSERT_TRUE(Language::utf8prefix(epee::wipeable_string("foo"), 1) == "f");
+ ASSERT_TRUE(Language::utf8prefix(epee::wipeable_string("foo"), 2) == "fo");
+ ASSERT_TRUE(Language::utf8prefix(epee::wipeable_string("foo"), 3) == "foo");
+ ASSERT_TRUE(Language::utf8prefix(epee::wipeable_string("foo"), 4) == "foo");
+ ASSERT_TRUE(Language::utf8prefix(epee::wipeable_string("æon"), 0) == "");
+ ASSERT_TRUE(Language::utf8prefix(epee::wipeable_string("æon"), 1) == "æ");
+ ASSERT_TRUE(Language::utf8prefix(epee::wipeable_string("æon"), 2) == "æo");
+ ASSERT_TRUE(Language::utf8prefix(epee::wipeable_string("æon"), 3) == "æon");
+ ASSERT_TRUE(Language::utf8prefix(epee::wipeable_string("æon"), 4) == "æon");
+}
diff --git a/tests/unit_tests/multiexp.cpp b/tests/unit_tests/multiexp.cpp
new file mode 100644
index 000000000..d8d79a7a2
--- /dev/null
+++ b/tests/unit_tests/multiexp.cpp
@@ -0,0 +1,254 @@
+// 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 "crypto/crypto.h"
+#include "ringct/rctOps.h"
+#include "ringct/multiexp.h"
+
+static const rct::key TESTSCALAR = rct::skGen();
+static const rct::key TESTPOW2SCALAR = {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}};
+static const rct::key TESTSMALLSCALAR = {{5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}};
+static const rct::key TESTPOINT = rct::scalarmultBase(rct::skGen());
+
+static rct::key basic(const std::vector<rct::MultiexpData> &data)
+{
+ ge_p3 res_p3 = ge_p3_identity;
+ for (const auto &d: data)
+ {
+ ge_cached cached;
+ ge_p3 p3;
+ ge_p1p1 p1;
+ ge_scalarmult_p3(&p3, d.scalar.bytes, &d.point);
+ ge_p3_to_cached(&cached, &p3);
+ ge_add(&p1, &res_p3, &cached);
+ ge_p1p1_to_p3(&res_p3, &p1);
+ }
+ rct::key res;
+ ge_p3_tobytes(res.bytes, &res_p3);
+ return res;
+}
+
+static ge_p3 get_p3(const rct::key &point)
+{
+ ge_p3 p3;
+ EXPECT_TRUE(ge_frombytes_vartime(&p3, point.bytes) == 0);
+ return p3;
+}
+
+TEST(multiexp, bos_coster_empty)
+{
+ std::vector<rct::MultiexpData> data;
+ data.push_back({rct::zero(), get_p3(rct::identity())});
+ ASSERT_TRUE(basic(data) == bos_coster_heap_conv_robust(data));
+}
+
+TEST(multiexp, straus_empty)
+{
+ std::vector<rct::MultiexpData> data;
+ data.push_back({rct::zero(), get_p3(rct::identity())});
+ ASSERT_TRUE(basic(data) == straus(data));
+}
+
+TEST(multiexp, pippenger_empty)
+{
+ std::vector<rct::MultiexpData> data;
+ data.push_back({rct::zero(), get_p3(rct::identity())});
+ ASSERT_TRUE(basic(data) == pippenger(data));
+}
+
+TEST(multiexp, bos_coster_zero_and_non_zero)
+{
+ std::vector<rct::MultiexpData> data;
+ data.push_back({rct::zero(), get_p3(TESTPOINT)});
+ data.push_back({TESTSCALAR, get_p3(TESTPOINT)});
+ ASSERT_TRUE(basic(data) == bos_coster_heap_conv_robust(data));
+}
+
+TEST(multiexp, straus_zero_and_non_zero)
+{
+ std::vector<rct::MultiexpData> data;
+ data.push_back({rct::zero(), get_p3(TESTPOINT)});
+ data.push_back({TESTSCALAR, get_p3(TESTPOINT)});
+ ASSERT_TRUE(basic(data) == straus(data));
+}
+
+TEST(multiexp, pippenger_zero_and_non_zero)
+{
+ std::vector<rct::MultiexpData> data;
+ data.push_back({rct::zero(), get_p3(TESTPOINT)});
+ data.push_back({TESTSCALAR, get_p3(TESTPOINT)});
+ ASSERT_TRUE(basic(data) == pippenger(data));
+}
+
+TEST(multiexp, bos_coster_pow2_scalar)
+{
+ std::vector<rct::MultiexpData> data;
+ data.push_back({TESTPOW2SCALAR, get_p3(TESTPOINT)});
+ data.push_back({TESTSMALLSCALAR, get_p3(TESTPOINT)});
+ ASSERT_TRUE(basic(data) == bos_coster_heap_conv_robust(data));
+}
+
+TEST(multiexp, straus_pow2_scalar)
+{
+ std::vector<rct::MultiexpData> data;
+ data.push_back({TESTPOW2SCALAR, get_p3(TESTPOINT)});
+ data.push_back({TESTSMALLSCALAR, get_p3(TESTPOINT)});
+ ASSERT_TRUE(basic(data) == straus(data));
+}
+
+TEST(multiexp, pippenger_pow2_scalar)
+{
+ std::vector<rct::MultiexpData> data;
+ data.push_back({TESTPOW2SCALAR, get_p3(TESTPOINT)});
+ data.push_back({TESTSMALLSCALAR, get_p3(TESTPOINT)});
+ ASSERT_TRUE(basic(data) == pippenger(data));
+}
+
+TEST(multiexp, bos_coster_only_zeroes)
+{
+ std::vector<rct::MultiexpData> data;
+ for (int n = 0; n < 16; ++n)
+ data.push_back({rct::zero(), get_p3(TESTPOINT)});
+ ASSERT_TRUE(basic(data) == bos_coster_heap_conv_robust(data));
+}
+
+TEST(multiexp, straus_only_zeroes)
+{
+ std::vector<rct::MultiexpData> data;
+ for (int n = 0; n < 16; ++n)
+ data.push_back({rct::zero(), get_p3(TESTPOINT)});
+ ASSERT_TRUE(basic(data) == straus(data));
+}
+
+TEST(multiexp, pippenger_only_zeroes)
+{
+ std::vector<rct::MultiexpData> data;
+ for (int n = 0; n < 16; ++n)
+ data.push_back({rct::zero(), get_p3(TESTPOINT)});
+ ASSERT_TRUE(basic(data) == pippenger(data));
+}
+
+TEST(multiexp, bos_coster_only_identities)
+{
+ std::vector<rct::MultiexpData> data;
+ for (int n = 0; n < 16; ++n)
+ data.push_back({TESTSCALAR, get_p3(rct::identity())});
+ ASSERT_TRUE(basic(data) == bos_coster_heap_conv_robust(data));
+}
+
+TEST(multiexp, straus_only_identities)
+{
+ std::vector<rct::MultiexpData> data;
+ for (int n = 0; n < 16; ++n)
+ data.push_back({TESTSCALAR, get_p3(rct::identity())});
+ ASSERT_TRUE(basic(data) == straus(data));
+}
+
+TEST(multiexp, pippenger_only_identities)
+{
+ std::vector<rct::MultiexpData> data;
+ for (int n = 0; n < 16; ++n)
+ data.push_back({TESTSCALAR, get_p3(rct::identity())});
+ ASSERT_TRUE(basic(data) == pippenger(data));
+}
+
+TEST(multiexp, bos_coster_random)
+{
+ std::vector<rct::MultiexpData> data;
+ for (int n = 0; n < 32; ++n)
+ {
+ data.push_back({rct::skGen(), get_p3(rct::scalarmultBase(rct::skGen()))});
+ ASSERT_TRUE(basic(data) == bos_coster_heap_conv_robust(data));
+ }
+}
+
+TEST(multiexp, straus_random)
+{
+ std::vector<rct::MultiexpData> data;
+ for (int n = 0; n < 32; ++n)
+ {
+ data.push_back({rct::skGen(), get_p3(rct::scalarmultBase(rct::skGen()))});
+ ASSERT_TRUE(basic(data) == straus(data));
+ }
+}
+
+TEST(multiexp, pippenger_random)
+{
+ std::vector<rct::MultiexpData> data;
+ for (int n = 0; n < 32; ++n)
+ {
+ data.push_back({rct::skGen(), get_p3(rct::scalarmultBase(rct::skGen()))});
+ ASSERT_TRUE(basic(data) == pippenger(data));
+ }
+}
+
+TEST(multiexp, straus_cached)
+{
+ static constexpr size_t N = 256;
+ std::vector<rct::MultiexpData> P(N);
+ for (size_t n = 0; n < N; ++n)
+ {
+ P[n].scalar = rct::zero();
+ ASSERT_TRUE(ge_frombytes_vartime(&P[n].point, rct::scalarmultBase(rct::skGen()).bytes) == 0);
+ }
+ std::shared_ptr<rct::straus_cached_data> cache = rct::straus_init_cache(P);
+ for (size_t n = 0; n < N/16; ++n)
+ {
+ std::vector<rct::MultiexpData> data;
+ size_t sz = 1 + crypto::rand<size_t>() % (N-1);
+ for (size_t s = 0; s < sz; ++s)
+ {
+ data.push_back({rct::skGen(), P[s].point});
+ }
+ ASSERT_TRUE(basic(data) == straus(data, cache));
+ }
+}
+
+TEST(multiexp, pippenger_cached)
+{
+ static constexpr size_t N = 256;
+ std::vector<rct::MultiexpData> P(N);
+ for (size_t n = 0; n < N; ++n)
+ {
+ P[n].scalar = rct::zero();
+ ASSERT_TRUE(ge_frombytes_vartime(&P[n].point, rct::scalarmultBase(rct::skGen()).bytes) == 0);
+ }
+ std::shared_ptr<rct::pippenger_cached_data> cache = rct::pippenger_init_cache(P);
+ for (size_t n = 0; n < N/16; ++n)
+ {
+ std::vector<rct::MultiexpData> data;
+ size_t sz = 1 + crypto::rand<size_t>() % (N-1);
+ for (size_t s = 0; s < sz; ++s)
+ {
+ data.push_back({rct::skGen(), P[s].point});
+ }
+ ASSERT_TRUE(basic(data) == pippenger(data, cache));
+ }
+}
diff --git a/tests/unit_tests/multisig.cpp b/tests/unit_tests/multisig.cpp
index 922299333..7268f2690 100644
--- a/tests/unit_tests/multisig.cpp
+++ b/tests/unit_tests/multisig.cpp
@@ -49,9 +49,19 @@ static const struct
{
"9t6Hn946u3eah5cuncH1hB5hGzsTUoevtf4SY7MHN5NgJZh2SFWsyVt3vUhuHyRKyrCQvr71Lfc1AevG3BXE11PQFoXDtD8",
"bbd3175ef9fd9f5eefdc43035f882f74ad14c4cf1799d8b6f9001bc197175d02"
+ },
+ {
+ "9zmAWoNyNPbgnYSm3nJNpAKHm6fCcs3MR94gBWxp9MCDUiMUhyYFfyQETUDLPF7DP6ZsmNo6LRxwPP9VmhHNxKrER9oGigT",
+ "f2efae45bef1917a7430cda8fcffc4ee010e3178761aa41d4628e23b1fe2d501"
+ },
+ {
+ "9ue8NJMg3WzKxTtmjeXzWYF5KmU6dC7LHEt9wvYdPn2qMmoFUa8hJJHhSHvJ46UEwpDyy5jSboNMRaDBKwU54NT42YcNUp5",
+ "a4cef54ed3fd61cd78a2ceb82ecf85a903ad2db9a86fb77ff56c35c56016280a"
}
};
+static const size_t KEYS_COUNT = 5;
+
static void make_wallet(unsigned int idx, tools::wallet2 &wallet)
{
ASSERT_TRUE(idx < sizeof(test_addresses) / sizeof(test_addresses[0]));
@@ -65,6 +75,9 @@ static void make_wallet(unsigned int idx, tools::wallet2 &wallet)
wallet.set_subaddress_lookahead(1, 1);
wallet.generate("", "", spendkey, true, false);
ASSERT_TRUE(test_addresses[idx].address == wallet.get_account().get_public_address_str(cryptonote::TESTNET));
+ wallet.decrypt_keys("");
+ ASSERT_TRUE(test_addresses[idx].spendkey == epee::string_tools::pod_to_hex(wallet.get_account().get_keys().m_spend_secret_key));
+ wallet.encrypt_keys("");
}
catch (const std::exception &e)
{
@@ -73,116 +86,87 @@ static void make_wallet(unsigned int idx, tools::wallet2 &wallet)
}
}
-static void make_M_2_wallet(tools::wallet2 &wallet0, tools::wallet2 &wallet1, unsigned int M)
+static std::vector<std::string> exchange_round(std::vector<tools::wallet2>& wallets, const std::vector<std::string>& mis)
{
- ASSERT_TRUE(M <= 2);
-
- make_wallet(0, wallet0);
- make_wallet(1, wallet1);
-
- std::vector<crypto::secret_key> sk0(1), sk1(1);
- std::vector<crypto::public_key> pk0(1), pk1(1);
-
- std::string mi0 = wallet0.get_multisig_info();
- std::string mi1 = wallet1.get_multisig_info();
-
- ASSERT_TRUE(tools::wallet2::verify_multisig_info(mi1, sk0[0], pk0[0]));
- ASSERT_TRUE(tools::wallet2::verify_multisig_info(mi0, sk1[0], pk1[0]));
-
- ASSERT_FALSE(wallet0.multisig() || wallet1.multisig());
- wallet0.make_multisig("", sk0, pk0, M);
- wallet1.make_multisig("", sk1, pk1, M);
-
- ASSERT_TRUE(wallet0.get_account().get_public_address_str(cryptonote::TESTNET) == wallet1.get_account().get_public_address_str(cryptonote::TESTNET));
+ std::vector<std::string> new_infos;
+ for (size_t i = 0; i < wallets.size(); ++i) {
+ new_infos.push_back(wallets[i].exchange_multisig_keys("", mis));
+ }
- bool ready;
- uint32_t threshold, total;
- ASSERT_TRUE(wallet0.multisig(&ready, &threshold, &total));
- ASSERT_TRUE(ready);
- ASSERT_TRUE(threshold == M);
- ASSERT_TRUE(total == 2);
- ASSERT_TRUE(wallet1.multisig(&ready, &threshold, &total));
- ASSERT_TRUE(ready);
- ASSERT_TRUE(threshold == M);
- ASSERT_TRUE(total == 2);
+ return new_infos;
}
-static void make_M_3_wallet(tools::wallet2 &wallet0, tools::wallet2 &wallet1, tools::wallet2 &wallet2, unsigned int M)
+static void make_wallets(std::vector<tools::wallet2>& wallets, unsigned int M)
{
- ASSERT_TRUE(M <= 3);
+ ASSERT_TRUE(wallets.size() > 1 && wallets.size() <= KEYS_COUNT);
+ ASSERT_TRUE(M <= wallets.size());
- make_wallet(0, wallet0);
- make_wallet(1, wallet1);
- make_wallet(2, wallet2);
+ std::vector<std::string> mis(wallets.size());
- std::vector<crypto::secret_key> sk0(2), sk1(2), sk2(2);
- std::vector<crypto::public_key> pk0(2), pk1(2), pk2(2);
+ for (size_t i = 0; i < wallets.size(); ++i) {
+ make_wallet(i, wallets[i]);
- std::string mi0 = wallet0.get_multisig_info();
- std::string mi1 = wallet1.get_multisig_info();
- std::string mi2 = wallet2.get_multisig_info();
-
- ASSERT_TRUE(tools::wallet2::verify_multisig_info(mi1, sk0[0], pk0[0]));
- ASSERT_TRUE(tools::wallet2::verify_multisig_info(mi2, sk0[1], pk0[1]));
- ASSERT_TRUE(tools::wallet2::verify_multisig_info(mi0, sk1[0], pk1[0]));
- ASSERT_TRUE(tools::wallet2::verify_multisig_info(mi2, sk1[1], pk1[1]));
- ASSERT_TRUE(tools::wallet2::verify_multisig_info(mi0, sk2[0], pk2[0]));
- ASSERT_TRUE(tools::wallet2::verify_multisig_info(mi1, sk2[1], pk2[1]));
+ wallets[i].decrypt_keys("");
+ mis[i] = wallets[i].get_multisig_info();
+ wallets[i].encrypt_keys("");
+ }
- ASSERT_FALSE(wallet0.multisig() || wallet1.multisig() || wallet2.multisig());
- std::string mxi0 = wallet0.make_multisig("", sk0, pk0, M);
- std::string mxi1 = wallet1.make_multisig("", sk1, pk1, M);
- std::string mxi2 = wallet2.make_multisig("", sk2, pk2, M);
+ for (auto& wallet: wallets) {
+ ASSERT_FALSE(wallet.multisig() || wallet.multisig() || wallet.multisig());
+ }
- const size_t nset = !mxi0.empty() + !mxi1.empty() + !mxi2.empty();
- ASSERT_TRUE((M < 3 && nset == 3) || (M == 3 && nset == 0));
+ std::vector<std::string> mxis;
+ for (size_t i = 0; i < wallets.size(); ++i) {
+ // it's ok to put all of multisig keys in this function. it throws in case of error
+ mxis.push_back(wallets[i].make_multisig("", mis, M));
+ }
- if (nset > 0)
- {
- std::unordered_set<crypto::public_key> pkeys;
- std::vector<crypto::public_key> signers(3, crypto::null_pkey);
- ASSERT_TRUE(tools::wallet2::verify_extra_multisig_info(mxi0, pkeys, signers[0]));
- ASSERT_TRUE(tools::wallet2::verify_extra_multisig_info(mxi1, pkeys, signers[1]));
- ASSERT_TRUE(tools::wallet2::verify_extra_multisig_info(mxi2, pkeys, signers[2]));
- ASSERT_TRUE(pkeys.size() == 3);
- ASSERT_TRUE(wallet0.finalize_multisig("", pkeys, signers));
- ASSERT_TRUE(wallet1.finalize_multisig("", pkeys, signers));
- ASSERT_TRUE(wallet2.finalize_multisig("", pkeys, signers));
+ while (!mxis[0].empty()) {
+ mxis = exchange_round(wallets, mxis);
}
- ASSERT_TRUE(wallet0.get_account().get_public_address_str(cryptonote::TESTNET) == wallet1.get_account().get_public_address_str(cryptonote::TESTNET));
- ASSERT_TRUE(wallet0.get_account().get_public_address_str(cryptonote::TESTNET) == wallet2.get_account().get_public_address_str(cryptonote::TESTNET));
-
- bool ready;
- uint32_t threshold, total;
- ASSERT_TRUE(wallet0.multisig(&ready, &threshold, &total));
- ASSERT_TRUE(ready);
- ASSERT_TRUE(threshold == M);
- ASSERT_TRUE(total == 3);
- ASSERT_TRUE(wallet1.multisig(&ready, &threshold, &total));
- ASSERT_TRUE(ready);
- ASSERT_TRUE(threshold == M);
- ASSERT_TRUE(total == 3);
- ASSERT_TRUE(wallet2.multisig(&ready, &threshold, &total));
- ASSERT_TRUE(ready);
- ASSERT_TRUE(threshold == M);
- ASSERT_TRUE(total == 3);
+ for (size_t i = 0; i < wallets.size(); ++i) {
+ ASSERT_TRUE(mxis[i].empty());
+ bool ready;
+ uint32_t threshold, total;
+ ASSERT_TRUE(wallets[i].multisig(&ready, &threshold, &total));
+ ASSERT_TRUE(ready);
+ ASSERT_TRUE(threshold == M);
+ ASSERT_TRUE(total == wallets.size());
+
+ if (i != 0) {
+ // "equals" is transitive relation so we need only to compare first wallet's address to each others' addresses. no need to compare 0's address with itself.
+ ASSERT_TRUE(wallets[0].get_account().get_public_address_str(cryptonote::TESTNET) == wallets[i].get_account().get_public_address_str(cryptonote::TESTNET));
+ }
+ }
}
TEST(multisig, make_2_2)
{
- tools::wallet2 wallet0, wallet1;
- make_M_2_wallet(wallet0, wallet1, 2);
+ std::vector<tools::wallet2> wallets(2);
+ make_wallets(wallets, 2);
}
TEST(multisig, make_3_3)
{
- tools::wallet2 wallet0, wallet1, wallet2;
- make_M_3_wallet(wallet0, wallet1, wallet2, 3);
+ std::vector<tools::wallet2> wallets(3);
+ make_wallets(wallets, 3);
}
TEST(multisig, make_2_3)
{
- tools::wallet2 wallet0, wallet1, wallet2;
- make_M_3_wallet(wallet0, wallet1, wallet2, 2);
+ std::vector<tools::wallet2> wallets(3);
+ make_wallets(wallets, 2);
+}
+
+TEST(multisig, make_2_4)
+{
+ std::vector<tools::wallet2> wallets(4);
+ make_wallets(wallets, 2);
+}
+
+TEST(multisig, make_2_5)
+{
+ std::vector<tools::wallet2> wallets(5);
+ make_wallets(wallets, 2);
}
diff --git a/tests/unit_tests/notify.cpp b/tests/unit_tests/notify.cpp
new file mode 100644
index 000000000..4daeeddee
--- /dev/null
+++ b/tests/unit_tests/notify.cpp
@@ -0,0 +1,79 @@
+// 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.
+
+#ifdef __GLIBC__
+#include <sys/stat.h>
+#endif
+
+#include "gtest/gtest.h"
+
+#include <boost/filesystem.hpp>
+
+#include "misc_language.h"
+#include "string_tools.h"
+#include "file_io_utils.h"
+#include "common/notify.h"
+
+TEST(notify, works)
+{
+#ifdef __GLIBC__
+ mode_t prevmode = umask(077);
+#endif
+ const char *tmp = getenv("TEMP");
+ if (!tmp)
+ tmp = "/tmp";
+ static const char *filename = "monero-notify-unit-test-XXXXXX";
+ const size_t len = strlen(tmp) + 1 + strlen(filename);
+ char *name_template = (char*)malloc(len + 1);
+ ASSERT_TRUE(name_template != NULL);
+ snprintf(name_template, len + 1, "%s/%s", tmp, filename);
+ int fd = mkstemp(name_template);
+#ifdef __GLIBC__
+ umask(prevmode);
+#endif
+ ASSERT_TRUE(fd >= 0);
+ close(fd);
+
+ const std::string spec = epee::string_tools::get_current_module_folder() + "/test_notifier"
+#ifdef _WIN32
+ + ".exe"
+#endif
+ + " " + name_template + " %s";
+
+ tools::Notify notify(spec.c_str());
+ notify.notify("1111111111111111111111111111111111111111111111111111111111111111");
+
+ epee::misc_utils::sleep_no_w(100);
+
+ std::string s;
+ ASSERT_TRUE(epee::file_io_utils::load_file_to_string(name_template, s));
+ ASSERT_TRUE(s == "1111111111111111111111111111111111111111111111111111111111111111");
+
+ boost::filesystem::remove(name_template);
+ free(name_template);
+}
diff --git a/tests/unit_tests/random.cpp b/tests/unit_tests/random.cpp
new file mode 100644
index 000000000..7653453cd
--- /dev/null
+++ b/tests/unit_tests/random.cpp
@@ -0,0 +1,47 @@
+// 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 "crypto/crypto.h"
+
+extern "C" {
+#include "crypto/crypto-ops.h"
+}
+
+TEST(random32_unbiased, less_than_order)
+{
+ unsigned char tmp[32], tmp2[32];
+ for (int i = 0; i < 1000; ++i)
+ {
+ crypto::random32_unbiased(tmp);
+ memcpy(tmp2, tmp, 32);
+ sc_reduce32(tmp2);
+ ASSERT_EQ(memcmp(tmp, tmp2, 32), 0);
+ }
+}
diff --git a/tests/unit_tests/ringct.cpp b/tests/unit_tests/ringct.cpp
index b7fcbbcab..3877ef785 100644
--- a/tests/unit_tests/ringct.cpp
+++ b/tests/unit_tests/ringct.cpp
@@ -957,12 +957,20 @@ TEST(ringct, fee_burn_valid_zero_out_simple)
EXPECT_TRUE(range_proof_test(true, NELTS(inputs), inputs, NELTS(outputs), outputs, true, true));
}
+static rctSig make_sig()
+{
+ static const uint64_t inputs[] = {1000, 1000};
+ static const uint64_t outputs[] = {1000, 1000};
+ static rct::rctSig sig = make_sample_rct_sig(NELTS(inputs), inputs, NELTS(outputs), outputs, true);
+ return sig;
+}
+
#define TEST_rctSig_elements(name, op) \
TEST(ringct, rctSig_##name) \
{ \
const uint64_t inputs[] = {1000, 1000}; \
const uint64_t outputs[] = {1000, 1000}; \
- rct::rctSig sig = make_sample_rct_sig(NELTS(inputs), inputs, NELTS(outputs), outputs, true); \
+ rct::rctSig sig = make_sig(); \
ASSERT_TRUE(rct::verRct(sig)); \
op; \
ASSERT_FALSE(rct::verRct(sig)); \
@@ -994,12 +1002,18 @@ TEST_rctSig_elements(outPk_empty, sig.outPk.resize(0));
TEST_rctSig_elements(outPk_too_many, sig.outPk.push_back(sig.outPk.back()));
TEST_rctSig_elements(outPk_too_few, sig.outPk.pop_back());
+static rct::rctSig make_sig_simple()
+{
+ static const uint64_t inputs[] = {1000, 1000};
+ static const uint64_t outputs[] = {1000};
+ static rct::rctSig sig = make_sample_simple_rct_sig(NELTS(inputs), inputs, NELTS(outputs), outputs, 1000);
+ return sig;
+}
+
#define TEST_rctSig_elements_simple(name, op) \
TEST(ringct, rctSig_##name##_simple) \
{ \
- const uint64_t inputs[] = {1000, 1000}; \
- const uint64_t outputs[] = {1000}; \
- rct::rctSig sig = make_sample_simple_rct_sig(NELTS(inputs), inputs, NELTS(outputs), outputs, 1000); \
+ rct::rctSig sig = make_sig_simple(); \
ASSERT_TRUE(rct::verRctSimple(sig)); \
op; \
ASSERT_FALSE(rct::verRctSimple(sig)); \
@@ -1061,3 +1075,44 @@ TEST(ringct, key_ostream)
out.str()
);
}
+
+TEST(ringct, zeroCommmit)
+{
+ static const uint64_t amount = crypto::rand<uint64_t>();
+ const rct::key z = rct::zeroCommit(amount);
+ const rct::key a = rct::scalarmultBase(rct::identity());
+ const rct::key b = rct::scalarmultH(rct::d2h(amount));
+ const rct::key manual = rct::addKeys(a, b);
+ ASSERT_EQ(z, manual);
+}
+
+TEST(ringct, H)
+{
+ ge_p3 p3;
+ ASSERT_EQ(ge_frombytes_vartime(&p3, rct::H.bytes), 0);
+ ASSERT_EQ(memcmp(&p3, &ge_p3_H, sizeof(ge_p3)), 0);
+}
+
+TEST(ringct, mul8)
+{
+ ASSERT_EQ(rct::scalarmult8(rct::identity()), rct::identity());
+ ASSERT_EQ(rct::scalarmult8(rct::H), rct::scalarmultKey(rct::H, rct::EIGHT));
+ ASSERT_EQ(rct::scalarmultKey(rct::scalarmultKey(rct::H, rct::INV_EIGHT), rct::EIGHT), rct::H);
+}
+
+TEST(ringct, aggregated)
+{
+ static const size_t N_PROOFS = 16;
+ std::vector<rctSig> s(N_PROOFS);
+ std::vector<const rctSig*> sp(N_PROOFS);
+
+ for (size_t n = 0; n < N_PROOFS; ++n)
+ {
+ static const uint64_t inputs[] = {1000, 1000};
+ static const uint64_t outputs[] = {500, 1500};
+ s[n] = make_sample_simple_rct_sig(NELTS(inputs), inputs, NELTS(outputs), outputs, 0);
+ sp[n] = &s[n];
+ }
+
+ ASSERT_TRUE(verRctSemanticsSimple(sp));
+}
diff --git a/tests/unit_tests/ringdb.cpp b/tests/unit_tests/ringdb.cpp
index d50d61b0f..ab634ea82 100644
--- a/tests/unit_tests/ringdb.cpp
+++ b/tests/unit_tests/ringdb.cpp
@@ -39,33 +39,37 @@
#include "crypto/crypto.h"
#include "crypto/random.h"
#include "crypto/chacha.h"
+#include "ringct/rctOps.h"
+#include "cryptonote_basic/cryptonote_basic.h"
#include "wallet/ringdb.h"
static crypto::chacha_key generate_chacha_key()
{
- uint8_t key[CHACHA_KEY_SIZE];
- crypto::rand(CHACHA_KEY_SIZE, key);
crypto::chacha_key chacha_key;
- memcpy(&chacha_key, key, CHACHA_KEY_SIZE);
+ uint64_t password = crypto::rand<uint64_t>();
+ crypto::generate_chacha_key(std::string((const char*)&password, sizeof(password)), chacha_key, 1);
return chacha_key;
}
static crypto::key_image generate_key_image()
{
- return crypto::rand<crypto::key_image>();
+ crypto::key_image key_image;
+ cryptonote::keypair keypair = cryptonote::keypair::generate(hw::get_device("default"));
+ crypto::generate_key_image(keypair.pub, keypair.sec, key_image);
+ return key_image;
}
-static crypto::public_key generate_output()
+static std::pair<uint64_t, uint64_t> generate_output()
{
- return crypto::rand<crypto::public_key>();
+ return std::make_pair(rand(), rand());
}
static const crypto::chacha_key KEY_1 = generate_chacha_key();
static const crypto::chacha_key KEY_2 = generate_chacha_key();
static const crypto::key_image KEY_IMAGE_1 = generate_key_image();
-static const crypto::public_key OUTPUT_1 = generate_output();
-static const crypto::public_key OUTPUT_2 = generate_output();
+static const std::pair<uint64_t, uint64_t> OUTPUT_1 = generate_output();
+static const std::pair<uint64_t, uint64_t> OUTPUT_2 = generate_output();
class RingDB: public tools::ringdb
{
@@ -76,13 +80,13 @@ public:
private:
std::string make_filename()
{
- boost::filesystem::path path = tools::get_default_data_dir();
- path /= "fake";
+ boost::filesystem::path path =
+ boost::filesystem::temp_directory_path();
#if defined(__MINGW32__) || defined(__MINGW__)
- filename = tempnam(path.string().c_str(), "ringdb-test-");
+ filename = tempnam(path.string().c_str(), "monero-ringdb-test-");
EXPECT_TRUE(filename != NULL);
#else
- path /= "ringdb-test-XXXXXX";
+ path /= "monero-ringdb-test-XXXXXX";
filename = strdup(path.string().c_str());
EXPECT_TRUE(mkdtemp(filename) != NULL);
#endif
@@ -132,21 +136,45 @@ TEST(ringdb, different_genesis)
ASSERT_FALSE(ringdb.get_ring(KEY_2, KEY_IMAGE_1, outs2));
}
-TEST(blackball, not_found)
+TEST(spent_outputs, not_found)
{
RingDB ringdb;
ASSERT_TRUE(ringdb.blackball(OUTPUT_1));
ASSERT_FALSE(ringdb.blackballed(OUTPUT_2));
}
-TEST(blackball, found)
+TEST(spent_outputs, found)
{
RingDB ringdb;
ASSERT_TRUE(ringdb.blackball(OUTPUT_1));
ASSERT_TRUE(ringdb.blackballed(OUTPUT_1));
}
-TEST(blackball, unblackball)
+TEST(spent_outputs, vector)
+{
+ RingDB ringdb;
+ std::vector<std::pair<uint64_t, uint64_t>> outputs;
+ outputs.push_back(std::make_pair(0, 1));
+ outputs.push_back(std::make_pair(10, 3));
+ outputs.push_back(std::make_pair(10, 4));
+ outputs.push_back(std::make_pair(10, 8));
+ outputs.push_back(std::make_pair(20, 0));
+ outputs.push_back(std::make_pair(20, 1));
+ outputs.push_back(std::make_pair(30, 5));
+ ASSERT_TRUE(ringdb.blackball(outputs));
+ ASSERT_TRUE(ringdb.blackballed(std::make_pair(0, 1)));
+ ASSERT_FALSE(ringdb.blackballed(std::make_pair(10, 2)));
+ ASSERT_TRUE(ringdb.blackballed(std::make_pair(10, 3)));
+ ASSERT_TRUE(ringdb.blackballed(std::make_pair(10, 4)));
+ ASSERT_FALSE(ringdb.blackballed(std::make_pair(10, 5)));
+ ASSERT_TRUE(ringdb.blackballed(std::make_pair(10, 8)));
+ ASSERT_TRUE(ringdb.blackballed(std::make_pair(20, 0)));
+ ASSERT_TRUE(ringdb.blackballed(std::make_pair(20, 1)));
+ ASSERT_FALSE(ringdb.blackballed(std::make_pair(20, 2)));
+ ASSERT_TRUE(ringdb.blackballed(std::make_pair(30, 5)));
+}
+
+TEST(spent_outputs, mark_as_unspent)
{
RingDB ringdb;
ASSERT_TRUE(ringdb.blackball(OUTPUT_1));
@@ -154,7 +182,7 @@ TEST(blackball, unblackball)
ASSERT_FALSE(ringdb.blackballed(OUTPUT_1));
}
-TEST(blackball, clear)
+TEST(spent_outputs, clear)
{
RingDB ringdb;
ASSERT_TRUE(ringdb.blackball(OUTPUT_1));
diff --git a/tests/unit_tests/serialization.cpp b/tests/unit_tests/serialization.cpp
index 5a2114027..2f7b5aac7 100644
--- a/tests/unit_tests/serialization.cpp
+++ b/tests/unit_tests/serialization.cpp
@@ -671,8 +671,7 @@ TEST(Serialization, serializes_ringct_types)
TEST(Serialization, portability_wallet)
{
const cryptonote::network_type nettype = cryptonote::TESTNET;
- const bool restricted = false;
- tools::wallet2 w(nettype, restricted);
+ tools::wallet2 w(nettype);
const boost::filesystem::path wallet_file = unit_test::data_dir / "wallet_9svHk1";
string password = "test";
bool r = false;
@@ -810,7 +809,7 @@ TEST(Serialization, portability_outputs)
if(ciphertext.size() < prefix_size)
return {};
crypto::chacha_key key;
- crypto::generate_chacha_key(&skey, sizeof(skey), key);
+ crypto::generate_chacha_key(&skey, sizeof(skey), key, 1);
const crypto::chacha_iv &iv = *(const crypto::chacha_iv*)&ciphertext[0];
std::string plaintext;
plaintext.resize(ciphertext.size() - prefix_size);
@@ -825,7 +824,7 @@ TEST(Serialization, portability_outputs)
return {};
}
crypto::chacha8(ciphertext.data() + sizeof(iv), ciphertext.size() - prefix_size, key, iv, &plaintext[0]);
- return std::move(plaintext);
+ return plaintext;
};
crypto::secret_key view_secret_key;
epee::string_tools::hex_to_pod("339673bb1187e2f73ba7841ab6841c5553f96e9f13f8fe6612e69318db4e9d0a", view_secret_key);
diff --git a/tests/unit_tests/test_notifier.cpp b/tests/unit_tests/test_notifier.cpp
new file mode 100644
index 000000000..7fd9809c5
--- /dev/null
+++ b/tests/unit_tests/test_notifier.cpp
@@ -0,0 +1,54 @@
+// 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+int main(int argc, char **argv)
+{
+ if (argc < 3)
+ {
+ fprintf(stderr, "usage: %s <filename> <hash>\n", argv[0]);
+ return 1;
+ }
+ const char *filename = argv[1];
+ const char *hash = argv[2];
+
+ FILE *f = fopen(filename, "a+");
+ if (!f)
+ {
+ fprintf(stderr, "error opening file %s: %s\n", filename, strerror(errno));
+ return 1;
+ }
+ fprintf(f, "%s", hash);
+ fclose(f);
+
+ return 0;
+}
diff --git a/tests/unit_tests/test_tx_utils.cpp b/tests/unit_tests/test_tx_utils.cpp
index 8a9f983e6..55c76c3b6 100644
--- a/tests/unit_tests/test_tx_utils.cpp
+++ b/tests/unit_tests/test_tx_utils.cpp
@@ -33,6 +33,8 @@
#include <vector>
#include "common/util.h"
+#include "cryptonote_basic/cryptonote_basic.h"
+#include "cryptonote_basic/tx_extra.h"
#include "cryptonote_core/cryptonote_tx_utils.h"
namespace
@@ -203,3 +205,85 @@ TEST(validate_parse_amount_case, validate_parse_amount)
r = cryptonote::parse_amount(res, "1 00.00 00");
ASSERT_FALSE(r);
}
+
+TEST(sort_tx_extra, empty)
+{
+ std::vector<uint8_t> extra, sorted;
+ ASSERT_TRUE(cryptonote::sort_tx_extra(extra, sorted));
+ ASSERT_EQ(extra, sorted);
+}
+
+TEST(sort_tx_extra, pubkey)
+{
+ std::vector<uint8_t> sorted;
+ const uint8_t extra_arr[] = {1, 30, 208, 98, 162, 133, 64, 85, 83, 112, 91, 188, 89, 211, 24, 131, 39, 154, 22, 228,
+ 80, 63, 198, 141, 173, 111, 244, 183, 4, 149, 186, 140, 230};
+ std::vector<uint8_t> extra(&extra_arr[0], &extra_arr[0] + sizeof(extra_arr));
+ ASSERT_TRUE(cryptonote::sort_tx_extra(extra, sorted));
+ ASSERT_EQ(extra, sorted);
+}
+
+TEST(sort_tx_extra, two_pubkeys)
+{
+ std::vector<uint8_t> sorted;
+ const uint8_t extra_arr[] = {1, 30, 208, 98, 162, 133, 64, 85, 83, 112, 91, 188, 89, 211, 24, 131, 39, 154, 22, 228,
+ 80, 63, 198, 141, 173, 111, 244, 183, 4, 149, 186, 140, 230,
+ 1, 30, 208, 98, 162, 133, 64, 85, 83, 112, 91, 188, 89, 211, 24, 131, 39, 154, 22, 228,
+ 80, 63, 198, 141, 173, 111, 244, 183, 4, 149, 186, 140, 230};
+ std::vector<uint8_t> extra(&extra_arr[0], &extra_arr[0] + sizeof(extra_arr));
+ ASSERT_TRUE(cryptonote::sort_tx_extra(extra, sorted));
+ ASSERT_EQ(extra, sorted);
+}
+
+TEST(sort_tx_extra, keep_order)
+{
+ std::vector<uint8_t> sorted;
+ const uint8_t extra_arr[] = {1, 30, 208, 98, 162, 133, 64, 85, 83, 112, 91, 188, 89, 211, 24, 131, 39, 154, 22, 228,
+ 80, 63, 198, 141, 173, 111, 244, 183, 4, 149, 186, 140, 230,
+ 2, 9, 1, 0, 0, 0, 0, 0, 0, 0, 0};
+ std::vector<uint8_t> extra(&extra_arr[0], &extra_arr[0] + sizeof(extra_arr));
+ ASSERT_TRUE(cryptonote::sort_tx_extra(extra, sorted));
+ ASSERT_EQ(extra, sorted);
+}
+
+TEST(sort_tx_extra, switch_order)
+{
+ std::vector<uint8_t> sorted;
+ const uint8_t extra_arr[] = {2, 9, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 1, 30, 208, 98, 162, 133, 64, 85, 83, 112, 91, 188, 89, 211, 24, 131, 39, 154, 22, 228,
+ 80, 63, 198, 141, 173, 111, 244, 183, 4, 149, 186, 140, 230};
+ const uint8_t expected_arr[] = {1, 30, 208, 98, 162, 133, 64, 85, 83, 112, 91, 188, 89, 211, 24, 131, 39, 154, 22, 228,
+ 80, 63, 198, 141, 173, 111, 244, 183, 4, 149, 186, 140, 230,
+ 2, 9, 1, 0, 0, 0, 0, 0, 0, 0, 0};
+ std::vector<uint8_t> extra(&extra_arr[0], &extra_arr[0] + sizeof(extra_arr));
+ ASSERT_TRUE(cryptonote::sort_tx_extra(extra, sorted));
+ std::vector<uint8_t> expected(&expected_arr[0], &expected_arr[0] + sizeof(expected_arr));
+ ASSERT_EQ(expected, sorted);
+}
+
+TEST(sort_tx_extra, invalid)
+{
+ std::vector<uint8_t> sorted;
+ const uint8_t extra_arr[] = {1};
+ std::vector<uint8_t> extra(&extra_arr[0], &extra_arr[0] + sizeof(extra_arr));
+ ASSERT_FALSE(cryptonote::sort_tx_extra(extra, sorted));
+}
+
+TEST(sort_tx_extra, invalid_suffix_strict)
+{
+ std::vector<uint8_t> sorted;
+ const uint8_t extra_arr[] = {2, 9, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1};
+ std::vector<uint8_t> extra(&extra_arr[0], &extra_arr[0] + sizeof(extra_arr));
+ ASSERT_FALSE(cryptonote::sort_tx_extra(extra, sorted));
+}
+
+TEST(sort_tx_extra, invalid_suffix_partial)
+{
+ std::vector<uint8_t> sorted;
+ const uint8_t extra_arr[] = {2, 9, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1};
+ const uint8_t expected_arr[] = {2, 9, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1};
+ std::vector<uint8_t> extra(&extra_arr[0], &extra_arr[0] + sizeof(extra_arr));
+ ASSERT_TRUE(cryptonote::sort_tx_extra(extra, sorted, true));
+ std::vector<uint8_t> expected(&expected_arr[0], &expected_arr[0] + sizeof(expected_arr));
+ ASSERT_EQ(sorted, expected);
+}
diff --git a/tests/unit_tests/threadpool.cpp b/tests/unit_tests/threadpool.cpp
new file mode 100644
index 000000000..1307cd738
--- /dev/null
+++ b/tests/unit_tests/threadpool.cpp
@@ -0,0 +1,146 @@
+// 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 <atomic>
+#include "gtest/gtest.h"
+#include "misc_language.h"
+#include "common/threadpool.h"
+
+TEST(threadpool, wait_nothing)
+{
+ std::shared_ptr<tools::threadpool> tpool(tools::threadpool::getNewForUnitTests());
+ tools::threadpool::waiter waiter;
+ waiter.wait(tpool.get());
+}
+
+TEST(threadpool, wait_waits)
+{
+ std::shared_ptr<tools::threadpool> tpool(tools::threadpool::getNewForUnitTests());
+ tools::threadpool::waiter waiter;
+ std::atomic<bool> b(false);
+ tpool->submit(&waiter, [&b](){ epee::misc_utils::sleep_no_w(1000); b = true; });
+ ASSERT_FALSE(b);
+ waiter.wait(tpool.get());
+ ASSERT_TRUE(b);
+}
+
+TEST(threadpool, one_thread)
+{
+ std::shared_ptr<tools::threadpool> tpool(tools::threadpool::getNewForUnitTests(1));
+ tools::threadpool::waiter waiter;
+
+ std::atomic<unsigned int> counter(0);
+ for (size_t n = 0; n < 4096; ++n)
+ {
+ tpool->submit(&waiter, [&counter](){++counter;});
+ }
+ waiter.wait(tpool.get());
+ ASSERT_EQ(counter, 4096);
+}
+
+TEST(threadpool, many_threads)
+{
+ std::shared_ptr<tools::threadpool> tpool(tools::threadpool::getNewForUnitTests(256));
+ tools::threadpool::waiter waiter;
+
+ std::atomic<unsigned int> counter(0);
+ for (size_t n = 0; n < 4096; ++n)
+ {
+ tpool->submit(&waiter, [&counter](){++counter;});
+ }
+ waiter.wait(tpool.get());
+ ASSERT_EQ(counter, 4096);
+}
+
+static uint64_t fibonacci(std::shared_ptr<tools::threadpool> tpool, uint64_t n)
+{
+ if (n <= 1)
+ return n;
+ uint64_t f1, f2;
+ tools::threadpool::waiter waiter;
+ tpool->submit(&waiter, [&tpool, &f1, n](){ f1 = fibonacci(tpool, n-1); });
+ tpool->submit(&waiter, [&tpool, &f2, n](){ f2 = fibonacci(tpool, n-2); });
+ waiter.wait(tpool.get());
+ return f1 + f2;
+}
+
+TEST(threadpool, reentrency)
+{
+ std::shared_ptr<tools::threadpool> tpool(tools::threadpool::getNewForUnitTests(4));
+ tools::threadpool::waiter waiter;
+
+ uint64_t f = fibonacci(tpool, 13);
+ waiter.wait(tpool.get());
+ ASSERT_EQ(f, 233);
+}
+
+TEST(threadpool, reentrancy)
+{
+ std::shared_ptr<tools::threadpool> tpool(tools::threadpool::getNewForUnitTests(4));
+ tools::threadpool::waiter waiter;
+
+ uint64_t f = fibonacci(tpool, 13);
+ waiter.wait(tpool.get());
+ ASSERT_EQ(f, 233);
+}
+
+TEST(threadpool, leaf_throws)
+{
+ std::shared_ptr<tools::threadpool> tpool(tools::threadpool::getNewForUnitTests());
+ tools::threadpool::waiter waiter;
+
+ bool thrown = false, executed = false;
+ tpool->submit(&waiter, [&](){
+ try { tpool->submit(&waiter, [&](){ executed = true; }); }
+ catch(const std::exception &e) { thrown = true; }
+ }, true);
+ waiter.wait(tpool.get());
+ ASSERT_TRUE(thrown);
+ ASSERT_FALSE(executed);
+}
+
+TEST(threadpool, leaf_reentrancy)
+{
+ std::shared_ptr<tools::threadpool> tpool(tools::threadpool::getNewForUnitTests(4));
+ tools::threadpool::waiter waiter;
+
+ std::atomic<int> counter(0);
+ for (int i = 0; i < 1000; ++i)
+ {
+ tpool->submit(&waiter, [&](){
+ tools::threadpool::waiter waiter;
+ for (int j = 0; j < 500; ++j)
+ {
+ tpool->submit(&waiter, [&](){ ++counter; }, true);
+ }
+ waiter.wait(tpool.get());
+ });
+ }
+ waiter.wait(tpool.get());
+ ASSERT_EQ(counter, 500000);
+}
diff --git a/tests/unit_tests/wipeable_string.cpp b/tests/unit_tests/wipeable_string.cpp
new file mode 100644
index 000000000..44e050c5c
--- /dev/null
+++ b/tests/unit_tests/wipeable_string.cpp
@@ -0,0 +1,211 @@
+// 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 <boost/optional/optional.hpp>
+#include <string.h>
+#include "gtest/gtest.h"
+
+#include "misc_log_ex.h"
+#include "wipeable_string.h"
+#include "hex.h"
+
+TEST(wipeable_string, ctor)
+{
+ epee::wipeable_string s0;
+ ASSERT_EQ(s0.size(), 0);
+
+ epee::wipeable_string s1(std::string("foo"));
+ ASSERT_EQ(s1.size(), 3);
+ ASSERT_TRUE(!memcmp(s1.data(), "foo", s1.size()));
+
+ epee::wipeable_string s2(std::string("bar"));
+ ASSERT_EQ(s2.size(), 3);
+ ASSERT_TRUE(!memcmp(s2.data(), "bar", s2.size()));
+
+ epee::wipeable_string s3(std::string("quux"));
+ ASSERT_EQ(s3.size(), 4);
+ ASSERT_TRUE(!memcmp(s3.data(), "quux", s3.size()));
+}
+
+TEST(wipeable_string, wipe)
+{
+ epee::wipeable_string s0(std::string("foo"));
+ ASSERT_EQ(s0.size(), 3);
+ s0.wipe();
+ ASSERT_EQ(s0.size(), 3);
+ ASSERT_TRUE(!memcmp(s0.data(), "\0\0\0", 3));
+}
+
+TEST(wipeable_string, clear)
+{
+ epee::wipeable_string s0(std::string("foo"));
+ ASSERT_EQ(s0.size(), 3);
+ s0.clear();
+ ASSERT_EQ(s0.size(), 0);
+}
+
+TEST(wipeable_string, push_back)
+{
+ epee::wipeable_string s0(std::string("fo"));
+ ASSERT_EQ(s0.size(), 2);
+ s0.push_back('o');
+ ASSERT_EQ(s0.size(), 3);
+ ASSERT_TRUE(!memcmp(s0.data(), "foo", s0.size()));
+}
+
+TEST(wipeable_string, append_char)
+{
+ epee::wipeable_string s0(std::string("fo"));
+ ASSERT_EQ(s0.size(), 2);
+ s0 += 'o';
+ ASSERT_EQ(s0.size(), 3);
+ ASSERT_TRUE(!memcmp(s0.data(), "foo", s0.size()));
+}
+
+TEST(wipeable_string, append_string)
+{
+ epee::wipeable_string s0(std::string("foo"));
+ ASSERT_EQ(s0.size(), 3);
+ s0 += "bar";
+ ASSERT_EQ(s0.size(), 6);
+ ASSERT_TRUE(!memcmp(s0.data(), "foobar", s0.size()));
+}
+
+TEST(wipeable_string, empty)
+{
+ epee::wipeable_string s0;
+ ASSERT_TRUE(s0.empty());
+ s0.push_back(' ');
+ ASSERT_FALSE(s0.empty());
+ ASSERT_EQ(s0.pop_back(), ' ');
+ ASSERT_TRUE(s0.empty());
+}
+
+TEST(wipeable_string, pop_back)
+{
+ epee::wipeable_string s = "test";
+ ASSERT_EQ(s.size(), 4);
+ ASSERT_EQ(s.pop_back(), 't');
+ ASSERT_EQ(s.size(), 3);
+ ASSERT_TRUE(!memcmp(s.data(), "tes", s.size()));
+}
+
+TEST(wipeable_string, equal)
+{
+ epee::wipeable_string s0 = "foo";
+ epee::wipeable_string s1 = "bar";
+ epee::wipeable_string s0_2 = "foo";
+ ASSERT_TRUE(s0 == s0);
+ ASSERT_TRUE(s0 == s0_2);
+ ASSERT_TRUE(s1 == s1);
+ ASSERT_FALSE(s1 == s0);
+ ASSERT_FALSE(s1 == s0_2);
+}
+
+TEST(wipeable_string, not_equal)
+{
+ epee::wipeable_string s0 = "foo";
+ epee::wipeable_string s1 = "bar";
+ epee::wipeable_string s0_2 = "foo";
+ ASSERT_FALSE(s0 != s0);
+ ASSERT_FALSE(s0 != s0_2);
+ ASSERT_FALSE(s1 != s1);
+ ASSERT_TRUE(s1 != s0);
+ ASSERT_TRUE(s1 != s0_2);
+}
+
+static epee::wipeable_string trimmed(const char *s)
+{
+ epee::wipeable_string str(s);
+ str.trim();
+ return str;
+}
+
+TEST(wipeable_string, trim)
+{
+ ASSERT_TRUE(trimmed("") == "");
+ ASSERT_TRUE(trimmed(" ") == "");
+ ASSERT_TRUE(trimmed(" ") == "");
+ ASSERT_TRUE(trimmed("a") == "a");
+ ASSERT_TRUE(trimmed(" a") == "a");
+ ASSERT_TRUE(trimmed(" a") == "a");
+ ASSERT_TRUE(trimmed("a ") == "a");
+ ASSERT_TRUE(trimmed("a ") == "a");
+ ASSERT_TRUE(trimmed(" a ") == "a");
+ ASSERT_TRUE(trimmed(" a ") == "a");
+ ASSERT_TRUE(trimmed(" ab ") == "ab");
+ ASSERT_TRUE(trimmed(" a b ") == "a b");
+ ASSERT_TRUE(trimmed(" a b ") == "a b");
+}
+
+static bool check_split(const char *s, const std::vector<epee::wipeable_string> &v)
+{
+ epee::wipeable_string str(s);
+ std::vector<epee::wipeable_string> fields;
+ str.split(fields);
+ return v == fields;
+}
+
+TEST(wipeable_string, split)
+{
+ ASSERT_TRUE(check_split("", {}));
+ ASSERT_TRUE(check_split("foo", {"foo"}));
+ ASSERT_TRUE(check_split(" foo ", {"foo"}));
+ ASSERT_TRUE(check_split("foo bar", {"foo", "bar"}));
+ ASSERT_TRUE(check_split("foo bar", {"foo", "bar"}));
+ ASSERT_TRUE(check_split("foo bar baz", {"foo", "bar", "baz"}));
+ ASSERT_TRUE(check_split(" foo bar baz ", {"foo", "bar", "baz"}));
+ ASSERT_TRUE(check_split(" foo bar baz", {"foo", "bar", "baz"}));
+ ASSERT_TRUE(check_split("foo bar baz ", {"foo", "bar", "baz"}));
+}
+
+TEST(wipeable_string, parse_hexstr)
+{
+ boost::optional<epee::wipeable_string> s;
+
+ ASSERT_EQ(boost::none, epee::wipeable_string("x").parse_hexstr());
+ ASSERT_EQ(boost::none, epee::wipeable_string("x0000000000000000").parse_hexstr());
+ ASSERT_EQ(boost::none, epee::wipeable_string("0000000000000000x").parse_hexstr());
+ ASSERT_EQ(boost::none, epee::wipeable_string("0").parse_hexstr());
+ ASSERT_EQ(boost::none, epee::wipeable_string("000").parse_hexstr());
+
+ ASSERT_TRUE((s = epee::wipeable_string("").parse_hexstr()) != boost::none);
+ ASSERT_EQ(*s, "");
+ ASSERT_TRUE((s = epee::wipeable_string("00").parse_hexstr()) != boost::none);
+ ASSERT_EQ(*s, epee::wipeable_string("", 1));
+ ASSERT_TRUE((s = epee::wipeable_string("41").parse_hexstr()) != boost::none);
+ ASSERT_EQ(*s, epee::wipeable_string("A"));
+ ASSERT_TRUE((s = epee::wipeable_string("414243").parse_hexstr()) != boost::none);
+ ASSERT_EQ(*s, epee::wipeable_string("ABC"));
+}
+
+TEST(wipeable_string, to_hex)
+{
+ ASSERT_TRUE(epee::to_hex::wipeable_string(epee::span<const uint8_t>((const uint8_t*)"", 0)) == epee::wipeable_string(""));
+ ASSERT_TRUE(epee::to_hex::wipeable_string(epee::span<const uint8_t>((const uint8_t*)"abc", 3)) == epee::wipeable_string("616263"));
+}