diff --git a/rclcpp_async/include/rclcpp_async/task.hpp b/rclcpp_async/include/rclcpp_async/task.hpp index a3f4f42..6504630 100644 --- a/rclcpp_async/include/rclcpp_async/task.hpp +++ b/rclcpp_async/include/rclcpp_async/task.hpp @@ -145,6 +145,7 @@ struct Task { if (this != &o) { if (handle) { + handle.promise().stop_source.request_stop(); handle.destroy(); } handle = o.handle; @@ -264,6 +265,7 @@ struct Task { if (this != &o) { if (handle) { + handle.promise().stop_source.request_stop(); handle.destroy(); } handle = o.handle; diff --git a/rclcpp_async/test/test_task.cpp b/rclcpp_async/test/test_task.cpp index 5f7b603..92daece 100644 --- a/rclcpp_async/test/test_task.cpp +++ b/rclcpp_async/test/test_task.cpp @@ -312,3 +312,50 @@ TEST(TaskVoid, OperatorBoolAndDone) EXPECT_TRUE(static_cast(task2)); EXPECT_TRUE(task2.done()); } + +TEST(TaskT, MoveAssignRequestsStop) +{ + auto task = returns_42(); + // Capture a token (not a reference to stop_source) so the shared stop-state + // outlives the coroutine frame destruction in move-assign. + auto token = task.handle.promise().stop_source.get_token(); + EXPECT_FALSE(token.stop_requested()); + + // Move-assign with empty Task should request_stop on the old handle. + task = Task{}; + EXPECT_TRUE(token.stop_requested()); +} + +TEST(TaskVoid, MoveAssignRequestsStop) +{ + auto task = does_nothing(); + auto token = task.handle.promise().stop_source.get_token(); + EXPECT_FALSE(token.stop_requested()); + + task = Task{}; + EXPECT_TRUE(token.stop_requested()); +} + +TEST(TaskT, MoveAssignStopCallbackFires) +{ + bool callback_fired = false; + auto task = returns_42(); + auto token = task.handle.promise().stop_source.get_token(); + std::stop_callback cb(token, [&]() { callback_fired = true; }); + + EXPECT_FALSE(callback_fired); + task = Task{}; + EXPECT_TRUE(callback_fired); +} + +TEST(TaskVoid, MoveAssignStopCallbackFires) +{ + bool callback_fired = false; + auto task = does_nothing(); + auto token = task.handle.promise().stop_source.get_token(); + std::stop_callback cb(token, [&]() { callback_fired = true; }); + + EXPECT_FALSE(callback_fired); + task = Task{}; + EXPECT_TRUE(callback_fired); +}