Files
EVEngine/test/editor_behavior_graph.cpp
西风逍遥游andCursor 24502babef Nest satellite packages under their host modules.
Keep CMake module names and trim switches, but stop flattening editing/editor and runtime bridges as top-level src/modules directories. Parent scans skip nested facets so runtime-3d can drop authoring by directory leaf.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-06 17:56:12 +08:00

56 lines
2.9 KiB
C++

#include "npc_ai/editing/BehaviorGraph.h"
#include "zeroerr/assert.h"
#include "zeroerr/unittest.h"
using namespace eve::npc_ai_editing;
using namespace eve::editing;
namespace {
GraphNodeRecord node(const char* id, const char* type, bool input, bool output) {
GraphNodeRecord result{GraphNodeId(id), type, EditorValue::Object{}, {}};
if (input) result.pins.push_back({GraphPinId(std::string(id) + ".in"), result.id,
"flow", GraphPinDirection::Input});
if (output) result.pins.push_back({GraphPinId(std::string(id) + ".out"), result.id,
"flow", GraphPinDirection::Output});
return result;
}
} // namespace
TEST_CASE("editor.behavior.graph_compiles_deterministic_tree") {
GraphDocument graph;
BehaviorGraphDomain domain;
CHECK(graph.createNode(node("root", "root", false, true)).ok());
CHECK(graph.createNode(node("sequence", "sequence", true, true)).ok());
CHECK(graph.createNode(node("condition", "condition", true, false)).ok());
CHECK(graph.createNode(node("action", "action", true, false)).ok());
CHECK(graph.connect({StableId("e1"), GraphPinId("root.out"), GraphPinId("sequence.in")},
domain.canConnect(*graph.findPin(GraphPinId("root.out")),
*graph.findPin(GraphPinId("sequence.in")))).ok());
CHECK(graph.connect({StableId("e2"), GraphPinId("sequence.out"), GraphPinId("condition.in")},
domain.canConnect(*graph.findPin(GraphPinId("sequence.out")),
*graph.findPin(GraphPinId("condition.in")))).ok());
CHECK(graph.connect({StableId("e3"), GraphPinId("sequence.out"), GraphPinId("action.in")},
domain.canConnect(*graph.findPin(GraphPinId("sequence.out")),
*graph.findPin(GraphPinId("action.in")))).ok());
auto compiled = domain.compile(graph.snapshot(domain.domain()));
CHECK_EQ(static_cast<int>(compiled.status), static_cast<int>(EditorStatus::Applied));
CHECK_EQ(compiled.root.value(), std::string("root"));
CHECK_EQ(compiled.instructions.size(), 4U);
CHECK_EQ(compiled.instructions[1].children.size(), 2U);
}
TEST_CASE("editor.behavior.graph_rejects_cycles_or_unreachable_nodes") {
BehaviorGraphDomain domain;
GraphDocumentData graph;
graph.domain = "behavior";
graph.revision = 7;
graph.nodes = {node("root", "root", false, true), node("orphan", "action", true, false)};
auto compiled = domain.compile(graph);
CHECK_EQ(static_cast<int>(compiled.status), static_cast<int>(EditorStatus::Failed));
CHECK(!compiled.diagnostics.empty());
auto wrongDirection = domain.canConnect({GraphPinId("a"), GraphNodeId("a"), "flow", GraphPinDirection::Input},
{GraphPinId("b"), GraphNodeId("b"), "flow", GraphPinDirection::Output});
CHECK(!wrongDirection.allowed);
}