OLD | NEW |
| (Empty) |
1 // Copyright 2016 The Chromium Authors. All rights reserved. | |
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 <limits> | |
6 #include <map> | |
7 #include <sstream> | |
8 #include <string> | |
9 #include <type_traits> | |
10 #include <unordered_map> | |
11 | |
12 #include "content/common/id_type.h" | |
13 #include "testing/gtest/include/gtest/gtest.h" | |
14 | |
15 namespace content { | |
16 | |
17 namespace { | |
18 | |
19 class Foo; | |
20 using FooId = IdType<Foo, int, 0>; | |
21 | |
22 class Bar; | |
23 using BarId = IdType<Bar, int, 0>; | |
24 | |
25 class AnotherIdMarker; | |
26 class DerivedId : public IdType<AnotherIdMarker, int, 0> { | |
27 public: | |
28 explicit DerivedId(int unsafe_value) | |
29 : IdType<AnotherIdMarker, int, 0>(unsafe_value) {} | |
30 }; | |
31 | |
32 } // namespace | |
33 | |
34 TEST(IdType, DefaultValueIsInvalid) { | |
35 FooId foo_id; | |
36 EXPECT_TRUE(foo_id.is_null()); | |
37 } | |
38 | |
39 TEST(IdType, NormalValueIsValid) { | |
40 FooId foo_id = FooId::FromUnsafeValue(123); | |
41 EXPECT_FALSE(foo_id.is_null()); | |
42 } | |
43 | |
44 TEST(IdType, OutputStreamTest) { | |
45 FooId foo_id = FooId::FromUnsafeValue(123); | |
46 | |
47 std::ostringstream ss; | |
48 ss << foo_id; | |
49 EXPECT_EQ("123", ss.str()); | |
50 } | |
51 | |
52 TEST(IdType, IdType32) { | |
53 IdType32<Foo> id; | |
54 | |
55 EXPECT_EQ(0, id.GetUnsafeValue()); | |
56 static_assert(sizeof(int32_t) == sizeof(id), ""); | |
57 } | |
58 | |
59 TEST(IdType, IdTypeU32) { | |
60 IdTypeU32<Foo> id; | |
61 | |
62 EXPECT_EQ(0u, id.GetUnsafeValue()); | |
63 static_assert(sizeof(uint32_t) == sizeof(id), ""); | |
64 } | |
65 | |
66 TEST(IdType, IdType64) { | |
67 IdType64<Foo> id; | |
68 | |
69 EXPECT_EQ(0, id.GetUnsafeValue()); | |
70 static_assert(sizeof(int64_t) == sizeof(id), ""); | |
71 } | |
72 | |
73 TEST(IdType, IdTypeU64) { | |
74 IdTypeU64<Foo> id; | |
75 | |
76 EXPECT_EQ(0u, id.GetUnsafeValue()); | |
77 static_assert(sizeof(uint64_t) == sizeof(id), ""); | |
78 } | |
79 | |
80 TEST(IdType, DerivedClasses) { | |
81 DerivedId derived_id(456); | |
82 | |
83 std::ostringstream ss; | |
84 ss << derived_id; | |
85 EXPECT_EQ("456", ss.str()); | |
86 | |
87 std::map<DerivedId, std::string> ordered_map; | |
88 ordered_map[derived_id] = "blah"; | |
89 EXPECT_EQ(ordered_map[derived_id], "blah"); | |
90 | |
91 std::unordered_map<DerivedId, std::string, DerivedId::Hasher> unordered_map; | |
92 unordered_map[derived_id] = "blah2"; | |
93 EXPECT_EQ(unordered_map[derived_id], "blah2"); | |
94 } | |
95 | |
96 TEST(IdType, StaticAsserts) { | |
97 static_assert(!std::is_constructible<FooId, int>::value, | |
98 "Should be impossible to construct FooId from a raw integer."); | |
99 static_assert(!std::is_convertible<int, FooId>::value, | |
100 "Should be impossible to convert a raw integer into FooId."); | |
101 | |
102 static_assert(!std::is_constructible<FooId, BarId>::value, | |
103 "Should be impossible to construct FooId from a BarId."); | |
104 static_assert(!std::is_convertible<BarId, FooId>::value, | |
105 "Should be impossible to convert a BarId into FooId."); | |
106 | |
107 // The presence of a custom default constructor means that FooId is not a | |
108 // "trivial" class and therefore is not a POD type (unlike an int32_t). | |
109 // At the same time FooId has almost all of the properties of a POD type: | |
110 // - is "trivially copyable" (i.e. is memcpy-able), | |
111 // - has "standard layout" (i.e. interops with things expecting C layout). | |
112 // See http://stackoverflow.com/a/7189821 for more info about these | |
113 // concepts. | |
114 static_assert(std::is_standard_layout<FooId>::value, | |
115 "FooId should have standard layout. " | |
116 "See http://stackoverflow.com/a/7189821 for more info."); | |
117 static_assert(sizeof(FooId) == sizeof(int), | |
118 "FooId should be the same size as the raw integer it wraps."); | |
119 // TODO(lukasza): Enable these once <type_traits> supports all the standard | |
120 // C++11 equivalents (i.e. std::is_trivially_copyable instead of the | |
121 // non-standard std::has_trivial_copy_assign). | |
122 // static_assert(std::has_trivial_copy_constructor<FooId>::value, | |
123 // "FooId should have a trivial copy constructor."); | |
124 // static_assert(std::has_trivial_copy_assign<FooId>::value, | |
125 // "FooId should have a trivial copy assignment operator."); | |
126 // static_assert(std::has_trivial_destructor<FooId>::value, | |
127 // "FooId should have a trivial destructor."); | |
128 } | |
129 | |
130 class IdTypeSpecificValueTest : public ::testing::TestWithParam<int> { | |
131 protected: | |
132 FooId test_id() { return FooId::FromUnsafeValue(GetParam()); } | |
133 | |
134 FooId other_id() { | |
135 if (GetParam() != std::numeric_limits<int>::max()) | |
136 return FooId::FromUnsafeValue(GetParam() + 1); | |
137 else | |
138 return FooId::FromUnsafeValue(std::numeric_limits<int>::min()); | |
139 } | |
140 }; | |
141 | |
142 TEST_P(IdTypeSpecificValueTest, ComparisonToSelf) { | |
143 EXPECT_TRUE(test_id() == test_id()); | |
144 EXPECT_FALSE(test_id() != test_id()); | |
145 EXPECT_FALSE(test_id() < test_id()); | |
146 } | |
147 | |
148 TEST_P(IdTypeSpecificValueTest, ComparisonToOther) { | |
149 EXPECT_FALSE(test_id() == other_id()); | |
150 EXPECT_TRUE(test_id() != other_id()); | |
151 } | |
152 | |
153 TEST_P(IdTypeSpecificValueTest, UnsafeValueRoundtrips) { | |
154 int original_value = GetParam(); | |
155 FooId id = FooId::FromUnsafeValue(original_value); | |
156 int final_value = id.GetUnsafeValue(); | |
157 EXPECT_EQ(original_value, final_value); | |
158 } | |
159 | |
160 TEST_P(IdTypeSpecificValueTest, Copying) { | |
161 FooId original = test_id(); | |
162 | |
163 FooId copy_via_constructor(original); | |
164 EXPECT_EQ(original, copy_via_constructor); | |
165 | |
166 FooId copy_via_assignment; | |
167 copy_via_assignment = original; | |
168 EXPECT_EQ(original, copy_via_assignment); | |
169 } | |
170 | |
171 TEST_P(IdTypeSpecificValueTest, StdUnorderedMap) { | |
172 std::unordered_map<FooId, std::string, FooId::Hasher> map; | |
173 | |
174 map[test_id()] = "test_id"; | |
175 map[other_id()] = "other_id"; | |
176 | |
177 EXPECT_EQ(map[test_id()], "test_id"); | |
178 EXPECT_EQ(map[other_id()], "other_id"); | |
179 } | |
180 | |
181 TEST_P(IdTypeSpecificValueTest, StdMap) { | |
182 std::map<FooId, std::string> map; | |
183 | |
184 map[test_id()] = "test_id"; | |
185 map[other_id()] = "other_id"; | |
186 | |
187 EXPECT_EQ(map[test_id()], "test_id"); | |
188 EXPECT_EQ(map[other_id()], "other_id"); | |
189 } | |
190 | |
191 INSTANTIATE_TEST_CASE_P(, | |
192 IdTypeSpecificValueTest, | |
193 ::testing::Values(std::numeric_limits<int>::min(), | |
194 -1, | |
195 0, | |
196 1, | |
197 123, | |
198 std::numeric_limits<int>::max())); | |
199 | |
200 } // namespace content | |
OLD | NEW |