From 3fdcb0b753ede69a60be380c2b7cd0dd4ad94ffd Mon Sep 17 00:00:00 2001 From: Serhii Snitsaruk Date: Wed, 30 Aug 2023 11:19:14 +0200 Subject: [PATCH] Add tests for BTRandomSequence --- tests/limbo_test.h | 5 ++ tests/test_random_sequence.h | 93 ++++++++++++++++++++++++++++++++++++ 2 files changed, 98 insertions(+) create mode 100644 tests/test_random_sequence.h diff --git a/tests/limbo_test.h b/tests/limbo_test.h index 7c6f367..8d59fd4 100644 --- a/tests/limbo_test.h +++ b/tests/limbo_test.h @@ -44,4 +44,9 @@ public: CHECK(m_task->num_ticks == m_ticks); \ CHECK(m_task->num_exits == m_exits); +#define CHECK_ENTRIES_TICKS_EXITS_UP_TO(m_task, m_entries, m_ticks, m_exits) \ + CHECK(m_task->num_entries <= m_entries); \ + CHECK(m_task->num_ticks <= m_ticks); \ + CHECK(m_task->num_exits <= m_exits); + #endif // LIMBO_TEST_H diff --git a/tests/test_random_sequence.h b/tests/test_random_sequence.h new file mode 100644 index 0000000..c03d1af --- /dev/null +++ b/tests/test_random_sequence.h @@ -0,0 +1,93 @@ +/** + * test_random_sequence.h + * ============================================================================= + * Copyright 2021-2023 Serhii Snitsaruk + * + * Use of this source code is governed by an MIT-style + * license that can be found in the LICENSE file or at + * https://opensource.org/licenses/MIT. + * ============================================================================= + */ + +#ifndef TEST_RANDOM_SEQUENCE_H +#define TEST_RANDOM_SEQUENCE_H + +#include "limbo_test.h" + +#include "modules/limboai/bt/tasks/bt_task.h" +#include "modules/limboai/bt/tasks/composites/bt_random_sequence.h" + +namespace TestRandomSequence { + +TEST_CASE("[Modules][LimboAI] BTRandomSequence") { + Ref seq = memnew(BTRandomSequence); + Ref task1 = memnew(BTTestAction()); + Ref task2 = memnew(BTTestAction()); + Ref task3 = memnew(BTTestAction()); + + seq->add_child(task1); + seq->add_child(task2); + seq->add_child(task3); + + REQUIRE(seq->get_child_count() == 3); + + SUBCASE("Expecting RUNNING status when a child task returns RUNNING") { + task1->ret_status = BTTask::SUCCESS; + task2->ret_status = BTTask::RUNNING; + task3->ret_status = BTTask::SUCCESS; + + CHECK(seq->execute(0.01666) == BTTask::RUNNING); + CHECK_ENTRIES_TICKS_EXITS_UP_TO(task1, 1, 1, 1); // * ran no more than once + CHECK_ENTRIES_TICKS_EXITS(task2, 1, 1, 0); // * running - enters and ticks + CHECK_ENTRIES_TICKS_EXITS_UP_TO(task3, 1, 1, 1); // * ran no more than once + + SUBCASE("Resuming and succeeding when all tasks succeed") { + task2->ret_status = BTTask::SUCCESS; + CHECK(seq->execute(0.01666) == BTTask::SUCCESS); + CHECK_ENTRIES_TICKS_EXITS(task1, 1, 1, 1); // * ran once + CHECK_ENTRIES_TICKS_EXITS(task2, 1, 2, 1); // * finishes - ticks and exits with SUCCESS + CHECK_ENTRIES_TICKS_EXITS(task3, 1, 1, 1); // * ran once + } + + SUBCASE("Resuming and failing when a child task fails") { + task2->ret_status = BTTask::FAILURE; + CHECK(seq->execute(0.01666) == BTTask::FAILURE); + CHECK_ENTRIES_TICKS_EXITS_UP_TO(task1, 1, 1, 1); // * ran no more than once + CHECK_ENTRIES_TICKS_EXITS(task2, 1, 2, 1); // * finishes - ticks and exits with FAILURE + CHECK_ENTRIES_TICKS_EXITS_UP_TO(task3, 1, 1, 1); // * ran no more than once + } + } + + SUBCASE("Verify that tasks are executed in random order") { + task1->ret_status = BTTask::SUCCESS; + task2->ret_status = BTTask::SUCCESS; + task3->ret_status = BTTask::RUNNING; + + int num_tries = 10; + bool is_confirmed = false; + while (!is_confirmed && num_tries--) { + CHECK(seq->execute(0.01666) == BTTask::RUNNING); + int checksum = 0; + if (task1->get_status() == BTTask::SUCCESS) { + checksum += 1; + } + if (task2->get_status() == BTTask::SUCCESS) { + checksum += 2; + } + if (task3->get_status() == BTTask::RUNNING) { + checksum += 4; + } + is_confirmed = (checksum != 7); + } + CHECK(is_confirmed); + } +} + +TEST_CASE("[Modules][LimboAI] Empty BTRandomSequence returns SUCCESS") { + Ref seq = memnew(BTRandomSequence); + CHECK(seq->execute(0.01666) == BTTask::SUCCESS); +} + +} //namespace TestRandomSequence + +#endif // TEST_RANDOM_SEQUENCE_H