blob: d82f0c475ea96677fc658e9329eca39db92d53c1 [file] [log] [blame]
MÃ¥rten Kongstad1e99b172019-01-28 08:49:12 +01001/*
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
24#include "idmap2/Result.h"
25
26namespace android::idmap2 {
27
28struct Container {
29 uint32_t value; // NOLINT(misc-non-private-member-variables-in-classes)
30};
31
32// Tests: Error
33
34TEST(ResultTests, ErrorTraits) {
35 ASSERT_TRUE(std::is_move_constructible<v2::Error>::value);
36 ASSERT_TRUE(std::is_move_assignable<v2::Error>::value);
37 ASSERT_TRUE(std::is_copy_constructible<v2::Error>::value);
38 ASSERT_TRUE(std::is_copy_assignable<v2::Error>::value);
39}
40
41TEST(ResultTests, ErrorCtorFormat) {
42 v2::Error e("%s=0x%08x", "resid", 0x7f010002);
43 ASSERT_EQ(e.GetMessage(), "resid=0x7f010002");
44}
45
46TEST(ResultTests, ErrorPropagateParent) {
47 v2::Error e1("foo");
48 ASSERT_EQ(e1.GetMessage(), "foo");
49
50 v2::Error e2(e1, "bar");
51 ASSERT_EQ(e2.GetMessage(), "foo -> bar");
52
53 v2::Error e3(e2); // NOLINT(performance-unnecessary-copy-initialization)
54 ASSERT_EQ(e3.GetMessage(), "foo -> bar");
55
56 v2::Error e4(e3, "%02d", 1);
57 ASSERT_EQ(e4.GetMessage(), "foo -> bar -> 01");
58}
59
60// Tests: Result<T> member functions
61
62// Result(const Result&)
63TEST(ResultTests, CopyConstructor) {
64 v2::Result<uint32_t> r1(42U);
65
66 v2::Result<uint32_t> r2(r1);
67 ASSERT_TRUE(r2);
68 ASSERT_EQ(*r2, 42U);
69
70 v2::Result<uint32_t> r3 = r2;
71 ASSERT_TRUE(r3);
72 ASSERT_EQ(*r3, 42U);
73}
74
75// Result(const T&)
76TEST(ResultTests, Constructor) {
77 uint32_t v = 42U;
78 v2::Result<uint32_t> r1(v);
79 ASSERT_TRUE(r1);
80 ASSERT_EQ(*r1, 42U);
81
82 v2::Error e("foo");
83 v2::Result<uint32_t> r2(e);
84 ASSERT_FALSE(r2);
85 ASSERT_EQ(r2.GetErrorMessage(), "foo");
86}
87
88// Result(const T&&)
89TEST(ResultTests, MoveConstructor) {
90 v2::Result<uint32_t> r1(42U);
91 ASSERT_TRUE(r1);
92 ASSERT_EQ(*r1, 42U);
93
94 v2::Result<uint32_t> r2(v2::Error("foo"));
95 ASSERT_FALSE(r2);
96 ASSERT_EQ(r2.GetErrorMessage(), "foo");
97}
98
99// operator=
100TEST(ResultTests, CopyAssignmentOperator) {
101 // note: 'Result<...> r2 = r1;' calls the copy ctor
102 v2::Result<uint32_t> r1(42U);
103 v2::Result<uint32_t> r2(0U);
104 r2 = r1;
105 ASSERT_TRUE(r2);
106 ASSERT_EQ(*r2, 42U);
107
108 v2::Result<uint32_t> r3(v2::Error("foo"));
109 r2 = r3;
110 ASSERT_FALSE(r2);
111 ASSERT_EQ(r2.GetErrorMessage(), "foo");
112}
113
114TEST(ResultTests, MoveAssignmentOperator) {
115 v2::Result<uint32_t> r(0U);
116 r = v2::Result<uint32_t>(42U);
117 ASSERT_TRUE(r);
118 ASSERT_EQ(*r, 42U);
119
120 r = v2::Result<uint32_t>(v2::Error("foo"));
121 ASSERT_FALSE(r);
122 ASSERT_EQ(r.GetErrorMessage(), "foo");
123}
124
125// operator bool()
126TEST(ResultTests, BoolOperator) {
127 v2::Result<uint32_t> r1(42U);
128 ASSERT_TRUE(r1);
129 ASSERT_EQ(*r1, 42U);
130
131 v2::Result<uint32_t> r2(v2::Error("foo"));
132 ASSERT_FALSE(r2);
133 ASSERT_EQ(r2.GetErrorMessage(), "foo");
134}
135
136// operator*
137TEST(ResultTests, IndirectionOperator) {
138 const v2::Result<uint32_t> r1(42U);
139 ASSERT_TRUE(r1);
140 ASSERT_EQ(*r1, 42U);
141
142 const v2::Result<Container> r2(Container{42U});
143 ASSERT_TRUE(r2);
144 const Container& c = *r2;
145 ASSERT_EQ(c.value, 42U);
146
147 v2::Result<Container> r3(Container{42U});
148 ASSERT_TRUE(r3);
149 ASSERT_EQ((*r3).value, 42U);
150 (*r3).value = 0U;
151 ASSERT_EQ((*r3).value, 0U);
152}
153
154// operator->
155TEST(ResultTests, DereferenceOperator) {
156 const v2::Result<Container> r1(Container{42U});
157 ASSERT_TRUE(r1);
158 ASSERT_EQ(r1->value, 42U);
159
160 v2::Result<Container> r2(Container{42U});
161 ASSERT_TRUE(r2);
162 ASSERT_EQ(r2->value, 42U);
163 r2->value = 0U;
164 ASSERT_EQ(r2->value, 0U);
165}
166
167// Tests: intended use of Result<T>
168
169TEST(ResultTests, ResultTraits) {
170 ASSERT_TRUE(std::is_move_constructible<v2::Result<uint32_t>>::value);
171 ASSERT_TRUE(std::is_move_assignable<v2::Result<uint32_t>>::value);
172 ASSERT_TRUE(std::is_copy_constructible<v2::Result<uint32_t>>::value);
173 ASSERT_TRUE(std::is_copy_assignable<v2::Result<uint32_t>>::value);
174}
175
176TEST(ResultTests, UnitTypeResult) {
177 v2::Result<v2::Unit> r(v2::Unit{});
178 ASSERT_TRUE(r);
179}
180
181struct RefCountData {
182 int ctor; // NOLINT(misc-non-private-member-variables-in-classes)
183 int copy_ctor; // NOLINT(misc-non-private-member-variables-in-classes)
184 int dtor; // NOLINT(misc-non-private-member-variables-in-classes)
185 int move; // NOLINT(misc-non-private-member-variables-in-classes)
186};
187
188class RefCountContainer {
189 public:
190 explicit RefCountContainer(RefCountData& data) : data_(data) {
191 ++data_.ctor;
192 }
193
194 RefCountContainer(RefCountContainer const&) = delete;
195
196 RefCountContainer(RefCountContainer&& rhs) noexcept : data_(rhs.data_) {
197 ++data_.copy_ctor;
198 }
199
200 RefCountContainer& operator=(RefCountContainer const&) = delete;
201
202 RefCountContainer& operator=(RefCountContainer&& rhs) noexcept {
203 data_ = rhs.data_;
204 ++data_.move;
205 return *this;
206 }
207
208 ~RefCountContainer() {
209 ++data_.dtor;
210 }
211
212 private:
213 RefCountData& data_;
214};
215
216TEST(ResultTests, ReferenceCount) {
217 ASSERT_TRUE(std::is_move_constructible<RefCountContainer>::value);
218 ASSERT_TRUE(std::is_move_assignable<RefCountContainer>::value);
219 ASSERT_FALSE(std::is_copy_constructible<RefCountContainer>::value);
220 ASSERT_FALSE(std::is_copy_assignable<RefCountContainer>::value);
221
222 RefCountData rc{0, 0, 0, 0};
223 { v2::Result<RefCountContainer> r(RefCountContainer{rc}); }
224 ASSERT_EQ(rc.ctor, 1);
225 ASSERT_EQ(rc.copy_ctor, 1);
226 ASSERT_EQ(rc.move, 0);
227 ASSERT_EQ(rc.dtor, 2);
228}
229
230v2::Result<Container> CreateContainer(bool succeed) {
231 if (!succeed) {
232 return v2::Error("foo");
233 }
234 return Container{42U};
235}
236
237TEST(ResultTests, FunctionReturn) {
238 auto r1 = CreateContainer(true);
239 ASSERT_TRUE(r1);
240 ASSERT_EQ(r1->value, 42U);
241
242 auto r2 = CreateContainer(false);
243 ASSERT_FALSE(r2);
244 ASSERT_EQ(r2.GetErrorMessage(), "foo");
245 ASSERT_EQ(r2.GetError().GetMessage(), "foo");
246}
247
248v2::Result<Container> FailToCreateContainer() {
249 auto container = CreateContainer(false);
250 if (!container) {
251 return v2::Error(container.GetError(), "bar");
252 }
253 return container;
254}
255
256TEST(ResultTests, CascadeError) {
257 auto container = FailToCreateContainer();
258 ASSERT_FALSE(container);
259 ASSERT_EQ(container.GetErrorMessage(), "foo -> bar");
260}
261
262struct NoCopyContainer {
263 uint32_t value; // NOLINT(misc-non-private-member-variables-in-classes)
264 DISALLOW_COPY_AND_ASSIGN(NoCopyContainer);
265};
266
267v2::Result<std::unique_ptr<NoCopyContainer>> CreateNoCopyContainer(bool succeed) {
268 if (!succeed) {
269 return v2::Error("foo");
270 }
271 std::unique_ptr<NoCopyContainer> p(new NoCopyContainer{0U});
272 p->value = 42U;
273 return std::move(p);
274}
275
276TEST(ResultTests, UniquePtr) {
277 auto r1 = CreateNoCopyContainer(true);
278 ASSERT_TRUE(r1);
279 ASSERT_EQ((*r1)->value, 42U);
280 (*r1)->value = 0U;
281 ASSERT_EQ((*r1)->value, 0U);
282
283 auto r2 = CreateNoCopyContainer(false);
284 ASSERT_FALSE(r2);
285 ASSERT_EQ(r2.GetErrorMessage(), "foo");
286}
287
288} // namespace android::idmap2