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 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 40 TEST(ResultTests, ErrorCtorFormat) { 41 Error e("%s=0x%08x", "resid", 0x7f010002); 42 ASSERT_EQ(e.GetMessage(), "resid=0x7f010002"); 43 } 44 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&) 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&) 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&&) 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= 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 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() 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* 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-> 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 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 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: 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 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 229 Result<Container> CreateContainer(bool succeed) { 230 if (!succeed) { 231 return Error("foo"); 232 } 233 return Container{42U}; 234 } 235 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 247 Result<Container> FailToCreateContainer() { 248 auto container = CreateContainer(false); 249 if (!container) { 250 return Error(container.GetError(), "bar"); 251 } 252 return container; 253 } 254 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 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 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