xref: /aosp_15_r20/external/pigweed/pw_async_fuchsia/dispatcher_test.cc (revision 61c4878ac05f98d0ceed94b57d316916de578985)
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_async_fuchsia/dispatcher.h"
16 
17 #include <lib/async-testing/test_loop.h>
18 
19 #include "pw_async_fuchsia/util.h"
20 #include "pw_unit_test/framework.h"
21 
22 #define ASSERT_CANCELLED(status) ASSERT_EQ(Status::Cancelled(), status)
23 
24 using namespace std::chrono_literals;
25 
26 namespace pw::async_fuchsia {
27 
28 class DispatcherFuchsiaTest : public ::testing::Test {
29  public:
dispatcher()30   async_dispatcher_t* dispatcher() { return loop_.dispatcher(); }
RunLoopUntilIdle()31   void RunLoopUntilIdle() { loop_.RunUntilIdle(); }
RunLoopFor(zx::duration duration)32   void RunLoopFor(zx::duration duration) { loop_.RunFor(duration); }
33 
34  private:
35   ::async::TestLoop loop_;
36 };
37 
TEST_F(DispatcherFuchsiaTest,TimeConversions)38 TEST_F(DispatcherFuchsiaTest, TimeConversions) {
39   zx::time time{timespec{123, 456}};
40   chrono::SystemClock::time_point tp =
41       pw::async_fuchsia::ZxTimeToTimepoint(time);
42   EXPECT_EQ(tp.time_since_epoch(), 123s + 456ns);
43   EXPECT_EQ(pw::async_fuchsia::TimepointToZxTime(tp), time);
44 }
45 
TEST_F(DispatcherFuchsiaTest,Basic)46 TEST_F(DispatcherFuchsiaTest, Basic) {
47   FuchsiaDispatcher fuchsia_dispatcher(dispatcher());
48 
49   bool set = false;
50   async::Task task([&set](async::Context& ctx, Status status) {
51     PW_TEST_ASSERT_OK(status);
52     set = true;
53   });
54   fuchsia_dispatcher.Post(task);
55 
56   RunLoopUntilIdle();
57   EXPECT_TRUE(set);
58 }
59 
TEST_F(DispatcherFuchsiaTest,DelayedTasks)60 TEST_F(DispatcherFuchsiaTest, DelayedTasks) {
61   FuchsiaDispatcher fuchsia_dispatcher(dispatcher());
62 
63   int c = 0;
64   async::Task first([&c](async::Context& ctx, Status status) {
65     PW_TEST_ASSERT_OK(status);
66     c = c * 10 + 1;
67   });
68   async::Task second([&c](async::Context& ctx, Status status) {
69     PW_TEST_ASSERT_OK(status);
70     c = c * 10 + 2;
71   });
72   async::Task third([&c](async::Context& ctx, Status status) {
73     PW_TEST_ASSERT_OK(status);
74     c = c * 10 + 3;
75   });
76 
77   fuchsia_dispatcher.PostAfter(third, 20ms);
78   fuchsia_dispatcher.PostAfter(first, 5ms);
79   fuchsia_dispatcher.PostAfter(second, 10ms);
80 
81   RunLoopFor(zx::msec(25));
82   EXPECT_EQ(c, 123);
83 }
84 
TEST_F(DispatcherFuchsiaTest,CancelTask)85 TEST_F(DispatcherFuchsiaTest, CancelTask) {
86   FuchsiaDispatcher fuchsia_dispatcher(dispatcher());
87 
88   async::Task task([](async::Context& ctx, Status status) { FAIL(); });
89   fuchsia_dispatcher.Post(task);
90   EXPECT_TRUE(fuchsia_dispatcher.Cancel(task));
91 
92   RunLoopUntilIdle();
93 }
94 
95 class DestructionChecker {
96  public:
DestructionChecker(bool * flag)97   explicit DestructionChecker(bool* flag) : flag_(flag) {}
DestructionChecker(DestructionChecker && other)98   DestructionChecker(DestructionChecker&& other) {
99     flag_ = other.flag_;
100     other.flag_ = nullptr;
101   }
~DestructionChecker()102   ~DestructionChecker() {
103     if (flag_) {
104       *flag_ = true;
105     }
106   }
107 
108  private:
109   bool* flag_;
110 };
111 
TEST_F(DispatcherFuchsiaTest,HeapAllocatedTasks)112 TEST_F(DispatcherFuchsiaTest, HeapAllocatedTasks) {
113   FuchsiaDispatcher fuchsia_dispatcher(dispatcher());
114 
115   int c = 0;
116   for (int i = 0; i < 3; i++) {
117     Post(&fuchsia_dispatcher, [&c](async::Context& ctx, Status status) {
118       PW_TEST_ASSERT_OK(status);
119       c++;
120     });
121   }
122 
123   EXPECT_EQ(c, 0);
124   RunLoopUntilIdle();
125   EXPECT_EQ(c, 3);
126 
127   // Test that the lambda is destroyed after being called.
128   bool flag = false;
129   Post(&fuchsia_dispatcher,
130        [checker = DestructionChecker(&flag)](async::Context& ctx,
131                                              Status status) {});
132   EXPECT_FALSE(flag);
133   RunLoopUntilIdle();
134   EXPECT_TRUE(flag);
135 }
136 
TEST_F(DispatcherFuchsiaTest,ChainedTasks)137 TEST_F(DispatcherFuchsiaTest, ChainedTasks) {
138   FuchsiaDispatcher fuchsia_dispatcher(dispatcher());
139 
140   int c = 0;
141 
142   Post(&fuchsia_dispatcher, [&c](async::Context& ctx, Status status) {
143     PW_TEST_ASSERT_OK(status);
144     c++;
145     Post(ctx.dispatcher, [&c](async::Context& ctx, Status status) {
146       PW_TEST_ASSERT_OK(status);
147       c++;
148       Post(ctx.dispatcher, [&c](async::Context& ctx, Status status) {
149         PW_TEST_ASSERT_OK(status);
150         c++;
151       });
152     });
153   });
154 
155   RunLoopUntilIdle();
156   EXPECT_EQ(c, 3);
157 }
158 
159 }  // namespace pw::async_fuchsia
160