Migrate tests from gtest to catch2

pull/1561/head
lyyn 3 years ago committed by Jeff Becker
parent 4992629f20
commit ece91e87fc
No known key found for this signature in database
GPG Key ID: F357B3B42F6F9B05

@ -56,7 +56,6 @@ local debian_pipeline(name, image,
'-DWITH_LTO=' + (if lto then 'ON ' else 'OFF ') +
cmake_extra,
'ninja -v',
'../contrib/ci/drone-gdb.sh ./test/testAll --gtest_color=yes',
'../contrib/ci/drone-gdb.sh ./test/catchAll --use-colour yes',
] + 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+' ' +
(if werror then '-DWARNINGS_AS_ERRORS=ON ' else '') + cmake_extra,
'ninja -v',
'./test/testAll --gtest_color=yes',
'./test/catchAll --use-colour yes',
] + extra_cmds,
}

@ -8,84 +8,71 @@ if (WITH_HIVE)
hive_build)
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_executable(catchAll
# helpers
check_main.cpp
test_util.cpp
# actual test cases
config/test_llarp_config_definition.cpp
config/test_llarp_config_ini.cpp
config/test_llarp_config_output.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
dns/test_llarp_dns_dns.cpp
exit/test_llarp_exit_context.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
dns/test_llarp_dns_dns.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_name.cpp
util/meta/test_llarp_util_memfn.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
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_output.cpp
net/test_ip_address.cpp
net/test_sock_addr.cpp
service/test_llarp_service_name.cpp
exit/test_llarp_exit_context.cpp
iwp/test_iwp_session.cpp
service/test_llarp_service_identity.cpp
test_util.cpp
test_llarp_router_contact.cpp
check_main.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})
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:
add_custom_target(catch COMMAND catchAll)
add_custom_target(rungtest COMMAND testAll)
# 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 <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>
struct TestINIParser : public ::testing::Test
#include <catch2/catch.hpp>
TEST_CASE("ConfigParser", "[config]")
{
llarp::ConfigParser parser;
void
TearDown()
SECTION("Parse empty")
{
parser.Clear();
REQUIRE(parser.LoadFromStr(""));
}
};
TEST_F(TestINIParser, TestParseEmpty)
{
ASSERT_TRUE(parser.LoadFromStr(""));
}
SECTION("Parse one section")
{
llarp::ConfigParser::SectionValues_t sect;
// this is an anti pattern don't write this kind of code with configpaser
auto assertVisit = [&sect](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)
{
llarp::ConfigParser::SectionValues_t sect;
// this is an anti pattern don't write this kind of code with configpaser
auto assertVisit = [&sect](const auto& section) -> bool {
sect = section;
return true;
};
ASSERT_TRUE(parser.LoadFromStr("[test]\nkey=val \n"));
ASSERT_TRUE(parser.VisitSection("test", assertVisit));
auto itr = sect.find("notfound");
ASSERT_EQ(itr, sect.end());
itr = sect.find("key");
ASSERT_NE(itr, sect.end());
ASSERT_EQ(itr->second, "val");
}
SECTION("Parse section duplicate keys")
{
REQUIRE(parser.LoadFromStr("[test]\nkey1=val1\nkey1=val2"));
size_t num = 0;
auto visit = [&num](const auto& section) -> bool {
num = section.count("key1");
return true;
};
REQUIRE(parser.VisitSection("test", visit));
REQUIRE(num == size_t(2));
}
TEST_F(TestINIParser, TestParseSectionDuplicateKeys)
{
ASSERT_TRUE(parser.LoadFromStr("[test]\nkey1=val1\nkey1=val2"));
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));
}
SECTION("No key")
{
REQUIRE_FALSE(parser.LoadFromStr("[test]\n=1090\n"));
}
TEST_F(TestINIParser, TestNoKey)
{
ASSERT_FALSE(parser.LoadFromStr("[test]\n=1090\n"));
}
SECTION("Parse invalid")
{
REQUIRE_FALSE(
parser.LoadFromStr("srged5ghe5\nf34wtge5\nw34tgfs4ygsd5yg=4;\n#"
"g4syhgd5\n"));
}
TEST_F(TestINIParser, TestParseInvalid)
{
ASSERT_FALSE(
parser.LoadFromStr("srged5ghe5\nf34wtge5\nw34tgfs4ygsd5yg=4;\n#"
"g4syhgd5\n"));
parser.Clear();
}

@ -1 +0,0 @@
#include <crypto/mock_crypto.hpp>

@ -9,76 +9,67 @@ namespace llarp
{
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(xchacha20,
bool(const llarp_buffer_t &, const SharedSecret &,
const TunnelNonce &));
MOCK_METHOD3(
maybe_decrypt_name,
std::optional<AlignedBuffer<32>>(std::string_view, llarp::SymmNonce, std::string_view));
MOCK_METHOD4(xchacha20_alt,
bool(const llarp_buffer_t &, const llarp_buffer_t &,
const SharedSecret &, const byte_t *));
MOCK_METHOD3(xchacha20, bool(const llarp_buffer_t&, const SharedSecret&, const TunnelNonce&));
MOCK_METHOD4(dh_client,
bool(SharedSecret &, const PubKey &, const SecretKey &,
const TunnelNonce &));
MOCK_METHOD4(
xchacha20_alt,
bool(const llarp_buffer_t&, const llarp_buffer_t&, const SharedSecret&, const byte_t*));
MOCK_METHOD4(dh_server,
bool(SharedSecret &, const PubKey &, const SecretKey &,
const TunnelNonce &));
MOCK_METHOD4(
dh_client, bool(SharedSecret&, const PubKey&, const SecretKey&, const TunnelNonce&));
MOCK_METHOD4(transport_dh_client,
bool(SharedSecret &, const PubKey &, const SecretKey &,
const TunnelNonce &));
MOCK_METHOD4(
dh_server, bool(SharedSecret&, const PubKey&, const SecretKey&, const TunnelNonce&));
MOCK_METHOD4(transport_dh_server,
bool(SharedSecret &, const PubKey &, const SecretKey &,
const TunnelNonce &));
MOCK_METHOD4(
transport_dh_client,
bool(SharedSecret&, const PubKey&, const SecretKey&, const TunnelNonce&));
MOCK_METHOD2(hash, bool(byte_t *, const llarp_buffer_t &));
MOCK_METHOD4(
transport_dh_server,
bool(SharedSecret&, const PubKey&, const SecretKey&, const TunnelNonce&));
MOCK_METHOD2(shorthash, bool(ShortHash &, const llarp_buffer_t &));
MOCK_METHOD2(hash, bool(byte_t*, const llarp_buffer_t&));
MOCK_METHOD3(hmac,
bool(byte_t *, const llarp_buffer_t &,
const SharedSecret &));
MOCK_METHOD2(shorthash, bool(ShortHash&, const llarp_buffer_t&));
MOCK_METHOD4(derive_subkey, bool(PubKey &, const PubKey &, uint64_t, const AlignedBuffer<32> *));
MOCK_METHOD3(hmac, bool(byte_t*, const llarp_buffer_t&, const SharedSecret&));
MOCK_METHOD4(derive_subkey_private,
bool(PrivateKey &, const SecretKey &, uint64_t, const AlignedBuffer<32> *));
MOCK_METHOD4(derive_subkey, bool(PubKey&, const PubKey&, uint64_t, const AlignedBuffer<32>*));
MOCK_METHOD(bool, sign, (Signature &, const SecretKey &, const llarp_buffer_t &));
MOCK_METHOD4(
derive_subkey_private,
bool(PrivateKey&, const SecretKey&, uint64_t, const AlignedBuffer<32>*));
MOCK_METHOD(bool, sign, (Signature &, const PrivateKey &, const llarp_buffer_t &));
MOCK_METHOD(bool, sign, (Signature&, const SecretKey&, const llarp_buffer_t&));
MOCK_METHOD3(verify,
bool(const PubKey &, const llarp_buffer_t &,
const Signature &));
MOCK_METHOD(bool, sign, (Signature&, const PrivateKey&, const llarp_buffer_t&));
MOCK_METHOD2(seed_to_secretkey,
bool(llarp::SecretKey &, const llarp::IdentitySecret &));
MOCK_METHOD3(verify, bool(const PubKey&, const llarp_buffer_t&, const Signature&));
MOCK_METHOD1(randomize, void(const llarp_buffer_t &));
MOCK_METHOD2(seed_to_secretkey, bool(llarp::SecretKey&, const llarp::IdentitySecret&));
MOCK_METHOD2(randbytes, void(byte_t *, size_t));
MOCK_METHOD1(randomize, void(const llarp_buffer_t&));
MOCK_METHOD1(identity_keygen, void(SecretKey &));
MOCK_METHOD2(randbytes, void(byte_t*, size_t));
MOCK_METHOD1(encryption_keygen, void(SecretKey &));
MOCK_METHOD1(identity_keygen, void(SecretKey&));
MOCK_METHOD1(pqe_keygen, void(PQKeyPair &));
MOCK_METHOD1(encryption_keygen, void(SecretKey&));
MOCK_METHOD3(pqe_decrypt,
bool(const PQCipherBlock &, SharedSecret &, const byte_t *));
MOCK_METHOD1(pqe_keygen, void(PQKeyPair&));
MOCK_METHOD3(pqe_encrypt,
bool(PQCipherBlock &, SharedSecret &, const PQPubKey &));
MOCK_METHOD3(pqe_decrypt, bool(const PQCipherBlock&, SharedSecret&, const byte_t*));
MOCK_METHOD1(check_identity_privkey, bool(const SecretKey &));
MOCK_METHOD3(pqe_encrypt, bool(PQCipherBlock&, SharedSecret&, const PQPubKey&));
MOCK_METHOD1(check_identity_privkey, bool(const SecretKey&));
};
} // namespace test
} // namespace llarp

@ -2,69 +2,48 @@
#include <iostream>
#include <gtest/gtest.h>
#include <catch2/catch.hpp>
namespace llarp
{
struct IdentityKeyTest : public ::testing::Test
{
llarp::sodium::CryptoLibSodium crypto;
using namespace llarp;
IdentityKeyTest()
{
}
};
TEST_CASE("Identity key")
{
llarp::sodium::CryptoLibSodium crypto;
SecretKey secret;
crypto.identity_keygen(secret);
TEST_F(IdentityKeyTest, TestKeyGen)
SECTION("Keygen")
{
SecretKey secret;
crypto.identity_keygen(secret);
ASSERT_FALSE(secret.IsZero());
REQUIRE_FALSE(secret.IsZero());
}
TEST_F(IdentityKeyTest, TestSignVerify)
SECTION("Sign-verify")
{
SecretKey secret;
crypto.identity_keygen(secret);
AlignedBuffer< 128 > random;
AlignedBuffer<128> random;
random.Randomize();
Signature sig;
const PubKey pk = secret.toPublic();
const llarp_buffer_t buf(random.data(), random.size());
ASSERT_TRUE(crypto.sign(sig, secret, buf));
ASSERT_TRUE(crypto.verify(pk, buf, sig));
REQUIRE(crypto.sign(sig, secret, buf));
REQUIRE(crypto.verify(pk, buf, sig));
random.Randomize();
// mangle body
ASSERT_FALSE(crypto.verify(pk, buf, sig));
REQUIRE_FALSE(crypto.verify(pk, buf, sig));
}
}
struct PQCryptoTest : public ::testing::Test
{
llarp::sodium::CryptoLibSodium crypto;
PQKeyPair keys;
PQCryptoTest()
{
}
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
TEST_CASE("PQ crypto")
{
llarp::sodium::CryptoLibSodium crypto;
PQKeyPair keys;
crypto.pqe_keygen(keys);
PQCipherBlock block;
SharedSecret shared, otherShared;
auto c = &crypto;
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);
}

@ -4,7 +4,7 @@
#include <string>
#include <test_util.hpp>
#include <gtest/gtest.h>
#include <catch2/catch.hpp>
// This used to be implied via the headers above *shrug*
#ifdef _WIN32
@ -17,43 +17,37 @@ struct ToStringData
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 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}};
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}};
// clang-format off
ToStringData toStringData[] = {
std::vector<ToStringData> toStringData{
{empty, "0000000000000000000000000000000000000000000000000000000000000000"},
{full, "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"},
};
// clang-format on
INSTANTIATE_TEST_SUITE_P(TestCryptoTypes, PubKeyString,
::testing::ValuesIn(toStringData));
TEST_CASE("PubKey-string conversion")
{
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
// - file missing
@ -63,32 +57,31 @@ INSTANTIATE_TEST_SUITE_P(TestCryptoTypes, PubKeyString,
// - raw buffer
// - bencoded
struct TestCryptoTypesSecret : public ::testing::Test
struct TestCryptoTypesSecret
{
std::string filename;
fs::path p;
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.
ASSERT_FALSE(fs::exists(fs::status(p)));
REQUIRE_FALSE(fs::exists(fs::status(p)));
llarp::SecretKey key;
ASSERT_FALSE(key.LoadFromFile(filename.c_str()));
REQUIRE_FALSE(key.LoadFromFile(filename.c_str()));
// 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.
ASSERT_FALSE(fs::exists(fs::status(p)));
REQUIRE_FALSE(fs::exists(fs::status(p)));
// Create empty file
std::fstream f;
@ -98,156 +91,154 @@ TEST_F(TestCryptoTypesSecret, secret_key_from_file_empty)
llarp::test::FileGuard guard(p);
llarp::SecretKey key;
ASSERT_FALSE(key.LoadFromFile(filename.c_str()));
REQUIRE_FALSE(key.LoadFromFile(filename.c_str()));
// 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.
ASSERT_FALSE(fs::exists(fs::status(p)));
REQUIRE_FALSE(fs::exists(fs::status(p)));
// Create empty file
std::fstream f;
f.open(filename, std::ios::out | std::ios::binary);
std::fill_n(std::ostream_iterator< byte_t >(f), llarp::SecretKey::SIZE / 2,
0xAA);
std::fill_n(std::ostream_iterator<byte_t>(f), llarp::SecretKey::SIZE / 2, 0xAA);
f.close();
llarp::test::FileGuard guard(p);
llarp::SecretKey key;
ASSERT_FALSE(key.LoadFromFile(filename.c_str()));
REQUIRE_FALSE(key.LoadFromFile(filename.c_str()));
// 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.
ASSERT_FALSE(fs::exists(fs::status(p)));
REQUIRE_FALSE(fs::exists(fs::status(p)));
// Create empty file
std::fstream f;
f.open(filename, std::ios::out | std::ios::binary);
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();
llarp::test::FileGuard guard(p);
llarp::SecretKey key;
ASSERT_FALSE(key.LoadFromFile(filename.c_str()));
REQUIRE_FALSE(key.LoadFromFile(filename.c_str()));
// 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.
ASSERT_FALSE(fs::exists(fs::status(p)));
REQUIRE_FALSE(fs::exists(fs::status(p)));
// Create empty file
std::fstream f;
f.open(filename, std::ios::out | std::ios::binary);
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();
llarp::test::FileGuard guard(p);
llarp::SecretKey key;
ASSERT_FALSE(key.LoadFromFile(filename.c_str()));
REQUIRE_FALSE(key.LoadFromFile(filename.c_str()));
// 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.
ASSERT_FALSE(fs::exists(fs::status(p)));
REQUIRE_FALSE(fs::exists(fs::status(p)));
// Create empty file
std::fstream f;
f.open(filename, std::ios::out | std::ios::binary);
std::fill_n(std::ostream_iterator< byte_t >(f), llarp::SecretKey::SIZE * 2,
0xAA);
std::fill_n(std::ostream_iterator<byte_t>(f), llarp::SecretKey::SIZE * 2, 0xAA);
f.close();
llarp::test::FileGuard guard(p);
llarp::SecretKey key;
ASSERT_FALSE(key.LoadFromFile(filename.c_str()));
REQUIRE_FALSE(key.LoadFromFile(filename.c_str()));
// 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.
ASSERT_FALSE(fs::exists(fs::status(p)));
REQUIRE_FALSE(fs::exists(fs::status(p)));
// Create empty file
std::fstream f;
f.open(filename, std::ios::out | std::ios::binary);
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();
llarp::test::FileGuard guard(p);
llarp::SecretKey key;
ASSERT_FALSE(key.LoadFromFile(filename.c_str()));
REQUIRE_FALSE(key.LoadFromFile(filename.c_str()));
// 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.
ASSERT_FALSE(fs::exists(fs::status(p)));
REQUIRE_FALSE(fs::exists(fs::status(p)));
// Create empty file
std::fstream f;
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();
llarp::test::FileGuard guard(p);
llarp::SecretKey key;
ASSERT_TRUE(key.LoadFromFile(filename.c_str()));
REQUIRE(key.LoadFromFile(filename.c_str()));
// 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.
ASSERT_FALSE(fs::exists(fs::status(p)));
REQUIRE_FALSE(fs::exists(fs::status(p)));
// Create empty file
std::fstream f;
f.open(filename, std::ios::out | std::ios::binary);
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();
llarp::test::FileGuard guard(p);
llarp::SecretKey key;
ASSERT_TRUE(key.LoadFromFile(filename.c_str()));
REQUIRE(key.LoadFromFile(filename.c_str()));
// 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
@ -261,15 +252,24 @@ TEST_F(TestCryptoTypesSecret, secret_key_from_file_happy_bencode)
BOOL
IsRunAsAdmin()
{
BOOL fIsRunAsAdmin = FALSE;
DWORD dwError = ERROR_SUCCESS;
BOOL fIsRunAsAdmin = FALSE;
DWORD dwError = ERROR_SUCCESS;
PSID pAdministratorsGroup = NULL;
// Allocate and initialize a SID of the administrators group.
SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
if(!AllocateAndInitializeSid(&NtAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID,
DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0,
&pAdministratorsGroup))
if (!AllocateAndInitializeSid(
&NtAuthority,
2,
SECURITY_BUILTIN_DOMAIN_RID,
DOMAIN_ALIAS_RID_ADMINS,
0,
0,
0,
0,
0,
0,
&pAdministratorsGroup))
{
dwError = GetLastError();
goto Cleanup;
@ -277,7 +277,7 @@ IsRunAsAdmin()
// Determine whether the SID of administrators group is enabled in
// the primary access token of the process.
if(!CheckTokenMembership(NULL, pAdministratorsGroup, &fIsRunAsAdmin))
if (!CheckTokenMembership(NULL, pAdministratorsGroup, &fIsRunAsAdmin))
{
dwError = GetLastError();
goto Cleanup;
@ -285,14 +285,14 @@ IsRunAsAdmin()
Cleanup:
// Centralized cleanup for all allocated resources.
if(pAdministratorsGroup)
if (pAdministratorsGroup)
{
FreeSid(pAdministratorsGroup);
pAdministratorsGroup = NULL;
}
// Throw the error if something failed in the function.
if(ERROR_SUCCESS != dwError)
if (ERROR_SUCCESS != dwError)
{
throw dwError;
}
@ -301,46 +301,46 @@ Cleanup:
}
#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.
// Assume we're not running as root, so can't write to [C:]/
// if we are root just skip this test
#ifndef _WIN32
if(getuid() == 0)
if (getuid() == 0)
return;
#else
if(IsRunAsAdmin())
if (IsRunAsAdmin())
return;
#endif
filename = "/" + filename;
p = filename;
ASSERT_FALSE(fs::exists(fs::status(p)));
p = filename;
REQUIRE_FALSE(fs::exists(fs::status(p)));
llarp::test::FileGuard guard(p);
llarp::SecretKey key;
ASSERT_FALSE(key.SaveToFile(filename.c_str()));
REQUIRE_FALSE(key.SaveToFile(filename.c_str()));
// 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::SecretKey key;
key.Randomize();
ASSERT_TRUE(key.SaveToFile(filename.c_str()));
REQUIRE(key.SaveToFile(filename.c_str()));
// 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;
other.LoadFromFile(filename.c_str());
ASSERT_EQ(other, key);
REQUIRE(other == key);
}

@ -9,12 +9,12 @@
#include <string>
#include <test_util.hpp>
#include <gtest/gtest.h>
#include <catch2/catch.hpp>
using namespace ::llarp;
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
test::FileGuard m_rcFileGuard;
@ -27,8 +27,7 @@ struct KeyManagerTest : public test::LlarpTest< llarp::sodium::CryptoLibSodium >
, m_encFileGuard(our_enc_key_filename)
, m_transportFileGuard(our_transport_key_filename)
, m_identFileGuard(our_identity_filename)
{
}
{}
/// generate a valid "rc.signed" file
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();
ASSERT_FALSE(fs::exists(p));
REQUIRE_FALSE(fs::exists(p));
// touch file
std::fstream f;
@ -51,33 +50,33 @@ TEST_F(KeyManagerTest, TestBackupFileByMoving_MovesExistingFiles)
KeyManager::backupFileByMoving(p.string());
ASSERT_FALSE(fs::exists(p));
REQUIRE_FALSE(fs::exists(p));
fs::path moved = p.string() + ".0.bak";
ASSERT_TRUE(fs::exists(moved));
REQUIRE(fs::exists(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();
ASSERT_FALSE(fs::exists(p));
REQUIRE_FALSE(fs::exists(p));
KeyManager::backupFileByMoving(p.string());
ASSERT_FALSE(fs::exists(p));
REQUIRE_FALSE(fs::exists(p));
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();
ASSERT_FALSE(fs::exists(base));
REQUIRE_FALSE(fs::exists(base));
// touch file
{
@ -93,9 +92,9 @@ TEST_F(KeyManagerTest, TestBackupFileByMoving_FailsIfBackupNamesAreExausted)
guards.reserve(numBackupNames);
// 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;
f.open(p.string(), std::ios::out);
@ -103,49 +102,48 @@ TEST_F(KeyManagerTest, TestBackupFileByMoving_FailsIfBackupNamesAreExausted)
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()};
conf.Load();
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
ASSERT_FALSE(fs::exists(our_rc_filename));
REQUIRE_FALSE(fs::exists(our_rc_filename));
ASSERT_TRUE(fs::exists(our_enc_key_filename));
ASSERT_TRUE(fs::exists(our_transport_key_filename));
ASSERT_TRUE(fs::exists(our_identity_filename));
REQUIRE(fs::exists(our_enc_key_filename));
REQUIRE(fs::exists(our_transport_key_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()};
conf.Load();
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)
ASSERT_FALSE(fs::exists(our_rc_filename));
ASSERT_FALSE(fs::exists(our_enc_key_filename));
ASSERT_FALSE(fs::exists(our_transport_key_filename));
ASSERT_FALSE(fs::exists(our_identity_filename));
REQUIRE_FALSE(fs::exists(our_rc_filename));
REQUIRE_FALSE(fs::exists(our_enc_key_filename));
REQUIRE_FALSE(fs::exists(our_transport_key_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()};
conf.Load();
conf.lokid.whitelistRouters = false;
std::fstream f;
@ -154,26 +152,25 @@ TEST_F(KeyManagerTest, TestInitialize_DetectsBadRcFile)
f.close();
KeyManager keyManager;
ASSERT_TRUE(keyManager.initialize(conf, true, true));
ASSERT_TRUE(keyManager.needBackup());
REQUIRE(keyManager.initialize(conf, true, true));
REQUIRE(keyManager.needBackup());
ASSERT_TRUE(fs::exists(our_enc_key_filename));
ASSERT_TRUE(fs::exists(our_transport_key_filename));
ASSERT_TRUE(fs::exists(our_identity_filename));
REQUIRE(fs::exists(our_enc_key_filename));
REQUIRE(fs::exists(our_transport_key_filename));
REQUIRE(fs::exists(our_identity_filename));
// test that keys are sane
SecretKey key;
key.Zero();
ASSERT_TRUE(key.LoadFromFile(our_enc_key_filename));
ASSERT_FALSE(key.IsZero());
REQUIRE(key.LoadFromFile(our_enc_key_filename));
REQUIRE_FALSE(key.IsZero());
key.Zero();
ASSERT_TRUE(key.LoadFromFile(our_transport_key_filename));
ASSERT_FALSE(key.IsZero());
REQUIRE(key.LoadFromFile(our_transport_key_filename));
REQUIRE_FALSE(key.IsZero());
key.Zero();
ASSERT_TRUE(key.LoadFromFile(our_identity_filename));
ASSERT_FALSE(key.IsZero());
REQUIRE(key.LoadFromFile(our_identity_filename));
REQUIRE_FALSE(key.IsZero());
}

@ -1 +0,0 @@
#include <dht/mock_context.hpp>

@ -9,71 +9,99 @@ namespace llarp
{
namespace test
{
struct MockContext final : public dht::AbstractContext
struct MockContext : public dht::AbstractContext
{
MOCK_CONST_METHOD1(StoreRC, void(const RouterContact));
MOCK_METHOD2(LookupRouter, bool(const RouterID&, RouterLookupHandler));
MOCK_METHOD5(LookupRouterRecursive,
void(const RouterID&, const dht::Key_t&, uint64_t,
const dht::Key_t&, RouterLookupHandler));
MOCK_METHOD6(LookupIntroSetRelayed,
void(const dht::Key_t&, const dht::Key_t&, uint64_t,
const dht::Key_t&, uint64_t,
service::EncryptedIntroSetLookupHandler));
MOCK_METHOD5(
LookupRouterRecursive,
void(
const RouterID&,
const dht::Key_t&,
uint64_t,
const dht::Key_t&,
RouterLookupHandler));
MOCK_METHOD6(
LookupIntroSetRelayed,
void(
const dht::Key_t&,
const dht::Key_t&,
uint64_t,
const dht::Key_t&,
uint64_t,
service::EncryptedIntroSetLookupHandler));
MOCK_METHOD5(LookupIntroSetDirect,
void(const dht::Key_t&, const dht::Key_t&, uint64_t,
const dht::Key_t&,
service::EncryptedIntroSetLookupHandler));
MOCK_METHOD5(
LookupIntroSetDirect,
void(
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_METHOD4(LookupRouterForPath,
void(const RouterID& target, uint64_t txid,
const PathID_t& path, const dht::Key_t& askpeer));
MOCK_METHOD4(
LookupRouterForPath,
void(
const RouterID& target,
uint64_t txid,
const PathID_t& path,
const dht::Key_t& askpeer));
MOCK_METHOD5(LookupIntroSetForPath,
void(const dht::Key_t&, uint64_t, const PathID_t&,
const dht::Key_t&, uint64_t));
MOCK_METHOD5(
LookupIntroSetForPath,
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_METHOD4(
HandleExploritoryRouterLookup,
bool(const dht::Key_t& requester, uint64_t txid,
const RouterID& target,
std::vector< std::unique_ptr< dht::IMessage > >& reply));
bool(
const dht::Key_t& requester,
uint64_t txid,
const RouterID& target,
std::vector<std::unique_ptr<dht::IMessage>>& reply));
MOCK_METHOD5(
LookupRouterRelayed,
void(const dht::Key_t& requester, uint64_t txid,
const dht::Key_t& target, bool recursive,
std::vector< std::unique_ptr< dht::IMessage > >& replies));
void(
const dht::Key_t& requester,
uint64_t txid,
const dht::Key_t& target,
bool recursive,
std::vector<std::unique_ptr<dht::IMessage>>& replies));
MOCK_METHOD2(RelayRequestForPath,
bool(const PathID_t& localPath, const dht::IMessage& msg));
MOCK_METHOD2(RelayRequestForPath, bool(const PathID_t& localPath, const dht::IMessage& msg));
MOCK_CONST_METHOD2(GetRCFromNodeDB,
bool(const dht::Key_t& k, RouterContact& rc));
MOCK_CONST_METHOD2(GetRCFromNodeDB, bool(const dht::Key_t& k, RouterContact& rc));
MOCK_METHOD5(PropagateIntroSetTo,
void(const dht::Key_t& source, uint64_t sourceTX,
const service::EncryptedIntroSet& introset,
const dht::Key_t& peer, 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_METHOD5(
PropagateIntroSetTo,
void(
const dht::Key_t& source,
uint64_t sourceTX,
const service::EncryptedIntroSet& introset,
const dht::Key_t& peer,
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,
void(const dht::Key_t&, AbstractRouter*));
MOCK_METHOD2(Init, void(const dht::Key_t&, AbstractRouter*));
MOCK_CONST_METHOD1(GetIntroSetByLocation,
std::optional< llarp::service::EncryptedIntroSet >(
const llarp::dht::Key_t&));
MOCK_CONST_METHOD1(
GetIntroSetByLocation,
std::optional<llarp::service::EncryptedIntroSet>(const llarp::dht::Key_t&));
MOCK_CONST_METHOD0(ExtractStatus, util::StatusObject());
@ -85,8 +113,7 @@ namespace llarp
MOCK_CONST_METHOD0(OurKey, const dht::Key_t&());
MOCK_CONST_METHOD0(pendingIntrosetLookups,
const PendingIntrosetLookups&());
MOCK_CONST_METHOD0(pendingIntrosetLookups, const PendingIntrosetLookups&());
MOCK_METHOD0(pendingIntrosetLookups, PendingIntrosetLookups&());
MOCK_METHOD0(pendingRouterLookups, PendingRouterLookups&());
@ -97,12 +124,12 @@ namespace llarp
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_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(DelRCNodeAsync, void(const dht::Key_t& val));

@ -2,22 +2,22 @@
#include <dht/key.hpp>
#include <dht/node.hpp>
#include <gtest/gtest.h>
#include <catch2/catch.hpp>
using Key_t = llarp::dht::Key_t;
using Value_t = llarp::dht::RCNode;
using Bucket_t = llarp::dht::Bucket< Value_t >;
using Key_t = llarp::dht::Key_t;
using Value_t = llarp::dht::RCNode;
using Bucket_t = llarp::dht::Bucket<Value_t>;
class TestDhtBucket : public ::testing::Test
class TestDhtBucket
{
public:
TestDhtBucket() : randInt(0)
{
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;
byte_t fill = 1;
while(numNodes)
byte_t fill = 1;
while (numNodes)
{
Value_t n;
n.ID.Fill(fill);
@ -30,10 +30,10 @@ class TestDhtBucket : public ::testing::Test
uint64_t randInt;
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.
nodes->Clear();
@ -45,27 +45,27 @@ TEST_F(TestDhtBucket, simple_cycle)
nodes->PutNode(val);
// Verify the value is in the bucket
ASSERT_TRUE(nodes->HasNode(val.ID));
ASSERT_EQ(1u, nodes->size());
REQUIRE(nodes->HasNode(val.ID));
REQUIRE(1u == nodes->size());
// Verify after deletion, the value is no longer in the bucket
nodes->DelNode(val.ID);
ASSERT_FALSE(nodes->HasNode(val.ID));
REQUIRE_FALSE(nodes->HasNode(val.ID));
// Verify deleting again succeeds;
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.
nodes->Clear();
// We expect not to find anything
Key_t result;
std::set< Key_t > excludeSet;
ASSERT_FALSE(nodes->GetRandomNodeExcluding(result, excludeSet));
std::set<Key_t> excludeSet;
REQUIRE_FALSE(nodes->GetRandomNodeExcluding(result, excludeSet));
// Create a simple value.
Value_t val;
@ -73,24 +73,24 @@ TEST_F(TestDhtBucket, get_random_node_excluding)
// Add the simple value to the exclude set
excludeSet.insert(val.ID);
ASSERT_FALSE(nodes->GetRandomNodeExcluding(result, excludeSet));
REQUIRE_FALSE(nodes->GetRandomNodeExcluding(result, excludeSet));
// Add the simple value to the bucket
nodes->PutNode(val);
ASSERT_FALSE(nodes->GetRandomNodeExcluding(result, excludeSet));
REQUIRE_FALSE(nodes->GetRandomNodeExcluding(result, excludeSet));
excludeSet.clear();
ASSERT_TRUE(nodes->GetRandomNodeExcluding(result, excludeSet));
ASSERT_EQ(val.ID, result);
REQUIRE(nodes->GetRandomNodeExcluding(result, excludeSet));
REQUIRE(val.ID == result);
// Add an element to the exclude set which isn't the bucket.
Key_t other;
other.Fill(0xff);
excludeSet.insert(other);
ASSERT_TRUE(nodes->GetRandomNodeExcluding(result, excludeSet));
ASSERT_EQ(val.ID, result);
REQUIRE(nodes->GetRandomNodeExcluding(result, excludeSet));
REQUIRE(val.ID == result);
// Add a node which is in both bucket and excludeSet
Value_t nextVal;
@ -98,28 +98,28 @@ TEST_F(TestDhtBucket, get_random_node_excluding)
excludeSet.insert(nextVal.ID);
nodes->PutNode(nextVal);
ASSERT_TRUE(nodes->GetRandomNodeExcluding(result, excludeSet));
ASSERT_EQ(val.ID, result);
REQUIRE(nodes->GetRandomNodeExcluding(result, excludeSet));
REQUIRE(val.ID == result);
// Clear the excludeSet - we should still have 2 nodes in the bucket
excludeSet.clear();
randInt = 0;
ASSERT_TRUE(nodes->GetRandomNodeExcluding(result, excludeSet));
ASSERT_EQ(val.ID, result);
REQUIRE(nodes->GetRandomNodeExcluding(result, excludeSet));
REQUIRE(val.ID == result);
// Set the random value to be 1, we should get the other node.
randInt = 1;
ASSERT_TRUE(nodes->GetRandomNodeExcluding(result, excludeSet));
ASSERT_EQ(nextVal.ID, result);
REQUIRE(nodes->GetRandomNodeExcluding(result, excludeSet));
REQUIRE(nextVal.ID == result);
// Set the random value to be 100, we should get the first node.
randInt = 100;
ASSERT_TRUE(nodes->GetRandomNodeExcluding(result, excludeSet));
ASSERT_EQ(val.ID, result);
REQUIRE(nodes->GetRandomNodeExcluding(result, excludeSet));
REQUIRE(val.ID == result);
}
TEST_F(TestDhtBucket, find_closest)
TEST_CASE_METHOD(TestDhtBucket, "find_closest", "[dht]")
{
// Empty the current bucket.
nodes->Clear();
@ -129,182 +129,182 @@ TEST_F(TestDhtBucket, find_closest)
target.Fill(0xF0);
Key_t result;
ASSERT_FALSE(nodes->FindClosest(target, result));
REQUIRE_FALSE(nodes->FindClosest(target, result));
// Add a node to the bucket
Value_t first;
first.ID.Zero();
nodes->PutNode(first);
ASSERT_TRUE(nodes->FindClosest(target, result));
ASSERT_EQ(result, first.ID);
REQUIRE(nodes->FindClosest(target, result));
REQUIRE(result == first.ID);
// Add another node to the bucket, closer to the target
Value_t second;
second.ID.Fill(0x10);
nodes->PutNode(second);
ASSERT_TRUE(nodes->FindClosest(target, result));
ASSERT_EQ(result, second.ID);
REQUIRE(nodes->FindClosest(target, result));
REQUIRE(result == second.ID);
// Add a third node to the bucket, closer to the target
Value_t third;
third.ID.Fill(0x20);
nodes->PutNode(third);
ASSERT_TRUE(nodes->FindClosest(target, result));
ASSERT_EQ(result, third.ID);
REQUIRE(nodes->FindClosest(target, result));
REQUIRE(result == third.ID);
// Add a fourth node to the bucket, greater than the target
Value_t fourth;
fourth.ID.Fill(0xF1);
nodes->PutNode(fourth);
ASSERT_TRUE(nodes->FindClosest(target, result));
ASSERT_EQ(result, fourth.ID);
REQUIRE(nodes->FindClosest(target, result));
REQUIRE(result == fourth.ID);
// Add a fifth node to the bucket, equal to the target
Value_t fifth;
fifth.ID.Fill(0xF0);
nodes->PutNode(fifth);
ASSERT_TRUE(nodes->FindClosest(target, result));
ASSERT_EQ(result, fifth.ID);
REQUIRE(nodes->FindClosest(target, result));
REQUIRE(result == fifth.ID);
}
TEST_F(TestDhtBucket, get_many_random)
TEST_CASE_METHOD(TestDhtBucket, "get_many_random", "[dht]")
{
// Empty the current bucket.
nodes->Clear();
// Verify behaviour with empty node set
std::set< Key_t > result;
ASSERT_FALSE(nodes->GetManyRandom(result, 0));
ASSERT_FALSE(nodes->GetManyRandom(result, 1));
std::set<Key_t> result;
REQUIRE_FALSE(nodes->GetManyRandom(result, 0));
REQUIRE_FALSE(nodes->GetManyRandom(result, 1));
// Add 5 nodes to the bucket
std::set< Value_t > curValues;
std::set< Key_t > curKeys;
for(byte_t i = 0x00; i < 0x05; ++i)
std::set<Value_t> curValues;
std::set<Key_t> curKeys;
for (byte_t i = 0x00; i < 0x05; ++i)
{
Value_t v;
v.ID.Fill(i);
ASSERT_TRUE(curKeys.insert(v.ID).second);
REQUIRE(curKeys.insert(v.ID).second);
nodes->PutNode(v);
}
// Fetching more than the current size fails
ASSERT_EQ(5u, nodes->size());
ASSERT_FALSE(nodes->GetManyRandom(result, nodes->size() + 1));
REQUIRE(5u == nodes->size());
REQUIRE_FALSE(nodes->GetManyRandom(result, nodes->size() + 1));
// Fetching the current size succeeds
ASSERT_TRUE(nodes->GetManyRandom(result, nodes->size()));
ASSERT_EQ(curKeys, result);
REQUIRE(nodes->GetManyRandom(result, nodes->size()));
REQUIRE(curKeys == result);
// Fetching a subset succeeds.
// Note we hack this by "fixing" the random number generator
result.clear();
ASSERT_TRUE(nodes->GetManyRandom(result, 1u));
ASSERT_EQ(1u, result.size());
ASSERT_EQ(*curKeys.begin(), *result.begin());
REQUIRE(nodes->GetManyRandom(result, 1u));
REQUIRE(1u == result.size());
REQUIRE(*curKeys.begin() == *result.begin());
randInt = 0;
result.clear();
ASSERT_TRUE(nodes->GetManyRandom(result, nodes->size() - 1));
ASSERT_EQ(nodes->size() - 1, result.size());
ASSERT_EQ(std::set< Key_t >(++curKeys.rbegin(), curKeys.rend()), result);
REQUIRE(nodes->GetManyRandom(result, nodes->size() - 1));
REQUIRE(nodes->size() - 1 == result.size());
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.
nodes->Clear();
Key_t target;
target.Zero();
std::set< Key_t > exclude;
std::set<Key_t> exclude;
Key_t result;
// Empty node + exclude set fails
ASSERT_FALSE(nodes->FindCloseExcluding(target, result, exclude));
REQUIRE_FALSE(nodes->FindCloseExcluding(target, result, exclude));
Value_t first;
first.ID.Fill(0xF0);
exclude.insert(first.ID);
// Empty nodes fails
ASSERT_FALSE(nodes->FindCloseExcluding(target, result, exclude));
REQUIRE_FALSE(nodes->FindCloseExcluding(target, result, exclude));
// Nodes and exclude set match
nodes->PutNode(first);
ASSERT_FALSE(nodes->FindCloseExcluding(target, result, exclude));
REQUIRE_FALSE(nodes->FindCloseExcluding(target, result, exclude));
// Exclude set empty
exclude.clear();
ASSERT_TRUE(nodes->FindCloseExcluding(target, result, exclude));
REQUIRE(nodes->FindCloseExcluding(target, result, exclude));
result = first.ID;
Value_t second;
second.ID.Fill(0x01);
nodes->PutNode(second);
ASSERT_TRUE(nodes->FindCloseExcluding(target, result, exclude));
REQUIRE(nodes->FindCloseExcluding(target, result, exclude));
result = second.ID;
exclude.insert(second.ID);
ASSERT_TRUE(nodes->FindCloseExcluding(target, result, exclude));
REQUIRE(nodes->FindCloseExcluding(target, result, exclude));
result = first.ID;
}
TEST_F(TestDhtBucket, find_many_near_excluding)
TEST_CASE_METHOD(TestDhtBucket, "find_many_near_excluding", "[dht]")
{
// Empty the current bucket.
nodes->Clear();
Key_t target;
target.Zero();
std::set< Key_t > exclude;
std::set< Key_t > result;
std::set<Key_t> exclude;
std::set<Key_t> result;
// Empty node + exclude set, with size 0 succeeds
ASSERT_TRUE(nodes->GetManyNearExcluding(target, result, 0, exclude));
ASSERT_EQ(0u, result.size());
REQUIRE(nodes->GetManyNearExcluding(target, result, 0, exclude));
REQUIRE(0u == result.size());
// Empty node + exclude set fails
ASSERT_FALSE(nodes->GetManyNearExcluding(target, result, 1, exclude));
REQUIRE_FALSE(nodes->GetManyNearExcluding(target, result, 1, exclude));
Value_t first;
first.ID.Fill(0xF0);
exclude.insert(first.ID);
// 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->PutNode(first);
ASSERT_FALSE(nodes->GetManyNearExcluding(target, result, 1, exclude));
REQUIRE_FALSE(nodes->GetManyNearExcluding(target, result, 1, exclude));
// Single node succeeds
exclude.clear();
ASSERT_TRUE(nodes->GetManyNearExcluding(target, result, 1, exclude));
ASSERT_EQ(result, std::set< Key_t >({first.ID}));
REQUIRE(nodes->GetManyNearExcluding(target, result, 1, exclude));
REQUIRE(result == std::set<Key_t>({first.ID}));
// Trying to grab 2 nodes from a 1 node set fails
result.clear();
ASSERT_FALSE(nodes->GetManyNearExcluding(target, result, 2, exclude));
REQUIRE_FALSE(nodes->GetManyNearExcluding(target, result, 2, exclude));
// two nodes finds closest
Value_t second;
second.ID.Fill(0x01);
nodes->PutNode(second);
result.clear();
ASSERT_TRUE(nodes->GetManyNearExcluding(target, result, 1, exclude));
ASSERT_EQ(result, std::set< Key_t >({second.ID}));
REQUIRE(nodes->GetManyNearExcluding(target, result, 1, exclude));
REQUIRE(result == std::set<Key_t>({second.ID}));
// 3 nodes finds 2 closest
Value_t third;
third.ID.Fill(0x02);
nodes->PutNode(third);
result.clear();
ASSERT_TRUE(nodes->GetManyNearExcluding(target, result, 2, exclude));
ASSERT_EQ(result, std::set< Key_t >({second.ID, third.ID}));
REQUIRE(nodes->GetManyNearExcluding(target, result, 2, exclude));
REQUIRE(result == std::set<Key_t>({second.ID, third.ID}));
// 4 nodes, one in exclude set finds 2 closest
Value_t fourth;
@ -312,27 +312,27 @@ TEST_F(TestDhtBucket, find_many_near_excluding)
nodes->PutNode(fourth);
exclude.insert(third.ID);
result.clear();
ASSERT_TRUE(nodes->GetManyNearExcluding(target, result, 2, exclude));
ASSERT_EQ(result, std::set< Key_t >({second.ID, fourth.ID}));
REQUIRE(nodes->GetManyNearExcluding(target, result, 2, exclude));
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 target;
target.Fill(5);
ASSERT_TRUE(nodes->FindClosest(target, result));
ASSERT_EQ(target, result);
REQUIRE(nodes->FindClosest(target, result));
REQUIRE(target == result);
const llarp::dht::Key_t oldResult = result;
target.Fill(0xf5);
ASSERT_TRUE(nodes->FindClosest(target, result));
ASSERT_EQ(oldResult, result);
REQUIRE(nodes->FindClosest(target, result));
REQUIRE(oldResult == result);
}
TEST_F(TestDhtBucket, TestBucketRandomized_1000)
TEST_CASE_METHOD(TestDhtBucket, "Bucket: randomized 1000", "[dht]")
{
size_t moreNodes = 100;
while(moreNodes--)
while (moreNodes--)
{
llarp::dht::RCNode n;
n.ID.Fill(randInt);
@ -340,31 +340,30 @@ TEST_F(TestDhtBucket, TestBucketRandomized_1000)
nodes->PutNode(n);
}
const size_t count = 1000;
size_t left = count;
while(left--)
size_t left = count;
while (left--)
{
llarp::dht::Key_t result;
llarp::dht::Key_t target;
target.Randomize();
const llarp::dht::Key_t expect = target;
ASSERT_TRUE(nodes->FindClosest(target, result));
if(target == result)
REQUIRE(nodes->FindClosest(target, result));
if (target == result)
{
ASSERT_GE(result ^ target, expect ^ target);
ASSERT_EQ(result ^ target, expect ^ target);
ASSERT_EQ(result ^ target, expect ^ target);
REQUIRE((result ^ target) >= (expect ^ target));
REQUIRE((result ^ target) == (expect ^ target));
REQUIRE((result ^ target) == (expect ^ target));
}
else
{
Key_t dist = result ^ target;
Key_t oldDist = expect ^ target;
ASSERT_NE(result ^ target, expect ^ target);
Key_t dist = (result ^ target);
Key_t oldDist = (expect ^ target);
REQUIRE((result ^ target) != (expect ^ target));
ASSERT_GE(result ^ target, expect ^ target)
<< "result=" << result << "expect=" << expect << std::endl
<< dist << ">=" << oldDist << "iteration=" << (count - left);
INFO(dist << ">=" << oldDist << "iteration=" << (count - left));
REQUIRE((result ^ target) >= (expect ^ target));
ASSERT_NE(result ^ target, expect ^ target);
REQUIRE((result ^ target) != (expect ^ target));
}
}
}

@ -4,38 +4,42 @@
#include <dht/mock_context.hpp>
#include <test_util.hpp>
#include <gtest/gtest.h>
#include <gmock/gmock.h>
#include <catch2/catch.hpp>
using namespace llarp;
using namespace ::testing;
using test::makeBuf;
struct TestDhtExploreNetworkJob : public ::testing::Test
struct TestDhtExploreNetworkJob
{
RouterID peer;
test::MockContext context;
dht::ExploreNetworkJob exploreNetworkJob;
TestDhtExploreNetworkJob()
: peer(makeBuf< RouterID >(0x01)), exploreNetworkJob(peer, &context)
TestDhtExploreNetworkJob() : 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);
ASSERT_TRUE(exploreNetworkJob.Validate(other));
const RouterID other = makeBuf<RouterID>(0x02);
REQUIRE(exploreNetworkJob.Validate(other));
}
TEST_F(TestDhtExploreNetworkJob, start)
TEST_CASE_METHOD(TestDhtExploreNetworkJob, "start", "[dht]")
{
// Verify input arguments are passed correctly.
// The actual logic is inside the `dht::AbstractContext` implementation.
const auto txKey = makeBuf< dht::Key_t >(0x02);
uint64_t txId = 4;
const auto txKey = makeBuf<dht::Key_t>(0x02);
uint64_t txId = 4;
dht::TXOwner txOwner(txKey, txId);
@ -47,10 +51,11 @@ TEST_F(TestDhtExploreNetworkJob, start)
).Times(1);
// 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:
// - Empty collection
@ -62,7 +67,7 @@ TEST_F(TestDhtExploreNetworkJob, send_reply)
EXPECT_CALL(context, LookupRouter(_, _)).Times(0);
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(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, LookupRouter(_, _)).Times(3).WillRepeatedly(Return(true));
ASSERT_NO_THROW(exploreNetworkJob.SendReply());
REQUIRE_NOTHROW(exploreNetworkJob.SendReply());
}
}

@ -1,10 +1,10 @@
#include <dht/kademlia.hpp>
#include <gtest/gtest.h>
#include <catch2/catch.hpp>
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
{
@ -15,34 +15,21 @@ struct XorMetricData
XorMetricData(const Array& u, const Array& l, const Array& r, bool res)
: us(u), left(l), right(r), result(res)
{
}
{}
};
std::ostream&
operator<<(std::ostream& stream, const XorMetricData& x)
{
stream << int(x.us[0]) << " " << int(x.left[0]) << " " << int(x.right[0])
<< " " << std::boolalpha << x.result;
stream << int(x.us[0]) << " " << int(x.left[0]) << " " << int(x.right[0]) << " " << std::boolalpha
<< x.result;
return stream;
}
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 >
std::vector<XorMetricData>
makeData()
{
std::vector< XorMetricData > result;
std::vector<XorMetricData> result;
Array zero;
zero.fill(0);
@ -84,5 +71,8 @@ makeData()
return result;
}
INSTANTIATE_TEST_SUITE_P(TestDhtXorMetric, XorMetric,
::testing::ValuesIn(makeData()));
TEST_CASE("XorMetric", "[dht]")
{
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>
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}};
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}};
TEST_P(DHT, constructor)
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 b(d.data());
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
{
ASSERT_NE(a, c);
REQUIRE(a != c);
}
}
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}};
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)
TEST_CASE("DHT key ==", "[dht]")
{
ASSERT_EQ(dht::Key_t(emptyArray), dht::Key_t(emptyArray));
ASSERT_EQ(dht::Key_t(fullArray), dht::Key_t(fullArray));
ASSERT_EQ(dht::Key_t(seqArray), dht::Key_t(seqArray));
REQUIRE(dht::Key_t(emptyArray) == dht::Key_t(emptyArray));
REQUIRE(dht::Key_t(fullArray) == dht::Key_t(fullArray));
REQUIRE(dht::Key_t(seqArray) == dht::Key_t(seqArray));
}
TEST(TestDhtKey, ne)
TEST_CASE("DHT key !=", "[dht]")
{
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));
REQUIRE(dht::Key_t(emptyArray) != dht::Key_t(fullArray));
REQUIRE(dht::Key_t(emptyArray) != dht::Key_t(seqArray));
REQUIRE(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));
ASSERT_LT(dht::Key_t(emptyArray), dht::Key_t(seqArray));
ASSERT_LT(dht::Key_t(seqArray), dht::Key_t(fullArray));
REQUIRE(dht::Key_t(emptyArray) < dht::Key_t(fullArray));
REQUIRE(dht::Key_t(emptyArray) < dht::Key_t(seqArray));
REQUIRE(dht::Key_t(seqArray) < dht::Key_t(fullArray));
}
TEST(TestDhtKey, gt)
TEST_CASE("DHT key >", "[dht]")
{
ASSERT_GT(dht::Key_t(fullArray), dht::Key_t(emptyArray));
ASSERT_GT(dht::Key_t(seqArray), dht::Key_t(emptyArray));
ASSERT_GT(dht::Key_t(fullArray), dht::Key_t(seqArray));
REQUIRE(dht::Key_t(fullArray) > dht::Key_t(emptyArray));
REQUIRE(dht::Key_t(seqArray) > dht::Key_t(emptyArray));
REQUIRE(dht::Key_t(fullArray) > dht::Key_t(seqArray));
}
TEST(TestDhtKey, XOR)
TEST_CASE("DHT key ^", "[dht]")
{
ASSERT_EQ(dht::Key_t(emptyArray),
dht::Key_t(emptyArray) ^ dht::Key_t(emptyArray));
REQUIRE(dht::Key_t(emptyArray) == (dht::Key_t(emptyArray) ^ dht::Key_t(emptyArray)));
ASSERT_EQ(dht::Key_t(seqArray),
dht::Key_t(emptyArray) ^ dht::Key_t(seqArray));
REQUIRE(dht::Key_t(seqArray) == (dht::Key_t(emptyArray) ^ dht::Key_t(seqArray)));
ASSERT_EQ(dht::Key_t(fullArray),
dht::Key_t(emptyArray) ^ dht::Key_t(fullArray));
REQUIRE(dht::Key_t(fullArray) == (dht::Key_t(emptyArray) ^ dht::Key_t(fullArray)));
ASSERT_EQ(dht::Key_t(emptyArray),
dht::Key_t(fullArray) ^ dht::Key_t(fullArray));
REQUIRE(dht::Key_t(emptyArray) == (dht::Key_t(fullArray) ^ dht::Key_t(fullArray)));
ASSERT_EQ(dht::Key_t(emptyArray),
dht::Key_t(seqArray) ^ dht::Key_t(seqArray));
REQUIRE(dht::Key_t(emptyArray) == (dht::Key_t(seqArray) ^ dht::Key_t(seqArray)));
Array xorResult;
std::iota(xorResult.rbegin(), xorResult.rend(), 0xE0);
ASSERT_EQ(dht::Key_t(xorResult),
dht::Key_t(seqArray) ^ dht::Key_t(fullArray));
REQUIRE(dht::Key_t(xorResult) == (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 one;
@ -108,16 +94,16 @@ TEST(TestDhtKey, TestBucketOperators)
zero.Zero();
one.Fill(1);
three.Fill(3);
ASSERT_LT(zero, one);
ASSERT_LT(zero, three);
ASSERT_FALSE(zero > one);
ASSERT_FALSE(zero > three);
ASSERT_NE(zero, three);
ASSERT_FALSE(zero == three);
ASSERT_EQ(zero ^ one, one);
ASSERT_LT(one, three);
ASSERT_GT(three, one);
ASSERT_NE(one, three);
ASSERT_FALSE(one == three);
ASSERT_EQ(one ^ three, three ^ one);
REQUIRE(zero < one);
REQUIRE(zero < three);
REQUIRE_FALSE(zero > one);
REQUIRE_FALSE(zero > three);
REQUIRE(zero != three);
REQUIRE_FALSE(zero == three);
REQUIRE((zero ^ one) == one);
REQUIRE(one < three);
REQUIRE(three > one);
REQUIRE(one != three);
REQUIRE_FALSE(one == three);
REQUIRE((one ^ three) == (three ^ one));
}

@ -2,115 +2,105 @@
#include <test_util.hpp>
#include <gtest/gtest.h>
#include <gmock/gmock.h>
#include <catch2/catch.hpp>
using namespace llarp;
using namespace ::testing;
using test::makeBuf;
struct TestDhtRCNode : public ::testing::Test
{
};
TEST_F(TestDhtRCNode, construct)
TEST_CASE("dht::RCNode construct", "[dht]")
{
dht::RCNode node;
ASSERT_THAT(node.ID, Property(&dht::Key_t::IsZero, true));
REQUIRE(node.ID.IsZero());
node.ID.Fill(0xCA);
node.rc.last_updated = 101s;
dht::RCNode other{node};
ASSERT_EQ(node.ID, other.ID);
ASSERT_EQ(node.rc, other.rc);
REQUIRE(node.ID == other.ID);
REQUIRE(node.rc == other.rc);
RouterContact contact;
contact.pubkey.Randomize();
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 two;
dht::RCNode three;
dht::RCNode eqThree;
one.rc.last_updated = 1s;
two.rc.last_updated = 2s;
three.rc.last_updated = 3s;
one.rc.last_updated = 1s;
two.rc.last_updated = 2s;
three.rc.last_updated = 3s;
eqThree.rc.last_updated = 3s;
// LT cases
ASSERT_THAT(one, Lt(two));
ASSERT_THAT(one, Lt(three));
ASSERT_THAT(one, Lt(eqThree));
ASSERT_THAT(two, Lt(three));
ASSERT_THAT(two, Lt(eqThree));
REQUIRE(one < two);
REQUIRE(one < three);
REQUIRE(one < eqThree);
REQUIRE(two < three);
REQUIRE(two < eqThree);
// !LT cases
ASSERT_THAT(one, Not(Lt(one)));
ASSERT_THAT(two, Not(Lt(one)));
ASSERT_THAT(two, Not(Lt(two)));
ASSERT_THAT(three, Not(Lt(one)));
ASSERT_THAT(three, Not(Lt(two)));
ASSERT_THAT(three, Not(Lt(three)));
ASSERT_THAT(three, Not(Lt(eqThree)));
REQUIRE(!(one < one));
REQUIRE(!(two < one));
REQUIRE(!(two < two));
REQUIRE(!(three < one));
REQUIRE(!(three < two));
REQUIRE(!(three < three));
REQUIRE(!(three < eqThree));
}
struct TestDhtISNode : public ::testing::Test
{
};
TEST_F(TestDhtISNode, construct)
TEST_CASE("dht::ISNode construct", "[dht]")
{
dht::ISNode node;
ASSERT_THAT(node.ID, Property(&dht::Key_t::IsZero, true));
REQUIRE(node.ID.IsZero());
node.ID.Fill(0xCA);
node.introset.derivedSigningKey.Fill(0xDB);
dht::ISNode other{node};
ASSERT_EQ(node.ID, other.ID);
ASSERT_EQ(node.introset, other.introset);
REQUIRE(node.ID == other.ID);
REQUIRE(node.introset == other.introset);
service::EncryptedIntroSet introSet;
introSet.derivedSigningKey.Randomize();
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 two;
dht::ISNode three;
dht::ISNode eqThree;
one.introset.signedAt = 1s;
two.introset.signedAt = 2s;
three.introset.signedAt = 3s;
one.introset.signedAt = 1s;
two.introset.signedAt = 2s;
three.introset.signedAt = 3s;
eqThree.introset.signedAt = 3s;
// LT cases
ASSERT_THAT(one, Lt(two));
ASSERT_THAT(one, Lt(three));
ASSERT_THAT(one, Lt(eqThree));
ASSERT_THAT(two, Lt(three));
ASSERT_THAT(two, Lt(eqThree));
REQUIRE(one < two);
REQUIRE(one < three);
REQUIRE(one < eqThree);
REQUIRE(two < three);
REQUIRE(two < eqThree);
// !LT cases
ASSERT_THAT(one, Not(Lt(one)));
ASSERT_THAT(two, Not(Lt(one)));
ASSERT_THAT(two, Not(Lt(two)));
ASSERT_THAT(three, Not(Lt(one)));
ASSERT_THAT(three, Not(Lt(two)));
ASSERT_THAT(three, Not(Lt(three)));
ASSERT_THAT(three, Not(Lt(eqThree)));
REQUIRE(!(one < one));
REQUIRE(!(two < one));
REQUIRE(!(two < two));
REQUIRE(!(three < one));
REQUIRE(!(three < two));
REQUIRE(!(three < three));
REQUIRE(!(three < eqThree));
}

@ -2,7 +2,7 @@
#include <service/tag.hpp>
#include <test_util.hpp>
#include <gtest/gtest.h>
#include <catch2/catch.hpp>
#include <gmock/gmock.h>
using namespace llarp;
@ -13,13 +13,11 @@ using llarp::test::makeBuf;
using Val_t = llarp::service::Tag;
// 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,
dht::AbstractContext* p)
: dht::TX< dht::Key_t, Val_t >(asker, k, p)
{
}
TestTx(const dht::TXOwner& asker, const dht::Key_t& k, dht::AbstractContext* p)
: dht::TX<dht::Key_t, Val_t>(asker, k, p)
{}
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());
};
struct TestDhtTx : public Test
struct TestDhtTx
{
dht::TXOwner asker;
dht::Key_t m_key;
TestTx tx;
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
// - Validate returns true
@ -48,7 +51,7 @@ TEST_F(TestDhtTx, on_found)
// - Repeated call on 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");
// Validate returns true
@ -57,19 +60,19 @@ TEST_F(TestDhtTx, on_found)
tx.OnFound(key, val);
ASSERT_THAT(tx.peersAsked, Contains(key));
ASSERT_THAT(tx.valuesFound, Contains(val));
REQUIRE(tx.peersAsked.count(key) > 0);
REQUIRE_THAT(tx.valuesFound, Catch::VectorContains(val));
}
// Repeated call on success
{
EXPECT_CALL(tx, Validate(val)).WillOnce(Return(true));
tx.OnFound(key, val);
ASSERT_THAT(tx.peersAsked, Contains(key));
ASSERT_THAT(tx.valuesFound, Contains(val));
REQUIRE(tx.peersAsked.count(key) > 0);
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");
// Validate returns false
@ -78,8 +81,8 @@ TEST_F(TestDhtTx, on_found)
tx.OnFound(key1, badVal);
ASSERT_THAT(tx.peersAsked, Contains(key1));
ASSERT_THAT(tx.valuesFound, Not(Contains(badVal)));
REQUIRE(tx.peersAsked.count(key1) > 0);
REQUIRE_THAT(tx.valuesFound, !Catch::VectorContains(badVal));
}
// Repeated call on failure
@ -88,8 +91,8 @@ TEST_F(TestDhtTx, on_found)
tx.OnFound(key1, badVal);
ASSERT_THAT(tx.peersAsked, Contains(key1));
ASSERT_THAT(tx.valuesFound, Not(Contains(badVal)));
REQUIRE(tx.peersAsked.count(key1) > 0);
REQUIRE_THAT(tx.valuesFound, !Catch::VectorContains(badVal));
}
// Repeated call on success after failure
@ -98,8 +101,7 @@ TEST_F(TestDhtTx, on_found)
tx.OnFound(key1, badVal);
ASSERT_THAT(tx.peersAsked, Contains(key1));
ASSERT_THAT(tx.valuesFound, Contains(badVal));
REQUIRE(tx.peersAsked.count(key1) > 0);
REQUIRE_THAT(tx.valuesFound, Catch::VectorContains(badVal));
}
}

@ -1,6 +1,6 @@
#include <dht/txowner.hpp>
#include <gtest/gtest.h>
#include <catch2/catch.hpp>
namespace
{
@ -13,37 +13,22 @@ namespace
uint64_t id;
size_t expectedHash;
TxOwnerData(const Key_t& k, uint64_t i, size_t h)
: node(k), id(i), expectedHash(h)
{
}
TxOwnerData(const Key_t& k, uint64_t i, size_t h) : node(k), id(i), expectedHash(h)
{}
};
struct TxOwner : public ::testing::TestWithParam< TxOwnerData >
{
};
TEST_F(TxOwner, default_construct)
TEST_CASE("TxOwner default construct", "[dht]")
{
TXOwner dc;
ASSERT_TRUE(dc.node.IsZero());
ASSERT_EQ(0u, dc.txid);
ASSERT_EQ(0u, TXOwner::Hash()(dc));
}
TEST_P(TxOwner, hash)
{
// test single interactions (constructor and hash)
auto d = GetParam();
TXOwner constructor(d.node, d.id);
ASSERT_EQ(d.expectedHash, TXOwner::Hash()(constructor));
REQUIRE(dc.node.IsZero());
REQUIRE(0u == dc.txid);
REQUIRE(0u == TXOwner::Hash()(dc));
}
std::vector< TxOwnerData >
std::vector<TxOwnerData>
makeData()
{
std::vector< TxOwnerData > result;
std::vector<TxOwnerData> result;
Key_t zero;
zero.Zero();
@ -52,7 +37,7 @@ namespace
Key_t two;
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, 1, 1ull);
@ -67,6 +52,15 @@ namespace
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
{
TXOwner lhs;
@ -76,27 +70,13 @@ namespace
TxOwnerCmpData(const TXOwner& l, const TXOwner& r, bool e, bool ls)
: lhs(l), rhs(r), equal(e), less(ls)
{
}
};
struct TxOwnerOps : public ::testing::TestWithParam< 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 >
std::vector<TxOwnerCmpData>
makeCmpData()
{
std::vector< TxOwnerCmpData > result;
std::vector<TxOwnerCmpData> result;
Key_t zero;
zero.Fill(0x00);
@ -114,10 +94,13 @@ namespace
return result;
}
} // namespace
INSTANTIATE_TEST_SUITE_P(TestDhtTxOwner, TxOwner,
::testing::ValuesIn(makeData()));
TEST_CASE("TxOwner ops", "[dht]")
{
// test single interactions (constructor and hash)
auto d = GENERATE(from_range(makeCmpData()));
INSTANTIATE_TEST_SUITE_P(TestDhtTxOwner, TxOwnerOps,
::testing::ValuesIn(makeCmpData()));
REQUIRE((d.lhs == d.rhs) == d.equal);
REQUIRE((d.lhs < d.rhs) == d.less);
}
} // namespace

@ -1 +0,0 @@
#include <llarp_test.hpp>

@ -1,15 +1,16 @@
#ifndef LLARP_TEST
#define LLARP_TEST
#include <gtest/gtest.h>
#include <crypto/mock_crypto.hpp>
#include <catch2/catch.hpp>
#include <gmock/gmock.h>
namespace llarp
{
namespace test
{
template < typename CryptoImpl = MockCrypto >
class LlarpTest : public ::testing::Test
template <typename CryptoImpl = MockCrypto>
class LlarpTest
{
protected:
CryptoImpl m_crypto;
@ -17,9 +18,18 @@ namespace llarp
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 llarp

@ -1,99 +1,104 @@
#include <gtest/gtest.h>
#include <net/net_int.hpp>
#include <net/ip.hpp>
#include <net/ip_range.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;
ASSERT_TRUE(ip.FromString("fc00::1"));
}
TEST_F(TestNet, TestIn6AddrFromStringFail)
{
llarp::huint128_t ip;
ASSERT_FALSE(ip.FromString("10.1.1.1"));
SECTION("From string")
{
REQUIRE(ip.FromString("fc00::1"));
}
SECTION("From string fail")
{
REQUIRE_FALSE(ip.FromString("10.1.1.1"));
}
}
TEST_F(TestNet, TestIn6AddrToHUIntLoopback)
TEST_CASE("In6AddrToHUIntLoopback")
{
llarp::huint128_t loopback = {0};
ASSERT_TRUE(loopback.FromString("::1"));
REQUIRE(loopback.FromString("::1"));
in6_addr addr = IN6ADDR_LOOPBACK_INIT;
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};
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}}};
auto huint = llarp::net::In6ToHUInt(addr);
ASSERT_EQ(huint, huint_parsed);
REQUIRE(huint == huint_parsed);
huint_parsed.h++;
ASSERT_NE(huint, huint_parsed);
}
TEST_F(TestNet, TestRangeContains8)
{
ASSERT_TRUE(
llarp::IPRange::FromIPv4(10, 0, 0, 1, 8).Contains(llarp::ipaddr_ipv4_bits(10, 40, 11, 6)));
}
TEST_F(TestNet, TestRangeContains24)
{
ASSERT_TRUE(llarp::IPRange::FromIPv4(10, 200, 0, 1, 24)
.Contains(llarp::ipaddr_ipv4_bits(10, 200, 0, 253)));
}
TEST_F(TestNet, TestRangeContainsFail)
{
ASSERT_TRUE(!llarp::IPRange::FromIPv4(192, 168, 0, 1, 24)
.Contains(llarp::ipaddr_ipv4_bits(10, 200, 0, 253)));
}
TEST_F(TestNet, TestIPv4Netmask)
{
ASSERT_TRUE(llarp::netmask_ipv4_bits(8) == llarp::huint32_t{0xFF000000});
ASSERT_TRUE(llarp::netmask_ipv4_bits(24) == llarp::huint32_t{0xFFFFFF00});
}
TEST_F(TestNet, TestBogon_10_8)
{
ASSERT_TRUE(llarp::IsIPv4Bogon(llarp::ipaddr_ipv4_bits(10, 40, 11, 6)));
}
TEST_F(TestNet, TestBogon_192_168_16)
{
ASSERT_TRUE(llarp::IsIPv4Bogon(llarp::ipaddr_ipv4_bits(192, 168, 1, 111)));
}
TEST_F(TestNet, TestBogon_DoD_8)
{
ASSERT_TRUE(llarp::IsIPv4Bogon(llarp::ipaddr_ipv4_bits(21, 3, 37, 70)));
REQUIRE(huint != huint_parsed);
}
TEST_F(TestNet, TestBogon_127_8)
TEST_CASE("Range")
{
ASSERT_TRUE(llarp::IsIPv4Bogon(llarp::ipaddr_ipv4_bits(127, 0, 0, 1)));
SECTION("Contains 8")
{
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, TestBogon_0_8)
TEST_CASE("IPv4 netmask")
{
ASSERT_TRUE(llarp::IsIPv4Bogon(llarp::ipaddr_ipv4_bits(0, 0, 0, 0)));
REQUIRE(llarp::netmask_ipv4_bits(8) == llarp::huint32_t{0xFF000000});
REQUIRE(llarp::netmask_ipv4_bits(24) == llarp::huint32_t{0xFFFFFF00});
}
TEST_F(TestNet, TestBogon_NonBogon)
TEST_CASE("Bogon")
{
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)));
SECTION("Bogon_10_8")
{
REQUIRE(llarp::IsIPv4Bogon(llarp::ipaddr_ipv4_bits(10, 40, 11, 6)));
}
SECTION("Bogon_192_168_16")
{
REQUIRE(llarp::IsIPv4Bogon(llarp::ipaddr_ipv4_bits(192, 168, 1, 111)));
}
SECTION("Bogon_DoD_8")
{
REQUIRE(llarp::IsIPv4Bogon(llarp::ipaddr_ipv4_bits(21, 3, 37, 70)));
}
SECTION("Bogon_127_8")
{
REQUIRE(llarp::IsIPv4Bogon(llarp::ipaddr_ipv4_bits(127, 0, 0, 1)));
}
SECTION("Bogon_0_8")
{
REQUIRE(llarp::IsIPv4Bogon(llarp::ipaddr_ipv4_bits(0, 0, 0, 0)));
}
SECTION("Non-bogon")
{
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)));
REQUIRE_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/router.hpp"
class TestRouterVersion : public ::testing::Test
{
};
#include <catch2/catch.hpp>
using Catch::Matchers::Equals;
TEST_F(TestRouterVersion, TestCompatibilityWhenProtocolEqual)
TEST_CASE("Compatibility when protocol equal", "[RouterVersion]")
{
llarp::RouterVersion v1( {0, 1, 2}, 1);
llarp::RouterVersion v2( {0, 1, 2}, 1);
llarp::RouterVersion v1({0, 1, 2}, 1);
llarp::RouterVersion v2({0, 1, 2}, 1);
EXPECT_TRUE(v1.IsCompatableWith(v2));
CHECK(v1.IsCompatableWith(v2));
}
TEST_F(TestRouterVersion, TestCompatibilityWhenProtocolUnequal)
TEST_CASE("Compatibility when protocol unequal", "[RouterVersion]")
{
llarp::RouterVersion older( {0, 1, 2}, 1);
llarp::RouterVersion newer( {0, 1, 2}, 2);
llarp::RouterVersion older({0, 1, 2}, 1);
llarp::RouterVersion newer({0, 1, 2}, 2);
EXPECT_FALSE(older.IsCompatableWith(newer));
EXPECT_FALSE(newer.IsCompatableWith(older));
CHECK_FALSE(older.IsCompatableWith(newer));
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);
EXPECT_FALSE(notEmpty.IsEmpty());
llarp::RouterVersion notEmpty({0, 0, 1}, LLARP_PROTO_VERSION);
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);
EXPECT_FALSE(version.IsEmpty());
llarp::RouterVersion version({0, 0, 1}, LLARP_PROTO_VERSION);
CHECK_FALSE(version.IsEmpty());
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);
EXPECT_TRUE(v1235.BEncode(&buf));
CHECK(v1235.BEncode(&buf));
std::string s((const char*)buf.begin(), (buf.end() - 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;
version.Clear();
const std::string bString("li9ei3ei2ei1ee");
llarp_buffer_t buf(bString.data(), bString.size());
EXPECT_TRUE(version.BDecode(&buf));
CHECK(version.BDecode(&buf));
llarp::RouterVersion expected( {3, 2, 1}, 9);
EXPECT_EQ(expected, version);
llarp::RouterVersion expected({3, 2, 1}, 9);
CHECK(expected == version);
}
TEST_F(TestRouterVersion, TestDecodeLongVersionArray)
TEST_CASE("Decode long version array", "[RouterVersion]")
{
llarp::RouterVersion version;
version.Clear();
const std::string bString("li9ei3ei2ei1ei2ei3ei4ei5ei6ei7ei8ei9ee");
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_libsodium.hpp>
#include <crypto/mock_crypto.hpp>
#include <llarp_test.hpp>
#include <gtest/gtest.h>
#include <gmock/gmock.h>
#include <catch2/catch.hpp>
using namespace ::testing;
using namespace ::llarp;
using namespace ::llarp::test;
using ObtainExitMessage = routing::ObtainExitMessage;
class ObtainExitTest : public test::LlarpTest<>
{
public:
SecretKey alice;
ObtainExitTest()
{
// m_crypto.identity_keygen(alice);
}
};
void
fill(Signature& s)
{
s.Fill(0xFF);
}
TEST_F(ObtainExitTest, TestSignVerify)
TEST_CASE_METHOD(LlarpTest<>, "Sign-verify")
{
EXPECT_CALL(m_crypto, sign(_, alice, _))
.WillOnce(DoAll(WithArg< 0 >(Invoke(&fill)), Return(true)));
SecretKey alice;
EXPECT_CALL(m_crypto, sign(_, alice, _)).WillOnce(DoAll(WithArg<0>(Invoke(&fill)), Return(true)));
EXPECT_CALL(m_crypto, verify(_, _, _)).WillOnce(Return(true));
ObtainExitMessage msg;
msg.Z.Zero();
msg.S = randint();
msg.T = randint();
EXPECT_TRUE(msg.Sign(alice));
EXPECT_TRUE(msg.Verify());
EXPECT_TRUE(msg.I == PubKey(seckey_topublic(alice)));
EXPECT_FALSE(msg.version != LLARP_PROTO_VERSION);
EXPECT_FALSE(msg.Z.IsZero());
CHECK(msg.Sign(alice));
CHECK(msg.Verify());
CHECK(msg.I == PubKey(seckey_topublic(alice)));
CHECK(msg.version == LLARP_PROTO_VERSION);
CHECK_FALSE(msg.Z.IsZero());
}

@ -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 <gtest/gtest.h>
#include <catch2/catch.hpp>
struct ServiceAddressTest : public ::testing::Test
TEST_CASE("Address", "[Address]")
{
const std::string snode =
"8zfiwpgonsu5zpddpxwdurxyb19x6r96xy4qbikff99jwsziws9y.snode";
const std::string loki =
"7okic5x5do3uh3usttnqz9ek3uuoemdrwzto1hciwim9f947or6y.loki";
const std::string snode = "8zfiwpgonsu5zpddpxwdurxyb19x6r96xy4qbikff99jwsziws9y.snode";
const std::string loki = "7okic5x5do3uh3usttnqz9ek3uuoemdrwzto1hciwim9f947or6y.loki";
const std::string sub = "lokinet.test";
const std::string invalid =
"7okic5x5do3uh3usttnqz9ek3uuoemdrwzto1hciwim9f947or6y.net";
};
TEST_F(ServiceAddressTest, TestParseBadTLD)
{
llarp::service::Address addr;
ASSERT_FALSE(addr.FromString(snode, ".net"));
ASSERT_FALSE(addr.FromString(invalid, ".net"));
}
TEST_F(ServiceAddressTest, TestParseBadTLDAppenedOnEnd)
{
const std::string invalid = "7okic5x5do3uh3usttnqz9ek3uuoemdrwzto1hciwim9f947or6y.net";
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"));
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, 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 <gtest/gtest.h>
#include <catch2/catch.hpp>
using namespace ::llarp;
using namespace ::testing;
using EncryptedFrame = EncryptedFrame;
using SecretKey = SecretKey;
using PubKey = PubKey;
using LRCR = LR_CommitRecord;
using SecretKey = SecretKey;
using PubKey = PubKey;
using LRCR = LR_CommitRecord;
class FrameTest : public test::LlarpTest<>
{
@ -23,7 +23,7 @@ class FrameTest : public test::LlarpTest<>
SecretKey alice, bob;
};
TEST_F(FrameTest, TestFrameCrypto)
TEST_CASE_METHOD(FrameTest, "Frame crypto")
{
EncryptedFrame f(256);
f.Fill(0);
@ -36,28 +36,25 @@ TEST_F(FrameTest, TestFrameCrypto)
auto buf = f.Buffer();
buf->cur = buf->base + EncryptedFrameOverheadSize;
ASSERT_TRUE(record.BEncode(buf));
REQUIRE(record.BEncode(buf));
EXPECT_CALL(m_crypto, randbytes(_, _))
.WillOnce(Invoke(&test::randbytes_impl));
EXPECT_CALL(m_crypto, randbytes(_, _)).WillOnce(Invoke(&test::randbytes_impl));
EXPECT_CALL(m_crypto, dh_client(_, _, alice, _)).WillOnce(Return(true));
EXPECT_CALL(m_crypto, xchacha20(_, _, _))
.Times(2)
.WillRepeatedly(Return(true));
EXPECT_CALL(m_crypto, xchacha20(_, _, _)).Times(2).WillRepeatedly(Return(true));
EXPECT_CALL(m_crypto, hmac(_, _, _)).Times(2).WillRepeatedly(Return(true));
// rewind buffer
buf->cur = buf->base + EncryptedFrameOverheadSize;
// 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));
// decrypt from alice
ASSERT_TRUE(f.DecryptInPlace(bob));
REQUIRE(f.DecryptInPlace(bob));
LRCR otherRecord;
ASSERT_TRUE(otherRecord.BDecode(buf));
ASSERT_TRUE(otherRecord == record);
REQUIRE(otherRecord.BDecode(buf));
REQUIRE(otherRecord == record);
}

@ -1,7 +1,6 @@
#include <util/meta/memfn.hpp>
#include <gtest/gtest.h>
#include <gmock/gmock.h>
#include <catch2/catch.hpp>
using namespace llarp;
@ -32,36 +31,25 @@ struct Foo
}
};
TEST(MemFn, call)
TEST_CASE("memFn call")
{
Foo foo;
ASSERT_FALSE(util::memFn(&Foo::empty, &foo)());
ASSERT_TRUE(util::memFn(&Foo::constEmpty, &foo)());
ASSERT_EQ(11, util::memFn(&Foo::arg, &foo)(10));
ASSERT_EQ(9, util::memFn(&Foo::constArg, &foo)(10));
REQUIRE_FALSE(util::memFn(&Foo::empty, &foo)());
REQUIRE(util::memFn(&Foo::constEmpty, &foo)());
REQUIRE(11 == util::memFn(&Foo::arg, &foo)(10));
REQUIRE(9 == util::memFn(&Foo::constArg, &foo)(10));
ASSERT_TRUE(util::memFn(&Foo::constEmpty, &foo)());
ASSERT_EQ(9, util::memFn(&Foo::constArg, &foo)(10));
REQUIRE(util::memFn(&Foo::constEmpty, &foo)());
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
using MemFnTypes = ::testing::Types<
using MemFnTypes = std::tuple<
Foo, const Foo>;
INSTANTIATE_TYPED_TEST_SUITE_P(MemFn, MemFnType, MemFnTypes);
// 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 <gtest/gtest.h>
#include <gmock/gmock.h>
#include <catch2/catch.hpp>
using namespace llarp;
TEST(traits_bottom, Smoke)
TEST_CASE("traits::Bottom smoke test")
{
traits::Bottom bottom;
(void)bottom;
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
using ContainerTypes = ::testing::Types<
using ContainerTypes = std::tuple<
std::tuple< std::vector< int >, 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 > >,
@ -41,8 +23,16 @@ using ContainerTypes = ::testing::Types<
std::tuple< std::tuple<std::string>, 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 B { };
struct C { };
@ -65,29 +55,11 @@ char f(H) { return 'H'; }
char f(I) { return 'I'; }
char f(J) { return 'J'; }
char f(traits::Bottom) { return '0'; }
// 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
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, '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 > >,
@ -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, '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>
using is_bool = std::is_same<T, bool>;
@ -126,56 +105,35 @@ selectCase()
return dispatch(Selection());
}
template < typename T >
class Select : public ::testing::Test
{
};
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<
// clang-format off
using SelectTypes = std::tuple<
std::tuple<std::integral_constant<char, '0'>, double >,
std::tuple<std::integral_constant<char, 'b'>, bool >,
std::tuple<std::integral_constant<char, 'c'>, char >,
std::tuple<std::integral_constant<char, 's'>, std::string >
>;
INSTANTIATE_TYPED_TEST_SUITE_P(traits, Select, SelectTypes);
// clang-format on
template < typename T >
class IsPointy : public ::testing::Test
{
};
TYPED_TEST_SUITE_P(IsPointy);
TYPED_TEST_P(IsPointy, Smoke)
TEMPLATE_LIST_TEST_CASE("selectCase smoke test", "", SelectTypes)
{
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);
char expected = std::tuple_element_t<0, TestType>::value;
char result = selectCase<std::tuple_element_t<1, TestType>>();
REQUIRE(expected == result);
}
REGISTER_TYPED_TEST_SUITE_P(IsPointy, Smoke);
// clang-format on
// clang-format off
using PointerTypes = ::testing::Types<
using PointerTypes = std::tuple<
std::tuple< int *, std::true_type >,
std::tuple< int, std::integral_constant< bool, false > >,
std::tuple< std::shared_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
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>
@ -7,218 +7,176 @@
#include <type_traits>
#include <unordered_map>
using TestSizes = ::testing::Types< std::integral_constant< std::size_t, 8 >,
std::integral_constant< std::size_t, 12 >,
std::integral_constant< std::size_t, 16 >,
std::integral_constant< std::size_t, 32 >,
std::integral_constant< std::size_t, 64 >,
std::integral_constant< std::size_t, 77 >,
std::integral_constant< std::size_t, 1024 >,
std::integral_constant< std::size_t, 3333 > >;
template < typename T >
struct AlignedBufferTest : public ::testing::Test
using TestSizes = std::tuple<
std::integral_constant<std::size_t, 8>,
std::integral_constant<std::size_t, 12>,
std::integral_constant<std::size_t, 16>,
std::integral_constant<std::size_t, 32>,
std::integral_constant<std::size_t, 64>,
std::integral_constant<std::size_t, 77>,
std::integral_constant<std::size_t, 1024>,
std::integral_constant<std::size_t, 3333>>;
TEMPLATE_LIST_TEST_CASE("AlignedBuffer", "[AlignedBuffer]", TestSizes)
{
};
TYPED_TEST_CASE(AlignedBufferTest, TestSizes, );
TYPED_TEST(AlignedBufferTest, Constructor)
{
using Buffer = llarp::AlignedBuffer< TypeParam::value >;
using Buffer = llarp::AlignedBuffer<TestType::value>;
Buffer b;
EXPECT_TRUE(b.IsZero());
EXPECT_EQ(b.size(), TypeParam::value);
}
TYPED_TEST(AlignedBufferTest, CopyConstructor)
{
using Buffer = llarp::AlignedBuffer< TypeParam::value >;
Buffer b;
EXPECT_TRUE(b.IsZero());
Buffer c = b;
EXPECT_TRUE(c.IsZero());
CHECK(b.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);
SECTION("Constructor")
{
CHECK(b.size() == TestType::value);
}
Buffer c(b.as_array());
EXPECT_FALSE(c.IsZero());
SECTION("CopyConstructor")
{
Buffer c = b;
CHECK(c.IsZero());
Buffer d(c.data());
EXPECT_FALSE(d.IsZero());
}
c.Fill(1);
CHECK_FALSE(c.IsZero());
TYPED_TEST(AlignedBufferTest, Assignment)
{
using Buffer = llarp::AlignedBuffer< TypeParam::value >;
Buffer d = c;
CHECK_FALSE(d.IsZero());
}
Buffer b;
EXPECT_TRUE(b.IsZero());
SECTION("AltConstructors")
{
b.Fill(2);
Buffer c;
c = b;
EXPECT_TRUE(c.IsZero());
Buffer c(b.as_array());
CHECK_FALSE(c.IsZero());
c.Fill(1);
EXPECT_FALSE(c.IsZero());
Buffer d(c.data());
CHECK_FALSE(d.IsZero());
}
Buffer d;
d = c;
EXPECT_FALSE(d.IsZero());
}
SECTION("Assignment")
{
Buffer c;
c = b;
CHECK(c.IsZero());
TYPED_TEST(AlignedBufferTest, StreamOut)
{
using Buffer = llarp::AlignedBuffer< TypeParam::value >;
c.Fill(1);
CHECK_FALSE(c.IsZero());
Buffer b;
EXPECT_TRUE(b.IsZero());
Buffer d;
d = c;
CHECK_FALSE(d.IsZero());
}
std::stringstream stream;
SECTION("StreamOut")
{
std::stringstream stream;
stream << b;
stream << b;
EXPECT_EQ(stream.str(), std::string(TypeParam::value * 2, '0'));
CHECK(stream.str() == std::string(TestType::value * 2, '0'));
stream.str("");
stream.str("");
b.Fill(255);
stream << b;
b.Fill(255);
stream << b;
EXPECT_EQ(stream.str(), std::string(TypeParam::value * 2, 'f'));
}
CHECK(stream.str() == std::string(TestType::value * 2, 'f'));
}
TYPED_TEST(AlignedBufferTest, BitwiseNot)
{
using Buffer = llarp::AlignedBuffer< TypeParam::value >;
SECTION("BitwiseNot")
{
Buffer c = ~b;
CHECK_FALSE(c.IsZero());
Buffer b;
EXPECT_TRUE(b.IsZero());
for (auto val : c.as_array())
{
CHECK(255 == val);
}
Buffer c = ~b;
EXPECT_FALSE(c.IsZero());
Buffer d = ~c;
CHECK(d.IsZero());
}
for(auto val : c.as_array())
SECTION("Operators")
{
EXPECT_EQ(255, val);
Buffer c = b;
CHECK(b == c);
CHECK(b >= c);
CHECK(b <= c);
CHECK(c >= b);
CHECK(c <= b);
c.Fill(1);
CHECK(b != c);
CHECK(b < c);
CHECK(c > b);
}
Buffer d = ~c;
EXPECT_TRUE(d.IsZero());
}
TYPED_TEST(AlignedBufferTest, Operators)
{
using Buffer = llarp::AlignedBuffer< TypeParam::value >;
Buffer b;
EXPECT_TRUE(b.IsZero());
Buffer c = b;
EXPECT_EQ(b, c);
EXPECT_GE(b, c);
EXPECT_LE(b, c);
EXPECT_GE(c, b);
EXPECT_LE(c, b);
c.Fill(1);
EXPECT_NE(b, c);
EXPECT_LT(b, c);
EXPECT_GT(c, b);
}
TYPED_TEST(AlignedBufferTest, Xor)
{
using Buffer = llarp::AlignedBuffer< TypeParam::value >;
Buffer b;
Buffer c;
b.Fill(255);
c.Fill(255);
EXPECT_FALSE(b.IsZero());
EXPECT_FALSE(c.IsZero());
Buffer d = b ^ c;
// 1 ^ 1 = 0
EXPECT_TRUE(d.IsZero());
// Verify unchanged
EXPECT_FALSE(b.IsZero());
EXPECT_FALSE(c.IsZero());
Buffer e, f;
e.Fill(255);
Buffer g = e ^ f;
// 1 ^ 0 = 1
EXPECT_FALSE(g.IsZero());
Buffer h, i;
i.Fill(255);
Buffer j = h ^ i;
// 0 ^ 1 = 1
EXPECT_FALSE(j.IsZero());
}
TYPED_TEST(AlignedBufferTest, XorAssign)
{
using Buffer = llarp::AlignedBuffer< TypeParam::value >;
Buffer b, c;
b.Fill(255);
c.Fill(255);
EXPECT_FALSE(b.IsZero());
EXPECT_FALSE(c.IsZero());
b ^= c;
EXPECT_TRUE(b.IsZero());
}
TYPED_TEST(AlignedBufferTest, Zero)
{
using Buffer = llarp::AlignedBuffer< TypeParam::value >;
SECTION("Xor")
{
Buffer c;
b.Fill(255);
c.Fill(255);
CHECK_FALSE(b.IsZero());
CHECK_FALSE(c.IsZero());
Buffer d = b ^ c;
// 1 ^ 1 = 0
CHECK(d.IsZero());
// Verify unchanged
CHECK_FALSE(b.IsZero());
CHECK_FALSE(c.IsZero());
Buffer e, f;
e.Fill(255);
Buffer g = e ^ f;
// 1 ^ 0 = 1
CHECK_FALSE(g.IsZero());
Buffer h, i;
i.Fill(255);
Buffer j = h ^ i;
// 0 ^ 1 = 1
CHECK_FALSE(j.IsZero());
}
Buffer b;
EXPECT_TRUE(b.IsZero());
SECTION("XorAssign")
{
Buffer c;
b.Fill(255);
c.Fill(255);
CHECK_FALSE(b.IsZero());
CHECK_FALSE(c.IsZero());
b ^= c;
CHECK(b.IsZero());
}
b.Fill(127);
EXPECT_FALSE(b.IsZero());
SECTION("Zero")
{
b.Fill(127);
CHECK_FALSE(b.IsZero());
b.Zero();
EXPECT_TRUE(b.IsZero());
}
b.Zero();
CHECK(b.IsZero());
}
TYPED_TEST(AlignedBufferTest, TestHash)
{
using Buffer = llarp::AlignedBuffer< TypeParam::value >;
using Map_t = std::unordered_map< Buffer, int, typename Buffer::Hash >;
Buffer k, other_k;
k.Randomize();
other_k.Randomize();
Map_t m;
EXPECT_TRUE(m.empty());
EXPECT_TRUE(m.emplace(k, 1).second);
EXPECT_TRUE(m.find(k) != m.end());
EXPECT_TRUE(m[k] == 1);
EXPECT_FALSE(m.find(other_k) != m.end());
EXPECT_TRUE(m.size() == 1);
Buffer k_copy = k;
EXPECT_FALSE(m.emplace(k_copy, 2).second);
EXPECT_FALSE(m[k_copy] == 2);
EXPECT_TRUE(m[k_copy] == 1);
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 <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
{
TestBuffer buffer;
@ -18,15 +18,15 @@ struct TestReadData
Result result;
};
using TestReadInt = TestReadData< uint64_t >;
using TestReadString = TestReadData< std::string >;
using TestReadInt = TestReadData<uint64_t>;
using TestReadString = TestReadData<std::string>;
template < typename Result >
template <typename Result>
std::ostream&
operator<<(std::ostream& os, const TestReadData< Result >& d)
operator<<(std::ostream& os, const TestReadData<Result>& d)
{
os << "buf = [ ";
for(auto x : d.buffer)
for (auto x : d.buffer)
{
os << x << " ";
}
@ -37,33 +37,16 @@ operator<<(std::ostream& os, const TestReadData< Result >& d)
return os;
}
struct ReadInt : public ::testing::TestWithParam< TestReadInt >
{
};
TEST_P(ReadInt, readInt)
{
auto d = GetParam();
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 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 const TestReadInt testReadInt[] = {
std::vector<TestReadInt> testReadInt{
// good cases
{{i, 0, e}, true, 0},
{{i, zero, e}, true, 0},
@ -80,28 +63,20 @@ static const TestReadInt testReadInt[] = {
{{z}, false, 0},
};
INSTANTIATE_TEST_SUITE_P(TestBencode, ReadInt,
::testing::ValuesIn(testReadInt));
struct ReadStr : public ::testing::TestWithParam< TestReadString >
{
};
TEST_P(ReadStr, readStr)
TEST_CASE("Read int", "[bencode]")
{
auto d = GetParam();
auto d = GENERATE(from_range(testReadInt));
llarp_buffer_t buffer(d.buffer);
llarp_buffer_t result;
bool rc = bencode_read_string(&buffer, &result);
uint64_t result = 0;
bool rc = bencode_read_integer(&buffer, &result);
EXPECT_EQ(rc, d.rc);
EXPECT_EQ(result.sz, d.result.size());
EXPECT_EQ(std::string(result.base, result.base + result.sz), d.result);
CHECK(rc == d.rc);
CHECK(result == d.result);
}
static const TestReadString testReadStr[] = {
std::vector<TestReadString> testReadStr{
// good cases
{{one, colon, 'a'}, true, "a"},
{{one, colon, 'b'}, true, "b"},
@ -118,10 +93,21 @@ static const TestReadString testReadStr[] = {
{{colon, colon}, false, ""},
};
INSTANTIATE_TEST_SUITE_P(TestBencode, ReadStr,
::testing::ValuesIn(testReadStr));
TEST_CASE("Read str", "[bencode]")
{
auto d = GENERATE(from_range(testReadStr));
llarp_buffer_t buffer(d.buffer);
llarp_buffer_t result;
bool rc = bencode_read_string(&buffer, &result);
template < typename Input >
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
{
Input input;
@ -130,62 +116,39 @@ struct TestWriteData
std::string output;
};
using TestWriteByteString = TestWriteData< std::string >;
using TestWriteInt = TestWriteData< uint64_t >;
struct WriteByteStr : public ::testing::TestWithParam< TestWriteByteString >
{
};
TEST_P(WriteByteStr, writeByte)
{
auto d = GetParam();
std::vector< byte_t > backingBuffer(d.bufferSize, 0);
llarp_buffer_t buffer(backingBuffer);
using TestWriteByteString = TestWriteData<std::string>;
using TestWriteInt = TestWriteData<uint64_t>;
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 constexpr size_t MAX_1 =
static_cast< size_t >(std::numeric_limits< int16_t >::max()) + 1;
static const TestWriteByteString testWriteByteString[] = {
std::vector<TestWriteByteString> testWriteByteString{
// good cases
{"abacus", 100, true, "6:abacus"},
{" abacus", 100, true, "8: abacus"},
{"", 100, true, "0:"},
{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')},
// bad cases
{"a", 1, false, ""},
};
INSTANTIATE_TEST_SUITE_P(TestBencode, WriteByteStr,
::testing::ValuesIn(testWriteByteString));
struct WriteInt : public ::testing::TestWithParam< TestWriteInt >
{
};
TEST_P(WriteInt, writeInt)
TEST_CASE("Write byte str", "[bencode]")
{
auto d = GetParam();
auto d = GENERATE(from_range(testWriteByteString));
std::vector< byte_t > backingBuffer(d.bufferSize, 0);
std::vector<byte_t> backingBuffer(d.bufferSize, 0);
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);
ASSERT_EQ(std::string(buffer.base, buffer.cur), d.output);
REQUIRE(rc == d.rc);
REQUIRE(std::string(buffer.base, buffer.cur) == d.output);
}
static const TestWriteInt testWriteInt[] = {
std::vector<TestWriteInt> testWriteInt{
// Good cases
{0, 100, true, "i0e"},
{1234, 100, true, "i1234e"},
@ -194,59 +157,62 @@ static const TestWriteInt testWriteInt[] = {
{1234567, 3, false, ""},
};
INSTANTIATE_TEST_SUITE_P(TestBencode, WriteInt,
::testing::ValuesIn(testWriteInt));
struct WriteIntValues : public ::testing::TestWithParam< uint64_t >
TEST_CASE("Write int", "[bencode]")
{
};
auto d = GENERATE(from_range(testWriteInt));
std::vector<byte_t> backingBuffer(d.bufferSize, 0);
llarp_buffer_t buffer(backingBuffer);
TEST_P(WriteIntValues, anyvalue)
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.
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);
bool rc = bencode_write_uint64(&buffer, val);
ASSERT_TRUE(rc);
REQUIRE(rc);
}
{
uint64_t result = 0;
llarp_buffer_t buffer(backingBuffer);
bool rc = bencode_read_integer(&buffer, &result);
ASSERT_TRUE(rc);
ASSERT_EQ(result, val);
REQUIRE(rc);
REQUIRE(result == val);
}
}
INSTANTIATE_TEST_SUITE_P(
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)
TEST_CASE("Bencode: good uint64 entry", "[bencode]")
{
std::vector< byte_t > backingBuffer(100, 0);
std::vector<byte_t> backingBuffer(100, 0);
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);
ASSERT_FALSE(bencode_write_uint64_entry(&buffer, "v", 1, 0));
REQUIRE_FALSE(bencode_write_uint64_entry(&buffer, "v", 1, 0));
}
struct ValueData
@ -259,172 +225,139 @@ struct ValueData
struct ListTestData
{
std::vector< ValueData > list;
std::vector<ValueData> list;
size_t bufferSize;
std::string result;
};
struct ListTest : public ::testing::TestWithParam< ListTestData >
{
std::vector<ListTestData> listTestData{
{{}, 100, "le"},
{{{"", 0, true}}, 100, "l0:e"},
{{{"", 0, false}}, 100, "li0ee"},
{{{"", 0, false}, {"", 0, true}}, 100, "li0e0:e"},
{{{"", 123, false}, {"abc", 0, true}}, 100, "li123e3:abce"},
{{{"", 123, false}, {"abc", 0, true}, {"abc", 0, true}}, 100, "li123e3:abc3:abce"},
};
TEST_P(ListTest, list)
TEST_CASE("List test", "[bencode]")
{
auto d = GetParam();
auto d = GENERATE(from_range(listTestData));
std::vector< byte_t > backingBuffer(d.bufferSize, 0);
std::vector<byte_t> backingBuffer(d.bufferSize, 0);
llarp_buffer_t buffer(backingBuffer);
ASSERT_TRUE(bencode_start_list(&buffer));
REQUIRE(bencode_start_list(&buffer));
for(const auto& x : d.list)
for (const auto& x : d.list)
{
if(x.isString)
if (x.isString)
{
ASSERT_TRUE(bencode_write_bytestring(&buffer, x.theString.data(),
x.theString.size()));
REQUIRE(bencode_write_bytestring(&buffer, x.theString.data(), x.theString.size()));
}
else
{
ASSERT_TRUE(bencode_write_uint64(&buffer, x.theInt));
REQUIRE(bencode_write_uint64(&buffer, x.theInt));
}
}
ASSERT_TRUE(bencode_end(&buffer));
REQUIRE(bencode_end(&buffer));
ASSERT_EQ(std::string(buffer.base, buffer.cur), d.result);
REQUIRE(std::string(buffer.base, buffer.cur) == d.result);
}
ListTestData listTestData[] = {
{{}, 100, "le"},
{{{"", 0, true}}, 100, "l0:e"},
{{{"", 0, false}}, 100, "li0ee"},
{{{"", 0, false}, {"", 0, true}}, 100, "li0e0:e"},
{{{"", 123, false}, {"abc", 0, true}}, 100, "li123e3:abce"},
{{{"", 123, false}, {"abc", 0, true}, {"abc", 0, true}},
100,
"li123e3:abc3:abce"},
};
INSTANTIATE_TEST_SUITE_P(TestBencode, ListTest,
::testing::ValuesIn(listTestData));
struct DictTestData
{
std::vector< std::pair< char, ValueData > > list;
std::vector<std::pair<char, ValueData>> list;
size_t bufferSize;
std::string result;
};
struct DictTest : public ::testing::TestWithParam< DictTestData >
{
std::vector<DictTestData> dictTestData{
{{}, 100, "de"},
{{{'a', {"", 0, true}}}, 100, "d1:a0:e"},
{{{'b', {"", 0, false}}}, 100, "d1:bi0ee"},
{{{'c', {"", 0, false}}, {'d', {"", 0, true}}}, 100, "d1:ci0e1:d0:e"},
{{{'e', {"", 123, false}}, {'f', {"abc", 0, true}}}, 100, "d1:ei123e1:f3:abce"},
{{{'a', {"", 123, false}}, {'b', {"abc", 0, true}}, {'c', {"abc", 0, true}}},
100,
"d1:ai123e1:b3:abc1:c3:abce"},
};
TEST_P(DictTest, dict)
TEST_CASE("Dict test", "[bencode]")
{
auto d = GetParam();
auto d = GENERATE(from_range(dictTestData));
std::vector< byte_t > backingBuffer(d.bufferSize, 0);
std::vector<byte_t> backingBuffer(d.bufferSize, 0);
llarp_buffer_t buffer(backingBuffer);
ASSERT_TRUE(bencode_start_dict(&buffer));
REQUIRE(bencode_start_dict(&buffer));
for(const auto& x : d.list)
for (const auto& x : d.list)
{
ASSERT_TRUE(bencode_write_bytestring(&buffer, &x.first, 1));
if(x.second.isString)
REQUIRE(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()));
REQUIRE(
bencode_write_bytestring(&buffer, x.second.theString.data(), x.second.theString.size()));
}
else
{
ASSERT_TRUE(bencode_write_uint64(&buffer, x.second.theInt));
REQUIRE(bencode_write_uint64(&buffer, x.second.theInt));
}
}
ASSERT_TRUE(bencode_end(&buffer));
REQUIRE(bencode_end(&buffer));
ASSERT_EQ(std::string(buffer.base, buffer.cur), d.result);
REQUIRE(std::string(buffer.base, buffer.cur) == d.result);
}
DictTestData dictTestData[] = {
{{}, 100, "de"},
{{{'a', {"", 0, true}}}, 100, "d1:a0:e"},
{{{'b', {"", 0, false}}}, 100, "d1:bi0ee"},
{{{'c', {"", 0, false}}, {'d', {"", 0, true}}}, 100, "d1:ci0e1:d0:e"},
{{{'e', {"", 123, false}}, {'f', {"abc", 0, true}}},
100,
"d1:ei123e1:f3:abce"},
{{{'a', {"", 123, false}},
{'b', {"abc", 0, true}},
{'c', {"abc", 0, true}}},
100,
"d1:ai123e1:b3:abc1:c3:abce"},
};
INSTANTIATE_TEST_SUITE_P(TestBencode, DictTest,
::testing::ValuesIn(dictTestData));
struct ReadData
{
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 =
const_cast< byte_t* >(reinterpret_cast< const byte_t* >(d.input.data()));
byte_t* input = const_cast<byte_t*>(reinterpret_cast<const byte_t*>(d.input.data()));
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) {
if(key)
if (key)
{
result.emplace_back(key->base, key->base + key->sz);
}
return true;
},
&buffer));
ASSERT_EQ(result, d.output);
REQUIRE(result == d.output);
}
ReadData dictReadData[] = {{"de", {}},
{"d1:a0:e", {"a", ""}},
{"d1:be", {"b"}},
{"d1:b2:23e", {"b", "23"}}};
INSTANTIATE_TEST_SUITE_P(TestBencode, DictReadTest,
::testing::ValuesIn(dictReadData));
struct ListReadTest : public ::testing::TestWithParam< ReadData >
{
};
std::vector<ReadData> listReadData{
{"le", {}}, {"l1:ae", {"a"}}, {"l1:be", {"b"}}, {"l1:b2:23e", {"b", "23"}}};
TEST_P(ListReadTest, readtest)
TEST_CASE("Read list", "[bencode]")
{
auto d = GetParam();
auto d = GENERATE(from_range(listReadData));
byte_t* input =
const_cast< byte_t* >(reinterpret_cast< const byte_t* >(d.input.data()));
byte_t* input = const_cast<byte_t*>(reinterpret_cast<const byte_t*>(d.input.data()));
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) {
if(cont)
if (cont)
{
llarp_buffer_t tmp;
bencode_read_string(b, &tmp);
@ -433,18 +366,12 @@ TEST_P(ListReadTest, readtest)
return true;
},
&buffer));
ASSERT_EQ(result, d.output);
REQUIRE(result == d.output);
}
ReadData listReadData[] = {
{"le", {}}, {"l1:ae", {"a"}}, {"l1:be", {"b"}}, {"l1:b2:23e", {"b", "23"}}};
INSTANTIATE_TEST_SUITE_P(TestBencode, ListReadTest,
::testing::ValuesIn(listReadData));
TEST(TestBencode, ReadDictEmptyBuffer)
TEST_CASE("Read dict to empty buffer", "[bencode]")
{
llarp_buffer_t buf((byte_t*)nullptr, 0);
ASSERT_FALSE(llarp::bencode_read_dict(
[](llarp_buffer_t*, llarp_buffer_t*) { return true; }, &buf));
REQUIRE_FALSE(
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 now = 1s;
llarp::util::DecayingHashSet<llarp::RouterID> hashset(timeout);
const llarp::RouterID zero;
llarp::util::DecayingHashSet<llarp::RouterID> hashset{timeout};
const llarp::RouterID zero{};
REQUIRE(zero.IsZero());
REQUIRE(not hashset.Contains(zero));
REQUIRE(hashset.Insert(zero, now));
@ -20,20 +20,20 @@ TEST_CASE("DecayingHashSet test decay static time", "[decaying-hashset]")
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;
const llarp_time_t now = llarp::time_now_ms();
llarp::util::DecayingHashSet<llarp::RouterID> hashset(timeout);
const llarp::RouterID zero;
constexpr auto now = llarp::time_now_ms;
llarp::util::DecayingHashSet<llarp::RouterID> hashset{timeout};
const llarp::RouterID zero{};
REQUIRE(zero.IsZero());
REQUIRE(not hashset.Contains(zero));
REQUIRE(hashset.Insert(zero));
REQUIRE(hashset.Contains(zero));
hashset.Decay(now + 1s);
hashset.Decay(now() + 1s);
REQUIRE(hashset.Contains(zero));
hashset.Decay(now + timeout);
hashset.Decay(now() + timeout);
REQUIRE(not hashset.Contains(zero));
hashset.Decay(now + timeout + 1s);
hashset.Decay(now() + timeout + 1s);
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/logger.hpp>
#include <config/config.hpp>
@ -8,58 +8,49 @@ using TestString = std::string;
struct TestParseLog
{
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_CASE("parseLevel")
{
};
TEST_P(LogLevelTest, parseLevel)
{
const auto data = GetParam();
const auto data = GENERATE(from_range(testParseLog));
const auto maybe = llarp::LogLevelFromString(data.input);
EXPECT_EQ(maybe, data.level);
CHECK(maybe == data.level);
}
static const 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}};
INSTANTIATE_TEST_SUITE_P(TestLogConfig, LogLevelTest,
::testing::ValuesIn(testParseLog));
TEST_F(LogLevelTest, TestLogLevelToName)
TEST_CASE("TestLogLevelToName")
{
EXPECT_EQ("Trace", LogLevelToName(llarp::eLogTrace));
EXPECT_EQ("Debug", LogLevelToName(llarp::eLogDebug));
EXPECT_EQ("Info", LogLevelToName(llarp::eLogInfo));
EXPECT_EQ("Warn", LogLevelToName(llarp::eLogWarn));
EXPECT_EQ("Error", LogLevelToName(llarp::eLogError));
EXPECT_EQ("None", LogLevelToName(llarp::eLogNone));
EXPECT_EQ("???", LogLevelToName( (llarp::LogLevel)99999 ));
CHECK("Trace" == LogLevelToName(llarp::eLogTrace));
CHECK("Debug" == LogLevelToName(llarp::eLogDebug));
CHECK("Info" == LogLevelToName(llarp::eLogInfo));
CHECK("Warn" == LogLevelToName(llarp::eLogWarn));
CHECK("Error" == LogLevelToName(llarp::eLogError));
CHECK("None" == LogLevelToName(llarp::eLogNone));
CHECK("???" == LogLevelToName((llarp::LogLevel)99999));
}
TEST_F(LogLevelTest, TestLogLevelToString)
TEST_CASE("TestLogLevelToString")
{
EXPECT_EQ("TRC", LogLevelToString(llarp::eLogTrace));
EXPECT_EQ("DBG", LogLevelToString(llarp::eLogDebug));
EXPECT_EQ("NFO", LogLevelToString(llarp::eLogInfo));
EXPECT_EQ("WRN", LogLevelToString(llarp::eLogWarn));
EXPECT_EQ("ERR", LogLevelToString(llarp::eLogError));
EXPECT_EQ("???", LogLevelToString(llarp::eLogNone));
CHECK("TRC" == LogLevelToString(llarp::eLogTrace));
CHECK("DBG" == LogLevelToString(llarp::eLogDebug));
CHECK("NFO" == LogLevelToString(llarp::eLogInfo));
CHECK("WRN" == LogLevelToString(llarp::eLogWarn));
CHECK("ERR" == LogLevelToString(llarp::eLogError));
CHECK("???" == LogLevelToString(llarp::eLogNone));
}

@ -7,7 +7,7 @@
#include <functional>
#include <thread>
#include <gtest/gtest.h>
#include <catch2/catch.hpp>
using namespace llarp;
using namespace llarp::thread;
@ -24,8 +24,7 @@ class Element
public:
Element(double d, bool _stop = false) : data(d), shouldStop(_stop)
{
}
{}
double
val() const
@ -46,7 +45,7 @@ operator==(const Element& lhs, const Element& rhs)
return lhs.val() == rhs.val();
}
using ObjQueue = Queue< Element >;
using ObjQueue = Queue<Element>;
class Args
{
@ -68,14 +67,8 @@ class Args
volatile size_t endSignal;
Args(size_t _iterations, size_t size = 20 * 1000)
: queue(size)
, iterations(_iterations)
, count(0)
, startSignal(0)
, runSignal(0)
, endSignal(0)
{
}
: queue(size), iterations(_iterations), count(0), startSignal(0), runSignal(0), endSignal(0)
{}
bool
signal() const
@ -93,10 +86,10 @@ popFrontTester(Args& args)
args.cv.wait(lock, [&] { return args.signal(); });
}
for(;;)
for (;;)
{
Element e = args.queue.popFront();
if(e.stop())
if (e.stop())
{
break;
}
@ -112,9 +105,9 @@ pushBackTester(Args& args)
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);
}
@ -122,38 +115,34 @@ pushBackTester(Args& args)
}
void
abaThread(char* firstValue, char* lastValue, Queue< char* >& queue,
util::Barrier& barrier)
abaThread(char* firstValue, char* lastValue, Queue<char*>& queue, util::Barrier& barrier)
{
barrier.Block();
for(char* val = firstValue; val <= lastValue; ++val)
for (char* val = firstValue; val <= lastValue; ++val)
{
queue.pushBack(val);
}
}
struct Exception : public std::exception
{
};
{};
struct ExceptionTester
{
static std::atomic< std::thread::id > throwFrom;
static std::atomic<std::thread::id> throwFrom;
void
test()
{
if(throwFrom != std::thread::id()
&& std::this_thread::get_id() == throwFrom)
if (throwFrom != std::thread::id() && std::this_thread::get_id() == throwFrom)
{
throw Exception();
}
}
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
sleepNWait(std::chrono::microseconds microseconds, util::Barrier& barrier)
@ -178,18 +167,18 @@ sleepNWait(std::chrono::microseconds microseconds, util::Barrier& barrier)
}
void
exceptionProducer(Queue< ExceptionTester >& queue, util::Semaphore& semaphore,
std::atomic_size_t& caught)
exceptionProducer(
Queue<ExceptionTester>& queue, util::Semaphore& semaphore, std::atomic_size_t& caught)
{
static constexpr size_t iterations = 3;
for(size_t i = 0; i < iterations; ++i)
for (size_t i = 0; i < iterations; ++i)
{
try
{
queue.pushBack(ExceptionTester());
}
catch(const Exception&)
catch (const Exception&)
{
++caught;
}
@ -204,18 +193,15 @@ struct MoveTester
size_t& moveCounter;
size_t value;
explicit MoveTester(size_t& counter, size_t val)
: moved(false), moveCounter(counter), value(val)
{
}
explicit MoveTester(size_t& counter, size_t val) : moved(false), moveCounter(counter), value(val)
{}
explicit MoveTester(const MoveTester& rhs) = delete;
MoveTester&
operator=(const MoveTester& rhs) = delete;
MoveTester(MoveTester&& rhs)
: moved(false), moveCounter(rhs.moveCounter), value(rhs.value)
MoveTester(MoveTester&& rhs) : moved(false), moveCounter(rhs.moveCounter), value(rhs.value)
{
rhs.moved = true;
moveCounter++;
@ -224,8 +210,8 @@ struct MoveTester
MoveTester&
operator=(MoveTester&& rhs)
{
value = rhs.value;
rhs.moved = true;
value = rhs.value;
rhs.moved = true;
moveCounter = rhs.moveCounter;
moveCounter++;
@ -234,22 +220,22 @@ struct MoveTester
}
};
TEST(TestQueue, single)
TEST_CASE("single")
{
ObjQueue queue(1u);
ASSERT_EQ(0u, queue.size());
ASSERT_EQ(1u, queue.capacity());
REQUIRE(0u == queue.size());
REQUIRE(1u == queue.capacity());
}
TEST(TestQueue, breathing)
TEST_CASE("breathing")
{
static constexpr size_t DEFAULT_CAP = 10 * 1000;
ObjQueue queue(DEFAULT_CAP);
ASSERT_EQ(0u, queue.size());
ASSERT_EQ(DEFAULT_CAP, queue.capacity());
REQUIRE(0u == queue.size());
REQUIRE(DEFAULT_CAP == queue.capacity());
Element e1(1.0);
Element e2(2.0);
@ -263,260 +249,261 @@ TEST(TestQueue, breathing)
Element p2 = queue.popFront();
Element p3 = queue.popFront();
ASSERT_EQ(e1, p1);
ASSERT_EQ(e2, p2);
ASSERT_EQ(e3, p3);
REQUIRE(e1 == p1);
REQUIRE(e2 == p2);
REQUIRE(e3 == p3);
}
TEST(TestQueue, singleProducerManyConsumer)
TEST_CASE("Single producer many consumer")
{
static constexpr size_t iterations = 100 * 1000;
static constexpr size_t numThreads = 5;
std::array< std::thread, numThreads > threads;
std::array<std::thread, numThreads> threads;
Args args{iterations};
{
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)));
args.cv.wait(lock, [&] { return args.count != i+1; });
args.cv.wait(lock, [&] { return args.count != i + 1; });
}
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);
}
for(size_t i = 0; i < numThreads; ++i)
for (size_t i = 0; i < numThreads; ++i)
{
Element e{0.0, true};
args.queue.pushBack(e);
}
for(size_t i = 0; i < numThreads; ++i)
for (size_t i = 0; i < numThreads; ++i)
{
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 numThreads = 5;
std::array< std::thread, numThreads * 2 > threads;
std::array<std::thread, numThreads * 2> threads;
Args args{iterations};
{
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)));
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] =
std::thread(std::bind(&pushBackTester, std::ref(args)));
args.cv.wait(lock, [&] { return args.count != numThreads+i+1; });
threads[i + numThreads] = std::thread(std::bind(&pushBackTester, std::ref(args)));
args.cv.wait(lock, [&] { return args.count != numThreads + i + 1; });
}
args.runSignal++;
}
for(auto& thread : threads)
for (auto& thread : threads)
{
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
// object to the same "empty" position in the queue.
static constexpr size_t numThreads = 50;
static constexpr size_t numValues = 6;
static constexpr size_t numThreads = 50;
static constexpr size_t numValues = 6;
static constexpr size_t numIterations = 1000;
static constexpr size_t numEntries = numThreads * numValues;
static constexpr size_t numEntries = numThreads * numValues;
char block[numEntries];
for(size_t i = 0; i < numIterations; ++i)
for (size_t i = 0; i < numIterations; ++i)
{
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* lastValue[numThreads];
for(size_t j = 0; j < numThreads; ++j)
for (size_t j = 0; j < numThreads; ++j)
{
nextValue[j] = block + (numValues * j);
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([&] {
std::this_thread::sleep_for(100us);
barrier.Block();
std::this_thread::sleep_for(100us);
barrier.Block();
});
for(size_t j = 0; j < numEntries; ++j)
for (size_t j = 0; j < numEntries; ++j)
{
char* val = queue.popFront();
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);
ASSERT_LE(nextValue[k], lastValue[k]);
REQUIRE(nextValue[k] <= lastValue[k]);
break;
}
}
ASSERT_LT(k, numThreads);
REQUIRE(k < numThreads);
}
for(auto& thread : threads)
for (auto& thread : threads)
{
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
// generation rollover logic).
// 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.
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 numValues = numEntries / numThreads;
static constexpr size_t numValues = numEntries / numThreads;
char block[numEntries];
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* lastValue[numThreads];
for(size_t j = 0; j < numThreads; ++j)
for (size_t j = 0; j < numThreads; ++j)
{
nextValue[j] = block + (numValues * j);
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([&] {
std::this_thread::sleep_for(100ms);
barrier.Block();
std::this_thread::sleep_for(100ms);
barrier.Block();
});
for(size_t j = 0; j < numEntries; ++j)
for (size_t j = 0; j < numEntries; ++j)
{
char* val = queue.popFront();
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);
ASSERT_LE(nextValue[k], lastValue[k]);
REQUIRE(nextValue[k] <= lastValue[k]);
break;
}
}
ASSERT_LT(k, numThreads);
REQUIRE(k < numThreads);
}
for(auto& thread : threads)
for (auto& thread : threads)
{
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();
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();
}
TEST(TestQueue, exceptionSafety)
TEST_CASE("Exception safety")
{
ExceptionTester::throwFrom = std::thread::id();
ExceptionTester::throwFrom = std::thread::id();
static constexpr size_t queueSize = 3;
Queue< ExceptionTester > queue{queueSize};
Queue<ExceptionTester> queue{queueSize};
ASSERT_EQ(QueueReturn::Success, queue.pushBack(ExceptionTester()));
ASSERT_EQ(QueueReturn::Success, queue.pushBack(ExceptionTester()));
ASSERT_EQ(QueueReturn::Success, queue.pushBack(ExceptionTester()));
ASSERT_NE(QueueReturn::Success, queue.tryPushBack(ExceptionTester()));
REQUIRE(QueueReturn::Success == queue.pushBack(ExceptionTester()));
REQUIRE(QueueReturn::Success == queue.pushBack(ExceptionTester()));
REQUIRE(QueueReturn::Success == queue.pushBack(ExceptionTester()));
REQUIRE(QueueReturn::Success != queue.tryPushBack(ExceptionTester()));
util::Semaphore semaphore{0};
std::atomic_size_t caught = {0};
std::thread producer(std::bind(&exceptionProducer, std::ref(queue),
std::ref(semaphore), std::ref(caught)));
std::thread producer(
std::bind(&exceptionProducer, std::ref(queue), std::ref(semaphore), std::ref(caught)));
ExceptionTester::throwFrom = std::this_thread::get_id();
ASSERT_THROW({ (void)queue.popFront(); }, Exception);
REQUIRE_THROWS_AS(queue.popFront(), Exception);
using namespace std::literals;
// 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.
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.
ExceptionTester::throwFrom = producer.get_id();
@ -524,61 +511,61 @@ TEST(TestQueue, exceptionSafety)
// pop an item to unblock the pusher
(void)queue.popFront();
ASSERT_TRUE(semaphore.waitFor(1s));
REQUIRE(semaphore.waitFor(1s));
ASSERT_EQ(1u, caught);
REQUIRE(1u == caught);
ASSERT_EQ(0u, queue.size());
ASSERT_TRUE(queue.empty());
REQUIRE(0u == queue.size());
REQUIRE(queue.empty());
// after throwing, the queue works fine.
ASSERT_EQ(QueueReturn::Success, queue.pushBack(ExceptionTester()));
ASSERT_EQ(QueueReturn::Success, queue.pushBack(ExceptionTester()));
ASSERT_EQ(QueueReturn::Success, queue.pushBack(ExceptionTester()));
ASSERT_NE(QueueReturn::Success, queue.tryPushBack(ExceptionTester()));
REQUIRE(QueueReturn::Success == queue.pushBack(ExceptionTester()));
REQUIRE(QueueReturn::Success == queue.pushBack(ExceptionTester()));
REQUIRE(QueueReturn::Success == queue.pushBack(ExceptionTester()));
REQUIRE(QueueReturn::Success != queue.tryPushBack(ExceptionTester()));
ExceptionTester::throwFrom = std::thread::id();
producer.join();
}
TEST(TestQueue, moveIt)
TEST_CASE("Move it")
{
static constexpr size_t queueSize = 40;
Queue< MoveTester > queue{queueSize};
Queue<MoveTester> queue{queueSize};
size_t counter = 0;
queue.pushBack(MoveTester{counter, 0});
ASSERT_EQ(1u, counter);
REQUIRE(1u == counter);
MoveTester tester2(counter, 2);
queue.pushBack(std::move(tester2));
ASSERT_TRUE(tester2.moved);
ASSERT_EQ(2u, counter);
REQUIRE(tester2.moved);
REQUIRE(2u == counter);
ASSERT_EQ(QueueReturn::Success, queue.tryPushBack(MoveTester{counter, 3}));
ASSERT_EQ(3u, counter);
REQUIRE(QueueReturn::Success == queue.tryPushBack(MoveTester{counter, 3}));
REQUIRE(3u == counter);
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);
ASSERT_EQ(4u, counter);
REQUIRE(tester4.moved);
REQUIRE(4u == counter);
MoveTester popped = queue.popFront();
(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.
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
#endif
; 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\lokinetctl.exe"; DestDir: "{app}"; Flags: ignoreversion
Source: "LICENSE"; DestDir: "{app}"; Flags: ignoreversion

Loading…
Cancel
Save