Skip to content

Commit 10b45b6

Browse files
Add Unit Tests (facebook#53913)
Summary: Pull Request resolved: facebook#53913 Changelog: [Internal] Reviewed By: rshest Differential Revision: D83091947 fbshipit-source-id: 63baf543b180070591d4779b1203909359aec132
1 parent 430765b commit 10b45b6

File tree

3 files changed

+138
-0
lines changed

3 files changed

+138
-0
lines changed

packages/react-native/ReactCxxPlatform/react/threading/TaskDispatchThread.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,9 @@ void TaskDispatchThread::runAsync(
7373
}
7474

7575
void TaskDispatchThread::runSync(TaskFn&& task) noexcept {
76+
if (!running_) {
77+
return;
78+
}
7679
std::promise<void> promise;
7780
runAsync([&]() {
7881
if (running_) {
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
InheritParentConfig: true
3+
Checks: '
4+
-facebook-hte-BadCall-sleep_for,
5+
'
Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
/*
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*/
7+
8+
#include <gtest/gtest.h>
9+
#include <react/threading/TaskDispatchThread.h>
10+
#include <atomic>
11+
#include <chrono>
12+
#include <thread>
13+
14+
namespace facebook::react {
15+
16+
class TaskDispatchThreadTest : public ::testing::Test {
17+
protected:
18+
TaskDispatchThread dispatcher;
19+
};
20+
21+
// Test: isOnThread returns true inside the looper thread
22+
TEST_F(TaskDispatchThreadTest, IsOnThreadReturnsTrueInLooper) {
23+
bool result = false;
24+
dispatcher.runSync([&] { result = dispatcher.isOnThread(); });
25+
EXPECT_TRUE(result);
26+
}
27+
28+
// Test: isRunning returns true before quit, false after
29+
TEST_F(TaskDispatchThreadTest, IsRunningFlag) {
30+
EXPECT_TRUE(dispatcher.isRunning());
31+
dispatcher.quit();
32+
EXPECT_FALSE(dispatcher.isRunning());
33+
}
34+
35+
// Test: runAsync executes the task
36+
TEST_F(TaskDispatchThreadTest, RunAsyncExecutesTask) {
37+
std::atomic<int> counter{0};
38+
dispatcher.runAsync([&] { counter++; });
39+
// Wait for task to complete
40+
std::this_thread::sleep_for(std::chrono::milliseconds(50));
41+
EXPECT_EQ(counter.load(), 1);
42+
}
43+
44+
// Test: runSync executes the task and blocks until done
45+
TEST_F(TaskDispatchThreadTest, RunSyncExecutesTask) {
46+
std::atomic<int> counter{0};
47+
dispatcher.runSync([&] { counter++; });
48+
EXPECT_EQ(counter.load(), 1);
49+
}
50+
51+
// Test: runAsync with delay
52+
TEST_F(TaskDispatchThreadTest, RunAsyncWithDelay) {
53+
std::atomic<int> counter{0};
54+
dispatcher.runAsync([&] { counter++; }, std::chrono::milliseconds(100));
55+
std::this_thread::sleep_for(std::chrono::milliseconds(50));
56+
EXPECT_EQ(counter.load(), 0); // Not yet executed
57+
std::this_thread::sleep_for(std::chrono::milliseconds(70));
58+
EXPECT_EQ(counter.load(), 1); // Should be executed now
59+
}
60+
61+
// Test: Multiple delayed tasks execute in order
62+
TEST_F(TaskDispatchThreadTest, MultipleDelayedTasksOrder) {
63+
std::vector<int> results;
64+
dispatcher.runAsync(
65+
[&] { results.push_back(1); }, std::chrono::milliseconds(50));
66+
dispatcher.runAsync(
67+
[&] { results.push_back(2); }, std::chrono::milliseconds(100));
68+
std::this_thread::sleep_for(std::chrono::milliseconds(120));
69+
ASSERT_EQ(results.size(), 2);
70+
EXPECT_EQ(results[0], 1);
71+
EXPECT_EQ(results[1], 2);
72+
}
73+
74+
// Test: runSync blocks until task is done
75+
TEST_F(TaskDispatchThreadTest, RunSyncBlocksUntilDone) {
76+
std::atomic<bool> started{false};
77+
std::atomic<bool> finished{false};
78+
dispatcher.runAsync([&] {
79+
started = true;
80+
std::this_thread::sleep_for(std::chrono::milliseconds(50));
81+
finished = true;
82+
});
83+
dispatcher.runSync([&] {
84+
EXPECT_TRUE(started);
85+
EXPECT_TRUE(finished);
86+
});
87+
}
88+
89+
// Test: quit prevents further tasks from running
90+
TEST_F(TaskDispatchThreadTest, QuitPreventsFurtherTasks) {
91+
dispatcher.quit();
92+
std::atomic<int> counter{0};
93+
dispatcher.runAsync([&] { counter++; });
94+
std::this_thread::sleep_for(std::chrono::milliseconds(50));
95+
EXPECT_EQ(counter.load(), 0);
96+
}
97+
98+
// Test: Multiple runSync tasks execute serially
99+
TEST_F(TaskDispatchThreadTest, MultipleRunSyncSerialExecution) {
100+
std::vector<int> results;
101+
dispatcher.runSync([&] { results.push_back(1); });
102+
dispatcher.runSync([&] { results.push_back(2); });
103+
EXPECT_EQ(results.size(), 2);
104+
EXPECT_EQ(results[0], 1);
105+
EXPECT_EQ(results[1], 2);
106+
}
107+
108+
// Test: Edge case - runSync after quit should not execute
109+
TEST_F(TaskDispatchThreadTest, RunSyncAfterQuitDoesNotExecute) {
110+
dispatcher.quit();
111+
std::atomic<int> counter{0};
112+
dispatcher.runSync([&] { counter++; });
113+
EXPECT_EQ(counter.load(), 0);
114+
}
115+
116+
// Test: Thread safety - runAsync from multiple threads
117+
TEST_F(TaskDispatchThreadTest, RunAsyncFromMultipleThreads) {
118+
std::atomic<int> counter{0};
119+
auto task = [&] { dispatcher.runAsync([&] { counter++; }); };
120+
std::thread t1(task);
121+
std::thread t2(task);
122+
std::thread t3(task);
123+
t1.join();
124+
t2.join();
125+
t3.join();
126+
std::this_thread::sleep_for(std::chrono::milliseconds(100));
127+
EXPECT_EQ(counter.load(), 3);
128+
}
129+
130+
} // namespace facebook::react

0 commit comments

Comments
 (0)