@@ -15,27 +15,28 @@ namespace facebook::react {
1515
1616class TaskDispatchThreadTest : public ::testing::Test {
1717 protected:
18- TaskDispatchThread dispatcher;
18+ std::unique_ptr<TaskDispatchThread> dispatcher{
19+ std::make_unique<TaskDispatchThread>()};
1920};
2021
2122// Test: isOnThread returns true inside the looper thread
2223TEST_F (TaskDispatchThreadTest, IsOnThreadReturnsTrueInLooper) {
2324 bool result = false ;
24- dispatcher. runSync ([&] { result = dispatcher. isOnThread (); });
25+ dispatcher-> runSync ([&] { result = dispatcher-> isOnThread (); });
2526 EXPECT_TRUE (result);
2627}
2728
2829// Test: isRunning returns true before quit, false after
2930TEST_F (TaskDispatchThreadTest, IsRunningFlag) {
30- EXPECT_TRUE (dispatcher. isRunning ());
31- dispatcher. quit ();
32- EXPECT_FALSE (dispatcher. isRunning ());
31+ EXPECT_TRUE (dispatcher-> isRunning ());
32+ dispatcher-> quit ();
33+ EXPECT_FALSE (dispatcher-> isRunning ());
3334}
3435
3536// Test: runAsync executes the task
3637TEST_F (TaskDispatchThreadTest, RunAsyncExecutesTask) {
3738 std::atomic<int > counter{0 };
38- dispatcher. runAsync ([&] { counter++; });
39+ dispatcher-> runAsync ([&] { counter++; });
3940 // Wait for task to complete
4041 std::this_thread::sleep_for (std::chrono::milliseconds (50 ));
4142 EXPECT_EQ (counter.load (), 1 );
@@ -44,14 +45,14 @@ TEST_F(TaskDispatchThreadTest, RunAsyncExecutesTask) {
4445// Test: runSync executes the task and blocks until done
4546TEST_F (TaskDispatchThreadTest, RunSyncExecutesTask) {
4647 std::atomic<int > counter{0 };
47- dispatcher. runSync ([&] { counter++; });
48+ dispatcher-> runSync ([&] { counter++; });
4849 EXPECT_EQ (counter.load (), 1 );
4950}
5051
5152// Test: runAsync with delay
5253TEST_F (TaskDispatchThreadTest, RunAsyncWithDelay) {
5354 std::atomic<int > counter{0 };
54- dispatcher. runAsync ([&] { counter++; }, std::chrono::milliseconds (100 ));
55+ dispatcher-> runAsync ([&] { counter++; }, std::chrono::milliseconds (100 ));
5556 std::this_thread::sleep_for (std::chrono::milliseconds (50 ));
5657 EXPECT_EQ (counter.load (), 0 ); // Not yet executed
5758 std::this_thread::sleep_for (std::chrono::milliseconds (70 ));
@@ -61,9 +62,9 @@ TEST_F(TaskDispatchThreadTest, RunAsyncWithDelay) {
6162// Test: Multiple delayed tasks execute in order
6263TEST_F (TaskDispatchThreadTest, MultipleDelayedTasksOrder) {
6364 std::vector<int > results;
64- dispatcher. runAsync (
65+ dispatcher-> runAsync (
6566 [&] { results.push_back (1 ); }, std::chrono::milliseconds (50 ));
66- dispatcher. runAsync (
67+ dispatcher-> runAsync (
6768 [&] { results.push_back (2 ); }, std::chrono::milliseconds (100 ));
6869 std::this_thread::sleep_for (std::chrono::milliseconds (120 ));
6970 ASSERT_EQ (results.size (), 2 );
@@ -75,48 +76,48 @@ TEST_F(TaskDispatchThreadTest, MultipleDelayedTasksOrder) {
7576TEST_F (TaskDispatchThreadTest, RunSyncBlocksUntilDone) {
7677 std::atomic<bool > started{false };
7778 std::atomic<bool > finished{false };
78- dispatcher. runAsync ([&] {
79+ dispatcher-> runAsync ([&] {
7980 started = true ;
8081 std::this_thread::sleep_for (std::chrono::milliseconds (50 ));
8182 finished = true ;
8283 });
83- dispatcher. runSync ([&] {
84+ dispatcher-> runSync ([&] {
8485 EXPECT_TRUE (started);
8586 EXPECT_TRUE (finished);
8687 });
8788}
8889
8990// Test: quit prevents further tasks from running
9091TEST_F (TaskDispatchThreadTest, QuitPreventsFurtherTasks) {
91- dispatcher. quit ();
92+ dispatcher-> quit ();
9293 std::atomic<int > counter{0 };
93- dispatcher. runAsync ([&] { counter++; });
94+ dispatcher-> runAsync ([&] { counter++; });
9495 std::this_thread::sleep_for (std::chrono::milliseconds (50 ));
9596 EXPECT_EQ (counter.load (), 0 );
9697}
9798
9899// Test: Multiple runSync tasks execute serially
99100TEST_F (TaskDispatchThreadTest, MultipleRunSyncSerialExecution) {
100101 std::vector<int > results;
101- dispatcher. runSync ([&] { results.push_back (1 ); });
102- dispatcher. runSync ([&] { results.push_back (2 ); });
102+ dispatcher-> runSync ([&] { results.push_back (1 ); });
103+ dispatcher-> runSync ([&] { results.push_back (2 ); });
103104 EXPECT_EQ (results.size (), 2 );
104105 EXPECT_EQ (results[0 ], 1 );
105106 EXPECT_EQ (results[1 ], 2 );
106107}
107108
108109// Test: Edge case - runSync after quit should not execute
109110TEST_F (TaskDispatchThreadTest, RunSyncAfterQuitDoesNotExecute) {
110- dispatcher. quit ();
111+ dispatcher-> quit ();
111112 std::atomic<int > counter{0 };
112- dispatcher. runSync ([&] { counter++; });
113+ dispatcher-> runSync ([&] { counter++; });
113114 EXPECT_EQ (counter.load (), 0 );
114115}
115116
116117// Test: Thread safety - runAsync from multiple threads
117118TEST_F (TaskDispatchThreadTest, RunAsyncFromMultipleThreads) {
118119 std::atomic<int > counter{0 };
119- auto task = [&] { dispatcher. runAsync ([&] { counter++; }); };
120+ auto task = [&] { dispatcher-> runAsync ([&] { counter++; }); };
120121 std::thread t1 (task);
121122 std::thread t2 (task);
122123 std::thread t3 (task);
@@ -127,4 +128,23 @@ TEST_F(TaskDispatchThreadTest, RunAsyncFromMultipleThreads) {
127128 EXPECT_EQ (counter.load (), 3 );
128129}
129130
131+ TEST_F (TaskDispatchThreadTest, QuitInTaskShouldntBeBlockedForever) {
132+ dispatcher->runSync ([&] { dispatcher->quit (); });
133+ }
134+
135+ TEST_F (TaskDispatchThreadTest, QuitShouldWaitAlreadyRunningTask) {
136+ {
137+ std::unique_ptr<int > counter = std::make_unique<int >(0 );
138+ dispatcher->runAsync ([&] {
139+ std::this_thread::sleep_for (std::chrono::milliseconds (300 ));
140+ *counter = 1 ;
141+ });
142+ std::this_thread::sleep_for (std::chrono::milliseconds (50 ));
143+ // if quit doesn't wait for running task, then *counter will access already
144+ // deleted object
145+ dispatcher->quit ();
146+ }
147+ // forcing dispatcher to join thread
148+ dispatcher.reset ();
149+ }
130150} // namespace facebook::react
0 commit comments