tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

cleanup_test.cc (8249B)


      1 // Copyright 2021 The Abseil Authors.
      2 //
      3 // Licensed under the Apache License, Version 2.0 (the "License");
      4 // you may not use this file except in compliance with the License.
      5 // You may obtain a copy of the License at
      6 //
      7 //      https://www.apache.org/licenses/LICENSE-2.0
      8 //
      9 // Unless required by applicable law or agreed to in writing, software
     10 // distributed under the License is distributed on an "AS IS" BASIS,
     11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     12 // See the License for the specific language governing permissions and
     13 // limitations under the License.
     14 
     15 #include "absl/cleanup/cleanup.h"
     16 
     17 #include <functional>
     18 #include <type_traits>
     19 #include <utility>
     20 
     21 #include "gtest/gtest.h"
     22 #include "absl/base/config.h"
     23 #include "absl/utility/utility.h"
     24 
     25 namespace {
     26 
     27 using Tag = absl::cleanup_internal::Tag;
     28 
     29 template <typename Type1, typename Type2>
     30 constexpr bool IsSame() {
     31  return (std::is_same<Type1, Type2>::value);
     32 }
     33 
     34 struct IdentityFactory {
     35  template <typename Callback>
     36  static Callback AsCallback(Callback callback) {
     37    return Callback(std::move(callback));
     38  }
     39 };
     40 
     41 // `FunctorClass` is a type used for testing `absl::Cleanup`. It is intended to
     42 // represent users that make their own move-only callback types outside of
     43 // `std::function` and lambda literals.
     44 class FunctorClass {
     45  using Callback = std::function<void()>;
     46 
     47 public:
     48  explicit FunctorClass(Callback callback) : callback_(std::move(callback)) {}
     49 
     50  FunctorClass(FunctorClass&& other)
     51      : callback_(std::exchange(other.callback_, Callback())) {}
     52 
     53  FunctorClass(const FunctorClass&) = delete;
     54 
     55  FunctorClass& operator=(const FunctorClass&) = delete;
     56 
     57  FunctorClass& operator=(FunctorClass&&) = delete;
     58 
     59  void operator()() const& = delete;
     60 
     61  void operator()() && {
     62    ASSERT_TRUE(callback_);
     63    callback_();
     64    callback_ = nullptr;
     65  }
     66 
     67 private:
     68  Callback callback_;
     69 };
     70 
     71 struct FunctorClassFactory {
     72  template <typename Callback>
     73  static FunctorClass AsCallback(Callback callback) {
     74    return FunctorClass(std::move(callback));
     75  }
     76 };
     77 
     78 struct StdFunctionFactory {
     79  template <typename Callback>
     80  static std::function<void()> AsCallback(Callback callback) {
     81    return std::function<void()>(std::move(callback));
     82  }
     83 };
     84 
     85 using CleanupTestParams =
     86    ::testing::Types<IdentityFactory, FunctorClassFactory, StdFunctionFactory>;
     87 template <typename>
     88 struct CleanupTest : public ::testing::Test {};
     89 TYPED_TEST_SUITE(CleanupTest, CleanupTestParams);
     90 
     91 bool fn_ptr_called = false;
     92 void FnPtrFunction() { fn_ptr_called = true; }
     93 
     94 TYPED_TEST(CleanupTest, FactoryProducesCorrectType) {
     95  {
     96    auto callback = TypeParam::AsCallback([] {});
     97    auto cleanup = absl::MakeCleanup(std::move(callback));
     98 
     99    static_assert(
    100        IsSame<absl::Cleanup<Tag, decltype(callback)>, decltype(cleanup)>(),
    101        "");
    102  }
    103 
    104  {
    105    auto cleanup = absl::MakeCleanup(&FnPtrFunction);
    106 
    107    static_assert(IsSame<absl::Cleanup<Tag, void (*)()>, decltype(cleanup)>(),
    108                  "");
    109  }
    110 
    111  {
    112    auto cleanup = absl::MakeCleanup(FnPtrFunction);
    113 
    114    static_assert(IsSame<absl::Cleanup<Tag, void (*)()>, decltype(cleanup)>(),
    115                  "");
    116  }
    117 }
    118 
    119 TYPED_TEST(CleanupTest, CTADProducesCorrectType) {
    120  {
    121    auto callback = TypeParam::AsCallback([] {});
    122    absl::Cleanup cleanup = std::move(callback);
    123 
    124    static_assert(
    125        IsSame<absl::Cleanup<Tag, decltype(callback)>, decltype(cleanup)>(),
    126        "");
    127  }
    128 
    129  {
    130    absl::Cleanup cleanup = &FnPtrFunction;
    131 
    132    static_assert(IsSame<absl::Cleanup<Tag, void (*)()>, decltype(cleanup)>(),
    133                  "");
    134  }
    135 
    136  {
    137    absl::Cleanup cleanup = FnPtrFunction;
    138 
    139    static_assert(IsSame<absl::Cleanup<Tag, void (*)()>, decltype(cleanup)>(),
    140                  "");
    141  }
    142 }
    143 
    144 TYPED_TEST(CleanupTest, FactoryAndCTADProduceSameType) {
    145  {
    146    auto callback = IdentityFactory::AsCallback([] {});
    147    auto factory_cleanup = absl::MakeCleanup(callback);
    148    absl::Cleanup deduction_cleanup = callback;
    149 
    150    static_assert(
    151        IsSame<decltype(factory_cleanup), decltype(deduction_cleanup)>(), "");
    152  }
    153 
    154  {
    155    auto factory_cleanup =
    156        absl::MakeCleanup(FunctorClassFactory::AsCallback([] {}));
    157    absl::Cleanup deduction_cleanup = FunctorClassFactory::AsCallback([] {});
    158 
    159    static_assert(
    160        IsSame<decltype(factory_cleanup), decltype(deduction_cleanup)>(), "");
    161  }
    162 
    163  {
    164    auto factory_cleanup =
    165        absl::MakeCleanup(StdFunctionFactory::AsCallback([] {}));
    166    absl::Cleanup deduction_cleanup = StdFunctionFactory::AsCallback([] {});
    167 
    168    static_assert(
    169        IsSame<decltype(factory_cleanup), decltype(deduction_cleanup)>(), "");
    170  }
    171 
    172  {
    173    auto factory_cleanup = absl::MakeCleanup(&FnPtrFunction);
    174    absl::Cleanup deduction_cleanup = &FnPtrFunction;
    175 
    176    static_assert(
    177        IsSame<decltype(factory_cleanup), decltype(deduction_cleanup)>(), "");
    178  }
    179 
    180  {
    181    auto factory_cleanup = absl::MakeCleanup(FnPtrFunction);
    182    absl::Cleanup deduction_cleanup = FnPtrFunction;
    183 
    184    static_assert(
    185        IsSame<decltype(factory_cleanup), decltype(deduction_cleanup)>(), "");
    186  }
    187 }
    188 
    189 TYPED_TEST(CleanupTest, BasicUsage) {
    190  bool called = false;
    191 
    192  {
    193    auto cleanup =
    194        absl::MakeCleanup(TypeParam::AsCallback([&called] { called = true; }));
    195    EXPECT_FALSE(called);  // Constructor shouldn't invoke the callback
    196  }
    197 
    198  EXPECT_TRUE(called);  // Destructor should invoke the callback
    199 }
    200 
    201 TYPED_TEST(CleanupTest, BasicUsageWithFunctionPointer) {
    202  fn_ptr_called = false;
    203 
    204  {
    205    auto cleanup = absl::MakeCleanup(TypeParam::AsCallback(&FnPtrFunction));
    206    EXPECT_FALSE(fn_ptr_called);  // Constructor shouldn't invoke the callback
    207  }
    208 
    209  EXPECT_TRUE(fn_ptr_called);  // Destructor should invoke the callback
    210 }
    211 
    212 TYPED_TEST(CleanupTest, Cancel) {
    213  bool called = false;
    214 
    215  {
    216    auto cleanup =
    217        absl::MakeCleanup(TypeParam::AsCallback([&called] { called = true; }));
    218    EXPECT_FALSE(called);  // Constructor shouldn't invoke the callback
    219 
    220    std::move(cleanup).Cancel();
    221    EXPECT_FALSE(called);  // Cancel shouldn't invoke the callback
    222  }
    223 
    224  EXPECT_FALSE(called);  // Destructor shouldn't invoke the callback
    225 }
    226 
    227 TYPED_TEST(CleanupTest, Invoke) {
    228  bool called = false;
    229 
    230  {
    231    auto cleanup =
    232        absl::MakeCleanup(TypeParam::AsCallback([&called] { called = true; }));
    233    EXPECT_FALSE(called);  // Constructor shouldn't invoke the callback
    234 
    235    std::move(cleanup).Invoke();
    236    EXPECT_TRUE(called);  // Invoke should invoke the callback
    237 
    238    called = false;  // Reset tracker before destructor runs
    239  }
    240 
    241  EXPECT_FALSE(called);  // Destructor shouldn't invoke the callback
    242 }
    243 
    244 TYPED_TEST(CleanupTest, Move) {
    245  bool called = false;
    246 
    247  {
    248    auto moved_from_cleanup =
    249        absl::MakeCleanup(TypeParam::AsCallback([&called] { called = true; }));
    250    EXPECT_FALSE(called);  // Constructor shouldn't invoke the callback
    251 
    252    {
    253      auto moved_to_cleanup = std::move(moved_from_cleanup);
    254      EXPECT_FALSE(called);  // Move shouldn't invoke the callback
    255    }
    256 
    257    EXPECT_TRUE(called);  // Destructor should invoke the callback
    258 
    259    called = false;  // Reset tracker before destructor runs
    260  }
    261 
    262  EXPECT_FALSE(called);  // Destructor shouldn't invoke the callback
    263 }
    264 
    265 int DestructionCount = 0;
    266 
    267 struct DestructionCounter {
    268  void operator()() {}
    269 
    270  ~DestructionCounter() { ++DestructionCount; }
    271 };
    272 
    273 TYPED_TEST(CleanupTest, DestructorDestroys) {
    274  {
    275    auto cleanup =
    276        absl::MakeCleanup(TypeParam::AsCallback(DestructionCounter()));
    277    DestructionCount = 0;
    278  }
    279 
    280  EXPECT_EQ(DestructionCount, 1);  // Engaged cleanup destroys
    281 }
    282 
    283 TYPED_TEST(CleanupTest, CancelDestroys) {
    284  {
    285    auto cleanup =
    286        absl::MakeCleanup(TypeParam::AsCallback(DestructionCounter()));
    287    DestructionCount = 0;
    288 
    289    std::move(cleanup).Cancel();
    290    EXPECT_EQ(DestructionCount, 1);  // Cancel destroys
    291  }
    292 
    293  EXPECT_EQ(DestructionCount, 1);  // Canceled cleanup does not double destroy
    294 }
    295 
    296 TYPED_TEST(CleanupTest, InvokeDestroys) {
    297  {
    298    auto cleanup =
    299        absl::MakeCleanup(TypeParam::AsCallback(DestructionCounter()));
    300    DestructionCount = 0;
    301 
    302    std::move(cleanup).Invoke();
    303    EXPECT_EQ(DestructionCount, 1);  // Invoke destroys
    304  }
    305 
    306  EXPECT_EQ(DestructionCount, 1);  // Invoked cleanup does not double destroy
    307 }
    308 
    309 }  // namespace