Olympe Engine 2.0
2D Game Engine with ECS Architecture
Loading...
Searching...
No Matches
TestAIGraphPlugin_BT.cpp
Go to the documentation of this file.
1/**
2 * @file TestAIGraphPlugin_BT.cpp
3 * @brief Comprehensive tests for AIGraphPlugin_BT (Phase 1.2)
4 * @author Olympe Engine
5 * @date 2026-02-18
6 *
7 * @details
8 * Tests all components of AIGraphPlugin_BT:
9 * - BTNodeRegistry (initialization, queries, validation)
10 * - BTGraphValidator (all 7 validation rules)
11 * - BTGraphCompiler (compilation, error handling)
12 * - BTNodePalette (basic instantiation)
13 *
14 * @note This is a test file. Test output uses std::cout which is acceptable
15 * for test reporting purposes. Production code uses SYSTEM_LOG.
16 */
17
18#include "../AIGraphPlugin_BT/BTNodeRegistry.h"
19#include "../AIGraphPlugin_BT/BTGraphValidator.h"
20#include "../AIGraphPlugin_BT/BTGraphCompiler.h"
21#include "../AIGraphPlugin_BT/BTNodePalette.h"
22#include "../../NodeGraphCore/GraphDocument.h"../
23#include "../BehaviorTree.h"
24
25#include <iostream>
26#include <cassert>
27#include <string>
28
29using namespace Olympe::AI;
30using namespace Olympe::NodeGraph;
31
32// Test counter
35
36void ReportTest(const std::string& testName, bool passed) {
37 if (passed) {
38 std::cout << "[PASS] " << testName << std::endl;
40 } else {
41 std::cout << "[FAIL] " << testName << std::endl;
43 }
44}
45
46// ============================================================================
47// Test 1: Registry Initialization
48// ============================================================================
51 auto allTypes = registry.GetAllNodeTypes();
52
53 bool passed = allTypes.size() >= 15; // At least 15 types
54 ReportTest("Test 1: Registry Initialization", passed);
55}
56
57// ============================================================================
58// Test 2: Node Type Query
59// ============================================================================
62
63 const BTNodeTypeInfo* info = registry.GetNodeTypeInfo("BT_Selector");
64 bool passed = (info != nullptr) &&
65 (info->category == BTNodeCategory::Composite) &&
66 (info->minChildren == 1) &&
67 (info->maxChildren == -1);
68
69 ReportTest("Test 2: Node Type Query", passed);
70}
71
72// ============================================================================
73// Test 3: Validation - Valid Single Root
74// ============================================================================
77 doc.type = "AIGraph";
78 doc.graphKind = "BehaviorTree";
79
80 NodeId root = doc.CreateNode("BT_Selector", Vector2(0, 0));
81 NodeId child = doc.CreateNode("BT_Wait", Vector2(0, 100));
82
83 // Connect child to root
84 auto* rootNode = doc.GetNode(root);
85 if (rootNode != nullptr) {
86 rootNode->children.push_back(child);
87 }
88
89 doc.rootNodeId = root;
90
92
93 // Should have no errors
94 bool hasError = false;
95 for (auto msgIt = messages.begin(); msgIt != messages.end(); ++msgIt) {
96 if (msgIt->severity == BTValidationSeverity::Error) {
97 hasError = true;
98 }
99 }
100
101 ReportTest("Test 3: Validation - Valid Single Root", !hasError);
102}
103
104// ============================================================================
105// Test 4: Validation - Multiple Roots Error
106// ============================================================================
109 doc.type = "AIGraph";
110 doc.graphKind = "BehaviorTree";
111
112 doc.CreateNode("BT_Selector", Vector2(0, 0));
113 doc.CreateNode("BT_Sequence", Vector2(100, 0));
114
116
117 // Should have multiple roots error
118 bool hasMultipleRootsError = false;
119 for (auto msgIt = messages.begin(); msgIt != messages.end(); ++msgIt) {
120 if (msgIt->message.find("Multiple root") != std::string::npos) {
122 }
123 }
124
125 ReportTest("Test 4: Validation - Multiple Roots Error", hasMultipleRootsError);
126}
127
128// ============================================================================
129// Test 5: Validation - Cycle Detection
130// ============================================================================
133 doc.type = "AIGraph";
134 doc.graphKind = "BehaviorTree";
135
136 NodeId a = doc.CreateNode("BT_Selector", Vector2(0, 0));
137 NodeId b = doc.CreateNode("BT_Sequence", Vector2(0, 100));
138 NodeId c = doc.CreateNode("BT_Selector", Vector2(0, 200));
139
140 // Create cycle: A -> B -> C -> A
141 auto* nodeA = doc.GetNode(a);
142 auto* nodeB = doc.GetNode(b);
143 auto* nodeC = doc.GetNode(c);
144
145 if (nodeA != nullptr && nodeB != nullptr && nodeC != nullptr) {
146 nodeA->children.push_back(b);
147 nodeB->children.push_back(c);
148 nodeC->children.push_back(a); // Cycle!
149 }
150
151 doc.rootNodeId = a;
152
154
155 bool hasCycleError = false;
156 for (auto msgIt = messages.begin(); msgIt != messages.end(); ++msgIt) {
157 if (msgIt->message.find("Cycle") != std::string::npos) {
158 hasCycleError = true;
159 }
160 }
161
162 ReportTest("Test 5: Validation - Cycle Detection", hasCycleError);
163}
164
165// ============================================================================
166// Test 6: Compilation - Simple BT
167// ============================================================================
170 doc.type = "AIGraph";
171 doc.graphKind = "BehaviorTree";
172
173 NodeId root = doc.CreateNode("BT_Selector", Vector2(0, 0));
174 NodeId action = doc.CreateNode("BT_Wait", Vector2(0, 100));
175
176 auto* rootNode = doc.GetNode(root);
177 if (rootNode != nullptr) {
178 rootNode->children.push_back(action);
179 }
180
181 doc.rootNodeId = root;
182
184 std::string error;
185 bool success = BTGraphCompiler::Compile(&doc, asset, error);
186
187 bool passed = success &&
188 (asset.nodes.size() == 2) &&
189 (asset.rootNodeId == root.value);
190
191 ReportTest("Test 6: Compilation - Simple BT", passed);
192}
193
194// ============================================================================
195// Test 7: Compilation - Invalid Node Type
196// ============================================================================
199 doc.type = "AIGraph";
200 doc.graphKind = "BehaviorTree";
201
202 doc.CreateNode("INVALID_TYPE", Vector2(0, 0));
203
205 std::string error;
206 bool success = BTGraphCompiler::Compile(&doc, asset, error);
207
208 bool passed = !success && (error.find("Unknown node type") != std::string::npos);
209
210 ReportTest("Test 7: Compilation - Invalid Node Type", passed);
211}
212
213// ============================================================================
214// Test 8: Validation - Children Count Error
215// ============================================================================
218 doc.type = "AIGraph";
219 doc.graphKind = "BehaviorTree";
220
221 // Selector without children (invalid, min = 1)
222 NodeId selector = doc.CreateNode("BT_Selector", Vector2(0, 0));
223 doc.rootNodeId = selector;
224
226
227 bool hasTooFewChildrenError = false;
228 for (auto msgIt = messages.begin(); msgIt != messages.end(); ++msgIt) {
229 if (msgIt->message.find("Too few children") != std::string::npos) {
231 }
232 }
233
234 ReportTest("Test 8: Validation - Children Count Error", hasTooFewChildrenError);
235}
236
237// ============================================================================
238// Test 9: Palette Instantiation
239// ============================================================================
241 try {
243 bool passed = !palette.IsDragging() && palette.GetDraggedNodeType().empty();
244 ReportTest("Test 9: Palette Instantiation", passed);
245 } catch (...) {
246 ReportTest("Test 9: Palette Instantiation", false);
247 }
248}
249
250// ============================================================================
251// Test 10: Registry Category Query
252// ============================================================================
255
256 auto composites = registry.GetNodeTypesByCategory(BTNodeCategory::Composite);
257 auto decorators = registry.GetNodeTypesByCategory(BTNodeCategory::Decorator);
258 auto conditions = registry.GetNodeTypesByCategory(BTNodeCategory::Condition);
259 auto actions = registry.GetNodeTypesByCategory(BTNodeCategory::Action);
260
261 bool passed = (composites.size() >= 3) && // Selector, Sequence, Parallel
262 (decorators.size() >= 5) && // Inverter, Repeater, UntilSuccess, UntilFailure, Cooldown
263 (conditions.size() >= 4) && // CheckBlackboardValue, HasTarget, IsTargetInRange, CanSeeTarget
264 (actions.size() >= 8); // Wait, WaitRandomTime, SetBlackboardValue, etc.
265
266 ReportTest("Test 10: Registry Category Query", passed);
267}
268
269// ============================================================================
270// Main Test Runner
271// ============================================================================
272int main(int argc, char** argv) {
273 std::cout << "========================================" << std::endl;
274 std::cout << "AIGraphPlugin_BT Test Suite (Phase 1.2)" << std::endl;
275 std::cout << "========================================" << std::endl;
276 std::cout << std::endl;
277
288
289 std::cout << std::endl;
290 std::cout << "========================================" << std::endl;
291 std::cout << "Results: " << g_testsPassed << " passed, " << g_testsFailed << " failed" << std::endl;
292 std::cout << "========================================" << std::endl;
293
294 return (g_testsFailed == 0) ? 0 : 1;
295}
ComponentTypeID GetComponentTypeID_Static()
Definition ECS_Entity.h:56
int main()
void Test7_CompilationInvalidNodeType()
void Test9_PaletteInstantiation()
void Test2_NodeTypeQuery()
void Test10_RegistryCategoryQuery()
void Test5_ValidationCycle()
int g_testsPassed
void Test4_ValidationMultipleRoots()
void Test3_ValidationValidRoot()
void Test6_CompilationSimpleBT()
void Test1_RegistryInitialization()
int g_testsFailed
void ReportTest(const std::string &testName, bool passed)
void Test8_ValidationChildrenCount()
static bool Compile(const NodeGraph::GraphDocument *graph, BehaviorTreeAsset &outAsset, std::string &errorMsg)
Compile GraphDocument to BehaviorTreeAsset.
static std::vector< BTValidationMessage > ValidateGraph(const NodeGraph::GraphDocument *graph)
Validate a complete BT graph.
UI palette for BT node selection.
bool IsDragging() const
Check if a drag operation is in progress.
static BTNodeRegistry & Get()
Get singleton instance.
Main document class for a node graph.
Metadata for a behavior tree node type.