146 lines
3.7 KiB
C++
146 lines
3.7 KiB
C++
#include "catch.hpp"
|
|
|
|
#include <cpputils/uuid.h>
|
|
#include <array>
|
|
#include <chrono>
|
|
#include <cstddef>
|
|
#include <string>
|
|
#include <thread>
|
|
#include <unordered_set>
|
|
|
|
using namespace cpputils::uuid;
|
|
|
|
TEST_CASE("uuidToString formats UUIDs correctly", "[uuid]") {
|
|
|
|
struct TestVector {
|
|
std::array<uint8_t, 16> 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<std::string> 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<std::string> uuids;
|
|
|
|
for (int i = 0; i < N; ++i) {
|
|
uuids.insert(uuidToString(v4.generate()));
|
|
uuids.insert(uuidToString(v7.generate()));
|
|
}
|
|
|
|
REQUIRE(uuids.size() == 2 * N);
|
|
}
|