1 /*
2 * Copyright (C) 2019 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <memory>
18 #include <type_traits>
19 #include <utility>
20
21 #include "gmock/gmock.h"
22 #include "gtest/gtest.h"
23 #include "idmap2/Result.h"
24
25 namespace android::idmap2 {
26
27 struct Container {
28 uint32_t value; // NOLINT(misc-non-private-member-variables-in-classes)
29 };
30
31 // Tests: Error
32
TEST(ResultTests,ErrorTraits)33 TEST(ResultTests, ErrorTraits) {
34 ASSERT_TRUE(std::is_move_constructible<Error>::value);
35 ASSERT_TRUE(std::is_move_assignable<Error>::value);
36 ASSERT_TRUE(std::is_copy_constructible<Error>::value);
37 ASSERT_TRUE(std::is_copy_assignable<Error>::value);
38 }
39
TEST(ResultTests,ErrorCtorFormat)40 TEST(ResultTests, ErrorCtorFormat) {
41 Error e("%s=0x%08x", "resid", 0x7f010002);
42 ASSERT_EQ(e.GetMessage(), "resid=0x7f010002");
43 }
44
TEST(ResultTests,ErrorPropagateParent)45 TEST(ResultTests, ErrorPropagateParent) {
46 Error e1("foo");
47 ASSERT_EQ(e1.GetMessage(), "foo");
48
49 Error e2(e1, "bar");
50 ASSERT_EQ(e2.GetMessage(), "foo -> bar");
51
52 Error e3(e2); // NOLINT(performance-unnecessary-copy-initialization)
53 ASSERT_EQ(e3.GetMessage(), "foo -> bar");
54
55 Error e4(e3, "%02d", 1);
56 ASSERT_EQ(e4.GetMessage(), "foo -> bar -> 01");
57 }
58
59 // Tests: Result<T> member functions
60
61 // Result(const Result&)
TEST(ResultTests,CopyConstructor)62 TEST(ResultTests, CopyConstructor) {
63 Result<uint32_t> r1(42U);
64
65 Result<uint32_t> r2(r1);
66 ASSERT_TRUE(r2);
67 ASSERT_EQ(*r2, 42U);
68
69 Result<uint32_t> r3 = r2;
70 ASSERT_TRUE(r3);
71 ASSERT_EQ(*r3, 42U);
72 }
73
74 // Result(const T&)
TEST(ResultTests,Constructor)75 TEST(ResultTests, Constructor) {
76 uint32_t v = 42U;
77 Result<uint32_t> r1(v);
78 ASSERT_TRUE(r1);
79 ASSERT_EQ(*r1, 42U);
80
81 Error e("foo");
82 Result<uint32_t> r2(e);
83 ASSERT_FALSE(r2);
84 ASSERT_EQ(r2.GetErrorMessage(), "foo");
85 }
86
87 // Result(const T&&)
TEST(ResultTests,MoveConstructor)88 TEST(ResultTests, MoveConstructor) {
89 Result<uint32_t> r1(42U);
90 ASSERT_TRUE(r1);
91 ASSERT_EQ(*r1, 42U);
92
93 Result<uint32_t> r2(Error("foo"));
94 ASSERT_FALSE(r2);
95 ASSERT_EQ(r2.GetErrorMessage(), "foo");
96 }
97
98 // operator=
TEST(ResultTests,CopyAssignmentOperator)99 TEST(ResultTests, CopyAssignmentOperator) {
100 // note: 'Result<...> r2 = r1;' calls the copy ctor
101 Result<uint32_t> r1(42U);
102 Result<uint32_t> r2(0U);
103 r2 = r1;
104 ASSERT_TRUE(r2);
105 ASSERT_EQ(*r2, 42U);
106
107 Result<uint32_t> r3(Error("foo"));
108 r2 = r3;
109 ASSERT_FALSE(r2);
110 ASSERT_EQ(r2.GetErrorMessage(), "foo");
111 }
112
TEST(ResultTests,MoveAssignmentOperator)113 TEST(ResultTests, MoveAssignmentOperator) {
114 Result<uint32_t> r(0U);
115 r = Result<uint32_t>(42U);
116 ASSERT_TRUE(r);
117 ASSERT_EQ(*r, 42U);
118
119 r = Result<uint32_t>(Error("foo"));
120 ASSERT_FALSE(r);
121 ASSERT_EQ(r.GetErrorMessage(), "foo");
122 }
123
124 // operator bool()
TEST(ResultTests,BoolOperator)125 TEST(ResultTests, BoolOperator) {
126 Result<uint32_t> r1(42U);
127 ASSERT_TRUE(r1);
128 ASSERT_EQ(*r1, 42U);
129
130 Result<uint32_t> r2(Error("foo"));
131 ASSERT_FALSE(r2);
132 ASSERT_EQ(r2.GetErrorMessage(), "foo");
133 }
134
135 // operator*
TEST(ResultTests,IndirectionOperator)136 TEST(ResultTests, IndirectionOperator) {
137 const Result<uint32_t> r1(42U);
138 ASSERT_TRUE(r1);
139 ASSERT_EQ(*r1, 42U);
140
141 const Result<Container> r2(Container{42U});
142 ASSERT_TRUE(r2);
143 const Container& c = *r2;
144 ASSERT_EQ(c.value, 42U);
145
146 Result<Container> r3(Container{42U});
147 ASSERT_TRUE(r3);
148 ASSERT_EQ((*r3).value, 42U);
149 (*r3).value = 0U;
150 ASSERT_EQ((*r3).value, 0U);
151 }
152
153 // operator->
TEST(ResultTests,DereferenceOperator)154 TEST(ResultTests, DereferenceOperator) {
155 const Result<Container> r1(Container{42U});
156 ASSERT_TRUE(r1);
157 ASSERT_EQ(r1->value, 42U);
158
159 Result<Container> r2(Container{42U});
160 ASSERT_TRUE(r2);
161 ASSERT_EQ(r2->value, 42U);
162 r2->value = 0U;
163 ASSERT_EQ(r2->value, 0U);
164 }
165
166 // Tests: intended use of Result<T>
167
TEST(ResultTests,ResultTraits)168 TEST(ResultTests, ResultTraits) {
169 ASSERT_TRUE(std::is_move_constructible<Result<uint32_t>>::value);
170 ASSERT_TRUE(std::is_move_assignable<Result<uint32_t>>::value);
171 ASSERT_TRUE(std::is_copy_constructible<Result<uint32_t>>::value);
172 ASSERT_TRUE(std::is_copy_assignable<Result<uint32_t>>::value);
173 }
174
TEST(ResultTests,UnitTypeResult)175 TEST(ResultTests, UnitTypeResult) {
176 Result<Unit> r(Unit{});
177 ASSERT_TRUE(r);
178 }
179
180 struct RefCountData {
181 int ctor; // NOLINT(misc-non-private-member-variables-in-classes)
182 int copy_ctor; // NOLINT(misc-non-private-member-variables-in-classes)
183 int dtor; // NOLINT(misc-non-private-member-variables-in-classes)
184 int move; // NOLINT(misc-non-private-member-variables-in-classes)
185 };
186
187 class RefCountContainer {
188 public:
RefCountContainer(RefCountData & data)189 explicit RefCountContainer(RefCountData& data) : data_(data) {
190 ++data_.ctor;
191 }
192
193 RefCountContainer(RefCountContainer const&) = delete;
194
RefCountContainer(RefCountContainer && rhs)195 RefCountContainer(RefCountContainer&& rhs) noexcept : data_(rhs.data_) {
196 ++data_.copy_ctor;
197 }
198
199 RefCountContainer& operator=(RefCountContainer const&) = delete;
200
operator =(RefCountContainer && rhs)201 RefCountContainer& operator=(RefCountContainer&& rhs) noexcept {
202 data_ = rhs.data_;
203 ++data_.move;
204 return *this;
205 }
206
~RefCountContainer()207 ~RefCountContainer() {
208 ++data_.dtor;
209 }
210
211 private:
212 RefCountData& data_;
213 };
214
TEST(ResultTests,ReferenceCount)215 TEST(ResultTests, ReferenceCount) {
216 ASSERT_TRUE(std::is_move_constructible<RefCountContainer>::value);
217 ASSERT_TRUE(std::is_move_assignable<RefCountContainer>::value);
218 ASSERT_FALSE(std::is_copy_constructible<RefCountContainer>::value);
219 ASSERT_FALSE(std::is_copy_assignable<RefCountContainer>::value);
220
221 RefCountData rc{0, 0, 0, 0};
222 { Result<RefCountContainer> r(RefCountContainer{rc}); }
223 ASSERT_EQ(rc.ctor, 1);
224 ASSERT_EQ(rc.copy_ctor, 1);
225 ASSERT_EQ(rc.move, 0);
226 ASSERT_EQ(rc.dtor, 2);
227 }
228
CreateContainer(bool succeed)229 Result<Container> CreateContainer(bool succeed) {
230 if (!succeed) {
231 return Error("foo");
232 }
233 return Container{42U};
234 }
235
TEST(ResultTests,FunctionReturn)236 TEST(ResultTests, FunctionReturn) {
237 auto r1 = CreateContainer(true);
238 ASSERT_TRUE(r1);
239 ASSERT_EQ(r1->value, 42U);
240
241 auto r2 = CreateContainer(false);
242 ASSERT_FALSE(r2);
243 ASSERT_EQ(r2.GetErrorMessage(), "foo");
244 ASSERT_EQ(r2.GetError().GetMessage(), "foo");
245 }
246
FailToCreateContainer()247 Result<Container> FailToCreateContainer() {
248 auto container = CreateContainer(false);
249 if (!container) {
250 return Error(container.GetError(), "bar");
251 }
252 return container;
253 }
254
TEST(ResultTests,CascadeError)255 TEST(ResultTests, CascadeError) {
256 auto container = FailToCreateContainer();
257 ASSERT_FALSE(container);
258 ASSERT_EQ(container.GetErrorMessage(), "foo -> bar");
259 }
260
261 struct NoCopyContainer {
262 uint32_t value = 0; // NOLINT(misc-non-private-member-variables-in-classes)
263 NoCopyContainer() = default;
264 NoCopyContainer(const NoCopyContainer&) = delete;
265 NoCopyContainer& operator=(const NoCopyContainer&) = delete;
266 };
267
CreateNoCopyContainer(bool succeed)268 Result<std::unique_ptr<NoCopyContainer>> CreateNoCopyContainer(bool succeed) {
269 if (!succeed) {
270 return Error("foo");
271 }
272 std::unique_ptr<NoCopyContainer> p(new NoCopyContainer{});
273 p->value = 42U;
274 return std::move(p);
275 }
276
TEST(ResultTests,UniquePtr)277 TEST(ResultTests, UniquePtr) {
278 auto r1 = CreateNoCopyContainer(true);
279 ASSERT_TRUE(r1);
280 ASSERT_EQ((*r1)->value, 42U);
281 (*r1)->value = 0U;
282 ASSERT_EQ((*r1)->value, 0U);
283
284 auto r2 = CreateNoCopyContainer(false);
285 ASSERT_FALSE(r2);
286 ASSERT_EQ(r2.GetErrorMessage(), "foo");
287 }
288
289 } // namespace android::idmap2
290