#include "catch.hpp" #include #include #include #include #include #include #include using namespace cpputils::uuid; TEST_CASE("uuidToString formats UUIDs correctly", "[uuid]") { struct TestVector { std::array uuid; char const* expected; }; constexpr TestVector tests[] = { {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, "00000000-0000-0000-0000-000000000000"}, {{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef}, "01234567-89ab-cdef-0123-456789abcdef"}, {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, "ffffffff-ffff-ffff-ffff-ffffffffffff"}, {{0x55, 0x0e, 0x84, 0x00, 0xe2, 0x9b, 0x41, 0xd4, 0xa7, 0x16, 0x44, 0x66, 0x55, 0x44, 0x00, 0x00}, "550e8400-e29b-41d4-a716-446655440000"}, {{0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe, 0xba, 0xbe, 0x80, 0x00, 0x01, 0x23, 0x45, 0x67, 0x89, 0xab}, "deadbeef-cafe-babe-8000-0123456789ab"}, {{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}, "00010203-0405-0607-0809-0a0b0c0d0e0f"}, }; for (auto const& t : tests) { REQUIRE(uuidToString(t.uuid) == t.expected); } } TEST_CASE("V4 generates unique UUIDs", "[uuid][v4]") { V4 generator; constexpr int N = 1000; std::unordered_set uuids; for (int i = 0; i < N; ++i) { auto uuid = generator.generate(); auto str = uuidToString(uuid); REQUIRE(uuids.find(str) == uuids.end()); uuids.insert(str); } } TEST_CASE("V7 generates increasing timestamps", "[uuid][v7]") { V7 generator; constexpr int N = 1000; int64_t prev_ts = 0; for (int i = 0; i < N; ++i) { auto uuid = generator.generate(); auto ts = V7::get_timestamp_from_uuid(uuid); REQUIRE(ts >= prev_ts); prev_ts = ts; } } TEST_CASE("V7 sequence increments on same timestamp", "[uuid][v7][!mayfail]") { INFO("info message"); V7 generator; size_t count = 0; size_t i = 1000; for (; i > 0;) { auto uuid1 = generator.generate(); auto uuid2 = generator.generate(); auto ts1 = V7::get_timestamp_from_uuid(uuid1); auto ts2 = V7::get_timestamp_from_uuid(uuid2); if (ts1 == ts2) { REQUIRE(uuid1 != uuid2); count++; if (count >= 10) { break; } } else { i--; } } INFO( "Testing that V7 UUIDs with the same timestamp produce unique UUIDs. " "Tries up to 1000 pairs to avoid long runtime if UUID generation is " "slow. " "(Test fails with 0 > 0 if no same-timestamp UUIDs could be generated)"); REQUIRE(i > 0); } TEST_CASE("UUID string formatting consistency", "[uuid]") { V4 v4; V7 v7; auto uuid4 = v4.generate(); auto uuid7 = v7.generate(); auto str4 = uuidToString(uuid4); auto str7 = uuidToString(uuid7); REQUIRE(str4.size() == 36); REQUIRE(str7.size() == 36); auto is_hex_or_dash = [](char c) { return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c == '-'); }; REQUIRE(std::all_of(str4.begin(), str4.end(), is_hex_or_dash)); REQUIRE(std::all_of(str7.begin(), str7.end(), is_hex_or_dash)); } TEST_CASE("V4 and V7 generate large number of UUIDs without collision", "[uuid][stress]") { V4 v4; V7 v7; constexpr int N = 5000; std::unordered_set uuids; for (int i = 0; i < N; ++i) { uuids.insert(uuidToString(v4.generate())); uuids.insert(uuidToString(v7.generate())); } REQUIRE(uuids.size() == 2 * N); }