1 // Copyright 2021 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "base/test/repeating_test_future.h"
6
7 #include "base/task/single_thread_task_runner.h"
8 #include "base/test/bind.h"
9 #include "base/test/gtest_util.h"
10 #include "base/test/task_environment.h"
11 #include "testing/gtest/include/gtest/gtest-spi.h"
12 #include "testing/gtest/include/gtest/gtest.h"
13
14 namespace base::test {
15
16 namespace {
17
18 struct MoveOnlyValue {
19 public:
20 MoveOnlyValue() = default;
MoveOnlyValuebase::test::__anon8ae5ce050111::MoveOnlyValue21 explicit MoveOnlyValue(std::string data) : data(std::move(data)) {}
22 MoveOnlyValue(const MoveOnlyValue&) = delete;
23 auto& operator=(const MoveOnlyValue&) = delete;
24 MoveOnlyValue(MoveOnlyValue&&) = default;
25 MoveOnlyValue& operator=(MoveOnlyValue&&) = default;
26 ~MoveOnlyValue() = default;
27
28 std::string data;
29 };
30
31 } // namespace
32
33 class RepeatingTestFutureTest : public ::testing::Test {
34 public:
35 RepeatingTestFutureTest() = default;
36 RepeatingTestFutureTest(const RepeatingTestFutureTest&) = delete;
37 RepeatingTestFutureTest& operator=(const RepeatingTestFutureTest&) = delete;
38 ~RepeatingTestFutureTest() override = default;
39
RunLater(OnceClosure callable)40 void RunLater(OnceClosure callable) {
41 SingleThreadTaskRunner::GetCurrentDefault()->PostTask(FROM_HERE,
42 std::move(callable));
43 }
44
45 private:
46 test::SingleThreadTaskEnvironment environment_;
47 };
48
TEST_F(RepeatingTestFutureTest,ShouldBeEmptyInitially)49 TEST_F(RepeatingTestFutureTest, ShouldBeEmptyInitially) {
50 RepeatingTestFuture<std::string> future;
51
52 EXPECT_TRUE(future.IsEmpty());
53 }
54
TEST_F(RepeatingTestFutureTest,ShouldNotBeEmptyAfterAddingAValue)55 TEST_F(RepeatingTestFutureTest, ShouldNotBeEmptyAfterAddingAValue) {
56 RepeatingTestFuture<std::string> future;
57
58 future.AddValue("a value");
59
60 EXPECT_FALSE(future.IsEmpty());
61 }
62
TEST_F(RepeatingTestFutureTest,ShouldBeEmptyAfterTakingTheOnlyElement)63 TEST_F(RepeatingTestFutureTest, ShouldBeEmptyAfterTakingTheOnlyElement) {
64 RepeatingTestFuture<std::string> future;
65
66 future.AddValue("a value");
67 future.Take();
68
69 EXPECT_TRUE(future.IsEmpty());
70 }
71
TEST_F(RepeatingTestFutureTest,ShouldNotBeEmptyIfTakingOneElementFromAfutureWith2Elements)72 TEST_F(RepeatingTestFutureTest,
73 ShouldNotBeEmptyIfTakingOneElementFromAfutureWith2Elements) {
74 RepeatingTestFuture<std::string> future;
75
76 future.AddValue("first value");
77 future.AddValue("second value");
78 future.Take();
79
80 EXPECT_FALSE(future.IsEmpty());
81 }
82
TEST_F(RepeatingTestFutureTest,ShouldTakeElementsFiFo)83 TEST_F(RepeatingTestFutureTest, ShouldTakeElementsFiFo) {
84 RepeatingTestFuture<std::string> future;
85
86 future.AddValue("first value");
87 future.AddValue("second value");
88
89 EXPECT_EQ(future.Take(), "first value");
90 EXPECT_EQ(future.Take(), "second value");
91 }
92
TEST_F(RepeatingTestFutureTest,WaitShouldBlockUntilElementArrives)93 TEST_F(RepeatingTestFutureTest, WaitShouldBlockUntilElementArrives) {
94 RepeatingTestFuture<std::string> future;
95
96 RunLater(BindLambdaForTesting([&future]() { future.AddValue("a value"); }));
97 EXPECT_TRUE(future.IsEmpty());
98
99 EXPECT_TRUE(future.Wait());
100
101 EXPECT_FALSE(future.IsEmpty());
102 }
103
TEST_F(RepeatingTestFutureTest,WaitShouldReturnTrueWhenValueArrives)104 TEST_F(RepeatingTestFutureTest, WaitShouldReturnTrueWhenValueArrives) {
105 RepeatingTestFuture<std::string> future;
106
107 RunLater(BindLambdaForTesting([&future]() { future.AddValue("a value"); }));
108
109 EXPECT_TRUE(future.Wait());
110
111 EXPECT_FALSE(future.IsEmpty());
112 }
113
TEST_F(RepeatingTestFutureTest,WaitShouldReturnTrueImmediatelyWhenValueIsAlreadyPresent)114 TEST_F(RepeatingTestFutureTest,
115 WaitShouldReturnTrueImmediatelyWhenValueIsAlreadyPresent) {
116 RepeatingTestFuture<std::string> future;
117
118 future.AddValue("value already present");
119
120 EXPECT_TRUE(future.Wait());
121 }
122
TEST_F(RepeatingTestFutureTest,WaitShouldReturnFalseIfTimeoutHappens)123 TEST_F(RepeatingTestFutureTest, WaitShouldReturnFalseIfTimeoutHappens) {
124 test::ScopedRunLoopTimeout timeout(FROM_HERE, Milliseconds(1));
125
126 // `ScopedRunLoopTimeout` will automatically fail the test when a timeout
127 // happens, so we use EXPECT_NONFATAL_FAILURE to handle this failure.
128 // EXPECT_NONFATAL_FAILURE only works on static objects.
129 static bool success;
130 static RepeatingTestFuture<std::string> future;
131
132 EXPECT_NONFATAL_FAILURE({ success = future.Wait(); }, "timed out");
133
134 EXPECT_FALSE(success);
135 }
136
TEST_F(RepeatingTestFutureTest,TakeShouldBlockUntilAnElementArrives)137 TEST_F(RepeatingTestFutureTest, TakeShouldBlockUntilAnElementArrives) {
138 RepeatingTestFuture<std::string> future;
139
140 RunLater(BindLambdaForTesting(
141 [&future]() { future.AddValue("value pushed delayed"); }));
142
143 EXPECT_EQ(future.Take(), "value pushed delayed");
144 }
145
TEST_F(RepeatingTestFutureTest,TakeShouldDcheckIfTimeoutHappens)146 TEST_F(RepeatingTestFutureTest, TakeShouldDcheckIfTimeoutHappens) {
147 test::ScopedRunLoopTimeout timeout(FROM_HERE, Milliseconds(1));
148
149 RepeatingTestFuture<std::string> future;
150
151 EXPECT_DCHECK_DEATH_WITH(future.Take(), "timed out");
152 }
153
TEST_F(RepeatingTestFutureTest,TakeShouldWorkWithMoveOnlyValue)154 TEST_F(RepeatingTestFutureTest, TakeShouldWorkWithMoveOnlyValue) {
155 RepeatingTestFuture<MoveOnlyValue> future;
156
157 RunLater(BindLambdaForTesting(
158 [&future]() { future.AddValue(MoveOnlyValue("move only value")); }));
159
160 MoveOnlyValue result = future.Take();
161
162 EXPECT_EQ(result.data, "move only value");
163 }
164
TEST_F(RepeatingTestFutureTest,ShouldStoreValuePassedToCallback)165 TEST_F(RepeatingTestFutureTest, ShouldStoreValuePassedToCallback) {
166 RepeatingTestFuture<std::string> future;
167
168 RunLater(BindOnce(future.GetCallback(), "value"));
169
170 EXPECT_EQ("value", future.Take());
171 }
172
TEST_F(RepeatingTestFutureTest,ShouldAllowInvokingCallbackMultipleTimes)173 TEST_F(RepeatingTestFutureTest, ShouldAllowInvokingCallbackMultipleTimes) {
174 RepeatingTestFuture<std::string> future;
175
176 RunLater(BindLambdaForTesting([callback = future.GetCallback()]() {
177 callback.Run("first value");
178 callback.Run("second value");
179 callback.Run("third value");
180 }));
181
182 EXPECT_EQ("first value", future.Take());
183 EXPECT_EQ("second value", future.Take());
184 EXPECT_EQ("third value", future.Take());
185 }
186
TEST_F(RepeatingTestFutureTest,ShouldAllowReferenceArgumentsForCallback)187 TEST_F(RepeatingTestFutureTest, ShouldAllowReferenceArgumentsForCallback) {
188 RepeatingTestFuture<std::string> future;
189
190 RepeatingCallback<void(const std::string&)> callback =
191 future.GetCallback<const std::string&>();
192 RunLater(BindOnce(std::move(callback), "expected value"));
193
194 EXPECT_EQ("expected value", future.Take());
195 }
196
TEST_F(RepeatingTestFutureTest,ShouldStoreMultipleValuesInATuple)197 TEST_F(RepeatingTestFutureTest, ShouldStoreMultipleValuesInATuple) {
198 const int expected_int_value = 5;
199 const std::string expected_string_value = "value";
200
201 RepeatingTestFuture<int, std::string> future;
202
203 RunLater(BindLambdaForTesting(
204 [&]() { future.AddValue(expected_int_value, expected_string_value); }));
205
206 std::tuple<int, std::string> actual = future.Take();
207 EXPECT_EQ(expected_int_value, std::get<0>(actual));
208 EXPECT_EQ(expected_string_value, std::get<1>(actual));
209 }
210
TEST_F(RepeatingTestFutureTest,ShouldAllowCallbackWithMultipleValues)211 TEST_F(RepeatingTestFutureTest, ShouldAllowCallbackWithMultipleValues) {
212 const int expected_int_value = 5;
213 const std::string expected_string_value = "value";
214
215 RepeatingTestFuture<int, std::string> future;
216
217 RunLater(BindOnce(future.GetCallback(), expected_int_value,
218 expected_string_value));
219
220 std::tuple<int, std::string> actual = future.Take();
221 EXPECT_EQ(expected_int_value, std::get<0>(actual));
222 EXPECT_EQ(expected_string_value, std::get<1>(actual));
223 }
224
TEST_F(RepeatingTestFutureTest,ShouldAllowCallbackWithMultipleReferenceValues)225 TEST_F(RepeatingTestFutureTest,
226 ShouldAllowCallbackWithMultipleReferenceValues) {
227 const int expected_int_value = 5;
228 const std::string expected_string_value = "value";
229
230 RepeatingTestFuture<int, std::string> future;
231
232 RepeatingCallback<void(const int&, std::string)> callback =
233 future.GetCallback<const int&, std::string>();
234 RunLater(
235 BindOnce(std::move(callback), expected_int_value, expected_string_value));
236
237 std::tuple<int, std::string> actual = future.Take();
238 EXPECT_EQ(expected_int_value, std::get<0>(actual));
239 EXPECT_EQ(expected_string_value, std::get<1>(actual));
240 }
241
TEST_F(RepeatingTestFutureTest,ShouldSupportCvRefType)242 TEST_F(RepeatingTestFutureTest, ShouldSupportCvRefType) {
243 std::string expected_value = "value";
244 RepeatingTestFuture<const std::string&> future;
245
246 base::OnceCallback<void(const std::string&)> callback = future.GetCallback();
247 std::move(callback).Run(expected_value);
248
249 std::string actual = future.Take();
250 EXPECT_EQ(expected_value, actual);
251 }
252
TEST_F(RepeatingTestFutureTest,ShouldSupportMultipleCvRefType)253 TEST_F(RepeatingTestFutureTest, ShouldSupportMultipleCvRefType) {
254 const int expected_first_value = 5;
255 std::string expected_second_value = "value";
256 const long expected_third_value = 10;
257 RepeatingTestFuture<const int, std::string&, const long&> future;
258
259 base::OnceCallback<void(const int, std::string&, const long&)> callback =
260 future.GetCallback();
261 std::move(callback).Run(expected_first_value, expected_second_value,
262 expected_third_value);
263
264 std::tuple<int, std::string, long> take_result = future.Take();
265 EXPECT_EQ(expected_first_value, std::get<0>(take_result));
266 EXPECT_EQ(expected_second_value, std::get<1>(take_result));
267 EXPECT_EQ(expected_third_value, std::get<2>(take_result));
268 }
269
270 } // namespace base::test
271