mirror of
https://github.com/oxen-io/lokinet
synced 2023-12-14 06:53:00 +01:00
Migrate tests from gtest to catch2
This commit is contained in:
parent
4992629f20
commit
ece91e87fc
36 changed files with 1857 additions and 2172 deletions
|
@ -56,7 +56,6 @@ local debian_pipeline(name, image,
|
||||||
'-DWITH_LTO=' + (if lto then 'ON ' else 'OFF ') +
|
'-DWITH_LTO=' + (if lto then 'ON ' else 'OFF ') +
|
||||||
cmake_extra,
|
cmake_extra,
|
||||||
'ninja -v',
|
'ninja -v',
|
||||||
'../contrib/ci/drone-gdb.sh ./test/testAll --gtest_color=yes',
|
|
||||||
'../contrib/ci/drone-gdb.sh ./test/catchAll --use-colour yes',
|
'../contrib/ci/drone-gdb.sh ./test/catchAll --use-colour yes',
|
||||||
] + extra_cmds,
|
] + extra_cmds,
|
||||||
}
|
}
|
||||||
|
@ -200,7 +199,6 @@ local mac_builder(name, build_type='Release', werror=true, cmake_extra='', extra
|
||||||
'cmake .. -G Ninja -DCMAKE_CXX_FLAGS=-fcolor-diagnostics -DCMAKE_BUILD_TYPE='+build_type+' ' +
|
'cmake .. -G Ninja -DCMAKE_CXX_FLAGS=-fcolor-diagnostics -DCMAKE_BUILD_TYPE='+build_type+' ' +
|
||||||
(if werror then '-DWARNINGS_AS_ERRORS=ON ' else '') + cmake_extra,
|
(if werror then '-DWARNINGS_AS_ERRORS=ON ' else '') + cmake_extra,
|
||||||
'ninja -v',
|
'ninja -v',
|
||||||
'./test/testAll --gtest_color=yes',
|
|
||||||
'./test/catchAll --use-colour yes',
|
'./test/catchAll --use-colour yes',
|
||||||
] + extra_cmds,
|
] + extra_cmds,
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,84 +8,71 @@ if (WITH_HIVE)
|
||||||
hive_build)
|
hive_build)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Old gtest-based tests; new tests should use Catch2, instead.
|
|
||||||
add_executable(testAll
|
|
||||||
# helpers
|
|
||||||
main.cpp
|
|
||||||
crypto/mock_crypto.cpp
|
|
||||||
dht/mock_context.cpp
|
|
||||||
test_util.cpp
|
|
||||||
# actual test cases
|
|
||||||
config/test_llarp_config_ini.cpp
|
|
||||||
crypto/test_llarp_crypto_types.cpp
|
|
||||||
crypto/test_llarp_crypto.cpp
|
|
||||||
crypto/test_llarp_key_manager.cpp
|
|
||||||
dht/test_llarp_dht_bucket.cpp
|
|
||||||
dht/test_llarp_dht_explorenetworkjob.cpp
|
|
||||||
dht/test_llarp_dht_kademlia.cpp
|
|
||||||
dht/test_llarp_dht_key.cpp
|
|
||||||
dht/test_llarp_dht_node.cpp
|
|
||||||
dht/test_llarp_dht_tx.cpp
|
|
||||||
dht/test_llarp_dht_txowner.cpp
|
|
||||||
llarp_test.cpp
|
|
||||||
net/test_llarp_net.cpp
|
|
||||||
router/test_llarp_router_version.cpp
|
|
||||||
routing/llarp_routing_transfer_traffic.cpp
|
|
||||||
routing/test_llarp_routing_obtainexitmessage.cpp
|
|
||||||
service/test_llarp_service_address.cpp
|
|
||||||
test_llarp_encrypted_frame.cpp
|
|
||||||
util/meta/test_llarp_util_memfn.cpp
|
|
||||||
util/meta/test_llarp_util_traits.cpp
|
|
||||||
util/test_llarp_util_aligned.cpp
|
|
||||||
util/test_llarp_util_bencode.cpp
|
|
||||||
util/test_llarp_util_log_level.cpp
|
|
||||||
util/thread/test_llarp_util_queue_manager.cpp
|
|
||||||
util/thread/test_llarp_util_queue.cpp
|
|
||||||
)
|
|
||||||
|
|
||||||
target_link_libraries(testAll PUBLIC gmock gtest liblokinet)
|
|
||||||
target_include_directories(testAll PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
|
|
||||||
|
|
||||||
if(WIN32)
|
|
||||||
target_sources(testAll PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/win32/test.rc")
|
|
||||||
target_link_libraries(testAll PUBLIC ws2_32 iphlpapi shlwapi)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD")
|
|
||||||
target_link_directories(testAll PRIVATE /usr/local/lib)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
add_subdirectory(Catch2)
|
add_subdirectory(Catch2)
|
||||||
|
|
||||||
add_executable(catchAll
|
add_executable(catchAll
|
||||||
nodedb/test_nodedb.cpp
|
# helpers
|
||||||
path/test_path.cpp
|
check_main.cpp
|
||||||
dns/test_llarp_dns_dns.cpp
|
test_util.cpp
|
||||||
regress/2020-06-08-key-backup-bug.cpp
|
# actual test cases
|
||||||
util/test_llarp_util_bits.cpp
|
|
||||||
util/test_llarp_util_printer.cpp
|
|
||||||
util/test_llarp_util_str.cpp
|
|
||||||
util/test_llarp_util_decaying_hashset.cpp
|
|
||||||
peerstats/test_peer_db.cpp
|
|
||||||
peerstats/test_peer_types.cpp
|
|
||||||
config/test_llarp_config_definition.cpp
|
config/test_llarp_config_definition.cpp
|
||||||
|
config/test_llarp_config_ini.cpp
|
||||||
config/test_llarp_config_output.cpp
|
config/test_llarp_config_output.cpp
|
||||||
net/test_ip_address.cpp
|
crypto/test_llarp_crypto_types.cpp
|
||||||
net/test_sock_addr.cpp
|
crypto/test_llarp_crypto.cpp
|
||||||
service/test_llarp_service_name.cpp
|
crypto/test_llarp_key_manager.cpp
|
||||||
|
dht/test_llarp_dht_bucket.cpp
|
||||||
|
dht/test_llarp_dht_explorenetworkjob.cpp
|
||||||
|
dht/test_llarp_dht_kademlia.cpp
|
||||||
|
dht/test_llarp_dht_key.cpp
|
||||||
|
dht/test_llarp_dht_node.cpp
|
||||||
|
dht/test_llarp_dht_tx.cpp
|
||||||
|
dht/test_llarp_dht_txowner.cpp
|
||||||
|
dns/test_llarp_dns_dns.cpp
|
||||||
exit/test_llarp_exit_context.cpp
|
exit/test_llarp_exit_context.cpp
|
||||||
iwp/test_iwp_session.cpp
|
iwp/test_iwp_session.cpp
|
||||||
|
net/test_ip_address.cpp
|
||||||
|
net/test_llarp_net.cpp
|
||||||
|
net/test_sock_addr.cpp
|
||||||
|
nodedb/test_nodedb.cpp
|
||||||
|
path/test_path.cpp
|
||||||
|
peerstats/test_peer_db.cpp
|
||||||
|
peerstats/test_peer_types.cpp
|
||||||
|
regress/2020-06-08-key-backup-bug.cpp
|
||||||
|
router/test_llarp_router_version.cpp
|
||||||
|
routing/test_llarp_routing_transfer_traffic.cpp
|
||||||
|
routing/test_llarp_routing_obtainexitmessage.cpp
|
||||||
|
service/test_llarp_service_address.cpp
|
||||||
service/test_llarp_service_identity.cpp
|
service/test_llarp_service_identity.cpp
|
||||||
test_util.cpp
|
service/test_llarp_service_name.cpp
|
||||||
test_llarp_router_contact.cpp
|
util/meta/test_llarp_util_memfn.cpp
|
||||||
check_main.cpp)
|
util/meta/test_llarp_util_traits.cpp
|
||||||
|
util/thread/test_llarp_util_queue_manager.cpp
|
||||||
|
util/thread/test_llarp_util_queue.cpp
|
||||||
|
util/test_llarp_util_aligned.cpp
|
||||||
|
util/test_llarp_util_bencode.cpp
|
||||||
|
util/test_llarp_util_bits.cpp
|
||||||
|
util/test_llarp_util_decaying_hashset.cpp
|
||||||
|
util/test_llarp_util_log_level.cpp
|
||||||
|
util/test_llarp_util_printer.cpp
|
||||||
|
util/test_llarp_util_str.cpp
|
||||||
|
test_llarp_encrypted_frame.cpp
|
||||||
|
test_llarp_router_contact.cpp)
|
||||||
|
|
||||||
target_link_libraries(catchAll PUBLIC liblokinet Catch2::Catch2)
|
target_link_libraries(catchAll PUBLIC gmock liblokinet Catch2::Catch2)
|
||||||
target_include_directories(catchAll PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
|
target_include_directories(catchAll PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
|
||||||
|
|
||||||
|
if(WIN32)
|
||||||
|
target_sources(catchAll PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/win32/test.rc")
|
||||||
|
target_link_libraries(catchAll PUBLIC ws2_32 iphlpapi shlwapi)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD")
|
||||||
|
target_link_directories(catchAll PRIVATE /usr/local/lib)
|
||||||
|
endif()
|
||||||
|
|
||||||
# Custom targets to invoke the different test suites:
|
# Custom targets to invoke the different test suites:
|
||||||
add_custom_target(catch COMMAND catchAll)
|
add_custom_target(catch COMMAND catchAll)
|
||||||
add_custom_target(rungtest COMMAND testAll)
|
|
||||||
|
|
||||||
# Add a custom "check" target that runs all the test suites:
|
# Add a custom "check" target that runs all the test suites:
|
||||||
add_custom_target(check DEPENDS rungtest catch)
|
add_custom_target(check DEPENDS catch)
|
||||||
|
|
|
@ -1,2 +1,42 @@
|
||||||
#define CATCH_CONFIG_MAIN
|
#define CATCH_CONFIG_RUNNER
|
||||||
#include <catch2/catch.hpp>
|
#include <catch2/catch.hpp>
|
||||||
|
|
||||||
|
#include <gmock/gmock.h>
|
||||||
|
|
||||||
|
#include <util/logging/logger.hpp>
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include <winsock2.h>
|
||||||
|
int
|
||||||
|
startWinsock()
|
||||||
|
{
|
||||||
|
WSADATA wsockd;
|
||||||
|
int err;
|
||||||
|
err = ::WSAStartup(MAKEWORD(2, 2), &wsockd);
|
||||||
|
if (err)
|
||||||
|
{
|
||||||
|
perror("Failed to start Windows Sockets");
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char* argv[])
|
||||||
|
{
|
||||||
|
llarp::LogSilencer shutup;
|
||||||
|
|
||||||
|
::testing::InitGoogleMock(&argc, argv);
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
if (startWinsock())
|
||||||
|
return -1;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int result = Catch::Session().run(argc, argv);
|
||||||
|
#ifdef _WIN32
|
||||||
|
WSACleanup();
|
||||||
|
#endif
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
|
@ -1,60 +1,56 @@
|
||||||
#include <gtest/gtest.h>
|
|
||||||
|
|
||||||
#include <config/ini.hpp>
|
#include <config/ini.hpp>
|
||||||
|
|
||||||
struct TestINIParser : public ::testing::Test
|
#include <catch2/catch.hpp>
|
||||||
|
|
||||||
|
TEST_CASE("ConfigParser", "[config]")
|
||||||
{
|
{
|
||||||
llarp::ConfigParser parser;
|
llarp::ConfigParser parser;
|
||||||
|
|
||||||
void
|
SECTION("Parse empty")
|
||||||
TearDown()
|
|
||||||
{
|
{
|
||||||
parser.Clear();
|
REQUIRE(parser.LoadFromStr(""));
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
TEST_F(TestINIParser, TestParseEmpty)
|
SECTION("Parse one section")
|
||||||
{
|
{
|
||||||
ASSERT_TRUE(parser.LoadFromStr(""));
|
llarp::ConfigParser::SectionValues_t sect;
|
||||||
}
|
// this is an anti pattern don't write this kind of code with configpaser
|
||||||
|
auto assertVisit = [§](const auto& section) -> bool {
|
||||||
|
sect = section;
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
REQUIRE(parser.LoadFromStr("[test]\nkey=val \n"));
|
||||||
|
REQUIRE(parser.VisitSection("test", assertVisit));
|
||||||
|
auto itr = sect.find("notfound");
|
||||||
|
REQUIRE(itr == sect.end());
|
||||||
|
itr = sect.find("key");
|
||||||
|
REQUIRE(itr != sect.end());
|
||||||
|
REQUIRE(itr->second == "val");
|
||||||
|
}
|
||||||
|
|
||||||
TEST_F(TestINIParser, TestParseOneSection)
|
SECTION("Parse section duplicate keys")
|
||||||
{
|
{
|
||||||
llarp::ConfigParser::SectionValues_t sect;
|
REQUIRE(parser.LoadFromStr("[test]\nkey1=val1\nkey1=val2"));
|
||||||
// this is an anti pattern don't write this kind of code with configpaser
|
size_t num = 0;
|
||||||
auto assertVisit = [§](const auto& section) -> bool {
|
auto visit = [&num](const auto& section) -> bool {
|
||||||
sect = section;
|
num = section.count("key1");
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
ASSERT_TRUE(parser.LoadFromStr("[test]\nkey=val \n"));
|
REQUIRE(parser.VisitSection("test", visit));
|
||||||
ASSERT_TRUE(parser.VisitSection("test", assertVisit));
|
REQUIRE(num == size_t(2));
|
||||||
auto itr = sect.find("notfound");
|
}
|
||||||
ASSERT_EQ(itr, sect.end());
|
|
||||||
itr = sect.find("key");
|
|
||||||
ASSERT_NE(itr, sect.end());
|
|
||||||
ASSERT_EQ(itr->second, "val");
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(TestINIParser, TestParseSectionDuplicateKeys)
|
SECTION("No key")
|
||||||
{
|
{
|
||||||
ASSERT_TRUE(parser.LoadFromStr("[test]\nkey1=val1\nkey1=val2"));
|
REQUIRE_FALSE(parser.LoadFromStr("[test]\n=1090\n"));
|
||||||
size_t num = 0;
|
}
|
||||||
auto visit = [&num](const auto& section) -> bool {
|
|
||||||
num = section.count("key1");
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
ASSERT_TRUE(parser.VisitSection("test", visit));
|
|
||||||
ASSERT_EQ(num, size_t(2));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(TestINIParser, TestNoKey)
|
SECTION("Parse invalid")
|
||||||
{
|
{
|
||||||
ASSERT_FALSE(parser.LoadFromStr("[test]\n=1090\n"));
|
REQUIRE_FALSE(
|
||||||
}
|
parser.LoadFromStr("srged5ghe5\nf34wtge5\nw34tgfs4ygsd5yg=4;\n#"
|
||||||
|
"g4syhgd5\n"));
|
||||||
|
}
|
||||||
|
|
||||||
TEST_F(TestINIParser, TestParseInvalid)
|
parser.Clear();
|
||||||
{
|
|
||||||
ASSERT_FALSE(
|
|
||||||
parser.LoadFromStr("srged5ghe5\nf34wtge5\nw34tgfs4ygsd5yg=4;\n#"
|
|
||||||
"g4syhgd5\n"));
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
#include <crypto/mock_crypto.hpp>
|
|
|
@ -9,76 +9,67 @@ namespace llarp
|
||||||
{
|
{
|
||||||
namespace test
|
namespace test
|
||||||
{
|
{
|
||||||
struct MockCrypto final : public Crypto
|
struct MockCrypto : public Crypto
|
||||||
{
|
{
|
||||||
MOCK_METHOD3(maybe_decrypt_name,std::optional<AlignedBuffer<32>>(std::string_view, llarp::SymmNonce, std::string_view));
|
MOCK_METHOD3(
|
||||||
|
maybe_decrypt_name,
|
||||||
|
std::optional<AlignedBuffer<32>>(std::string_view, llarp::SymmNonce, std::string_view));
|
||||||
|
|
||||||
|
MOCK_METHOD3(xchacha20, bool(const llarp_buffer_t&, const SharedSecret&, const TunnelNonce&));
|
||||||
|
|
||||||
MOCK_METHOD3(xchacha20,
|
MOCK_METHOD4(
|
||||||
bool(const llarp_buffer_t &, const SharedSecret &,
|
xchacha20_alt,
|
||||||
const TunnelNonce &));
|
bool(const llarp_buffer_t&, const llarp_buffer_t&, const SharedSecret&, const byte_t*));
|
||||||
|
|
||||||
MOCK_METHOD4(xchacha20_alt,
|
MOCK_METHOD4(
|
||||||
bool(const llarp_buffer_t &, const llarp_buffer_t &,
|
dh_client, bool(SharedSecret&, const PubKey&, const SecretKey&, const TunnelNonce&));
|
||||||
const SharedSecret &, const byte_t *));
|
|
||||||
|
|
||||||
MOCK_METHOD4(dh_client,
|
MOCK_METHOD4(
|
||||||
bool(SharedSecret &, const PubKey &, const SecretKey &,
|
dh_server, bool(SharedSecret&, const PubKey&, const SecretKey&, const TunnelNonce&));
|
||||||
const TunnelNonce &));
|
|
||||||
|
|
||||||
MOCK_METHOD4(dh_server,
|
MOCK_METHOD4(
|
||||||
bool(SharedSecret &, const PubKey &, const SecretKey &,
|
transport_dh_client,
|
||||||
const TunnelNonce &));
|
bool(SharedSecret&, const PubKey&, const SecretKey&, const TunnelNonce&));
|
||||||
|
|
||||||
MOCK_METHOD4(transport_dh_client,
|
MOCK_METHOD4(
|
||||||
bool(SharedSecret &, const PubKey &, const SecretKey &,
|
transport_dh_server,
|
||||||
const TunnelNonce &));
|
bool(SharedSecret&, const PubKey&, const SecretKey&, const TunnelNonce&));
|
||||||
|
|
||||||
MOCK_METHOD4(transport_dh_server,
|
MOCK_METHOD2(hash, bool(byte_t*, const llarp_buffer_t&));
|
||||||
bool(SharedSecret &, const PubKey &, const SecretKey &,
|
|
||||||
const TunnelNonce &));
|
|
||||||
|
|
||||||
MOCK_METHOD2(hash, bool(byte_t *, const llarp_buffer_t &));
|
MOCK_METHOD2(shorthash, bool(ShortHash&, const llarp_buffer_t&));
|
||||||
|
|
||||||
MOCK_METHOD2(shorthash, bool(ShortHash &, const llarp_buffer_t &));
|
MOCK_METHOD3(hmac, bool(byte_t*, const llarp_buffer_t&, const SharedSecret&));
|
||||||
|
|
||||||
MOCK_METHOD3(hmac,
|
MOCK_METHOD4(derive_subkey, bool(PubKey&, const PubKey&, uint64_t, const AlignedBuffer<32>*));
|
||||||
bool(byte_t *, const llarp_buffer_t &,
|
|
||||||
const SharedSecret &));
|
|
||||||
|
|
||||||
MOCK_METHOD4(derive_subkey, bool(PubKey &, const PubKey &, uint64_t, const AlignedBuffer<32> *));
|
MOCK_METHOD4(
|
||||||
|
derive_subkey_private,
|
||||||
|
bool(PrivateKey&, const SecretKey&, uint64_t, const AlignedBuffer<32>*));
|
||||||
|
|
||||||
MOCK_METHOD4(derive_subkey_private,
|
MOCK_METHOD(bool, sign, (Signature&, const SecretKey&, const llarp_buffer_t&));
|
||||||
bool(PrivateKey &, const SecretKey &, uint64_t, const AlignedBuffer<32> *));
|
|
||||||
|
|
||||||
MOCK_METHOD(bool, sign, (Signature &, const SecretKey &, const llarp_buffer_t &));
|
MOCK_METHOD(bool, sign, (Signature&, const PrivateKey&, const llarp_buffer_t&));
|
||||||
|
|
||||||
MOCK_METHOD(bool, sign, (Signature &, const PrivateKey &, const llarp_buffer_t &));
|
MOCK_METHOD3(verify, bool(const PubKey&, const llarp_buffer_t&, const Signature&));
|
||||||
|
|
||||||
MOCK_METHOD3(verify,
|
MOCK_METHOD2(seed_to_secretkey, bool(llarp::SecretKey&, const llarp::IdentitySecret&));
|
||||||
bool(const PubKey &, const llarp_buffer_t &,
|
|
||||||
const Signature &));
|
|
||||||
|
|
||||||
MOCK_METHOD2(seed_to_secretkey,
|
MOCK_METHOD1(randomize, void(const llarp_buffer_t&));
|
||||||
bool(llarp::SecretKey &, const llarp::IdentitySecret &));
|
|
||||||
|
|
||||||
MOCK_METHOD1(randomize, void(const llarp_buffer_t &));
|
MOCK_METHOD2(randbytes, void(byte_t*, size_t));
|
||||||
|
|
||||||
MOCK_METHOD2(randbytes, void(byte_t *, size_t));
|
MOCK_METHOD1(identity_keygen, void(SecretKey&));
|
||||||
|
|
||||||
MOCK_METHOD1(identity_keygen, void(SecretKey &));
|
MOCK_METHOD1(encryption_keygen, void(SecretKey&));
|
||||||
|
|
||||||
MOCK_METHOD1(encryption_keygen, void(SecretKey &));
|
MOCK_METHOD1(pqe_keygen, void(PQKeyPair&));
|
||||||
|
|
||||||
MOCK_METHOD1(pqe_keygen, void(PQKeyPair &));
|
MOCK_METHOD3(pqe_decrypt, bool(const PQCipherBlock&, SharedSecret&, const byte_t*));
|
||||||
|
|
||||||
MOCK_METHOD3(pqe_decrypt,
|
MOCK_METHOD3(pqe_encrypt, bool(PQCipherBlock&, SharedSecret&, const PQPubKey&));
|
||||||
bool(const PQCipherBlock &, SharedSecret &, const byte_t *));
|
|
||||||
|
|
||||||
MOCK_METHOD3(pqe_encrypt,
|
MOCK_METHOD1(check_identity_privkey, bool(const SecretKey&));
|
||||||
bool(PQCipherBlock &, SharedSecret &, const PQPubKey &));
|
|
||||||
|
|
||||||
MOCK_METHOD1(check_identity_privkey, bool(const SecretKey &));
|
|
||||||
};
|
};
|
||||||
} // namespace test
|
} // namespace test
|
||||||
} // namespace llarp
|
} // namespace llarp
|
||||||
|
|
|
@ -2,69 +2,48 @@
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
#include <gtest/gtest.h>
|
#include <catch2/catch.hpp>
|
||||||
|
|
||||||
namespace llarp
|
using namespace llarp;
|
||||||
|
|
||||||
|
TEST_CASE("Identity key")
|
||||||
{
|
{
|
||||||
struct IdentityKeyTest : public ::testing::Test
|
llarp::sodium::CryptoLibSodium crypto;
|
||||||
{
|
SecretKey secret;
|
||||||
llarp::sodium::CryptoLibSodium crypto;
|
crypto.identity_keygen(secret);
|
||||||
|
|
||||||
IdentityKeyTest()
|
SECTION("Keygen")
|
||||||
{
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
TEST_F(IdentityKeyTest, TestKeyGen)
|
|
||||||
{
|
{
|
||||||
SecretKey secret;
|
REQUIRE_FALSE(secret.IsZero());
|
||||||
crypto.identity_keygen(secret);
|
|
||||||
ASSERT_FALSE(secret.IsZero());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(IdentityKeyTest, TestSignVerify)
|
SECTION("Sign-verify")
|
||||||
{
|
{
|
||||||
SecretKey secret;
|
AlignedBuffer<128> random;
|
||||||
crypto.identity_keygen(secret);
|
|
||||||
AlignedBuffer< 128 > random;
|
|
||||||
random.Randomize();
|
random.Randomize();
|
||||||
Signature sig;
|
Signature sig;
|
||||||
const PubKey pk = secret.toPublic();
|
const PubKey pk = secret.toPublic();
|
||||||
|
|
||||||
const llarp_buffer_t buf(random.data(), random.size());
|
const llarp_buffer_t buf(random.data(), random.size());
|
||||||
ASSERT_TRUE(crypto.sign(sig, secret, buf));
|
REQUIRE(crypto.sign(sig, secret, buf));
|
||||||
ASSERT_TRUE(crypto.verify(pk, buf, sig));
|
REQUIRE(crypto.verify(pk, buf, sig));
|
||||||
random.Randomize();
|
random.Randomize();
|
||||||
// mangle body
|
// mangle body
|
||||||
ASSERT_FALSE(crypto.verify(pk, buf, sig));
|
REQUIRE_FALSE(crypto.verify(pk, buf, sig));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
struct PQCryptoTest : public ::testing::Test
|
TEST_CASE("PQ crypto")
|
||||||
{
|
{
|
||||||
llarp::sodium::CryptoLibSodium crypto;
|
llarp::sodium::CryptoLibSodium crypto;
|
||||||
PQKeyPair keys;
|
PQKeyPair keys;
|
||||||
|
crypto.pqe_keygen(keys);
|
||||||
|
PQCipherBlock block;
|
||||||
|
SharedSecret shared, otherShared;
|
||||||
|
auto c = &crypto;
|
||||||
|
|
||||||
PQCryptoTest()
|
REQUIRE(keys.size() == PQ_KEYPAIRSIZE);
|
||||||
{
|
REQUIRE(c->pqe_encrypt(block, shared, PQPubKey(pq_keypair_to_public(keys))));
|
||||||
}
|
REQUIRE(c->pqe_decrypt(block, otherShared, pq_keypair_to_secret(keys)));
|
||||||
|
REQUIRE(otherShared == shared);
|
||||||
void
|
}
|
||||||
SetUp()
|
|
||||||
{
|
|
||||||
crypto.pqe_keygen(keys);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
TEST_F(PQCryptoTest, TestCrypto)
|
|
||||||
{
|
|
||||||
PQCipherBlock block;
|
|
||||||
SharedSecret shared, otherShared;
|
|
||||||
auto c = &crypto;
|
|
||||||
|
|
||||||
ASSERT_TRUE(keys.size() == PQ_KEYPAIRSIZE);
|
|
||||||
ASSERT_TRUE(
|
|
||||||
c->pqe_encrypt(block, shared, PQPubKey(pq_keypair_to_public(keys))));
|
|
||||||
ASSERT_TRUE(c->pqe_decrypt(block, otherShared, pq_keypair_to_secret(keys)));
|
|
||||||
ASSERT_TRUE(otherShared == shared);
|
|
||||||
}
|
|
||||||
} // namespace llarp
|
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include <test_util.hpp>
|
#include <test_util.hpp>
|
||||||
#include <gtest/gtest.h>
|
#include <catch2/catch.hpp>
|
||||||
|
|
||||||
// This used to be implied via the headers above *shrug*
|
// This used to be implied via the headers above *shrug*
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
|
@ -17,43 +17,37 @@ struct ToStringData
|
||||||
std::string output;
|
std::string output;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct PubKeyString : public ::testing::TestWithParam< ToStringData >
|
|
||||||
{
|
|
||||||
};
|
|
||||||
|
|
||||||
TEST_P(PubKeyString, tostring)
|
|
||||||
{
|
|
||||||
auto d = GetParam();
|
|
||||||
llarp::PubKey key(d.input);
|
|
||||||
|
|
||||||
ASSERT_EQ(key.ToString(), d.output);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_P(PubKeyString, fromstring)
|
|
||||||
{
|
|
||||||
auto d = GetParam();
|
|
||||||
|
|
||||||
llarp::PubKey key;
|
|
||||||
|
|
||||||
ASSERT_TRUE(key.FromString(d.output));
|
|
||||||
ASSERT_EQ(key, llarp::PubKey(d.input));
|
|
||||||
}
|
|
||||||
|
|
||||||
llarp::PubKey::Data empty = {};
|
llarp::PubKey::Data empty = {};
|
||||||
llarp::PubKey::Data full = {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
llarp::PubKey::Data full = {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}};
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}};
|
|
||||||
|
|
||||||
// clang-format off
|
// clang-format off
|
||||||
ToStringData toStringData[] = {
|
std::vector<ToStringData> toStringData{
|
||||||
{empty, "0000000000000000000000000000000000000000000000000000000000000000"},
|
{empty, "0000000000000000000000000000000000000000000000000000000000000000"},
|
||||||
{full, "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"},
|
{full, "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"},
|
||||||
};
|
};
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
INSTANTIATE_TEST_SUITE_P(TestCryptoTypes, PubKeyString,
|
TEST_CASE("PubKey-string conversion")
|
||||||
::testing::ValuesIn(toStringData));
|
{
|
||||||
|
auto d = GENERATE(from_range(toStringData));
|
||||||
|
|
||||||
|
SECTION("To string")
|
||||||
|
{
|
||||||
|
llarp::PubKey key(d.input);
|
||||||
|
|
||||||
|
REQUIRE(key.ToString() == d.output);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("From string")
|
||||||
|
{
|
||||||
|
llarp::PubKey key;
|
||||||
|
|
||||||
|
REQUIRE(key.FromString(d.output));
|
||||||
|
REQUIRE(key == llarp::PubKey(d.input));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Concerns
|
// Concerns
|
||||||
// - file missing
|
// - file missing
|
||||||
|
@ -63,32 +57,31 @@ INSTANTIATE_TEST_SUITE_P(TestCryptoTypes, PubKeyString,
|
||||||
// - raw buffer
|
// - raw buffer
|
||||||
// - bencoded
|
// - bencoded
|
||||||
|
|
||||||
struct TestCryptoTypesSecret : public ::testing::Test
|
struct TestCryptoTypesSecret
|
||||||
{
|
{
|
||||||
std::string filename;
|
std::string filename;
|
||||||
fs::path p;
|
fs::path p;
|
||||||
|
|
||||||
TestCryptoTypesSecret() : filename(llarp::test::randFilename()), p(filename)
|
TestCryptoTypesSecret() : filename(llarp::test::randFilename()), p(filename)
|
||||||
{
|
{}
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
TEST_F(TestCryptoTypesSecret, secret_key_from_file_missing)
|
TEST_CASE_METHOD(TestCryptoTypesSecret, "secret_key_from_file_missing")
|
||||||
{
|
{
|
||||||
// Verify loading an empty file fails cleanly.
|
// Verify loading an empty file fails cleanly.
|
||||||
ASSERT_FALSE(fs::exists(fs::status(p)));
|
REQUIRE_FALSE(fs::exists(fs::status(p)));
|
||||||
|
|
||||||
llarp::SecretKey key;
|
llarp::SecretKey key;
|
||||||
ASSERT_FALSE(key.LoadFromFile(filename.c_str()));
|
REQUIRE_FALSE(key.LoadFromFile(filename.c_str()));
|
||||||
|
|
||||||
// Verify we didn't create a file
|
// Verify we didn't create a file
|
||||||
ASSERT_FALSE(fs::exists(fs::status(p)));
|
REQUIRE_FALSE(fs::exists(fs::status(p)));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(TestCryptoTypesSecret, secret_key_from_file_empty)
|
TEST_CASE_METHOD(TestCryptoTypesSecret, "secret_key_from_file_empty")
|
||||||
{
|
{
|
||||||
// Verify loading an empty file fails cleanly.
|
// Verify loading an empty file fails cleanly.
|
||||||
ASSERT_FALSE(fs::exists(fs::status(p)));
|
REQUIRE_FALSE(fs::exists(fs::status(p)));
|
||||||
|
|
||||||
// Create empty file
|
// Create empty file
|
||||||
std::fstream f;
|
std::fstream f;
|
||||||
|
@ -98,156 +91,154 @@ TEST_F(TestCryptoTypesSecret, secret_key_from_file_empty)
|
||||||
llarp::test::FileGuard guard(p);
|
llarp::test::FileGuard guard(p);
|
||||||
|
|
||||||
llarp::SecretKey key;
|
llarp::SecretKey key;
|
||||||
ASSERT_FALSE(key.LoadFromFile(filename.c_str()));
|
REQUIRE_FALSE(key.LoadFromFile(filename.c_str()));
|
||||||
|
|
||||||
// Verify we didn't delete the file
|
// Verify we didn't delete the file
|
||||||
ASSERT_TRUE(fs::exists(fs::status(fs::path(filename))));
|
REQUIRE(fs::exists(fs::status(fs::path(filename))));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(TestCryptoTypesSecret, secret_key_from_file_smaller)
|
TEST_CASE_METHOD(TestCryptoTypesSecret, "secret_key_from_file_smaller")
|
||||||
{
|
{
|
||||||
// Verify loading a file which is too small fails cleanly.
|
// Verify loading a file which is too small fails cleanly.
|
||||||
ASSERT_FALSE(fs::exists(fs::status(p)));
|
REQUIRE_FALSE(fs::exists(fs::status(p)));
|
||||||
|
|
||||||
// Create empty file
|
// Create empty file
|
||||||
std::fstream f;
|
std::fstream f;
|
||||||
f.open(filename, std::ios::out | std::ios::binary);
|
f.open(filename, std::ios::out | std::ios::binary);
|
||||||
std::fill_n(std::ostream_iterator< byte_t >(f), llarp::SecretKey::SIZE / 2,
|
std::fill_n(std::ostream_iterator<byte_t>(f), llarp::SecretKey::SIZE / 2, 0xAA);
|
||||||
0xAA);
|
|
||||||
f.close();
|
f.close();
|
||||||
|
|
||||||
llarp::test::FileGuard guard(p);
|
llarp::test::FileGuard guard(p);
|
||||||
|
|
||||||
llarp::SecretKey key;
|
llarp::SecretKey key;
|
||||||
ASSERT_FALSE(key.LoadFromFile(filename.c_str()));
|
REQUIRE_FALSE(key.LoadFromFile(filename.c_str()));
|
||||||
|
|
||||||
// Verify we didn't delete the file
|
// Verify we didn't delete the file
|
||||||
ASSERT_TRUE(fs::exists(fs::status(fs::path(filename))));
|
REQUIRE(fs::exists(fs::status(fs::path(filename))));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(TestCryptoTypesSecret, secret_key_from_file_smaller_bencode)
|
TEST_CASE_METHOD(TestCryptoTypesSecret, "secret_key_from_file_smaller_bencode")
|
||||||
{
|
{
|
||||||
// Verify loading a file which is too small fails cleanly.
|
// Verify loading a file which is too small fails cleanly.
|
||||||
ASSERT_FALSE(fs::exists(fs::status(p)));
|
REQUIRE_FALSE(fs::exists(fs::status(p)));
|
||||||
|
|
||||||
// Create empty file
|
// Create empty file
|
||||||
std::fstream f;
|
std::fstream f;
|
||||||
f.open(filename, std::ios::out | std::ios::binary);
|
f.open(filename, std::ios::out | std::ios::binary);
|
||||||
f.write("32:", 3);
|
f.write("32:", 3);
|
||||||
std::fill_n(std::ostream_iterator< byte_t >(f), 32, 0xAA);
|
std::fill_n(std::ostream_iterator<byte_t>(f), 32, 0xAA);
|
||||||
f.close();
|
f.close();
|
||||||
|
|
||||||
llarp::test::FileGuard guard(p);
|
llarp::test::FileGuard guard(p);
|
||||||
|
|
||||||
llarp::SecretKey key;
|
llarp::SecretKey key;
|
||||||
ASSERT_FALSE(key.LoadFromFile(filename.c_str()));
|
REQUIRE_FALSE(key.LoadFromFile(filename.c_str()));
|
||||||
|
|
||||||
// Verify we didn't delete the file
|
// Verify we didn't delete the file
|
||||||
ASSERT_TRUE(fs::exists(fs::status(fs::path(filename))));
|
REQUIRE(fs::exists(fs::status(fs::path(filename))));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(TestCryptoTypesSecret, secret_key_from_file_smaller_corrupt_bencode)
|
TEST_CASE_METHOD(TestCryptoTypesSecret, "secret_key_from_file_smaller_corrupt_bencode")
|
||||||
{
|
{
|
||||||
// Verify loading a file which is too small + corrupt fails cleanly.
|
// Verify loading a file which is too small + corrupt fails cleanly.
|
||||||
ASSERT_FALSE(fs::exists(fs::status(p)));
|
REQUIRE_FALSE(fs::exists(fs::status(p)));
|
||||||
|
|
||||||
// Create empty file
|
// Create empty file
|
||||||
std::fstream f;
|
std::fstream f;
|
||||||
f.open(filename, std::ios::out | std::ios::binary);
|
f.open(filename, std::ios::out | std::ios::binary);
|
||||||
f.write("256:", 4);
|
f.write("256:", 4);
|
||||||
std::fill_n(std::ostream_iterator< byte_t >(f), 32, 0xAA);
|
std::fill_n(std::ostream_iterator<byte_t>(f), 32, 0xAA);
|
||||||
f.close();
|
f.close();
|
||||||
|
|
||||||
llarp::test::FileGuard guard(p);
|
llarp::test::FileGuard guard(p);
|
||||||
|
|
||||||
llarp::SecretKey key;
|
llarp::SecretKey key;
|
||||||
ASSERT_FALSE(key.LoadFromFile(filename.c_str()));
|
REQUIRE_FALSE(key.LoadFromFile(filename.c_str()));
|
||||||
|
|
||||||
// Verify we didn't delete the file
|
// Verify we didn't delete the file
|
||||||
ASSERT_TRUE(fs::exists(fs::status(fs::path(filename))));
|
REQUIRE(fs::exists(fs::status(fs::path(filename))));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(TestCryptoTypesSecret, secret_key_from_file_larger)
|
TEST_CASE_METHOD(TestCryptoTypesSecret, "secret_key_from_file_larger")
|
||||||
{
|
{
|
||||||
// Verify loading a file which is too large fails cleanly.
|
// Verify loading a file which is too large fails cleanly.
|
||||||
ASSERT_FALSE(fs::exists(fs::status(p)));
|
REQUIRE_FALSE(fs::exists(fs::status(p)));
|
||||||
|
|
||||||
// Create empty file
|
// Create empty file
|
||||||
std::fstream f;
|
std::fstream f;
|
||||||
f.open(filename, std::ios::out | std::ios::binary);
|
f.open(filename, std::ios::out | std::ios::binary);
|
||||||
std::fill_n(std::ostream_iterator< byte_t >(f), llarp::SecretKey::SIZE * 2,
|
std::fill_n(std::ostream_iterator<byte_t>(f), llarp::SecretKey::SIZE * 2, 0xAA);
|
||||||
0xAA);
|
|
||||||
f.close();
|
f.close();
|
||||||
|
|
||||||
llarp::test::FileGuard guard(p);
|
llarp::test::FileGuard guard(p);
|
||||||
|
|
||||||
llarp::SecretKey key;
|
llarp::SecretKey key;
|
||||||
ASSERT_FALSE(key.LoadFromFile(filename.c_str()));
|
REQUIRE_FALSE(key.LoadFromFile(filename.c_str()));
|
||||||
|
|
||||||
// Verify we didn't delete the file
|
// Verify we didn't delete the file
|
||||||
ASSERT_TRUE(fs::exists(fs::status(fs::path(filename))));
|
REQUIRE(fs::exists(fs::status(fs::path(filename))));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(TestCryptoTypesSecret, secret_key_from_file_larger_bencode)
|
TEST_CASE_METHOD(TestCryptoTypesSecret, "secret_key_from_file_larger_bencode")
|
||||||
{
|
{
|
||||||
// Verify loading a file which is too large fails cleanly.
|
// Verify loading a file which is too large fails cleanly.
|
||||||
ASSERT_FALSE(fs::exists(fs::status(p)));
|
REQUIRE_FALSE(fs::exists(fs::status(p)));
|
||||||
|
|
||||||
// Create empty file
|
// Create empty file
|
||||||
std::fstream f;
|
std::fstream f;
|
||||||
f.open(filename, std::ios::out | std::ios::binary);
|
f.open(filename, std::ios::out | std::ios::binary);
|
||||||
f.write("256:", 4);
|
f.write("256:", 4);
|
||||||
std::fill_n(std::ostream_iterator< byte_t >(f), 256, 0xAA);
|
std::fill_n(std::ostream_iterator<byte_t>(f), 256, 0xAA);
|
||||||
f.close();
|
f.close();
|
||||||
|
|
||||||
llarp::test::FileGuard guard(p);
|
llarp::test::FileGuard guard(p);
|
||||||
|
|
||||||
llarp::SecretKey key;
|
llarp::SecretKey key;
|
||||||
ASSERT_FALSE(key.LoadFromFile(filename.c_str()));
|
REQUIRE_FALSE(key.LoadFromFile(filename.c_str()));
|
||||||
|
|
||||||
// Verify we didn't delete the file
|
// Verify we didn't delete the file
|
||||||
ASSERT_TRUE(fs::exists(fs::status(fs::path(filename))));
|
REQUIRE(fs::exists(fs::status(fs::path(filename))));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(TestCryptoTypesSecret, secret_key_from_file_happy_raw)
|
TEST_CASE_METHOD(TestCryptoTypesSecret, "secret_key_from_file_happy_raw")
|
||||||
{
|
{
|
||||||
// Verify loading a valid raw file succeeds.
|
// Verify loading a valid raw file succeeds.
|
||||||
ASSERT_FALSE(fs::exists(fs::status(p)));
|
REQUIRE_FALSE(fs::exists(fs::status(p)));
|
||||||
|
|
||||||
// Create empty file
|
// Create empty file
|
||||||
std::fstream f;
|
std::fstream f;
|
||||||
f.open(filename, std::ios::out | std::ios::binary);
|
f.open(filename, std::ios::out | std::ios::binary);
|
||||||
std::fill_n(std::ostream_iterator< byte_t >(f), llarp::SecretKey::SIZE, 0xAA);
|
std::fill_n(std::ostream_iterator<byte_t>(f), llarp::SecretKey::SIZE, 0xAA);
|
||||||
f.close();
|
f.close();
|
||||||
|
|
||||||
llarp::test::FileGuard guard(p);
|
llarp::test::FileGuard guard(p);
|
||||||
|
|
||||||
llarp::SecretKey key;
|
llarp::SecretKey key;
|
||||||
ASSERT_TRUE(key.LoadFromFile(filename.c_str()));
|
REQUIRE(key.LoadFromFile(filename.c_str()));
|
||||||
|
|
||||||
// Verify we didn't delete the file
|
// Verify we didn't delete the file
|
||||||
ASSERT_TRUE(fs::exists(fs::status(fs::path(filename))));
|
REQUIRE(fs::exists(fs::status(fs::path(filename))));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(TestCryptoTypesSecret, secret_key_from_file_happy_bencode)
|
TEST_CASE_METHOD(TestCryptoTypesSecret, "secret_key_from_file_happy_bencode")
|
||||||
{
|
{
|
||||||
// Verify loading a valid bencoded file succeeds.
|
// Verify loading a valid bencoded file succeeds.
|
||||||
ASSERT_FALSE(fs::exists(fs::status(p)));
|
REQUIRE_FALSE(fs::exists(fs::status(p)));
|
||||||
|
|
||||||
// Create empty file
|
// Create empty file
|
||||||
std::fstream f;
|
std::fstream f;
|
||||||
f.open(filename, std::ios::out | std::ios::binary);
|
f.open(filename, std::ios::out | std::ios::binary);
|
||||||
f.write("64:", 4);
|
f.write("64:", 4);
|
||||||
std::fill_n(std::ostream_iterator< byte_t >(f), llarp::SecretKey::SIZE, 0xAA);
|
std::fill_n(std::ostream_iterator<byte_t>(f), llarp::SecretKey::SIZE, 0xAA);
|
||||||
f.close();
|
f.close();
|
||||||
|
|
||||||
llarp::test::FileGuard guard(p);
|
llarp::test::FileGuard guard(p);
|
||||||
|
|
||||||
llarp::SecretKey key;
|
llarp::SecretKey key;
|
||||||
ASSERT_TRUE(key.LoadFromFile(filename.c_str()));
|
REQUIRE(key.LoadFromFile(filename.c_str()));
|
||||||
|
|
||||||
// Verify we didn't delete the file
|
// Verify we didn't delete the file
|
||||||
ASSERT_TRUE(fs::exists(fs::status(fs::path(filename))));
|
REQUIRE(fs::exists(fs::status(fs::path(filename))));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Save to file
|
// Save to file
|
||||||
|
@ -261,15 +252,24 @@ TEST_F(TestCryptoTypesSecret, secret_key_from_file_happy_bencode)
|
||||||
BOOL
|
BOOL
|
||||||
IsRunAsAdmin()
|
IsRunAsAdmin()
|
||||||
{
|
{
|
||||||
BOOL fIsRunAsAdmin = FALSE;
|
BOOL fIsRunAsAdmin = FALSE;
|
||||||
DWORD dwError = ERROR_SUCCESS;
|
DWORD dwError = ERROR_SUCCESS;
|
||||||
PSID pAdministratorsGroup = NULL;
|
PSID pAdministratorsGroup = NULL;
|
||||||
|
|
||||||
// Allocate and initialize a SID of the administrators group.
|
// Allocate and initialize a SID of the administrators group.
|
||||||
SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
|
SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
|
||||||
if(!AllocateAndInitializeSid(&NtAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID,
|
if (!AllocateAndInitializeSid(
|
||||||
DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0,
|
&NtAuthority,
|
||||||
&pAdministratorsGroup))
|
2,
|
||||||
|
SECURITY_BUILTIN_DOMAIN_RID,
|
||||||
|
DOMAIN_ALIAS_RID_ADMINS,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
&pAdministratorsGroup))
|
||||||
{
|
{
|
||||||
dwError = GetLastError();
|
dwError = GetLastError();
|
||||||
goto Cleanup;
|
goto Cleanup;
|
||||||
|
@ -277,7 +277,7 @@ IsRunAsAdmin()
|
||||||
|
|
||||||
// Determine whether the SID of administrators group is enabled in
|
// Determine whether the SID of administrators group is enabled in
|
||||||
// the primary access token of the process.
|
// the primary access token of the process.
|
||||||
if(!CheckTokenMembership(NULL, pAdministratorsGroup, &fIsRunAsAdmin))
|
if (!CheckTokenMembership(NULL, pAdministratorsGroup, &fIsRunAsAdmin))
|
||||||
{
|
{
|
||||||
dwError = GetLastError();
|
dwError = GetLastError();
|
||||||
goto Cleanup;
|
goto Cleanup;
|
||||||
|
@ -285,14 +285,14 @@ IsRunAsAdmin()
|
||||||
|
|
||||||
Cleanup:
|
Cleanup:
|
||||||
// Centralized cleanup for all allocated resources.
|
// Centralized cleanup for all allocated resources.
|
||||||
if(pAdministratorsGroup)
|
if (pAdministratorsGroup)
|
||||||
{
|
{
|
||||||
FreeSid(pAdministratorsGroup);
|
FreeSid(pAdministratorsGroup);
|
||||||
pAdministratorsGroup = NULL;
|
pAdministratorsGroup = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Throw the error if something failed in the function.
|
// Throw the error if something failed in the function.
|
||||||
if(ERROR_SUCCESS != dwError)
|
if (ERROR_SUCCESS != dwError)
|
||||||
{
|
{
|
||||||
throw dwError;
|
throw dwError;
|
||||||
}
|
}
|
||||||
|
@ -301,46 +301,46 @@ Cleanup:
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
TEST_F(TestCryptoTypesSecret, secret_key_to_missing_file)
|
TEST_CASE_METHOD(TestCryptoTypesSecret, "secret_key_to_missing_file")
|
||||||
{
|
{
|
||||||
// Verify writing to an unwritable file fails.
|
// Verify writing to an unwritable file fails.
|
||||||
// Assume we're not running as root, so can't write to [C:]/
|
// Assume we're not running as root, so can't write to [C:]/
|
||||||
// if we are root just skip this test
|
// if we are root just skip this test
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
if(getuid() == 0)
|
if (getuid() == 0)
|
||||||
return;
|
return;
|
||||||
#else
|
#else
|
||||||
if(IsRunAsAdmin())
|
if (IsRunAsAdmin())
|
||||||
return;
|
return;
|
||||||
#endif
|
#endif
|
||||||
filename = "/" + filename;
|
filename = "/" + filename;
|
||||||
p = filename;
|
p = filename;
|
||||||
ASSERT_FALSE(fs::exists(fs::status(p)));
|
REQUIRE_FALSE(fs::exists(fs::status(p)));
|
||||||
|
|
||||||
llarp::test::FileGuard guard(p);
|
llarp::test::FileGuard guard(p);
|
||||||
|
|
||||||
llarp::SecretKey key;
|
llarp::SecretKey key;
|
||||||
ASSERT_FALSE(key.SaveToFile(filename.c_str()));
|
REQUIRE_FALSE(key.SaveToFile(filename.c_str()));
|
||||||
|
|
||||||
// Verify we didn't create the file
|
// Verify we didn't create the file
|
||||||
ASSERT_FALSE(fs::exists(fs::status(fs::path(filename))));
|
REQUIRE_FALSE(fs::exists(fs::status(fs::path(filename))));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(TestCryptoTypesSecret, secret_key_to_file)
|
TEST_CASE_METHOD(TestCryptoTypesSecret, "secret_key_to_file")
|
||||||
{
|
{
|
||||||
ASSERT_FALSE(fs::exists(fs::status(p)));
|
REQUIRE_FALSE(fs::exists(fs::status(p)));
|
||||||
|
|
||||||
llarp::test::FileGuard guard(p);
|
llarp::test::FileGuard guard(p);
|
||||||
|
|
||||||
llarp::SecretKey key;
|
llarp::SecretKey key;
|
||||||
key.Randomize();
|
key.Randomize();
|
||||||
ASSERT_TRUE(key.SaveToFile(filename.c_str()));
|
REQUIRE(key.SaveToFile(filename.c_str()));
|
||||||
|
|
||||||
// Verify we created the file
|
// Verify we created the file
|
||||||
ASSERT_TRUE(fs::exists(fs::status(fs::path(filename))));
|
REQUIRE(fs::exists(fs::status(fs::path(filename))));
|
||||||
|
|
||||||
llarp::SecretKey other;
|
llarp::SecretKey other;
|
||||||
other.LoadFromFile(filename.c_str());
|
other.LoadFromFile(filename.c_str());
|
||||||
|
|
||||||
ASSERT_EQ(other, key);
|
REQUIRE(other == key);
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,12 +9,12 @@
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <test_util.hpp>
|
#include <test_util.hpp>
|
||||||
#include <gtest/gtest.h>
|
#include <catch2/catch.hpp>
|
||||||
|
|
||||||
using namespace ::llarp;
|
using namespace ::llarp;
|
||||||
using namespace ::testing;
|
using namespace ::testing;
|
||||||
|
|
||||||
struct KeyManagerTest : public test::LlarpTest< llarp::sodium::CryptoLibSodium >
|
struct KeyManagerTest : public test::LlarpTest<llarp::sodium::CryptoLibSodium>
|
||||||
{
|
{
|
||||||
// paranoid file guards for anything KeyManager might touch
|
// paranoid file guards for anything KeyManager might touch
|
||||||
test::FileGuard m_rcFileGuard;
|
test::FileGuard m_rcFileGuard;
|
||||||
|
@ -27,8 +27,7 @@ struct KeyManagerTest : public test::LlarpTest< llarp::sodium::CryptoLibSodium >
|
||||||
, m_encFileGuard(our_enc_key_filename)
|
, m_encFileGuard(our_enc_key_filename)
|
||||||
, m_transportFileGuard(our_transport_key_filename)
|
, m_transportFileGuard(our_transport_key_filename)
|
||||||
, m_identFileGuard(our_identity_filename)
|
, m_identFileGuard(our_identity_filename)
|
||||||
{
|
{}
|
||||||
}
|
|
||||||
|
|
||||||
/// generate a valid "rc.signed" file
|
/// generate a valid "rc.signed" file
|
||||||
bool
|
bool
|
||||||
|
@ -39,10 +38,10 @@ struct KeyManagerTest : public test::LlarpTest< llarp::sodium::CryptoLibSodium >
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
TEST_F(KeyManagerTest, TestBackupFileByMoving_MovesExistingFiles)
|
TEST_CASE_METHOD(KeyManagerTest, "Backup file by moving moves existing files")
|
||||||
{
|
{
|
||||||
fs::path p = test::randFilename();
|
fs::path p = test::randFilename();
|
||||||
ASSERT_FALSE(fs::exists(p));
|
REQUIRE_FALSE(fs::exists(p));
|
||||||
|
|
||||||
// touch file
|
// touch file
|
||||||
std::fstream f;
|
std::fstream f;
|
||||||
|
@ -51,33 +50,33 @@ TEST_F(KeyManagerTest, TestBackupFileByMoving_MovesExistingFiles)
|
||||||
|
|
||||||
KeyManager::backupFileByMoving(p.string());
|
KeyManager::backupFileByMoving(p.string());
|
||||||
|
|
||||||
ASSERT_FALSE(fs::exists(p));
|
REQUIRE_FALSE(fs::exists(p));
|
||||||
|
|
||||||
fs::path moved = p.string() + ".0.bak";
|
fs::path moved = p.string() + ".0.bak";
|
||||||
|
|
||||||
ASSERT_TRUE(fs::exists(moved));
|
REQUIRE(fs::exists(moved));
|
||||||
|
|
||||||
test::FileGuard guard(moved);
|
test::FileGuard guard(moved);
|
||||||
};
|
};
|
||||||
|
|
||||||
TEST_F(KeyManagerTest, TestBackupFileByMoving_DoesntTouchNonExistentFiles)
|
TEST_CASE_METHOD(KeyManagerTest, "Backup file by moving doesnt touch non existent files")
|
||||||
{
|
{
|
||||||
fs::path p = test::randFilename();
|
fs::path p = test::randFilename();
|
||||||
ASSERT_FALSE(fs::exists(p));
|
REQUIRE_FALSE(fs::exists(p));
|
||||||
|
|
||||||
KeyManager::backupFileByMoving(p.string());
|
KeyManager::backupFileByMoving(p.string());
|
||||||
|
|
||||||
ASSERT_FALSE(fs::exists(p));
|
REQUIRE_FALSE(fs::exists(p));
|
||||||
|
|
||||||
fs::path moved = p.string() + ".0.bak";
|
fs::path moved = p.string() + ".0.bak";
|
||||||
|
|
||||||
ASSERT_FALSE(fs::exists(moved));
|
REQUIRE_FALSE(fs::exists(moved));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(KeyManagerTest, TestBackupFileByMoving_FailsIfBackupNamesAreExausted)
|
TEST_CASE_METHOD(KeyManagerTest, "Backup file by moving fails if backup names are exausted")
|
||||||
{
|
{
|
||||||
fs::path base = test::randFilename();
|
fs::path base = test::randFilename();
|
||||||
ASSERT_FALSE(fs::exists(base));
|
REQUIRE_FALSE(fs::exists(base));
|
||||||
|
|
||||||
// touch file
|
// touch file
|
||||||
{
|
{
|
||||||
|
@ -93,9 +92,9 @@ TEST_F(KeyManagerTest, TestBackupFileByMoving_FailsIfBackupNamesAreExausted)
|
||||||
guards.reserve(numBackupNames);
|
guards.reserve(numBackupNames);
|
||||||
|
|
||||||
// generate backup files foo.0.bak through foo.9.bak
|
// generate backup files foo.0.bak through foo.9.bak
|
||||||
for (uint32_t i=0; i<numBackupNames; ++i)
|
for (uint32_t i = 0; i < numBackupNames; ++i)
|
||||||
{
|
{
|
||||||
fs::path p = base.string() +"."+ std::to_string(i) +".bak";
|
fs::path p = base.string() + "." + std::to_string(i) + ".bak";
|
||||||
|
|
||||||
std::fstream f;
|
std::fstream f;
|
||||||
f.open(p.string(), std::ios::out);
|
f.open(p.string(), std::ios::out);
|
||||||
|
@ -103,45 +102,44 @@ TEST_F(KeyManagerTest, TestBackupFileByMoving_FailsIfBackupNamesAreExausted)
|
||||||
|
|
||||||
guards.emplace_back(p);
|
guards.emplace_back(p);
|
||||||
|
|
||||||
ASSERT_TRUE(fs::exists(p));
|
REQUIRE(fs::exists(p));
|
||||||
}
|
}
|
||||||
|
|
||||||
ASSERT_FALSE(KeyManager::backupFileByMoving(base.string()));
|
REQUIRE_FALSE(KeyManager::backupFileByMoving(base.string()));
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
TEST_F(KeyManagerTest, TestInitialize_MakesKeyfiles)
|
TEST_CASE_METHOD(KeyManagerTest, "Initialize makes keyfiles")
|
||||||
{
|
{
|
||||||
llarp::Config conf{fs::current_path()};
|
llarp::Config conf{fs::current_path()};
|
||||||
conf.Load();
|
conf.Load();
|
||||||
|
|
||||||
KeyManager keyManager;
|
KeyManager keyManager;
|
||||||
ASSERT_TRUE(keyManager.initialize(conf, true, true));
|
REQUIRE(keyManager.initialize(conf, true, true));
|
||||||
|
|
||||||
// KeyManager doesn't generate RC file, but should generate others
|
// KeyManager doesn't generate RC file, but should generate others
|
||||||
ASSERT_FALSE(fs::exists(our_rc_filename));
|
REQUIRE_FALSE(fs::exists(our_rc_filename));
|
||||||
|
|
||||||
ASSERT_TRUE(fs::exists(our_enc_key_filename));
|
REQUIRE(fs::exists(our_enc_key_filename));
|
||||||
ASSERT_TRUE(fs::exists(our_transport_key_filename));
|
REQUIRE(fs::exists(our_transport_key_filename));
|
||||||
ASSERT_TRUE(fs::exists(our_identity_filename));
|
REQUIRE(fs::exists(our_identity_filename));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(KeyManagerTest, TestInitialize_RespectsGenFlag)
|
TEST_CASE_METHOD(KeyManagerTest, "Initialize respects gen flag")
|
||||||
{
|
{
|
||||||
llarp::Config conf{fs::current_path()};
|
llarp::Config conf{fs::current_path()};
|
||||||
conf.Load();
|
conf.Load();
|
||||||
|
|
||||||
KeyManager keyManager;
|
KeyManager keyManager;
|
||||||
ASSERT_FALSE(keyManager.initialize(conf, false, true));
|
REQUIRE_FALSE(keyManager.initialize(conf, false, true));
|
||||||
|
|
||||||
// KeyManager shouldn't have touched any files without (genIfAbsent == true)
|
// KeyManager shouldn't have touched any files without (genIfAbsent == true)
|
||||||
ASSERT_FALSE(fs::exists(our_rc_filename));
|
REQUIRE_FALSE(fs::exists(our_rc_filename));
|
||||||
ASSERT_FALSE(fs::exists(our_enc_key_filename));
|
REQUIRE_FALSE(fs::exists(our_enc_key_filename));
|
||||||
ASSERT_FALSE(fs::exists(our_transport_key_filename));
|
REQUIRE_FALSE(fs::exists(our_transport_key_filename));
|
||||||
ASSERT_FALSE(fs::exists(our_identity_filename));
|
REQUIRE_FALSE(fs::exists(our_identity_filename));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(KeyManagerTest, TestInitialize_DetectsBadRcFile)
|
TEST_CASE_METHOD(KeyManagerTest, "Initialize detects bad rc file")
|
||||||
{
|
{
|
||||||
llarp::Config conf{fs::current_path()};
|
llarp::Config conf{fs::current_path()};
|
||||||
conf.Load();
|
conf.Load();
|
||||||
|
@ -154,26 +152,25 @@ TEST_F(KeyManagerTest, TestInitialize_DetectsBadRcFile)
|
||||||
f.close();
|
f.close();
|
||||||
|
|
||||||
KeyManager keyManager;
|
KeyManager keyManager;
|
||||||
ASSERT_TRUE(keyManager.initialize(conf, true, true));
|
REQUIRE(keyManager.initialize(conf, true, true));
|
||||||
ASSERT_TRUE(keyManager.needBackup());
|
REQUIRE(keyManager.needBackup());
|
||||||
|
|
||||||
ASSERT_TRUE(fs::exists(our_enc_key_filename));
|
REQUIRE(fs::exists(our_enc_key_filename));
|
||||||
ASSERT_TRUE(fs::exists(our_transport_key_filename));
|
REQUIRE(fs::exists(our_transport_key_filename));
|
||||||
ASSERT_TRUE(fs::exists(our_identity_filename));
|
REQUIRE(fs::exists(our_identity_filename));
|
||||||
|
|
||||||
// test that keys are sane
|
// test that keys are sane
|
||||||
SecretKey key;
|
SecretKey key;
|
||||||
|
|
||||||
key.Zero();
|
key.Zero();
|
||||||
ASSERT_TRUE(key.LoadFromFile(our_enc_key_filename));
|
REQUIRE(key.LoadFromFile(our_enc_key_filename));
|
||||||
ASSERT_FALSE(key.IsZero());
|
REQUIRE_FALSE(key.IsZero());
|
||||||
|
|
||||||
key.Zero();
|
key.Zero();
|
||||||
ASSERT_TRUE(key.LoadFromFile(our_transport_key_filename));
|
REQUIRE(key.LoadFromFile(our_transport_key_filename));
|
||||||
ASSERT_FALSE(key.IsZero());
|
REQUIRE_FALSE(key.IsZero());
|
||||||
|
|
||||||
key.Zero();
|
key.Zero();
|
||||||
ASSERT_TRUE(key.LoadFromFile(our_identity_filename));
|
REQUIRE(key.LoadFromFile(our_identity_filename));
|
||||||
ASSERT_FALSE(key.IsZero());
|
REQUIRE_FALSE(key.IsZero());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
#include <dht/mock_context.hpp>
|
|
|
@ -9,71 +9,99 @@ namespace llarp
|
||||||
{
|
{
|
||||||
namespace test
|
namespace test
|
||||||
{
|
{
|
||||||
struct MockContext final : public dht::AbstractContext
|
struct MockContext : public dht::AbstractContext
|
||||||
{
|
{
|
||||||
MOCK_CONST_METHOD1(StoreRC, void(const RouterContact));
|
MOCK_CONST_METHOD1(StoreRC, void(const RouterContact));
|
||||||
|
|
||||||
MOCK_METHOD2(LookupRouter, bool(const RouterID&, RouterLookupHandler));
|
MOCK_METHOD2(LookupRouter, bool(const RouterID&, RouterLookupHandler));
|
||||||
|
|
||||||
MOCK_METHOD5(LookupRouterRecursive,
|
MOCK_METHOD5(
|
||||||
void(const RouterID&, const dht::Key_t&, uint64_t,
|
LookupRouterRecursive,
|
||||||
const dht::Key_t&, RouterLookupHandler));
|
void(
|
||||||
|
const RouterID&,
|
||||||
|
const dht::Key_t&,
|
||||||
|
uint64_t,
|
||||||
|
const dht::Key_t&,
|
||||||
|
RouterLookupHandler));
|
||||||
|
|
||||||
MOCK_METHOD6(LookupIntroSetRelayed,
|
MOCK_METHOD6(
|
||||||
void(const dht::Key_t&, const dht::Key_t&, uint64_t,
|
LookupIntroSetRelayed,
|
||||||
const dht::Key_t&, uint64_t,
|
void(
|
||||||
service::EncryptedIntroSetLookupHandler));
|
const dht::Key_t&,
|
||||||
|
const dht::Key_t&,
|
||||||
|
uint64_t,
|
||||||
|
const dht::Key_t&,
|
||||||
|
uint64_t,
|
||||||
|
service::EncryptedIntroSetLookupHandler));
|
||||||
|
|
||||||
MOCK_METHOD5(LookupIntroSetDirect,
|
MOCK_METHOD5(
|
||||||
void(const dht::Key_t&, const dht::Key_t&, uint64_t,
|
LookupIntroSetDirect,
|
||||||
const dht::Key_t&,
|
void(
|
||||||
service::EncryptedIntroSetLookupHandler));
|
const dht::Key_t&,
|
||||||
|
const dht::Key_t&,
|
||||||
|
uint64_t,
|
||||||
|
const dht::Key_t&,
|
||||||
|
service::EncryptedIntroSetLookupHandler));
|
||||||
|
|
||||||
MOCK_CONST_METHOD1(HasRouterLookup, bool(const RouterID& target));
|
MOCK_CONST_METHOD1(HasRouterLookup, bool(const RouterID& target));
|
||||||
|
|
||||||
MOCK_METHOD4(LookupRouterForPath,
|
MOCK_METHOD4(
|
||||||
void(const RouterID& target, uint64_t txid,
|
LookupRouterForPath,
|
||||||
const PathID_t& path, const dht::Key_t& askpeer));
|
void(
|
||||||
|
const RouterID& target,
|
||||||
|
uint64_t txid,
|
||||||
|
const PathID_t& path,
|
||||||
|
const dht::Key_t& askpeer));
|
||||||
|
|
||||||
MOCK_METHOD5(LookupIntroSetForPath,
|
MOCK_METHOD5(
|
||||||
void(const dht::Key_t&, uint64_t, const PathID_t&,
|
LookupIntroSetForPath,
|
||||||
const dht::Key_t&, uint64_t));
|
void(const dht::Key_t&, uint64_t, const PathID_t&, const dht::Key_t&, uint64_t));
|
||||||
|
|
||||||
MOCK_METHOD3(DHTSendTo, void(const RouterID&, dht::IMessage*, bool));
|
MOCK_METHOD3(DHTSendTo, void(const RouterID&, dht::IMessage*, bool));
|
||||||
|
|
||||||
MOCK_METHOD4(
|
MOCK_METHOD4(
|
||||||
HandleExploritoryRouterLookup,
|
HandleExploritoryRouterLookup,
|
||||||
bool(const dht::Key_t& requester, uint64_t txid,
|
bool(
|
||||||
const RouterID& target,
|
const dht::Key_t& requester,
|
||||||
std::vector< std::unique_ptr< dht::IMessage > >& reply));
|
uint64_t txid,
|
||||||
|
const RouterID& target,
|
||||||
|
std::vector<std::unique_ptr<dht::IMessage>>& reply));
|
||||||
|
|
||||||
MOCK_METHOD5(
|
MOCK_METHOD5(
|
||||||
LookupRouterRelayed,
|
LookupRouterRelayed,
|
||||||
void(const dht::Key_t& requester, uint64_t txid,
|
void(
|
||||||
const dht::Key_t& target, bool recursive,
|
const dht::Key_t& requester,
|
||||||
std::vector< std::unique_ptr< dht::IMessage > >& replies));
|
uint64_t txid,
|
||||||
|
const dht::Key_t& target,
|
||||||
|
bool recursive,
|
||||||
|
std::vector<std::unique_ptr<dht::IMessage>>& replies));
|
||||||
|
|
||||||
MOCK_METHOD2(RelayRequestForPath,
|
MOCK_METHOD2(RelayRequestForPath, bool(const PathID_t& localPath, const dht::IMessage& msg));
|
||||||
bool(const PathID_t& localPath, const dht::IMessage& msg));
|
|
||||||
|
|
||||||
MOCK_CONST_METHOD2(GetRCFromNodeDB,
|
MOCK_CONST_METHOD2(GetRCFromNodeDB, bool(const dht::Key_t& k, RouterContact& rc));
|
||||||
bool(const dht::Key_t& k, RouterContact& rc));
|
|
||||||
|
|
||||||
MOCK_METHOD5(PropagateIntroSetTo,
|
MOCK_METHOD5(
|
||||||
void(const dht::Key_t& source, uint64_t sourceTX,
|
PropagateIntroSetTo,
|
||||||
const service::EncryptedIntroSet& introset,
|
void(
|
||||||
const dht::Key_t& peer, uint64_t relayOrder));
|
const dht::Key_t& source,
|
||||||
MOCK_METHOD5(PropagateLocalIntroSet,
|
uint64_t sourceTX,
|
||||||
void(const PathID_t& source, uint64_t sourceTX,
|
const service::EncryptedIntroSet& introset,
|
||||||
const service::EncryptedIntroSet& introset,
|
const dht::Key_t& peer,
|
||||||
const dht::Key_t& peer, uint64_t relayOrder));
|
uint64_t relayOrder));
|
||||||
|
MOCK_METHOD5(
|
||||||
|
PropagateLocalIntroSet,
|
||||||
|
void(
|
||||||
|
const PathID_t& source,
|
||||||
|
uint64_t sourceTX,
|
||||||
|
const service::EncryptedIntroSet& introset,
|
||||||
|
const dht::Key_t& peer,
|
||||||
|
uint64_t relayOrder));
|
||||||
|
|
||||||
MOCK_METHOD2(Init,
|
MOCK_METHOD2(Init, void(const dht::Key_t&, AbstractRouter*));
|
||||||
void(const dht::Key_t&, AbstractRouter*));
|
|
||||||
|
|
||||||
MOCK_CONST_METHOD1(GetIntroSetByLocation,
|
MOCK_CONST_METHOD1(
|
||||||
std::optional< llarp::service::EncryptedIntroSet >(
|
GetIntroSetByLocation,
|
||||||
const llarp::dht::Key_t&));
|
std::optional<llarp::service::EncryptedIntroSet>(const llarp::dht::Key_t&));
|
||||||
|
|
||||||
MOCK_CONST_METHOD0(ExtractStatus, util::StatusObject());
|
MOCK_CONST_METHOD0(ExtractStatus, util::StatusObject());
|
||||||
|
|
||||||
|
@ -85,8 +113,7 @@ namespace llarp
|
||||||
|
|
||||||
MOCK_CONST_METHOD0(OurKey, const dht::Key_t&());
|
MOCK_CONST_METHOD0(OurKey, const dht::Key_t&());
|
||||||
|
|
||||||
MOCK_CONST_METHOD0(pendingIntrosetLookups,
|
MOCK_CONST_METHOD0(pendingIntrosetLookups, const PendingIntrosetLookups&());
|
||||||
const PendingIntrosetLookups&());
|
|
||||||
MOCK_METHOD0(pendingIntrosetLookups, PendingIntrosetLookups&());
|
MOCK_METHOD0(pendingIntrosetLookups, PendingIntrosetLookups&());
|
||||||
|
|
||||||
MOCK_METHOD0(pendingRouterLookups, PendingRouterLookups&());
|
MOCK_METHOD0(pendingRouterLookups, PendingRouterLookups&());
|
||||||
|
@ -97,12 +124,12 @@ namespace llarp
|
||||||
|
|
||||||
MOCK_CONST_METHOD0(pendingExploreLookups, const PendingExploreLookups&());
|
MOCK_CONST_METHOD0(pendingExploreLookups, const PendingExploreLookups&());
|
||||||
|
|
||||||
MOCK_METHOD0(services, dht::Bucket< dht::ISNode >*());
|
MOCK_METHOD0(services, dht::Bucket<dht::ISNode>*());
|
||||||
|
|
||||||
MOCK_CONST_METHOD0(AllowTransit, const bool&());
|
MOCK_CONST_METHOD0(AllowTransit, const bool&());
|
||||||
MOCK_METHOD0(AllowTransit, bool&());
|
MOCK_METHOD0(AllowTransit, bool&());
|
||||||
|
|
||||||
MOCK_CONST_METHOD0(Nodes, dht::Bucket< dht::RCNode >*());
|
MOCK_CONST_METHOD0(Nodes, dht::Bucket<dht::RCNode>*());
|
||||||
MOCK_METHOD1(PutRCNodeAsync, void(const dht::RCNode& val));
|
MOCK_METHOD1(PutRCNodeAsync, void(const dht::RCNode& val));
|
||||||
MOCK_METHOD1(DelRCNodeAsync, void(const dht::Key_t& val));
|
MOCK_METHOD1(DelRCNodeAsync, void(const dht::Key_t& val));
|
||||||
|
|
||||||
|
|
|
@ -2,22 +2,22 @@
|
||||||
#include <dht/key.hpp>
|
#include <dht/key.hpp>
|
||||||
#include <dht/node.hpp>
|
#include <dht/node.hpp>
|
||||||
|
|
||||||
#include <gtest/gtest.h>
|
#include <catch2/catch.hpp>
|
||||||
|
|
||||||
using Key_t = llarp::dht::Key_t;
|
using Key_t = llarp::dht::Key_t;
|
||||||
using Value_t = llarp::dht::RCNode;
|
using Value_t = llarp::dht::RCNode;
|
||||||
using Bucket_t = llarp::dht::Bucket< Value_t >;
|
using Bucket_t = llarp::dht::Bucket<Value_t>;
|
||||||
|
|
||||||
class TestDhtBucket : public ::testing::Test
|
class TestDhtBucket
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
TestDhtBucket() : randInt(0)
|
TestDhtBucket() : randInt(0)
|
||||||
{
|
{
|
||||||
us.Fill(16);
|
us.Fill(16);
|
||||||
nodes = std::make_unique< Bucket_t >(us, [&]() { return randInt++; });
|
nodes = std::make_unique<Bucket_t>(us, [&]() { return randInt++; });
|
||||||
size_t numNodes = 10;
|
size_t numNodes = 10;
|
||||||
byte_t fill = 1;
|
byte_t fill = 1;
|
||||||
while(numNodes)
|
while (numNodes)
|
||||||
{
|
{
|
||||||
Value_t n;
|
Value_t n;
|
||||||
n.ID.Fill(fill);
|
n.ID.Fill(fill);
|
||||||
|
@ -30,10 +30,10 @@ class TestDhtBucket : public ::testing::Test
|
||||||
uint64_t randInt;
|
uint64_t randInt;
|
||||||
|
|
||||||
llarp::dht::Key_t us;
|
llarp::dht::Key_t us;
|
||||||
std::unique_ptr< Bucket_t > nodes;
|
std::unique_ptr<Bucket_t> nodes;
|
||||||
};
|
};
|
||||||
|
|
||||||
TEST_F(TestDhtBucket, simple_cycle)
|
TEST_CASE_METHOD(TestDhtBucket, "Simple cycle", "[dht]")
|
||||||
{
|
{
|
||||||
// Empty the current bucket.
|
// Empty the current bucket.
|
||||||
nodes->Clear();
|
nodes->Clear();
|
||||||
|
@ -45,27 +45,27 @@ TEST_F(TestDhtBucket, simple_cycle)
|
||||||
nodes->PutNode(val);
|
nodes->PutNode(val);
|
||||||
|
|
||||||
// Verify the value is in the bucket
|
// Verify the value is in the bucket
|
||||||
ASSERT_TRUE(nodes->HasNode(val.ID));
|
REQUIRE(nodes->HasNode(val.ID));
|
||||||
ASSERT_EQ(1u, nodes->size());
|
REQUIRE(1u == nodes->size());
|
||||||
|
|
||||||
// Verify after deletion, the value is no longer in the bucket
|
// Verify after deletion, the value is no longer in the bucket
|
||||||
nodes->DelNode(val.ID);
|
nodes->DelNode(val.ID);
|
||||||
ASSERT_FALSE(nodes->HasNode(val.ID));
|
REQUIRE_FALSE(nodes->HasNode(val.ID));
|
||||||
|
|
||||||
// Verify deleting again succeeds;
|
// Verify deleting again succeeds;
|
||||||
nodes->DelNode(val.ID);
|
nodes->DelNode(val.ID);
|
||||||
ASSERT_FALSE(nodes->HasNode(val.ID));
|
REQUIRE_FALSE(nodes->HasNode(val.ID));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(TestDhtBucket, get_random_node_excluding)
|
TEST_CASE_METHOD(TestDhtBucket, "get_random_node_excluding")
|
||||||
{
|
{
|
||||||
// Empty the current bucket.
|
// Empty the current bucket.
|
||||||
nodes->Clear();
|
nodes->Clear();
|
||||||
|
|
||||||
// We expect not to find anything
|
// We expect not to find anything
|
||||||
Key_t result;
|
Key_t result;
|
||||||
std::set< Key_t > excludeSet;
|
std::set<Key_t> excludeSet;
|
||||||
ASSERT_FALSE(nodes->GetRandomNodeExcluding(result, excludeSet));
|
REQUIRE_FALSE(nodes->GetRandomNodeExcluding(result, excludeSet));
|
||||||
|
|
||||||
// Create a simple value.
|
// Create a simple value.
|
||||||
Value_t val;
|
Value_t val;
|
||||||
|
@ -73,24 +73,24 @@ TEST_F(TestDhtBucket, get_random_node_excluding)
|
||||||
|
|
||||||
// Add the simple value to the exclude set
|
// Add the simple value to the exclude set
|
||||||
excludeSet.insert(val.ID);
|
excludeSet.insert(val.ID);
|
||||||
ASSERT_FALSE(nodes->GetRandomNodeExcluding(result, excludeSet));
|
REQUIRE_FALSE(nodes->GetRandomNodeExcluding(result, excludeSet));
|
||||||
|
|
||||||
// Add the simple value to the bucket
|
// Add the simple value to the bucket
|
||||||
nodes->PutNode(val);
|
nodes->PutNode(val);
|
||||||
ASSERT_FALSE(nodes->GetRandomNodeExcluding(result, excludeSet));
|
REQUIRE_FALSE(nodes->GetRandomNodeExcluding(result, excludeSet));
|
||||||
|
|
||||||
excludeSet.clear();
|
excludeSet.clear();
|
||||||
|
|
||||||
ASSERT_TRUE(nodes->GetRandomNodeExcluding(result, excludeSet));
|
REQUIRE(nodes->GetRandomNodeExcluding(result, excludeSet));
|
||||||
ASSERT_EQ(val.ID, result);
|
REQUIRE(val.ID == result);
|
||||||
|
|
||||||
// Add an element to the exclude set which isn't the bucket.
|
// Add an element to the exclude set which isn't the bucket.
|
||||||
Key_t other;
|
Key_t other;
|
||||||
other.Fill(0xff);
|
other.Fill(0xff);
|
||||||
excludeSet.insert(other);
|
excludeSet.insert(other);
|
||||||
|
|
||||||
ASSERT_TRUE(nodes->GetRandomNodeExcluding(result, excludeSet));
|
REQUIRE(nodes->GetRandomNodeExcluding(result, excludeSet));
|
||||||
ASSERT_EQ(val.ID, result);
|
REQUIRE(val.ID == result);
|
||||||
|
|
||||||
// Add a node which is in both bucket and excludeSet
|
// Add a node which is in both bucket and excludeSet
|
||||||
Value_t nextVal;
|
Value_t nextVal;
|
||||||
|
@ -98,28 +98,28 @@ TEST_F(TestDhtBucket, get_random_node_excluding)
|
||||||
excludeSet.insert(nextVal.ID);
|
excludeSet.insert(nextVal.ID);
|
||||||
nodes->PutNode(nextVal);
|
nodes->PutNode(nextVal);
|
||||||
|
|
||||||
ASSERT_TRUE(nodes->GetRandomNodeExcluding(result, excludeSet));
|
REQUIRE(nodes->GetRandomNodeExcluding(result, excludeSet));
|
||||||
ASSERT_EQ(val.ID, result);
|
REQUIRE(val.ID == result);
|
||||||
|
|
||||||
// Clear the excludeSet - we should still have 2 nodes in the bucket
|
// Clear the excludeSet - we should still have 2 nodes in the bucket
|
||||||
excludeSet.clear();
|
excludeSet.clear();
|
||||||
|
|
||||||
randInt = 0;
|
randInt = 0;
|
||||||
ASSERT_TRUE(nodes->GetRandomNodeExcluding(result, excludeSet));
|
REQUIRE(nodes->GetRandomNodeExcluding(result, excludeSet));
|
||||||
ASSERT_EQ(val.ID, result);
|
REQUIRE(val.ID == result);
|
||||||
|
|
||||||
// Set the random value to be 1, we should get the other node.
|
// Set the random value to be 1, we should get the other node.
|
||||||
randInt = 1;
|
randInt = 1;
|
||||||
ASSERT_TRUE(nodes->GetRandomNodeExcluding(result, excludeSet));
|
REQUIRE(nodes->GetRandomNodeExcluding(result, excludeSet));
|
||||||
ASSERT_EQ(nextVal.ID, result);
|
REQUIRE(nextVal.ID == result);
|
||||||
|
|
||||||
// Set the random value to be 100, we should get the first node.
|
// Set the random value to be 100, we should get the first node.
|
||||||
randInt = 100;
|
randInt = 100;
|
||||||
ASSERT_TRUE(nodes->GetRandomNodeExcluding(result, excludeSet));
|
REQUIRE(nodes->GetRandomNodeExcluding(result, excludeSet));
|
||||||
ASSERT_EQ(val.ID, result);
|
REQUIRE(val.ID == result);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(TestDhtBucket, find_closest)
|
TEST_CASE_METHOD(TestDhtBucket, "find_closest", "[dht]")
|
||||||
{
|
{
|
||||||
// Empty the current bucket.
|
// Empty the current bucket.
|
||||||
nodes->Clear();
|
nodes->Clear();
|
||||||
|
@ -129,182 +129,182 @@ TEST_F(TestDhtBucket, find_closest)
|
||||||
target.Fill(0xF0);
|
target.Fill(0xF0);
|
||||||
|
|
||||||
Key_t result;
|
Key_t result;
|
||||||
ASSERT_FALSE(nodes->FindClosest(target, result));
|
REQUIRE_FALSE(nodes->FindClosest(target, result));
|
||||||
|
|
||||||
// Add a node to the bucket
|
// Add a node to the bucket
|
||||||
Value_t first;
|
Value_t first;
|
||||||
first.ID.Zero();
|
first.ID.Zero();
|
||||||
nodes->PutNode(first);
|
nodes->PutNode(first);
|
||||||
|
|
||||||
ASSERT_TRUE(nodes->FindClosest(target, result));
|
REQUIRE(nodes->FindClosest(target, result));
|
||||||
ASSERT_EQ(result, first.ID);
|
REQUIRE(result == first.ID);
|
||||||
|
|
||||||
// Add another node to the bucket, closer to the target
|
// Add another node to the bucket, closer to the target
|
||||||
Value_t second;
|
Value_t second;
|
||||||
second.ID.Fill(0x10);
|
second.ID.Fill(0x10);
|
||||||
nodes->PutNode(second);
|
nodes->PutNode(second);
|
||||||
ASSERT_TRUE(nodes->FindClosest(target, result));
|
REQUIRE(nodes->FindClosest(target, result));
|
||||||
ASSERT_EQ(result, second.ID);
|
REQUIRE(result == second.ID);
|
||||||
|
|
||||||
// Add a third node to the bucket, closer to the target
|
// Add a third node to the bucket, closer to the target
|
||||||
Value_t third;
|
Value_t third;
|
||||||
third.ID.Fill(0x20);
|
third.ID.Fill(0x20);
|
||||||
nodes->PutNode(third);
|
nodes->PutNode(third);
|
||||||
ASSERT_TRUE(nodes->FindClosest(target, result));
|
REQUIRE(nodes->FindClosest(target, result));
|
||||||
ASSERT_EQ(result, third.ID);
|
REQUIRE(result == third.ID);
|
||||||
|
|
||||||
// Add a fourth node to the bucket, greater than the target
|
// Add a fourth node to the bucket, greater than the target
|
||||||
Value_t fourth;
|
Value_t fourth;
|
||||||
fourth.ID.Fill(0xF1);
|
fourth.ID.Fill(0xF1);
|
||||||
nodes->PutNode(fourth);
|
nodes->PutNode(fourth);
|
||||||
ASSERT_TRUE(nodes->FindClosest(target, result));
|
REQUIRE(nodes->FindClosest(target, result));
|
||||||
ASSERT_EQ(result, fourth.ID);
|
REQUIRE(result == fourth.ID);
|
||||||
|
|
||||||
// Add a fifth node to the bucket, equal to the target
|
// Add a fifth node to the bucket, equal to the target
|
||||||
Value_t fifth;
|
Value_t fifth;
|
||||||
fifth.ID.Fill(0xF0);
|
fifth.ID.Fill(0xF0);
|
||||||
nodes->PutNode(fifth);
|
nodes->PutNode(fifth);
|
||||||
ASSERT_TRUE(nodes->FindClosest(target, result));
|
REQUIRE(nodes->FindClosest(target, result));
|
||||||
ASSERT_EQ(result, fifth.ID);
|
REQUIRE(result == fifth.ID);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(TestDhtBucket, get_many_random)
|
TEST_CASE_METHOD(TestDhtBucket, "get_many_random", "[dht]")
|
||||||
{
|
{
|
||||||
// Empty the current bucket.
|
// Empty the current bucket.
|
||||||
nodes->Clear();
|
nodes->Clear();
|
||||||
|
|
||||||
// Verify behaviour with empty node set
|
// Verify behaviour with empty node set
|
||||||
std::set< Key_t > result;
|
std::set<Key_t> result;
|
||||||
ASSERT_FALSE(nodes->GetManyRandom(result, 0));
|
REQUIRE_FALSE(nodes->GetManyRandom(result, 0));
|
||||||
ASSERT_FALSE(nodes->GetManyRandom(result, 1));
|
REQUIRE_FALSE(nodes->GetManyRandom(result, 1));
|
||||||
|
|
||||||
// Add 5 nodes to the bucket
|
// Add 5 nodes to the bucket
|
||||||
std::set< Value_t > curValues;
|
std::set<Value_t> curValues;
|
||||||
std::set< Key_t > curKeys;
|
std::set<Key_t> curKeys;
|
||||||
for(byte_t i = 0x00; i < 0x05; ++i)
|
for (byte_t i = 0x00; i < 0x05; ++i)
|
||||||
{
|
{
|
||||||
Value_t v;
|
Value_t v;
|
||||||
v.ID.Fill(i);
|
v.ID.Fill(i);
|
||||||
ASSERT_TRUE(curKeys.insert(v.ID).second);
|
REQUIRE(curKeys.insert(v.ID).second);
|
||||||
nodes->PutNode(v);
|
nodes->PutNode(v);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fetching more than the current size fails
|
// Fetching more than the current size fails
|
||||||
ASSERT_EQ(5u, nodes->size());
|
REQUIRE(5u == nodes->size());
|
||||||
ASSERT_FALSE(nodes->GetManyRandom(result, nodes->size() + 1));
|
REQUIRE_FALSE(nodes->GetManyRandom(result, nodes->size() + 1));
|
||||||
|
|
||||||
// Fetching the current size succeeds
|
// Fetching the current size succeeds
|
||||||
ASSERT_TRUE(nodes->GetManyRandom(result, nodes->size()));
|
REQUIRE(nodes->GetManyRandom(result, nodes->size()));
|
||||||
ASSERT_EQ(curKeys, result);
|
REQUIRE(curKeys == result);
|
||||||
|
|
||||||
// Fetching a subset succeeds.
|
// Fetching a subset succeeds.
|
||||||
// Note we hack this by "fixing" the random number generator
|
// Note we hack this by "fixing" the random number generator
|
||||||
result.clear();
|
result.clear();
|
||||||
|
|
||||||
ASSERT_TRUE(nodes->GetManyRandom(result, 1u));
|
REQUIRE(nodes->GetManyRandom(result, 1u));
|
||||||
ASSERT_EQ(1u, result.size());
|
REQUIRE(1u == result.size());
|
||||||
ASSERT_EQ(*curKeys.begin(), *result.begin());
|
REQUIRE(*curKeys.begin() == *result.begin());
|
||||||
|
|
||||||
randInt = 0;
|
randInt = 0;
|
||||||
result.clear();
|
result.clear();
|
||||||
|
|
||||||
ASSERT_TRUE(nodes->GetManyRandom(result, nodes->size() - 1));
|
REQUIRE(nodes->GetManyRandom(result, nodes->size() - 1));
|
||||||
ASSERT_EQ(nodes->size() - 1, result.size());
|
REQUIRE(nodes->size() - 1 == result.size());
|
||||||
ASSERT_EQ(std::set< Key_t >(++curKeys.rbegin(), curKeys.rend()), result);
|
REQUIRE(std::set<Key_t>(++curKeys.rbegin(), curKeys.rend()) == result);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(TestDhtBucket, find_close_excluding)
|
TEST_CASE_METHOD(TestDhtBucket, "find_close_excluding", "[dht]")
|
||||||
{
|
{
|
||||||
// Empty the current bucket.
|
// Empty the current bucket.
|
||||||
nodes->Clear();
|
nodes->Clear();
|
||||||
|
|
||||||
Key_t target;
|
Key_t target;
|
||||||
target.Zero();
|
target.Zero();
|
||||||
std::set< Key_t > exclude;
|
std::set<Key_t> exclude;
|
||||||
Key_t result;
|
Key_t result;
|
||||||
|
|
||||||
// Empty node + exclude set fails
|
// Empty node + exclude set fails
|
||||||
ASSERT_FALSE(nodes->FindCloseExcluding(target, result, exclude));
|
REQUIRE_FALSE(nodes->FindCloseExcluding(target, result, exclude));
|
||||||
|
|
||||||
Value_t first;
|
Value_t first;
|
||||||
first.ID.Fill(0xF0);
|
first.ID.Fill(0xF0);
|
||||||
exclude.insert(first.ID);
|
exclude.insert(first.ID);
|
||||||
|
|
||||||
// Empty nodes fails
|
// Empty nodes fails
|
||||||
ASSERT_FALSE(nodes->FindCloseExcluding(target, result, exclude));
|
REQUIRE_FALSE(nodes->FindCloseExcluding(target, result, exclude));
|
||||||
|
|
||||||
// Nodes and exclude set match
|
// Nodes and exclude set match
|
||||||
nodes->PutNode(first);
|
nodes->PutNode(first);
|
||||||
ASSERT_FALSE(nodes->FindCloseExcluding(target, result, exclude));
|
REQUIRE_FALSE(nodes->FindCloseExcluding(target, result, exclude));
|
||||||
|
|
||||||
// Exclude set empty
|
// Exclude set empty
|
||||||
exclude.clear();
|
exclude.clear();
|
||||||
ASSERT_TRUE(nodes->FindCloseExcluding(target, result, exclude));
|
REQUIRE(nodes->FindCloseExcluding(target, result, exclude));
|
||||||
result = first.ID;
|
result = first.ID;
|
||||||
|
|
||||||
Value_t second;
|
Value_t second;
|
||||||
second.ID.Fill(0x01);
|
second.ID.Fill(0x01);
|
||||||
nodes->PutNode(second);
|
nodes->PutNode(second);
|
||||||
|
|
||||||
ASSERT_TRUE(nodes->FindCloseExcluding(target, result, exclude));
|
REQUIRE(nodes->FindCloseExcluding(target, result, exclude));
|
||||||
result = second.ID;
|
result = second.ID;
|
||||||
|
|
||||||
exclude.insert(second.ID);
|
exclude.insert(second.ID);
|
||||||
ASSERT_TRUE(nodes->FindCloseExcluding(target, result, exclude));
|
REQUIRE(nodes->FindCloseExcluding(target, result, exclude));
|
||||||
result = first.ID;
|
result = first.ID;
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(TestDhtBucket, find_many_near_excluding)
|
TEST_CASE_METHOD(TestDhtBucket, "find_many_near_excluding", "[dht]")
|
||||||
{
|
{
|
||||||
// Empty the current bucket.
|
// Empty the current bucket.
|
||||||
nodes->Clear();
|
nodes->Clear();
|
||||||
|
|
||||||
Key_t target;
|
Key_t target;
|
||||||
target.Zero();
|
target.Zero();
|
||||||
std::set< Key_t > exclude;
|
std::set<Key_t> exclude;
|
||||||
std::set< Key_t > result;
|
std::set<Key_t> result;
|
||||||
|
|
||||||
// Empty node + exclude set, with size 0 succeeds
|
// Empty node + exclude set, with size 0 succeeds
|
||||||
ASSERT_TRUE(nodes->GetManyNearExcluding(target, result, 0, exclude));
|
REQUIRE(nodes->GetManyNearExcluding(target, result, 0, exclude));
|
||||||
ASSERT_EQ(0u, result.size());
|
REQUIRE(0u == result.size());
|
||||||
// Empty node + exclude set fails
|
// Empty node + exclude set fails
|
||||||
ASSERT_FALSE(nodes->GetManyNearExcluding(target, result, 1, exclude));
|
REQUIRE_FALSE(nodes->GetManyNearExcluding(target, result, 1, exclude));
|
||||||
|
|
||||||
Value_t first;
|
Value_t first;
|
||||||
first.ID.Fill(0xF0);
|
first.ID.Fill(0xF0);
|
||||||
exclude.insert(first.ID);
|
exclude.insert(first.ID);
|
||||||
|
|
||||||
// Empty nodes fails
|
// Empty nodes fails
|
||||||
ASSERT_FALSE(nodes->GetManyNearExcluding(target, result, 1, exclude));
|
REQUIRE_FALSE(nodes->GetManyNearExcluding(target, result, 1, exclude));
|
||||||
|
|
||||||
// Nodes and exclude set match
|
// Nodes and exclude set match
|
||||||
nodes->PutNode(first);
|
nodes->PutNode(first);
|
||||||
ASSERT_FALSE(nodes->GetManyNearExcluding(target, result, 1, exclude));
|
REQUIRE_FALSE(nodes->GetManyNearExcluding(target, result, 1, exclude));
|
||||||
|
|
||||||
// Single node succeeds
|
// Single node succeeds
|
||||||
exclude.clear();
|
exclude.clear();
|
||||||
ASSERT_TRUE(nodes->GetManyNearExcluding(target, result, 1, exclude));
|
REQUIRE(nodes->GetManyNearExcluding(target, result, 1, exclude));
|
||||||
ASSERT_EQ(result, std::set< Key_t >({first.ID}));
|
REQUIRE(result == std::set<Key_t>({first.ID}));
|
||||||
|
|
||||||
// Trying to grab 2 nodes from a 1 node set fails
|
// Trying to grab 2 nodes from a 1 node set fails
|
||||||
result.clear();
|
result.clear();
|
||||||
ASSERT_FALSE(nodes->GetManyNearExcluding(target, result, 2, exclude));
|
REQUIRE_FALSE(nodes->GetManyNearExcluding(target, result, 2, exclude));
|
||||||
|
|
||||||
// two nodes finds closest
|
// two nodes finds closest
|
||||||
Value_t second;
|
Value_t second;
|
||||||
second.ID.Fill(0x01);
|
second.ID.Fill(0x01);
|
||||||
nodes->PutNode(second);
|
nodes->PutNode(second);
|
||||||
result.clear();
|
result.clear();
|
||||||
ASSERT_TRUE(nodes->GetManyNearExcluding(target, result, 1, exclude));
|
REQUIRE(nodes->GetManyNearExcluding(target, result, 1, exclude));
|
||||||
ASSERT_EQ(result, std::set< Key_t >({second.ID}));
|
REQUIRE(result == std::set<Key_t>({second.ID}));
|
||||||
|
|
||||||
// 3 nodes finds 2 closest
|
// 3 nodes finds 2 closest
|
||||||
Value_t third;
|
Value_t third;
|
||||||
third.ID.Fill(0x02);
|
third.ID.Fill(0x02);
|
||||||
nodes->PutNode(third);
|
nodes->PutNode(third);
|
||||||
result.clear();
|
result.clear();
|
||||||
ASSERT_TRUE(nodes->GetManyNearExcluding(target, result, 2, exclude));
|
REQUIRE(nodes->GetManyNearExcluding(target, result, 2, exclude));
|
||||||
ASSERT_EQ(result, std::set< Key_t >({second.ID, third.ID}));
|
REQUIRE(result == std::set<Key_t>({second.ID, third.ID}));
|
||||||
|
|
||||||
// 4 nodes, one in exclude set finds 2 closest
|
// 4 nodes, one in exclude set finds 2 closest
|
||||||
Value_t fourth;
|
Value_t fourth;
|
||||||
|
@ -312,27 +312,27 @@ TEST_F(TestDhtBucket, find_many_near_excluding)
|
||||||
nodes->PutNode(fourth);
|
nodes->PutNode(fourth);
|
||||||
exclude.insert(third.ID);
|
exclude.insert(third.ID);
|
||||||
result.clear();
|
result.clear();
|
||||||
ASSERT_TRUE(nodes->GetManyNearExcluding(target, result, 2, exclude));
|
REQUIRE(nodes->GetManyNearExcluding(target, result, 2, exclude));
|
||||||
ASSERT_EQ(result, std::set< Key_t >({second.ID, fourth.ID}));
|
REQUIRE(result == std::set<Key_t>({second.ID, fourth.ID}));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(TestDhtBucket, TestBucketFindClosest)
|
TEST_CASE_METHOD(TestDhtBucket, "Bucket: FindClosest", "[dht]")
|
||||||
{
|
{
|
||||||
llarp::dht::Key_t result;
|
llarp::dht::Key_t result;
|
||||||
llarp::dht::Key_t target;
|
llarp::dht::Key_t target;
|
||||||
target.Fill(5);
|
target.Fill(5);
|
||||||
ASSERT_TRUE(nodes->FindClosest(target, result));
|
REQUIRE(nodes->FindClosest(target, result));
|
||||||
ASSERT_EQ(target, result);
|
REQUIRE(target == result);
|
||||||
const llarp::dht::Key_t oldResult = result;
|
const llarp::dht::Key_t oldResult = result;
|
||||||
target.Fill(0xf5);
|
target.Fill(0xf5);
|
||||||
ASSERT_TRUE(nodes->FindClosest(target, result));
|
REQUIRE(nodes->FindClosest(target, result));
|
||||||
ASSERT_EQ(oldResult, result);
|
REQUIRE(oldResult == result);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(TestDhtBucket, TestBucketRandomized_1000)
|
TEST_CASE_METHOD(TestDhtBucket, "Bucket: randomized 1000", "[dht]")
|
||||||
{
|
{
|
||||||
size_t moreNodes = 100;
|
size_t moreNodes = 100;
|
||||||
while(moreNodes--)
|
while (moreNodes--)
|
||||||
{
|
{
|
||||||
llarp::dht::RCNode n;
|
llarp::dht::RCNode n;
|
||||||
n.ID.Fill(randInt);
|
n.ID.Fill(randInt);
|
||||||
|
@ -340,31 +340,30 @@ TEST_F(TestDhtBucket, TestBucketRandomized_1000)
|
||||||
nodes->PutNode(n);
|
nodes->PutNode(n);
|
||||||
}
|
}
|
||||||
const size_t count = 1000;
|
const size_t count = 1000;
|
||||||
size_t left = count;
|
size_t left = count;
|
||||||
while(left--)
|
while (left--)
|
||||||
{
|
{
|
||||||
llarp::dht::Key_t result;
|
llarp::dht::Key_t result;
|
||||||
llarp::dht::Key_t target;
|
llarp::dht::Key_t target;
|
||||||
target.Randomize();
|
target.Randomize();
|
||||||
const llarp::dht::Key_t expect = target;
|
const llarp::dht::Key_t expect = target;
|
||||||
ASSERT_TRUE(nodes->FindClosest(target, result));
|
REQUIRE(nodes->FindClosest(target, result));
|
||||||
if(target == result)
|
if (target == result)
|
||||||
{
|
{
|
||||||
ASSERT_GE(result ^ target, expect ^ target);
|
REQUIRE((result ^ target) >= (expect ^ target));
|
||||||
ASSERT_EQ(result ^ target, expect ^ target);
|
REQUIRE((result ^ target) == (expect ^ target));
|
||||||
ASSERT_EQ(result ^ target, expect ^ target);
|
REQUIRE((result ^ target) == (expect ^ target));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Key_t dist = result ^ target;
|
Key_t dist = (result ^ target);
|
||||||
Key_t oldDist = expect ^ target;
|
Key_t oldDist = (expect ^ target);
|
||||||
ASSERT_NE(result ^ target, expect ^ target);
|
REQUIRE((result ^ target) != (expect ^ target));
|
||||||
|
|
||||||
ASSERT_GE(result ^ target, expect ^ target)
|
INFO(dist << ">=" << oldDist << "iteration=" << (count - left));
|
||||||
<< "result=" << result << "expect=" << expect << std::endl
|
REQUIRE((result ^ target) >= (expect ^ target));
|
||||||
<< dist << ">=" << oldDist << "iteration=" << (count - left);
|
|
||||||
|
|
||||||
ASSERT_NE(result ^ target, expect ^ target);
|
REQUIRE((result ^ target) != (expect ^ target));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,38 +4,42 @@
|
||||||
#include <dht/mock_context.hpp>
|
#include <dht/mock_context.hpp>
|
||||||
#include <test_util.hpp>
|
#include <test_util.hpp>
|
||||||
|
|
||||||
#include <gtest/gtest.h>
|
#include <gmock/gmock.h>
|
||||||
|
#include <catch2/catch.hpp>
|
||||||
|
|
||||||
using namespace llarp;
|
using namespace llarp;
|
||||||
using namespace ::testing;
|
using namespace ::testing;
|
||||||
|
|
||||||
using test::makeBuf;
|
using test::makeBuf;
|
||||||
|
|
||||||
struct TestDhtExploreNetworkJob : public ::testing::Test
|
struct TestDhtExploreNetworkJob
|
||||||
{
|
{
|
||||||
RouterID peer;
|
RouterID peer;
|
||||||
test::MockContext context;
|
test::MockContext context;
|
||||||
dht::ExploreNetworkJob exploreNetworkJob;
|
dht::ExploreNetworkJob exploreNetworkJob;
|
||||||
|
|
||||||
TestDhtExploreNetworkJob()
|
TestDhtExploreNetworkJob() : peer(makeBuf<RouterID>(0x01)), exploreNetworkJob(peer, &context)
|
||||||
: peer(makeBuf< RouterID >(0x01)), exploreNetworkJob(peer, &context)
|
{}
|
||||||
|
|
||||||
|
~TestDhtExploreNetworkJob()
|
||||||
{
|
{
|
||||||
|
CHECK(Mock::VerifyAndClearExpectations(&context));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
TEST_F(TestDhtExploreNetworkJob, validate)
|
TEST_CASE_METHOD(TestDhtExploreNetworkJob, "validate", "[dht]")
|
||||||
{
|
{
|
||||||
const RouterID other = makeBuf< RouterID >(0x02);
|
const RouterID other = makeBuf<RouterID>(0x02);
|
||||||
ASSERT_TRUE(exploreNetworkJob.Validate(other));
|
REQUIRE(exploreNetworkJob.Validate(other));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(TestDhtExploreNetworkJob, start)
|
TEST_CASE_METHOD(TestDhtExploreNetworkJob, "start", "[dht]")
|
||||||
{
|
{
|
||||||
// Verify input arguments are passed correctly.
|
// Verify input arguments are passed correctly.
|
||||||
// The actual logic is inside the `dht::AbstractContext` implementation.
|
// The actual logic is inside the `dht::AbstractContext` implementation.
|
||||||
|
|
||||||
const auto txKey = makeBuf< dht::Key_t >(0x02);
|
const auto txKey = makeBuf<dht::Key_t>(0x02);
|
||||||
uint64_t txId = 4;
|
uint64_t txId = 4;
|
||||||
|
|
||||||
dht::TXOwner txOwner(txKey, txId);
|
dht::TXOwner txOwner(txKey, txId);
|
||||||
|
|
||||||
|
@ -47,10 +51,11 @@ TEST_F(TestDhtExploreNetworkJob, start)
|
||||||
).Times(1);
|
).Times(1);
|
||||||
// clang-format off
|
// clang-format off
|
||||||
|
|
||||||
ASSERT_NO_THROW(exploreNetworkJob.Start(txOwner));
|
REQUIRE_NOTHROW(exploreNetworkJob.Start(txOwner));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(TestDhtExploreNetworkJob, send_reply)
|
// TODO: sections?
|
||||||
|
TEST_CASE_METHOD(TestDhtExploreNetworkJob, "send_reply", "[dht]")
|
||||||
{
|
{
|
||||||
// Concerns:
|
// Concerns:
|
||||||
// - Empty collection
|
// - Empty collection
|
||||||
|
@ -62,7 +67,7 @@ TEST_F(TestDhtExploreNetworkJob, send_reply)
|
||||||
EXPECT_CALL(context, LookupRouter(_, _)).Times(0);
|
EXPECT_CALL(context, LookupRouter(_, _)).Times(0);
|
||||||
EXPECT_CALL(context, GetRouter()).WillOnce(Return(nullptr));
|
EXPECT_CALL(context, GetRouter()).WillOnce(Return(nullptr));
|
||||||
|
|
||||||
ASSERT_NO_THROW(exploreNetworkJob.SendReply());
|
REQUIRE_NOTHROW(exploreNetworkJob.SendReply());
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
|
@ -75,7 +80,7 @@ TEST_F(TestDhtExploreNetworkJob, send_reply)
|
||||||
EXPECT_CALL(context, LookupRouter(Ne(makeBuf<RouterID>(0x01)), _)).Times(2).WillRepeatedly(Return(true));
|
EXPECT_CALL(context, LookupRouter(Ne(makeBuf<RouterID>(0x01)), _)).Times(2).WillRepeatedly(Return(true));
|
||||||
EXPECT_CALL(context, LookupRouter(Eq(makeBuf<RouterID>(0x01)), _)).WillOnce(Return(false));
|
EXPECT_CALL(context, LookupRouter(Eq(makeBuf<RouterID>(0x01)), _)).WillOnce(Return(false));
|
||||||
|
|
||||||
ASSERT_NO_THROW(exploreNetworkJob.SendReply());
|
REQUIRE_NOTHROW(exploreNetworkJob.SendReply());
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
|
@ -87,6 +92,6 @@ TEST_F(TestDhtExploreNetworkJob, send_reply)
|
||||||
EXPECT_CALL(context, GetRouter()).WillOnce(Return(nullptr));
|
EXPECT_CALL(context, GetRouter()).WillOnce(Return(nullptr));
|
||||||
EXPECT_CALL(context, LookupRouter(_, _)).Times(3).WillRepeatedly(Return(true));
|
EXPECT_CALL(context, LookupRouter(_, _)).Times(3).WillRepeatedly(Return(true));
|
||||||
|
|
||||||
ASSERT_NO_THROW(exploreNetworkJob.SendReply());
|
REQUIRE_NOTHROW(exploreNetworkJob.SendReply());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
#include <dht/kademlia.hpp>
|
#include <dht/kademlia.hpp>
|
||||||
|
|
||||||
#include <gtest/gtest.h>
|
#include <catch2/catch.hpp>
|
||||||
|
|
||||||
using llarp::dht::Key_t;
|
using llarp::dht::Key_t;
|
||||||
|
|
||||||
using Array = std::array< byte_t, Key_t::SIZE >;
|
using Array = std::array<byte_t, Key_t::SIZE>;
|
||||||
|
|
||||||
struct XorMetricData
|
struct XorMetricData
|
||||||
{
|
{
|
||||||
|
@ -15,34 +15,21 @@ struct XorMetricData
|
||||||
|
|
||||||
XorMetricData(const Array& u, const Array& l, const Array& r, bool res)
|
XorMetricData(const Array& u, const Array& l, const Array& r, bool res)
|
||||||
: us(u), left(l), right(r), result(res)
|
: us(u), left(l), right(r), result(res)
|
||||||
{
|
{}
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
std::ostream&
|
std::ostream&
|
||||||
operator<<(std::ostream& stream, const XorMetricData& x)
|
operator<<(std::ostream& stream, const XorMetricData& x)
|
||||||
{
|
{
|
||||||
stream << int(x.us[0]) << " " << int(x.left[0]) << " " << int(x.right[0])
|
stream << int(x.us[0]) << " " << int(x.left[0]) << " " << int(x.right[0]) << " " << std::boolalpha
|
||||||
<< " " << std::boolalpha << x.result;
|
<< x.result;
|
||||||
|
|
||||||
return stream;
|
return stream;
|
||||||
}
|
}
|
||||||
|
std::vector<XorMetricData>
|
||||||
struct XorMetric : public ::testing::TestWithParam< XorMetricData >
|
|
||||||
{
|
|
||||||
};
|
|
||||||
|
|
||||||
TEST_P(XorMetric, test)
|
|
||||||
{
|
|
||||||
auto d = GetParam();
|
|
||||||
ASSERT_EQ(llarp::dht::XorMetric{Key_t{d.us}}(Key_t{d.left}, Key_t{d.right}),
|
|
||||||
d.result);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector< XorMetricData >
|
|
||||||
makeData()
|
makeData()
|
||||||
{
|
{
|
||||||
std::vector< XorMetricData > result;
|
std::vector<XorMetricData> result;
|
||||||
|
|
||||||
Array zero;
|
Array zero;
|
||||||
zero.fill(0);
|
zero.fill(0);
|
||||||
|
@ -84,5 +71,8 @@ makeData()
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
INSTANTIATE_TEST_SUITE_P(TestDhtXorMetric, XorMetric,
|
TEST_CASE("XorMetric", "[dht]")
|
||||||
::testing::ValuesIn(makeData()));
|
{
|
||||||
|
auto d = GENERATE(from_range(makeData()));
|
||||||
|
REQUIRE(llarp::dht::XorMetric{Key_t{d.us}}(Key_t{d.left}, Key_t{d.right}) == d.result);
|
||||||
|
}
|
||||||
|
|
|
@ -1,105 +1,91 @@
|
||||||
#include <gtest/gtest.h>
|
#include <catch2/catch.hpp>
|
||||||
|
|
||||||
#include <dht/key.hpp>
|
#include <dht/key.hpp>
|
||||||
|
|
||||||
using namespace llarp;
|
using namespace llarp;
|
||||||
|
|
||||||
using Array = std::array< byte_t, dht::Key_t::SIZE >;
|
using Array = std::array<byte_t, dht::Key_t::SIZE>;
|
||||||
|
|
||||||
struct DHT : public ::testing::TestWithParam< Array >
|
static constexpr Array emptyArray{{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}};
|
||||||
|
|
||||||
TEST_P(DHT, constructor)
|
static constexpr Array fullArray{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}};
|
||||||
|
|
||||||
|
static constexpr Array seqArray{{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A,
|
||||||
|
0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15,
|
||||||
|
0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F}};
|
||||||
|
|
||||||
|
std::vector<Array> data{emptyArray, fullArray, seqArray};
|
||||||
|
|
||||||
|
TEST_CASE("DHT key constructor", "[dht]")
|
||||||
{
|
{
|
||||||
auto d = GetParam();
|
auto d = GENERATE(from_range(data));
|
||||||
|
|
||||||
dht::Key_t a(d);
|
dht::Key_t a(d);
|
||||||
dht::Key_t b(d.data());
|
dht::Key_t b(d.data());
|
||||||
dht::Key_t c;
|
dht::Key_t c;
|
||||||
|
|
||||||
ASSERT_EQ(a, b);
|
REQUIRE(a == b);
|
||||||
|
|
||||||
if(a.IsZero())
|
if (a.IsZero())
|
||||||
{
|
{
|
||||||
ASSERT_EQ(a, c);
|
REQUIRE(a == c);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ASSERT_NE(a, c);
|
REQUIRE(a != c);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static constexpr Array emptyArray{
|
TEST_CASE("DHT key ==", "[dht]")
|
||||||
{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}};
|
|
||||||
|
|
||||||
static constexpr Array fullArray{
|
|
||||||
{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}};
|
|
||||||
|
|
||||||
static constexpr Array seqArray{
|
|
||||||
{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A,
|
|
||||||
0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15,
|
|
||||||
0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F}};
|
|
||||||
|
|
||||||
static const Array data[] = {emptyArray, fullArray, seqArray};
|
|
||||||
|
|
||||||
INSTANTIATE_TEST_SUITE_P(TestDhtKey, DHT, ::testing::ValuesIn(data));
|
|
||||||
|
|
||||||
TEST(TestDhtKey, eq)
|
|
||||||
{
|
{
|
||||||
ASSERT_EQ(dht::Key_t(emptyArray), dht::Key_t(emptyArray));
|
REQUIRE(dht::Key_t(emptyArray) == dht::Key_t(emptyArray));
|
||||||
ASSERT_EQ(dht::Key_t(fullArray), dht::Key_t(fullArray));
|
REQUIRE(dht::Key_t(fullArray) == dht::Key_t(fullArray));
|
||||||
ASSERT_EQ(dht::Key_t(seqArray), dht::Key_t(seqArray));
|
REQUIRE(dht::Key_t(seqArray) == dht::Key_t(seqArray));
|
||||||
}
|
|
||||||
TEST(TestDhtKey, ne)
|
|
||||||
{
|
|
||||||
ASSERT_NE(dht::Key_t(emptyArray), dht::Key_t(fullArray));
|
|
||||||
ASSERT_NE(dht::Key_t(emptyArray), dht::Key_t(seqArray));
|
|
||||||
ASSERT_NE(dht::Key_t(fullArray), dht::Key_t(seqArray));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(TestDhtKey, lt)
|
TEST_CASE("DHT key !=", "[dht]")
|
||||||
{
|
{
|
||||||
ASSERT_LT(dht::Key_t(emptyArray), dht::Key_t(fullArray));
|
REQUIRE(dht::Key_t(emptyArray) != dht::Key_t(fullArray));
|
||||||
ASSERT_LT(dht::Key_t(emptyArray), dht::Key_t(seqArray));
|
REQUIRE(dht::Key_t(emptyArray) != dht::Key_t(seqArray));
|
||||||
ASSERT_LT(dht::Key_t(seqArray), dht::Key_t(fullArray));
|
REQUIRE(dht::Key_t(fullArray) != dht::Key_t(seqArray));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(TestDhtKey, gt)
|
TEST_CASE("DHT key <", "[dht]")
|
||||||
{
|
{
|
||||||
ASSERT_GT(dht::Key_t(fullArray), dht::Key_t(emptyArray));
|
REQUIRE(dht::Key_t(emptyArray) < dht::Key_t(fullArray));
|
||||||
ASSERT_GT(dht::Key_t(seqArray), dht::Key_t(emptyArray));
|
REQUIRE(dht::Key_t(emptyArray) < dht::Key_t(seqArray));
|
||||||
ASSERT_GT(dht::Key_t(fullArray), dht::Key_t(seqArray));
|
REQUIRE(dht::Key_t(seqArray) < dht::Key_t(fullArray));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(TestDhtKey, XOR)
|
TEST_CASE("DHT key >", "[dht]")
|
||||||
{
|
{
|
||||||
ASSERT_EQ(dht::Key_t(emptyArray),
|
REQUIRE(dht::Key_t(fullArray) > dht::Key_t(emptyArray));
|
||||||
dht::Key_t(emptyArray) ^ dht::Key_t(emptyArray));
|
REQUIRE(dht::Key_t(seqArray) > dht::Key_t(emptyArray));
|
||||||
|
REQUIRE(dht::Key_t(fullArray) > dht::Key_t(seqArray));
|
||||||
|
}
|
||||||
|
|
||||||
ASSERT_EQ(dht::Key_t(seqArray),
|
TEST_CASE("DHT key ^", "[dht]")
|
||||||
dht::Key_t(emptyArray) ^ dht::Key_t(seqArray));
|
{
|
||||||
|
REQUIRE(dht::Key_t(emptyArray) == (dht::Key_t(emptyArray) ^ dht::Key_t(emptyArray)));
|
||||||
|
|
||||||
ASSERT_EQ(dht::Key_t(fullArray),
|
REQUIRE(dht::Key_t(seqArray) == (dht::Key_t(emptyArray) ^ dht::Key_t(seqArray)));
|
||||||
dht::Key_t(emptyArray) ^ dht::Key_t(fullArray));
|
|
||||||
|
|
||||||
ASSERT_EQ(dht::Key_t(emptyArray),
|
REQUIRE(dht::Key_t(fullArray) == (dht::Key_t(emptyArray) ^ dht::Key_t(fullArray)));
|
||||||
dht::Key_t(fullArray) ^ dht::Key_t(fullArray));
|
|
||||||
|
|
||||||
ASSERT_EQ(dht::Key_t(emptyArray),
|
REQUIRE(dht::Key_t(emptyArray) == (dht::Key_t(fullArray) ^ dht::Key_t(fullArray)));
|
||||||
dht::Key_t(seqArray) ^ dht::Key_t(seqArray));
|
|
||||||
|
REQUIRE(dht::Key_t(emptyArray) == (dht::Key_t(seqArray) ^ dht::Key_t(seqArray)));
|
||||||
|
|
||||||
Array xorResult;
|
Array xorResult;
|
||||||
std::iota(xorResult.rbegin(), xorResult.rend(), 0xE0);
|
std::iota(xorResult.rbegin(), xorResult.rend(), 0xE0);
|
||||||
ASSERT_EQ(dht::Key_t(xorResult),
|
REQUIRE(dht::Key_t(xorResult) == (dht::Key_t(seqArray) ^ dht::Key_t(fullArray)));
|
||||||
dht::Key_t(seqArray) ^ dht::Key_t(fullArray));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(TestDhtKey, TestBucketOperators)
|
TEST_CASE("DHT key: test bucket operators", "[dht]")
|
||||||
{
|
{
|
||||||
dht::Key_t zero;
|
dht::Key_t zero;
|
||||||
dht::Key_t one;
|
dht::Key_t one;
|
||||||
|
@ -108,16 +94,16 @@ TEST(TestDhtKey, TestBucketOperators)
|
||||||
zero.Zero();
|
zero.Zero();
|
||||||
one.Fill(1);
|
one.Fill(1);
|
||||||
three.Fill(3);
|
three.Fill(3);
|
||||||
ASSERT_LT(zero, one);
|
REQUIRE(zero < one);
|
||||||
ASSERT_LT(zero, three);
|
REQUIRE(zero < three);
|
||||||
ASSERT_FALSE(zero > one);
|
REQUIRE_FALSE(zero > one);
|
||||||
ASSERT_FALSE(zero > three);
|
REQUIRE_FALSE(zero > three);
|
||||||
ASSERT_NE(zero, three);
|
REQUIRE(zero != three);
|
||||||
ASSERT_FALSE(zero == three);
|
REQUIRE_FALSE(zero == three);
|
||||||
ASSERT_EQ(zero ^ one, one);
|
REQUIRE((zero ^ one) == one);
|
||||||
ASSERT_LT(one, three);
|
REQUIRE(one < three);
|
||||||
ASSERT_GT(three, one);
|
REQUIRE(three > one);
|
||||||
ASSERT_NE(one, three);
|
REQUIRE(one != three);
|
||||||
ASSERT_FALSE(one == three);
|
REQUIRE_FALSE(one == three);
|
||||||
ASSERT_EQ(one ^ three, three ^ one);
|
REQUIRE((one ^ three) == (three ^ one));
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,115 +2,105 @@
|
||||||
|
|
||||||
#include <test_util.hpp>
|
#include <test_util.hpp>
|
||||||
|
|
||||||
#include <gtest/gtest.h>
|
#include <catch2/catch.hpp>
|
||||||
#include <gmock/gmock.h>
|
|
||||||
|
|
||||||
using namespace llarp;
|
using namespace llarp;
|
||||||
using namespace ::testing;
|
|
||||||
|
|
||||||
using test::makeBuf;
|
using test::makeBuf;
|
||||||
|
|
||||||
struct TestDhtRCNode : public ::testing::Test
|
TEST_CASE("dht::RCNode construct", "[dht]")
|
||||||
{
|
|
||||||
};
|
|
||||||
|
|
||||||
TEST_F(TestDhtRCNode, construct)
|
|
||||||
{
|
{
|
||||||
dht::RCNode node;
|
dht::RCNode node;
|
||||||
ASSERT_THAT(node.ID, Property(&dht::Key_t::IsZero, true));
|
REQUIRE(node.ID.IsZero());
|
||||||
|
|
||||||
node.ID.Fill(0xCA);
|
node.ID.Fill(0xCA);
|
||||||
node.rc.last_updated = 101s;
|
node.rc.last_updated = 101s;
|
||||||
|
|
||||||
dht::RCNode other{node};
|
dht::RCNode other{node};
|
||||||
ASSERT_EQ(node.ID, other.ID);
|
REQUIRE(node.ID == other.ID);
|
||||||
ASSERT_EQ(node.rc, other.rc);
|
REQUIRE(node.rc == other.rc);
|
||||||
|
|
||||||
RouterContact contact;
|
RouterContact contact;
|
||||||
contact.pubkey.Randomize();
|
contact.pubkey.Randomize();
|
||||||
|
|
||||||
dht::RCNode fromContact{contact};
|
dht::RCNode fromContact{contact};
|
||||||
ASSERT_EQ(fromContact.ID.as_array(), contact.pubkey.as_array());
|
REQUIRE(fromContact.ID.as_array() == contact.pubkey.as_array());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(TestDhtRCNode, lt)
|
TEST_CASE("dht::RCNode <", "[dht]")
|
||||||
{
|
{
|
||||||
dht::RCNode one;
|
dht::RCNode one;
|
||||||
dht::RCNode two;
|
dht::RCNode two;
|
||||||
dht::RCNode three;
|
dht::RCNode three;
|
||||||
dht::RCNode eqThree;
|
dht::RCNode eqThree;
|
||||||
|
|
||||||
one.rc.last_updated = 1s;
|
one.rc.last_updated = 1s;
|
||||||
two.rc.last_updated = 2s;
|
two.rc.last_updated = 2s;
|
||||||
three.rc.last_updated = 3s;
|
three.rc.last_updated = 3s;
|
||||||
eqThree.rc.last_updated = 3s;
|
eqThree.rc.last_updated = 3s;
|
||||||
|
|
||||||
// LT cases
|
// LT cases
|
||||||
ASSERT_THAT(one, Lt(two));
|
REQUIRE(one < two);
|
||||||
ASSERT_THAT(one, Lt(three));
|
REQUIRE(one < three);
|
||||||
ASSERT_THAT(one, Lt(eqThree));
|
REQUIRE(one < eqThree);
|
||||||
ASSERT_THAT(two, Lt(three));
|
REQUIRE(two < three);
|
||||||
ASSERT_THAT(two, Lt(eqThree));
|
REQUIRE(two < eqThree);
|
||||||
|
|
||||||
// !LT cases
|
// !LT cases
|
||||||
ASSERT_THAT(one, Not(Lt(one)));
|
REQUIRE(!(one < one));
|
||||||
ASSERT_THAT(two, Not(Lt(one)));
|
REQUIRE(!(two < one));
|
||||||
ASSERT_THAT(two, Not(Lt(two)));
|
REQUIRE(!(two < two));
|
||||||
ASSERT_THAT(three, Not(Lt(one)));
|
REQUIRE(!(three < one));
|
||||||
ASSERT_THAT(three, Not(Lt(two)));
|
REQUIRE(!(three < two));
|
||||||
ASSERT_THAT(three, Not(Lt(three)));
|
REQUIRE(!(three < three));
|
||||||
ASSERT_THAT(three, Not(Lt(eqThree)));
|
REQUIRE(!(three < eqThree));
|
||||||
}
|
}
|
||||||
|
|
||||||
struct TestDhtISNode : public ::testing::Test
|
TEST_CASE("dht::ISNode construct", "[dht]")
|
||||||
{
|
|
||||||
};
|
|
||||||
|
|
||||||
TEST_F(TestDhtISNode, construct)
|
|
||||||
{
|
{
|
||||||
dht::ISNode node;
|
dht::ISNode node;
|
||||||
ASSERT_THAT(node.ID, Property(&dht::Key_t::IsZero, true));
|
REQUIRE(node.ID.IsZero());
|
||||||
|
|
||||||
node.ID.Fill(0xCA);
|
node.ID.Fill(0xCA);
|
||||||
node.introset.derivedSigningKey.Fill(0xDB);
|
node.introset.derivedSigningKey.Fill(0xDB);
|
||||||
|
|
||||||
dht::ISNode other{node};
|
dht::ISNode other{node};
|
||||||
ASSERT_EQ(node.ID, other.ID);
|
REQUIRE(node.ID == other.ID);
|
||||||
ASSERT_EQ(node.introset, other.introset);
|
REQUIRE(node.introset == other.introset);
|
||||||
|
|
||||||
service::EncryptedIntroSet introSet;
|
service::EncryptedIntroSet introSet;
|
||||||
introSet.derivedSigningKey.Randomize();
|
introSet.derivedSigningKey.Randomize();
|
||||||
|
|
||||||
dht::ISNode fromIntro{introSet};
|
dht::ISNode fromIntro{introSet};
|
||||||
|
|
||||||
ASSERT_EQ(fromIntro.ID.as_array(), introSet.derivedSigningKey);
|
REQUIRE(fromIntro.ID.as_array() == introSet.derivedSigningKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(TestDhtISNode, lt)
|
TEST_CASE("dht::ISNode <", "[dht]")
|
||||||
{
|
{
|
||||||
dht::ISNode one;
|
dht::ISNode one;
|
||||||
dht::ISNode two;
|
dht::ISNode two;
|
||||||
dht::ISNode three;
|
dht::ISNode three;
|
||||||
dht::ISNode eqThree;
|
dht::ISNode eqThree;
|
||||||
|
|
||||||
one.introset.signedAt = 1s;
|
one.introset.signedAt = 1s;
|
||||||
two.introset.signedAt = 2s;
|
two.introset.signedAt = 2s;
|
||||||
three.introset.signedAt = 3s;
|
three.introset.signedAt = 3s;
|
||||||
eqThree.introset.signedAt = 3s;
|
eqThree.introset.signedAt = 3s;
|
||||||
|
|
||||||
// LT cases
|
// LT cases
|
||||||
ASSERT_THAT(one, Lt(two));
|
REQUIRE(one < two);
|
||||||
ASSERT_THAT(one, Lt(three));
|
REQUIRE(one < three);
|
||||||
ASSERT_THAT(one, Lt(eqThree));
|
REQUIRE(one < eqThree);
|
||||||
ASSERT_THAT(two, Lt(three));
|
REQUIRE(two < three);
|
||||||
ASSERT_THAT(two, Lt(eqThree));
|
REQUIRE(two < eqThree);
|
||||||
|
|
||||||
// !LT cases
|
// !LT cases
|
||||||
ASSERT_THAT(one, Not(Lt(one)));
|
REQUIRE(!(one < one));
|
||||||
ASSERT_THAT(two, Not(Lt(one)));
|
REQUIRE(!(two < one));
|
||||||
ASSERT_THAT(two, Not(Lt(two)));
|
REQUIRE(!(two < two));
|
||||||
ASSERT_THAT(three, Not(Lt(one)));
|
REQUIRE(!(three < one));
|
||||||
ASSERT_THAT(three, Not(Lt(two)));
|
REQUIRE(!(three < two));
|
||||||
ASSERT_THAT(three, Not(Lt(three)));
|
REQUIRE(!(three < three));
|
||||||
ASSERT_THAT(three, Not(Lt(eqThree)));
|
REQUIRE(!(three < eqThree));
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
#include <service/tag.hpp>
|
#include <service/tag.hpp>
|
||||||
#include <test_util.hpp>
|
#include <test_util.hpp>
|
||||||
|
|
||||||
#include <gtest/gtest.h>
|
#include <catch2/catch.hpp>
|
||||||
#include <gmock/gmock.h>
|
#include <gmock/gmock.h>
|
||||||
|
|
||||||
using namespace llarp;
|
using namespace llarp;
|
||||||
|
@ -13,13 +13,11 @@ using llarp::test::makeBuf;
|
||||||
using Val_t = llarp::service::Tag;
|
using Val_t = llarp::service::Tag;
|
||||||
|
|
||||||
// Mock implementation of TX.
|
// Mock implementation of TX.
|
||||||
struct TestTx final : public dht::TX< dht::Key_t, Val_t >
|
struct TestTx : public dht::TX<dht::Key_t, Val_t>
|
||||||
{
|
{
|
||||||
TestTx(const dht::TXOwner& asker, const dht::Key_t& k,
|
TestTx(const dht::TXOwner& asker, const dht::Key_t& k, dht::AbstractContext* p)
|
||||||
dht::AbstractContext* p)
|
: dht::TX<dht::Key_t, Val_t>(asker, k, p)
|
||||||
: dht::TX< dht::Key_t, Val_t >(asker, k, p)
|
{}
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
MOCK_CONST_METHOD1(Validate, bool(const Val_t&));
|
MOCK_CONST_METHOD1(Validate, bool(const Val_t&));
|
||||||
|
|
||||||
|
@ -28,18 +26,23 @@ struct TestTx final : public dht::TX< dht::Key_t, Val_t >
|
||||||
MOCK_METHOD0(SendReply, void());
|
MOCK_METHOD0(SendReply, void());
|
||||||
};
|
};
|
||||||
|
|
||||||
struct TestDhtTx : public Test
|
struct TestDhtTx
|
||||||
{
|
{
|
||||||
dht::TXOwner asker;
|
dht::TXOwner asker;
|
||||||
dht::Key_t m_key;
|
dht::Key_t m_key;
|
||||||
TestTx tx;
|
TestTx tx;
|
||||||
|
|
||||||
TestDhtTx() : tx(asker, m_key, nullptr)
|
TestDhtTx() : tx(asker, m_key, nullptr)
|
||||||
|
{}
|
||||||
|
|
||||||
|
~TestDhtTx()
|
||||||
{
|
{
|
||||||
|
CHECK(Mock::VerifyAndClearExpectations(&tx));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
TEST_F(TestDhtTx, on_found)
|
// TODO: sections?
|
||||||
|
TEST_CASE_METHOD(TestDhtTx, "on_found", "[dht]")
|
||||||
{
|
{
|
||||||
// Concerns
|
// Concerns
|
||||||
// - Validate returns true
|
// - Validate returns true
|
||||||
|
@ -48,7 +51,7 @@ TEST_F(TestDhtTx, on_found)
|
||||||
// - Repeated call on failure
|
// - Repeated call on failure
|
||||||
// - Repeated call on success after failure
|
// - Repeated call on success after failure
|
||||||
|
|
||||||
const auto key = makeBuf< dht::Key_t >(0x00);
|
const auto key = makeBuf<dht::Key_t>(0x00);
|
||||||
Val_t val("good value");
|
Val_t val("good value");
|
||||||
|
|
||||||
// Validate returns true
|
// Validate returns true
|
||||||
|
@ -57,19 +60,19 @@ TEST_F(TestDhtTx, on_found)
|
||||||
|
|
||||||
tx.OnFound(key, val);
|
tx.OnFound(key, val);
|
||||||
|
|
||||||
ASSERT_THAT(tx.peersAsked, Contains(key));
|
REQUIRE(tx.peersAsked.count(key) > 0);
|
||||||
ASSERT_THAT(tx.valuesFound, Contains(val));
|
REQUIRE_THAT(tx.valuesFound, Catch::VectorContains(val));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Repeated call on success
|
// Repeated call on success
|
||||||
{
|
{
|
||||||
EXPECT_CALL(tx, Validate(val)).WillOnce(Return(true));
|
EXPECT_CALL(tx, Validate(val)).WillOnce(Return(true));
|
||||||
tx.OnFound(key, val);
|
tx.OnFound(key, val);
|
||||||
ASSERT_THAT(tx.peersAsked, Contains(key));
|
REQUIRE(tx.peersAsked.count(key) > 0);
|
||||||
ASSERT_THAT(tx.valuesFound, Contains(val));
|
REQUIRE_THAT(tx.valuesFound, Catch::VectorContains(val));
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto key1 = makeBuf< dht::Key_t >(0x01);
|
const auto key1 = makeBuf<dht::Key_t>(0x01);
|
||||||
Val_t badVal("bad value");
|
Val_t badVal("bad value");
|
||||||
|
|
||||||
// Validate returns false
|
// Validate returns false
|
||||||
|
@ -78,8 +81,8 @@ TEST_F(TestDhtTx, on_found)
|
||||||
|
|
||||||
tx.OnFound(key1, badVal);
|
tx.OnFound(key1, badVal);
|
||||||
|
|
||||||
ASSERT_THAT(tx.peersAsked, Contains(key1));
|
REQUIRE(tx.peersAsked.count(key1) > 0);
|
||||||
ASSERT_THAT(tx.valuesFound, Not(Contains(badVal)));
|
REQUIRE_THAT(tx.valuesFound, !Catch::VectorContains(badVal));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Repeated call on failure
|
// Repeated call on failure
|
||||||
|
@ -88,8 +91,8 @@ TEST_F(TestDhtTx, on_found)
|
||||||
|
|
||||||
tx.OnFound(key1, badVal);
|
tx.OnFound(key1, badVal);
|
||||||
|
|
||||||
ASSERT_THAT(tx.peersAsked, Contains(key1));
|
REQUIRE(tx.peersAsked.count(key1) > 0);
|
||||||
ASSERT_THAT(tx.valuesFound, Not(Contains(badVal)));
|
REQUIRE_THAT(tx.valuesFound, !Catch::VectorContains(badVal));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Repeated call on success after failure
|
// Repeated call on success after failure
|
||||||
|
@ -98,8 +101,7 @@ TEST_F(TestDhtTx, on_found)
|
||||||
|
|
||||||
tx.OnFound(key1, badVal);
|
tx.OnFound(key1, badVal);
|
||||||
|
|
||||||
ASSERT_THAT(tx.peersAsked, Contains(key1));
|
REQUIRE(tx.peersAsked.count(key1) > 0);
|
||||||
ASSERT_THAT(tx.valuesFound, Contains(badVal));
|
REQUIRE_THAT(tx.valuesFound, Catch::VectorContains(badVal));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
#include <dht/txowner.hpp>
|
#include <dht/txowner.hpp>
|
||||||
|
|
||||||
#include <gtest/gtest.h>
|
#include <catch2/catch.hpp>
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
|
@ -13,37 +13,22 @@ namespace
|
||||||
uint64_t id;
|
uint64_t id;
|
||||||
size_t expectedHash;
|
size_t expectedHash;
|
||||||
|
|
||||||
TxOwnerData(const Key_t& k, uint64_t i, size_t h)
|
TxOwnerData(const Key_t& k, uint64_t i, size_t h) : node(k), id(i), expectedHash(h)
|
||||||
: node(k), id(i), expectedHash(h)
|
{}
|
||||||
{
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct TxOwner : public ::testing::TestWithParam< TxOwnerData >
|
TEST_CASE("TxOwner default construct", "[dht]")
|
||||||
{
|
|
||||||
};
|
|
||||||
|
|
||||||
TEST_F(TxOwner, default_construct)
|
|
||||||
{
|
{
|
||||||
TXOwner dc;
|
TXOwner dc;
|
||||||
ASSERT_TRUE(dc.node.IsZero());
|
REQUIRE(dc.node.IsZero());
|
||||||
ASSERT_EQ(0u, dc.txid);
|
REQUIRE(0u == dc.txid);
|
||||||
ASSERT_EQ(0u, TXOwner::Hash()(dc));
|
REQUIRE(0u == TXOwner::Hash()(dc));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_P(TxOwner, hash)
|
std::vector<TxOwnerData>
|
||||||
{
|
|
||||||
// test single interactions (constructor and hash)
|
|
||||||
auto d = GetParam();
|
|
||||||
TXOwner constructor(d.node, d.id);
|
|
||||||
|
|
||||||
ASSERT_EQ(d.expectedHash, TXOwner::Hash()(constructor));
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector< TxOwnerData >
|
|
||||||
makeData()
|
makeData()
|
||||||
{
|
{
|
||||||
std::vector< TxOwnerData > result;
|
std::vector<TxOwnerData> result;
|
||||||
|
|
||||||
Key_t zero;
|
Key_t zero;
|
||||||
zero.Zero();
|
zero.Zero();
|
||||||
|
@ -52,7 +37,7 @@ namespace
|
||||||
Key_t two;
|
Key_t two;
|
||||||
two.Fill(0x02);
|
two.Fill(0x02);
|
||||||
|
|
||||||
uint64_t max = std::numeric_limits< uint64_t >::max();
|
uint64_t max = std::numeric_limits<uint64_t>::max();
|
||||||
|
|
||||||
result.emplace_back(zero, 0, 0ull);
|
result.emplace_back(zero, 0, 0ull);
|
||||||
result.emplace_back(zero, 1, 1ull);
|
result.emplace_back(zero, 1, 1ull);
|
||||||
|
@ -67,6 +52,15 @@ namespace
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE("TxOwner hash", "[dht]")
|
||||||
|
{
|
||||||
|
// test single interactions (constructor and hash)
|
||||||
|
auto d = GENERATE(from_range(makeData()));
|
||||||
|
TXOwner constructor(d.node, d.id);
|
||||||
|
|
||||||
|
REQUIRE(d.expectedHash == TXOwner::Hash()(constructor));
|
||||||
|
}
|
||||||
|
|
||||||
struct TxOwnerCmpData
|
struct TxOwnerCmpData
|
||||||
{
|
{
|
||||||
TXOwner lhs;
|
TXOwner lhs;
|
||||||
|
@ -76,27 +70,13 @@ namespace
|
||||||
|
|
||||||
TxOwnerCmpData(const TXOwner& l, const TXOwner& r, bool e, bool ls)
|
TxOwnerCmpData(const TXOwner& l, const TXOwner& r, bool e, bool ls)
|
||||||
: lhs(l), rhs(r), equal(e), less(ls)
|
: lhs(l), rhs(r), equal(e), less(ls)
|
||||||
{
|
{}
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct TxOwnerOps : public ::testing::TestWithParam< TxOwnerCmpData >
|
std::vector<TxOwnerCmpData>
|
||||||
{
|
|
||||||
};
|
|
||||||
|
|
||||||
TEST_P(TxOwnerOps, operators)
|
|
||||||
{
|
|
||||||
// test single interactions (constructor and hash)
|
|
||||||
auto d = GetParam();
|
|
||||||
|
|
||||||
ASSERT_EQ(d.lhs == d.rhs, d.equal);
|
|
||||||
ASSERT_EQ(d.lhs < d.rhs, d.less);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector< TxOwnerCmpData >
|
|
||||||
makeCmpData()
|
makeCmpData()
|
||||||
{
|
{
|
||||||
std::vector< TxOwnerCmpData > result;
|
std::vector<TxOwnerCmpData> result;
|
||||||
|
|
||||||
Key_t zero;
|
Key_t zero;
|
||||||
zero.Fill(0x00);
|
zero.Fill(0x00);
|
||||||
|
@ -114,10 +94,13 @@ namespace
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE("TxOwner ops", "[dht]")
|
||||||
|
{
|
||||||
|
// test single interactions (constructor and hash)
|
||||||
|
auto d = GENERATE(from_range(makeCmpData()));
|
||||||
|
|
||||||
|
REQUIRE((d.lhs == d.rhs) == d.equal);
|
||||||
|
REQUIRE((d.lhs < d.rhs) == d.less);
|
||||||
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
INSTANTIATE_TEST_SUITE_P(TestDhtTxOwner, TxOwner,
|
|
||||||
::testing::ValuesIn(makeData()));
|
|
||||||
|
|
||||||
INSTANTIATE_TEST_SUITE_P(TestDhtTxOwner, TxOwnerOps,
|
|
||||||
::testing::ValuesIn(makeCmpData()));
|
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
#include <llarp_test.hpp>
|
|
|
@ -1,15 +1,16 @@
|
||||||
#ifndef LLARP_TEST
|
#ifndef LLARP_TEST
|
||||||
#define LLARP_TEST
|
#define LLARP_TEST
|
||||||
|
|
||||||
#include <gtest/gtest.h>
|
|
||||||
#include <crypto/mock_crypto.hpp>
|
#include <crypto/mock_crypto.hpp>
|
||||||
|
#include <catch2/catch.hpp>
|
||||||
|
#include <gmock/gmock.h>
|
||||||
|
|
||||||
namespace llarp
|
namespace llarp
|
||||||
{
|
{
|
||||||
namespace test
|
namespace test
|
||||||
{
|
{
|
||||||
template < typename CryptoImpl = MockCrypto >
|
template <typename CryptoImpl = MockCrypto>
|
||||||
class LlarpTest : public ::testing::Test
|
class LlarpTest
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
CryptoImpl m_crypto;
|
CryptoImpl m_crypto;
|
||||||
|
@ -17,9 +18,18 @@ namespace llarp
|
||||||
|
|
||||||
LlarpTest() : cm(&m_crypto)
|
LlarpTest() : cm(&m_crypto)
|
||||||
{
|
{
|
||||||
static_assert(std::is_base_of< Crypto, CryptoImpl >::value, "");
|
static_assert(std::is_base_of<Crypto, CryptoImpl>::value, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
~LlarpTest()
|
||||||
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
inline LlarpTest<MockCrypto>::~LlarpTest()
|
||||||
|
{
|
||||||
|
CHECK(::testing::Mock::VerifyAndClearExpectations(&m_crypto));
|
||||||
|
}
|
||||||
} // namespace test
|
} // namespace test
|
||||||
} // namespace llarp
|
} // namespace llarp
|
||||||
|
|
||||||
|
|
|
@ -1,99 +1,104 @@
|
||||||
#include <gtest/gtest.h>
|
|
||||||
|
|
||||||
#include <net/net_int.hpp>
|
#include <net/net_int.hpp>
|
||||||
#include <net/ip.hpp>
|
#include <net/ip.hpp>
|
||||||
#include <net/ip_range.hpp>
|
#include <net/ip_range.hpp>
|
||||||
#include <net/net.hpp>
|
#include <net/net.hpp>
|
||||||
|
|
||||||
struct TestNet : public ::testing::Test
|
#include <catch2/catch.hpp>
|
||||||
{
|
|
||||||
};
|
|
||||||
|
|
||||||
TEST_F(TestNet, TestIn6AddrFromString)
|
TEST_CASE("In6Addr")
|
||||||
{
|
{
|
||||||
llarp::huint128_t ip;
|
llarp::huint128_t ip;
|
||||||
ASSERT_TRUE(ip.FromString("fc00::1"));
|
|
||||||
|
SECTION("From string")
|
||||||
|
{
|
||||||
|
REQUIRE(ip.FromString("fc00::1"));
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("From string fail")
|
||||||
|
{
|
||||||
|
REQUIRE_FALSE(ip.FromString("10.1.1.1"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(TestNet, TestIn6AddrFromStringFail)
|
TEST_CASE("In6AddrToHUIntLoopback")
|
||||||
{
|
|
||||||
llarp::huint128_t ip;
|
|
||||||
ASSERT_FALSE(ip.FromString("10.1.1.1"));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(TestNet, TestIn6AddrToHUIntLoopback)
|
|
||||||
{
|
{
|
||||||
llarp::huint128_t loopback = {0};
|
llarp::huint128_t loopback = {0};
|
||||||
ASSERT_TRUE(loopback.FromString("::1"));
|
REQUIRE(loopback.FromString("::1"));
|
||||||
in6_addr addr = IN6ADDR_LOOPBACK_INIT;
|
in6_addr addr = IN6ADDR_LOOPBACK_INIT;
|
||||||
auto huint = llarp::net::In6ToHUInt(addr);
|
auto huint = llarp::net::In6ToHUInt(addr);
|
||||||
ASSERT_EQ(huint, loopback);
|
REQUIRE(huint == loopback);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(TestNet, TestIn6AddrToHUInt)
|
TEST_CASE("In6AddrToHUInt")
|
||||||
{
|
{
|
||||||
llarp::huint128_t huint_parsed = {0};
|
llarp::huint128_t huint_parsed = {0};
|
||||||
ASSERT_TRUE(huint_parsed.FromString("fd00::1"));
|
REQUIRE(huint_parsed.FromString("fd00::1"));
|
||||||
in6_addr addr = {{{0xfd, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x01}}};
|
in6_addr addr = {{{0xfd, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x01}}};
|
||||||
auto huint = llarp::net::In6ToHUInt(addr);
|
auto huint = llarp::net::In6ToHUInt(addr);
|
||||||
ASSERT_EQ(huint, huint_parsed);
|
REQUIRE(huint == huint_parsed);
|
||||||
huint_parsed.h++;
|
huint_parsed.h++;
|
||||||
ASSERT_NE(huint, huint_parsed);
|
REQUIRE(huint != huint_parsed);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(TestNet, TestRangeContains8)
|
TEST_CASE("Range")
|
||||||
{
|
{
|
||||||
ASSERT_TRUE(
|
SECTION("Contains 8")
|
||||||
llarp::IPRange::FromIPv4(10, 0, 0, 1, 8).Contains(llarp::ipaddr_ipv4_bits(10, 40, 11, 6)));
|
{
|
||||||
|
REQUIRE(
|
||||||
|
llarp::IPRange::FromIPv4(10, 0, 0, 1, 8).Contains(llarp::ipaddr_ipv4_bits(10, 40, 11, 6)));
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("Contains 24")
|
||||||
|
{
|
||||||
|
REQUIRE(llarp::IPRange::FromIPv4(10, 200, 0, 1, 24)
|
||||||
|
.Contains(llarp::ipaddr_ipv4_bits(10, 200, 0, 253)));
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("Contains fail")
|
||||||
|
{
|
||||||
|
REQUIRE(!llarp::IPRange::FromIPv4(192, 168, 0, 1, 24)
|
||||||
|
.Contains(llarp::ipaddr_ipv4_bits(10, 200, 0, 253)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(TestNet, TestRangeContains24)
|
TEST_CASE("IPv4 netmask")
|
||||||
{
|
{
|
||||||
ASSERT_TRUE(llarp::IPRange::FromIPv4(10, 200, 0, 1, 24)
|
REQUIRE(llarp::netmask_ipv4_bits(8) == llarp::huint32_t{0xFF000000});
|
||||||
.Contains(llarp::ipaddr_ipv4_bits(10, 200, 0, 253)));
|
REQUIRE(llarp::netmask_ipv4_bits(24) == llarp::huint32_t{0xFFFFFF00});
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(TestNet, TestRangeContainsFail)
|
TEST_CASE("Bogon")
|
||||||
{
|
{
|
||||||
ASSERT_TRUE(!llarp::IPRange::FromIPv4(192, 168, 0, 1, 24)
|
SECTION("Bogon_10_8")
|
||||||
.Contains(llarp::ipaddr_ipv4_bits(10, 200, 0, 253)));
|
{
|
||||||
}
|
REQUIRE(llarp::IsIPv4Bogon(llarp::ipaddr_ipv4_bits(10, 40, 11, 6)));
|
||||||
|
}
|
||||||
|
|
||||||
TEST_F(TestNet, TestIPv4Netmask)
|
SECTION("Bogon_192_168_16")
|
||||||
{
|
{
|
||||||
ASSERT_TRUE(llarp::netmask_ipv4_bits(8) == llarp::huint32_t{0xFF000000});
|
REQUIRE(llarp::IsIPv4Bogon(llarp::ipaddr_ipv4_bits(192, 168, 1, 111)));
|
||||||
ASSERT_TRUE(llarp::netmask_ipv4_bits(24) == llarp::huint32_t{0xFFFFFF00});
|
}
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(TestNet, TestBogon_10_8)
|
SECTION("Bogon_DoD_8")
|
||||||
{
|
{
|
||||||
ASSERT_TRUE(llarp::IsIPv4Bogon(llarp::ipaddr_ipv4_bits(10, 40, 11, 6)));
|
REQUIRE(llarp::IsIPv4Bogon(llarp::ipaddr_ipv4_bits(21, 3, 37, 70)));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(TestNet, TestBogon_192_168_16)
|
SECTION("Bogon_127_8")
|
||||||
{
|
{
|
||||||
ASSERT_TRUE(llarp::IsIPv4Bogon(llarp::ipaddr_ipv4_bits(192, 168, 1, 111)));
|
REQUIRE(llarp::IsIPv4Bogon(llarp::ipaddr_ipv4_bits(127, 0, 0, 1)));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(TestNet, TestBogon_DoD_8)
|
SECTION("Bogon_0_8")
|
||||||
{
|
{
|
||||||
ASSERT_TRUE(llarp::IsIPv4Bogon(llarp::ipaddr_ipv4_bits(21, 3, 37, 70)));
|
REQUIRE(llarp::IsIPv4Bogon(llarp::ipaddr_ipv4_bits(0, 0, 0, 0)));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(TestNet, TestBogon_127_8)
|
SECTION("Non-bogon")
|
||||||
{
|
{
|
||||||
ASSERT_TRUE(llarp::IsIPv4Bogon(llarp::ipaddr_ipv4_bits(127, 0, 0, 1)));
|
REQUIRE_FALSE(llarp::IsIPv4Bogon(llarp::ipaddr_ipv4_bits(1, 1, 1, 1)));
|
||||||
}
|
REQUIRE_FALSE(llarp::IsIPv4Bogon(llarp::ipaddr_ipv4_bits(8, 8, 6, 6)));
|
||||||
|
REQUIRE_FALSE(llarp::IsIPv4Bogon(llarp::ipaddr_ipv4_bits(141, 55, 12, 99)));
|
||||||
TEST_F(TestNet, TestBogon_0_8)
|
REQUIRE_FALSE(llarp::IsIPv4Bogon(llarp::ipaddr_ipv4_bits(79, 12, 3, 4)));
|
||||||
{
|
}
|
||||||
ASSERT_TRUE(llarp::IsIPv4Bogon(llarp::ipaddr_ipv4_bits(0, 0, 0, 0)));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(TestNet, TestBogon_NonBogon)
|
|
||||||
{
|
|
||||||
ASSERT_FALSE(llarp::IsIPv4Bogon(llarp::ipaddr_ipv4_bits(1, 1, 1, 1)));
|
|
||||||
ASSERT_FALSE(llarp::IsIPv4Bogon(llarp::ipaddr_ipv4_bits(8, 8, 6, 6)));
|
|
||||||
ASSERT_FALSE(llarp::IsIPv4Bogon(llarp::ipaddr_ipv4_bits(141, 55, 12, 99)));
|
|
||||||
ASSERT_FALSE(llarp::IsIPv4Bogon(llarp::ipaddr_ipv4_bits(79, 12, 3, 4)));
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,91 +1,87 @@
|
||||||
#include <gtest/gtest.h>
|
|
||||||
#include <router_version.hpp>
|
#include <router_version.hpp>
|
||||||
#include "router/router.hpp"
|
#include "router/router.hpp"
|
||||||
|
|
||||||
class TestRouterVersion : public ::testing::Test
|
#include <catch2/catch.hpp>
|
||||||
{
|
|
||||||
};
|
|
||||||
|
|
||||||
TEST_F(TestRouterVersion, TestCompatibilityWhenProtocolEqual)
|
using Catch::Matchers::Equals;
|
||||||
{
|
|
||||||
llarp::RouterVersion v1( {0, 1, 2}, 1);
|
|
||||||
llarp::RouterVersion v2( {0, 1, 2}, 1);
|
|
||||||
|
|
||||||
EXPECT_TRUE(v1.IsCompatableWith(v2));
|
TEST_CASE("Compatibility when protocol equal", "[RouterVersion]")
|
||||||
|
{
|
||||||
|
llarp::RouterVersion v1({0, 1, 2}, 1);
|
||||||
|
llarp::RouterVersion v2({0, 1, 2}, 1);
|
||||||
|
|
||||||
|
CHECK(v1.IsCompatableWith(v2));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(TestRouterVersion, TestCompatibilityWhenProtocolUnequal)
|
TEST_CASE("Compatibility when protocol unequal", "[RouterVersion]")
|
||||||
{
|
{
|
||||||
llarp::RouterVersion older( {0, 1, 2}, 1);
|
llarp::RouterVersion older({0, 1, 2}, 1);
|
||||||
llarp::RouterVersion newer( {0, 1, 2}, 2);
|
llarp::RouterVersion newer({0, 1, 2}, 2);
|
||||||
|
|
||||||
EXPECT_FALSE(older.IsCompatableWith(newer));
|
CHECK_FALSE(older.IsCompatableWith(newer));
|
||||||
EXPECT_FALSE(newer.IsCompatableWith(older));
|
CHECK_FALSE(newer.IsCompatableWith(older));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(TestRouterVersion, TestEmptyCompatibility)
|
TEST_CASE("Empty compatibility", "[RouterVersion]")
|
||||||
{
|
{
|
||||||
llarp::RouterVersion v1( {0, 0, 1}, LLARP_PROTO_VERSION);
|
llarp::RouterVersion v1({0, 0, 1}, LLARP_PROTO_VERSION);
|
||||||
|
|
||||||
EXPECT_FALSE(v1.IsCompatableWith(llarp::emptyRouterVersion));
|
CHECK_FALSE(v1.IsCompatableWith(llarp::emptyRouterVersion));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(TestRouterVersion, TestIsEmpty)
|
TEST_CASE("IsEmpty", "[RouterVersion]")
|
||||||
{
|
{
|
||||||
llarp::RouterVersion notEmpty( {0, 0, 1}, LLARP_PROTO_VERSION);
|
llarp::RouterVersion notEmpty({0, 0, 1}, LLARP_PROTO_VERSION);
|
||||||
EXPECT_FALSE(notEmpty.IsEmpty());
|
CHECK_FALSE(notEmpty.IsEmpty());
|
||||||
|
|
||||||
EXPECT_TRUE(llarp::emptyRouterVersion.IsEmpty());
|
CHECK(llarp::emptyRouterVersion.IsEmpty());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(TestRouterVersion, TestClear)
|
TEST_CASE("Clear", "[RouterVersion]")
|
||||||
{
|
{
|
||||||
llarp::RouterVersion version( {0, 0, 1}, LLARP_PROTO_VERSION);
|
llarp::RouterVersion version({0, 0, 1}, LLARP_PROTO_VERSION);
|
||||||
EXPECT_FALSE(version.IsEmpty());
|
CHECK_FALSE(version.IsEmpty());
|
||||||
|
|
||||||
version.Clear();
|
version.Clear();
|
||||||
|
|
||||||
EXPECT_TRUE(version.IsEmpty());
|
CHECK(version.IsEmpty());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(TestRouterVersion, TestBEncode)
|
TEST_CASE("BEncode", "[RouterVersion]")
|
||||||
{
|
{
|
||||||
llarp::RouterVersion v1235( {1, 2, 3}, 5);
|
llarp::RouterVersion v1235({1, 2, 3}, 5);
|
||||||
|
|
||||||
std::array< byte_t, 128 > tmp{};
|
std::array<byte_t, 128> tmp{};
|
||||||
llarp_buffer_t buf(tmp);
|
llarp_buffer_t buf(tmp);
|
||||||
|
|
||||||
EXPECT_TRUE(v1235.BEncode(&buf));
|
CHECK(v1235.BEncode(&buf));
|
||||||
|
|
||||||
std::string s((const char*)buf.begin(), (buf.end() - buf.begin()));
|
std::string s((const char*)buf.begin(), (buf.end() - buf.begin()));
|
||||||
LogInfo("bencoded: ", buf.begin());
|
LogInfo("bencoded: ", buf.begin());
|
||||||
|
|
||||||
EXPECT_STREQ((const char*)buf.begin(), "li5ei1ei2ei3ee");
|
CHECK_THAT((const char*)buf.begin(), Equals("li5ei1ei2ei3ee"));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(TestRouterVersion, TestBDecode)
|
TEST_CASE("BDecode", "[RouterVersion]")
|
||||||
{
|
{
|
||||||
llarp::RouterVersion version;
|
llarp::RouterVersion version;
|
||||||
version.Clear();
|
version.Clear();
|
||||||
|
|
||||||
const std::string bString("li9ei3ei2ei1ee");
|
const std::string bString("li9ei3ei2ei1ee");
|
||||||
llarp_buffer_t buf(bString.data(), bString.size());
|
llarp_buffer_t buf(bString.data(), bString.size());
|
||||||
EXPECT_TRUE(version.BDecode(&buf));
|
CHECK(version.BDecode(&buf));
|
||||||
|
|
||||||
llarp::RouterVersion expected( {3, 2, 1}, 9);
|
llarp::RouterVersion expected({3, 2, 1}, 9);
|
||||||
|
|
||||||
EXPECT_EQ(expected, version);
|
|
||||||
|
|
||||||
|
CHECK(expected == version);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(TestRouterVersion, TestDecodeLongVersionArray)
|
TEST_CASE("Decode long version array", "[RouterVersion]")
|
||||||
{
|
{
|
||||||
llarp::RouterVersion version;
|
llarp::RouterVersion version;
|
||||||
version.Clear();
|
version.Clear();
|
||||||
|
|
||||||
const std::string bString("li9ei3ei2ei1ei2ei3ei4ei5ei6ei7ei8ei9ee");
|
const std::string bString("li9ei3ei2ei1ei2ei3ei4ei5ei6ei7ei8ei9ee");
|
||||||
llarp_buffer_t buf(bString.data(), bString.size());
|
llarp_buffer_t buf(bString.data(), bString.size());
|
||||||
EXPECT_FALSE(version.BDecode(&buf));
|
CHECK_FALSE(version.BDecode(&buf));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,24 +0,0 @@
|
||||||
#include <gtest/gtest.h>
|
|
||||||
#include <routing/transfer_traffic_message.hpp>
|
|
||||||
|
|
||||||
using TransferTrafficMessage = llarp::routing::TransferTrafficMessage;
|
|
||||||
|
|
||||||
class TransferTrafficTest : public ::testing::Test
|
|
||||||
{
|
|
||||||
};
|
|
||||||
|
|
||||||
TEST_F(TransferTrafficTest, TestPutBufferOverflow)
|
|
||||||
{
|
|
||||||
TransferTrafficMessage msg;
|
|
||||||
std::array< byte_t, llarp::routing::MaxExitMTU* 2 > tmp = {{0}};
|
|
||||||
llarp_buffer_t buf(tmp);
|
|
||||||
ASSERT_FALSE(msg.PutBuffer(buf, 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(TransferTrafficTest, TestPutBuffer)
|
|
||||||
{
|
|
||||||
TransferTrafficMessage msg;
|
|
||||||
std::array< byte_t, llarp::routing::MaxExitMTU > tmp = {{0}};
|
|
||||||
llarp_buffer_t buf(tmp);
|
|
||||||
ASSERT_TRUE(msg.PutBuffer(buf, 1));
|
|
||||||
}
|
|
|
@ -2,45 +2,37 @@
|
||||||
|
|
||||||
#include <crypto/crypto.hpp>
|
#include <crypto/crypto.hpp>
|
||||||
#include <crypto/crypto_libsodium.hpp>
|
#include <crypto/crypto_libsodium.hpp>
|
||||||
|
#include <crypto/mock_crypto.hpp>
|
||||||
#include <llarp_test.hpp>
|
#include <llarp_test.hpp>
|
||||||
|
|
||||||
#include <gtest/gtest.h>
|
|
||||||
#include <gmock/gmock.h>
|
#include <gmock/gmock.h>
|
||||||
|
|
||||||
|
#include <catch2/catch.hpp>
|
||||||
|
|
||||||
using namespace ::testing;
|
using namespace ::testing;
|
||||||
using namespace ::llarp;
|
using namespace ::llarp;
|
||||||
|
using namespace ::llarp::test;
|
||||||
|
|
||||||
using ObtainExitMessage = routing::ObtainExitMessage;
|
using ObtainExitMessage = routing::ObtainExitMessage;
|
||||||
|
|
||||||
class ObtainExitTest : public test::LlarpTest<>
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
SecretKey alice;
|
|
||||||
|
|
||||||
ObtainExitTest()
|
|
||||||
{
|
|
||||||
// m_crypto.identity_keygen(alice);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
void
|
void
|
||||||
fill(Signature& s)
|
fill(Signature& s)
|
||||||
{
|
{
|
||||||
s.Fill(0xFF);
|
s.Fill(0xFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ObtainExitTest, TestSignVerify)
|
TEST_CASE_METHOD(LlarpTest<>, "Sign-verify")
|
||||||
{
|
{
|
||||||
EXPECT_CALL(m_crypto, sign(_, alice, _))
|
SecretKey alice;
|
||||||
.WillOnce(DoAll(WithArg< 0 >(Invoke(&fill)), Return(true)));
|
EXPECT_CALL(m_crypto, sign(_, alice, _)).WillOnce(DoAll(WithArg<0>(Invoke(&fill)), Return(true)));
|
||||||
EXPECT_CALL(m_crypto, verify(_, _, _)).WillOnce(Return(true));
|
EXPECT_CALL(m_crypto, verify(_, _, _)).WillOnce(Return(true));
|
||||||
ObtainExitMessage msg;
|
ObtainExitMessage msg;
|
||||||
msg.Z.Zero();
|
msg.Z.Zero();
|
||||||
msg.S = randint();
|
msg.S = randint();
|
||||||
msg.T = randint();
|
msg.T = randint();
|
||||||
EXPECT_TRUE(msg.Sign(alice));
|
CHECK(msg.Sign(alice));
|
||||||
EXPECT_TRUE(msg.Verify());
|
CHECK(msg.Verify());
|
||||||
EXPECT_TRUE(msg.I == PubKey(seckey_topublic(alice)));
|
CHECK(msg.I == PubKey(seckey_topublic(alice)));
|
||||||
EXPECT_FALSE(msg.version != LLARP_PROTO_VERSION);
|
CHECK(msg.version == LLARP_PROTO_VERSION);
|
||||||
EXPECT_FALSE(msg.Z.IsZero());
|
CHECK_FALSE(msg.Z.IsZero());
|
||||||
}
|
}
|
||||||
|
|
24
test/routing/test_llarp_routing_transfer_traffic.cpp
Normal file
24
test/routing/test_llarp_routing_transfer_traffic.cpp
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
#include <routing/transfer_traffic_message.hpp>
|
||||||
|
|
||||||
|
#include <catch2/catch.hpp>
|
||||||
|
|
||||||
|
using TransferTrafficMessage = llarp::routing::TransferTrafficMessage;
|
||||||
|
|
||||||
|
TEST_CASE("TransferTrafficMessage", "[TransferTrafficMessage]")
|
||||||
|
{
|
||||||
|
TransferTrafficMessage msg;
|
||||||
|
|
||||||
|
SECTION("Put buffer overflow")
|
||||||
|
{
|
||||||
|
std::array<byte_t, llarp::routing::MaxExitMTU* 2> tmp = {{0}};
|
||||||
|
llarp_buffer_t buf(tmp);
|
||||||
|
REQUIRE_FALSE(msg.PutBuffer(buf, 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("Put buffer")
|
||||||
|
{
|
||||||
|
std::array<byte_t, llarp::routing::MaxExitMTU> tmp = {{0}};
|
||||||
|
llarp_buffer_t buf(tmp);
|
||||||
|
REQUIRE(msg.PutBuffer(buf, 1));
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,67 +1,58 @@
|
||||||
#include <service/address.hpp>
|
#include <service/address.hpp>
|
||||||
|
|
||||||
#include <gtest/gtest.h>
|
#include <catch2/catch.hpp>
|
||||||
|
|
||||||
struct ServiceAddressTest : public ::testing::Test
|
TEST_CASE("Address", "[Address]")
|
||||||
{
|
{
|
||||||
const std::string snode =
|
const std::string snode = "8zfiwpgonsu5zpddpxwdurxyb19x6r96xy4qbikff99jwsziws9y.snode";
|
||||||
"8zfiwpgonsu5zpddpxwdurxyb19x6r96xy4qbikff99jwsziws9y.snode";
|
const std::string loki = "7okic5x5do3uh3usttnqz9ek3uuoemdrwzto1hciwim9f947or6y.loki";
|
||||||
const std::string loki =
|
|
||||||
"7okic5x5do3uh3usttnqz9ek3uuoemdrwzto1hciwim9f947or6y.loki";
|
|
||||||
const std::string sub = "lokinet.test";
|
const std::string sub = "lokinet.test";
|
||||||
const std::string invalid =
|
const std::string invalid = "7okic5x5do3uh3usttnqz9ek3uuoemdrwzto1hciwim9f947or6y.net";
|
||||||
"7okic5x5do3uh3usttnqz9ek3uuoemdrwzto1hciwim9f947or6y.net";
|
|
||||||
};
|
|
||||||
|
|
||||||
TEST_F(ServiceAddressTest, TestParseBadTLD)
|
|
||||||
{
|
|
||||||
llarp::service::Address addr;
|
llarp::service::Address addr;
|
||||||
ASSERT_FALSE(addr.FromString(snode, ".net"));
|
|
||||||
ASSERT_FALSE(addr.FromString(invalid, ".net"));
|
SECTION("Parse bad TLD")
|
||||||
|
{
|
||||||
|
REQUIRE_FALSE(addr.FromString(snode, ".net"));
|
||||||
|
REQUIRE_FALSE(addr.FromString(invalid, ".net"));
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("Parse bad TLD appened on end")
|
||||||
|
{
|
||||||
|
const std::string bad = loki + ".net";
|
||||||
|
REQUIRE_FALSE(addr.FromString(bad, ".net"));
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("Parse bad TLD appened on end with subdomain")
|
||||||
|
{
|
||||||
|
const std::string bad = sub + "." + loki + ".net";
|
||||||
|
REQUIRE_FALSE(addr.FromString(bad, ".net"));
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("Parse SNode not Loki")
|
||||||
|
{
|
||||||
|
REQUIRE(addr.FromString(snode, ".snode"));
|
||||||
|
REQUIRE_FALSE(addr.FromString(snode, ".loki"));
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("Parse Loki not SNode")
|
||||||
|
{
|
||||||
|
REQUIRE_FALSE(addr.FromString(loki, ".snode"));
|
||||||
|
REQUIRE(addr.FromString(loki, ".loki"));
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("Parse Loki with subdomain")
|
||||||
|
{
|
||||||
|
const std::string addr_str = sub + "." + loki;
|
||||||
|
REQUIRE(addr.FromString(addr_str, ".loki"));
|
||||||
|
REQUIRE(addr.subdomain == sub);
|
||||||
|
REQUIRE(addr.ToString() == addr_str);
|
||||||
|
};
|
||||||
|
|
||||||
|
SECTION("Parse SNode with subdomain")
|
||||||
|
{
|
||||||
|
const std::string addr_str = sub + "." + snode;
|
||||||
|
REQUIRE(addr.FromString(addr_str, ".snode"));
|
||||||
|
REQUIRE(addr.subdomain == sub);
|
||||||
|
REQUIRE(addr.ToString(".snode") == addr_str);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ServiceAddressTest, TestParseBadTLDAppenedOnEnd)
|
|
||||||
{
|
|
||||||
llarp::service::Address addr;
|
|
||||||
const std::string bad = loki + ".net";
|
|
||||||
ASSERT_FALSE(addr.FromString(bad, ".net"));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(ServiceAddressTest, TestParseBadTLDAppenedOnEndWithSubdomain)
|
|
||||||
{
|
|
||||||
llarp::service::Address addr;
|
|
||||||
const std::string bad = sub + "." + loki + ".net";
|
|
||||||
ASSERT_FALSE(addr.FromString(bad, ".net"));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(ServiceAddressTest, TestParseSNodeNotLoki)
|
|
||||||
{
|
|
||||||
llarp::service::Address addr;
|
|
||||||
ASSERT_TRUE(addr.FromString(snode, ".snode"));
|
|
||||||
ASSERT_FALSE(addr.FromString(snode, ".loki"));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(ServiceAddressTest, TestParseLokiNotSNode)
|
|
||||||
{
|
|
||||||
llarp::service::Address addr;
|
|
||||||
ASSERT_FALSE(addr.FromString(loki, ".snode"));
|
|
||||||
ASSERT_TRUE(addr.FromString(loki, ".loki"));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(ServiceAddressTest, TestParseLokiWithSubdomain)
|
|
||||||
{
|
|
||||||
llarp::service::Address addr;
|
|
||||||
const std::string addr_str = sub + "." + loki;
|
|
||||||
ASSERT_TRUE(addr.FromString(addr_str, ".loki"));
|
|
||||||
ASSERT_EQ(addr.subdomain, sub);
|
|
||||||
ASSERT_EQ(addr.ToString(), addr_str);
|
|
||||||
};
|
|
||||||
|
|
||||||
TEST_F(ServiceAddressTest, TestParseSnodeWithSubdomain)
|
|
||||||
{
|
|
||||||
llarp::service::Address addr;
|
|
||||||
const std::string addr_str = sub + "." + snode;
|
|
||||||
ASSERT_TRUE(addr.FromString(addr_str, ".snode"));
|
|
||||||
ASSERT_EQ(addr.subdomain, sub);
|
|
||||||
ASSERT_EQ(addr.ToString(".snode"), addr_str);
|
|
||||||
};
|
|
||||||
|
|
|
@ -7,15 +7,15 @@
|
||||||
|
|
||||||
#include <test_util.hpp>
|
#include <test_util.hpp>
|
||||||
|
|
||||||
#include <gtest/gtest.h>
|
#include <catch2/catch.hpp>
|
||||||
|
|
||||||
using namespace ::llarp;
|
using namespace ::llarp;
|
||||||
using namespace ::testing;
|
using namespace ::testing;
|
||||||
|
|
||||||
using EncryptedFrame = EncryptedFrame;
|
using EncryptedFrame = EncryptedFrame;
|
||||||
using SecretKey = SecretKey;
|
using SecretKey = SecretKey;
|
||||||
using PubKey = PubKey;
|
using PubKey = PubKey;
|
||||||
using LRCR = LR_CommitRecord;
|
using LRCR = LR_CommitRecord;
|
||||||
|
|
||||||
class FrameTest : public test::LlarpTest<>
|
class FrameTest : public test::LlarpTest<>
|
||||||
{
|
{
|
||||||
|
@ -23,7 +23,7 @@ class FrameTest : public test::LlarpTest<>
|
||||||
SecretKey alice, bob;
|
SecretKey alice, bob;
|
||||||
};
|
};
|
||||||
|
|
||||||
TEST_F(FrameTest, TestFrameCrypto)
|
TEST_CASE_METHOD(FrameTest, "Frame crypto")
|
||||||
{
|
{
|
||||||
EncryptedFrame f(256);
|
EncryptedFrame f(256);
|
||||||
f.Fill(0);
|
f.Fill(0);
|
||||||
|
@ -36,28 +36,25 @@ TEST_F(FrameTest, TestFrameCrypto)
|
||||||
auto buf = f.Buffer();
|
auto buf = f.Buffer();
|
||||||
buf->cur = buf->base + EncryptedFrameOverheadSize;
|
buf->cur = buf->base + EncryptedFrameOverheadSize;
|
||||||
|
|
||||||
ASSERT_TRUE(record.BEncode(buf));
|
REQUIRE(record.BEncode(buf));
|
||||||
|
|
||||||
EXPECT_CALL(m_crypto, randbytes(_, _))
|
EXPECT_CALL(m_crypto, randbytes(_, _)).WillOnce(Invoke(&test::randbytes_impl));
|
||||||
.WillOnce(Invoke(&test::randbytes_impl));
|
|
||||||
|
|
||||||
EXPECT_CALL(m_crypto, dh_client(_, _, alice, _)).WillOnce(Return(true));
|
EXPECT_CALL(m_crypto, dh_client(_, _, alice, _)).WillOnce(Return(true));
|
||||||
EXPECT_CALL(m_crypto, xchacha20(_, _, _))
|
EXPECT_CALL(m_crypto, xchacha20(_, _, _)).Times(2).WillRepeatedly(Return(true));
|
||||||
.Times(2)
|
|
||||||
.WillRepeatedly(Return(true));
|
|
||||||
EXPECT_CALL(m_crypto, hmac(_, _, _)).Times(2).WillRepeatedly(Return(true));
|
EXPECT_CALL(m_crypto, hmac(_, _, _)).Times(2).WillRepeatedly(Return(true));
|
||||||
|
|
||||||
// rewind buffer
|
// rewind buffer
|
||||||
buf->cur = buf->base + EncryptedFrameOverheadSize;
|
buf->cur = buf->base + EncryptedFrameOverheadSize;
|
||||||
// encrypt to alice
|
// encrypt to alice
|
||||||
ASSERT_TRUE(f.EncryptInPlace(alice, bob.toPublic()));
|
REQUIRE(f.EncryptInPlace(alice, bob.toPublic()));
|
||||||
|
|
||||||
EXPECT_CALL(m_crypto, dh_server(_, _, _, _)).WillOnce(Return(true));
|
EXPECT_CALL(m_crypto, dh_server(_, _, _, _)).WillOnce(Return(true));
|
||||||
|
|
||||||
// decrypt from alice
|
// decrypt from alice
|
||||||
ASSERT_TRUE(f.DecryptInPlace(bob));
|
REQUIRE(f.DecryptInPlace(bob));
|
||||||
|
|
||||||
LRCR otherRecord;
|
LRCR otherRecord;
|
||||||
ASSERT_TRUE(otherRecord.BDecode(buf));
|
REQUIRE(otherRecord.BDecode(buf));
|
||||||
ASSERT_TRUE(otherRecord == record);
|
REQUIRE(otherRecord == record);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
#include <util/meta/memfn.hpp>
|
#include <util/meta/memfn.hpp>
|
||||||
|
|
||||||
#include <gtest/gtest.h>
|
#include <catch2/catch.hpp>
|
||||||
#include <gmock/gmock.h>
|
|
||||||
|
|
||||||
using namespace llarp;
|
using namespace llarp;
|
||||||
|
|
||||||
|
@ -32,36 +31,25 @@ struct Foo
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
TEST(MemFn, call)
|
TEST_CASE("memFn call")
|
||||||
{
|
{
|
||||||
Foo foo;
|
Foo foo;
|
||||||
ASSERT_FALSE(util::memFn(&Foo::empty, &foo)());
|
REQUIRE_FALSE(util::memFn(&Foo::empty, &foo)());
|
||||||
ASSERT_TRUE(util::memFn(&Foo::constEmpty, &foo)());
|
REQUIRE(util::memFn(&Foo::constEmpty, &foo)());
|
||||||
ASSERT_EQ(11, util::memFn(&Foo::arg, &foo)(10));
|
REQUIRE(11 == util::memFn(&Foo::arg, &foo)(10));
|
||||||
ASSERT_EQ(9, util::memFn(&Foo::constArg, &foo)(10));
|
REQUIRE(9 == util::memFn(&Foo::constArg, &foo)(10));
|
||||||
|
|
||||||
ASSERT_TRUE(util::memFn(&Foo::constEmpty, &foo)());
|
REQUIRE(util::memFn(&Foo::constEmpty, &foo)());
|
||||||
ASSERT_EQ(9, util::memFn(&Foo::constArg, &foo)(10));
|
REQUIRE(9 == util::memFn(&Foo::constArg, &foo)(10));
|
||||||
}
|
}
|
||||||
|
|
||||||
template < typename T >
|
|
||||||
class MemFnType : public ::testing::Test
|
|
||||||
{
|
|
||||||
};
|
|
||||||
|
|
||||||
TYPED_TEST_SUITE_P(MemFnType);
|
|
||||||
|
|
||||||
TYPED_TEST_P(MemFnType, Smoke)
|
|
||||||
{
|
|
||||||
TypeParam foo{};
|
|
||||||
ASSERT_TRUE(util::memFn(&Foo::constEmpty, &foo)());
|
|
||||||
}
|
|
||||||
|
|
||||||
REGISTER_TYPED_TEST_SUITE_P(MemFnType, Smoke);
|
|
||||||
|
|
||||||
// clang-format off
|
// clang-format off
|
||||||
using MemFnTypes = ::testing::Types<
|
using MemFnTypes = std::tuple<
|
||||||
Foo, const Foo>;
|
Foo, const Foo>;
|
||||||
|
|
||||||
INSTANTIATE_TYPED_TEST_SUITE_P(MemFn, MemFnType, MemFnTypes);
|
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
|
TEMPLATE_LIST_TEST_CASE("memFn type smoke test", "", MemFnTypes)
|
||||||
|
{
|
||||||
|
TestType foo{};
|
||||||
|
REQUIRE(util::memFn(&Foo::constEmpty, &foo)());
|
||||||
|
}
|
||||||
|
|
|
@ -2,37 +2,19 @@
|
||||||
|
|
||||||
#include <list>
|
#include <list>
|
||||||
|
|
||||||
#include <gtest/gtest.h>
|
#include <catch2/catch.hpp>
|
||||||
#include <gmock/gmock.h>
|
|
||||||
|
|
||||||
using namespace llarp;
|
using namespace llarp;
|
||||||
|
|
||||||
TEST(traits_bottom, Smoke)
|
TEST_CASE("traits::Bottom smoke test")
|
||||||
{
|
{
|
||||||
traits::Bottom bottom;
|
traits::Bottom bottom;
|
||||||
(void)bottom;
|
(void)bottom;
|
||||||
SUCCEED();
|
SUCCEED();
|
||||||
}
|
}
|
||||||
|
|
||||||
template < typename T >
|
|
||||||
class IsContainer : public ::testing::Test
|
|
||||||
{
|
|
||||||
};
|
|
||||||
|
|
||||||
TYPED_TEST_SUITE_P(IsContainer);
|
|
||||||
|
|
||||||
TYPED_TEST_P(IsContainer, Smoke)
|
|
||||||
{
|
|
||||||
bool expected = std::tuple_element_t< 1, TypeParam >::value;
|
|
||||||
bool result =
|
|
||||||
traits::is_container< std::tuple_element_t< 0, TypeParam > >::value;
|
|
||||||
ASSERT_EQ(expected, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
REGISTER_TYPED_TEST_SUITE_P(IsContainer, Smoke);
|
|
||||||
|
|
||||||
// clang-format off
|
// clang-format off
|
||||||
using ContainerTypes = ::testing::Types<
|
using ContainerTypes = std::tuple<
|
||||||
std::tuple< std::vector< int >, std::integral_constant< bool, true > >,
|
std::tuple< std::vector< int >, std::integral_constant< bool, true > >,
|
||||||
std::tuple< std::vector< std::string >, std::integral_constant< bool, true > >,
|
std::tuple< std::vector< std::string >, std::integral_constant< bool, true > >,
|
||||||
std::tuple< std::list< std::string >, std::integral_constant< bool, true > >,
|
std::tuple< std::list< std::string >, std::integral_constant< bool, true > >,
|
||||||
|
@ -41,8 +23,16 @@ using ContainerTypes = ::testing::Types<
|
||||||
std::tuple< std::tuple<std::string>, std::integral_constant< bool, false > >,
|
std::tuple< std::tuple<std::string>, std::integral_constant< bool, false > >,
|
||||||
std::tuple< int, std::integral_constant< bool, false > >
|
std::tuple< int, std::integral_constant< bool, false > >
|
||||||
>;
|
>;
|
||||||
INSTANTIATE_TYPED_TEST_SUITE_P(traits, IsContainer, ContainerTypes);
|
// clang-format on
|
||||||
|
|
||||||
|
TEMPLATE_LIST_TEST_CASE("is_container smoke test", "", ContainerTypes)
|
||||||
|
{
|
||||||
|
bool expected = std::tuple_element_t<1, TestType>::value;
|
||||||
|
bool result = traits::is_container<std::tuple_element_t<0, TestType>>::value;
|
||||||
|
REQUIRE(expected == result);
|
||||||
|
}
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
struct A { };
|
struct A { };
|
||||||
struct B { };
|
struct B { };
|
||||||
struct C { };
|
struct C { };
|
||||||
|
@ -65,29 +55,11 @@ char f(H) { return 'H'; }
|
||||||
char f(I) { return 'I'; }
|
char f(I) { return 'I'; }
|
||||||
char f(J) { return 'J'; }
|
char f(J) { return 'J'; }
|
||||||
char f(traits::Bottom) { return '0'; }
|
char f(traits::Bottom) { return '0'; }
|
||||||
|
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
template < typename T >
|
|
||||||
class TestSwitch : public ::testing::Test
|
|
||||||
{
|
|
||||||
};
|
|
||||||
|
|
||||||
TYPED_TEST_SUITE_P(TestSwitch);
|
|
||||||
|
|
||||||
TYPED_TEST_P(TestSwitch, Smoke)
|
|
||||||
{
|
|
||||||
char expected = std::tuple_element_t< 0, TypeParam >::value;
|
|
||||||
using InputType = typename std::tuple_element_t< 1, TypeParam >::Type;
|
|
||||||
char result = f(InputType());
|
|
||||||
ASSERT_EQ(expected, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
REGISTER_TYPED_TEST_SUITE_P(TestSwitch, Smoke);
|
|
||||||
|
|
||||||
// clang-format off
|
// clang-format off
|
||||||
using namespace traits::Switch;
|
using namespace traits::Switch;
|
||||||
using SwitchTypes = ::testing::Types<
|
using SwitchTypes = std::tuple<
|
||||||
std::tuple<std::integral_constant<char, 'A'>, Switch< 0, A, B, C, D, E, F, G, H, I, J > >,
|
std::tuple<std::integral_constant<char, 'A'>, Switch< 0, A, B, C, D, E, F, G, H, I, J > >,
|
||||||
std::tuple<std::integral_constant<char, 'B'>, Switch< 1, A, B, C, D, E, F, G, H, I, J > >,
|
std::tuple<std::integral_constant<char, 'B'>, Switch< 1, A, B, C, D, E, F, G, H, I, J > >,
|
||||||
std::tuple<std::integral_constant<char, 'C'>, Switch< 2, A, B, C, D, E, F, G, H, I, J > >,
|
std::tuple<std::integral_constant<char, 'C'>, Switch< 2, A, B, C, D, E, F, G, H, I, J > >,
|
||||||
|
@ -102,8 +74,15 @@ using SwitchTypes = ::testing::Types<
|
||||||
std::tuple<std::integral_constant<char, 'C'>, Switch< 6, C, C, C, C, C, C, C, C, C, J > >,
|
std::tuple<std::integral_constant<char, 'C'>, Switch< 6, C, C, C, C, C, C, C, C, C, J > >,
|
||||||
std::tuple<std::integral_constant<char, '0'>, Switch< 10, A, B, C, D, E, F, G, H, I, J > >
|
std::tuple<std::integral_constant<char, '0'>, Switch< 10, A, B, C, D, E, F, G, H, I, J > >
|
||||||
>;
|
>;
|
||||||
|
// clang-format off
|
||||||
|
|
||||||
INSTANTIATE_TYPED_TEST_SUITE_P(traits, TestSwitch, SwitchTypes);
|
TEMPLATE_LIST_TEST_CASE("Switch smoke test", "", SwitchTypes)
|
||||||
|
{
|
||||||
|
char expected = std::tuple_element_t<0, TestType>::value;
|
||||||
|
using InputType = typename std::tuple_element_t<1, TestType>::Type;
|
||||||
|
char result = f(InputType());
|
||||||
|
REQUIRE(expected == result);
|
||||||
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
using is_bool = std::is_same<T, bool>;
|
using is_bool = std::is_same<T, bool>;
|
||||||
|
@ -126,56 +105,35 @@ selectCase()
|
||||||
return dispatch(Selection());
|
return dispatch(Selection());
|
||||||
}
|
}
|
||||||
|
|
||||||
template < typename T >
|
// clang-format off
|
||||||
class Select : public ::testing::Test
|
using SelectTypes = std::tuple<
|
||||||
{
|
|
||||||
};
|
|
||||||
|
|
||||||
TYPED_TEST_SUITE_P(Select);
|
|
||||||
|
|
||||||
TYPED_TEST_P(Select, Smoke)
|
|
||||||
{
|
|
||||||
char expected = std::tuple_element_t< 0, TypeParam >::value;
|
|
||||||
char result = selectCase<std::tuple_element_t< 1, TypeParam > >();
|
|
||||||
ASSERT_EQ(expected, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
REGISTER_TYPED_TEST_SUITE_P(Select, Smoke);
|
|
||||||
|
|
||||||
using SelectTypes = ::testing::Types<
|
|
||||||
std::tuple<std::integral_constant<char, '0'>, double >,
|
std::tuple<std::integral_constant<char, '0'>, double >,
|
||||||
std::tuple<std::integral_constant<char, 'b'>, bool >,
|
std::tuple<std::integral_constant<char, 'b'>, bool >,
|
||||||
std::tuple<std::integral_constant<char, 'c'>, char >,
|
std::tuple<std::integral_constant<char, 'c'>, char >,
|
||||||
std::tuple<std::integral_constant<char, 's'>, std::string >
|
std::tuple<std::integral_constant<char, 's'>, std::string >
|
||||||
>;
|
>;
|
||||||
|
|
||||||
INSTANTIATE_TYPED_TEST_SUITE_P(traits, Select, SelectTypes);
|
|
||||||
|
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
template < typename T >
|
TEMPLATE_LIST_TEST_CASE("selectCase smoke test", "", SelectTypes)
|
||||||
class IsPointy : public ::testing::Test
|
|
||||||
{
|
{
|
||||||
};
|
char expected = std::tuple_element_t<0, TestType>::value;
|
||||||
|
char result = selectCase<std::tuple_element_t<1, TestType>>();
|
||||||
TYPED_TEST_SUITE_P(IsPointy);
|
REQUIRE(expected == result);
|
||||||
|
|
||||||
TYPED_TEST_P(IsPointy, Smoke)
|
|
||||||
{
|
|
||||||
bool expected = std::tuple_element_t< 1, TypeParam >::value;
|
|
||||||
bool result =
|
|
||||||
traits::is_pointy< std::tuple_element_t< 0, TypeParam > >::value;
|
|
||||||
ASSERT_EQ(expected, result);
|
|
||||||
}
|
}
|
||||||
|
// clang-format on
|
||||||
REGISTER_TYPED_TEST_SUITE_P(IsPointy, Smoke);
|
|
||||||
|
|
||||||
// clang-format off
|
// clang-format off
|
||||||
using PointerTypes = ::testing::Types<
|
using PointerTypes = std::tuple<
|
||||||
std::tuple< int *, std::true_type >,
|
std::tuple< int *, std::true_type >,
|
||||||
std::tuple< int, std::integral_constant< bool, false > >,
|
std::tuple< int, std::integral_constant< bool, false > >,
|
||||||
std::tuple< std::shared_ptr<int>, std::true_type >,
|
std::tuple< std::shared_ptr<int>, std::true_type >,
|
||||||
std::tuple< std::unique_ptr<int>, std::true_type >
|
std::tuple< std::unique_ptr<int>, std::true_type >
|
||||||
>;
|
>;
|
||||||
INSTANTIATE_TYPED_TEST_SUITE_P(traits, IsPointy, PointerTypes);
|
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
|
TEMPLATE_LIST_TEST_CASE("is_pointy smoke test", "", PointerTypes)
|
||||||
|
{
|
||||||
|
bool expected = std::tuple_element_t<1, TestType>::value;
|
||||||
|
bool result = traits::is_pointy<std::tuple_element_t<0, TestType>>::value;
|
||||||
|
REQUIRE(expected == result);
|
||||||
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
#include <gtest/gtest.h>
|
#include <catch2/catch.hpp>
|
||||||
|
|
||||||
#include <util/aligned.hpp>
|
#include <util/aligned.hpp>
|
||||||
|
|
||||||
|
@ -7,218 +7,176 @@
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
|
||||||
using TestSizes = ::testing::Types< std::integral_constant< std::size_t, 8 >,
|
using TestSizes = std::tuple<
|
||||||
std::integral_constant< std::size_t, 12 >,
|
std::integral_constant<std::size_t, 8>,
|
||||||
std::integral_constant< std::size_t, 16 >,
|
std::integral_constant<std::size_t, 12>,
|
||||||
std::integral_constant< std::size_t, 32 >,
|
std::integral_constant<std::size_t, 16>,
|
||||||
std::integral_constant< std::size_t, 64 >,
|
std::integral_constant<std::size_t, 32>,
|
||||||
std::integral_constant< std::size_t, 77 >,
|
std::integral_constant<std::size_t, 64>,
|
||||||
std::integral_constant< std::size_t, 1024 >,
|
std::integral_constant<std::size_t, 77>,
|
||||||
std::integral_constant< std::size_t, 3333 > >;
|
std::integral_constant<std::size_t, 1024>,
|
||||||
|
std::integral_constant<std::size_t, 3333>>;
|
||||||
|
|
||||||
template < typename T >
|
TEMPLATE_LIST_TEST_CASE("AlignedBuffer", "[AlignedBuffer]", TestSizes)
|
||||||
struct AlignedBufferTest : public ::testing::Test
|
|
||||||
{
|
{
|
||||||
};
|
using Buffer = llarp::AlignedBuffer<TestType::value>;
|
||||||
|
|
||||||
TYPED_TEST_CASE(AlignedBufferTest, TestSizes, );
|
|
||||||
|
|
||||||
TYPED_TEST(AlignedBufferTest, Constructor)
|
|
||||||
{
|
|
||||||
using Buffer = llarp::AlignedBuffer< TypeParam::value >;
|
|
||||||
|
|
||||||
Buffer b;
|
Buffer b;
|
||||||
EXPECT_TRUE(b.IsZero());
|
CHECK(b.IsZero());
|
||||||
EXPECT_EQ(b.size(), TypeParam::value);
|
|
||||||
}
|
|
||||||
|
|
||||||
TYPED_TEST(AlignedBufferTest, CopyConstructor)
|
SECTION("Constructor")
|
||||||
{
|
|
||||||
using Buffer = llarp::AlignedBuffer< TypeParam::value >;
|
|
||||||
|
|
||||||
Buffer b;
|
|
||||||
EXPECT_TRUE(b.IsZero());
|
|
||||||
|
|
||||||
Buffer c = b;
|
|
||||||
EXPECT_TRUE(c.IsZero());
|
|
||||||
|
|
||||||
c.Fill(1);
|
|
||||||
EXPECT_FALSE(c.IsZero());
|
|
||||||
|
|
||||||
Buffer d = c;
|
|
||||||
EXPECT_FALSE(d.IsZero());
|
|
||||||
}
|
|
||||||
|
|
||||||
TYPED_TEST(AlignedBufferTest, AltConstructors)
|
|
||||||
{
|
|
||||||
using Buffer = llarp::AlignedBuffer< TypeParam::value >;
|
|
||||||
|
|
||||||
Buffer b;
|
|
||||||
EXPECT_TRUE(b.IsZero());
|
|
||||||
b.Fill(2);
|
|
||||||
|
|
||||||
Buffer c(b.as_array());
|
|
||||||
EXPECT_FALSE(c.IsZero());
|
|
||||||
|
|
||||||
Buffer d(c.data());
|
|
||||||
EXPECT_FALSE(d.IsZero());
|
|
||||||
}
|
|
||||||
|
|
||||||
TYPED_TEST(AlignedBufferTest, Assignment)
|
|
||||||
{
|
|
||||||
using Buffer = llarp::AlignedBuffer< TypeParam::value >;
|
|
||||||
|
|
||||||
Buffer b;
|
|
||||||
EXPECT_TRUE(b.IsZero());
|
|
||||||
|
|
||||||
Buffer c;
|
|
||||||
c = b;
|
|
||||||
EXPECT_TRUE(c.IsZero());
|
|
||||||
|
|
||||||
c.Fill(1);
|
|
||||||
EXPECT_FALSE(c.IsZero());
|
|
||||||
|
|
||||||
Buffer d;
|
|
||||||
d = c;
|
|
||||||
EXPECT_FALSE(d.IsZero());
|
|
||||||
}
|
|
||||||
|
|
||||||
TYPED_TEST(AlignedBufferTest, StreamOut)
|
|
||||||
{
|
|
||||||
using Buffer = llarp::AlignedBuffer< TypeParam::value >;
|
|
||||||
|
|
||||||
Buffer b;
|
|
||||||
EXPECT_TRUE(b.IsZero());
|
|
||||||
|
|
||||||
std::stringstream stream;
|
|
||||||
|
|
||||||
stream << b;
|
|
||||||
|
|
||||||
EXPECT_EQ(stream.str(), std::string(TypeParam::value * 2, '0'));
|
|
||||||
|
|
||||||
stream.str("");
|
|
||||||
|
|
||||||
b.Fill(255);
|
|
||||||
stream << b;
|
|
||||||
|
|
||||||
EXPECT_EQ(stream.str(), std::string(TypeParam::value * 2, 'f'));
|
|
||||||
}
|
|
||||||
|
|
||||||
TYPED_TEST(AlignedBufferTest, BitwiseNot)
|
|
||||||
{
|
|
||||||
using Buffer = llarp::AlignedBuffer< TypeParam::value >;
|
|
||||||
|
|
||||||
Buffer b;
|
|
||||||
EXPECT_TRUE(b.IsZero());
|
|
||||||
|
|
||||||
Buffer c = ~b;
|
|
||||||
EXPECT_FALSE(c.IsZero());
|
|
||||||
|
|
||||||
for(auto val : c.as_array())
|
|
||||||
{
|
{
|
||||||
EXPECT_EQ(255, val);
|
CHECK(b.size() == TestType::value);
|
||||||
}
|
}
|
||||||
|
|
||||||
Buffer d = ~c;
|
SECTION("CopyConstructor")
|
||||||
EXPECT_TRUE(d.IsZero());
|
{
|
||||||
}
|
Buffer c = b;
|
||||||
|
CHECK(c.IsZero());
|
||||||
TYPED_TEST(AlignedBufferTest, Operators)
|
|
||||||
{
|
c.Fill(1);
|
||||||
using Buffer = llarp::AlignedBuffer< TypeParam::value >;
|
CHECK_FALSE(c.IsZero());
|
||||||
|
|
||||||
Buffer b;
|
Buffer d = c;
|
||||||
EXPECT_TRUE(b.IsZero());
|
CHECK_FALSE(d.IsZero());
|
||||||
|
}
|
||||||
Buffer c = b;
|
|
||||||
EXPECT_EQ(b, c);
|
SECTION("AltConstructors")
|
||||||
EXPECT_GE(b, c);
|
{
|
||||||
EXPECT_LE(b, c);
|
b.Fill(2);
|
||||||
EXPECT_GE(c, b);
|
|
||||||
EXPECT_LE(c, b);
|
Buffer c(b.as_array());
|
||||||
|
CHECK_FALSE(c.IsZero());
|
||||||
c.Fill(1);
|
|
||||||
EXPECT_NE(b, c);
|
Buffer d(c.data());
|
||||||
EXPECT_LT(b, c);
|
CHECK_FALSE(d.IsZero());
|
||||||
EXPECT_GT(c, b);
|
}
|
||||||
}
|
|
||||||
|
SECTION("Assignment")
|
||||||
TYPED_TEST(AlignedBufferTest, Xor)
|
{
|
||||||
{
|
Buffer c;
|
||||||
using Buffer = llarp::AlignedBuffer< TypeParam::value >;
|
c = b;
|
||||||
|
CHECK(c.IsZero());
|
||||||
Buffer b;
|
|
||||||
Buffer c;
|
c.Fill(1);
|
||||||
b.Fill(255);
|
CHECK_FALSE(c.IsZero());
|
||||||
c.Fill(255);
|
|
||||||
EXPECT_FALSE(b.IsZero());
|
Buffer d;
|
||||||
EXPECT_FALSE(c.IsZero());
|
d = c;
|
||||||
|
CHECK_FALSE(d.IsZero());
|
||||||
Buffer d = b ^ c;
|
}
|
||||||
// 1 ^ 1 = 0
|
|
||||||
EXPECT_TRUE(d.IsZero());
|
SECTION("StreamOut")
|
||||||
// Verify unchanged
|
{
|
||||||
EXPECT_FALSE(b.IsZero());
|
std::stringstream stream;
|
||||||
EXPECT_FALSE(c.IsZero());
|
|
||||||
|
stream << b;
|
||||||
Buffer e, f;
|
|
||||||
e.Fill(255);
|
CHECK(stream.str() == std::string(TestType::value * 2, '0'));
|
||||||
Buffer g = e ^ f;
|
|
||||||
// 1 ^ 0 = 1
|
stream.str("");
|
||||||
EXPECT_FALSE(g.IsZero());
|
|
||||||
|
b.Fill(255);
|
||||||
Buffer h, i;
|
stream << b;
|
||||||
i.Fill(255);
|
|
||||||
Buffer j = h ^ i;
|
CHECK(stream.str() == std::string(TestType::value * 2, 'f'));
|
||||||
// 0 ^ 1 = 1
|
}
|
||||||
EXPECT_FALSE(j.IsZero());
|
|
||||||
}
|
SECTION("BitwiseNot")
|
||||||
|
{
|
||||||
TYPED_TEST(AlignedBufferTest, XorAssign)
|
Buffer c = ~b;
|
||||||
{
|
CHECK_FALSE(c.IsZero());
|
||||||
using Buffer = llarp::AlignedBuffer< TypeParam::value >;
|
|
||||||
|
for (auto val : c.as_array())
|
||||||
Buffer b, c;
|
{
|
||||||
b.Fill(255);
|
CHECK(255 == val);
|
||||||
c.Fill(255);
|
}
|
||||||
EXPECT_FALSE(b.IsZero());
|
|
||||||
EXPECT_FALSE(c.IsZero());
|
Buffer d = ~c;
|
||||||
|
CHECK(d.IsZero());
|
||||||
b ^= c;
|
}
|
||||||
EXPECT_TRUE(b.IsZero());
|
|
||||||
}
|
SECTION("Operators")
|
||||||
|
{
|
||||||
TYPED_TEST(AlignedBufferTest, Zero)
|
Buffer c = b;
|
||||||
{
|
CHECK(b == c);
|
||||||
using Buffer = llarp::AlignedBuffer< TypeParam::value >;
|
CHECK(b >= c);
|
||||||
|
CHECK(b <= c);
|
||||||
Buffer b;
|
CHECK(c >= b);
|
||||||
EXPECT_TRUE(b.IsZero());
|
CHECK(c <= b);
|
||||||
|
|
||||||
b.Fill(127);
|
c.Fill(1);
|
||||||
EXPECT_FALSE(b.IsZero());
|
CHECK(b != c);
|
||||||
|
CHECK(b < c);
|
||||||
b.Zero();
|
CHECK(c > b);
|
||||||
EXPECT_TRUE(b.IsZero());
|
}
|
||||||
}
|
|
||||||
|
SECTION("Xor")
|
||||||
TYPED_TEST(AlignedBufferTest, TestHash)
|
{
|
||||||
{
|
Buffer c;
|
||||||
using Buffer = llarp::AlignedBuffer< TypeParam::value >;
|
b.Fill(255);
|
||||||
using Map_t = std::unordered_map< Buffer, int, typename Buffer::Hash >;
|
c.Fill(255);
|
||||||
|
CHECK_FALSE(b.IsZero());
|
||||||
Buffer k, other_k;
|
CHECK_FALSE(c.IsZero());
|
||||||
k.Randomize();
|
|
||||||
other_k.Randomize();
|
Buffer d = b ^ c;
|
||||||
Map_t m;
|
// 1 ^ 1 = 0
|
||||||
EXPECT_TRUE(m.empty());
|
CHECK(d.IsZero());
|
||||||
EXPECT_TRUE(m.emplace(k, 1).second);
|
// Verify unchanged
|
||||||
EXPECT_TRUE(m.find(k) != m.end());
|
CHECK_FALSE(b.IsZero());
|
||||||
EXPECT_TRUE(m[k] == 1);
|
CHECK_FALSE(c.IsZero());
|
||||||
EXPECT_FALSE(m.find(other_k) != m.end());
|
|
||||||
EXPECT_TRUE(m.size() == 1);
|
Buffer e, f;
|
||||||
Buffer k_copy = k;
|
e.Fill(255);
|
||||||
EXPECT_FALSE(m.emplace(k_copy, 2).second);
|
Buffer g = e ^ f;
|
||||||
EXPECT_FALSE(m[k_copy] == 2);
|
// 1 ^ 0 = 1
|
||||||
EXPECT_TRUE(m[k_copy] == 1);
|
CHECK_FALSE(g.IsZero());
|
||||||
|
|
||||||
|
Buffer h, i;
|
||||||
|
i.Fill(255);
|
||||||
|
Buffer j = h ^ i;
|
||||||
|
// 0 ^ 1 = 1
|
||||||
|
CHECK_FALSE(j.IsZero());
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("XorAssign")
|
||||||
|
{
|
||||||
|
Buffer c;
|
||||||
|
b.Fill(255);
|
||||||
|
c.Fill(255);
|
||||||
|
CHECK_FALSE(b.IsZero());
|
||||||
|
CHECK_FALSE(c.IsZero());
|
||||||
|
|
||||||
|
b ^= c;
|
||||||
|
CHECK(b.IsZero());
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("Zero")
|
||||||
|
{
|
||||||
|
b.Fill(127);
|
||||||
|
CHECK_FALSE(b.IsZero());
|
||||||
|
|
||||||
|
b.Zero();
|
||||||
|
CHECK(b.IsZero());
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("TestHash")
|
||||||
|
{
|
||||||
|
using Map_t = std::unordered_map<Buffer, int, typename Buffer::Hash>;
|
||||||
|
|
||||||
|
Buffer k, other_k;
|
||||||
|
k.Randomize();
|
||||||
|
other_k.Randomize();
|
||||||
|
Map_t m;
|
||||||
|
CHECK(m.empty());
|
||||||
|
CHECK(m.emplace(k, 1).second);
|
||||||
|
CHECK(m.find(k) != m.end());
|
||||||
|
CHECK(m[k] == 1);
|
||||||
|
CHECK_FALSE(m.find(other_k) != m.end());
|
||||||
|
CHECK(m.size() == 1);
|
||||||
|
Buffer k_copy = k;
|
||||||
|
CHECK_FALSE(m.emplace(k_copy, 2).second);
|
||||||
|
CHECK_FALSE(m[k_copy] == 2);
|
||||||
|
CHECK(m[k_copy] == 1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,11 +6,11 @@
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include <gtest/gtest.h>
|
#include <catch2/catch.hpp>
|
||||||
|
|
||||||
using TestBuffer = std::vector< byte_t >;
|
using TestBuffer = std::vector<byte_t>;
|
||||||
|
|
||||||
template < typename Result >
|
template <typename Result>
|
||||||
struct TestReadData
|
struct TestReadData
|
||||||
{
|
{
|
||||||
TestBuffer buffer;
|
TestBuffer buffer;
|
||||||
|
@ -18,15 +18,15 @@ struct TestReadData
|
||||||
Result result;
|
Result result;
|
||||||
};
|
};
|
||||||
|
|
||||||
using TestReadInt = TestReadData< uint64_t >;
|
using TestReadInt = TestReadData<uint64_t>;
|
||||||
using TestReadString = TestReadData< std::string >;
|
using TestReadString = TestReadData<std::string>;
|
||||||
|
|
||||||
template < typename Result >
|
template <typename Result>
|
||||||
std::ostream&
|
std::ostream&
|
||||||
operator<<(std::ostream& os, const TestReadData< Result >& d)
|
operator<<(std::ostream& os, const TestReadData<Result>& d)
|
||||||
{
|
{
|
||||||
os << "buf = [ ";
|
os << "buf = [ ";
|
||||||
for(auto x : d.buffer)
|
for (auto x : d.buffer)
|
||||||
{
|
{
|
||||||
os << x << " ";
|
os << x << " ";
|
||||||
}
|
}
|
||||||
|
@ -37,33 +37,16 @@ operator<<(std::ostream& os, const TestReadData< Result >& d)
|
||||||
return os;
|
return os;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ReadInt : public ::testing::TestWithParam< TestReadInt >
|
static constexpr byte_t i = 'i';
|
||||||
{
|
static constexpr byte_t e = 'e';
|
||||||
};
|
static constexpr byte_t zero = '0';
|
||||||
|
static constexpr byte_t one = '1';
|
||||||
TEST_P(ReadInt, readInt)
|
static constexpr byte_t two = '2';
|
||||||
{
|
static constexpr byte_t f = 'f';
|
||||||
auto d = GetParam();
|
static constexpr byte_t z = 'z';
|
||||||
|
|
||||||
llarp_buffer_t buffer(d.buffer);
|
|
||||||
|
|
||||||
uint64_t result = 0;
|
|
||||||
bool rc = bencode_read_integer(&buffer, &result);
|
|
||||||
|
|
||||||
EXPECT_EQ(rc, d.rc);
|
|
||||||
EXPECT_EQ(result, d.result);
|
|
||||||
}
|
|
||||||
|
|
||||||
static constexpr byte_t i = 'i';
|
|
||||||
static constexpr byte_t e = 'e';
|
|
||||||
static constexpr byte_t zero = '0';
|
|
||||||
static constexpr byte_t one = '1';
|
|
||||||
static constexpr byte_t two = '2';
|
|
||||||
static constexpr byte_t f = 'f';
|
|
||||||
static constexpr byte_t z = 'z';
|
|
||||||
static constexpr byte_t colon = ':';
|
static constexpr byte_t colon = ':';
|
||||||
|
|
||||||
static const TestReadInt testReadInt[] = {
|
std::vector<TestReadInt> testReadInt{
|
||||||
// good cases
|
// good cases
|
||||||
{{i, 0, e}, true, 0},
|
{{i, 0, e}, true, 0},
|
||||||
{{i, zero, e}, true, 0},
|
{{i, zero, e}, true, 0},
|
||||||
|
@ -80,28 +63,20 @@ static const TestReadInt testReadInt[] = {
|
||||||
{{z}, false, 0},
|
{{z}, false, 0},
|
||||||
};
|
};
|
||||||
|
|
||||||
INSTANTIATE_TEST_SUITE_P(TestBencode, ReadInt,
|
TEST_CASE("Read int", "[bencode]")
|
||||||
::testing::ValuesIn(testReadInt));
|
|
||||||
|
|
||||||
struct ReadStr : public ::testing::TestWithParam< TestReadString >
|
|
||||||
{
|
{
|
||||||
};
|
auto d = GENERATE(from_range(testReadInt));
|
||||||
|
|
||||||
TEST_P(ReadStr, readStr)
|
|
||||||
{
|
|
||||||
auto d = GetParam();
|
|
||||||
|
|
||||||
llarp_buffer_t buffer(d.buffer);
|
llarp_buffer_t buffer(d.buffer);
|
||||||
|
|
||||||
llarp_buffer_t result;
|
uint64_t result = 0;
|
||||||
bool rc = bencode_read_string(&buffer, &result);
|
bool rc = bencode_read_integer(&buffer, &result);
|
||||||
|
|
||||||
EXPECT_EQ(rc, d.rc);
|
CHECK(rc == d.rc);
|
||||||
EXPECT_EQ(result.sz, d.result.size());
|
CHECK(result == d.result);
|
||||||
EXPECT_EQ(std::string(result.base, result.base + result.sz), d.result);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const TestReadString testReadStr[] = {
|
std::vector<TestReadString> testReadStr{
|
||||||
// good cases
|
// good cases
|
||||||
{{one, colon, 'a'}, true, "a"},
|
{{one, colon, 'a'}, true, "a"},
|
||||||
{{one, colon, 'b'}, true, "b"},
|
{{one, colon, 'b'}, true, "b"},
|
||||||
|
@ -118,10 +93,21 @@ static const TestReadString testReadStr[] = {
|
||||||
{{colon, colon}, false, ""},
|
{{colon, colon}, false, ""},
|
||||||
};
|
};
|
||||||
|
|
||||||
INSTANTIATE_TEST_SUITE_P(TestBencode, ReadStr,
|
TEST_CASE("Read str", "[bencode]")
|
||||||
::testing::ValuesIn(testReadStr));
|
{
|
||||||
|
auto d = GENERATE(from_range(testReadStr));
|
||||||
|
|
||||||
template < typename Input >
|
llarp_buffer_t buffer(d.buffer);
|
||||||
|
|
||||||
|
llarp_buffer_t result;
|
||||||
|
bool rc = bencode_read_string(&buffer, &result);
|
||||||
|
|
||||||
|
CHECK(rc == d.rc);
|
||||||
|
CHECK(result.sz == d.result.size());
|
||||||
|
CHECK(std::string(result.base, result.base + result.sz) == d.result);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Input>
|
||||||
struct TestWriteData
|
struct TestWriteData
|
||||||
{
|
{
|
||||||
Input input;
|
Input input;
|
||||||
|
@ -130,62 +116,39 @@ struct TestWriteData
|
||||||
std::string output;
|
std::string output;
|
||||||
};
|
};
|
||||||
|
|
||||||
using TestWriteByteString = TestWriteData< std::string >;
|
using TestWriteByteString = TestWriteData<std::string>;
|
||||||
using TestWriteInt = TestWriteData< uint64_t >;
|
using TestWriteInt = TestWriteData<uint64_t>;
|
||||||
|
|
||||||
struct WriteByteStr : public ::testing::TestWithParam< TestWriteByteString >
|
static constexpr size_t MAX_1 = static_cast<size_t>(std::numeric_limits<int16_t>::max()) + 1;
|
||||||
{
|
|
||||||
};
|
|
||||||
|
|
||||||
TEST_P(WriteByteStr, writeByte)
|
std::vector<TestWriteByteString> testWriteByteString{
|
||||||
{
|
|
||||||
auto d = GetParam();
|
|
||||||
|
|
||||||
std::vector< byte_t > backingBuffer(d.bufferSize, 0);
|
|
||||||
llarp_buffer_t buffer(backingBuffer);
|
|
||||||
|
|
||||||
bool rc = bencode_write_bytestring(&buffer, d.input.data(), d.input.size());
|
|
||||||
|
|
||||||
ASSERT_EQ(rc, d.rc);
|
|
||||||
ASSERT_EQ(std::string(buffer.base, buffer.cur), d.output);
|
|
||||||
}
|
|
||||||
|
|
||||||
static constexpr size_t MAX_1 =
|
|
||||||
static_cast< size_t >(std::numeric_limits< int16_t >::max()) + 1;
|
|
||||||
|
|
||||||
static const TestWriteByteString testWriteByteString[] = {
|
|
||||||
// good cases
|
// good cases
|
||||||
{"abacus", 100, true, "6:abacus"},
|
{"abacus", 100, true, "6:abacus"},
|
||||||
{" abacus", 100, true, "8: abacus"},
|
{" abacus", 100, true, "8: abacus"},
|
||||||
{"", 100, true, "0:"},
|
{"", 100, true, "0:"},
|
||||||
{std::string("\0\0\0", 3), 100, true, std::string("3:\0\0\0", 5)},
|
{std::string("\0\0\0", 3), 100, true, std::string("3:\0\0\0", 5)},
|
||||||
{std::string(MAX_1, 'a'), MAX_1 + 100, true,
|
{std::string(MAX_1, 'a'),
|
||||||
|
MAX_1 + 100,
|
||||||
|
true,
|
||||||
std::to_string(MAX_1) + std::string(":") + std::string(MAX_1, 'a')},
|
std::to_string(MAX_1) + std::string(":") + std::string(MAX_1, 'a')},
|
||||||
// bad cases
|
// bad cases
|
||||||
{"a", 1, false, ""},
|
{"a", 1, false, ""},
|
||||||
};
|
};
|
||||||
|
|
||||||
INSTANTIATE_TEST_SUITE_P(TestBencode, WriteByteStr,
|
TEST_CASE("Write byte str", "[bencode]")
|
||||||
::testing::ValuesIn(testWriteByteString));
|
|
||||||
|
|
||||||
struct WriteInt : public ::testing::TestWithParam< TestWriteInt >
|
|
||||||
{
|
{
|
||||||
};
|
auto d = GENERATE(from_range(testWriteByteString));
|
||||||
|
|
||||||
TEST_P(WriteInt, writeInt)
|
std::vector<byte_t> backingBuffer(d.bufferSize, 0);
|
||||||
{
|
|
||||||
auto d = GetParam();
|
|
||||||
|
|
||||||
std::vector< byte_t > backingBuffer(d.bufferSize, 0);
|
|
||||||
llarp_buffer_t buffer(backingBuffer);
|
llarp_buffer_t buffer(backingBuffer);
|
||||||
|
|
||||||
bool rc = bencode_write_uint64(&buffer, d.input);
|
bool rc = bencode_write_bytestring(&buffer, d.input.data(), d.input.size());
|
||||||
|
|
||||||
ASSERT_EQ(rc, d.rc);
|
REQUIRE(rc == d.rc);
|
||||||
ASSERT_EQ(std::string(buffer.base, buffer.cur), d.output);
|
REQUIRE(std::string(buffer.base, buffer.cur) == d.output);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const TestWriteInt testWriteInt[] = {
|
std::vector<TestWriteInt> testWriteInt{
|
||||||
// Good cases
|
// Good cases
|
||||||
{0, 100, true, "i0e"},
|
{0, 100, true, "i0e"},
|
||||||
{1234, 100, true, "i1234e"},
|
{1234, 100, true, "i1234e"},
|
||||||
|
@ -194,59 +157,62 @@ static const TestWriteInt testWriteInt[] = {
|
||||||
{1234567, 3, false, ""},
|
{1234567, 3, false, ""},
|
||||||
};
|
};
|
||||||
|
|
||||||
INSTANTIATE_TEST_SUITE_P(TestBencode, WriteInt,
|
TEST_CASE("Write int", "[bencode]")
|
||||||
::testing::ValuesIn(testWriteInt));
|
|
||||||
|
|
||||||
struct WriteIntValues : public ::testing::TestWithParam< uint64_t >
|
|
||||||
{
|
{
|
||||||
};
|
auto d = GENERATE(from_range(testWriteInt));
|
||||||
|
|
||||||
TEST_P(WriteIntValues, anyvalue)
|
std::vector<byte_t> backingBuffer(d.bufferSize, 0);
|
||||||
|
llarp_buffer_t buffer(backingBuffer);
|
||||||
|
|
||||||
|
bool rc = bencode_write_uint64(&buffer, d.input);
|
||||||
|
|
||||||
|
REQUIRE(rc == d.rc);
|
||||||
|
REQUIRE(std::string(buffer.base, buffer.cur) == d.output);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Write int values", "[bencode]")
|
||||||
{
|
{
|
||||||
// test we can encode any uint64_t into a buffer.
|
// test we can encode any uint64_t into a buffer.
|
||||||
uint64_t val = GetParam();
|
uint64_t val = GENERATE(
|
||||||
|
std::numeric_limits<uint64_t>::min(),
|
||||||
|
std::numeric_limits<uint64_t>::max(),
|
||||||
|
std::numeric_limits<uint64_t>::max() / 2,
|
||||||
|
std::numeric_limits<uint64_t>::max() / 3);
|
||||||
|
|
||||||
std::vector< byte_t > backingBuffer(100, 0);
|
std::vector<byte_t> backingBuffer(100, 0);
|
||||||
|
|
||||||
{
|
{
|
||||||
llarp_buffer_t buffer(backingBuffer);
|
llarp_buffer_t buffer(backingBuffer);
|
||||||
|
|
||||||
bool rc = bencode_write_uint64(&buffer, val);
|
bool rc = bencode_write_uint64(&buffer, val);
|
||||||
ASSERT_TRUE(rc);
|
REQUIRE(rc);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
uint64_t result = 0;
|
uint64_t result = 0;
|
||||||
llarp_buffer_t buffer(backingBuffer);
|
llarp_buffer_t buffer(backingBuffer);
|
||||||
bool rc = bencode_read_integer(&buffer, &result);
|
bool rc = bencode_read_integer(&buffer, &result);
|
||||||
ASSERT_TRUE(rc);
|
REQUIRE(rc);
|
||||||
ASSERT_EQ(result, val);
|
REQUIRE(result == val);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
INSTANTIATE_TEST_SUITE_P(
|
TEST_CASE("Bencode: good uint64 entry", "[bencode]")
|
||||||
TestBencode, WriteIntValues,
|
|
||||||
::testing::Values(std::numeric_limits< uint64_t >::min(),
|
|
||||||
std::numeric_limits< uint64_t >::max(),
|
|
||||||
std::numeric_limits< uint64_t >::max() / 2,
|
|
||||||
std::numeric_limits< uint64_t >::max() / 3));
|
|
||||||
|
|
||||||
TEST(TestBencode, good_uint64_entry)
|
|
||||||
{
|
{
|
||||||
std::vector< byte_t > backingBuffer(100, 0);
|
std::vector<byte_t> backingBuffer(100, 0);
|
||||||
llarp_buffer_t buffer(backingBuffer);
|
llarp_buffer_t buffer(backingBuffer);
|
||||||
|
|
||||||
ASSERT_TRUE(bencode_write_uint64_entry(&buffer, "v", 1, 0));
|
REQUIRE(bencode_write_uint64_entry(&buffer, "v", 1, 0));
|
||||||
|
|
||||||
ASSERT_EQ(std::string(buffer.base, buffer.cur), "1:vi0e");
|
REQUIRE(std::string(buffer.base, buffer.cur) == "1:vi0e");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(TestBencode, bad_uint64_entry)
|
TEST_CASE("Bencode: bad uint64 entry", "[bencode]")
|
||||||
{
|
{
|
||||||
std::vector< byte_t > otherBuffer(1, 0);
|
std::vector<byte_t> otherBuffer(1, 0);
|
||||||
llarp_buffer_t buffer(otherBuffer);
|
llarp_buffer_t buffer(otherBuffer);
|
||||||
|
|
||||||
ASSERT_FALSE(bencode_write_uint64_entry(&buffer, "v", 1, 0));
|
REQUIRE_FALSE(bencode_write_uint64_entry(&buffer, "v", 1, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ValueData
|
struct ValueData
|
||||||
|
@ -259,172 +225,139 @@ struct ValueData
|
||||||
|
|
||||||
struct ListTestData
|
struct ListTestData
|
||||||
{
|
{
|
||||||
std::vector< ValueData > list;
|
std::vector<ValueData> list;
|
||||||
size_t bufferSize;
|
size_t bufferSize;
|
||||||
std::string result;
|
std::string result;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ListTest : public ::testing::TestWithParam< ListTestData >
|
std::vector<ListTestData> listTestData{
|
||||||
{
|
|
||||||
};
|
|
||||||
|
|
||||||
TEST_P(ListTest, list)
|
|
||||||
{
|
|
||||||
auto d = GetParam();
|
|
||||||
|
|
||||||
std::vector< byte_t > backingBuffer(d.bufferSize, 0);
|
|
||||||
llarp_buffer_t buffer(backingBuffer);
|
|
||||||
|
|
||||||
ASSERT_TRUE(bencode_start_list(&buffer));
|
|
||||||
|
|
||||||
for(const auto& x : d.list)
|
|
||||||
{
|
|
||||||
if(x.isString)
|
|
||||||
{
|
|
||||||
ASSERT_TRUE(bencode_write_bytestring(&buffer, x.theString.data(),
|
|
||||||
x.theString.size()));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ASSERT_TRUE(bencode_write_uint64(&buffer, x.theInt));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ASSERT_TRUE(bencode_end(&buffer));
|
|
||||||
|
|
||||||
ASSERT_EQ(std::string(buffer.base, buffer.cur), d.result);
|
|
||||||
}
|
|
||||||
|
|
||||||
ListTestData listTestData[] = {
|
|
||||||
{{}, 100, "le"},
|
{{}, 100, "le"},
|
||||||
{{{"", 0, true}}, 100, "l0:e"},
|
{{{"", 0, true}}, 100, "l0:e"},
|
||||||
{{{"", 0, false}}, 100, "li0ee"},
|
{{{"", 0, false}}, 100, "li0ee"},
|
||||||
{{{"", 0, false}, {"", 0, true}}, 100, "li0e0:e"},
|
{{{"", 0, false}, {"", 0, true}}, 100, "li0e0:e"},
|
||||||
{{{"", 123, false}, {"abc", 0, true}}, 100, "li123e3:abce"},
|
{{{"", 123, false}, {"abc", 0, true}}, 100, "li123e3:abce"},
|
||||||
{{{"", 123, false}, {"abc", 0, true}, {"abc", 0, true}},
|
{{{"", 123, false}, {"abc", 0, true}, {"abc", 0, true}}, 100, "li123e3:abc3:abce"},
|
||||||
100,
|
|
||||||
"li123e3:abc3:abce"},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
INSTANTIATE_TEST_SUITE_P(TestBencode, ListTest,
|
TEST_CASE("List test", "[bencode]")
|
||||||
::testing::ValuesIn(listTestData));
|
{
|
||||||
|
auto d = GENERATE(from_range(listTestData));
|
||||||
|
|
||||||
|
std::vector<byte_t> backingBuffer(d.bufferSize, 0);
|
||||||
|
llarp_buffer_t buffer(backingBuffer);
|
||||||
|
|
||||||
|
REQUIRE(bencode_start_list(&buffer));
|
||||||
|
|
||||||
|
for (const auto& x : d.list)
|
||||||
|
{
|
||||||
|
if (x.isString)
|
||||||
|
{
|
||||||
|
REQUIRE(bencode_write_bytestring(&buffer, x.theString.data(), x.theString.size()));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
REQUIRE(bencode_write_uint64(&buffer, x.theInt));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
REQUIRE(bencode_end(&buffer));
|
||||||
|
|
||||||
|
REQUIRE(std::string(buffer.base, buffer.cur) == d.result);
|
||||||
|
}
|
||||||
|
|
||||||
struct DictTestData
|
struct DictTestData
|
||||||
{
|
{
|
||||||
std::vector< std::pair< char, ValueData > > list;
|
std::vector<std::pair<char, ValueData>> list;
|
||||||
size_t bufferSize;
|
size_t bufferSize;
|
||||||
std::string result;
|
std::string result;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct DictTest : public ::testing::TestWithParam< DictTestData >
|
std::vector<DictTestData> dictTestData{
|
||||||
{
|
|
||||||
};
|
|
||||||
|
|
||||||
TEST_P(DictTest, dict)
|
|
||||||
{
|
|
||||||
auto d = GetParam();
|
|
||||||
|
|
||||||
std::vector< byte_t > backingBuffer(d.bufferSize, 0);
|
|
||||||
llarp_buffer_t buffer(backingBuffer);
|
|
||||||
|
|
||||||
ASSERT_TRUE(bencode_start_dict(&buffer));
|
|
||||||
|
|
||||||
for(const auto& x : d.list)
|
|
||||||
{
|
|
||||||
ASSERT_TRUE(bencode_write_bytestring(&buffer, &x.first, 1));
|
|
||||||
if(x.second.isString)
|
|
||||||
{
|
|
||||||
ASSERT_TRUE(bencode_write_bytestring(&buffer, x.second.theString.data(),
|
|
||||||
x.second.theString.size()));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ASSERT_TRUE(bencode_write_uint64(&buffer, x.second.theInt));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ASSERT_TRUE(bencode_end(&buffer));
|
|
||||||
|
|
||||||
ASSERT_EQ(std::string(buffer.base, buffer.cur), d.result);
|
|
||||||
}
|
|
||||||
|
|
||||||
DictTestData dictTestData[] = {
|
|
||||||
{{}, 100, "de"},
|
{{}, 100, "de"},
|
||||||
{{{'a', {"", 0, true}}}, 100, "d1:a0:e"},
|
{{{'a', {"", 0, true}}}, 100, "d1:a0:e"},
|
||||||
{{{'b', {"", 0, false}}}, 100, "d1:bi0ee"},
|
{{{'b', {"", 0, false}}}, 100, "d1:bi0ee"},
|
||||||
{{{'c', {"", 0, false}}, {'d', {"", 0, true}}}, 100, "d1:ci0e1:d0:e"},
|
{{{'c', {"", 0, false}}, {'d', {"", 0, true}}}, 100, "d1:ci0e1:d0:e"},
|
||||||
{{{'e', {"", 123, false}}, {'f', {"abc", 0, true}}},
|
{{{'e', {"", 123, false}}, {'f', {"abc", 0, true}}}, 100, "d1:ei123e1:f3:abce"},
|
||||||
100,
|
{{{'a', {"", 123, false}}, {'b', {"abc", 0, true}}, {'c', {"abc", 0, true}}},
|
||||||
"d1:ei123e1:f3:abce"},
|
|
||||||
{{{'a', {"", 123, false}},
|
|
||||||
{'b', {"abc", 0, true}},
|
|
||||||
{'c', {"abc", 0, true}}},
|
|
||||||
100,
|
100,
|
||||||
"d1:ai123e1:b3:abc1:c3:abce"},
|
"d1:ai123e1:b3:abc1:c3:abce"},
|
||||||
};
|
};
|
||||||
|
|
||||||
INSTANTIATE_TEST_SUITE_P(TestBencode, DictTest,
|
TEST_CASE("Dict test", "[bencode]")
|
||||||
::testing::ValuesIn(dictTestData));
|
{
|
||||||
|
auto d = GENERATE(from_range(dictTestData));
|
||||||
|
|
||||||
|
std::vector<byte_t> backingBuffer(d.bufferSize, 0);
|
||||||
|
llarp_buffer_t buffer(backingBuffer);
|
||||||
|
|
||||||
|
REQUIRE(bencode_start_dict(&buffer));
|
||||||
|
|
||||||
|
for (const auto& x : d.list)
|
||||||
|
{
|
||||||
|
REQUIRE(bencode_write_bytestring(&buffer, &x.first, 1));
|
||||||
|
if (x.second.isString)
|
||||||
|
{
|
||||||
|
REQUIRE(
|
||||||
|
bencode_write_bytestring(&buffer, x.second.theString.data(), x.second.theString.size()));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
REQUIRE(bencode_write_uint64(&buffer, x.second.theInt));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
REQUIRE(bencode_end(&buffer));
|
||||||
|
|
||||||
|
REQUIRE(std::string(buffer.base, buffer.cur) == d.result);
|
||||||
|
}
|
||||||
|
|
||||||
struct ReadData
|
struct ReadData
|
||||||
{
|
{
|
||||||
std::string input;
|
std::string input;
|
||||||
std::vector< std::string > output;
|
std::vector<std::string> output;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct DictReadTest : public ::testing::TestWithParam< ReadData >
|
std::vector<ReadData> dictReadData{
|
||||||
{
|
{"de", {}}, {"d1:a0:e", {"a", ""}}, {"d1:be", {"b"}}, {"d1:b2:23e", {"b", "23"}}};
|
||||||
};
|
|
||||||
|
|
||||||
TEST_P(DictReadTest, readtest)
|
TEST_CASE("Read dict", "[bencode]")
|
||||||
{
|
{
|
||||||
auto d = GetParam();
|
auto d = GENERATE(from_range(dictReadData));
|
||||||
|
|
||||||
byte_t* input =
|
byte_t* input = const_cast<byte_t*>(reinterpret_cast<const byte_t*>(d.input.data()));
|
||||||
const_cast< byte_t* >(reinterpret_cast< const byte_t* >(d.input.data()));
|
|
||||||
|
|
||||||
llarp_buffer_t buffer(input, input, d.input.size());
|
llarp_buffer_t buffer(input, input, d.input.size());
|
||||||
|
|
||||||
std::vector< std::string > result;
|
std::vector<std::string> result;
|
||||||
|
|
||||||
ASSERT_TRUE(llarp::bencode_read_dict(
|
REQUIRE(llarp::bencode_read_dict(
|
||||||
[&](llarp_buffer_t*, llarp_buffer_t* key) {
|
[&](llarp_buffer_t*, llarp_buffer_t* key) {
|
||||||
if(key)
|
if (key)
|
||||||
{
|
{
|
||||||
result.emplace_back(key->base, key->base + key->sz);
|
result.emplace_back(key->base, key->base + key->sz);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
&buffer));
|
&buffer));
|
||||||
ASSERT_EQ(result, d.output);
|
REQUIRE(result == d.output);
|
||||||
}
|
}
|
||||||
|
|
||||||
ReadData dictReadData[] = {{"de", {}},
|
std::vector<ReadData> listReadData{
|
||||||
{"d1:a0:e", {"a", ""}},
|
{"le", {}}, {"l1:ae", {"a"}}, {"l1:be", {"b"}}, {"l1:b2:23e", {"b", "23"}}};
|
||||||
{"d1:be", {"b"}},
|
|
||||||
{"d1:b2:23e", {"b", "23"}}};
|
|
||||||
|
|
||||||
INSTANTIATE_TEST_SUITE_P(TestBencode, DictReadTest,
|
TEST_CASE("Read list", "[bencode]")
|
||||||
::testing::ValuesIn(dictReadData));
|
|
||||||
|
|
||||||
struct ListReadTest : public ::testing::TestWithParam< ReadData >
|
|
||||||
{
|
{
|
||||||
};
|
auto d = GENERATE(from_range(listReadData));
|
||||||
|
|
||||||
TEST_P(ListReadTest, readtest)
|
byte_t* input = const_cast<byte_t*>(reinterpret_cast<const byte_t*>(d.input.data()));
|
||||||
{
|
|
||||||
auto d = GetParam();
|
|
||||||
|
|
||||||
byte_t* input =
|
|
||||||
const_cast< byte_t* >(reinterpret_cast< const byte_t* >(d.input.data()));
|
|
||||||
|
|
||||||
llarp_buffer_t buffer(input, input, d.input.size());
|
llarp_buffer_t buffer(input, input, d.input.size());
|
||||||
|
|
||||||
std::vector< std::string > result;
|
std::vector<std::string> result;
|
||||||
|
|
||||||
ASSERT_TRUE(llarp::bencode_read_list(
|
REQUIRE(llarp::bencode_read_list(
|
||||||
[&](llarp_buffer_t* b, bool cont) {
|
[&](llarp_buffer_t* b, bool cont) {
|
||||||
if(cont)
|
if (cont)
|
||||||
{
|
{
|
||||||
llarp_buffer_t tmp;
|
llarp_buffer_t tmp;
|
||||||
bencode_read_string(b, &tmp);
|
bencode_read_string(b, &tmp);
|
||||||
|
@ -433,18 +366,12 @@ TEST_P(ListReadTest, readtest)
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
&buffer));
|
&buffer));
|
||||||
ASSERT_EQ(result, d.output);
|
REQUIRE(result == d.output);
|
||||||
}
|
}
|
||||||
|
|
||||||
ReadData listReadData[] = {
|
TEST_CASE("Read dict to empty buffer", "[bencode]")
|
||||||
{"le", {}}, {"l1:ae", {"a"}}, {"l1:be", {"b"}}, {"l1:b2:23e", {"b", "23"}}};
|
|
||||||
|
|
||||||
INSTANTIATE_TEST_SUITE_P(TestBencode, ListReadTest,
|
|
||||||
::testing::ValuesIn(listReadData));
|
|
||||||
|
|
||||||
TEST(TestBencode, ReadDictEmptyBuffer)
|
|
||||||
{
|
{
|
||||||
llarp_buffer_t buf((byte_t*)nullptr, 0);
|
llarp_buffer_t buf((byte_t*)nullptr, 0);
|
||||||
ASSERT_FALSE(llarp::bencode_read_dict(
|
REQUIRE_FALSE(
|
||||||
[](llarp_buffer_t*, llarp_buffer_t*) { return true; }, &buf));
|
llarp::bencode_read_dict([](llarp_buffer_t*, llarp_buffer_t*) { return true; }, &buf));
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,8 +6,8 @@ TEST_CASE("DecayingHashSet test decay static time", "[decaying-hashset]")
|
||||||
{
|
{
|
||||||
static constexpr auto timeout = 5s;
|
static constexpr auto timeout = 5s;
|
||||||
static constexpr auto now = 1s;
|
static constexpr auto now = 1s;
|
||||||
llarp::util::DecayingHashSet<llarp::RouterID> hashset(timeout);
|
llarp::util::DecayingHashSet<llarp::RouterID> hashset{timeout};
|
||||||
const llarp::RouterID zero;
|
const llarp::RouterID zero{};
|
||||||
REQUIRE(zero.IsZero());
|
REQUIRE(zero.IsZero());
|
||||||
REQUIRE(not hashset.Contains(zero));
|
REQUIRE(not hashset.Contains(zero));
|
||||||
REQUIRE(hashset.Insert(zero, now));
|
REQUIRE(hashset.Insert(zero, now));
|
||||||
|
@ -20,20 +20,20 @@ TEST_CASE("DecayingHashSet test decay static time", "[decaying-hashset]")
|
||||||
REQUIRE(not hashset.Contains(zero));
|
REQUIRE(not hashset.Contains(zero));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("DecayingHashSet tset decay dynamic time", "[decaying-hashset]")
|
TEST_CASE("DecayingHashSet test decay dynamic time", "[decaying-hashset]")
|
||||||
{
|
{
|
||||||
static constexpr llarp_time_t timeout = 5s;
|
static constexpr llarp_time_t timeout = 5s;
|
||||||
const llarp_time_t now = llarp::time_now_ms();
|
constexpr auto now = llarp::time_now_ms;
|
||||||
llarp::util::DecayingHashSet<llarp::RouterID> hashset(timeout);
|
llarp::util::DecayingHashSet<llarp::RouterID> hashset{timeout};
|
||||||
const llarp::RouterID zero;
|
const llarp::RouterID zero{};
|
||||||
REQUIRE(zero.IsZero());
|
REQUIRE(zero.IsZero());
|
||||||
REQUIRE(not hashset.Contains(zero));
|
REQUIRE(not hashset.Contains(zero));
|
||||||
REQUIRE(hashset.Insert(zero));
|
REQUIRE(hashset.Insert(zero));
|
||||||
REQUIRE(hashset.Contains(zero));
|
REQUIRE(hashset.Contains(zero));
|
||||||
hashset.Decay(now + 1s);
|
hashset.Decay(now() + 1s);
|
||||||
REQUIRE(hashset.Contains(zero));
|
REQUIRE(hashset.Contains(zero));
|
||||||
hashset.Decay(now + timeout);
|
hashset.Decay(now() + timeout);
|
||||||
REQUIRE(not hashset.Contains(zero));
|
REQUIRE(not hashset.Contains(zero));
|
||||||
hashset.Decay(now + timeout + 1s);
|
hashset.Decay(now() + timeout + 1s);
|
||||||
REQUIRE(not hashset.Contains(zero));
|
REQUIRE(not hashset.Contains(zero));
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
#include <gtest/gtest.h>
|
#include <catch2/catch.hpp>
|
||||||
#include <util/logging/loglevel.hpp>
|
#include <util/logging/loglevel.hpp>
|
||||||
#include <util/logging/logger.hpp>
|
#include <util/logging/logger.hpp>
|
||||||
#include <config/config.hpp>
|
#include <config/config.hpp>
|
||||||
|
@ -8,58 +8,49 @@ using TestString = std::string;
|
||||||
struct TestParseLog
|
struct TestParseLog
|
||||||
{
|
{
|
||||||
TestString input;
|
TestString input;
|
||||||
std::optional< llarp::LogLevel > level;
|
std::optional<llarp::LogLevel> level;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct LogLevelTest : public ::testing::TestWithParam< TestParseLog >
|
std::vector<TestParseLog> testParseLog{// bad cases
|
||||||
{
|
{"bogus", {}},
|
||||||
};
|
{"BOGUS", {}},
|
||||||
|
{"", {}},
|
||||||
|
{" ", {}},
|
||||||
|
// good cases
|
||||||
|
{"info", llarp::eLogInfo},
|
||||||
|
{"infO", llarp::eLogInfo},
|
||||||
|
{"iNfO", llarp::eLogInfo},
|
||||||
|
{"InfO", llarp::eLogInfo},
|
||||||
|
{"INFO", llarp::eLogInfo},
|
||||||
|
{"debug", llarp::eLogDebug},
|
||||||
|
{"warn", llarp::eLogWarn},
|
||||||
|
{"error", llarp::eLogError},
|
||||||
|
{"none", llarp::eLogNone}};
|
||||||
|
|
||||||
TEST_P(LogLevelTest, parseLevel)
|
TEST_CASE("parseLevel")
|
||||||
{
|
{
|
||||||
const auto data = GetParam();
|
const auto data = GENERATE(from_range(testParseLog));
|
||||||
const auto maybe = llarp::LogLevelFromString(data.input);
|
const auto maybe = llarp::LogLevelFromString(data.input);
|
||||||
EXPECT_EQ(maybe, data.level);
|
CHECK(maybe == data.level);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const TestParseLog testParseLog[] = {
|
TEST_CASE("TestLogLevelToName")
|
||||||
// bad cases
|
|
||||||
{"bogus", {}},
|
|
||||||
{"BOGUS", {}},
|
|
||||||
{"", {}},
|
|
||||||
{" ", {}},
|
|
||||||
// good cases
|
|
||||||
{"info", llarp::eLogInfo},
|
|
||||||
{"infO", llarp::eLogInfo},
|
|
||||||
{"iNfO", llarp::eLogInfo},
|
|
||||||
{"InfO", llarp::eLogInfo},
|
|
||||||
{"INFO", llarp::eLogInfo},
|
|
||||||
{"debug", llarp::eLogDebug},
|
|
||||||
{"warn", llarp::eLogWarn},
|
|
||||||
{"error", llarp::eLogError},
|
|
||||||
{"none", llarp::eLogNone}};
|
|
||||||
|
|
||||||
INSTANTIATE_TEST_SUITE_P(TestLogConfig, LogLevelTest,
|
|
||||||
::testing::ValuesIn(testParseLog));
|
|
||||||
|
|
||||||
TEST_F(LogLevelTest, TestLogLevelToName)
|
|
||||||
{
|
{
|
||||||
EXPECT_EQ("Trace", LogLevelToName(llarp::eLogTrace));
|
CHECK("Trace" == LogLevelToName(llarp::eLogTrace));
|
||||||
EXPECT_EQ("Debug", LogLevelToName(llarp::eLogDebug));
|
CHECK("Debug" == LogLevelToName(llarp::eLogDebug));
|
||||||
EXPECT_EQ("Info", LogLevelToName(llarp::eLogInfo));
|
CHECK("Info" == LogLevelToName(llarp::eLogInfo));
|
||||||
EXPECT_EQ("Warn", LogLevelToName(llarp::eLogWarn));
|
CHECK("Warn" == LogLevelToName(llarp::eLogWarn));
|
||||||
EXPECT_EQ("Error", LogLevelToName(llarp::eLogError));
|
CHECK("Error" == LogLevelToName(llarp::eLogError));
|
||||||
EXPECT_EQ("None", LogLevelToName(llarp::eLogNone));
|
CHECK("None" == LogLevelToName(llarp::eLogNone));
|
||||||
EXPECT_EQ("???", LogLevelToName( (llarp::LogLevel)99999 ));
|
CHECK("???" == LogLevelToName((llarp::LogLevel)99999));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(LogLevelTest, TestLogLevelToString)
|
TEST_CASE("TestLogLevelToString")
|
||||||
{
|
{
|
||||||
EXPECT_EQ("TRC", LogLevelToString(llarp::eLogTrace));
|
CHECK("TRC" == LogLevelToString(llarp::eLogTrace));
|
||||||
EXPECT_EQ("DBG", LogLevelToString(llarp::eLogDebug));
|
CHECK("DBG" == LogLevelToString(llarp::eLogDebug));
|
||||||
EXPECT_EQ("NFO", LogLevelToString(llarp::eLogInfo));
|
CHECK("NFO" == LogLevelToString(llarp::eLogInfo));
|
||||||
EXPECT_EQ("WRN", LogLevelToString(llarp::eLogWarn));
|
CHECK("WRN" == LogLevelToString(llarp::eLogWarn));
|
||||||
EXPECT_EQ("ERR", LogLevelToString(llarp::eLogError));
|
CHECK("ERR" == LogLevelToString(llarp::eLogError));
|
||||||
EXPECT_EQ("???", LogLevelToString(llarp::eLogNone));
|
CHECK("???" == LogLevelToString(llarp::eLogNone));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
|
||||||
#include <gtest/gtest.h>
|
#include <catch2/catch.hpp>
|
||||||
|
|
||||||
using namespace llarp;
|
using namespace llarp;
|
||||||
using namespace llarp::thread;
|
using namespace llarp::thread;
|
||||||
|
@ -24,8 +24,7 @@ class Element
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Element(double d, bool _stop = false) : data(d), shouldStop(_stop)
|
Element(double d, bool _stop = false) : data(d), shouldStop(_stop)
|
||||||
{
|
{}
|
||||||
}
|
|
||||||
|
|
||||||
double
|
double
|
||||||
val() const
|
val() const
|
||||||
|
@ -46,7 +45,7 @@ operator==(const Element& lhs, const Element& rhs)
|
||||||
return lhs.val() == rhs.val();
|
return lhs.val() == rhs.val();
|
||||||
}
|
}
|
||||||
|
|
||||||
using ObjQueue = Queue< Element >;
|
using ObjQueue = Queue<Element>;
|
||||||
|
|
||||||
class Args
|
class Args
|
||||||
{
|
{
|
||||||
|
@ -68,14 +67,8 @@ class Args
|
||||||
volatile size_t endSignal;
|
volatile size_t endSignal;
|
||||||
|
|
||||||
Args(size_t _iterations, size_t size = 20 * 1000)
|
Args(size_t _iterations, size_t size = 20 * 1000)
|
||||||
: queue(size)
|
: queue(size), iterations(_iterations), count(0), startSignal(0), runSignal(0), endSignal(0)
|
||||||
, iterations(_iterations)
|
{}
|
||||||
, count(0)
|
|
||||||
, startSignal(0)
|
|
||||||
, runSignal(0)
|
|
||||||
, endSignal(0)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
signal() const
|
signal() const
|
||||||
|
@ -93,10 +86,10 @@ popFrontTester(Args& args)
|
||||||
args.cv.wait(lock, [&] { return args.signal(); });
|
args.cv.wait(lock, [&] { return args.signal(); });
|
||||||
}
|
}
|
||||||
|
|
||||||
for(;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
Element e = args.queue.popFront();
|
Element e = args.queue.popFront();
|
||||||
if(e.stop())
|
if (e.stop())
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -112,9 +105,9 @@ pushBackTester(Args& args)
|
||||||
args.cv.wait(lock, [&] { return args.signal(); });
|
args.cv.wait(lock, [&] { return args.signal(); });
|
||||||
}
|
}
|
||||||
|
|
||||||
for(size_t i = 0; i < args.iterations; ++i)
|
for (size_t i = 0; i < args.iterations; ++i)
|
||||||
{
|
{
|
||||||
Element e{static_cast< double >(i)};
|
Element e{static_cast<double>(i)};
|
||||||
args.queue.pushBack(e);
|
args.queue.pushBack(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -122,38 +115,34 @@ pushBackTester(Args& args)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
abaThread(char* firstValue, char* lastValue, Queue< char* >& queue,
|
abaThread(char* firstValue, char* lastValue, Queue<char*>& queue, util::Barrier& barrier)
|
||||||
util::Barrier& barrier)
|
|
||||||
{
|
{
|
||||||
barrier.Block();
|
barrier.Block();
|
||||||
|
|
||||||
for(char* val = firstValue; val <= lastValue; ++val)
|
for (char* val = firstValue; val <= lastValue; ++val)
|
||||||
{
|
{
|
||||||
queue.pushBack(val);
|
queue.pushBack(val);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Exception : public std::exception
|
struct Exception : public std::exception
|
||||||
{
|
{};
|
||||||
};
|
|
||||||
|
|
||||||
struct ExceptionTester
|
struct ExceptionTester
|
||||||
{
|
{
|
||||||
static std::atomic< std::thread::id > throwFrom;
|
static std::atomic<std::thread::id> throwFrom;
|
||||||
|
|
||||||
void
|
void
|
||||||
test()
|
test()
|
||||||
{
|
{
|
||||||
if(throwFrom != std::thread::id()
|
if (throwFrom != std::thread::id() && std::this_thread::get_id() == throwFrom)
|
||||||
&& std::this_thread::get_id() == throwFrom)
|
|
||||||
{
|
{
|
||||||
throw Exception();
|
throw Exception();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ExceptionTester()
|
ExceptionTester()
|
||||||
{
|
{}
|
||||||
}
|
|
||||||
|
|
||||||
ExceptionTester(const ExceptionTester&)
|
ExceptionTester(const ExceptionTester&)
|
||||||
{
|
{
|
||||||
|
@ -168,7 +157,7 @@ struct ExceptionTester
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
std::atomic< std::thread::id > ExceptionTester::throwFrom = {std::thread::id()};
|
std::atomic<std::thread::id> ExceptionTester::throwFrom = {std::thread::id()};
|
||||||
|
|
||||||
void
|
void
|
||||||
sleepNWait(std::chrono::microseconds microseconds, util::Barrier& barrier)
|
sleepNWait(std::chrono::microseconds microseconds, util::Barrier& barrier)
|
||||||
|
@ -178,18 +167,18 @@ sleepNWait(std::chrono::microseconds microseconds, util::Barrier& barrier)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
exceptionProducer(Queue< ExceptionTester >& queue, util::Semaphore& semaphore,
|
exceptionProducer(
|
||||||
std::atomic_size_t& caught)
|
Queue<ExceptionTester>& queue, util::Semaphore& semaphore, std::atomic_size_t& caught)
|
||||||
{
|
{
|
||||||
static constexpr size_t iterations = 3;
|
static constexpr size_t iterations = 3;
|
||||||
|
|
||||||
for(size_t i = 0; i < iterations; ++i)
|
for (size_t i = 0; i < iterations; ++i)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
queue.pushBack(ExceptionTester());
|
queue.pushBack(ExceptionTester());
|
||||||
}
|
}
|
||||||
catch(const Exception&)
|
catch (const Exception&)
|
||||||
{
|
{
|
||||||
++caught;
|
++caught;
|
||||||
}
|
}
|
||||||
|
@ -204,18 +193,15 @@ struct MoveTester
|
||||||
size_t& moveCounter;
|
size_t& moveCounter;
|
||||||
size_t value;
|
size_t value;
|
||||||
|
|
||||||
explicit MoveTester(size_t& counter, size_t val)
|
explicit MoveTester(size_t& counter, size_t val) : moved(false), moveCounter(counter), value(val)
|
||||||
: moved(false), moveCounter(counter), value(val)
|
{}
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
explicit MoveTester(const MoveTester& rhs) = delete;
|
explicit MoveTester(const MoveTester& rhs) = delete;
|
||||||
|
|
||||||
MoveTester&
|
MoveTester&
|
||||||
operator=(const MoveTester& rhs) = delete;
|
operator=(const MoveTester& rhs) = delete;
|
||||||
|
|
||||||
MoveTester(MoveTester&& rhs)
|
MoveTester(MoveTester&& rhs) : moved(false), moveCounter(rhs.moveCounter), value(rhs.value)
|
||||||
: moved(false), moveCounter(rhs.moveCounter), value(rhs.value)
|
|
||||||
{
|
{
|
||||||
rhs.moved = true;
|
rhs.moved = true;
|
||||||
moveCounter++;
|
moveCounter++;
|
||||||
|
@ -224,8 +210,8 @@ struct MoveTester
|
||||||
MoveTester&
|
MoveTester&
|
||||||
operator=(MoveTester&& rhs)
|
operator=(MoveTester&& rhs)
|
||||||
{
|
{
|
||||||
value = rhs.value;
|
value = rhs.value;
|
||||||
rhs.moved = true;
|
rhs.moved = true;
|
||||||
moveCounter = rhs.moveCounter;
|
moveCounter = rhs.moveCounter;
|
||||||
|
|
||||||
moveCounter++;
|
moveCounter++;
|
||||||
|
@ -234,22 +220,22 @@ struct MoveTester
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
TEST(TestQueue, single)
|
TEST_CASE("single")
|
||||||
{
|
{
|
||||||
ObjQueue queue(1u);
|
ObjQueue queue(1u);
|
||||||
|
|
||||||
ASSERT_EQ(0u, queue.size());
|
REQUIRE(0u == queue.size());
|
||||||
ASSERT_EQ(1u, queue.capacity());
|
REQUIRE(1u == queue.capacity());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(TestQueue, breathing)
|
TEST_CASE("breathing")
|
||||||
{
|
{
|
||||||
static constexpr size_t DEFAULT_CAP = 10 * 1000;
|
static constexpr size_t DEFAULT_CAP = 10 * 1000;
|
||||||
|
|
||||||
ObjQueue queue(DEFAULT_CAP);
|
ObjQueue queue(DEFAULT_CAP);
|
||||||
|
|
||||||
ASSERT_EQ(0u, queue.size());
|
REQUIRE(0u == queue.size());
|
||||||
ASSERT_EQ(DEFAULT_CAP, queue.capacity());
|
REQUIRE(DEFAULT_CAP == queue.capacity());
|
||||||
|
|
||||||
Element e1(1.0);
|
Element e1(1.0);
|
||||||
Element e2(2.0);
|
Element e2(2.0);
|
||||||
|
@ -263,260 +249,261 @@ TEST(TestQueue, breathing)
|
||||||
Element p2 = queue.popFront();
|
Element p2 = queue.popFront();
|
||||||
Element p3 = queue.popFront();
|
Element p3 = queue.popFront();
|
||||||
|
|
||||||
ASSERT_EQ(e1, p1);
|
REQUIRE(e1 == p1);
|
||||||
ASSERT_EQ(e2, p2);
|
REQUIRE(e2 == p2);
|
||||||
ASSERT_EQ(e3, p3);
|
REQUIRE(e3 == p3);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(TestQueue, singleProducerManyConsumer)
|
TEST_CASE("Single producer many consumer")
|
||||||
{
|
{
|
||||||
static constexpr size_t iterations = 100 * 1000;
|
static constexpr size_t iterations = 100 * 1000;
|
||||||
static constexpr size_t numThreads = 5;
|
static constexpr size_t numThreads = 5;
|
||||||
|
|
||||||
std::array< std::thread, numThreads > threads;
|
std::array<std::thread, numThreads> threads;
|
||||||
|
|
||||||
Args args{iterations};
|
Args args{iterations};
|
||||||
|
|
||||||
{
|
{
|
||||||
LockGuard lock(args.mutex);
|
LockGuard lock(args.mutex);
|
||||||
|
|
||||||
for(size_t i = 0; i < threads.size(); ++i)
|
for (size_t i = 0; i < threads.size(); ++i)
|
||||||
{
|
{
|
||||||
threads[i] = std::thread(std::bind(&popFrontTester, std::ref(args)));
|
threads[i] = std::thread(std::bind(&popFrontTester, std::ref(args)));
|
||||||
args.cv.wait(lock, [&] { return args.count != i+1; });
|
args.cv.wait(lock, [&] { return args.count != i + 1; });
|
||||||
}
|
}
|
||||||
|
|
||||||
args.runSignal++;
|
args.runSignal++;
|
||||||
}
|
}
|
||||||
|
|
||||||
for(size_t i = 0; i < iterations; ++i)
|
for (size_t i = 0; i < iterations; ++i)
|
||||||
{
|
{
|
||||||
Element e{static_cast< double >(i)};
|
Element e{static_cast<double>(i)};
|
||||||
args.queue.pushBack(e);
|
args.queue.pushBack(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
for(size_t i = 0; i < numThreads; ++i)
|
for (size_t i = 0; i < numThreads; ++i)
|
||||||
{
|
{
|
||||||
Element e{0.0, true};
|
Element e{0.0, true};
|
||||||
args.queue.pushBack(e);
|
args.queue.pushBack(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
for(size_t i = 0; i < numThreads; ++i)
|
for (size_t i = 0; i < numThreads; ++i)
|
||||||
{
|
{
|
||||||
threads[i].join();
|
threads[i].join();
|
||||||
}
|
}
|
||||||
|
|
||||||
ASSERT_EQ(0u, args.queue.size());
|
REQUIRE(0u == args.queue.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(TestQueue, manyProducerManyConsumer)
|
TEST_CASE("Many producer many consumer")
|
||||||
{
|
{
|
||||||
static constexpr size_t iterations = 100 * 1000;
|
static constexpr size_t iterations = 100 * 1000;
|
||||||
static constexpr size_t numThreads = 5;
|
static constexpr size_t numThreads = 5;
|
||||||
|
|
||||||
std::array< std::thread, numThreads * 2 > threads;
|
std::array<std::thread, numThreads * 2> threads;
|
||||||
|
|
||||||
Args args{iterations};
|
Args args{iterations};
|
||||||
|
|
||||||
{
|
{
|
||||||
LockGuard lock(args.mutex);
|
LockGuard lock(args.mutex);
|
||||||
|
|
||||||
for(size_t i = 0; i < numThreads; ++i)
|
for (size_t i = 0; i < numThreads; ++i)
|
||||||
{
|
{
|
||||||
threads[i] = std::thread(std::bind(&popFrontTester, std::ref(args)));
|
threads[i] = std::thread(std::bind(&popFrontTester, std::ref(args)));
|
||||||
args.cv.wait(lock, [&] { return args.count != i+1; });
|
args.cv.wait(lock, [&] { return args.count != i + 1; });
|
||||||
}
|
}
|
||||||
|
|
||||||
for(size_t i = 0; i < numThreads; ++i)
|
for (size_t i = 0; i < numThreads; ++i)
|
||||||
{
|
{
|
||||||
threads[i + numThreads] =
|
threads[i + numThreads] = std::thread(std::bind(&pushBackTester, std::ref(args)));
|
||||||
std::thread(std::bind(&pushBackTester, std::ref(args)));
|
args.cv.wait(lock, [&] { return args.count != numThreads + i + 1; });
|
||||||
args.cv.wait(lock, [&] { return args.count != numThreads+i+1; });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
args.runSignal++;
|
args.runSignal++;
|
||||||
}
|
}
|
||||||
|
|
||||||
for(auto& thread : threads)
|
for (auto& thread : threads)
|
||||||
{
|
{
|
||||||
thread.join();
|
thread.join();
|
||||||
}
|
}
|
||||||
|
|
||||||
ASSERT_EQ(0u, args.queue.size());
|
REQUIRE(0u == args.queue.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(TestQueue, ABAEmpty)
|
TEST_CASE("ABA empty")
|
||||||
{
|
{
|
||||||
// Verify we avoid the ABA problem, where multiple threads try to push an
|
// Verify we avoid the ABA problem, where multiple threads try to push an
|
||||||
// object to the same "empty" position in the queue.
|
// object to the same "empty" position in the queue.
|
||||||
|
|
||||||
static constexpr size_t numThreads = 50;
|
static constexpr size_t numThreads = 50;
|
||||||
static constexpr size_t numValues = 6;
|
static constexpr size_t numValues = 6;
|
||||||
static constexpr size_t numIterations = 1000;
|
static constexpr size_t numIterations = 1000;
|
||||||
static constexpr size_t numEntries = numThreads * numValues;
|
static constexpr size_t numEntries = numThreads * numValues;
|
||||||
|
|
||||||
char block[numEntries];
|
char block[numEntries];
|
||||||
|
|
||||||
for(size_t i = 0; i < numIterations; ++i)
|
for (size_t i = 0; i < numIterations; ++i)
|
||||||
{
|
{
|
||||||
util::Barrier barrier{numThreads + 1};
|
util::Barrier barrier{numThreads + 1};
|
||||||
|
|
||||||
Queue< char* > queue{numEntries + 1};
|
Queue<char*> queue{numEntries + 1};
|
||||||
|
|
||||||
std::array< std::thread, numThreads + 1 > threads;
|
std::array<std::thread, numThreads + 1> threads;
|
||||||
|
|
||||||
char* nextValue[numThreads];
|
char* nextValue[numThreads];
|
||||||
char* lastValue[numThreads];
|
char* lastValue[numThreads];
|
||||||
|
|
||||||
for(size_t j = 0; j < numThreads; ++j)
|
for (size_t j = 0; j < numThreads; ++j)
|
||||||
{
|
{
|
||||||
nextValue[j] = block + (numValues * j);
|
nextValue[j] = block + (numValues * j);
|
||||||
lastValue[j] = block + (numValues * (j + 1)) - 1;
|
lastValue[j] = block + (numValues * (j + 1)) - 1;
|
||||||
|
|
||||||
threads[j] = std::thread([&, n=nextValue[j], l=lastValue[j]] { abaThread(n, l, queue, barrier); });
|
threads[j] =
|
||||||
|
std::thread([&, n = nextValue[j], l = lastValue[j]] { abaThread(n, l, queue, barrier); });
|
||||||
}
|
}
|
||||||
|
|
||||||
threads[numThreads] = std::thread([&] {
|
threads[numThreads] = std::thread([&] {
|
||||||
std::this_thread::sleep_for(100us);
|
std::this_thread::sleep_for(100us);
|
||||||
barrier.Block();
|
barrier.Block();
|
||||||
});
|
});
|
||||||
|
|
||||||
for(size_t j = 0; j < numEntries; ++j)
|
for (size_t j = 0; j < numEntries; ++j)
|
||||||
{
|
{
|
||||||
char* val = queue.popFront();
|
char* val = queue.popFront();
|
||||||
|
|
||||||
size_t k = 0;
|
size_t k = 0;
|
||||||
|
|
||||||
for(k = 0; k < numThreads; ++k)
|
for (k = 0; k < numThreads; ++k)
|
||||||
{
|
{
|
||||||
if(val == nextValue[k])
|
if (val == nextValue[k])
|
||||||
{
|
{
|
||||||
nextValue[k] += (val == lastValue[k] ? 0 : 1);
|
nextValue[k] += (val == lastValue[k] ? 0 : 1);
|
||||||
ASSERT_LE(nextValue[k], lastValue[k]);
|
REQUIRE(nextValue[k] <= lastValue[k]);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ASSERT_LT(k, numThreads);
|
REQUIRE(k < numThreads);
|
||||||
}
|
}
|
||||||
|
|
||||||
for(auto& thread : threads)
|
for (auto& thread : threads)
|
||||||
{
|
{
|
||||||
thread.join();
|
thread.join();
|
||||||
}
|
}
|
||||||
|
|
||||||
ASSERT_EQ(0u, queue.size());
|
REQUIRE(0u == queue.size());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(TestQueue, generationCount)
|
TEST_CASE("Generation count")
|
||||||
{
|
{
|
||||||
// Verify functionality after running through a full cycle (and invoking the
|
// Verify functionality after running through a full cycle (and invoking the
|
||||||
// generation rollover logic).
|
// generation rollover logic).
|
||||||
// For a queue of size 3, this is currently 508 cycles, implying we need to go
|
// For a queue of size 3, this is currently 508 cycles, implying we need to go
|
||||||
// through at least 3048 objects (3 * 508 * 2) to trigger this logic twice.
|
// through at least 3048 objects (3 * 508 * 2) to trigger this logic twice.
|
||||||
static constexpr size_t numThreads = 6;
|
static constexpr size_t numThreads = 6;
|
||||||
static constexpr size_t queueSize = 3;
|
static constexpr size_t queueSize = 3;
|
||||||
static constexpr size_t numEntries = 3060;
|
static constexpr size_t numEntries = 3060;
|
||||||
static constexpr size_t numValues = numEntries / numThreads;
|
static constexpr size_t numValues = numEntries / numThreads;
|
||||||
|
|
||||||
char block[numEntries];
|
char block[numEntries];
|
||||||
|
|
||||||
util::Barrier barrier{numThreads + 1};
|
util::Barrier barrier{numThreads + 1};
|
||||||
|
|
||||||
Queue< char* > queue{queueSize};
|
Queue<char*> queue{queueSize};
|
||||||
|
|
||||||
std::array< std::thread, numThreads + 1 > threads;
|
std::array<std::thread, numThreads + 1> threads;
|
||||||
|
|
||||||
char* nextValue[numThreads];
|
char* nextValue[numThreads];
|
||||||
char* lastValue[numThreads];
|
char* lastValue[numThreads];
|
||||||
|
|
||||||
for(size_t j = 0; j < numThreads; ++j)
|
for (size_t j = 0; j < numThreads; ++j)
|
||||||
{
|
{
|
||||||
nextValue[j] = block + (numValues * j);
|
nextValue[j] = block + (numValues * j);
|
||||||
lastValue[j] = block + (numValues * (j + 1)) - 1;
|
lastValue[j] = block + (numValues * (j + 1)) - 1;
|
||||||
|
|
||||||
threads[j] = std::thread([&, n=nextValue[j], l=lastValue[j]] { abaThread(n, l, queue, barrier); });
|
threads[j] =
|
||||||
|
std::thread([&, n = nextValue[j], l = lastValue[j]] { abaThread(n, l, queue, barrier); });
|
||||||
}
|
}
|
||||||
|
|
||||||
threads[numThreads] = std::thread([&] {
|
threads[numThreads] = std::thread([&] {
|
||||||
std::this_thread::sleep_for(100ms);
|
std::this_thread::sleep_for(100ms);
|
||||||
barrier.Block();
|
barrier.Block();
|
||||||
});
|
});
|
||||||
|
|
||||||
for(size_t j = 0; j < numEntries; ++j)
|
for (size_t j = 0; j < numEntries; ++j)
|
||||||
{
|
{
|
||||||
char* val = queue.popFront();
|
char* val = queue.popFront();
|
||||||
|
|
||||||
size_t k = 0;
|
size_t k = 0;
|
||||||
|
|
||||||
for(k = 0; k < numThreads; ++k)
|
for (k = 0; k < numThreads; ++k)
|
||||||
{
|
{
|
||||||
if(val == nextValue[k])
|
if (val == nextValue[k])
|
||||||
{
|
{
|
||||||
nextValue[k] += (val == lastValue[k] ? 0 : 1);
|
nextValue[k] += (val == lastValue[k] ? 0 : 1);
|
||||||
ASSERT_LE(nextValue[k], lastValue[k]);
|
REQUIRE(nextValue[k] <= lastValue[k]);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ASSERT_LT(k, numThreads);
|
REQUIRE(k < numThreads);
|
||||||
}
|
}
|
||||||
|
|
||||||
for(auto& thread : threads)
|
for (auto& thread : threads)
|
||||||
{
|
{
|
||||||
thread.join();
|
thread.join();
|
||||||
}
|
}
|
||||||
|
|
||||||
ASSERT_EQ(0u, queue.size());
|
REQUIRE(0u == queue.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(TestQueue, basicExceptionSafety)
|
TEST_CASE("Basic exception safety")
|
||||||
{
|
{
|
||||||
ExceptionTester::throwFrom = std::this_thread::get_id();
|
ExceptionTester::throwFrom = std::this_thread::get_id();
|
||||||
|
|
||||||
Queue< ExceptionTester > queue{1};
|
Queue<ExceptionTester> queue{1};
|
||||||
|
|
||||||
ASSERT_THROW(queue.pushBack(ExceptionTester()), Exception);
|
REQUIRE_THROWS_AS(queue.pushBack(ExceptionTester()), Exception);
|
||||||
|
|
||||||
ExceptionTester::throwFrom = std::thread::id();
|
ExceptionTester::throwFrom = std::thread::id();
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(TestQueue, exceptionSafety)
|
TEST_CASE("Exception safety")
|
||||||
{
|
{
|
||||||
ExceptionTester::throwFrom = std::thread::id();
|
ExceptionTester::throwFrom = std::thread::id();
|
||||||
static constexpr size_t queueSize = 3;
|
static constexpr size_t queueSize = 3;
|
||||||
|
|
||||||
Queue< ExceptionTester > queue{queueSize};
|
Queue<ExceptionTester> queue{queueSize};
|
||||||
|
|
||||||
ASSERT_EQ(QueueReturn::Success, queue.pushBack(ExceptionTester()));
|
REQUIRE(QueueReturn::Success == queue.pushBack(ExceptionTester()));
|
||||||
ASSERT_EQ(QueueReturn::Success, queue.pushBack(ExceptionTester()));
|
REQUIRE(QueueReturn::Success == queue.pushBack(ExceptionTester()));
|
||||||
ASSERT_EQ(QueueReturn::Success, queue.pushBack(ExceptionTester()));
|
REQUIRE(QueueReturn::Success == queue.pushBack(ExceptionTester()));
|
||||||
ASSERT_NE(QueueReturn::Success, queue.tryPushBack(ExceptionTester()));
|
REQUIRE(QueueReturn::Success != queue.tryPushBack(ExceptionTester()));
|
||||||
|
|
||||||
util::Semaphore semaphore{0};
|
util::Semaphore semaphore{0};
|
||||||
|
|
||||||
std::atomic_size_t caught = {0};
|
std::atomic_size_t caught = {0};
|
||||||
|
|
||||||
std::thread producer(std::bind(&exceptionProducer, std::ref(queue),
|
std::thread producer(
|
||||||
std::ref(semaphore), std::ref(caught)));
|
std::bind(&exceptionProducer, std::ref(queue), std::ref(semaphore), std::ref(caught)));
|
||||||
|
|
||||||
ExceptionTester::throwFrom = std::this_thread::get_id();
|
ExceptionTester::throwFrom = std::this_thread::get_id();
|
||||||
|
|
||||||
ASSERT_THROW({ (void)queue.popFront(); }, Exception);
|
REQUIRE_THROWS_AS(queue.popFront(), Exception);
|
||||||
|
|
||||||
using namespace std::literals;
|
using namespace std::literals;
|
||||||
// Now the queue is not full, and the producer thread can start adding items.
|
// Now the queue is not full, and the producer thread can start adding items.
|
||||||
ASSERT_TRUE(semaphore.waitFor(1s));
|
REQUIRE(semaphore.waitFor(1s));
|
||||||
|
|
||||||
ASSERT_EQ(queueSize, queue.size());
|
REQUIRE(queueSize == queue.size());
|
||||||
|
|
||||||
ASSERT_THROW({ (void)queue.popFront(); }, Exception);
|
REQUIRE_THROWS_AS(queue.popFront(), Exception);
|
||||||
|
|
||||||
// Now the queue is not full, and the producer thread can start adding items.
|
// Now the queue is not full, and the producer thread can start adding items.
|
||||||
ASSERT_TRUE(semaphore.waitFor(1s));
|
REQUIRE(semaphore.waitFor(1s));
|
||||||
|
|
||||||
ASSERT_EQ(queueSize, queue.size());
|
REQUIRE(queueSize == queue.size());
|
||||||
|
|
||||||
// Pushing into the queue with exception empties the queue.
|
// Pushing into the queue with exception empties the queue.
|
||||||
ExceptionTester::throwFrom = producer.get_id();
|
ExceptionTester::throwFrom = producer.get_id();
|
||||||
|
@ -524,61 +511,61 @@ TEST(TestQueue, exceptionSafety)
|
||||||
// pop an item to unblock the pusher
|
// pop an item to unblock the pusher
|
||||||
(void)queue.popFront();
|
(void)queue.popFront();
|
||||||
|
|
||||||
ASSERT_TRUE(semaphore.waitFor(1s));
|
REQUIRE(semaphore.waitFor(1s));
|
||||||
|
|
||||||
ASSERT_EQ(1u, caught);
|
REQUIRE(1u == caught);
|
||||||
|
|
||||||
ASSERT_EQ(0u, queue.size());
|
REQUIRE(0u == queue.size());
|
||||||
ASSERT_TRUE(queue.empty());
|
REQUIRE(queue.empty());
|
||||||
|
|
||||||
// after throwing, the queue works fine.
|
// after throwing, the queue works fine.
|
||||||
|
|
||||||
ASSERT_EQ(QueueReturn::Success, queue.pushBack(ExceptionTester()));
|
REQUIRE(QueueReturn::Success == queue.pushBack(ExceptionTester()));
|
||||||
ASSERT_EQ(QueueReturn::Success, queue.pushBack(ExceptionTester()));
|
REQUIRE(QueueReturn::Success == queue.pushBack(ExceptionTester()));
|
||||||
ASSERT_EQ(QueueReturn::Success, queue.pushBack(ExceptionTester()));
|
REQUIRE(QueueReturn::Success == queue.pushBack(ExceptionTester()));
|
||||||
ASSERT_NE(QueueReturn::Success, queue.tryPushBack(ExceptionTester()));
|
REQUIRE(QueueReturn::Success != queue.tryPushBack(ExceptionTester()));
|
||||||
|
|
||||||
ExceptionTester::throwFrom = std::thread::id();
|
ExceptionTester::throwFrom = std::thread::id();
|
||||||
|
|
||||||
producer.join();
|
producer.join();
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(TestQueue, moveIt)
|
TEST_CASE("Move it")
|
||||||
{
|
{
|
||||||
static constexpr size_t queueSize = 40;
|
static constexpr size_t queueSize = 40;
|
||||||
|
|
||||||
Queue< MoveTester > queue{queueSize};
|
Queue<MoveTester> queue{queueSize};
|
||||||
|
|
||||||
size_t counter = 0;
|
size_t counter = 0;
|
||||||
|
|
||||||
queue.pushBack(MoveTester{counter, 0});
|
queue.pushBack(MoveTester{counter, 0});
|
||||||
|
|
||||||
ASSERT_EQ(1u, counter);
|
REQUIRE(1u == counter);
|
||||||
|
|
||||||
MoveTester tester2(counter, 2);
|
MoveTester tester2(counter, 2);
|
||||||
queue.pushBack(std::move(tester2));
|
queue.pushBack(std::move(tester2));
|
||||||
|
|
||||||
ASSERT_TRUE(tester2.moved);
|
REQUIRE(tester2.moved);
|
||||||
ASSERT_EQ(2u, counter);
|
REQUIRE(2u == counter);
|
||||||
|
|
||||||
ASSERT_EQ(QueueReturn::Success, queue.tryPushBack(MoveTester{counter, 3}));
|
REQUIRE(QueueReturn::Success == queue.tryPushBack(MoveTester{counter, 3}));
|
||||||
ASSERT_EQ(3u, counter);
|
REQUIRE(3u == counter);
|
||||||
|
|
||||||
MoveTester tester4(counter, 4);
|
MoveTester tester4(counter, 4);
|
||||||
ASSERT_EQ(QueueReturn::Success, queue.tryPushBack(std::move(tester4)));
|
REQUIRE(QueueReturn::Success == queue.tryPushBack(std::move(tester4)));
|
||||||
|
|
||||||
ASSERT_TRUE(tester4.moved);
|
REQUIRE(tester4.moved);
|
||||||
ASSERT_EQ(4u, counter);
|
REQUIRE(4u == counter);
|
||||||
|
|
||||||
MoveTester popped = queue.popFront();
|
MoveTester popped = queue.popFront();
|
||||||
(void)popped;
|
(void)popped;
|
||||||
|
|
||||||
ASSERT_EQ(5u, counter);
|
REQUIRE(5u == counter);
|
||||||
|
|
||||||
std::optional< MoveTester > optPopped = queue.tryPopFront();
|
std::optional<MoveTester> optPopped = queue.tryPopFront();
|
||||||
|
|
||||||
ASSERT_TRUE(optPopped);
|
REQUIRE(optPopped);
|
||||||
|
|
||||||
// Moved twice here to construct the optional.
|
// Moved twice here to construct the optional.
|
||||||
ASSERT_EQ(6u, counter);
|
REQUIRE(6u == counter);
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -90,7 +90,6 @@ Source: "{#DevPath}ui-win32\bin\release\lokinetui.exe.config"; DestDir: "{app}";
|
||||||
Source: "{#DevPath}ui-win32\bin\release\lokinetui.pdb"; DestDir: "{app}"; Flags: ignoreversion
|
Source: "{#DevPath}ui-win32\bin\release\lokinetui.pdb"; DestDir: "{app}"; Flags: ignoreversion
|
||||||
#endif
|
#endif
|
||||||
; eh, might as well ship the 32-bit port of everything else
|
; eh, might as well ship the 32-bit port of everything else
|
||||||
;Source: "{#DevPath}build\testAll.exe"; DestDir: "{app}"; Flags: ignoreversion
|
|
||||||
;Source: "{#DevPath}build\catchAll.exe"; DestDir: "{app}"; Flags: ignoreversion
|
;Source: "{#DevPath}build\catchAll.exe"; DestDir: "{app}"; Flags: ignoreversion
|
||||||
Source: "{#DevPath}build\lokinetctl.exe"; DestDir: "{app}"; Flags: ignoreversion
|
Source: "{#DevPath}build\lokinetctl.exe"; DestDir: "{app}"; Flags: ignoreversion
|
||||||
Source: "LICENSE"; DestDir: "{app}"; Flags: ignoreversion
|
Source: "LICENSE"; DestDir: "{app}"; Flags: ignoreversion
|
||||||
|
|
Loading…
Reference in a new issue