• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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;  // NOLINT(misc-non-private-member-variables-in-classes)
263   DISALLOW_COPY_AND_ASSIGN(NoCopyContainer);
264 };
265 
CreateNoCopyContainer(bool succeed)266 Result<std::unique_ptr<NoCopyContainer>> CreateNoCopyContainer(bool succeed) {
267   if (!succeed) {
268     return Error("foo");
269   }
270   std::unique_ptr<NoCopyContainer> p(new NoCopyContainer{0U});
271   p->value = 42U;
272   return std::move(p);
273 }
274 
TEST(ResultTests,UniquePtr)275 TEST(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
288