File: uuid.cpp

package info (click to toggle)
actor-framework 0.18.7-1~exp1
  • links: PTS
  • area: main
  • in suites: experimental
  • size: 8,740 kB
  • sloc: cpp: 85,162; sh: 491; python: 187; makefile: 11
file content (179 lines) | stat: -rw-r--r-- 6,039 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
// This file is part of CAF, the C++ Actor Framework. See the file LICENSE in
// the main distribution directory for license terms and copyright or visit
// https://github.com/actor-framework/actor-framework/blob/master/LICENSE.

#define CAF_SUITE uuid

#include "caf/uuid.hpp"

#include "core-test.hpp"

#include "caf/json_reader.hpp"
#include "caf/json_writer.hpp"

using namespace caf;

namespace {

uuid operator"" _uuid(const char* cstr, size_t cstr_len) {
  if (cstr_len != 36)
    CAF_FAIL("malformed test input");
  std::string str{cstr, cstr_len};
  if (str[8] != '-' || str[13] != '-' || str[18] != '-' || str[23] != '-')
    CAF_FAIL("malformed test input");
  str.erase(std::remove(str.begin(), str.end(), '-'), str.end());
  if (str.size() != 32)
    CAF_FAIL("malformed test input");
  uuid result;
  for (size_t index = 0; index < 16; ++index) {
    auto input_index = index * 2;
    char buf[] = {str[input_index], str[input_index + 1], '\0'};
    result.bytes().at(index) = static_cast<byte>(std::stoi(buf, nullptr, 16));
  }
  return result;
}

struct fixture {
  uuid nil; // 00000000-0000-0000-0000-000000000000

  // A couple of UUIDs for version 1.
  uuid v1[3] = {
    "cbba341a-6ceb-11ea-bc55-0242ac130003"_uuid,
    "cbba369a-6ceb-11ea-bc55-0242ac130003"_uuid,
    "cbba38fc-6ceb-11ea-bc55-0242ac130003"_uuid,
  };

  // A couple of UUIDs for version 4.
  uuid v4[3] = {
    "2ee4ded7-69c0-4dd6-876d-02e446b21784"_uuid,
    "934a33b6-7f0c-4d70-9749-5ad4292358dd"_uuid,
    "bf761f7c-00f2-4161-855e-e286cfa63c11"_uuid,
  };
};

} // namespace

BEGIN_FIXTURE_SCOPE(fixture)

CAF_TEST(default generated UUIDs have all 128 bits set to zero) {
  uuid nil;
  CHECK(!nil);
  auto zero = [](byte x) { return to_integer<int>(x) == 0; };
  CHECK(std::all_of(nil.bytes().begin(), nil.bytes().end(), zero));
  CHECK(nil == uuid::nil());
}

CAF_TEST(UUIDs print in 4 2 2 2 6 format) {
  CHECK_EQ(to_string(nil), "00000000-0000-0000-0000-000000000000");
  CHECK_EQ(to_string(v1[0]), "cbba341a-6ceb-11ea-bc55-0242ac130003");
  CHECK_EQ(to_string(v1[1]), "cbba369a-6ceb-11ea-bc55-0242ac130003");
  CHECK_EQ(to_string(v1[2]), "cbba38fc-6ceb-11ea-bc55-0242ac130003");
}

CAF_TEST(make_uuid parses strings in 4 2 2 2 6 format) {
  CHECK_EQ(make_uuid("00000000-0000-0000-0000-000000000000"), nil);
  CHECK_EQ(make_uuid("cbba341a-6ceb-11ea-bc55-0242ac130003"), v1[0]);
  CHECK_EQ(make_uuid("cbba369a-6ceb-11ea-bc55-0242ac130003"), v1[1]);
  CHECK_EQ(make_uuid("cbba38fc-6ceb-11ea-bc55-0242ac130003"), v1[2]);
}

CAF_TEST(make_uuid rejects strings with invalid variant or version values) {
  CHECK(!uuid::can_parse("cbba341a-6ceb-81ea-bc55-0242ac130003"));
  CHECK(!uuid::can_parse("cbba369a-6ceb-F1ea-bc55-0242ac130003"));
  CHECK(!uuid::can_parse("cbba38fc-6ceb-01ea-bc55-0242ac130003"));
  CHECK_EQ(make_uuid("cbba341a-6ceb-81ea-bc55-0242ac130003"),
           pec::invalid_argument);
  CHECK_EQ(make_uuid("cbba369a-6ceb-F1ea-bc55-0242ac130003"),
           pec::invalid_argument);
  CHECK_EQ(make_uuid("cbba38fc-6ceb-01ea-bc55-0242ac130003"),
           pec::invalid_argument);
}

#define WITH(uuid_str) if (auto x = uuid_str##_uuid; true)

CAF_TEST(version 1 defines UUIDs that are based on time) {
  CHECK_EQ(v1[0].version(), uuid::time_based);
  CHECK_EQ(v1[1].version(), uuid::time_based);
  CHECK_EQ(v1[2].version(), uuid::time_based);
  CHECK_NE(v4[0].version(), uuid::time_based);
  CHECK_NE(v4[1].version(), uuid::time_based);
  CHECK_NE(v4[2].version(), uuid::time_based);
  WITH("00000001-0000-1000-8122-334455667788") {
    CHECK_EQ(x.variant(), uuid::rfc4122);
    CHECK_EQ(x.version(), uuid::time_based);
    CHECK_EQ(x.timestamp(), 0x0000000000000001ull);
    CHECK_EQ(x.clock_sequence(), 0x0122u);
    CHECK_EQ(x.node(), 0x334455667788ull);
  }
  WITH("00000001-0001-1000-8122-334455667788") {
    CHECK_EQ(x.variant(), uuid::rfc4122);
    CHECK_EQ(x.version(), uuid::time_based);
    CHECK_EQ(x.timestamp(), 0x0000000100000001ull);
    CHECK_EQ(x.clock_sequence(), 0x0122u);
    CHECK_EQ(x.node(), 0x334455667788ull);
  }
  WITH("00000001-0001-1001-8122-334455667788") {
    CHECK_EQ(x.variant(), uuid::rfc4122);
    CHECK_EQ(x.version(), uuid::time_based);
    CHECK_EQ(x.timestamp(), 0x0001000100000001ull);
    CHECK_EQ(x.clock_sequence(), 0x0122u);
    CHECK_EQ(x.node(), 0x334455667788ull);
  }
  WITH("ffffffff-ffff-1fff-bfff-334455667788") {
    CHECK_EQ(x.variant(), uuid::rfc4122);
    CHECK_EQ(x.version(), uuid::time_based);
    CHECK_EQ(x.timestamp(), 0x0FFFFFFFFFFFFFFFull);
    CHECK_EQ(x.clock_sequence(), 0x3FFFu);
    CHECK_EQ(x.node(), 0x334455667788ull);
  }
}

SCENARIO("UUIDs are inspectable") {
  auto id = "2ee4ded7-69c0-4dd6-876d-02e446b21784"_uuid;
  GIVEN("a binary serializer") {
    byte_buffer buf;
    binary_serializer sink{nullptr, buf};
    WHEN("applying an UUID to the serializer") {
      CHECK(sink.apply(id));
      THEN("a binary deserializer reproduces the UUID") {
        binary_deserializer source{nullptr, buf};
        uuid id_copy;
        CHECK(source.apply(id_copy));
        CHECK_EQ(id, id_copy);
      }
    }
  }
  GIVEN("a JSON writer") {
    json_writer sink;
    WHEN("applying an UUID to the writer") {
      CHECK(sink.apply(id));
      THEN("the writer renders the UUID as string") {
        CHECK_EQ(sink.str(), R"("2ee4ded7-69c0-4dd6-876d-02e446b21784")");
      }
      AND("a JSON reader reproduces the UUID") {
        json_reader source;
        uuid id_copy;
        CHECK(source.load(sink.str()));
        CHECK(source.apply(id_copy));
        CHECK_EQ(id, id_copy);
      }
    }
  }
}

SCENARIO("UUIDs are hashable") {
  GIVEN("two UUIDs ") {
    auto id1 = "2ee4ded7-69c0-4dd6-876d-02e446b21784"_uuid;
    auto id2 = "a6155548-2994-4833-b4e3-9823f5f15fe9"_uuid;
    WHEN("retrieving a hash value for the UUIDs") {
      THEN("the UUIDs return different hash values") {
        std::hash<uuid> f;
        CHECK_EQ(id1.hash(), f(id1));
        CHECK_EQ(id2.hash(), f(id2));
        CHECK_NE(f(id1), f(id2));
      }
    }
  }
}

END_FIXTURE_SCOPE()