1 // Copyright 2024 The Pigweed Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // 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, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14
15 #include "pw_bluetooth_sapphire/fuchsia/lib/fidl/hanging_getter.h"
16
17 #include <gtest/gtest.h>
18
19 namespace bt_lib_fidl {
20 namespace {
21
22 template <typename T, typename Getter = HangingGetter<T>>
23 class HangingGetterTestBase : public ::testing::Test {
24 public:
Watch()25 void Watch() {
26 getter_.Watch([this](T value) {
27 callback_count_++;
28 last_value_ = value;
29 });
30 }
31
callback_count() const32 int callback_count() const { return callback_count_; }
last_value() const33 const std::optional<T>& last_value() const { return last_value_; }
34
getter()35 Getter* getter() { return &getter_; }
36
37 private:
38 int callback_count_ = 0;
39 std::optional<T> last_value_;
40 Getter getter_;
41 };
42
43 using HangingGetterTest = HangingGetterTestBase<bool>;
44
TEST_F(HangingGetterTest,Armed)45 TEST_F(HangingGetterTest, Armed) {
46 EXPECT_FALSE(getter()->armed());
47 Watch();
48 EXPECT_TRUE(getter()->armed());
49 }
50
TEST_F(HangingGetterTest,WatchFailsWhilePending)51 TEST_F(HangingGetterTest, WatchFailsWhilePending) {
52 Watch();
53 EXPECT_EQ(0, callback_count());
54 Watch();
55 EXPECT_EQ(0, callback_count());
56 }
57
TEST_F(HangingGetterTest,WatchCallbackDeferredWithoutAValue)58 TEST_F(HangingGetterTest, WatchCallbackDeferredWithoutAValue) {
59 Watch();
60 EXPECT_EQ(0, callback_count());
61 EXPECT_FALSE(last_value().has_value());
62
63 getter()->Set(false);
64 EXPECT_EQ(1, callback_count());
65 ASSERT_TRUE(last_value().has_value());
66 EXPECT_FALSE(*last_value());
67 }
68
TEST_F(HangingGetterTest,WatchCallbackRunsRightAwayWithAValue)69 TEST_F(HangingGetterTest, WatchCallbackRunsRightAwayWithAValue) {
70 getter()->Set(false);
71 EXPECT_EQ(0, callback_count());
72 EXPECT_FALSE(last_value().has_value());
73
74 // Assign the value again to test that the latest value is returned in
75 // Watch().
76 getter()->Set(true);
77 EXPECT_EQ(0, callback_count());
78 EXPECT_FALSE(last_value().has_value());
79 EXPECT_FALSE(getter()->armed());
80
81 Watch();
82 EXPECT_EQ(1, callback_count());
83 ASSERT_TRUE(last_value().has_value());
84 EXPECT_TRUE(*last_value());
85
86 // Calling Watch() again should succeed and defer the callback.
87 Watch();
88 EXPECT_EQ(1, callback_count());
89 }
90
TEST_F(HangingGetterTest,MultipleWatchersPending)91 TEST_F(HangingGetterTest, MultipleWatchersPending) {
92 Watch(); // 1
93 Watch(); // 2
94 Watch(); // 3
95 getter()->Set(true);
96 EXPECT_EQ(3, callback_count());
97 ASSERT_TRUE(last_value().has_value());
98 EXPECT_TRUE(*last_value());
99 EXPECT_FALSE(getter()->armed());
100 }
101
TEST_F(HangingGetterTest,OnlyFirstOfManyWatchersRunsWithAValue)102 TEST_F(HangingGetterTest, OnlyFirstOfManyWatchersRunsWithAValue) {
103 getter()->Set(true);
104
105 // Only the first watch call should result in a callback. The following two
106 // are expected to remain pending until a new value gets assigned.
107 Watch(); // 1
108 Watch(); // 2
109 Watch(); // 3
110 EXPECT_EQ(1, callback_count());
111 ASSERT_TRUE(last_value().has_value());
112 EXPECT_TRUE(*last_value());
113
114 EXPECT_TRUE(getter()->armed());
115 getter()->Set(false);
116 EXPECT_EQ(3, callback_count());
117 ASSERT_TRUE(last_value().has_value());
118 EXPECT_FALSE(*last_value());
119 }
120
TEST_F(HangingGetterTest,WatchClearsExistingValue)121 TEST_F(HangingGetterTest, WatchClearsExistingValue) {
122 getter()->Set(true);
123 Watch();
124 EXPECT_EQ(1, callback_count());
125 ASSERT_TRUE(last_value().has_value());
126 EXPECT_TRUE(*last_value());
127
128 // Callback should be deferred.
129 Watch();
130 EXPECT_EQ(1, callback_count());
131
132 // Test the deferral.
133 getter()->Set(true);
134 EXPECT_EQ(2, callback_count());
135 }
136
TEST_F(HangingGetterTest,Transform)137 TEST_F(HangingGetterTest, Transform) {
138 getter()->Set(false);
139 getter()->Transform([](bool current) {
140 EXPECT_FALSE(current);
141 return true;
142 });
143
144 Watch();
145 EXPECT_EQ(1, callback_count());
146 ASSERT_TRUE(last_value().has_value());
147 EXPECT_TRUE(*last_value());
148 }
149
150 using HangingVectorGetterTest =
151 HangingGetterTestBase<std::vector<bool>, HangingVectorGetter<bool>>;
152
TEST_F(HangingVectorGetterTest,AddAndWatch)153 TEST_F(HangingVectorGetterTest, AddAndWatch) {
154 getter()->Add(false);
155 getter()->Add(true);
156
157 Watch();
158 EXPECT_EQ(1, callback_count());
159 EXPECT_TRUE(last_value().has_value());
160 EXPECT_EQ(2u, last_value()->size());
161 EXPECT_FALSE((*last_value())[0]);
162 EXPECT_TRUE((*last_value())[1]);
163 }
164
TEST_F(HangingVectorGetterTest,WatchAndAdd)165 TEST_F(HangingVectorGetterTest, WatchAndAdd) {
166 Watch();
167 EXPECT_EQ(0, callback_count());
168
169 getter()->Add(true);
170 EXPECT_EQ(1, callback_count());
171 EXPECT_TRUE(last_value().has_value());
172 EXPECT_EQ(1u, last_value()->size());
173 EXPECT_TRUE((*last_value())[0]);
174 }
175
176 } // namespace
177 } // namespace bt_lib_fidl
178