aboutsummaryrefslogtreecommitdiff
path: root/tests/unit_tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests/unit_tests')
-rw-r--r--tests/unit_tests/base58.cpp502
-rw-r--r--tests/unit_tests/block_reward.cpp226
-rw-r--r--tests/unit_tests/chacha8.cpp84
-rw-r--r--tests/unit_tests/decompose_amount_into_digits.cpp119
-rw-r--r--tests/unit_tests/epee_boosted_tcp_server.cpp109
-rw-r--r--tests/unit_tests/epee_levin_protocol_handler_async.cpp506
-rw-r--r--tests/unit_tests/main.cpp15
-rw-r--r--tests/unit_tests/mul_div.cpp179
-rw-r--r--tests/unit_tests/serialization.cpp418
-rw-r--r--tests/unit_tests/test_format_utils.cpp97
-rw-r--r--tests/unit_tests/test_peerlist.cpp58
-rw-r--r--tests/unit_tests/test_protocol_pack.cpp29
-rw-r--r--tests/unit_tests/unit_tests_utils.h38
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;
+ };
+}