blob: cbced0ae32fb76caec9f3ad3e19083f137809af9 [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"
Mårten Kongstad1e99b172019-01-28 08:49:12 +010023#include "idmap2/Result.h"
24
25namespace android::idmap2 {
26
27struct Container {
28 uint32_t value; // NOLINT(misc-non-private-member-variables-in-classes)
29};
30
31// Tests: Error
32
33TEST(ResultTests, ErrorTraits) {
Mårten Kongstad49d835d2019-01-31 10:50:48 +010034 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);
Mårten Kongstad1e99b172019-01-28 08:49:12 +010038}
39
40TEST(ResultTests, ErrorCtorFormat) {
Mårten Kongstad49d835d2019-01-31 10:50:48 +010041 Error e("%s=0x%08x", "resid", 0x7f010002);
Mårten Kongstad1e99b172019-01-28 08:49:12 +010042 ASSERT_EQ(e.GetMessage(), "resid=0x7f010002");
43}
44
45TEST(ResultTests, ErrorPropagateParent) {
Mårten Kongstad49d835d2019-01-31 10:50:48 +010046 Error e1("foo");
Mårten Kongstad1e99b172019-01-28 08:49:12 +010047 ASSERT_EQ(e1.GetMessage(), "foo");
48
Mårten Kongstad49d835d2019-01-31 10:50:48 +010049 Error e2(e1, "bar");
Mårten Kongstad1e99b172019-01-28 08:49:12 +010050 ASSERT_EQ(e2.GetMessage(), "foo -> bar");
51
Mårten Kongstad49d835d2019-01-31 10:50:48 +010052 Error e3(e2); // NOLINT(performance-unnecessary-copy-initialization)
Mårten Kongstad1e99b172019-01-28 08:49:12 +010053 ASSERT_EQ(e3.GetMessage(), "foo -> bar");
54
Mårten Kongstad49d835d2019-01-31 10:50:48 +010055 Error e4(e3, "%02d", 1);
Mårten Kongstad1e99b172019-01-28 08:49:12 +010056 ASSERT_EQ(e4.GetMessage(), "foo -> bar -> 01");
57}
58
59// Tests: Result<T> member functions
60
61// Result(const Result&)
62TEST(ResultTests, CopyConstructor) {
Mårten Kongstad49d835d2019-01-31 10:50:48 +010063 Result<uint32_t> r1(42U);
Mårten Kongstad1e99b172019-01-28 08:49:12 +010064
Mårten Kongstad49d835d2019-01-31 10:50:48 +010065 Result<uint32_t> r2(r1);
Mårten Kongstad1e99b172019-01-28 08:49:12 +010066 ASSERT_TRUE(r2);
67 ASSERT_EQ(*r2, 42U);
68
Mårten Kongstad49d835d2019-01-31 10:50:48 +010069 Result<uint32_t> r3 = r2;
Mårten Kongstad1e99b172019-01-28 08:49:12 +010070 ASSERT_TRUE(r3);
71 ASSERT_EQ(*r3, 42U);
72}
73
74// Result(const T&)
75TEST(ResultTests, Constructor) {
76 uint32_t v = 42U;
Mårten Kongstad49d835d2019-01-31 10:50:48 +010077 Result<uint32_t> r1(v);
Mårten Kongstad1e99b172019-01-28 08:49:12 +010078 ASSERT_TRUE(r1);
79 ASSERT_EQ(*r1, 42U);
80
Mårten Kongstad49d835d2019-01-31 10:50:48 +010081 Error e("foo");
82 Result<uint32_t> r2(e);
Mårten Kongstad1e99b172019-01-28 08:49:12 +010083 ASSERT_FALSE(r2);
84 ASSERT_EQ(r2.GetErrorMessage(), "foo");
85}
86
87// Result(const T&&)
88TEST(ResultTests, MoveConstructor) {
Mårten Kongstad49d835d2019-01-31 10:50:48 +010089 Result<uint32_t> r1(42U);
Mårten Kongstad1e99b172019-01-28 08:49:12 +010090 ASSERT_TRUE(r1);
91 ASSERT_EQ(*r1, 42U);
92
Mårten Kongstad49d835d2019-01-31 10:50:48 +010093 Result<uint32_t> r2(Error("foo"));
Mårten Kongstad1e99b172019-01-28 08:49:12 +010094 ASSERT_FALSE(r2);
95 ASSERT_EQ(r2.GetErrorMessage(), "foo");
96}
97
98// operator=
99TEST(ResultTests, CopyAssignmentOperator) {
100 // note: 'Result<...> r2 = r1;' calls the copy ctor
Mårten Kongstad49d835d2019-01-31 10:50:48 +0100101 Result<uint32_t> r1(42U);
102 Result<uint32_t> r2(0U);
Mårten Kongstad1e99b172019-01-28 08:49:12 +0100103 r2 = r1;
104 ASSERT_TRUE(r2);
105 ASSERT_EQ(*r2, 42U);
106
Mårten Kongstad49d835d2019-01-31 10:50:48 +0100107 Result<uint32_t> r3(Error("foo"));
Mårten Kongstad1e99b172019-01-28 08:49:12 +0100108 r2 = r3;
109 ASSERT_FALSE(r2);
110 ASSERT_EQ(r2.GetErrorMessage(), "foo");
111}
112
113TEST(ResultTests, MoveAssignmentOperator) {
Mårten Kongstad49d835d2019-01-31 10:50:48 +0100114 Result<uint32_t> r(0U);
115 r = Result<uint32_t>(42U);
Mårten Kongstad1e99b172019-01-28 08:49:12 +0100116 ASSERT_TRUE(r);
117 ASSERT_EQ(*r, 42U);
118
Mårten Kongstad49d835d2019-01-31 10:50:48 +0100119 r = Result<uint32_t>(Error("foo"));
Mårten Kongstad1e99b172019-01-28 08:49:12 +0100120 ASSERT_FALSE(r);
121 ASSERT_EQ(r.GetErrorMessage(), "foo");
122}
123
124// operator bool()
125TEST(ResultTests, BoolOperator) {
Mårten Kongstad49d835d2019-01-31 10:50:48 +0100126 Result<uint32_t> r1(42U);
Mårten Kongstad1e99b172019-01-28 08:49:12 +0100127 ASSERT_TRUE(r1);
128 ASSERT_EQ(*r1, 42U);
129
Mårten Kongstad49d835d2019-01-31 10:50:48 +0100130 Result<uint32_t> r2(Error("foo"));
Mårten Kongstad1e99b172019-01-28 08:49:12 +0100131 ASSERT_FALSE(r2);
132 ASSERT_EQ(r2.GetErrorMessage(), "foo");
133}
134
135// operator*
136TEST(ResultTests, IndirectionOperator) {
Mårten Kongstad49d835d2019-01-31 10:50:48 +0100137 const Result<uint32_t> r1(42U);
Mårten Kongstad1e99b172019-01-28 08:49:12 +0100138 ASSERT_TRUE(r1);
139 ASSERT_EQ(*r1, 42U);
140
Mårten Kongstad49d835d2019-01-31 10:50:48 +0100141 const Result<Container> r2(Container{42U});
Mårten Kongstad1e99b172019-01-28 08:49:12 +0100142 ASSERT_TRUE(r2);
143 const Container& c = *r2;
144 ASSERT_EQ(c.value, 42U);
145
Mårten Kongstad49d835d2019-01-31 10:50:48 +0100146 Result<Container> r3(Container{42U});
Mårten Kongstad1e99b172019-01-28 08:49:12 +0100147 ASSERT_TRUE(r3);
148 ASSERT_EQ((*r3).value, 42U);
149 (*r3).value = 0U;
150 ASSERT_EQ((*r3).value, 0U);
151}
152
153// operator->
154TEST(ResultTests, DereferenceOperator) {
Mårten Kongstad49d835d2019-01-31 10:50:48 +0100155 const Result<Container> r1(Container{42U});
Mårten Kongstad1e99b172019-01-28 08:49:12 +0100156 ASSERT_TRUE(r1);
157 ASSERT_EQ(r1->value, 42U);
158
Mårten Kongstad49d835d2019-01-31 10:50:48 +0100159 Result<Container> r2(Container{42U});
Mårten Kongstad1e99b172019-01-28 08:49:12 +0100160 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
168TEST(ResultTests, ResultTraits) {
Mårten Kongstad49d835d2019-01-31 10:50:48 +0100169 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);
Mårten Kongstad1e99b172019-01-28 08:49:12 +0100173}
174
175TEST(ResultTests, UnitTypeResult) {
Mårten Kongstad49d835d2019-01-31 10:50:48 +0100176 Result<Unit> r(Unit{});
Mårten Kongstad1e99b172019-01-28 08:49:12 +0100177 ASSERT_TRUE(r);
178}
179
180struct 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
187class RefCountContainer {
188 public:
189 explicit RefCountContainer(RefCountData& data) : data_(data) {
190 ++data_.ctor;
191 }
192
193 RefCountContainer(RefCountContainer const&) = delete;
194
195 RefCountContainer(RefCountContainer&& rhs) noexcept : data_(rhs.data_) {
196 ++data_.copy_ctor;
197 }
198
199 RefCountContainer& operator=(RefCountContainer const&) = delete;
200
201 RefCountContainer& operator=(RefCountContainer&& rhs) noexcept {
202 data_ = rhs.data_;
203 ++data_.move;
204 return *this;
205 }
206
207 ~RefCountContainer() {
208 ++data_.dtor;
209 }
210
211 private:
212 RefCountData& data_;
213};
214
215TEST(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};
Mårten Kongstad49d835d2019-01-31 10:50:48 +0100222 { Result<RefCountContainer> r(RefCountContainer{rc}); }
Mårten Kongstad1e99b172019-01-28 08:49:12 +0100223 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
Mårten Kongstad49d835d2019-01-31 10:50:48 +0100229Result<Container> CreateContainer(bool succeed) {
Mårten Kongstad1e99b172019-01-28 08:49:12 +0100230 if (!succeed) {
Mårten Kongstad49d835d2019-01-31 10:50:48 +0100231 return Error("foo");
Mårten Kongstad1e99b172019-01-28 08:49:12 +0100232 }
233 return Container{42U};
234}
235
236TEST(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
Mårten Kongstad49d835d2019-01-31 10:50:48 +0100247Result<Container> FailToCreateContainer() {
Mårten Kongstad1e99b172019-01-28 08:49:12 +0100248 auto container = CreateContainer(false);
249 if (!container) {
Mårten Kongstad49d835d2019-01-31 10:50:48 +0100250 return Error(container.GetError(), "bar");
Mårten Kongstad1e99b172019-01-28 08:49:12 +0100251 }
252 return container;
253}
254
255TEST(ResultTests, CascadeError) {
256 auto container = FailToCreateContainer();
257 ASSERT_FALSE(container);
258 ASSERT_EQ(container.GetErrorMessage(), "foo -> bar");
259}
260
261struct NoCopyContainer {
262 uint32_t value; // NOLINT(misc-non-private-member-variables-in-classes)
263 DISALLOW_COPY_AND_ASSIGN(NoCopyContainer);
264};
265
Mårten Kongstad49d835d2019-01-31 10:50:48 +0100266Result<std::unique_ptr<NoCopyContainer>> CreateNoCopyContainer(bool succeed) {
Mårten Kongstad1e99b172019-01-28 08:49:12 +0100267 if (!succeed) {
Mårten Kongstad49d835d2019-01-31 10:50:48 +0100268 return Error("foo");
Mårten Kongstad1e99b172019-01-28 08:49:12 +0100269 }
270 std::unique_ptr<NoCopyContainer> p(new NoCopyContainer{0U});
271 p->value = 42U;
272 return std::move(p);
273}
274
275TEST(ResultTests, UniquePtr) {
276 auto r1 = CreateNoCopyContainer(true);
277 ASSERT_TRUE(r1);
278 ASSERT_EQ((*r1)->value, 42U);
279 (*r1)->value = 0U;
280 ASSERT_EQ((*r1)->value, 0U);
281
282 auto r2 = CreateNoCopyContainer(false);
283 ASSERT_FALSE(r2);
284 ASSERT_EQ(r2.GetErrorMessage(), "foo");
285}
286
287} // namespace android::idmap2