@@ -220,3 +220,46 @@ TEST(Decorator, RunOnce)
220220 // counters[1] contains the number of times TestB was ticked
221221 ASSERT_EQ (counters[1 ], 5 );
222222}
223+
224+ // Test for DelayNode with XML: delay_msec port should be honored
225+ TEST (Decorator, DelayWithXML)
226+ {
227+ BT::BehaviorTreeFactory factory;
228+
229+ const std::string xml_text = R"(
230+ <root BTCPP_format="4" >
231+ <BehaviorTree>
232+ <Delay delay_msec="100">
233+ <AlwaysSuccess/>
234+ </Delay>
235+ </BehaviorTree>
236+ </root>)" ;
237+
238+ auto tree = factory.createTreeFromText (xml_text);
239+
240+ // First tick should return RUNNING (delay not complete)
241+ auto start = std::chrono::steady_clock::now ();
242+ NodeStatus status = tree.tickOnce ();
243+ ASSERT_EQ (status, NodeStatus::RUNNING);
244+
245+ // Wait for a short time, still should be RUNNING
246+ std::this_thread::sleep_for (std::chrono::milliseconds (50 ));
247+ status = tree.tickOnce ();
248+ ASSERT_EQ (status, NodeStatus::RUNNING);
249+
250+ // Poll until the delay completes (with timeout for safety)
251+ while (status == NodeStatus::RUNNING)
252+ {
253+ std::this_thread::sleep_for (std::chrono::milliseconds (1 ));
254+ status = tree.tickOnce ();
255+ }
256+ auto end = std::chrono::steady_clock::now ();
257+ auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
258+
259+ // The child (AlwaysSuccess) should have been executed after the delay
260+ ASSERT_EQ (status, NodeStatus::SUCCESS);
261+ // Verify that at least ~200ms have passed (with small tolerance for timing jitter)
262+ ASSERT_GE (elapsed.count (), 80 );
263+ // Ensure the test didn't take too long (sanity check)
264+ ASSERT_LE (elapsed.count (), 200 );
265+ }
0 commit comments