diff options
Diffstat (limited to 'tests/unit_tests')
-rw-r--r-- | tests/unit_tests/base58.cpp | 502 | ||||
-rw-r--r-- | tests/unit_tests/block_reward.cpp | 226 | ||||
-rw-r--r-- | tests/unit_tests/chacha8.cpp | 84 | ||||
-rw-r--r-- | tests/unit_tests/decompose_amount_into_digits.cpp | 119 | ||||
-rw-r--r-- | tests/unit_tests/epee_boosted_tcp_server.cpp | 109 | ||||
-rw-r--r-- | tests/unit_tests/epee_levin_protocol_handler_async.cpp | 506 | ||||
-rw-r--r-- | tests/unit_tests/main.cpp | 15 | ||||
-rw-r--r-- | tests/unit_tests/mul_div.cpp | 179 | ||||
-rw-r--r-- | tests/unit_tests/serialization.cpp | 418 | ||||
-rw-r--r-- | tests/unit_tests/test_format_utils.cpp | 97 | ||||
-rw-r--r-- | tests/unit_tests/test_peerlist.cpp | 58 | ||||
-rw-r--r-- | tests/unit_tests/test_protocol_pack.cpp | 29 | ||||
-rw-r--r-- | tests/unit_tests/unit_tests_utils.h | 38 |
13 files changed, 2380 insertions, 0 deletions
diff --git a/tests/unit_tests/base58.cpp b/tests/unit_tests/base58.cpp new file mode 100644 index 000000000..05bf5afc7 --- /dev/null +++ b/tests/unit_tests/base58.cpp @@ -0,0 +1,502 @@ +// Copyright (c) 2012-2013 The Cryptonote developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "gtest/gtest.h" + +#include <cstdint> + +#include "common/base58.cpp" +#include "cryptonote_core/cryptonote_basic_impl.h" +#include "serialization/binary_utils.h" + +using namespace tools; + +#define MAKE_STR(arr) std::string(arr, sizeof(arr) - 1) + +namespace +{ + void do_test_uint_8be_to_64(uint64_t expected, const uint8_t* data, size_t size) + { + uint64_t val = base58::uint_8be_to_64(data, size); + ASSERT_EQ(val, expected); + } + + void do_test_uint_64_to_8be(uint64_t num, const std::string& expected_str) + { + std::string data(expected_str.size(), '\x0'); + base58::uint_64_to_8be(num, data.size(), reinterpret_cast<uint8_t*>(&data[0])); + ASSERT_EQ(data, expected_str); + } + + void do_test_encode_block(const std::string& block, const std::string& expected) + { + ASSERT_TRUE(1 <= block.size() && block.size() <= base58::full_block_size); + std::string enc(base58::encoded_block_sizes[block.size()], base58::alphabet[0]); + base58::encode_block(block.data(), block.size(), &enc[0]); + ASSERT_EQ(enc, expected); + + std::string dec(block.size(), '\0'); + ASSERT_TRUE(base58::decode_block(enc.data(), enc.size(), &dec[0])); + ASSERT_EQ(block, dec); + } + + void do_test_decode_block_pos(const std::string& enc, const std::string& expected) + { + std::string data(base58::decoded_block_sizes::instance(enc.size()), '\0'); + ASSERT_TRUE(base58::decode_block(enc.data(), enc.size(), &data[0])); + ASSERT_EQ(data, expected); + } + + void do_test_decode_block_neg(const std::string& enc) + { + std::string data(base58::full_block_size, '\0'); + ASSERT_FALSE(base58::decode_block(enc.data(), enc.size(), &data[0])); + } + + void do_test_encode(const std::string& data, const std::string& expected) + { + std::string enc = base58::encode(data); + ASSERT_EQ(enc, expected); + + std::string dec; + ASSERT_TRUE(base58::decode(enc, dec)); + ASSERT_EQ(dec, data); + } + + void do_test_decode_pos(const std::string& enc, const std::string& expected) + { + std::string dec; + ASSERT_TRUE(base58::decode(enc, dec)); + ASSERT_EQ(dec, expected); + } + + void do_test_decode_neg(const std::string& enc) + { + std::string dec; + ASSERT_FALSE(base58::decode(enc, dec)); + } + + void do_test_encode_decode_addr(uint64_t tag, const std::string& data, const std::string& expected) + { + std::string addr = base58::encode_addr(tag, data); + ASSERT_EQ(addr, expected); + + uint64_t dec_tag; + std::string dec_data; + ASSERT_TRUE(base58::decode_addr(addr, dec_tag, dec_data)); + ASSERT_EQ(tag, dec_tag); + ASSERT_EQ(data, dec_data); + } +} + +#define TEST_uint_8be_to_64(expected, str) \ + TEST(base58_uint_8be_to_64, handles_bytes_##expected) \ + { \ + std::string data = str; \ + do_test_uint_8be_to_64(expected, reinterpret_cast<const uint8_t*>(data.data()), data.size()); \ + } + +TEST_uint_8be_to_64(0x0000000000000001, "\x1"); +TEST_uint_8be_to_64(0x0000000000000102, "\x1\x2"); +TEST_uint_8be_to_64(0x0000000000010203, "\x1\x2\x3"); +TEST_uint_8be_to_64(0x0000000001020304, "\x1\x2\x3\x4"); +TEST_uint_8be_to_64(0x0000000102030405, "\x1\x2\x3\x4\x5"); +TEST_uint_8be_to_64(0x0000010203040506, "\x1\x2\x3\x4\x5\x6"); +TEST_uint_8be_to_64(0x0001020304050607, "\x1\x2\x3\x4\x5\x6\x7"); +TEST_uint_8be_to_64(0x0102030405060708, "\x1\x2\x3\x4\x5\x6\x7\x8"); + + +#define TEST_uint_64_to_8be(num, expected_str) \ + TEST(base58_uint_64_to_8be, handles_bytes_##num) \ + { \ + do_test_uint_64_to_8be(num, expected_str); \ + } + +TEST_uint_64_to_8be(0x0000000000000001, "\x1"); +TEST_uint_64_to_8be(0x0000000000000102, "\x1\x2"); +TEST_uint_64_to_8be(0x0000000000010203, "\x1\x2\x3"); +TEST_uint_64_to_8be(0x0000000001020304, "\x1\x2\x3\x4"); +TEST_uint_64_to_8be(0x0000000102030405, "\x1\x2\x3\x4\x5"); +TEST_uint_64_to_8be(0x0000010203040506, "\x1\x2\x3\x4\x5\x6"); +TEST_uint_64_to_8be(0x0001020304050607, "\x1\x2\x3\x4\x5\x6\x7"); +TEST_uint_64_to_8be(0x0102030405060708, "\x1\x2\x3\x4\x5\x6\x7\x8"); + +TEST(reverse_alphabet, is_correct) +{ + ASSERT_EQ(-1, base58::reverse_alphabet::instance(0)); + ASSERT_EQ(-1, base58::reverse_alphabet::instance(std::numeric_limits<char>::min())); + ASSERT_EQ(-1, base58::reverse_alphabet::instance(std::numeric_limits<char>::max())); + ASSERT_EQ(-1, base58::reverse_alphabet::instance('1' - 1)); + ASSERT_EQ(-1, base58::reverse_alphabet::instance('z' + 1)); + ASSERT_EQ(-1, base58::reverse_alphabet::instance('0')); + ASSERT_EQ(-1, base58::reverse_alphabet::instance('I')); + ASSERT_EQ(-1, base58::reverse_alphabet::instance('O')); + ASSERT_EQ(-1, base58::reverse_alphabet::instance('l')); + ASSERT_EQ(0, base58::reverse_alphabet::instance('1')); + ASSERT_EQ(8, base58::reverse_alphabet::instance('9')); + ASSERT_EQ(base58::alphabet_size - 1, base58::reverse_alphabet::instance('z')); +} + + +#define TEST_encode_block(block, expected) \ + TEST(base58_encode_block, handles_##expected) \ + { \ + do_test_encode_block(MAKE_STR(block), #expected); \ + } + +TEST_encode_block("\x00", 11); +TEST_encode_block("\x39", 1z); +TEST_encode_block("\xFF", 5Q); + +TEST_encode_block("\x00\x00", 111); +TEST_encode_block("\x00\x39", 11z); +TEST_encode_block("\x01\x00", 15R); +TEST_encode_block("\xFF\xFF", LUv); + +TEST_encode_block("\x00\x00\x00", 11111); +TEST_encode_block("\x00\x00\x39", 1111z); +TEST_encode_block("\x01\x00\x00", 11LUw); +TEST_encode_block("\xFF\xFF\xFF", 2UzHL); + +TEST_encode_block("\x00\x00\x00\x39", 11111z); +TEST_encode_block("\xFF\xFF\xFF\xFF", 7YXq9G); +TEST_encode_block("\x00\x00\x00\x00\x39", 111111z); +TEST_encode_block("\xFF\xFF\xFF\xFF\xFF", VtB5VXc); +TEST_encode_block("\x00\x00\x00\x00\x00\x39", 11111111z); +TEST_encode_block("\xFF\xFF\xFF\xFF\xFF\xFF", 3CUsUpv9t); +TEST_encode_block("\x00\x00\x00\x00\x00\x00\x39", 111111111z); +TEST_encode_block("\xFF\xFF\xFF\xFF\xFF\xFF\xFF", Ahg1opVcGW); +TEST_encode_block("\x00\x00\x00\x00\x00\x00\x00\x39", 1111111111z); +TEST_encode_block("\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF", jpXCZedGfVQ); + +TEST_encode_block("\x00\x00\x00\x00\x00\x00\x00\x00", 11111111111); +TEST_encode_block("\x00\x00\x00\x00\x00\x00\x00\x01", 11111111112); +TEST_encode_block("\x00\x00\x00\x00\x00\x00\x00\x08", 11111111119); +TEST_encode_block("\x00\x00\x00\x00\x00\x00\x00\x09", 1111111111A); +TEST_encode_block("\x00\x00\x00\x00\x00\x00\x00\x3A", 11111111121); +TEST_encode_block("\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 1Ahg1opVcGW); +TEST_encode_block("\x06\x15\x60\x13\x76\x28\x79\xF7", 22222222222); +TEST_encode_block("\x05\xE0\x22\xBA\x37\x4B\x2A\x00", 1z111111111); + + +#define TEST_decode_block_pos(enc, expected) \ + TEST(base58_decode_block, handles_pos_##enc) \ + { \ + do_test_decode_block_pos(#enc, MAKE_STR(expected)); \ + } + +#define TEST_decode_block_neg(enc) \ + TEST(base58_decode_block, handles_neg_##enc) \ + { \ + do_test_decode_block_neg(#enc); \ + } + +// 1-byte block +TEST_decode_block_neg(1); +TEST_decode_block_neg(z); +// 2-bytes block +TEST_decode_block_pos(11, "\x00"); +TEST_decode_block_pos(5Q, "\xFF"); +TEST_decode_block_neg(5R); +TEST_decode_block_neg(zz); +// 3-bytes block +TEST_decode_block_pos(111, "\x00\x00"); +TEST_decode_block_pos(LUv, "\xFF\xFF"); +TEST_decode_block_neg(LUw); +TEST_decode_block_neg(zzz); +// 4-bytes block +TEST_decode_block_neg(1111); +TEST_decode_block_neg(zzzz); +// 5-bytes block +TEST_decode_block_pos(11111, "\x00\x00\x00"); +TEST_decode_block_pos(2UzHL, "\xFF\xFF\xFF"); +TEST_decode_block_neg(2UzHM); +TEST_decode_block_neg(zzzzz); +// 6-bytes block +TEST_decode_block_pos(111111, "\x00\x00\x00\x00"); +TEST_decode_block_pos(7YXq9G, "\xFF\xFF\xFF\xFF"); +TEST_decode_block_neg(7YXq9H); +TEST_decode_block_neg(zzzzzz); +// 7-bytes block +TEST_decode_block_pos(1111111, "\x00\x00\x00\x00\x00"); +TEST_decode_block_pos(VtB5VXc, "\xFF\xFF\xFF\xFF\xFF"); +TEST_decode_block_neg(VtB5VXd); +TEST_decode_block_neg(zzzzzzz); +// 8-bytes block +TEST_decode_block_neg(11111111); +TEST_decode_block_neg(zzzzzzzz); +// 9-bytes block +TEST_decode_block_pos(111111111, "\x00\x00\x00\x00\x00\x00"); +TEST_decode_block_pos(3CUsUpv9t, "\xFF\xFF\xFF\xFF\xFF\xFF"); +TEST_decode_block_neg(3CUsUpv9u); +TEST_decode_block_neg(zzzzzzzzz); +// 10-bytes block +TEST_decode_block_pos(1111111111, "\x00\x00\x00\x00\x00\x00\x00"); +TEST_decode_block_pos(Ahg1opVcGW, "\xFF\xFF\xFF\xFF\xFF\xFF\xFF"); +TEST_decode_block_neg(Ahg1opVcGX); +TEST_decode_block_neg(zzzzzzzzzz); +// 11-bytes block +TEST_decode_block_pos(11111111111, "\x00\x00\x00\x00\x00\x00\x00\x00"); +TEST_decode_block_pos(jpXCZedGfVQ, "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"); +TEST_decode_block_neg(jpXCZedGfVR); +TEST_decode_block_neg(zzzzzzzzzzz); +// Invalid symbols +TEST_decode_block_neg(01111111111); +TEST_decode_block_neg(11111111110); +TEST_decode_block_neg(11111011111); +TEST_decode_block_neg(I1111111111); +TEST_decode_block_neg(O1111111111); +TEST_decode_block_neg(l1111111111); +TEST_decode_block_neg(_1111111111); + + +#define TEST_encode(expected, data) \ + TEST(base58_encode, handles_##expected) \ + { \ + do_test_encode(MAKE_STR(data), #expected); \ + } + +TEST_encode(11, "\x00"); +TEST_encode(111, "\x00\x00"); +TEST_encode(11111, "\x00\x00\x00"); +TEST_encode(111111, "\x00\x00\x00\x00"); +TEST_encode(1111111, "\x00\x00\x00\x00\x00"); +TEST_encode(111111111, "\x00\x00\x00\x00\x00\x00"); +TEST_encode(1111111111, "\x00\x00\x00\x00\x00\x00\x00"); +TEST_encode(11111111111, "\x00\x00\x00\x00\x00\x00\x00\x00"); +TEST_encode(1111111111111, "\x00\x00\x00\x00\x00\x00\x00\x00\x00"); +TEST_encode(11111111111111, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"); +TEST_encode(1111111111111111, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"); +TEST_encode(11111111111111111, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"); +TEST_encode(111111111111111111, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"); +TEST_encode(11111111111111111111, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"); +TEST_encode(111111111111111111111, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"); +TEST_encode(1111111111111111111111, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"); +TEST_encode(22222222222VtB5VXc, "\x06\x15\x60\x13\x76\x28\x79\xF7\xFF\xFF\xFF\xFF\xFF"); + + +#define TEST_decode_pos(enc, expected) \ + TEST(base58_decode_pos, handles_pos_##enc) \ + { \ + do_test_decode_pos(#enc, MAKE_STR(expected)); \ + } + +#define TEST_decode_neg(enc) \ + TEST(base58_decode_neg, handles_neg_##enc) \ + { \ + do_test_decode_neg(#enc); \ + } + +TEST_decode_pos(, ""); +TEST_decode_pos(5Q, "\xFF"); +TEST_decode_pos(LUv, "\xFF\xFF"); +TEST_decode_pos(2UzHL, "\xFF\xFF\xFF"); +TEST_decode_pos(7YXq9G, "\xFF\xFF\xFF\xFF"); +TEST_decode_pos(VtB5VXc, "\xFF\xFF\xFF\xFF\xFF"); +TEST_decode_pos(3CUsUpv9t, "\xFF\xFF\xFF\xFF\xFF\xFF"); +TEST_decode_pos(Ahg1opVcGW, "\xFF\xFF\xFF\xFF\xFF\xFF\xFF"); +TEST_decode_pos(jpXCZedGfVQ, "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"); +TEST_decode_pos(jpXCZedGfVQ5Q, "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"); +TEST_decode_pos(jpXCZedGfVQLUv, "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"); +TEST_decode_pos(jpXCZedGfVQ2UzHL, "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"); +TEST_decode_pos(jpXCZedGfVQ7YXq9G, "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"); +TEST_decode_pos(jpXCZedGfVQVtB5VXc, "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"); +TEST_decode_pos(jpXCZedGfVQ3CUsUpv9t, "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"); +TEST_decode_pos(jpXCZedGfVQAhg1opVcGW, "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"); +TEST_decode_pos(jpXCZedGfVQjpXCZedGfVQ, "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"); +// Invalid length +TEST_decode_neg(1); +TEST_decode_neg(z); +TEST_decode_neg(1111); +TEST_decode_neg(zzzz); +TEST_decode_neg(11111111); +TEST_decode_neg(zzzzzzzz); +TEST_decode_neg(123456789AB1); +TEST_decode_neg(123456789ABz); +TEST_decode_neg(123456789AB1111); +TEST_decode_neg(123456789ABzzzz); +TEST_decode_neg(123456789AB11111111); +TEST_decode_neg(123456789ABzzzzzzzz); +// Overflow +TEST_decode_neg(5R); +TEST_decode_neg(zz); +TEST_decode_neg(LUw); +TEST_decode_neg(zzz); +TEST_decode_neg(2UzHM); +TEST_decode_neg(zzzzz); +TEST_decode_neg(7YXq9H); +TEST_decode_neg(zzzzzz); +TEST_decode_neg(VtB5VXd); +TEST_decode_neg(zzzzzzz); +TEST_decode_neg(3CUsUpv9u); +TEST_decode_neg(zzzzzzzzz); +TEST_decode_neg(Ahg1opVcGX); +TEST_decode_neg(zzzzzzzzzz); +TEST_decode_neg(jpXCZedGfVR); +TEST_decode_neg(zzzzzzzzzzz); +TEST_decode_neg(123456789AB5R); +TEST_decode_neg(123456789ABzz); +TEST_decode_neg(123456789ABLUw); +TEST_decode_neg(123456789ABzzz); +TEST_decode_neg(123456789AB2UzHM); +TEST_decode_neg(123456789ABzzzzz); +TEST_decode_neg(123456789AB7YXq9H); +TEST_decode_neg(123456789ABzzzzzz); +TEST_decode_neg(123456789ABVtB5VXd); +TEST_decode_neg(123456789ABzzzzzzz); +TEST_decode_neg(123456789AB3CUsUpv9u); +TEST_decode_neg(123456789ABzzzzzzzzz); +TEST_decode_neg(123456789ABAhg1opVcGX); +TEST_decode_neg(123456789ABzzzzzzzzzz); +TEST_decode_neg(123456789ABjpXCZedGfVR); +TEST_decode_neg(123456789ABzzzzzzzzzzz); +TEST_decode_neg(zzzzzzzzzzz11); +// Invalid symbols +TEST_decode_neg(10); +TEST_decode_neg(11I); +TEST_decode_neg(11O11); +TEST_decode_neg(11l111); +TEST_decode_neg(11_11111111); +TEST_decode_neg(1101111111111); +TEST_decode_neg(11I11111111111111); +TEST_decode_neg(11O1111111111111111111); +TEST_decode_neg(1111111111110); +TEST_decode_neg(111111111111l1111); +TEST_decode_neg(111111111111_111111111); + + +#define TEST_encode_decode_addr(addr, tag, data) \ + TEST(base58_encode_decode_addr, handles_##addr) \ + { \ + do_test_encode_decode_addr(UINT64_C(tag), MAKE_STR(data), #addr); \ + } + +TEST_encode_decode_addr(21D35quxec71111111111111111111111111111111111111111111111111111111111111111111111111111116Q5tCH, 6, + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"); +TEST_encode_decode_addr(2Aui6ejTFscjpXCZedGfVQjpXCZedGfVQjpXCZedGfVQjpXCZedGfVQjpXCZedGfVQjpXCZedGfVQjpXCZedGfVQVqegMoV, 6, + "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF" + "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"); +TEST_encode_decode_addr(1119XrkPuSmLzdHXgVgrZKjepg5hZAxffLzdHXgVgrZKjepg5hZAxffLzdHXgVgrZKjepg5hZAxffLzdHXgVgrZKVphZRvn, 0, + "\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xAA\xBB\xCC\xDD\xEE\xFF\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xAA\xBB\xCC\xDD\xEE\xFF" + "\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xAA\xBB\xCC\xDD\xEE\xFF\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xAA\xBB\xCC\xDD\xEE\xFF"); +TEST_encode_decode_addr(111111111111111111111111111111111111111111111111111111111111111111111111111111111111111115TXfiA, 0, + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"); +TEST_encode_decode_addr(PuT7GAdgbA83qvSEivPLYo11111111111111111111111111111111111111111111111111111111111111111111111111111169tWrH, 0x1122334455667788, + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"); +TEST_encode_decode_addr(PuT7GAdgbA841d7FXjswpJjpXCZedGfVQjpXCZedGfVQjpXCZedGfVQjpXCZedGfVQjpXCZedGfVQjpXCZedGfVQjpXCZedGfVQVq4LL1v, 0x1122334455667788, + "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF" + "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"); +TEST_encode_decode_addr(PuT7GAdgbA819VwdWVDP, 0x1122334455667788, "\x11"); +TEST_encode_decode_addr(PuT7GAdgbA81efAfdCjPg, 0x1122334455667788, "\x22\x22"); +TEST_encode_decode_addr(PuT7GAdgbA83sryEt3YC8Q, 0x1122334455667788, "\x33\x33\x33"); +TEST_encode_decode_addr(PuT7GAdgbA83tWUuc54PFP3b, 0x1122334455667788, "\x44\x44\x44\x44"); +TEST_encode_decode_addr(PuT7GAdgbA83u9zaKrtRKZ1J6, 0x1122334455667788, "\x55\x55\x55\x55\x55"); +TEST_encode_decode_addr(PuT7GAdgbA83uoWF3eanGG1aRoG, 0x1122334455667788, "\x66\x66\x66\x66\x66\x66"); +TEST_encode_decode_addr(PuT7GAdgbA83vT1umSHMYJ4oNVdu, 0x1122334455667788, "\x77\x77\x77\x77\x77\x77\x77"); +TEST_encode_decode_addr(PuT7GAdgbA83w6XaVDyvpoGQBEWbB, 0x1122334455667788, "\x88\x88\x88\x88\x88\x88\x88\x88"); +TEST_encode_decode_addr(PuT7GAdgbA83wk3FD1gW7J2KVGofA1r, 0x1122334455667788, "\x99\x99\x99\x99\x99\x99\x99\x99\x99"); +TEST_encode_decode_addr(11efCaY6UjG7JrxuB, 0, "\x11\x22\x33\x44\x55\x66\x77"); +TEST_encode_decode_addr(21rhHRT48LN4PriP9, 6, "\x11\x22\x33\x44\x55\x66\x77"); +TEST_encode_decode_addr(3BzAD7n3y, 0xFF, ""); + + +#define TEST_decode_addr_neg(addr, test_name) \ + TEST(base58_decode_addr_neg, test_name) \ + { \ + uint64_t tag; \ + std::string data; \ + ASSERT_FALSE(base58::decode_addr(MAKE_STR(addr), tag, data)); \ + } + +TEST_decode_addr_neg("zuT7GAdgbA819VwdWVDP", decode_fails_due_overflow); +TEST_decode_addr_neg("0uT7GAdgbA819VwdWVDP", decode_fails_due_invalid_char_0); +TEST_decode_addr_neg("IuT7GAdgbA819VwdWVDP", decode_fails_due_invalid_char_I); +TEST_decode_addr_neg("OuT7GAdgbA819VwdWVDP", decode_fails_due_invalid_char_O); +TEST_decode_addr_neg("luT7GAdgbA819VwdWVDP", decode_fails_due_invalid_char_l); +TEST_decode_addr_neg("\0uT7GAdgbA819VwdWVDP", decode_fails_due_invalid_char_00); +TEST_decode_addr_neg("PuT7GAdgbA819VwdWVD", decode_fails_due_invalid_lenght); +TEST_decode_addr_neg("11efCaY6UjG7JrxuC", handles_invalid_checksum); +TEST_decode_addr_neg("jerj2e4mESo", handles_non_correct_tag); // "jerj2e4mESo" == "\xFF\x00\xFF\xFF\x5A\xD9\xF1\x1C" + +namespace +{ + std::string test_serialized_keys = MAKE_STR( + "\xf7\x24\xbc\x5c\x6c\xfb\xb9\xd9\x76\x02\xc3\x00\x42\x3a\x2f\x28" + "\x64\x18\x74\x51\x3a\x03\x57\x78\xa0\xc1\x77\x8d\x83\x32\x01\xe9" + "\x22\x09\x39\x68\x9e\xdf\x1a\xbd\x5b\xc1\xd0\x31\xf7\x3e\xcd\x6c" + "\x99\x3a\xdd\x66\xd6\x80\x88\x70\x45\x6a\xfe\xb8\xe7\xee\xb6\x8d"); + std::string test_keys_addr_str = "2AaF4qEmER6dNeM6dfiBFL7kqund3HYGvMBF3ttsNd9SfzgYB6L7ep1Yg1osYJzLdaKAYSLVh6e6jKnAuzj3bw1oGyd1x7Z"; +} + +TEST(get_account_address_as_str, works_correctly) +{ + cryptonote::account_public_address addr; + ASSERT_TRUE(serialization::parse_binary(test_serialized_keys, addr)); + std::string addr_str = cryptonote::get_account_address_as_str(addr); + ASSERT_EQ(addr_str, test_keys_addr_str); +} + +TEST(get_account_address_from_str, handles_valid_address) +{ + cryptonote::account_public_address addr; + ASSERT_TRUE(cryptonote::get_account_address_from_str(addr, test_keys_addr_str)); + + std::string blob; + ASSERT_TRUE(serialization::dump_binary(addr, blob)); + ASSERT_EQ(blob, test_serialized_keys); +} + +TEST(get_account_address_from_str, fails_on_invalid_address_format) +{ + cryptonote::account_public_address addr; + std::string addr_str = test_keys_addr_str; + addr_str[0] = '0'; + + ASSERT_FALSE(cryptonote::get_account_address_from_str(addr, addr_str)); +} + +TEST(get_account_address_from_str, fails_on_invalid_address_prefix) +{ + std::string addr_str = base58::encode_addr(0, test_serialized_keys); + + cryptonote::account_public_address addr; + ASSERT_FALSE(cryptonote::get_account_address_from_str(addr, addr_str)); +} + +TEST(get_account_address_from_str, fails_on_invalid_address_content) +{ + std::string addr_str = base58::encode_addr(CRYPTONOTE_PUBLIC_ADDRESS_BASE58_PREFIX, test_serialized_keys.substr(1)); + + cryptonote::account_public_address addr; + ASSERT_FALSE(cryptonote::get_account_address_from_str(addr, addr_str)); +} + +TEST(get_account_address_from_str, fails_on_invalid_address_spend_key) +{ + std::string serialized_keys_copy = test_serialized_keys; + serialized_keys_copy[0] = '\0'; + std::string addr_str = base58::encode_addr(CRYPTONOTE_PUBLIC_ADDRESS_BASE58_PREFIX, serialized_keys_copy); + + cryptonote::account_public_address addr; + ASSERT_FALSE(cryptonote::get_account_address_from_str(addr, addr_str)); +} + +TEST(get_account_address_from_str, fails_on_invalid_address_view_key) +{ + std::string serialized_keys_copy = test_serialized_keys; + serialized_keys_copy.back() = '\x01'; + std::string addr_str = base58::encode_addr(CRYPTONOTE_PUBLIC_ADDRESS_BASE58_PREFIX, serialized_keys_copy); + + cryptonote::account_public_address addr; + ASSERT_FALSE(cryptonote::get_account_address_from_str(addr, addr_str)); +} + +TEST(get_account_address_from_str, parses_old_address_format) +{ + cryptonote::account_public_address addr; + ASSERT_TRUE(cryptonote::get_account_address_from_str(addr, "002391bbbb24dea6fd95232e97594a27769d0153d053d2102b789c498f57a2b00b69cd6f2f5c529c1660f2f4a2b50178d6640c20ce71fe26373041af97c5b10236fc")); +} diff --git a/tests/unit_tests/block_reward.cpp b/tests/unit_tests/block_reward.cpp new file mode 100644 index 000000000..cfa12a7c8 --- /dev/null +++ b/tests/unit_tests/block_reward.cpp @@ -0,0 +1,226 @@ +// Copyright (c) 2012-2013 The Cryptonote developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "gtest/gtest.h" + +#include "cryptonote_core/cryptonote_basic_impl.h" + +using namespace cryptonote; + +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 / 2; + + std::vector<size_t> m_last_block_sizes; + bool m_block_too_big; + uint64_t m_block_reward; + }; + + #define TEST_ALREADY_GENERATED_COINS(already_generated_coins, expected_reward) \ + m_block_reward = get_block_reward(m_last_block_sizes, current_block_size, m_block_too_big, already_generated_coins); \ + ASSERT_FALSE(m_block_too_big); \ + ASSERT_EQ(m_block_reward, UINT64_C(expected_reward)); + + TEST_F(block_reward_and_already_generated_coins, handles_first_values) + { + TEST_ALREADY_GENERATED_COINS(0, 70368744177663); + TEST_ALREADY_GENERATED_COINS(m_block_reward, 70368475742208); + TEST_ALREADY_GENERATED_COINS(UINT64_C(2756434948434199641), 59853779316998); + } + + TEST_F(block_reward_and_already_generated_coins, correctly_steps_from_2_to_1) + { + TEST_ALREADY_GENERATED_COINS(MONEY_SUPPLY - ((2 << 18) + 1), 2); + TEST_ALREADY_GENERATED_COINS(MONEY_SUPPLY - (2 << 18) , 2); + TEST_ALREADY_GENERATED_COINS(MONEY_SUPPLY - ((2 << 18) - 1), 1); + } + + TEST_F(block_reward_and_already_generated_coins, handles_max) + { + TEST_ALREADY_GENERATED_COINS(MONEY_SUPPLY - ((1 << 18) + 1), 1); + TEST_ALREADY_GENERATED_COINS(MONEY_SUPPLY - (1 << 18) , 1); + TEST_ALREADY_GENERATED_COINS(MONEY_SUPPLY - ((1 << 18) - 1), 0); + } + + //-------------------------------------------------------------------------------------------------------------------- + class block_reward_and_current_block_size : public ::testing::Test + { + protected: + virtual void SetUp() + { + m_standard_block_reward = get_block_reward(m_last_block_sizes, 0, m_block_too_big, already_generated_coins); + ASSERT_FALSE(m_block_too_big); + ASSERT_LT(CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE, m_standard_block_reward); + } + + void do_test(size_t current_block_size) + { + m_block_reward = get_block_reward(m_last_block_sizes, current_block_size, m_block_too_big, already_generated_coins); + } + + static const uint64_t already_generated_coins = 0; + + std::vector<size_t> m_last_block_sizes; + bool m_block_too_big; + uint64_t m_block_reward; + uint64_t m_standard_block_reward; + }; + + TEST_F(block_reward_and_current_block_size, handles_block_size_less_relevance_level) + { + do_test(CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE - 1); + ASSERT_FALSE(m_block_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) + { + do_test(CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE); + ASSERT_FALSE(m_block_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) + { + do_test(CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE + 1); + ASSERT_FALSE(m_block_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) + { + do_test(2 * CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE - 1); + ASSERT_FALSE(m_block_too_big); + ASSERT_LT(m_block_reward, m_standard_block_reward); + ASSERT_LT(0, m_block_reward); + } + + TEST_F(block_reward_and_current_block_size, handles_block_size_eq_2_relevance_level) + { + do_test(2 * CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE); + ASSERT_FALSE(m_block_too_big); + ASSERT_EQ(0, m_block_reward); + } + + TEST_F(block_reward_and_current_block_size, handles_block_size_gt_2_relevance_level) + { + do_test(2 * CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE + 1); + ASSERT_TRUE(m_block_too_big); + } + + TEST_F(block_reward_and_current_block_size, fails_on_huge_median_size) + { +#if !defined(NDEBUG) + size_t huge_size = std::numeric_limits<uint32_t>::max() + UINT64_C(2); + m_last_block_sizes.push_back(huge_size); + ASSERT_DEATH(do_test(huge_size + 1), ""); +#endif + } + + TEST_F(block_reward_and_current_block_size, fails_on_huge_block_size) + { +#if !defined(NDEBUG) + size_t huge_size = std::numeric_limits<uint32_t>::max() + UINT64_C(2); + m_last_block_sizes.push_back(huge_size - 2); + ASSERT_DEATH(do_test(huge_size), ""); +#endif + } + + //-------------------------------------------------------------------------------------------------------------------- + class block_reward_and_last_block_sizes : public ::testing::Test + { + protected: + virtual void SetUp() + { + m_last_block_sizes.push_back(3 * CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE); + m_last_block_sizes.push_back(5 * CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE); + m_last_block_sizes.push_back(7 * CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE); + m_last_block_sizes.push_back(11 * CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE); + m_last_block_sizes.push_back(13 * CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE); + + m_last_block_sizes_median = 7 * CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE; + + m_standard_block_reward = get_block_reward(m_last_block_sizes, 0, m_block_too_big, already_generated_coins); + ASSERT_FALSE(m_block_too_big); + ASSERT_LT(CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE, m_standard_block_reward); + } + + void do_test(size_t current_block_size) + { + m_block_reward = get_block_reward(m_last_block_sizes, current_block_size, m_block_too_big, already_generated_coins); + } + + static const uint64_t already_generated_coins = 0; + + std::vector<size_t> m_last_block_sizes; + uint64_t m_last_block_sizes_median; + bool m_block_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) + { + do_test(m_last_block_sizes_median - 1); + ASSERT_FALSE(m_block_too_big); + ASSERT_EQ(m_block_reward, m_standard_block_reward); + } + + TEST_F(block_reward_and_last_block_sizes, handles_block_size_eq_median) + { + do_test(m_last_block_sizes_median); + ASSERT_FALSE(m_block_too_big); + ASSERT_EQ(m_block_reward, m_standard_block_reward); + } + + TEST_F(block_reward_and_last_block_sizes, handles_block_size_gt_median) + { + do_test(m_last_block_sizes_median + 1); + ASSERT_FALSE(m_block_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) + { + do_test(2 * m_last_block_sizes_median - 1); + ASSERT_FALSE(m_block_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) + { + do_test(2 * m_last_block_sizes_median); + ASSERT_FALSE(m_block_too_big); + ASSERT_EQ(0, m_block_reward); + } + + TEST_F(block_reward_and_last_block_sizes, handles_block_size_gt_2_medians) + { + do_test(2 * m_last_block_sizes_median + 1); + ASSERT_TRUE(m_block_too_big); + } + + TEST_F(block_reward_and_last_block_sizes, calculates_correctly) + { + ASSERT_EQ(0, m_last_block_sizes_median % 8); + + do_test(m_last_block_sizes_median * 9 / 8); + ASSERT_FALSE(m_block_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); + ASSERT_FALSE(m_block_too_big); + ASSERT_EQ(m_block_reward, m_standard_block_reward * 3 / 4); + + do_test(m_last_block_sizes_median * 15 / 8); + ASSERT_FALSE(m_block_too_big); + ASSERT_EQ(m_block_reward, m_standard_block_reward * 15 / 64); + } +} diff --git a/tests/unit_tests/chacha8.cpp b/tests/unit_tests/chacha8.cpp new file mode 100644 index 000000000..e3eeae5cf --- /dev/null +++ b/tests/unit_tests/chacha8.cpp @@ -0,0 +1,84 @@ +// Copyright (c) 2012-2013 The Cryptonote developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include <string> + +#include "gtest/gtest.h" + +#include "crypto/chacha8.h" + +namespace +{ + struct test_data { + const uint8_t* key; + const uint8_t* iv; + const size_t text_length; + const uint8_t* plain_text; + const uint8_t* cipher_text; + }; + + #define ARR(...) __VA_ARGS__ + + #define MAKE_TEST_DATA(index, key, iv, plain_text, cipher_text) \ + static const uint8_t test_key_##index[] = key; \ + static const uint8_t test_iv_##index[] = iv; \ + static const uint8_t test_plain_text_##index[] = plain_text; \ + static const uint8_t test_cipher_text_##index[] = cipher_text; \ + static const test_data test_##index = {test_key_##index, test_iv_##index, sizeof(test_plain_text_##index), test_plain_text_##index, test_cipher_text_##index}; + + MAKE_TEST_DATA( + 0, + ARR({0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}), + ARR({0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}), + ARR({0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}), + ARR({0x65, 0x3f, 0x4a, 0x18, 0xe3, 0xd2, 0x7d, 0xaf, 0x51, 0xf8, 0x41, 0xa0, 0x0b, 0x6c, 0x1a, 0x2b, 0xd2, 0x48, 0x98, 0x52, 0xd4, 0xae, 0x07, 0x11, 0xe1, 0xa4, 0xa3, 0x2a, 0xd1, 0x66, 0xfa, 0x6f, 0x88, 0x1a, 0x28, 0x43, 0x23, 0x8c, 0x7e, 0x17, 0x78, 0x6b, 0xa5, 0x16, 0x2b, 0xc0, 0x19, 0xd5, 0x73, 0x84, 0x9c, 0x16, 0x76, 0x68, 0x51, 0x0a, 0xda, 0x2f, 0x62, 0xb4, 0xff, 0x31, 0xad, 0x04}) + ) + + MAKE_TEST_DATA( + 1, + ARR({0x0f, 0x62, 0xb5, 0x08, 0x5b, 0xae, 0x01, 0x54, 0xa7, 0xfa, 0x4d, 0xa0, 0xf3, 0x46, 0x99, 0xec, 0x3f, 0x92, 0xe5, 0x38, 0x8b, 0xde, 0x31, 0x84, 0xd7, 0x2a, 0x7d, 0xd0, 0x23, 0x76, 0xc9, 0x1c}), + ARR({0x28, 0x8f, 0xf6, 0x5d, 0xc4, 0x2b, 0x92, 0xf9}), + ARR({0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}), + ARR({0xdb, 0x16, 0x58, 0x14, 0xf6, 0x67, 0x33, 0xb7, 0xa8, 0xe3, 0x4d, 0x1f, 0xfc, 0x12, 0x34, 0x27, 0x12, 0x56, 0xd3, 0xbf, 0x8d, 0x8d, 0xa2, 0x16, 0x69, 0x22, 0xe5, 0x98, 0xac, 0xac, 0x70, 0xf4, 0x12, 0xb3, 0xfe, 0x35, 0xa9, 0x41, 0x90, 0xad, 0x0a, 0xe2, 0xe8, 0xec, 0x62, 0x13, 0x48, 0x19, 0xab, 0x61, 0xad, 0xdc, 0xcc, 0xfe, 0x99, 0xd8, 0x67, 0xca, 0x3d, 0x73, 0x18, 0x3f, 0xa3, 0xfd}) + ) + + MAKE_TEST_DATA( + 2, + ARR({0x0f, 0x62, 0xb5, 0x08, 0x5b, 0xae, 0x01, 0x54, 0xa7, 0xfa, 0x4d, 0xa0, 0xf3, 0x46, 0x99, 0xec, 0x3f, 0x92, 0xe5, 0x38, 0x8b, 0xde, 0x31, 0x84, 0xd7, 0x2a, 0x7d, 0xd0, 0x23, 0x76, 0xc9, 0x1c}), + ARR({0x28, 0x8f, 0xf6, 0x5d, 0xc4, 0x2b, 0x92, 0xf9}), + ARR({0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}), + ARR({0xdb, 0x16, 0x58, 0x14, 0xf6, 0x67, 0x33, 0xb7, 0xa8, 0xe3, 0x4d, 0x1f, 0xfc, 0x12, 0x34, 0x27, 0x12, 0x56, 0xd3, 0xbf, 0x8d, 0x8d, 0xa2, 0x16, 0x69, 0x22, 0xe5, 0x98, 0xac, 0xac, 0x70, 0xf4, 0x12, 0xb3, 0xfe, 0x35, 0xa9, 0x41, 0x90, 0xad, 0x0a, 0xe2, 0xe8, 0xec, 0x62, 0x13, 0x48, 0x19, 0xab, 0x61, 0xad, 0xdc, 0xcc, 0xfe, 0x99, 0xd8, 0x67, 0xca, 0x3d, 0x73, 0x18, 0x3f, 0xa3, 0xfd, 0x82, 0x87, 0x0F}) + ) + + MAKE_TEST_DATA( + 3, + ARR({0x0f, 0x62, 0xb5, 0x08, 0x5b, 0xae, 0x01, 0x54, 0xa7, 0xfa, 0x4d, 0xa0, 0xf3, 0x46, 0x99, 0xec, 0x3f, 0x92, 0xe5, 0x38, 0x8b, 0xde, 0x31, 0x84, 0xd7, 0x2a, 0x7d, 0xd0, 0x23, 0x76, 0xc9, 0x1c}), + ARR({0x28, 0x8f, 0xf6, 0x5d, 0xc4, 0x2b, 0x92, 0xf9}), + ARR({0x00}), + ARR({0xdb}) + ) + + void run_test(const test_data* test) + { + std::string buf; + buf.resize(test->text_length); + + crypto::chacha8(test->plain_text, test->text_length, test->key, test->iv, &buf[0]); + ASSERT_EQ(buf, std::string(reinterpret_cast<const char*>(test->cipher_text), test->text_length)); + + crypto::chacha8(test->cipher_text, test->text_length, test->key, test->iv, &buf[0]); + ASSERT_EQ(buf, std::string(reinterpret_cast<const char*>(test->plain_text), test->text_length)); + } +} + +#define TEST_CHACHA8(test_no) \ + TEST(chacha8, is_correct_##test_no) \ + { \ + run_test(&test_##test_no); \ + } + +TEST_CHACHA8(0) +TEST_CHACHA8(1) +TEST_CHACHA8(2) +TEST_CHACHA8(3) diff --git a/tests/unit_tests/decompose_amount_into_digits.cpp b/tests/unit_tests/decompose_amount_into_digits.cpp new file mode 100644 index 000000000..d7c66cc73 --- /dev/null +++ b/tests/unit_tests/decompose_amount_into_digits.cpp @@ -0,0 +1,119 @@ +// Copyright (c) 2012-2013 The Cryptonote developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "gtest/gtest.h" + +#include <cstdint> +#include <vector> + +#include "cryptonote_core/cryptonote_format_utils.h" + +#define VEC_FROM_ARR(vec) \ + std::vector<uint64_t> vec; \ + for (size_t i = 0; i < sizeof(vec##_arr) / sizeof(vec##_arr[0]); ++i) \ + { \ + vec.push_back(vec##_arr[i]); \ + } + +namespace +{ + struct chunk_handler_t + { + void operator()(uint64_t chunk) const + { + m_chunks.push_back(chunk); + } + + mutable std::vector<uint64_t> m_chunks; + }; + + struct dust_handler_t + { + dust_handler_t() + : m_dust(0) + , m_has_dust(false) + { + } + + void operator()(uint64_t dust) const + { + m_dust = dust; + m_has_dust = true; + } + + mutable uint64_t m_dust; + mutable bool m_has_dust; + }; + + class decompose_amount_into_digits_test : public ::testing::Test + { + protected: + chunk_handler_t m_chunk_handler; + dust_handler_t m_dust_handler; + }; +} + +TEST_F(decompose_amount_into_digits_test, is_correct_0) +{ + uint64_t expected_chunks_arr[] = {0}; + VEC_FROM_ARR(expected_chunks); + cryptonote::decompose_amount_into_digits(0, 0, m_chunk_handler, m_dust_handler); + ASSERT_EQ(m_chunk_handler.m_chunks, expected_chunks); + ASSERT_EQ(m_dust_handler.m_has_dust, false); +} + +TEST_F(decompose_amount_into_digits_test, is_correct_1) +{ + uint64_t expected_chunks_arr[] = {0}; + VEC_FROM_ARR(expected_chunks); + cryptonote::decompose_amount_into_digits(0, 10, m_chunk_handler, m_dust_handler); + ASSERT_EQ(m_chunk_handler.m_chunks, expected_chunks); + ASSERT_EQ(m_dust_handler.m_has_dust, false); +} + +TEST_F(decompose_amount_into_digits_test, is_correct_2) +{ + uint64_t expected_chunks_arr[] = {10}; + VEC_FROM_ARR(expected_chunks); + cryptonote::decompose_amount_into_digits(10, 0, m_chunk_handler, m_dust_handler); + ASSERT_EQ(m_chunk_handler.m_chunks, expected_chunks); + ASSERT_EQ(m_dust_handler.m_has_dust, false); +} + +TEST_F(decompose_amount_into_digits_test, is_correct_3) +{ + std::vector<uint64_t> expected_chunks; + uint64_t expected_dust = 10; + cryptonote::decompose_amount_into_digits(10, 10, m_chunk_handler, m_dust_handler); + ASSERT_EQ(m_chunk_handler.m_chunks, expected_chunks); + ASSERT_EQ(m_dust_handler.m_dust, expected_dust); +} + +TEST_F(decompose_amount_into_digits_test, is_correct_4) +{ + uint64_t expected_dust = 8100; + std::vector<uint64_t> expected_chunks; + cryptonote::decompose_amount_into_digits(8100, 1000000, m_chunk_handler, m_dust_handler); + ASSERT_EQ(m_chunk_handler.m_chunks, expected_chunks); + ASSERT_EQ(m_dust_handler.m_dust, expected_dust); +} + +TEST_F(decompose_amount_into_digits_test, is_correct_5) +{ + uint64_t expected_chunks_arr[] = {100, 900000, 8000000}; + VEC_FROM_ARR(expected_chunks); + cryptonote::decompose_amount_into_digits(8900100, 10, m_chunk_handler, m_dust_handler); + ASSERT_EQ(m_chunk_handler.m_chunks, expected_chunks); + ASSERT_EQ(m_dust_handler.m_has_dust, false); +} + +TEST_F(decompose_amount_into_digits_test, is_correct_6) +{ + uint64_t expected_chunks_arr[] = {900000, 8000000}; + VEC_FROM_ARR(expected_chunks); + uint64_t expected_dust = 100; + cryptonote::decompose_amount_into_digits(8900100, 1000, m_chunk_handler, m_dust_handler); + ASSERT_EQ(m_chunk_handler.m_chunks, expected_chunks); + ASSERT_EQ(m_dust_handler.m_dust, expected_dust); +} diff --git a/tests/unit_tests/epee_boosted_tcp_server.cpp b/tests/unit_tests/epee_boosted_tcp_server.cpp new file mode 100644 index 000000000..1e606163d --- /dev/null +++ b/tests/unit_tests/epee_boosted_tcp_server.cpp @@ -0,0 +1,109 @@ +// Copyright (c) 2012-2013 The Cryptonote developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include <condition_variable> +#include <chrono> +#include <mutex> +#include <thread> + +#include "gtest/gtest.h" + +#include "include_base_utils.h" +#include "string_tools.h" +#include "net/abstract_tcp_server2.h" + +namespace +{ + const uint32_t test_server_port = 5626; + const std::string test_server_host("127.0.0.1"); + + struct test_connection_context : public epee::net_utils::connection_context_base + { + }; + + struct test_protocol_handler_config + { + }; + + struct test_protocol_handler + { + typedef test_connection_context connection_context; + typedef test_protocol_handler_config config_type; + + test_protocol_handler(epee::net_utils::i_service_endpoint* /*psnd_hndlr*/, config_type& /*config*/, connection_context& /*conn_context*/) + { + } + + void after_init_connection() + { + } + + void handle_qued_callback() + { + } + + bool release_protocol() + { + return true; + } + + bool handle_recv(const void* /*data*/, size_t /*size*/) + { + return false; + } + }; + + typedef epee::net_utils::boosted_tcp_server<test_protocol_handler> test_tcp_server; +} + +TEST(boosted_tcp_server, worker_threads_are_exception_resistant) +{ + test_tcp_server srv; + ASSERT_TRUE(srv.init_server(test_server_port, test_server_host)); + + std::mutex mtx; + std::condition_variable cond; + int counter = 0; + + auto counter_incrementer = [&counter, &cond, &mtx]() + { + std::unique_lock<std::mutex> lock(mtx); + ++counter; + if (4 <= counter) + { + cond.notify_one(); + } + }; + + // 2 theads, but 4 exceptions + ASSERT_TRUE(srv.run_server(2, false)); + ASSERT_TRUE(srv.async_call([&counter_incrementer]() { counter_incrementer(); throw std::runtime_error("test 1"); })); + ASSERT_TRUE(srv.async_call([&counter_incrementer]() { counter_incrementer(); throw std::string("test 2"); })); + ASSERT_TRUE(srv.async_call([&counter_incrementer]() { counter_incrementer(); throw "test 3"; })); + ASSERT_TRUE(srv.async_call([&counter_incrementer]() { counter_incrementer(); throw 4; })); + + { + std::unique_lock<std::mutex> lock(mtx); + ASSERT_NE(std::cv_status::timeout, cond.wait_for(lock, std::chrono::seconds(5))); + ASSERT_EQ(4, counter); + } + + // Check if threads are alive + counter = 0; + //auto counter_incrementer = [&counter]() { counter.fetch_add(1); epee::misc_utils::sleep_no_w(counter.load() * 10); }; + ASSERT_TRUE(srv.async_call(counter_incrementer)); + ASSERT_TRUE(srv.async_call(counter_incrementer)); + ASSERT_TRUE(srv.async_call(counter_incrementer)); + ASSERT_TRUE(srv.async_call(counter_incrementer)); + + { + std::unique_lock<std::mutex> lock(mtx); + ASSERT_NE(std::cv_status::timeout, cond.wait_for(lock, std::chrono::seconds(5))); + ASSERT_EQ(4, counter); + } + + srv.send_stop_signal(); + ASSERT_TRUE(srv.timed_wait_server_stop(5 * 1000)); + ASSERT_TRUE(srv.deinit_server()); +} diff --git a/tests/unit_tests/epee_levin_protocol_handler_async.cpp b/tests/unit_tests/epee_levin_protocol_handler_async.cpp new file mode 100644 index 000000000..da22d9d2d --- /dev/null +++ b/tests/unit_tests/epee_levin_protocol_handler_async.cpp @@ -0,0 +1,506 @@ +// Copyright (c) 2012-2013 The Cryptonote developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include <mutex> +#include <thread> + +#include "gtest/gtest.h" + +#include "include_base_utils.h" +#include "string_tools.h" +#include "net/levin_protocol_handler_async.h" +#include "net/net_utils_base.h" +#include "unit_tests_utils.h" + +namespace +{ + struct test_levin_connection_context : public epee::net_utils::connection_context_base + { + }; + + typedef epee::levin::async_protocol_handler_config<test_levin_connection_context> test_levin_protocol_handler_config; + typedef epee::levin::async_protocol_handler<test_levin_connection_context> test_levin_protocol_handler; + + struct test_levin_commands_handler : public epee::levin::levin_commands_handler<test_levin_connection_context> + { + test_levin_commands_handler() + : m_return_code(LEVIN_OK) + , m_last_command(-1) + { + } + + virtual int invoke(int command, const std::string& in_buff, std::string& buff_out, test_levin_connection_context& context) + { + m_invoke_counter.inc(); + std::unique_lock<std::mutex> lock(m_mutex); + m_last_command = command; + m_last_in_buf = in_buff; + buff_out = m_invoke_out_buf; + return m_return_code; + } + + virtual int notify(int command, const std::string& in_buff, test_levin_connection_context& context) + { + m_notify_counter.inc(); + std::unique_lock<std::mutex> lock(m_mutex); + m_last_command = command; + m_last_in_buf = in_buff; + return m_return_code; + } + + virtual void callback(test_levin_connection_context& context) + { + m_callback_counter.inc(); + //std::cout << "test_levin_commands_handler::callback()" << std::endl; + } + + virtual void on_connection_new(test_levin_connection_context& context) + { + m_new_connection_counter.inc(); + //std::cout << "test_levin_commands_handler::on_connection_new()" << std::endl; + } + + virtual void on_connection_close(test_levin_connection_context& context) + { + m_close_connection_counter.inc(); + //std::cout << "test_levin_commands_handler::on_connection_close()" << std::endl; + } + + size_t invoke_counter() const { return m_invoke_counter.get(); } + size_t notify_counter() const { return m_notify_counter.get(); } + size_t callback_counter() const { return m_callback_counter.get(); } + size_t new_connection_counter() const { return m_new_connection_counter.get(); } + size_t close_connection_counter() const { return m_close_connection_counter.get(); } + + int return_code() const { return m_return_code; } + void return_code(int v) { m_return_code = v; } + + const std::string& invoke_out_buf() const { return m_invoke_out_buf; } + void invoke_out_buf(const std::string& v) { m_invoke_out_buf = v; } + + int last_command() const { return m_last_command; } + const std::string& last_in_buf() const { return m_last_in_buf; } + + private: + unit_test::call_counter m_invoke_counter; + unit_test::call_counter m_notify_counter; + unit_test::call_counter m_callback_counter; + unit_test::call_counter m_new_connection_counter; + unit_test::call_counter m_close_connection_counter; + + std::mutex m_mutex; + + int m_return_code; + std::string m_invoke_out_buf; + + int m_last_command; + std::string m_last_in_buf; + }; + + class test_connection : public epee::net_utils::i_service_endpoint + { + public: + test_connection(boost::asio::io_service& io_service, test_levin_protocol_handler_config& protocol_config) + : m_io_service(io_service) + , m_protocol_handler(this, protocol_config, m_context) + , m_send_return(true) + { + } + + void start() + { + ASSERT_TRUE(m_protocol_handler.after_init_connection()); + } + + // Implement epee::net_utils::i_service_endpoint interface + virtual bool do_send(const void* ptr, size_t cb) + { + //std::cout << "test_connection::do_send()" << std::endl; + m_send_counter.inc(); + std::unique_lock<std::mutex> lock(m_mutex); + m_last_send_data.append(reinterpret_cast<const char*>(ptr), cb); + return m_send_return; + } + + virtual bool close() { /*std::cout << "test_connection::close()" << 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; } + virtual bool add_ref() { std::cout << "test_connection::add_ref()" << std::endl; return true; } + virtual bool release() { std::cout << "test_connection::release()" << std::endl; return true; } + + size_t send_counter() const { return m_send_counter.get(); } + + const std::string& last_send_data() const { return m_last_send_data; } + void reset_last_send_data() { std::unique_lock<std::mutex> lock(m_mutex); m_last_send_data.clear(); } + + bool send_return() const { return m_send_return; } + void send_return(bool v) { m_send_return = v; } + + public: + test_levin_protocol_handler m_protocol_handler; + + private: + boost::asio::io_service& m_io_service; + test_levin_connection_context m_context; + + unit_test::call_counter m_send_counter; + std::mutex m_mutex; + + std::string m_last_send_data; + + bool m_send_return; + }; + + class async_protocol_handler_test : public ::testing::Test + { + public: + const static uint64_t invoke_timeout = 5 * 1000; + const static size_t max_packet_size = 10 * 1024 * 1024; + + typedef std::unique_ptr<test_connection> test_connection_ptr; + + async_protocol_handler_test() + { + m_handler_config.m_pcommands_handler = &m_commands_handler; + m_handler_config.m_invoke_timeout = invoke_timeout; + m_handler_config.m_max_packet_size = max_packet_size; + } + + virtual void SetUp() + { + } + + protected: + test_connection_ptr create_connection(bool start = true) + { + test_connection_ptr conn(new test_connection(m_io_service, m_handler_config)); + if (start) + { + conn->start(); + } + return conn; + } + + protected: + boost::asio::io_service m_io_service; + test_levin_protocol_handler_config m_handler_config; + test_levin_commands_handler m_commands_handler; + }; + + class positive_test_connection_to_levin_protocol_handler_calls : public async_protocol_handler_test + { + }; + + class test_levin_protocol_handler__hanle_recv_with_invalid_data : public async_protocol_handler_test + { + public: + static const int expected_command = 5615871; + static const int expected_return_code = 782546; + + test_levin_protocol_handler__hanle_recv_with_invalid_data() + : m_expected_invoke_out_buf(512, 'y') + { + } + + virtual void SetUp() + { + async_protocol_handler_test::SetUp(); + + m_conn = create_connection(); + + m_in_data.assign(256, 't'); + + m_req_head.m_signature = LEVIN_SIGNATURE; + m_req_head.m_cb = m_in_data.size(); + m_req_head.m_have_to_return_data = true; + m_req_head.m_command = expected_command; + m_req_head.m_flags = LEVIN_PACKET_REQUEST; + m_req_head.m_protocol_version = LEVIN_PROTOCOL_VER_1; + + m_commands_handler.return_code(expected_return_code); + m_commands_handler.invoke_out_buf(m_expected_invoke_out_buf); + } + + protected: + void prepare_buf() + { + m_buf.assign(reinterpret_cast<const char*>(&m_req_head), sizeof(m_req_head)); + m_buf += m_in_data; + } + + protected: + test_connection_ptr m_conn; + epee::levin::bucket_head2 m_req_head; + std::string m_in_data; + std::string m_buf; + std::string m_expected_invoke_out_buf; + }; +} + +TEST_F(positive_test_connection_to_levin_protocol_handler_calls, new_handler_is_not_initialized) +{ + test_connection_ptr conn = create_connection(false); + ASSERT_FALSE(conn->m_protocol_handler.m_connection_initialized); + ASSERT_EQ(0, m_handler_config.get_connections_count()); + ASSERT_EQ(0, m_commands_handler.new_connection_counter()); + conn.reset(); + ASSERT_EQ(0, m_handler_config.get_connections_count()); + ASSERT_EQ(0, m_commands_handler.close_connection_counter()); +} + +TEST_F(positive_test_connection_to_levin_protocol_handler_calls, handler_initialization_and_destruction_is_correct) +{ + test_connection_ptr conn = create_connection(); + ASSERT_TRUE(conn->m_protocol_handler.m_connection_initialized); + ASSERT_EQ(1, m_handler_config.get_connections_count()); + ASSERT_EQ(1, m_commands_handler.new_connection_counter()); + conn.reset(); + ASSERT_EQ(0, m_handler_config.get_connections_count()); + ASSERT_EQ(1, m_commands_handler.close_connection_counter()); +} + +TEST_F(positive_test_connection_to_levin_protocol_handler_calls, concurent_handler_initialization_and_destruction_is_correct) +{ + const size_t connection_count = 10000; + auto create_and_destroy_connections = [this, connection_count]() + { + std::vector<test_connection_ptr> connections(connection_count); + for (size_t i = 0; i < connection_count; ++i) + { + connections[i] = create_connection(); + } + + for (size_t i = 0; i < connection_count; ++i) + { + connections[i].reset(); + } + }; + + const size_t thread_count = std::thread::hardware_concurrency(); + std::vector<std::thread> threads(thread_count); + for (std::thread& th : threads) + { + th = std::thread(create_and_destroy_connections); + } + + for (std::thread& th : threads) + { + th.join(); + } + + ASSERT_EQ(0, m_handler_config.get_connections_count()); + ASSERT_EQ(connection_count * thread_count, m_commands_handler.new_connection_counter()); + ASSERT_EQ(connection_count * thread_count, m_commands_handler.close_connection_counter()); +} + +TEST_F(positive_test_connection_to_levin_protocol_handler_calls, handler_processes_handle_read_as_invoke) +{ + // Setup + const int expected_command = 2634981; + const int expected_return_code = 6732; + const std::string expected_out_data(128, 'w'); + + test_connection_ptr conn = create_connection(); + + std::string in_data(256, 'q'); + + epee::levin::bucket_head2 req_head; + req_head.m_signature = LEVIN_SIGNATURE; + req_head.m_cb = in_data.size(); + req_head.m_have_to_return_data = true; + req_head.m_command = expected_command; + req_head.m_flags = LEVIN_PACKET_REQUEST; + req_head.m_protocol_version = LEVIN_PROTOCOL_VER_1; + + std::string buf(reinterpret_cast<const char*>(&req_head), sizeof(req_head)); + buf += in_data; + + m_commands_handler.invoke_out_buf(expected_out_data); + m_commands_handler.return_code(expected_return_code); + + // Test + ASSERT_TRUE(conn->m_protocol_handler.handle_recv(buf.data(), buf.size())); + + // + // Check + // + + // Check connection and levin_commands_handler states + ASSERT_EQ(1, m_commands_handler.invoke_counter()); + ASSERT_EQ(0, m_commands_handler.notify_counter()); + ASSERT_EQ(expected_command, m_commands_handler.last_command()); + ASSERT_EQ(in_data, m_commands_handler.last_in_buf()); + ASSERT_LE(1, conn->send_counter()); + + // Parse send data + std::string send_data = conn->last_send_data(); + epee::levin::bucket_head2 resp_head; + resp_head = *reinterpret_cast<const epee::levin::bucket_head2*>(send_data.data()); + ASSERT_LT(sizeof(resp_head), send_data.size()); + std::string out_data = send_data.substr(sizeof(resp_head)); + + // Check sent response + ASSERT_EQ(expected_out_data, out_data); + ASSERT_EQ(LEVIN_SIGNATURE, resp_head.m_signature); + ASSERT_EQ(expected_command, resp_head.m_command); + ASSERT_EQ(expected_return_code, resp_head.m_return_code); + ASSERT_EQ(expected_out_data.size(), resp_head.m_cb); + ASSERT_FALSE(resp_head.m_have_to_return_data); + ASSERT_EQ(LEVIN_PROTOCOL_VER_1, resp_head.m_protocol_version); + ASSERT_TRUE(0 != (resp_head.m_flags | LEVIN_PACKET_RESPONSE)); +} + +TEST_F(positive_test_connection_to_levin_protocol_handler_calls, handler_processes_handle_read_as_notify) +{ + // Setup + const int expected_command = 4673261; + + test_connection_ptr conn = create_connection(); + + std::string in_data(256, 'e'); + + epee::levin::bucket_head2 req_head; + req_head.m_signature = LEVIN_SIGNATURE; + req_head.m_cb = in_data.size(); + req_head.m_have_to_return_data = false; + req_head.m_command = expected_command; + req_head.m_flags = LEVIN_PACKET_REQUEST; + req_head.m_protocol_version = LEVIN_PROTOCOL_VER_1; + + std::string buf(reinterpret_cast<const char*>(&req_head), sizeof(req_head)); + buf += in_data; + + // Test + ASSERT_TRUE(conn->m_protocol_handler.handle_recv(buf.data(), buf.size())); + + // Check connection and levin_commands_handler states + ASSERT_EQ(1, m_commands_handler.notify_counter()); + ASSERT_EQ(0, m_commands_handler.invoke_counter()); + ASSERT_EQ(expected_command, m_commands_handler.last_command()); + ASSERT_EQ(in_data, m_commands_handler.last_in_buf()); + ASSERT_LE(0, conn->send_counter()); + ASSERT_TRUE(conn->last_send_data().empty()); +} + +TEST_F(positive_test_connection_to_levin_protocol_handler_calls, handler_processes_qued_callback) +{ + test_connection_ptr conn = create_connection(); + + conn->m_protocol_handler.handle_qued_callback(); + conn->m_protocol_handler.handle_qued_callback(); + conn->m_protocol_handler.handle_qued_callback(); + + ASSERT_EQ(3, m_commands_handler.callback_counter()); +} + +TEST_F(test_levin_protocol_handler__hanle_recv_with_invalid_data, handles_big_packet_1) +{ + std::string buf("yyyyyy"); + ASSERT_FALSE(m_conn->m_protocol_handler.handle_recv(buf.data(), max_packet_size + 1)); +} + +TEST_F(test_levin_protocol_handler__hanle_recv_with_invalid_data, handles_big_packet_2) +{ + prepare_buf(); + const size_t first_packet_size = sizeof(m_req_head) - 1; + + m_buf.resize(first_packet_size); + ASSERT_TRUE(m_conn->m_protocol_handler.handle_recv(m_buf.data(), m_buf.size())); + + ASSERT_FALSE(m_conn->m_protocol_handler.handle_recv(m_buf.data(), max_packet_size - m_buf.size() + 1)); +} + +TEST_F(test_levin_protocol_handler__hanle_recv_with_invalid_data, handles_invalid_signature_for_full_header) +{ + m_req_head.m_signature = LEVIN_SIGNATURE ^ 1; + prepare_buf(); + + ASSERT_FALSE(m_conn->m_protocol_handler.handle_recv(m_buf.data(), m_buf.size())); +} + +TEST_F(test_levin_protocol_handler__hanle_recv_with_invalid_data, handles_invalid_signature_for_partial_header) +{ + m_req_head.m_signature = LEVIN_SIGNATURE ^ 1; + prepare_buf(); + m_buf.resize(sizeof(m_req_head.m_signature)); + + ASSERT_FALSE(m_conn->m_protocol_handler.handle_recv(m_buf.data(), m_buf.size())); +} + +TEST_F(test_levin_protocol_handler__hanle_recv_with_invalid_data, handles_big_cb) +{ + m_req_head.m_cb = max_packet_size + 1; + prepare_buf(); + + ASSERT_FALSE(m_conn->m_protocol_handler.handle_recv(m_buf.data(), m_buf.size())); +} + +TEST_F(test_levin_protocol_handler__hanle_recv_with_invalid_data, does_not_handle_data_after_close) +{ + prepare_buf(); + + ASSERT_TRUE(m_conn->m_protocol_handler.close()); + ASSERT_FALSE(m_conn->m_protocol_handler.handle_recv(m_buf.data(), m_buf.size())); +} + +TEST_F(test_levin_protocol_handler__hanle_recv_with_invalid_data, handles_network_error) +{ + prepare_buf(); + + m_conn->send_return(false); + ASSERT_FALSE(m_conn->m_protocol_handler.handle_recv(m_buf.data(), m_buf.size())); +} + +TEST_F(test_levin_protocol_handler__hanle_recv_with_invalid_data, handles_chunked_header) +{ + prepare_buf(); + + size_t buf1_size = sizeof(m_req_head) / 2; + + std::string buf1 = m_buf.substr(0, buf1_size); + std::string buf2 = m_buf.substr(buf1_size); + ASSERT_EQ(m_buf, buf1 + buf2); + + ASSERT_TRUE(m_conn->m_protocol_handler.handle_recv(buf1.data(), buf1.size())); + ASSERT_EQ(0, m_commands_handler.invoke_counter()); + + ASSERT_TRUE(m_conn->m_protocol_handler.handle_recv(buf2.data(), buf2.size())); + ASSERT_EQ(1, m_commands_handler.invoke_counter()); +} + + +TEST_F(test_levin_protocol_handler__hanle_recv_with_invalid_data, handles_chunked_body) +{ + prepare_buf(); + + size_t buf1_size = sizeof(m_req_head) + (m_buf.size() - sizeof(m_req_head)) / 2; + + std::string buf1 = m_buf.substr(0, buf1_size); + std::string buf2 = m_buf.substr(buf1_size); + ASSERT_EQ(m_buf, buf1 + buf2); + + ASSERT_TRUE(m_conn->m_protocol_handler.handle_recv(buf1.data(), buf1.size())); + ASSERT_EQ(0, m_commands_handler.invoke_counter()); + + ASSERT_TRUE(m_conn->m_protocol_handler.handle_recv(buf2.data(), buf2.size())); + ASSERT_EQ(1, m_commands_handler.invoke_counter()); +} + +TEST_F(test_levin_protocol_handler__hanle_recv_with_invalid_data, handles_two_requests_at_once) +{ + prepare_buf(); + m_buf.append(m_buf); + + ASSERT_TRUE(m_conn->m_protocol_handler.handle_recv(m_buf.data(), m_buf.size())); + ASSERT_EQ(2, m_commands_handler.invoke_counter()); +} + +TEST_F(test_levin_protocol_handler__hanle_recv_with_invalid_data, handles_unexpected_response) +{ + m_req_head.m_flags = LEVIN_PACKET_RESPONSE; + prepare_buf(); + + ASSERT_FALSE(m_conn->m_protocol_handler.handle_recv(m_buf.data(), m_buf.size())); +} diff --git a/tests/unit_tests/main.cpp b/tests/unit_tests/main.cpp new file mode 100644 index 000000000..65bf247d8 --- /dev/null +++ b/tests/unit_tests/main.cpp @@ -0,0 +1,15 @@ +// Copyright (c) 2012-2013 The Cryptonote developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "gtest/gtest.h" + +#include "include_base_utils.h" + +int main(int argc, char** argv) +{ + epee::debug::get_set_enable_assert(true, false); + + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/tests/unit_tests/mul_div.cpp b/tests/unit_tests/mul_div.cpp new file mode 100644 index 000000000..291e4f191 --- /dev/null +++ b/tests/unit_tests/mul_div.cpp @@ -0,0 +1,179 @@ +// Copyright (c) 2012-2013 The Cryptonote developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "gtest/gtest.h" + +#include "common/int-util.h" + +namespace +{ + TEST(mul128, handles_zero) + { + uint64_t hi, lo; + + lo = mul128(0, 0, &hi); + ASSERT_EQ(lo, 0); + ASSERT_EQ(hi, 0); + + lo = mul128(7, 0, &hi); + ASSERT_EQ(lo, 0); + ASSERT_EQ(hi, 0); + + lo = mul128(0, 7, &hi); + ASSERT_EQ(lo, 0); + ASSERT_EQ(hi, 0); + } + + TEST(mul128, handles_one) + { + uint64_t hi, lo; + + lo = mul128(1, 1, &hi); + ASSERT_EQ(lo, 1); + ASSERT_EQ(hi, 0); + + lo = mul128(7, 1, &hi); + ASSERT_EQ(lo, 7); + ASSERT_EQ(hi, 0); + + lo = mul128(1, 7, &hi); + ASSERT_EQ(lo, 7); + ASSERT_EQ(hi, 0); + } + + TEST(mul128_without_carry, multiplies_correctly) + { + uint64_t hi, lo; + + lo = mul128(0x3333333333333333, 5, &hi); + ASSERT_EQ(lo, 0xffffffffffffffff); + ASSERT_EQ(hi, 0); + + lo = mul128(5, 0x3333333333333333, &hi); + ASSERT_EQ(lo, 0xffffffffffffffff); + ASSERT_EQ(hi, 0); + + lo = mul128(0x1111111111111111, 0x1111111111111111, &hi); + ASSERT_EQ(lo, 0x0fedcba987654321); + ASSERT_EQ(hi, 0x0123456789abcdf0);; + } + + TEST(mul128_with_carry_1_only, multiplies_correctly) + { + uint64_t hi, lo; + + lo = mul128(0xe0000000e0000000, 0xe0000000e0000000, &hi); + ASSERT_EQ(lo, 0xc400000000000000); + ASSERT_EQ(hi, 0xc400000188000000); + } + + TEST(mul128_with_carry_2_only, multiplies_correctly) + { + uint64_t hi, lo; + + lo = mul128(0x10000000ffffffff, 0x10000000ffffffff, &hi); + ASSERT_EQ(lo, 0xdffffffe00000001); + ASSERT_EQ(hi, 0x0100000020000000); + } + + TEST(mul128_with_carry_1_and_2, multiplies_correctly) + { + uint64_t hi, lo; + + lo = mul128(0xf1f2f3f4f5f6f7f8, 0xf9f0fafbfcfdfeff, &hi); + ASSERT_EQ(lo, 0x52118e5f3b211008); + ASSERT_EQ(hi, 0xec39104363716e59); + + lo = mul128(0xffffffffffffffff, 0xffffffffffffffff, &hi); + ASSERT_EQ(lo, 0x0000000000000001); + ASSERT_EQ(hi, 0xfffffffffffffffe); + } + + TEST(div128_32, handles_zero) + { + uint32_t reminder; + uint64_t hi; + uint64_t lo; + + reminder = div128_32(0, 0, 7, &hi, &lo); + ASSERT_EQ(reminder, 0); + ASSERT_EQ(hi, 0); + ASSERT_EQ(lo, 0); + + // Division by zero is UB, so can be tested correctly + } + + TEST(div128_32, handles_one) + { + uint32_t reminder; + uint64_t hi; + uint64_t lo; + + reminder = div128_32(0, 7, 1, &hi, &lo); + ASSERT_EQ(reminder, 0); + ASSERT_EQ(hi, 0); + ASSERT_EQ(lo, 7); + + reminder = div128_32(7, 0, 1, &hi, &lo); + ASSERT_EQ(reminder, 0); + ASSERT_EQ(hi, 7); + ASSERT_EQ(lo, 0); + } + + TEST(div128_32, handles_if_dividend_less_divider) + { + uint32_t reminder; + uint64_t hi; + uint64_t lo; + + reminder = div128_32(0, 1383746, 1645825, &hi, &lo); + ASSERT_EQ(reminder, 1383746); + ASSERT_EQ(hi, 0); + ASSERT_EQ(lo, 0); + } + + TEST(div128_32, handles_if_dividend_dwords_less_divider) + { + uint32_t reminder; + uint64_t hi; + uint64_t lo; + + reminder = div128_32(0x5AD629E441074F28, 0x0DBCAB2B231081F1, 0xFE735CD6, &hi, &lo); + ASSERT_EQ(reminder, 0xB9C924E9); + ASSERT_EQ(hi, 0x000000005B63C274); + ASSERT_EQ(lo, 0x9084FC024383E48C); + } + + TEST(div128_32, works_correctly) + { + uint32_t reminder; + uint64_t hi; + uint64_t lo; + + reminder = div128_32(2, 0, 2, &hi, &lo); + ASSERT_EQ(reminder, 0); + ASSERT_EQ(hi, 1); + ASSERT_EQ(lo, 0); + + reminder = div128_32(0xffffffffffffffff, 0, 0xffffffff, &hi, &lo); + ASSERT_EQ(reminder, 0); + ASSERT_EQ(hi, 0x0000000100000001); + ASSERT_EQ(lo, 0); + + reminder = div128_32(0xffffffffffffffff, 5846, 0xffffffff, &hi, &lo); + ASSERT_EQ(reminder, 5846); + ASSERT_EQ(hi, 0x0000000100000001); + ASSERT_EQ(lo, 0); + + reminder = div128_32(0xffffffffffffffff - 1, 0, 0xffffffff, &hi, &lo); + ASSERT_EQ(reminder, 0xfffffffe); + ASSERT_EQ(hi, 0x0000000100000000); + ASSERT_EQ(lo, 0xfffffffefffffffe); + + reminder = div128_32(0x2649372534875028, 0xaedbfedc5adbc739, 0x27826534, &hi, &lo); + ASSERT_EQ(reminder, 0x1a6dc2e5); + ASSERT_EQ(hi, 0x00000000f812c1f8); + ASSERT_EQ(lo, 0xddf2fdb09bc2e2e9); + } +} diff --git a/tests/unit_tests/serialization.cpp b/tests/unit_tests/serialization.cpp new file mode 100644 index 000000000..616509d82 --- /dev/null +++ b/tests/unit_tests/serialization.cpp @@ -0,0 +1,418 @@ +// Copyright (c) 2012-2013 The Cryptonote developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include <cstring> +#include <cstdint> +#include <cstdio> +#include <iostream> +#include <vector> +#include <boost/foreach.hpp> +#include "cryptonote_core/cryptonote_basic.h" +#include "cryptonote_core/cryptonote_basic_impl.h" +#include "serialization/serialization.h" +#include "serialization/binary_archive.h" +#include "serialization/json_archive.h" +#include "serialization/debug_archive.h" +#include "serialization/variant.h" +#include "serialization/vector.h" +#include "serialization/binary_utils.h" +#include "gtest/gtest.h" +using namespace std; + +struct Struct +{ + int32_t a; + int32_t b; + char blob[8]; +}; + +template <class Archive> +struct serializer<Archive, Struct> +{ + static bool serialize(Archive &ar, Struct &s) { + ar.begin_object(); + ar.tag("a"); + ar.serialize_int(s.a); + ar.tag("b"); + ar.serialize_int(s.b); + ar.tag("blob"); + ar.serialize_blob(s.blob, sizeof(s.blob)); + ar.end_object(); + return true; + } +}; + +struct Struct1 +{ + vector<boost::variant<Struct, int32_t>> si; + vector<int16_t> vi; + + BEGIN_SERIALIZE_OBJECT() + FIELD(si) + FIELD(vi) + END_SERIALIZE() + /*template <bool W, template <bool> class Archive> + bool do_serialize(Archive<W> &ar) + { + ar.begin_object(); + ar.tag("si"); + ::do_serialize(ar, si); + ar.tag("vi"); + ::do_serialize(ar, vi); + ar.end_object(); + }*/ +}; + +struct Blob +{ + uint64_t a; + uint32_t b; + + bool operator==(const Blob& rhs) const + { + return a == rhs.a; + } +}; + +VARIANT_TAG(binary_archive, Struct, 0xe0); +VARIANT_TAG(binary_archive, int, 0xe1); +VARIANT_TAG(json_archive, Struct, "struct"); +VARIANT_TAG(json_archive, int, "int"); +VARIANT_TAG(debug_archive, Struct1, "struct1"); +VARIANT_TAG(debug_archive, Struct, "struct"); +VARIANT_TAG(debug_archive, int, "int"); + +BLOB_SERIALIZER(Blob); + +bool try_parse(const string &blob) +{ + Struct1 s1; + return serialization::parse_binary(blob, s1); +} + +TEST(Serialization, BinaryArchiveInts) { + uint64_t x = 0xff00000000, x1; + + ostringstream oss; + binary_archive<true> oar(oss); + oar.serialize_int(x); + ASSERT_TRUE(oss.good()); + ASSERT_EQ(8, oss.str().size()); + ASSERT_EQ(string("\0\0\0\0\xff\0\0\0", 8), oss.str()); + + istringstream iss(oss.str()); + binary_archive<false> iar(iss); + iar.serialize_int(x1); + ASSERT_EQ(8, iss.tellg()); + ASSERT_TRUE(iss.good()); + + ASSERT_EQ(x, x1); +} + +TEST(Serialization, BinaryArchiveVarInts) { + uint64_t x = 0xff00000000, x1; + + ostringstream oss; + binary_archive<true> oar(oss); + oar.serialize_varint(x); + ASSERT_TRUE(oss.good()); + ASSERT_EQ(6, oss.str().size()); + ASSERT_EQ(string("\x80\x80\x80\x80\xF0\x1F", 6), oss.str()); + + istringstream iss(oss.str()); + binary_archive<false> iar(iss); + iar.serialize_varint(x1); + ASSERT_TRUE(iss.good()); + ASSERT_EQ(x, x1); +} + +TEST(Serialization, Test1) { + ostringstream str; + binary_archive<true> ar(str); + + Struct1 s1; + s1.si.push_back(0); + { + Struct s; + s.a = 5; + s.b = 65539; + std::memcpy(s.blob, "12345678", 8); + s1.si.push_back(s); + } + s1.si.push_back(1); + s1.vi.push_back(10); + s1.vi.push_back(22); + + string blob; + ASSERT_TRUE(serialization::dump_binary(s1, blob)); + ASSERT_TRUE(try_parse(blob)); + + ASSERT_EQ('\xE0', blob[6]); + blob[6] = '\xE1'; + ASSERT_FALSE(try_parse(blob)); + blob[6] = '\xE2'; + ASSERT_FALSE(try_parse(blob)); +} + +TEST(Serialization, Overflow) { + Blob x = { 0xff00000000 }; + Blob x1; + + string blob; + ASSERT_TRUE(serialization::dump_binary(x, blob)); + ASSERT_EQ(sizeof(Blob), blob.size()); + + ASSERT_TRUE(serialization::parse_binary(blob, x1)); + ASSERT_EQ(x, x1); + + vector<Blob> bigvector; + ASSERT_FALSE(serialization::parse_binary(blob, bigvector)); + ASSERT_EQ(0, bigvector.size()); +} + +TEST(Serialization, serializes_vector_uint64_as_varint) +{ + std::vector<uint64_t> v; + string blob; + + ASSERT_TRUE(serialization::dump_binary(v, blob)); + ASSERT_EQ(1, blob.size()); + + // +1 byte + v.push_back(0); + ASSERT_TRUE(serialization::dump_binary(v, blob)); + ASSERT_EQ(2, blob.size()); + + // +1 byte + v.push_back(1); + ASSERT_TRUE(serialization::dump_binary(v, blob)); + ASSERT_EQ(3, blob.size()); + + // +2 bytes + v.push_back(0x80); + ASSERT_TRUE(serialization::dump_binary(v, blob)); + ASSERT_EQ(5, blob.size()); + + // +2 bytes + v.push_back(0xFF); + ASSERT_TRUE(serialization::dump_binary(v, blob)); + ASSERT_EQ(7, blob.size()); + + // +2 bytes + v.push_back(0x3FFF); + ASSERT_TRUE(serialization::dump_binary(v, blob)); + ASSERT_EQ(9, blob.size()); + + // +3 bytes + v.push_back(0x40FF); + ASSERT_TRUE(serialization::dump_binary(v, blob)); + ASSERT_EQ(12, blob.size()); + + // +10 bytes + v.push_back(0xFFFFFFFFFFFFFFFF); + ASSERT_TRUE(serialization::dump_binary(v, blob)); + ASSERT_EQ(22, blob.size()); +} + +TEST(Serialization, serializes_vector_int64_as_fixed_int) +{ + std::vector<int64_t> v; + string blob; + + ASSERT_TRUE(serialization::dump_binary(v, blob)); + ASSERT_EQ(1, blob.size()); + + // +8 bytes + v.push_back(0); + ASSERT_TRUE(serialization::dump_binary(v, blob)); + ASSERT_EQ(9, blob.size()); + + // +8 bytes + v.push_back(1); + ASSERT_TRUE(serialization::dump_binary(v, blob)); + ASSERT_EQ(17, blob.size()); + + // +8 bytes + v.push_back(0x80); + ASSERT_TRUE(serialization::dump_binary(v, blob)); + ASSERT_EQ(25, blob.size()); + + // +8 bytes + v.push_back(0xFF); + ASSERT_TRUE(serialization::dump_binary(v, blob)); + ASSERT_EQ(33, blob.size()); + + // +8 bytes + v.push_back(0x3FFF); + ASSERT_TRUE(serialization::dump_binary(v, blob)); + ASSERT_EQ(41, blob.size()); + + // +8 bytes + v.push_back(0x40FF); + ASSERT_TRUE(serialization::dump_binary(v, blob)); + ASSERT_EQ(49, blob.size()); + + // +8 bytes + v.push_back(0xFFFFFFFFFFFFFFFF); + ASSERT_TRUE(serialization::dump_binary(v, blob)); + ASSERT_EQ(57, blob.size()); +} + +namespace +{ + template<typename T> + std::vector<T> linearize_vector2(const std::vector< std::vector<T> >& vec_vec) + { + std::vector<T> res; + BOOST_FOREACH(const auto& vec, vec_vec) + { + res.insert(res.end(), vec.begin(), vec.end()); + } + return res; + } +} + +TEST(Serialization, serializes_transacion_signatures_correctly) +{ + using namespace cryptonote; + + transaction tx; + transaction tx1; + string blob; + + // Empty tx + tx.set_null(); + ASSERT_TRUE(serialization::dump_binary(tx, blob)); + ASSERT_EQ(5, blob.size()); // 5 bytes + 0 bytes extra + 0 bytes signatures + ASSERT_TRUE(serialization::parse_binary(blob, tx1)); + ASSERT_EQ(tx, tx1); + ASSERT_EQ(linearize_vector2(tx.signatures), linearize_vector2(tx1.signatures)); + + // Miner tx without signatures + txin_gen txin_gen1; + txin_gen1.height = 0; + tx.set_null(); + tx.vin.push_back(txin_gen1); + ASSERT_TRUE(serialization::dump_binary(tx, blob)); + ASSERT_EQ(7, blob.size()); // 5 bytes + 2 bytes vin[0] + 0 bytes extra + 0 bytes signatures + ASSERT_TRUE(serialization::parse_binary(blob, tx1)); + ASSERT_EQ(tx, tx1); + ASSERT_EQ(linearize_vector2(tx.signatures), linearize_vector2(tx1.signatures)); + + // Miner tx with empty signatures 2nd vector + tx.signatures.resize(1); + ASSERT_TRUE(serialization::dump_binary(tx, blob)); + ASSERT_EQ(7, blob.size()); // 5 bytes + 2 bytes vin[0] + 0 bytes extra + 0 bytes signatures + ASSERT_TRUE(serialization::parse_binary(blob, tx1)); + ASSERT_EQ(tx, tx1); + ASSERT_EQ(linearize_vector2(tx.signatures), linearize_vector2(tx1.signatures)); + + // Miner tx with one signature + tx.signatures[0].resize(1); + ASSERT_FALSE(serialization::dump_binary(tx, blob)); + + // Miner tx with 2 empty vectors + tx.signatures.resize(2); + tx.signatures[0].resize(0); + tx.signatures[1].resize(0); + ASSERT_FALSE(serialization::dump_binary(tx, blob)); + + // Miner tx with 2 signatures + tx.signatures[0].resize(1); + tx.signatures[1].resize(1); + ASSERT_FALSE(serialization::dump_binary(tx, blob)); + + // Two txin_gen, no signatures + tx.vin.push_back(txin_gen1); + tx.signatures.resize(0); + ASSERT_TRUE(serialization::dump_binary(tx, blob)); + ASSERT_EQ(9, blob.size()); // 5 bytes + 2 * 2 bytes vins + 0 bytes extra + 0 bytes signatures + ASSERT_TRUE(serialization::parse_binary(blob, tx1)); + ASSERT_EQ(tx, tx1); + ASSERT_EQ(linearize_vector2(tx.signatures), linearize_vector2(tx1.signatures)); + + // Two txin_gen, signatures vector contains only one empty element + tx.signatures.resize(1); + ASSERT_FALSE(serialization::dump_binary(tx, blob)); + + // Two txin_gen, signatures vector contains two empty elements + tx.signatures.resize(2); + ASSERT_TRUE(serialization::dump_binary(tx, blob)); + ASSERT_EQ(9, blob.size()); // 5 bytes + 2 * 2 bytes vins + 0 bytes extra + 0 bytes signatures + ASSERT_TRUE(serialization::parse_binary(blob, tx1)); + ASSERT_EQ(tx, tx1); + ASSERT_EQ(linearize_vector2(tx.signatures), linearize_vector2(tx1.signatures)); + + // Two txin_gen, signatures vector contains three empty elements + tx.signatures.resize(3); + ASSERT_FALSE(serialization::dump_binary(tx, blob)); + + // Two txin_gen, signatures vector contains two non empty elements + tx.signatures.resize(2); + tx.signatures[0].resize(1); + tx.signatures[1].resize(1); + ASSERT_FALSE(serialization::dump_binary(tx, blob)); + + // A few bytes instead of signature + tx.vin.clear(); + tx.vin.push_back(txin_gen1); + tx.signatures.clear(); + ASSERT_TRUE(serialization::dump_binary(tx, blob)); + blob.append(std::string(sizeof(crypto::signature) / 2, 'x')); + ASSERT_FALSE(serialization::parse_binary(blob, tx1)); + + // blob contains one signature + blob.append(std::string(sizeof(crypto::signature) / 2, 'y')); + ASSERT_FALSE(serialization::parse_binary(blob, tx1)); + + // Not enough signature vectors for all inputs + txin_to_key txin_to_key1; + txin_to_key1.key_offsets.resize(2); + tx.vin.clear(); + tx.vin.push_back(txin_to_key1); + tx.vin.push_back(txin_to_key1); + tx.signatures.resize(1); + tx.signatures[0].resize(2); + ASSERT_FALSE(serialization::dump_binary(tx, blob)); + + // Too much signatures for two inputs + tx.signatures.resize(3); + tx.signatures[0].resize(2); + tx.signatures[1].resize(2); + tx.signatures[2].resize(2); + ASSERT_FALSE(serialization::dump_binary(tx, blob)); + + // First signatures vector contains too little elements + tx.signatures.resize(2); + tx.signatures[0].resize(1); + tx.signatures[1].resize(2); + ASSERT_FALSE(serialization::dump_binary(tx, blob)); + + // First signatures vector contains too much elements + tx.signatures.resize(2); + tx.signatures[0].resize(3); + tx.signatures[1].resize(2); + ASSERT_FALSE(serialization::dump_binary(tx, blob)); + + // There are signatures for each input + tx.signatures.resize(2); + tx.signatures[0].resize(2); + tx.signatures[1].resize(2); + ASSERT_TRUE(serialization::dump_binary(tx, blob)); + ASSERT_TRUE(serialization::parse_binary(blob, tx1)); + ASSERT_EQ(tx, tx1); + ASSERT_EQ(linearize_vector2(tx.signatures), linearize_vector2(tx1.signatures)); + + // Blob doesn't contain enough data + blob.resize(blob.size() - sizeof(crypto::signature) / 2); + ASSERT_FALSE(serialization::parse_binary(blob, tx1)); + + // Blob contains too much data + blob.resize(blob.size() + sizeof(crypto::signature)); + ASSERT_FALSE(serialization::parse_binary(blob, tx1)); + + // Blob contains one excess signature + blob.resize(blob.size() + sizeof(crypto::signature) / 2); + ASSERT_FALSE(serialization::parse_binary(blob, tx1)); +} diff --git a/tests/unit_tests/test_format_utils.cpp b/tests/unit_tests/test_format_utils.cpp new file mode 100644 index 000000000..22f56628e --- /dev/null +++ b/tests/unit_tests/test_format_utils.cpp @@ -0,0 +1,97 @@ +// Copyright (c) 2012-2013 The Cryptonote developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "gtest/gtest.h" + +#include "common/util.h" +#include "cryptonote_core/cryptonote_format_utils.h" + +TEST(parse_and_validate_tx_extra, is_correct_parse_and_validate_tx_extra) +{ + cryptonote::transaction tx = AUTO_VAL_INIT(tx); + cryptonote::account_base acc; + acc.generate(); + std::vector<size_t> bss; + cryptonote::blobdata b = "dsdsdfsdfsf"; + bool r = cryptonote::construct_miner_tx(0, 10000000000000, acc.get_keys().m_account_address, tx, DEFAULT_FEE, bss, 1000, b, 1); + ASSERT_TRUE(r); + crypto::public_key tx_pub_key; + r = cryptonote::parse_and_validate_tx_extra(tx, tx_pub_key); + ASSERT_TRUE(r); +} +TEST(parse_and_validate_tx_extra, is_correct_extranonce_too_big) +{ + cryptonote::transaction tx = AUTO_VAL_INIT(tx); + cryptonote::account_base acc; + acc.generate(); + std::vector<size_t> bss; + cryptonote::blobdata b(260, 0); + bool r = cryptonote::construct_miner_tx(0, 10000000000000, acc.get_keys().m_account_address, tx, DEFAULT_FEE, bss, 1000, b, 1); + ASSERT_FALSE(r); +} +TEST(parse_and_validate_tx_extra, is_correct_wrong_extra_couner_too_big) +{ + cryptonote::transaction tx = AUTO_VAL_INIT(tx); + tx.extra.resize(20, 0); + tx.extra[0] = TX_EXTRA_NONCE; + tx.extra[1] = 255; + crypto::public_key tx_pub_key; + bool r = parse_and_validate_tx_extra(tx, tx_pub_key); + ASSERT_FALSE(r); +} +TEST(parse_and_validate_tx_extra, is_correct_wrong_extra_nonce_double_entry) +{ + cryptonote::transaction tx = AUTO_VAL_INIT(tx); + tx.extra.resize(20, 0); + cryptonote::blobdata v = "asasdasd"; + cryptonote::add_tx_extra_nonce(tx, v); + cryptonote::add_tx_extra_nonce(tx, v); + crypto::public_key tx_pub_key; + bool r = parse_and_validate_tx_extra(tx, tx_pub_key); + ASSERT_FALSE(r); +} + +TEST(validate_parse_amount_case, validate_parse_amount) +{ + uint64_t res = 0; + bool r = cryptonote::parse_amount(res, "0.0001"); + ASSERT_TRUE(r); + ASSERT_EQ(res, 10000); + + r = cryptonote::parse_amount(res, "100.0001"); + ASSERT_TRUE(r); + ASSERT_EQ(res, 10000010000); + + r = cryptonote::parse_amount(res, "000.0000"); + ASSERT_TRUE(r); + ASSERT_EQ(res, 0); + + r = cryptonote::parse_amount(res, "0"); + ASSERT_TRUE(r); + ASSERT_EQ(res, 0); + + + r = cryptonote::parse_amount(res, " 100.0001 "); + ASSERT_TRUE(r); + ASSERT_EQ(res, 10000010000); + + r = cryptonote::parse_amount(res, " 100.0000 "); + ASSERT_TRUE(r); + ASSERT_EQ(res, 10000000000); + + r = cryptonote::parse_amount(res, " 100. 0000 "); + ASSERT_FALSE(r); + + r = cryptonote::parse_amount(res, "100. 0000"); + ASSERT_FALSE(r); + + r = cryptonote::parse_amount(res, "100 . 0000"); + ASSERT_FALSE(r); + + r = cryptonote::parse_amount(res, "100.00 00"); + ASSERT_FALSE(r); + + r = cryptonote::parse_amount(res, "1 00.00 00"); + ASSERT_FALSE(r); +} diff --git a/tests/unit_tests/test_peerlist.cpp b/tests/unit_tests/test_peerlist.cpp new file mode 100644 index 000000000..bd58ca753 --- /dev/null +++ b/tests/unit_tests/test_peerlist.cpp @@ -0,0 +1,58 @@ +// Copyright (c) 2012-2013 The Cryptonote developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "gtest/gtest.h" + +#include "common/util.h" +#include "p2p/net_peerlist.h" +#include "net/net_utils_base.h" + +TEST(peer_list, peer_list_general) +{ + nodetool::peerlist_manager plm; + plm.init(false); +#define ADD_GRAY_NODE(ip_, port_, id_, last_seen_) { nodetool::peerlist_entry ple; ple.last_seen=last_seen_;ple.adr.ip = ip_; ple.adr.port = port_; ple.id = id_;plm.append_with_peer_gray(ple);} +#define ADD_WHITE_NODE(ip_, port_, id_, last_seen_) { nodetool::peerlist_entry ple;ple.last_seen=last_seen_; ple.adr.ip = ip_; ple.adr.port = port_; ple.id = id_;plm.append_with_peer_white(ple);} + +#define PRINT_HEAD(step) {std::list<nodetool::peerlist_entry> bs_head; bool r = plm.get_peerlist_head(bs_head, 100);std::cout << "step " << step << ": " << bs_head.size() << std::endl;} + + ADD_GRAY_NODE(MAKE_IP(123,43,12,1), 8080, 121241, 34345); + ADD_GRAY_NODE(MAKE_IP(123,43,12,2), 8080, 121241, 34345); + ADD_GRAY_NODE(MAKE_IP(123,43,12,3), 8080, 121241, 34345); + ADD_GRAY_NODE(MAKE_IP(123,43,12,4), 8080, 121241, 34345); + ADD_GRAY_NODE(MAKE_IP(123,43,12,5), 8080, 121241, 34345); + + ADD_WHITE_NODE(MAKE_IP(123,43,12,1), 8080, 121241, 34345); + ADD_WHITE_NODE(MAKE_IP(123,43,12,2), 8080, 121241, 34345); + ADD_WHITE_NODE(MAKE_IP(123,43,12,3), 8080, 121241, 34345); + ADD_WHITE_NODE(MAKE_IP(123,43,12,4), 8080, 121241, 34345); + + size_t gray_list_size = plm.get_gray_peers_count(); + ASSERT_EQ(gray_list_size, 1); + + std::list<nodetool::peerlist_entry> bs_head; + bool r = plm.get_peerlist_head(bs_head, 100); + std::cout << bs_head.size() << std::endl; + ASSERT_TRUE(r); + + ASSERT_EQ(bs_head.size(), 4); + + + ADD_GRAY_NODE(MAKE_IP(123,43,12,5), 8080, 121241, 34345); + ASSERT_EQ(plm.get_gray_peers_count(), 1); + ASSERT_EQ(plm.get_white_peers_count(), 4); +} + + +TEST(peer_list, merge_peer_lists) +{ + //([^ \t]*)\t([^ \t]*):([^ \t]*) \tlast_seen: d(\d+)\.h(\d+)\.m(\d+)\.s(\d+)\n + //ADD_NODE_TO_PL("\2", \3, 0x\1, (1353346618 -(\4*60*60*24+\5*60*60+\6*60+\7 )));\n + nodetool::peerlist_manager plm; + plm.init(false); + std::list<nodetool::peerlist_entry> outer_bs; +#define ADD_NODE_TO_PL(ip_, port_, id_, timestamp_) { nodetool::peerlist_entry ple; epee::string_tools::get_ip_int32_from_string(ple.adr.ip, ip_); ple.last_seen = timestamp_; ple.adr.port = port_; ple.id = id_;outer_bs.push_back(ple);} + + +} diff --git a/tests/unit_tests/test_protocol_pack.cpp b/tests/unit_tests/test_protocol_pack.cpp new file mode 100644 index 000000000..18c7bc78b --- /dev/null +++ b/tests/unit_tests/test_protocol_pack.cpp @@ -0,0 +1,29 @@ +// Copyright (c) 2012-2013 The Cryptonote developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "gtest/gtest.h" + +#include "include_base_utils.h" +#include "cryptonote_protocol/cryptonote_protocol_defs.h" +#include "storages/portable_storage_template_helper.h" + +TEST(protocol_pack, protocol_pack_command) +{ + std::string buff; + cryptonote::NOTIFY_RESPONSE_CHAIN_ENTRY::request r; + r.start_height = 1; + r.total_height = 3; + for(int i = 1; i < 10000; i += i*10) + { + r.m_block_ids.resize(i, boost::value_initialized<crypto::hash>()); + bool res = epee::serialization::store_t_to_binary(r, buff); + ASSERT_TRUE(res); + + cryptonote::NOTIFY_RESPONSE_CHAIN_ENTRY::request r2; + res = epee::serialization::load_t_from_binary(r2, buff); + ASSERT_TRUE(r.m_block_ids.size() == i); + ASSERT_TRUE(r.start_height == 1); + ASSERT_TRUE(r.total_height == 3); + } +} diff --git a/tests/unit_tests/unit_tests_utils.h b/tests/unit_tests/unit_tests_utils.h new file mode 100644 index 000000000..9eebb7ed9 --- /dev/null +++ b/tests/unit_tests/unit_tests_utils.h @@ -0,0 +1,38 @@ +// Copyright (c) 2012-2013 The Cryptonote developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#pragma once + +#include <atomic> + +namespace unit_test +{ + class call_counter + { + public: + call_counter() + : m_counter(0) + { + } + + void inc() volatile + { + // memory_order_relaxed is enough for call counter + m_counter.fetch_add(1, std::memory_order_relaxed); + } + + size_t get() volatile const + { + return m_counter.load(std::memory_order_relaxed); + } + + void reset() volatile + { + m_counter.store(0, std::memory_order_relaxed); + } + + private: + std::atomic<size_t> m_counter; + }; +} |