Home | History | Annotate | Download | only in tests
      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