1 /*
2 * Copyright (C) 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 <audio_utils/DeferredExecutor.h>
18 #include <atomic>
19 #include <gtest/gtest.h>
20
21 // Test object
22 class RunOnClose {
23 public:
24 template <typename F>
RunOnClose(F && f)25 explicit RunOnClose(F&& f) : thunk_(std::forward<F>(f)) {}
26 explicit RunOnClose(RunOnClose&& other) = default;
~RunOnClose()27 ~RunOnClose() { if (thunk_) thunk_(); }
28 private:
29 std::function<void()> thunk_;
30 };
31
TEST(deferredexecutor,basic)32 TEST(deferredexecutor, basic) {
33 std::atomic<int> disposed{};
34 std::atomic<int> deferred{};
35 {
36 android::audio_utils::DeferredExecutor de;
37
38 de.defer([&](){++deferred;});
39 de.dispose(std::make_shared<RunOnClose>([&]{++disposed;}));
40 EXPECT_EQ(0, deferred);
41 EXPECT_EQ(0, disposed);
42 EXPECT_EQ(false, de.empty());
43 de.process();
44 EXPECT_EQ(1, deferred);
45 EXPECT_EQ(1, disposed);
46 EXPECT_EQ(true, de.empty());
47 }
48 EXPECT_EQ(1, deferred);
49 EXPECT_EQ(1, disposed);
50 }
51
TEST(deferredexecutor,clear)52 TEST(deferredexecutor, clear) {
53 std::atomic<int> disposed{};
54 std::atomic<int> deferred{};
55 {
56 android::audio_utils::DeferredExecutor de;
57
58 de.defer([&](){++deferred;});
59 de.dispose(std::make_shared<RunOnClose>([&]{++disposed;}));
60 EXPECT_EQ(0, deferred);
61 EXPECT_EQ(0, disposed);
62 EXPECT_EQ(false, de.empty());
63 de.clear();
64 EXPECT_EQ(0, deferred);
65 EXPECT_EQ(1, disposed);
66 EXPECT_EQ(true, de.empty());
67 }
68 EXPECT_EQ(0, deferred);
69 EXPECT_EQ(1, disposed);
70 }
71
72 class DtorAndRecursive : public testing::TestWithParam<std::tuple<bool, bool>> {};
73
TEST_P(DtorAndRecursive,deferred_adds_deferred)74 TEST_P(DtorAndRecursive, deferred_adds_deferred) {
75 const auto [processInDtor, recursive] = GetParam();
76 std::atomic<int> disposed{};
77 std::atomic<int> deferred{};
78 {
79 android::audio_utils::DeferredExecutor de(processInDtor);
80
81 // The deferred action adds another deferred action.
82 de.defer([&](){ de.defer([&](){++deferred;}); ++deferred;});
83 de.dispose(std::make_shared<RunOnClose>([&]{++disposed;}));
84 EXPECT_EQ(0, deferred);
85 EXPECT_EQ(0, disposed);
86 EXPECT_EQ(false, de.empty());
87 de.process(recursive);
88 EXPECT_EQ(1 + recursive, deferred);
89 EXPECT_EQ(1, disposed);
90 EXPECT_EQ(recursive, de.empty());
91 }
92 EXPECT_EQ(1 + (recursive || processInDtor), deferred);
93 EXPECT_EQ(1, disposed);
94 }
95
__anon0d4bc96f0802(const auto& param) 96 static const auto paramToString = [](const auto& param) {
97 const auto [processInDtor, recursive] = param.param;
98 return std::string("processInDtor_")
99 .append(processInDtor ? "true" : "false")
100 .append("__recursive_")
101 .append(recursive ? "true" : "false");
102 };
103
104 INSTANTIATE_TEST_SUITE_P(DeferredExecutorSuite,
105 DtorAndRecursive,
106 testing::Combine(testing::Bool(), testing::Bool()),
107 paramToString);
108