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