diff --git a/src/utils/utils.hpp b/src/utils/utils.hpp index a9cee0a..bc26764 100644 --- a/src/utils/utils.hpp +++ b/src/utils/utils.hpp @@ -142,11 +142,6 @@ namespace detail { constexpr unsigned n_digits(unsigned value) noexcept { return value < 10 ? 1 : 1 + n_digits(value / 10); } - static_assert(n_digits(1) == 1, "n_digits utility producing the wrong result"); - static_assert(n_digits(9) == 1, "n_digits utility producing the wrong result"); - static_assert(n_digits(10) == 2, "n_digits utility producing the wrong result"); - static_assert(n_digits(11) == 2, "n_digits utility producing the wrong result"); - static_assert(n_digits(1024) == 4, "n_digits utility producing the wrong result"); // TODO: Re-evaluate use of off_t template::value, int>::type = 0> diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 2642471..35ea151 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -89,6 +89,8 @@ if(NOT CPPTRACE_SKIP_UNIT) unit/tracing/traced_exception.cpp unit/internals/optional.cpp unit/internals/result.cpp + unit/internals/string_utils.cpp + unit/internals/general.cpp ) target_compile_features(unittest PRIVATE cxx_std_20) target_link_libraries(unittest PRIVATE ${target_name} GTest::gtest_main GTest::gmock_main) diff --git a/test/unit/internals/general.cpp b/test/unit/internals/general.cpp new file mode 100644 index 0000000..9513fe2 --- /dev/null +++ b/test/unit/internals/general.cpp @@ -0,0 +1,219 @@ +#include +#include +#include +#include + +#include "utils/utils.hpp" + +using cpptrace::detail::byteswap; +using cpptrace::detail::n_digits; +using cpptrace::detail::to; +using cpptrace::detail::raii_wrapper; +using cpptrace::detail::raii_wrap; +using cpptrace::detail::maybe_owned; + +namespace { + +TEST(ByteSwapTest, ByteSwapUint8) { + uint8_t input = 0x12; + uint8_t expected = 0x12; + uint8_t result = byteswap(input); + EXPECT_EQ(result, expected); +} + +TEST(ByteSwapTest, ByteSwapInt8) { + int8_t input = 0x7F; + int8_t expected = 0x7F; + int8_t result = byteswap(input); + EXPECT_EQ(result, expected); + + int8_t neg_input = to(0x80); + int8_t neg_expected = to(0x80); + int8_t neg_result = byteswap(neg_input); + EXPECT_EQ(neg_result, neg_expected); +} + +TEST(ByteSwapTest, ByteSwapUint16) +{ + uint16_t input = 0x1234; + uint16_t expected = 0x3412; + uint16_t result = byteswap(input); + EXPECT_EQ(result, expected); + EXPECT_EQ(byteswap(to(0x0000)), to(0x0000)); + EXPECT_EQ(byteswap(to(0xFFFF)), to(0xFFFF)); +} + +TEST(ByteSwapTest, ByteSwapInt16) { + int16_t input = 0x1234; + int16_t expected = to(0x3412); + int16_t result = byteswap(input); + EXPECT_EQ(result, expected); + + int16_t neg_input = to(0xFEFF); + int16_t neg_expected = to(0xFFFE); + int16_t neg_result = byteswap(neg_input); + EXPECT_EQ(neg_result, neg_expected); +} + +TEST(ByteSwapTest, ByteSwapUint32) +{ + uint32_t input = 0x12345678; + uint32_t expected = 0x78563412; + uint32_t result = byteswap(input); + EXPECT_EQ(result, expected); + EXPECT_EQ(byteswap(to(0x00000000)), to(0x00000000)); + EXPECT_EQ(byteswap(to(0xFFFFFFFF)), to(0xFFFFFFFF)); +} + +TEST(ByteSwapTest, ByteSwapInt32) +{ + int32_t input = 0x12345678; + int32_t expected = to(0x78563412); + int32_t result = byteswap(input); + EXPECT_EQ(result, expected); + + int32_t neg_input = to(0xFF000000); + int32_t neg_expected = to(0x000000FF); + int32_t neg_result = byteswap(neg_input); + EXPECT_EQ(neg_result, neg_expected); +} + +TEST(ByteSwapTest, ByteSwapUint64) +{ + uint64_t input = 0x1122334455667788ULL; + uint64_t expected = 0x8877665544332211ULL; + uint64_t result = byteswap(input); + EXPECT_EQ(result, expected); + EXPECT_EQ(byteswap(to(0x0000000000000000ULL)), to(0x0000000000000000ULL)); + EXPECT_EQ(byteswap(to(0xFFFFFFFFFFFFFFFFULL)), to(0xFFFFFFFFFFFFFFFFULL)); +} + +TEST(ByteSwapTest, ByteSwapInt64) +{ + int64_t input = 0x1122334455667788LL; + int64_t expected = to(0x8877665544332211ULL); + int64_t result = byteswap(input); + EXPECT_EQ(result, expected); + + int64_t neg_input = to(0xFF00000000000000ULL); + int64_t neg_expected = to(0x00000000000000FFULL); + int64_t neg_result = byteswap(neg_input); + EXPECT_EQ(neg_result, neg_expected); +} + +TEST(NDigitsTest, Basic) +{ + static_assert(n_digits(1) == 1, "n_digits utility producing the wrong result"); + static_assert(n_digits(9) == 1, "n_digits utility producing the wrong result"); + static_assert(n_digits(10) == 2, "n_digits utility producing the wrong result"); + static_assert(n_digits(11) == 2, "n_digits utility producing the wrong result"); + static_assert(n_digits(1024) == 4, "n_digits utility producing the wrong result"); + + EXPECT_EQ(n_digits(1), 1); + EXPECT_EQ(n_digits(9), 1); + EXPECT_EQ(n_digits(10), 2); + EXPECT_EQ(n_digits(11), 2); + EXPECT_EQ(n_digits(1024), 4); +} + +struct test_deleter { + static int call_count; + static int last_value; + + void operator()(int value) { + call_count++; + last_value = value; + } +}; +int test_deleter::call_count = 0; +int test_deleter::last_value = 0; + +class RaiiWrapperTest : public ::testing::Test { +protected: + RaiiWrapperTest() { + test_deleter::call_count = 0; + test_deleter::last_value = 0; + } +}; + +TEST_F(RaiiWrapperTest, construct_and_destroy_calls_deleter) { + { + auto w = raii_wrap(42, test_deleter{}); + EXPECT_EQ(test_deleter::call_count, 0); + } + EXPECT_EQ(test_deleter::call_count, 1); + EXPECT_EQ(test_deleter::last_value, 42); +} + +TEST_F(RaiiWrapperTest, move_constructor_transfers_ownership) { + { + auto w1 = raii_wrap(123, test_deleter{}); + auto w2 = std::move(w1); + EXPECT_EQ(test_deleter::call_count, 0); + EXPECT_EQ(static_cast(w2), 123); + } + EXPECT_EQ(test_deleter::call_count, 1); + EXPECT_EQ(test_deleter::last_value, 123); +} + +TEST_F(RaiiWrapperTest, operator_t_and_get) { + { + auto w = raii_wrap(999, test_deleter{}); + int i = w; + EXPECT_EQ(i, 999); + w.get() = 1000; + EXPECT_EQ(static_cast(w), 1000); + } + EXPECT_EQ(test_deleter::call_count, 1); + EXPECT_EQ(test_deleter::last_value, 1000); +} + +class counting_helper { +public: + static int active; + int value; + counting_helper(int value) : value(value) { + ++active; + } + ~counting_helper() { + --active; + } + counting_helper(const counting_helper&) = delete; + counting_helper(counting_helper&&) = delete; + counting_helper& operator=(const counting_helper&) = delete; + counting_helper& operator=(counting_helper&&) = delete; + int foo() const { + return value; + } +}; +int counting_helper::active = 0; + +TEST(MaybeOwnedTest, NonOwningPointer) { + ASSERT_EQ(counting_helper::active, 0); + auto instance = std::make_unique(42); + EXPECT_EQ(counting_helper::active, 1); + { + maybe_owned non_owning(instance.get()); + EXPECT_EQ(counting_helper::active, 1); + EXPECT_EQ(non_owning->foo(), 42); + } + EXPECT_EQ(counting_helper::active, 1); + instance.reset(); + EXPECT_EQ(counting_helper::active, 0); +} + +TEST(MaybeOwnedTest, OwningPointer) { + ASSERT_EQ(counting_helper::active, 0); + auto instance = std::make_unique(42); + EXPECT_EQ(counting_helper::active, 1); + { + maybe_owned non_owning(std::move(instance)); + EXPECT_EQ(counting_helper::active, 1); + EXPECT_EQ(non_owning->foo(), 42); + } + EXPECT_EQ(counting_helper::active, 0); + instance.reset(); + EXPECT_EQ(counting_helper::active, 0); +} + +} diff --git a/test/unit/internals/optional.cpp b/test/unit/internals/optional.cpp index f69d915..8367bb8 100644 --- a/test/unit/internals/optional.cpp +++ b/test/unit/internals/optional.cpp @@ -2,7 +2,10 @@ #include "utils/optional.hpp" -using namespace cpptrace::detail; +using cpptrace::detail::optional; +using cpptrace::detail::nullopt; + +namespace { TEST(OptionalTest, DefaultConstructor) { optional o; @@ -117,3 +120,5 @@ TEST(OptionalTest, ValueOr) { optional o2(nullopt); EXPECT_EQ(o2.value_or(100), 100); } + +} diff --git a/test/unit/internals/result.cpp b/test/unit/internals/result.cpp index b942139..640ec79 100644 --- a/test/unit/internals/result.cpp +++ b/test/unit/internals/result.cpp @@ -2,7 +2,9 @@ #include "utils/result.hpp" -using namespace cpptrace::detail; +using cpptrace::detail::Result; + +namespace { // A simple custom error type that behaves like a standard exception. struct error { @@ -96,3 +98,5 @@ TEST_F(ResultFixture, ValueOr) { EXPECT_EQ(std::move(res_with_error).value_or(-1), -1); } } + +} diff --git a/test/unit/internals/string_utils.cpp b/test/unit/internals/string_utils.cpp new file mode 100644 index 0000000..49a0dad --- /dev/null +++ b/test/unit/internals/string_utils.cpp @@ -0,0 +1,80 @@ +#include +#include +#include +#include + +#include "utils/utils.hpp" + +using testing::ElementsAre; +using cpptrace::detail::split; +using cpptrace::detail::join; +using cpptrace::detail::trim; + +namespace { + +TEST(SplitTest, SplitBySingleDelimiter) { + std::string input = "hello,world"; + auto tokens = split(input, ","); + EXPECT_THAT(tokens, ElementsAre("hello", "world")); +} + +TEST(SplitTest, SplitByMultipleDelimiters) { + std::string input = "hello,world;test"; + auto tokens = split(input, ",;"); + EXPECT_THAT(tokens, ElementsAre("hello", "world", "test")); +} + +TEST(SplitTest, HandlesNoDelimiterFound) { + std::string input = "nodellimitershere"; + auto tokens = split(input, ", "); + EXPECT_THAT(tokens, ElementsAre("nodellimitershere")); +} + +TEST(SplitTest, HandlesEmptyString) { + std::string input = ""; + auto tokens = split(input, ","); + EXPECT_THAT(tokens, ElementsAre("")); +} + +TEST(SplitTest, HandlesConsecutiveDelimiters) { + std::string input = "one,,two,,,three"; + auto tokens = split(input, ","); + EXPECT_THAT(tokens, ElementsAre("one", "", "two", "", "", "three")); +} + +TEST(SplitTest, HandlesTrailingDelimiter) { + std::string input = "abc,"; + auto tokens = split(input, ","); + EXPECT_THAT(tokens, ElementsAre("abc", "")); +} + +TEST(SplitTest, HandlesLeadingDelimiter) { + std::string input = ",abc"; + auto tokens = split(input, ","); + EXPECT_THAT(tokens, ElementsAre("", "abc")); +} + +TEST(JoinTest, EmptyContainer) { + std::vector vec; + EXPECT_EQ(join(vec, ","), ""); +} + +TEST(JoinTest, SingleElements) { + std::vector vec = {"one"}; + EXPECT_EQ(join(vec, ","), "one"); +} + +TEST(JoinTest, MultipleElements) { + std::vector vec = {"one", "two", "three"}; + EXPECT_EQ(join(vec, ","), "one,two,three"); +} + +TEST(TrimTest, Basic) { + EXPECT_EQ(trim(""), ""); + EXPECT_EQ(trim("test"), "test"); + EXPECT_EQ(trim(" test "), "test"); + EXPECT_EQ(trim(" test\n "), "test"); + EXPECT_EQ(trim("\t test\n "), "test"); +} + +}