Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
future_utils_test.cc
Go to the documentation of this file.
1
2/*
3 Aleph_w
4
5 Data structures & Algorithms
6 version 2.0.0b
7 https://github.com/lrleon/Aleph-w
8
9 This file is part of Aleph-w library
10
11 Copyright (c) 2002-2026 Leandro Rabindranath Leon
12
13 Permission is hereby granted, free of charge, to any person obtaining a copy
14 of this software and associated documentation files (the "Software"), to deal
15 in the Software without restriction, including without limitation the rights
16 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17 copies of the Software, and to permit persons to whom the Software is
18 furnished to do so, subject to the following conditions:
19
20 The above copyright notice and this permission notice shall be included in all
21 copies or substantial portions of the Software.
22
23 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
29 SOFTWARE.
30*/
31
32
33
38#include <gtest/gtest.h>
39#include <future>
40#include <chrono>
41#include <thread>
42#include <stdexcept>
43#include <atomic>
44#include <future_utils.H>
45
46using namespace Aleph;
47
48// =============================================================================
49// Test Fixtures
50// =============================================================================
51
52class FutureUtilsTest : public ::testing::Test
53{
54protected:
55 // Helper to create a simple async task that returns its input
56 static std::future<int> make_int_future(int value)
57 {
58 return std::async(std::launch::async, [value] { return value; });
59 }
60
61 // Helper to create a delayed async task
62 static std::future<int> make_delayed_future(int value, int delay_ms)
63 {
64 return std::async(std::launch::async, [value, delay_ms] {
65 std::this_thread::sleep_for(std::chrono::milliseconds(delay_ms));
66 return value;
67 });
68 }
69
70 // Helper to create a void async task
71 static std::future<void> make_void_future()
72 {
73 return std::async(std::launch::async, [] {});
74 }
75
76 // Helper to create a void async task that modifies a counter
77 static std::future<void> make_void_future_with_effect(std::atomic<int> & counter)
78 {
79 return std::async(std::launch::async, [&counter] { ++counter; });
80 }
81
82 // Helper to create a failing async task
83 static std::future<int> make_failing_future()
84 {
85 return std::async(std::launch::async, []() -> int {
86 throw std::runtime_error("Test exception");
87 });
88 }
89};
90
91// =============================================================================
92// Basic get_futures Tests (int)
93// =============================================================================
94
103
115
117{
119 for (int i = 1; i <= 5; ++i)
120 futures.append(make_int_future(i * 10));
121
123
124 EXPECT_EQ(results.size(), 5u);
126
127 // Verify order is preserved
128 int expected = 10;
129 results.traverse([&expected](int val) {
130 EXPECT_EQ(val, expected);
131 expected += 10;
132 return true;
133 });
134}
135
137{
139 futures.append(make_int_future(1));
140 futures.append(make_int_future(2));
141 futures.append(make_int_future(3));
142
144
145 auto it = results.get_it();
146 EXPECT_EQ(it.get_curr(), 1); it.next();
147 EXPECT_EQ(it.get_curr(), 2); it.next();
148 EXPECT_EQ(it.get_curr(), 3);
149}
150
152{
154 futures.append(make_delayed_future(100, 50));
155 futures.append(make_delayed_future(200, 10));
156 futures.append(make_delayed_future(300, 30));
157
159
160 EXPECT_EQ(results.size(), 3u);
161
162 // Order should be preserved (100, 200, 300), not completion order
163 auto it = results.get_it();
164 EXPECT_EQ(it.get_curr(), 100); it.next();
165 EXPECT_EQ(it.get_curr(), 200); it.next();
166 EXPECT_EQ(it.get_curr(), 300);
167}
168
169// =============================================================================
170// get_futures Rvalue Overload Tests
171// =============================================================================
172
174{
175 auto make_list = []() {
177 futures.append(std::async(std::launch::async, [] { return 42; }));
178 futures.append(std::async(std::launch::async, [] { return 43; }));
179 return futures;
180 };
181
182 auto results = get_futures(make_list());
183
184 EXPECT_EQ(results.size(), 2u);
185}
186
187// =============================================================================
188// Void Future Tests
189// =============================================================================
190
197
206
208{
209 std::atomic<int> counter{0};
211
212 for (int i = 0; i < 5; ++i)
213 futures.append(make_void_future_with_effect(counter));
214
216
217 EXPECT_EQ(counter.load(), 5);
219}
220
222{
223 std::atomic<int> counter{0};
224
225 auto make_list = [&counter]() {
227 futures.append(std::async(std::launch::async, [&counter] { ++counter; }));
228 futures.append(std::async(std::launch::async, [&counter] { ++counter; }));
229 return futures;
230 };
231
233
234 EXPECT_EQ(counter.load(), 2);
235}
236
237// =============================================================================
238// Exception Handling Tests
239// =============================================================================
240
242{
244 futures.append(make_int_future(1));
245 futures.append(make_failing_future());
246 futures.append(make_int_future(3));
247
248 EXPECT_THROW(get_futures(futures), std::runtime_error);
249}
250
252{
254 futures.append(make_void_future());
255 futures.append(std::async(std::launch::async, [] {
256 throw std::logic_error("Void exception");
257 }));
258
259 EXPECT_THROW(get_futures(futures), std::logic_error);
260}
261
262// =============================================================================
263// all_ready Tests
264// =============================================================================
265
271
273{
275 futures.append(make_int_future(1));
276 futures.append(make_int_future(2));
277
278 // Give futures time to complete
279 std::this_thread::sleep_for(std::chrono::milliseconds(50));
280
282}
283
285{
287 futures.append(make_delayed_future(1, 500)); // Long delay
288
289 // Check immediately - should not be ready
291
292 // Clean up
294}
295
297{
299 futures.append(make_int_future(1)); // Ready immediately
300 futures.append(make_delayed_future(2, 500)); // Still pending
301
302 // Give first future time but not second
303 std::this_thread::sleep_for(std::chrono::milliseconds(50));
304
306
307 // Clean up
309}
310
311// =============================================================================
312// count_ready Tests
313// =============================================================================
314
320
322{
324 for (int i = 0; i < 5; ++i)
325 futures.append(make_int_future(i));
326
327 // Give futures time to complete
328 std::this_thread::sleep_for(std::chrono::milliseconds(50));
329
331
332 // Clean up
334}
335
337{
339 for (int i = 0; i < 3; ++i)
340 futures.append(make_delayed_future(i, 500));
341
342 // Check immediately
344
345 // Clean up
347}
348
350{
352 futures.append(make_int_future(1));
353 futures.append(make_int_future(2));
354 futures.append(make_delayed_future(3, 500));
355
356 // Give fast futures time to complete
357 std::this_thread::sleep_for(std::chrono::milliseconds(50));
358
362
363 // Clean up
365}
366
367// =============================================================================
368// Different Types Tests
369// =============================================================================
370
372{
374 futures.append(std::async(std::launch::async, [] { return std::string("hello"); }));
375 futures.append(std::async(std::launch::async, [] { return std::string("world"); }));
376
378
379 EXPECT_EQ(results.size(), 2u);
380
381 auto it = results.get_it();
382 EXPECT_EQ(it.get_curr(), "hello"); it.next();
383 EXPECT_EQ(it.get_curr(), "world");
384}
385
387{
389 futures.append(std::async(std::launch::async, [] { return 3.14; }));
390 futures.append(std::async(std::launch::async, [] { return 2.71; }));
391
393
394 EXPECT_EQ(results.size(), 2u);
395
396 auto it = results.get_it();
397 EXPECT_DOUBLE_EQ(it.get_curr(), 3.14); it.next();
398 EXPECT_DOUBLE_EQ(it.get_curr(), 2.71);
399}
400
402{
404 futures.append(std::async(std::launch::async, [] {
405 return std::vector<int>{1, 2, 3};
406 }));
407 futures.append(std::async(std::launch::async, [] {
408 return std::vector<int>{4, 5};
409 }));
410
412
413 EXPECT_EQ(results.size(), 2u);
414
415 auto it = results.get_it();
416 EXPECT_EQ(it.get_curr().size(), 3u);
417 it.next();
418 EXPECT_EQ(it.get_curr().size(), 2u);
419}
420
421// =============================================================================
422// Stress Tests
423// =============================================================================
424
426{
428 constexpr int N = 100;
429
430 for (int i = 0; i < N; ++i)
431 futures.append(make_int_future(i));
432
434
435 EXPECT_EQ(results.size(), static_cast<size_t>(N));
437
438 // Verify all values
439 int expected = 0;
440 results.traverse([&expected](int val) {
441 EXPECT_EQ(val, expected++);
442 return true;
443 });
444}
445
447{
448 std::atomic<int> counter{0};
450 constexpr int N = 100;
451
452 for (int i = 0; i < N; ++i)
453 futures.append(make_void_future_with_effect(counter));
454
456
457 EXPECT_EQ(counter.load(), N);
459}
460
461// =============================================================================
462// Edge Cases
463// =============================================================================
464
475
486
488{
490 futures.append(std::async(std::launch::async, [] { return std::string(); }));
491
493
494 EXPECT_EQ(results.size(), 1u);
495 EXPECT_TRUE(results.get_first().empty());
496}
497
498// =============================================================================
499// Main
500// =============================================================================
501
502int main(int argc, char ** argv)
503{
504 ::testing::InitGoogleTest(&argc, argv);
505 return RUN_ALL_TESTS();
506}
int main()
Dynamic singly linked list with functional programming support.
Definition htlist.H:1423
T & append(const T &item)
Append a new item by copy.
Definition htlist.H:1562
T & get_first() const
Return the first item of the list.
Definition htlist.H:1675
constexpr bool is_empty() const noexcept
Return true if list is empty.
Definition htlist.H:523
size_t size() const noexcept
Count the number of elements of the list.
Definition htlist.H:1319
static std::future< void > make_void_future()
static std::future< int > make_int_future(int value)
static std::future< int > make_delayed_future(int value, int delay_ms)
static std::future< void > make_void_future_with_effect(std::atomic< int > &counter)
static std::future< int > make_failing_future()
auto get_it() const
Return a properly initialized iterator positioned at the first item on the container.
Definition ah-dry.H:190
#define N
Definition fib.C:294
Utility functions for working with std::future collections.
TEST_F(FutureUtilsTest, GetFuturesEmptyList)
Main namespace for Aleph-w library functions.
Definition ah-arena.H:89
size_t count_ready(DynList< std::future< T > > &future_list)
Count how many futures are ready.
DynList< T > get_futures(DynList< std::future< T > > &future_list)
Collect results from a list of futures.
bool all_ready(DynList< std::future< T > > &future_list)
Check if all futures in a list are ready.
DynList< T > maps(const C &c, Op op)
Classic map operation.
bool traverse(Operation &operation) noexcept(traverse_is_noexcept< Operation >())
Traverse the container via its iterator and performs a conditioned operation on each item.
Definition ah-dry.H:95