1 // Copyright 2012 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "base/uuid.h"
6
7 #include <stdint.h>
8
9 #include <limits>
10 #include <set>
11 #include <string_view>
12 #include <unordered_set>
13
14 #include "base/strings/string_util.h"
15 #include "build/build_config.h"
16 #include "testing/gtest/include/gtest/gtest.h"
17
18 namespace base {
19
20 namespace {
21
22 // The format of Uuid version 4 must be xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx,
23 // where y is one of [8, 9, a, b].
IsValidV4(const Uuid & guid)24 bool IsValidV4(const Uuid& guid) {
25 const std::string& lowercase = guid.AsLowercaseString();
26 return guid.is_valid() && lowercase[14] == '4' &&
27 (lowercase[19] == '8' || lowercase[19] == '9' ||
28 lowercase[19] == 'a' || lowercase[19] == 'b');
29 }
30
31 } // namespace
32
TEST(UuidTest,UuidBasicUniqueness)33 TEST(UuidTest, UuidBasicUniqueness) {
34 constexpr int kIterations = 10;
35 for (int i = 0; i < kIterations; ++i) {
36 const Uuid guid1 = Uuid::GenerateRandomV4();
37 const Uuid guid2 = Uuid::GenerateRandomV4();
38 EXPECT_NE(guid1, guid2);
39 EXPECT_TRUE(guid1.is_valid());
40 EXPECT_TRUE(IsValidV4(guid1));
41 EXPECT_TRUE(guid2.is_valid());
42 EXPECT_TRUE(IsValidV4(guid2));
43 }
44 }
45
46 namespace {
47
TestUuidValidity(std::string_view input,bool case_insensitive,bool strict)48 void TestUuidValidity(std::string_view input,
49 bool case_insensitive,
50 bool strict) {
51 SCOPED_TRACE(input);
52 {
53 const Uuid guid = Uuid::ParseCaseInsensitive(input);
54 EXPECT_EQ(case_insensitive, guid.is_valid());
55 }
56 {
57 const Uuid guid = Uuid::ParseLowercase(input);
58 EXPECT_EQ(strict, guid.is_valid());
59 }
60 }
61
62 } // namespace
63
TEST(UuidTest,Validity)64 TEST(UuidTest, Validity) {
65 // Empty Uuid is invalid.
66 EXPECT_FALSE(Uuid().is_valid());
67
68 enum Parsability { kDoesntParse, kParsesCaseInsensitiveOnly, kAlwaysParses };
69
70 static constexpr struct {
71 std::string_view input;
72 Parsability parsability;
73 } kUuidValidity[] = {
74 {"invalid", kDoesntParse},
75 {"0123456789ab-cdef-fedc-ba98-76543210", kDoesntParse},
76 {"0123456789abcdeffedcba9876543210", kDoesntParse},
77 {"01234567-89Zz-ZzZz-ZzZz-Zz9876543210", kDoesntParse},
78 {"DEADBEEFDEADBEEFDEADBEEFDEADBEEF", kDoesntParse},
79 {"deadbeefWdeadXbeefYdeadZbeefdeadbeef", kDoesntParse},
80 {"XXXdeadbeefWdeadXbeefYdeadZbeefdeadbeefXXX", kDoesntParse},
81 {"01234567-89aB-cDeF-fEdC-bA9876543210", kParsesCaseInsensitiveOnly},
82 {"DEADBEEF-DEAD-BEEF-DEAD-BEEFDEADBEEF", kParsesCaseInsensitiveOnly},
83 {"00000000-0000-0000-0000-000000000000", kAlwaysParses},
84 {"deadbeef-dead-beef-dead-beefdeadbeef", kAlwaysParses},
85 };
86
87 for (const auto& validity : kUuidValidity) {
88 const bool case_insensitive = validity.parsability != kDoesntParse;
89 const bool strict = validity.parsability == kAlwaysParses;
90 TestUuidValidity(validity.input, case_insensitive, strict);
91 }
92 }
93
TEST(UuidTest,EqualityAndRoundTrip)94 TEST(UuidTest, EqualityAndRoundTrip) {
95 static constexpr char kCanonicalStr[] =
96 "deadbeef-dead-4eef-bead-beefdeadbeef";
97
98 const Uuid from_lower =
99 Uuid::ParseCaseInsensitive(ToLowerASCII(kCanonicalStr));
100 EXPECT_EQ(kCanonicalStr, from_lower.AsLowercaseString());
101
102 const Uuid from_upper =
103 Uuid::ParseCaseInsensitive(ToUpperASCII(kCanonicalStr));
104 EXPECT_EQ(kCanonicalStr, from_upper.AsLowercaseString());
105
106 EXPECT_EQ(from_lower, from_upper);
107
108 // Invalid Uuids are equal.
109 EXPECT_EQ(Uuid(), Uuid());
110 }
111
TEST(UuidTest,UnorderedSet)112 TEST(UuidTest, UnorderedSet) {
113 std::unordered_set<Uuid, UuidHash> guid_set;
114
115 static constexpr char kUuid1[] = "01234567-89ab-cdef-fedc-ba9876543210";
116 guid_set.insert(Uuid::ParseCaseInsensitive(ToLowerASCII(kUuid1)));
117 EXPECT_EQ(1u, guid_set.size());
118 guid_set.insert(Uuid::ParseCaseInsensitive(ToUpperASCII(kUuid1)));
119 EXPECT_EQ(1u, guid_set.size());
120
121 static constexpr char kUuid2[] = "deadbeef-dead-beef-dead-beefdeadbeef";
122 guid_set.insert(Uuid::ParseCaseInsensitive(ToLowerASCII(kUuid2)));
123 EXPECT_EQ(2u, guid_set.size());
124 guid_set.insert(Uuid::ParseCaseInsensitive(ToUpperASCII(kUuid2)));
125 EXPECT_EQ(2u, guid_set.size());
126 }
127
TEST(UuidTest,Set)128 TEST(UuidTest, Set) {
129 std::set<Uuid> guid_set;
130
131 static constexpr char kUuid1[] = "01234567-89ab-cdef-0123-456789abcdef";
132 const Uuid guid1 = Uuid::ParseLowercase(kUuid1);
133 ASSERT_TRUE(guid1.is_valid());
134 guid_set.insert(guid1);
135
136 static constexpr char kUuid2[] = "deadbeef-dead-beef-dead-beefdeadbeef";
137 const Uuid guid2 = Uuid::ParseLowercase(kUuid2);
138 ASSERT_TRUE(guid2.is_valid());
139 guid_set.insert(guid2);
140
141 // Test that the order of the Uuids was preserved.
142 auto it = guid_set.begin();
143 EXPECT_EQ(guid1, *it);
144 ++it;
145 EXPECT_EQ(guid2, *it);
146 ++it;
147 EXPECT_EQ(guid_set.end(), it);
148 }
149
TEST(UuidTest,Compare)150 TEST(UuidTest, Compare) {
151 static constexpr char kUuid[] = "21abd97f-73e8-4b88-9389-a9fee6abda5e";
152 static constexpr char kUuidLess[] = "1e0dcaca-9e7c-4f4b-bcc6-e4c02b0c99df";
153 static constexpr char kUuidGreater[] = "6eeb1bc8-186b-433c-9d6a-a827bc96b2d4";
154
155 const Uuid guid = Uuid::ParseLowercase(kUuid);
156 const Uuid guid_eq = Uuid::ParseLowercase(kUuid);
157 const Uuid guid_lt = Uuid::ParseLowercase(kUuidLess);
158 const Uuid guid_gt = Uuid::ParseLowercase(kUuidGreater);
159 const Uuid guid_invalid = Uuid();
160
161 EXPECT_TRUE(guid_eq == guid);
162 EXPECT_FALSE(guid_eq != guid);
163 EXPECT_FALSE(guid_eq < guid);
164 EXPECT_TRUE(guid_eq <= guid);
165 EXPECT_FALSE(guid_eq > guid);
166 EXPECT_TRUE(guid_eq >= guid);
167
168 EXPECT_FALSE(guid_lt == guid);
169 EXPECT_TRUE(guid_lt != guid);
170 EXPECT_TRUE(guid_lt < guid);
171 EXPECT_TRUE(guid_lt <= guid);
172 EXPECT_FALSE(guid_lt > guid);
173 EXPECT_FALSE(guid_lt >= guid);
174
175 EXPECT_FALSE(guid_gt == guid);
176 EXPECT_TRUE(guid_gt != guid);
177 EXPECT_FALSE(guid_gt < guid);
178 EXPECT_FALSE(guid_gt <= guid);
179 EXPECT_TRUE(guid_gt > guid);
180 EXPECT_TRUE(guid_gt >= guid);
181
182 // Invalid Uuids are the "least".
183 EXPECT_FALSE(guid_invalid == guid);
184 EXPECT_TRUE(guid_invalid != guid);
185 EXPECT_TRUE(guid_invalid < guid);
186 EXPECT_TRUE(guid_invalid <= guid);
187 EXPECT_FALSE(guid_invalid > guid);
188 EXPECT_FALSE(guid_invalid >= guid);
189 }
190
TEST(UuidTest,FormatRandomDataAsV4)191 TEST(UuidTest, FormatRandomDataAsV4) {
192 static constexpr uint64_t bytes1a[] = {0x0123456789abcdefull,
193 0x5a5a5a5aa5a5a5a5ull};
194 static constexpr uint64_t bytes1b[] = {bytes1a[0], bytes1a[1]};
195 static constexpr uint64_t bytes2[] = {0xfffffffffffffffdull,
196 0xfffffffffffffffeull};
197 static constexpr uint64_t bytes3[] = {0xfffffffffffffffdull,
198 0xfffffffffffffffcull};
199
200 const Uuid guid1a =
201 Uuid::FormatRandomDataAsV4ForTesting(as_bytes(make_span(bytes1a)));
202 const Uuid guid1b =
203 Uuid::FormatRandomDataAsV4ForTesting(as_bytes(make_span(bytes1b)));
204 const Uuid guid2 =
205 Uuid::FormatRandomDataAsV4ForTesting(as_bytes(make_span(bytes2)));
206 const Uuid guid3 =
207 Uuid::FormatRandomDataAsV4ForTesting(as_bytes(make_span(bytes3)));
208
209 EXPECT_TRUE(guid1a.is_valid());
210 EXPECT_TRUE(guid1b.is_valid());
211 EXPECT_TRUE(guid2.is_valid());
212 EXPECT_TRUE(guid3.is_valid());
213
214 // The same input should give the same Uuid.
215 EXPECT_EQ(guid1a, guid1b);
216
217 EXPECT_NE(guid1a, guid2);
218 EXPECT_NE(guid1a, guid3);
219 EXPECT_NE(guid2, guid3);
220 }
221
222 } // namespace base
223