• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2024 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 <ftl/finalizer.h>
22 #include <gtest/gtest.h>
23 
24 namespace android::test {
25 
26 namespace {
27 
28 struct Counter {
increment_fnandroid::test::__anondcbbe77d0111::Counter29   constexpr auto increment_fn() {
30     return [this] { ++value_; };
31   }
32 
increment_finalizerandroid::test::__anondcbbe77d0111::Counter33   auto increment_finalizer() {
34     return ftl::Finalizer([this] { ++value_; });
35   }
36 
valueandroid::test::__anondcbbe77d0111::Counter37   [[nodiscard]] constexpr auto value() const -> int { return value_; }
38 
39  private:
40   int value_ = 0;
41 };
42 
43 struct CounterPair {
increment_first_fnandroid::test::__anondcbbe77d0111::CounterPair44   constexpr auto increment_first_fn() { return first.increment_fn(); }
increment_second_fnandroid::test::__anondcbbe77d0111::CounterPair45   constexpr auto increment_second_fn() { return second.increment_fn(); }
valuesandroid::test::__anondcbbe77d0111::CounterPair46   [[nodiscard]] constexpr auto values() const -> std::pair<int, int> {
47     return {first.value(), second.value()};
48   }
49 
50  private:
51   Counter first;
52   Counter second;
53 };
54 
55 }  // namespace
56 
TEST(Finalizer,DefaultConstructionAndNoOpDestructionWhenPolymorphicType)57 TEST(Finalizer, DefaultConstructionAndNoOpDestructionWhenPolymorphicType) {
58   ftl::FinalizerStd finalizer1;
59   ftl::FinalizerFtl finalizer2;
60   ftl::FinalizerFtl1 finalizer3;
61   ftl::FinalizerFtl2 finalizer4;
62   ftl::FinalizerFtl3 finalizer5;
63 }
64 
TEST(Finalizer,InvokesTheFunctionOnDestruction)65 TEST(Finalizer, InvokesTheFunctionOnDestruction) {
66   Counter counter;
67   {
68     const auto finalizer = counter.increment_finalizer();
69     EXPECT_EQ(counter.value(), 0);
70   }
71   EXPECT_EQ(counter.value(), 1);
72 }
73 
TEST(Finalizer,InvocationCanBeCanceled)74 TEST(Finalizer, InvocationCanBeCanceled) {
75   Counter counter;
76   {
77     auto finalizer = counter.increment_finalizer();
78     EXPECT_EQ(counter.value(), 0);
79     finalizer.cancel();
80     EXPECT_EQ(counter.value(), 0);
81   }
82   EXPECT_EQ(counter.value(), 0);
83 }
84 
TEST(Finalizer,InvokesTheFunctionOnce)85 TEST(Finalizer, InvokesTheFunctionOnce) {
86   Counter counter;
87   {
88     auto finalizer = counter.increment_finalizer();
89     EXPECT_EQ(counter.value(), 0);
90     finalizer();
91     EXPECT_EQ(counter.value(), 1);
92     finalizer();
93     EXPECT_EQ(counter.value(), 1);
94   }
95   EXPECT_EQ(counter.value(), 1);
96 }
97 
TEST(Finalizer,SelfInvocationIsAllowedAndANoOp)98 TEST(Finalizer, SelfInvocationIsAllowedAndANoOp) {
99   Counter counter;
100   ftl::FinalizerStd finalizer;
101   finalizer = ftl::Finalizer([&]() {
102     counter.increment_fn()();
103     finalizer();  // recursive invocation should do nothing.
104   });
105   EXPECT_EQ(counter.value(), 0);
106   finalizer();
107   EXPECT_EQ(counter.value(), 1);
108 }
109 
TEST(Finalizer,MoveConstruction)110 TEST(Finalizer, MoveConstruction) {
111   Counter counter;
112   {
113     ftl::FinalizerStd outer_finalizer = counter.increment_finalizer();
114     EXPECT_EQ(counter.value(), 0);
115     {
116       ftl::FinalizerStd inner_finalizer = std::move(outer_finalizer);
117       static_assert(std::is_same_v<decltype(inner_finalizer), decltype(outer_finalizer)>);
118       EXPECT_EQ(counter.value(), 0);
119     }
120     EXPECT_EQ(counter.value(), 1);
121   }
122   EXPECT_EQ(counter.value(), 1);
123 }
124 
TEST(Finalizer,MoveConstructionWithImplicitConversion)125 TEST(Finalizer, MoveConstructionWithImplicitConversion) {
126   Counter counter;
127   {
128     auto outer_finalizer = counter.increment_finalizer();
129     EXPECT_EQ(counter.value(), 0);
130     {
131       ftl::FinalizerStd inner_finalizer = std::move(outer_finalizer);
132       static_assert(!std::is_same_v<decltype(inner_finalizer), decltype(outer_finalizer)>);
133       EXPECT_EQ(counter.value(), 0);
134     }
135     EXPECT_EQ(counter.value(), 1);
136   }
137   EXPECT_EQ(counter.value(), 1);
138 }
139 
TEST(Finalizer,MoveAssignment)140 TEST(Finalizer, MoveAssignment) {
141   CounterPair pair;
142   {
143     ftl::FinalizerStd outer_finalizer = ftl::Finalizer(pair.increment_first_fn());
144     EXPECT_EQ(pair.values(), std::make_pair(0, 0));
145 
146     {
147       ftl::FinalizerStd inner_finalizer = ftl::Finalizer(pair.increment_second_fn());
148       static_assert(std::is_same_v<decltype(inner_finalizer), decltype(outer_finalizer)>);
149       EXPECT_EQ(pair.values(), std::make_pair(0, 0));
150       inner_finalizer = std::move(outer_finalizer);
151       EXPECT_EQ(pair.values(), std::make_pair(0, 1));
152     }
153     EXPECT_EQ(pair.values(), std::make_pair(1, 1));
154   }
155   EXPECT_EQ(pair.values(), std::make_pair(1, 1));
156 }
157 
TEST(Finalizer,MoveAssignmentWithImplicitConversion)158 TEST(Finalizer, MoveAssignmentWithImplicitConversion) {
159   CounterPair pair;
160   {
161     auto outer_finalizer = ftl::Finalizer(pair.increment_first_fn());
162     EXPECT_EQ(pair.values(), std::make_pair(0, 0));
163 
164     {
165       ftl::FinalizerStd inner_finalizer = ftl::Finalizer(pair.increment_second_fn());
166       static_assert(!std::is_same_v<decltype(inner_finalizer), decltype(outer_finalizer)>);
167       EXPECT_EQ(pair.values(), std::make_pair(0, 0));
168       inner_finalizer = std::move(outer_finalizer);
169       EXPECT_EQ(pair.values(), std::make_pair(0, 1));
170     }
171     EXPECT_EQ(pair.values(), std::make_pair(1, 1));
172   }
173   EXPECT_EQ(pair.values(), std::make_pair(1, 1));
174 }
175 
TEST(Finalizer,NullifiesTheFunctionWhenInvokedIfPossible)176 TEST(Finalizer, NullifiesTheFunctionWhenInvokedIfPossible) {
177   auto shared = std::make_shared<int>(0);
178   std::weak_ptr<int> weak = shared;
179 
180   int count = 0;
181   {
182     auto lambda = [capture = std::move(shared)]() {};
183     auto finalizer = ftl::Finalizer(std::move(lambda));
184     EXPECT_FALSE(weak.expired());
185 
186     // A lambda is not nullable. Invoking the finalizer cannot destroy it to destroy the lambda's
187     // capture.
188     finalizer();
189     EXPECT_FALSE(weak.expired());
190   }
191   // The lambda is only destroyed when the finalizer instance is destroyed.
192   EXPECT_TRUE(weak.expired());
193 
194   shared = std::make_shared<int>(0);
195   weak = shared;
196 
197   {
198     auto lambda = [capture = std::move(shared)]() {};
199     auto finalizer = ftl::FinalizerStd(std::move(lambda));
200     EXPECT_FALSE(weak.expired());
201 
202     // Since std::function is used, and is nullable, invoking the finalizer will destroy the
203     // contained function, which will destroy the lambda's capture.
204     finalizer();
205     EXPECT_TRUE(weak.expired());
206   }
207 }
208 
209 }  // namespace android::test
210