xref: /aosp_15_r20/external/abseil-cpp/absl/cleanup/cleanup_test.cc (revision 9356374a3709195abf420251b3e825997ff56c0f)
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>
IsSame()30 constexpr bool IsSame() {
31   return (std::is_same<Type1, Type2>::value);
32 }
33 
34 struct IdentityFactory {
35   template <typename Callback>
AsCallback__anone27e19390111::IdentityFactory36   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:
FunctorClass(Callback callback)48   explicit FunctorClass(Callback callback) : callback_(std::move(callback)) {}
49 
FunctorClass(FunctorClass && other)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 
operator ()()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>
AsCallback__anone27e19390111::FunctorClassFactory73   static FunctorClass AsCallback(Callback callback) {
74     return FunctorClass(std::move(callback));
75   }
76 };
77 
78 struct StdFunctionFactory {
79   template <typename Callback>
AsCallback__anone27e19390111::StdFunctionFactory80   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;
FnPtrFunction()92 void FnPtrFunction() { fn_ptr_called = true; }
93 
TYPED_TEST(CleanupTest,FactoryProducesCorrectType)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 #if defined(ABSL_HAVE_CLASS_TEMPLATE_ARGUMENT_DEDUCTION)
TYPED_TEST(CleanupTest,CTADProducesCorrectType)120 TYPED_TEST(CleanupTest, CTADProducesCorrectType) {
121   {
122     auto callback = TypeParam::AsCallback([] {});
123     absl::Cleanup cleanup = std::move(callback);
124 
125     static_assert(
126         IsSame<absl::Cleanup<Tag, decltype(callback)>, decltype(cleanup)>(),
127         "");
128   }
129 
130   {
131     absl::Cleanup cleanup = &FnPtrFunction;
132 
133     static_assert(IsSame<absl::Cleanup<Tag, void (*)()>, decltype(cleanup)>(),
134                   "");
135   }
136 
137   {
138     absl::Cleanup cleanup = FnPtrFunction;
139 
140     static_assert(IsSame<absl::Cleanup<Tag, void (*)()>, decltype(cleanup)>(),
141                   "");
142   }
143 }
144 
TYPED_TEST(CleanupTest,FactoryAndCTADProduceSameType)145 TYPED_TEST(CleanupTest, FactoryAndCTADProduceSameType) {
146   {
147     auto callback = IdentityFactory::AsCallback([] {});
148     auto factory_cleanup = absl::MakeCleanup(callback);
149     absl::Cleanup deduction_cleanup = callback;
150 
151     static_assert(
152         IsSame<decltype(factory_cleanup), decltype(deduction_cleanup)>(), "");
153   }
154 
155   {
156     auto factory_cleanup =
157         absl::MakeCleanup(FunctorClassFactory::AsCallback([] {}));
158     absl::Cleanup deduction_cleanup = FunctorClassFactory::AsCallback([] {});
159 
160     static_assert(
161         IsSame<decltype(factory_cleanup), decltype(deduction_cleanup)>(), "");
162   }
163 
164   {
165     auto factory_cleanup =
166         absl::MakeCleanup(StdFunctionFactory::AsCallback([] {}));
167     absl::Cleanup deduction_cleanup = StdFunctionFactory::AsCallback([] {});
168 
169     static_assert(
170         IsSame<decltype(factory_cleanup), decltype(deduction_cleanup)>(), "");
171   }
172 
173   {
174     auto factory_cleanup = absl::MakeCleanup(&FnPtrFunction);
175     absl::Cleanup deduction_cleanup = &FnPtrFunction;
176 
177     static_assert(
178         IsSame<decltype(factory_cleanup), decltype(deduction_cleanup)>(), "");
179   }
180 
181   {
182     auto factory_cleanup = absl::MakeCleanup(FnPtrFunction);
183     absl::Cleanup deduction_cleanup = FnPtrFunction;
184 
185     static_assert(
186         IsSame<decltype(factory_cleanup), decltype(deduction_cleanup)>(), "");
187   }
188 }
189 #endif  // defined(ABSL_HAVE_CLASS_TEMPLATE_ARGUMENT_DEDUCTION)
190 
TYPED_TEST(CleanupTest,BasicUsage)191 TYPED_TEST(CleanupTest, BasicUsage) {
192   bool called = false;
193 
194   {
195     auto cleanup =
196         absl::MakeCleanup(TypeParam::AsCallback([&called] { called = true; }));
197     EXPECT_FALSE(called);  // Constructor shouldn't invoke the callback
198   }
199 
200   EXPECT_TRUE(called);  // Destructor should invoke the callback
201 }
202 
TYPED_TEST(CleanupTest,BasicUsageWithFunctionPointer)203 TYPED_TEST(CleanupTest, BasicUsageWithFunctionPointer) {
204   fn_ptr_called = false;
205 
206   {
207     auto cleanup = absl::MakeCleanup(TypeParam::AsCallback(&FnPtrFunction));
208     EXPECT_FALSE(fn_ptr_called);  // Constructor shouldn't invoke the callback
209   }
210 
211   EXPECT_TRUE(fn_ptr_called);  // Destructor should invoke the callback
212 }
213 
TYPED_TEST(CleanupTest,Cancel)214 TYPED_TEST(CleanupTest, Cancel) {
215   bool called = false;
216 
217   {
218     auto cleanup =
219         absl::MakeCleanup(TypeParam::AsCallback([&called] { called = true; }));
220     EXPECT_FALSE(called);  // Constructor shouldn't invoke the callback
221 
222     std::move(cleanup).Cancel();
223     EXPECT_FALSE(called);  // Cancel shouldn't invoke the callback
224   }
225 
226   EXPECT_FALSE(called);  // Destructor shouldn't invoke the callback
227 }
228 
TYPED_TEST(CleanupTest,Invoke)229 TYPED_TEST(CleanupTest, Invoke) {
230   bool called = false;
231 
232   {
233     auto cleanup =
234         absl::MakeCleanup(TypeParam::AsCallback([&called] { called = true; }));
235     EXPECT_FALSE(called);  // Constructor shouldn't invoke the callback
236 
237     std::move(cleanup).Invoke();
238     EXPECT_TRUE(called);  // Invoke should invoke the callback
239 
240     called = false;  // Reset tracker before destructor runs
241   }
242 
243   EXPECT_FALSE(called);  // Destructor shouldn't invoke the callback
244 }
245 
TYPED_TEST(CleanupTest,Move)246 TYPED_TEST(CleanupTest, Move) {
247   bool called = false;
248 
249   {
250     auto moved_from_cleanup =
251         absl::MakeCleanup(TypeParam::AsCallback([&called] { called = true; }));
252     EXPECT_FALSE(called);  // Constructor shouldn't invoke the callback
253 
254     {
255       auto moved_to_cleanup = std::move(moved_from_cleanup);
256       EXPECT_FALSE(called);  // Move shouldn't invoke the callback
257     }
258 
259     EXPECT_TRUE(called);  // Destructor should invoke the callback
260 
261     called = false;  // Reset tracker before destructor runs
262   }
263 
264   EXPECT_FALSE(called);  // Destructor shouldn't invoke the callback
265 }
266 
267 int DestructionCount = 0;
268 
269 struct DestructionCounter {
operator ()__anone27e19390111::DestructionCounter270   void operator()() {}
271 
~DestructionCounter__anone27e19390111::DestructionCounter272   ~DestructionCounter() { ++DestructionCount; }
273 };
274 
TYPED_TEST(CleanupTest,DestructorDestroys)275 TYPED_TEST(CleanupTest, DestructorDestroys) {
276   {
277     auto cleanup =
278         absl::MakeCleanup(TypeParam::AsCallback(DestructionCounter()));
279     DestructionCount = 0;
280   }
281 
282   EXPECT_EQ(DestructionCount, 1);  // Engaged cleanup destroys
283 }
284 
TYPED_TEST(CleanupTest,CancelDestroys)285 TYPED_TEST(CleanupTest, CancelDestroys) {
286   {
287     auto cleanup =
288         absl::MakeCleanup(TypeParam::AsCallback(DestructionCounter()));
289     DestructionCount = 0;
290 
291     std::move(cleanup).Cancel();
292     EXPECT_EQ(DestructionCount, 1);  // Cancel destroys
293   }
294 
295   EXPECT_EQ(DestructionCount, 1);  // Canceled cleanup does not double destroy
296 }
297 
TYPED_TEST(CleanupTest,InvokeDestroys)298 TYPED_TEST(CleanupTest, InvokeDestroys) {
299   {
300     auto cleanup =
301         absl::MakeCleanup(TypeParam::AsCallback(DestructionCounter()));
302     DestructionCount = 0;
303 
304     std::move(cleanup).Invoke();
305     EXPECT_EQ(DestructionCount, 1);  // Invoke destroys
306   }
307 
308   EXPECT_EQ(DestructionCount, 1);  // Invoked cleanup does not double destroy
309 }
310 
311 }  // namespace
312