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