mirror of
https://github.com/irungentoo/toxcore.git
synced 2024-03-22 13:30:51 +08:00
test: Add more unit tests for add_to_list
.
This commit is contained in:
parent
05ce5c1ab9
commit
afc38f2458
|
@ -68,6 +68,7 @@ jobs:
|
|||
cmake
|
||||
git
|
||||
libconfig-dev
|
||||
libgmock-dev
|
||||
libgtest-dev
|
||||
libopus-dev
|
||||
libsodium-dev
|
||||
|
|
1
.github/scripts/coverage-linux
vendored
1
.github/scripts/coverage-linux
vendored
|
@ -5,6 +5,7 @@ set -eu
|
|||
NPROC=$(nproc)
|
||||
|
||||
sudo apt-get install -y --no-install-recommends \
|
||||
libgmock-dev \
|
||||
libgtest-dev \
|
||||
libopus-dev \
|
||||
libsodium-dev \
|
||||
|
|
|
@ -477,14 +477,25 @@ install_module(toxcore DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/tox)
|
|||
#
|
||||
################################################################################
|
||||
|
||||
add_library(test_util STATIC
|
||||
toxcore/DHT_test_util.cc
|
||||
toxcore/DHT_test_util.hh
|
||||
toxcore/crypto_core_test_util.cc
|
||||
toxcore/crypto_core_test_util.hh
|
||||
toxcore/network_test_util.cc
|
||||
toxcore/network_test_util.hh
|
||||
toxcore/test_util.cc
|
||||
toxcore/test_util.hh)
|
||||
|
||||
function(unit_test subdir target)
|
||||
add_executable(unit_${target}_test ${subdir}/${target}_test.cc)
|
||||
target_link_libraries(unit_${target}_test PRIVATE test_util)
|
||||
if(TARGET toxcore_static)
|
||||
target_link_libraries(unit_${target}_test PRIVATE toxcore_static)
|
||||
else()
|
||||
target_link_libraries(unit_${target}_test PRIVATE toxcore_shared)
|
||||
endif()
|
||||
target_link_libraries(unit_${target}_test PRIVATE GTest::GTest GTest::Main)
|
||||
target_link_libraries(unit_${target}_test PRIVATE GTest::gtest GTest::gtest_main GTest::gmock)
|
||||
set_target_properties(unit_${target}_test PROPERTIES COMPILE_FLAGS "${TEST_CXX_FLAGS}")
|
||||
add_test(NAME ${target} COMMAND ${CROSSCOMPILING_EMULATOR} unit_${target}_test)
|
||||
set_property(TEST ${target} PROPERTY ENVIRONMENT "LLVM_PROFILE_FILE=${target}.profraw")
|
||||
|
@ -504,6 +515,7 @@ if(GTEST_FOUND)
|
|||
unit_test(toxcore mem)
|
||||
unit_test(toxcore mono_time)
|
||||
unit_test(toxcore ping_array)
|
||||
unit_test(toxcore test_util)
|
||||
unit_test(toxcore tox)
|
||||
unit_test(toxcore util)
|
||||
endif()
|
||||
|
|
|
@ -15,7 +15,7 @@ CPPFLAGS+=("-Itoxav")
|
|||
CPPFLAGS+=("-Itoxencryptsave")
|
||||
CPPFLAGS+=("-Ithird_party/cmp")
|
||||
|
||||
LDFLAGS=("-lopus" "-lsodium" "-lvpx" "-lpthread" "-lconfig" "-lgtest")
|
||||
LDFLAGS=("-lopus" "-lsodium" "-lvpx" "-lpthread" "-lconfig" "-lgmock" "-lgtest")
|
||||
LDFLAGS+=("-fuse-ld=gold")
|
||||
LDFLAGS+=("-Wl,--detect-odr-violations")
|
||||
LDFLAGS+=("-Wl,--warn-common")
|
||||
|
|
|
@ -10,7 +10,7 @@ run() {
|
|||
"${CPPFLAGS[@]}" \
|
||||
"${LDFLAGS[@]}" \
|
||||
"$@" \
|
||||
-std=c++11 \
|
||||
-std=c++17 \
|
||||
-Werror \
|
||||
-Weverything \
|
||||
-Wno-alloca \
|
||||
|
|
|
@ -9,7 +9,7 @@ run() {
|
|||
clang++ --analyze amalgamation.cc \
|
||||
"${CPPFLAGS[@]}" \
|
||||
"$@" \
|
||||
-std=c++11
|
||||
-std=c++20
|
||||
}
|
||||
|
||||
. other/analysis/variants.sh
|
||||
|
|
|
@ -34,6 +34,8 @@ CPPCHECK_CXX+=("--suppress=AssignmentAddressToInteger")
|
|||
CPPCHECK_CXX+=("--suppress=cstyleCast")
|
||||
# Used in Messenger.c for a static_assert(...)
|
||||
CPPCHECK_CXX+=("--suppress=sizeofFunctionCall")
|
||||
# This is outdated. Range-for is a good choice.
|
||||
CPPCHECK_CXX+=("--suppress=useStlAlgorithm")
|
||||
|
||||
run() {
|
||||
echo "Running cppcheck in variant '$*'"
|
||||
|
|
|
@ -11,7 +11,7 @@ run() {
|
|||
"${CPPFLAGS[@]}" \
|
||||
"${LDFLAGS[@]}" \
|
||||
"$@" \
|
||||
-std=c++11 \
|
||||
-std=c++17 \
|
||||
-fdiagnostics-color=always \
|
||||
-Wall \
|
||||
-Wextra \
|
||||
|
|
|
@ -1 +1 @@
|
|||
870f1e19aa3f3f802c7e53af3848df6a0f7af9ad4c98213aa1578fa325b30fad /usr/local/bin/tox-bootstrapd
|
||||
bc830120a87517f830eb85494b769c523bd1696328938d46e9eac1eefea61d38 /usr/local/bin/tox-bootstrapd
|
||||
|
|
|
@ -7,6 +7,7 @@ RUN apt-get update && \
|
|||
clang \
|
||||
cmake \
|
||||
libconfig-dev \
|
||||
libgmock-dev \
|
||||
libgtest-dev \
|
||||
libopus-dev \
|
||||
libsodium-dev \
|
||||
|
|
|
@ -11,6 +11,7 @@ RUN apt-get update && \
|
|||
git \
|
||||
golang-1.18 \
|
||||
libconfig-dev \
|
||||
libgmock-dev \
|
||||
libgtest-dev \
|
||||
libopus-dev \
|
||||
libsodium-dev \
|
||||
|
@ -25,9 +26,11 @@ RUN apt-get update && \
|
|||
&& apt-get clean \
|
||||
&& rm -rf /var/lib/apt/lists/* \
|
||||
&& pip3 install --no-cache-dir gcovr
|
||||
# strip gtest so it doesn't end up in stack traces. This speeds up the
|
||||
# strip gtest/gmock so it doesn't end up in stack traces. This speeds up the
|
||||
# mallocfail run below by a lot.
|
||||
RUN ["strip", "-g",\
|
||||
"/usr/lib/x86_64-linux-gnu/libgmock.a",\
|
||||
"/usr/lib/x86_64-linux-gnu/libgmock_main.a",\
|
||||
"/usr/lib/x86_64-linux-gnu/libgtest.a",\
|
||||
"/usr/lib/x86_64-linux-gnu/libgtest_main.a"]
|
||||
RUN ["curl", "-s", "https://codecov.io/bash", "-o", "/usr/local/bin/codecov"]
|
||||
|
|
|
@ -5,7 +5,7 @@ ENV LANG=en_US.UTF-8 \
|
|||
LC_CTYPE=en_US.UTF-8 \
|
||||
LC_ALL=en_US.UTF-8
|
||||
|
||||
RUN apk add --no-cache doxygen git graphviz \
|
||||
RUN apk add --no-cache doxygen git graphviz texlive \
|
||||
&& git clone --depth=1 https://github.com/jothepro/doxygen-awesome-css.git /work/doxygen-awesome-css
|
||||
WORKDIR /work
|
||||
COPY . /work/
|
||||
|
|
|
@ -10,3 +10,6 @@ sonar.sources=.
|
|||
|
||||
# Encoding of the source code.
|
||||
sonar.sourceEncoding=UTF-8
|
||||
|
||||
# More precise Python version.
|
||||
sonar.python.version=3.11
|
||||
|
|
|
@ -10,6 +10,23 @@ exports_files(
|
|||
visibility = ["//c-toxcore:__pkg__"],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "test_util",
|
||||
srcs = ["test_util.cc"],
|
||||
hdrs = ["test_util.hh"],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "test_util_test",
|
||||
size = "small",
|
||||
srcs = ["test_util_test.cc"],
|
||||
deps = [
|
||||
":crypto_core_test_util",
|
||||
"@com_google_googletest//:gtest",
|
||||
"@com_google_googletest//:gtest_main",
|
||||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "attributes",
|
||||
hdrs = ["attributes.h"],
|
||||
|
@ -142,6 +159,16 @@ cc_library(
|
|||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "crypto_core_test_util",
|
||||
srcs = ["crypto_core_test_util.cc"],
|
||||
hdrs = ["crypto_core_test_util.hh"],
|
||||
deps = [
|
||||
":crypto_core",
|
||||
":test_util",
|
||||
],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "crypto_core_test",
|
||||
size = "small",
|
||||
|
@ -149,6 +176,7 @@ cc_test(
|
|||
flaky = True,
|
||||
deps = [
|
||||
":crypto_core",
|
||||
":crypto_core_test_util",
|
||||
":util",
|
||||
"@com_google_googletest//:gtest",
|
||||
"@com_google_googletest//:gtest_main",
|
||||
|
@ -261,6 +289,16 @@ cc_library(
|
|||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "network_test_util",
|
||||
srcs = ["network_test_util.cc"],
|
||||
hdrs = ["network_test_util.hh"],
|
||||
deps = [
|
||||
":crypto_core",
|
||||
":network",
|
||||
],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "network_test",
|
||||
size = "small",
|
||||
|
@ -357,13 +395,28 @@ cc_library(
|
|||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "DHT_test_util",
|
||||
srcs = ["DHT_test_util.cc"],
|
||||
hdrs = ["DHT_test_util.hh"],
|
||||
deps = [
|
||||
":DHT",
|
||||
":crypto_core",
|
||||
":crypto_core_test_util",
|
||||
":network_test_util",
|
||||
":test_util",
|
||||
],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "DHT_test",
|
||||
size = "small",
|
||||
srcs = ["DHT_test.cc"],
|
||||
deps = [
|
||||
":DHT",
|
||||
":DHT_test_util",
|
||||
":crypto_core",
|
||||
":network_test_util",
|
||||
"@com_google_googletest//:gtest",
|
||||
"@com_google_googletest//:gtest_main",
|
||||
],
|
||||
|
|
|
@ -750,16 +750,21 @@ static bool client_or_ip_port_in_list(const Logger *log, const Mono_Time *mono_t
|
|||
return true;
|
||||
}
|
||||
|
||||
bool add_to_list(Node_format *nodes_list, uint32_t length, const uint8_t *pk, const IP_Port *ip_port,
|
||||
const uint8_t *cmp_pk)
|
||||
bool add_to_list(
|
||||
Node_format *nodes_list, uint32_t length, const uint8_t pk[CRYPTO_PUBLIC_KEY_SIZE],
|
||||
const IP_Port *ip_port, const uint8_t cmp_pk[CRYPTO_PUBLIC_KEY_SIZE])
|
||||
{
|
||||
for (uint32_t i = 0; i < length; ++i) {
|
||||
if (id_closest(cmp_pk, nodes_list[i].public_key, pk) == 2) {
|
||||
Node_format *node = &nodes_list[i];
|
||||
|
||||
if (id_closest(cmp_pk, node->public_key, pk) == 2) {
|
||||
uint8_t pk_bak[CRYPTO_PUBLIC_KEY_SIZE];
|
||||
memcpy(pk_bak, nodes_list[i].public_key, CRYPTO_PUBLIC_KEY_SIZE);
|
||||
const IP_Port ip_port_bak = nodes_list[i].ip_port;
|
||||
memcpy(nodes_list[i].public_key, pk, CRYPTO_PUBLIC_KEY_SIZE);
|
||||
nodes_list[i].ip_port = *ip_port;
|
||||
memcpy(pk_bak, node->public_key, CRYPTO_PUBLIC_KEY_SIZE);
|
||||
|
||||
const IP_Port ip_port_bak = node->ip_port;
|
||||
memcpy(node->public_key, pk, CRYPTO_PUBLIC_KEY_SIZE);
|
||||
|
||||
node->ip_port = *ip_port;
|
||||
|
||||
if (i != length - 1) {
|
||||
add_to_list(nodes_list, length, pk_bak, &ip_port_bak, cmp_pk);
|
||||
|
|
|
@ -370,7 +370,8 @@ unsigned int bit_by_bit_cmp(const uint8_t *pk1, const uint8_t *pk2);
|
|||
*/
|
||||
non_null()
|
||||
bool add_to_list(
|
||||
Node_format *nodes_list, uint32_t length, const uint8_t *pk, const IP_Port *ip_port, const uint8_t *cmp_pk);
|
||||
Node_format *nodes_list, uint32_t length, const uint8_t pk[CRYPTO_PUBLIC_KEY_SIZE],
|
||||
const IP_Port *ip_port, const uint8_t cmp_pk[CRYPTO_PUBLIC_KEY_SIZE]);
|
||||
|
||||
/** Return 1 if node can be added to close list, 0 if it can't. */
|
||||
non_null()
|
||||
|
|
|
@ -1,15 +1,26 @@
|
|||
#include "DHT.h"
|
||||
|
||||
#include <gmock/gmock.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cstring>
|
||||
#include <random>
|
||||
|
||||
#include "DHT_test_util.hh"
|
||||
#include "crypto_core.h"
|
||||
#include "crypto_core_test_util.hh"
|
||||
#include "network_test_util.hh"
|
||||
|
||||
namespace {
|
||||
|
||||
using PublicKey = std::array<uint8_t, CRYPTO_PUBLIC_KEY_SIZE>;
|
||||
using ::testing::Each;
|
||||
using ::testing::ElementsAre;
|
||||
using ::testing::Eq;
|
||||
using ::testing::PrintToString;
|
||||
using ::testing::UnorderedElementsAre;
|
||||
|
||||
using SecretKey = std::array<uint8_t, CRYPTO_SECRET_KEY_SIZE>;
|
||||
|
||||
struct KeyPair {
|
||||
|
@ -19,72 +30,66 @@ struct KeyPair {
|
|||
explicit KeyPair(const Random *rng) { crypto_new_keypair(rng, pk.data(), sk.data()); }
|
||||
};
|
||||
|
||||
template <typename T, size_t N>
|
||||
std::array<T, N> to_array(T const (&arr)[N])
|
||||
TEST(IdClosest, KeyIsClosestToItself)
|
||||
{
|
||||
std::array<T, N> stdarr;
|
||||
std::copy(arr, arr + N, stdarr.begin());
|
||||
return stdarr;
|
||||
}
|
||||
Test_Random rng;
|
||||
|
||||
PublicKey random_pk(const Random *rng)
|
||||
{
|
||||
PublicKey pk;
|
||||
random_bytes(rng, pk.data(), pk.size());
|
||||
return pk;
|
||||
PublicKey pk0 = random_pk(rng);
|
||||
PublicKey pk1;
|
||||
do {
|
||||
// Get a random key that's not the same as pk0.
|
||||
pk1 = random_pk(rng);
|
||||
} while (pk0 == pk1);
|
||||
|
||||
EXPECT_EQ(id_closest(pk0.data(), pk0.data(), pk1.data()), 1);
|
||||
}
|
||||
|
||||
TEST(IdClosest, IdenticalKeysAreSameDistance)
|
||||
{
|
||||
const Random *rng = system_random();
|
||||
ASSERT_NE(rng, nullptr);
|
||||
Test_Random rng;
|
||||
|
||||
PublicKey pk0 = random_pk(rng);
|
||||
PublicKey pk1 = random_pk(rng);
|
||||
PublicKey pk2 = pk1;
|
||||
|
||||
EXPECT_EQ(id_closest(pk0.data(), pk1.data(), pk2.data()), 0);
|
||||
EXPECT_EQ(id_closest(pk0.data(), pk1.data(), pk1.data()), 0);
|
||||
}
|
||||
|
||||
TEST(IdClosest, DistanceIsCommutative)
|
||||
{
|
||||
const Random *rng = system_random();
|
||||
ASSERT_NE(rng, nullptr);
|
||||
Test_Random rng;
|
||||
|
||||
for (uint32_t i = 0; i < 100; ++i) {
|
||||
PublicKey pk0 = random_pk(rng);
|
||||
PublicKey pk1 = random_pk(rng);
|
||||
PublicKey pk2 = random_pk(rng);
|
||||
PublicKey pk0 = random_pk(rng);
|
||||
PublicKey pk1 = random_pk(rng);
|
||||
PublicKey pk2 = random_pk(rng);
|
||||
|
||||
ASSERT_NE(pk1, pk2); // RNG can't produce the same random key twice
|
||||
ASSERT_NE(pk1, pk2); // RNG can't produce the same random key twice
|
||||
|
||||
// Two non-equal keys can't have the same distance from any given key.
|
||||
EXPECT_NE(id_closest(pk0.data(), pk1.data(), pk2.data()), 0);
|
||||
// Two non-equal keys can't have the same distance from any given key.
|
||||
EXPECT_NE(id_closest(pk0.data(), pk1.data(), pk2.data()), 0);
|
||||
|
||||
if (id_closest(pk0.data(), pk1.data(), pk2.data()) == 1) {
|
||||
EXPECT_EQ(id_closest(pk0.data(), pk2.data(), pk1.data()), 2);
|
||||
}
|
||||
if (id_closest(pk0.data(), pk1.data(), pk2.data()) == 1) {
|
||||
EXPECT_EQ(id_closest(pk0.data(), pk2.data(), pk1.data()), 2);
|
||||
}
|
||||
|
||||
if (id_closest(pk0.data(), pk1.data(), pk2.data()) == 2) {
|
||||
EXPECT_EQ(id_closest(pk0.data(), pk2.data(), pk1.data()), 1);
|
||||
}
|
||||
if (id_closest(pk0.data(), pk1.data(), pk2.data()) == 2) {
|
||||
EXPECT_EQ(id_closest(pk0.data(), pk2.data(), pk1.data()), 1);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(IdClosest, SmallXorDistanceIsCloser)
|
||||
{
|
||||
PublicKey const pk0 = {{0xaa}};
|
||||
PublicKey const pk1 = {{0xa0}};
|
||||
PublicKey const pk2 = {{0x0a}};
|
||||
PublicKey const pk0 = {0xaa};
|
||||
PublicKey const pk1 = {0xa0};
|
||||
PublicKey const pk2 = {0x0a};
|
||||
|
||||
EXPECT_EQ(id_closest(pk0.data(), pk1.data(), pk2.data()), 1);
|
||||
}
|
||||
|
||||
TEST(IdClosest, DistinctKeysCannotHaveTheSameDistance)
|
||||
{
|
||||
PublicKey const pk0 = {{0x06}};
|
||||
PublicKey const pk1 = {{0x00}};
|
||||
PublicKey pk2 = {{0x00}};
|
||||
PublicKey const pk0 = {0x06};
|
||||
PublicKey const pk1 = {0x00};
|
||||
PublicKey pk2 = {0x00};
|
||||
|
||||
for (uint8_t i = 1; i < 0xff; ++i) {
|
||||
pk2[0] = i;
|
||||
|
@ -94,14 +99,14 @@ TEST(IdClosest, DistinctKeysCannotHaveTheSameDistance)
|
|||
|
||||
TEST(AddToList, OverridesKeysWithCloserKeys)
|
||||
{
|
||||
PublicKey const self_pk = {{0xaa}};
|
||||
PublicKey const self_pk = {0xaa};
|
||||
PublicKey const keys[] = {
|
||||
{{0xa0}}, // closest
|
||||
{{0x0a}}, //
|
||||
{{0x0b}}, //
|
||||
{{0x0c}}, //
|
||||
{{0x0d}}, //
|
||||
{{0xa1}}, // closer than the 4 keys above
|
||||
{0xa0}, // closest
|
||||
{0x0a}, //
|
||||
{0x0b}, //
|
||||
{0x0c}, //
|
||||
{0x0d}, //
|
||||
{0xa1}, // closer than the 4 keys above
|
||||
};
|
||||
|
||||
std::array<Node_format, 4> nodes{};
|
||||
|
@ -128,10 +133,143 @@ TEST(AddToList, OverridesKeysWithCloserKeys)
|
|||
EXPECT_EQ(to_array(nodes[3].public_key), keys[2]);
|
||||
}
|
||||
|
||||
Node_format fill(Node_format v, PublicKey const &pk, IP_Port const &ip_port)
|
||||
{
|
||||
std::copy(pk.begin(), pk.end(), v.public_key);
|
||||
v.ip_port = ip_port;
|
||||
return v;
|
||||
}
|
||||
|
||||
TEST(AddToList, AddsFirstKeysInOrder)
|
||||
{
|
||||
Test_Random rng;
|
||||
|
||||
// Make cmp_key the furthest away from 00000... as possible, so all initial inserts succeed.
|
||||
PublicKey const cmp_pk{0xff, 0xff, 0xff, 0xff};
|
||||
|
||||
// Generate a bunch of other keys, sorted by distance from cmp_pk.
|
||||
auto const keys
|
||||
= sorted(array_of<20>(random_pk, rng), [&cmp_pk](auto const &pk1, auto const &pk2) {
|
||||
return id_closest(cmp_pk.data(), pk1.data(), pk2.data()) == 1;
|
||||
});
|
||||
auto const ips = array_of<20>(increasing_ip_port(0, rng));
|
||||
|
||||
std::vector<Node_format> nodes(4);
|
||||
|
||||
// Add a bunch of nodes.
|
||||
ASSERT_TRUE(add_to_list(nodes.data(), nodes.size(), keys[2].data(), &ips[2], cmp_pk.data()))
|
||||
<< "failed to insert\n"
|
||||
<< " cmp_pk = " << cmp_pk << "\n"
|
||||
<< " pk = " << keys[2] << "\n"
|
||||
<< " nodes_list = " << PrintToString(nodes);
|
||||
ASSERT_TRUE(add_to_list(nodes.data(), nodes.size(), keys[5].data(), &ips[5], cmp_pk.data()))
|
||||
<< "failed to insert\n"
|
||||
<< " cmp_pk = " << cmp_pk << "\n"
|
||||
<< " pk = " << keys[5] << "\n"
|
||||
<< " nodes_list = " << PrintToString(nodes);
|
||||
ASSERT_TRUE(add_to_list(nodes.data(), nodes.size(), keys[7].data(), &ips[7], cmp_pk.data()))
|
||||
<< "failed to insert\n"
|
||||
<< " cmp_pk = " << cmp_pk << "\n"
|
||||
<< " pk = " << keys[7] << "\n"
|
||||
<< " nodes_list = " << PrintToString(nodes);
|
||||
ASSERT_TRUE(add_to_list(nodes.data(), nodes.size(), keys[9].data(), &ips[9], cmp_pk.data()))
|
||||
<< "failed to insert\n"
|
||||
<< " cmp_pk = " << cmp_pk << "\n"
|
||||
<< " pk = " << keys[9] << "\n"
|
||||
<< " nodes_list = " << PrintToString(nodes);
|
||||
|
||||
// They should all appear in order.
|
||||
EXPECT_THAT(nodes,
|
||||
ElementsAre( //
|
||||
fill(Node_format{}, keys[2], ips[2]), //
|
||||
fill(Node_format{}, keys[5], ips[5]), //
|
||||
fill(Node_format{}, keys[7], ips[7]), //
|
||||
fill(Node_format{}, keys[9], ips[9])));
|
||||
|
||||
// Adding another node that's further away will not happen.
|
||||
ASSERT_FALSE(add_to_list(nodes.data(), nodes.size(), keys[10].data(), &ips[10], cmp_pk.data()))
|
||||
<< "incorrectly inserted\n"
|
||||
<< " cmp_pk = " << cmp_pk << "\n"
|
||||
<< " pk = " << keys[10] << "\n"
|
||||
<< " nodes_list = " << PrintToString(nodes);
|
||||
|
||||
// Now shuffle each time we add a node, which should work fine.
|
||||
std::mt19937 mt_rng;
|
||||
|
||||
// Adding one that's closer will happen.
|
||||
std::shuffle(nodes.begin(), nodes.end(), mt_rng);
|
||||
ASSERT_TRUE(add_to_list(nodes.data(), nodes.size(), keys[8].data(), &ips[8], cmp_pk.data()))
|
||||
<< "failed to insert\n"
|
||||
<< " cmp_pk = " << cmp_pk << "\n"
|
||||
<< " pk = " << keys[8] << "\n"
|
||||
<< " nodes_list = " << PrintToString(nodes);
|
||||
|
||||
EXPECT_THAT(nodes,
|
||||
UnorderedElementsAre( //
|
||||
fill(Node_format{}, keys[2], ips[2]), //
|
||||
fill(Node_format{}, keys[5], ips[5]), //
|
||||
fill(Node_format{}, keys[7], ips[7]), //
|
||||
fill(Node_format{}, keys[8], ips[8])));
|
||||
|
||||
// Adding one that's closer than almost all of them will happen.
|
||||
std::shuffle(nodes.begin(), nodes.end(), mt_rng);
|
||||
ASSERT_TRUE(add_to_list(nodes.data(), nodes.size(), keys[4].data(), &ips[4], cmp_pk.data()))
|
||||
<< "failed to insert\n"
|
||||
<< " cmp_pk = " << cmp_pk << "\n"
|
||||
<< " pk = " << keys[4] << "\n"
|
||||
<< " nodes_list = " << PrintToString(nodes);
|
||||
|
||||
EXPECT_THAT(nodes,
|
||||
UnorderedElementsAre( //
|
||||
fill(Node_format{}, keys[2], ips[2]), //
|
||||
fill(Node_format{}, keys[4], ips[4]), //
|
||||
fill(Node_format{}, keys[5], ips[5]), //
|
||||
fill(Node_format{}, keys[7], ips[7])));
|
||||
|
||||
// Adding one that's closer than all of them will happen.
|
||||
std::shuffle(nodes.begin(), nodes.end(), mt_rng);
|
||||
ASSERT_TRUE(add_to_list(nodes.data(), nodes.size(), keys[1].data(), &ips[1], cmp_pk.data()))
|
||||
<< "failed to insert\n"
|
||||
<< " cmp_pk = " << cmp_pk << "\n"
|
||||
<< " pk = " << keys[1] << "\n"
|
||||
<< " nodes_list = " << PrintToString(nodes);
|
||||
|
||||
EXPECT_THAT(nodes,
|
||||
UnorderedElementsAre( //
|
||||
fill(Node_format{}, keys[1], ips[1]), //
|
||||
fill(Node_format{}, keys[2], ips[2]), //
|
||||
fill(Node_format{}, keys[4], ips[4]), //
|
||||
fill(Node_format{}, keys[5], ips[5])));
|
||||
}
|
||||
|
||||
TEST(AddToList, KeepsKeysInOrder)
|
||||
{
|
||||
Test_Random rng;
|
||||
|
||||
// Any random cmp_pk should work, as well as the smallest or (approximately) largest pk.
|
||||
for (PublicKey const cmp_pk : {random_pk(rng), PublicKey{0x00}, PublicKey{0xff, 0xff}}) {
|
||||
auto const by_distance = [&cmp_pk](auto const &node1, auto const &node2) {
|
||||
return id_closest(cmp_pk.data(), node1.public_key, node2.public_key) == 1;
|
||||
};
|
||||
|
||||
// Generate a bunch of other keys, not sorted.
|
||||
auto const nodes = vector_of(16, random_node_format, rng);
|
||||
|
||||
std::vector<Node_format> node_list(4);
|
||||
|
||||
// Add all of them.
|
||||
for (Node_format const &node : nodes) {
|
||||
add_to_list(
|
||||
node_list.data(), node_list.size(), node.public_key, &node.ip_port, cmp_pk.data());
|
||||
// Nodes should always be sorted.
|
||||
EXPECT_THAT(node_list, Eq(sorted(node_list, by_distance)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Request, CreateAndParse)
|
||||
{
|
||||
const Random *rng = system_random();
|
||||
ASSERT_NE(rng, nullptr);
|
||||
Test_Random rng;
|
||||
|
||||
// Peers.
|
||||
const KeyPair sender(rng);
|
||||
|
@ -187,7 +325,7 @@ TEST(Request, CreateAndParse)
|
|||
|
||||
TEST(AnnounceNodes, SetAndTest)
|
||||
{
|
||||
const Random *rng = system_random();
|
||||
Test_Random rng;
|
||||
const Network *ns = system_network();
|
||||
const Memory *mem = system_memory();
|
||||
|
||||
|
@ -202,14 +340,14 @@ TEST(AnnounceNodes, SetAndTest)
|
|||
|
||||
uint8_t pk_data[CRYPTO_PUBLIC_KEY_SIZE];
|
||||
memcpy(pk_data, dht_get_self_public_key(dht), sizeof(pk_data));
|
||||
PublicKey self_pk = to_array(pk_data);
|
||||
PublicKey self_pk(to_array(pk_data));
|
||||
|
||||
PublicKey pk1 = random_pk(rng);
|
||||
ASSERT_NE(pk1, self_pk);
|
||||
|
||||
// Test with maximally close key to self
|
||||
pk_data[CRYPTO_PUBLIC_KEY_SIZE - 1] = ~pk_data[CRYPTO_PUBLIC_KEY_SIZE - 1];
|
||||
PublicKey pk2 = to_array(pk_data);
|
||||
PublicKey pk2(to_array(pk_data));
|
||||
ASSERT_NE(pk2, pk1);
|
||||
|
||||
IP_Port ip_port = {0};
|
||||
|
|
28
toxcore/DHT_test_util.cc
Normal file
28
toxcore/DHT_test_util.cc
Normal file
|
@ -0,0 +1,28 @@
|
|||
#include "DHT_test_util.hh"
|
||||
|
||||
#include <cstring>
|
||||
#include <iomanip>
|
||||
|
||||
#include "crypto_core_test_util.hh"
|
||||
#include "network_test_util.hh"
|
||||
|
||||
Node_format random_node_format(const Random *rng)
|
||||
{
|
||||
Node_format node;
|
||||
auto const pk = random_pk(rng);
|
||||
std::copy(pk.begin(), pk.end(), node.public_key);
|
||||
node.ip_port = random_ip_port(rng);
|
||||
return node;
|
||||
}
|
||||
|
||||
bool operator==(Node_format const &a, Node_format const &b)
|
||||
{
|
||||
return std::memcmp(&a, &b, sizeof(Node_format)) == 0;
|
||||
}
|
||||
|
||||
std::ostream &operator<<(std::ostream &out, Node_format const &v)
|
||||
{
|
||||
return out << "\n Node_format{\n"
|
||||
<< " public_key = " << PublicKey(v.public_key) << ",\n"
|
||||
<< " ip_port = " << v.ip_port << " }";
|
||||
}
|
14
toxcore/DHT_test_util.hh
Normal file
14
toxcore/DHT_test_util.hh
Normal file
|
@ -0,0 +1,14 @@
|
|||
#ifndef C_TOXCORE_TOXCORE_DHT_TEST_UTIL_H
|
||||
#define C_TOXCORE_TOXCORE_DHT_TEST_UTIL_H
|
||||
|
||||
#include <iosfwd>
|
||||
|
||||
#include "DHT.h"
|
||||
|
||||
bool operator==(Node_format const &a, Node_format const &b);
|
||||
|
||||
std::ostream &operator<<(std::ostream &out, Node_format const &v);
|
||||
|
||||
Node_format random_node_format(const Random *rng);
|
||||
|
||||
#endif // C_TOXCORE_TOXCORE_DHT_TEST_UTIL_H
|
|
@ -6,13 +6,13 @@
|
|||
#include <array>
|
||||
#include <vector>
|
||||
|
||||
#include "crypto_core_test_util.hh"
|
||||
#include "util.h"
|
||||
|
||||
namespace {
|
||||
|
||||
using HmacKey = std::array<uint8_t, CRYPTO_HMAC_KEY_SIZE>;
|
||||
using Hmac = std::array<uint8_t, CRYPTO_HMAC_SIZE>;
|
||||
using PublicKey = std::array<uint8_t, CRYPTO_PUBLIC_KEY_SIZE>;
|
||||
using SecretKey = std::array<uint8_t, CRYPTO_SECRET_KEY_SIZE>;
|
||||
using ExtPublicKey = std::array<uint8_t, EXT_PUBLIC_KEY_SIZE>;
|
||||
using ExtSecretKey = std::array<uint8_t, EXT_SECRET_KEY_SIZE>;
|
||||
|
@ -21,8 +21,7 @@ using Nonce = std::array<uint8_t, CRYPTO_NONCE_SIZE>;
|
|||
|
||||
TEST(CryptoCore, EncryptLargeData)
|
||||
{
|
||||
const Random *rng = system_random();
|
||||
ASSERT_NE(rng, nullptr);
|
||||
Test_Random rng;
|
||||
|
||||
Nonce nonce{};
|
||||
PublicKey pk;
|
||||
|
@ -71,8 +70,7 @@ TEST(CryptoCore, IncrementNonceNumber)
|
|||
|
||||
TEST(CryptoCore, Signatures)
|
||||
{
|
||||
const Random *rng = system_random();
|
||||
ASSERT_NE(rng, nullptr);
|
||||
Test_Random rng;
|
||||
|
||||
ExtPublicKey pk;
|
||||
ExtSecretKey sk;
|
||||
|
@ -96,8 +94,7 @@ TEST(CryptoCore, Signatures)
|
|||
|
||||
TEST(CryptoCore, Hmac)
|
||||
{
|
||||
const Random *rng = system_random();
|
||||
ASSERT_NE(rng, nullptr);
|
||||
Test_Random rng;
|
||||
|
||||
HmacKey sk;
|
||||
new_hmac_key(rng, sk.data());
|
||||
|
|
46
toxcore/crypto_core_test_util.cc
Normal file
46
toxcore/crypto_core_test_util.cc
Normal file
|
@ -0,0 +1,46 @@
|
|||
#include "crypto_core_test_util.hh"
|
||||
|
||||
#include <cstring>
|
||||
#include <iomanip>
|
||||
|
||||
PublicKey random_pk(const Random *rng)
|
||||
{
|
||||
PublicKey pk;
|
||||
random_bytes(rng, pk.data(), pk.size());
|
||||
return pk;
|
||||
}
|
||||
|
||||
std::ostream &operator<<(std::ostream &out, PublicKey const &pk)
|
||||
{
|
||||
out << '"';
|
||||
for (uint8_t byte : pk) {
|
||||
out << std::setw(2) << std::setfill('0') << std::hex << uint32_t(byte);
|
||||
}
|
||||
out << '"';
|
||||
return out;
|
||||
}
|
||||
|
||||
static void test_random_bytes(void *obj, uint8_t *bytes, size_t length)
|
||||
{
|
||||
Test_Random *self = static_cast<Test_Random *>(obj);
|
||||
std::generate(bytes, &bytes[length], std::ref(self->lcg));
|
||||
}
|
||||
|
||||
static uint32_t test_random_uniform(void *obj, uint32_t upper_bound)
|
||||
{
|
||||
Test_Random *self = static_cast<Test_Random *>(obj);
|
||||
std::uniform_int_distribution<uint32_t> distrib(0, upper_bound);
|
||||
return distrib(self->lcg);
|
||||
}
|
||||
|
||||
Random_Funcs const Test_Random::vtable = {
|
||||
test_random_bytes,
|
||||
test_random_uniform,
|
||||
};
|
||||
|
||||
Test_Random::Test_Random()
|
||||
: self{&vtable, this}
|
||||
{
|
||||
}
|
||||
|
||||
Test_Random::operator Random const *() const { return &self; }
|
75
toxcore/crypto_core_test_util.hh
Normal file
75
toxcore/crypto_core_test_util.hh
Normal file
|
@ -0,0 +1,75 @@
|
|||
#ifndef C_TOXCORE_TOXCORE_CRYPTO_CORE_TEST_UTIL_H
|
||||
#define C_TOXCORE_TOXCORE_CRYPTO_CORE_TEST_UTIL_H
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <iosfwd>
|
||||
#include <random>
|
||||
|
||||
#include "crypto_core.h"
|
||||
#include "test_util.hh"
|
||||
|
||||
/**
|
||||
* A very simple, fast, and deterministic PRNG just for testing.
|
||||
*
|
||||
* We generally don't want to use system_random(), since it's a
|
||||
* cryptographically secure PRNG and we don't need that in unit tests.
|
||||
*/
|
||||
class Test_Random {
|
||||
static Random_Funcs const vtable;
|
||||
Random const self;
|
||||
|
||||
public:
|
||||
Test_Random();
|
||||
operator Random const *() const;
|
||||
|
||||
std::minstd_rand lcg;
|
||||
};
|
||||
|
||||
struct PublicKey : private std::array<uint8_t, CRYPTO_PUBLIC_KEY_SIZE> {
|
||||
using Base = std::array<uint8_t, CRYPTO_PUBLIC_KEY_SIZE>;
|
||||
|
||||
using Base::begin;
|
||||
using Base::data;
|
||||
using Base::end;
|
||||
using Base::size;
|
||||
using Base::operator[];
|
||||
|
||||
PublicKey() = default;
|
||||
explicit PublicKey(uint8_t const (&arr)[CRYPTO_PUBLIC_KEY_SIZE])
|
||||
: PublicKey(to_array(arr))
|
||||
{
|
||||
}
|
||||
explicit PublicKey(std::array<uint8_t, CRYPTO_PUBLIC_KEY_SIZE> const &arr)
|
||||
{
|
||||
std::copy(arr.begin(), arr.end(), begin());
|
||||
}
|
||||
|
||||
PublicKey(std::initializer_list<uint8_t> const &arr)
|
||||
{
|
||||
std::copy(arr.begin(), arr.end(), begin());
|
||||
}
|
||||
|
||||
Base const &base() const { return *this; }
|
||||
};
|
||||
|
||||
inline bool operator!=(PublicKey const &pk1, PublicKey const &pk2)
|
||||
{
|
||||
return pk1.base() != pk2.base();
|
||||
}
|
||||
|
||||
inline bool operator==(PublicKey const &pk1, PublicKey const &pk2)
|
||||
{
|
||||
return pk1.base() == pk2.base();
|
||||
}
|
||||
|
||||
inline bool operator==(PublicKey::Base const &pk1, PublicKey const &pk2)
|
||||
{
|
||||
return pk1 == pk2.base();
|
||||
}
|
||||
|
||||
std::ostream &operator<<(std::ostream &out, PublicKey const &pk);
|
||||
|
||||
PublicKey random_pk(const Random *rng);
|
||||
|
||||
#endif // C_TOXCORE_TOXCORE_CRYPTO_CORE_TEST_UTIL_H
|
42
toxcore/network_test_util.cc
Normal file
42
toxcore/network_test_util.cc
Normal file
|
@ -0,0 +1,42 @@
|
|||
#include "network_test_util.hh"
|
||||
|
||||
#include <iomanip>
|
||||
|
||||
IP_Port increasing_ip_port::operator()()
|
||||
{
|
||||
IP_Port ip_port;
|
||||
ip_port.ip.family = net_family_ipv4();
|
||||
ip_port.ip.ip.v4.uint8[0] = 192;
|
||||
ip_port.ip.ip.v4.uint8[1] = 168;
|
||||
ip_port.ip.ip.v4.uint8[2] = 0;
|
||||
ip_port.ip.ip.v4.uint8[3] = start_;
|
||||
ip_port.port = random_u16(rng_);
|
||||
++start_;
|
||||
return ip_port;
|
||||
}
|
||||
|
||||
IP_Port random_ip_port(const Random *rng)
|
||||
{
|
||||
IP_Port ip_port;
|
||||
ip_port.ip.family = net_family_ipv4();
|
||||
ip_port.ip.ip.v4.uint8[0] = 192;
|
||||
ip_port.ip.ip.v4.uint8[1] = 168;
|
||||
ip_port.ip.ip.v4.uint8[2] = 0;
|
||||
ip_port.ip.ip.v4.uint8[3] = random_u08(rng);
|
||||
ip_port.port = random_u16(rng);
|
||||
return ip_port;
|
||||
}
|
||||
|
||||
std::ostream &operator<<(std::ostream &out, IP const &v)
|
||||
{
|
||||
Ip_Ntoa ip_str;
|
||||
out << '"' << net_ip_ntoa(&v, &ip_str) << '"';
|
||||
return out;
|
||||
}
|
||||
|
||||
std::ostream &operator<<(std::ostream &out, IP_Port const &v)
|
||||
{
|
||||
return out << "IP_Port{\n"
|
||||
<< " ip = " << v.ip << ",\n"
|
||||
<< " port = " << std::dec << std::setw(0) << v.port << " }";
|
||||
}
|
28
toxcore/network_test_util.hh
Normal file
28
toxcore/network_test_util.hh
Normal file
|
@ -0,0 +1,28 @@
|
|||
#ifndef C_TOXCORE_TOXCORE_NETWORK_TEST_UTIL_H
|
||||
#define C_TOXCORE_TOXCORE_NETWORK_TEST_UTIL_H
|
||||
|
||||
#include <ostream>
|
||||
|
||||
#include "crypto_core.h"
|
||||
#include "network.h"
|
||||
|
||||
IP_Port random_ip_port(const Random *rng);
|
||||
|
||||
class increasing_ip_port {
|
||||
uint8_t start_;
|
||||
const Random *rng_;
|
||||
|
||||
public:
|
||||
explicit increasing_ip_port(uint8_t start, const Random *rng)
|
||||
: start_(start)
|
||||
, rng_(rng)
|
||||
{
|
||||
}
|
||||
|
||||
IP_Port operator()();
|
||||
};
|
||||
|
||||
std::ostream &operator<<(std::ostream &out, IP const &v);
|
||||
std::ostream &operator<<(std::ostream &out, IP_Port const &v);
|
||||
|
||||
#endif // C_TOXCORE_TOXCORE_NETWORK_TEST_UTIL_H
|
1
toxcore/test_util.cc
Normal file
1
toxcore/test_util.cc
Normal file
|
@ -0,0 +1 @@
|
|||
#include "test_util.hh"
|
43
toxcore/test_util.hh
Normal file
43
toxcore/test_util.hh
Normal file
|
@ -0,0 +1,43 @@
|
|||
#ifndef C_TOXCORE_TOXCORE_TEST_UTIL_H
|
||||
#define C_TOXCORE_TOXCORE_TEST_UTIL_H
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <vector>
|
||||
|
||||
template <typename T, std::size_t N>
|
||||
std::array<T, N> to_array(T const (&arr)[N])
|
||||
{
|
||||
std::array<T, N> stdarr;
|
||||
std::copy(arr, arr + N, stdarr.begin());
|
||||
return stdarr;
|
||||
}
|
||||
|
||||
template <std::size_t N, typename T, typename... Args>
|
||||
auto array_of(T &&make, Args... args)
|
||||
{
|
||||
std::array<typename std::result_of<T(Args...)>::type, N> arr;
|
||||
for (auto &elem : arr) {
|
||||
elem = make(args...);
|
||||
}
|
||||
return arr;
|
||||
}
|
||||
|
||||
template <typename T, typename... Args>
|
||||
auto vector_of(std::size_t n, T &&make, Args... args)
|
||||
{
|
||||
std::vector<typename std::result_of<T(Args...)>::type> vec;
|
||||
for (std::size_t i = 0; i < n; ++i) {
|
||||
vec.push_back(make(args...));
|
||||
}
|
||||
return vec;
|
||||
}
|
||||
|
||||
template <typename Container, typename Less>
|
||||
Container sorted(Container arr, Less less)
|
||||
{
|
||||
std::sort(arr.begin(), arr.end(), less);
|
||||
return arr;
|
||||
}
|
||||
|
||||
#endif // C_TOXCORE_TOXCORE_TEST_UTIL_H
|
64
toxcore/test_util_test.cc
Normal file
64
toxcore/test_util_test.cc
Normal file
|
@ -0,0 +1,64 @@
|
|||
#include "test_util.hh"
|
||||
|
||||
#include <gmock/gmock.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <array>
|
||||
|
||||
#include "crypto_core_test_util.hh"
|
||||
|
||||
namespace {
|
||||
|
||||
using ::testing::Each;
|
||||
using ::testing::Eq;
|
||||
|
||||
TEST(CryptoCoreTestUtil, RandomBytesDoesNotTouchZeroSizeArray)
|
||||
{
|
||||
const Test_Random rng;
|
||||
std::array<uint8_t, 32> bytes{};
|
||||
for (uint32_t i = 0; i < 100; ++i) {
|
||||
random_bytes(rng, bytes.data(), 0);
|
||||
ASSERT_THAT(bytes, Each(Eq(0x00)));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(CryptoCoreTestUtil, RandomBytesFillsEntireArray)
|
||||
{
|
||||
const Test_Random rng;
|
||||
std::array<uint8_t, 32> bytes{};
|
||||
|
||||
for (uint32_t size = 1; size < bytes.size(); ++size) {
|
||||
bool const success = [&]() {
|
||||
// Try a few times. There ought to be a non-zero byte in our randomness at
|
||||
// some point.
|
||||
for (uint32_t i = 0; i < 100; ++i) {
|
||||
random_bytes(rng, bytes.data(), bytes.size());
|
||||
if (bytes[size - 1] != 0x00) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}();
|
||||
ASSERT_TRUE(success);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(CryptoCoreTestUtil, RandomBytesDoesNotBufferOverrun)
|
||||
{
|
||||
const Test_Random rng;
|
||||
|
||||
std::array<uint8_t, 32> bytes{};
|
||||
|
||||
// Try a few times. It should never overrun.
|
||||
for (uint32_t i = 0; i < 100; ++i) {
|
||||
for (uint32_t diff = 1; diff < sizeof(uint64_t); ++diff) {
|
||||
bytes = {};
|
||||
random_bytes(rng, bytes.data(), bytes.size() - diff);
|
||||
// All bytes not in the range we want to write should be 0.
|
||||
ASSERT_THAT(std::vector<uint8_t>(bytes.begin() + (bytes.size() - diff), bytes.end()),
|
||||
Each(Eq(0x00)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
Loading…
Reference in New Issue
Block a user