/** * @file test_scene_graph.cpp * @brief SceneGraph 单元测试 * * 测试场景图的节点管理、遍历、查找等功能。 */ #include "test_framework.h" #include #include #include using namespace extra2d; using namespace extra2d::test; namespace { constexpr f32 EPSILON = 0.0001f; bool vec2Equal(const Vec2& a, const Vec2& b, f32 eps = EPSILON) { return std::abs(a.x - b.x) < eps && std::abs(a.y - b.y) < eps; } } // --------------------------------------------------------------------------- // SceneGraph 基本测试 // --------------------------------------------------------------------------- TEST(SceneGraph, Create) { SceneGraph graph; TEST_ASSERT_EQ(0u, graph.nodeCount()); TEST_ASSERT_TRUE(graph.roots().empty()); } TEST(SceneGraph, CreateNode) { SceneGraph graph; auto node = graph.create(); TEST_ASSERT_NOT_NULL(node.get()); TEST_ASSERT_EQ(1u, graph.nodeCount()); TEST_ASSERT_EQ(node.get(), graph.roots()[0].get()); } TEST(SceneGraph, AddNode) { SceneGraph graph; auto node = ptr::make(); graph.add(node); TEST_ASSERT_EQ(1u, graph.nodeCount()); TEST_ASSERT_EQ(node.get(), graph.roots()[0].get()); } TEST(SceneGraph, RemoveNode) { SceneGraph graph; auto node = graph.create(); graph.remove(node); TEST_ASSERT_EQ(0u, graph.nodeCount()); } TEST(SceneGraph, Clear) { SceneGraph graph; graph.create(); graph.create(); graph.create(); TEST_ASSERT_EQ(3u, graph.nodeCount()); graph.clear(); TEST_ASSERT_EQ(0u, graph.nodeCount()); } // --------------------------------------------------------------------------- // 节点查找测试 // --------------------------------------------------------------------------- TEST(SceneGraph, FindByName) { SceneGraph graph; auto node1 = graph.create(); node1->setName("Node1"); auto node2 = graph.create(); node2->setName("Node2"); auto node3 = graph.create(); node3->setName("Node3"); Node* found = graph.find("Node2"); TEST_ASSERT_NOT_NULL(found); TEST_ASSERT_EQ(node2.get(), found); } TEST(SceneGraph, FindByNameNotFound) { SceneGraph graph; graph.create()->setName("Node1"); graph.create()->setName("Node2"); Node* found = graph.find("NonExistent"); TEST_ASSERT_NULL(found); } TEST(SceneGraph, FindByTag) { SceneGraph graph; auto node1 = graph.create(); node1->setTag(1); auto node2 = graph.create(); node2->setTag(2); auto node3 = graph.create(); node3->setTag(3); Node* found = graph.findByTag(2); TEST_ASSERT_NOT_NULL(found); TEST_ASSERT_EQ(node2.get(), found); } TEST(SceneGraph, FindByTagNotFound) { SceneGraph graph; graph.create()->setTag(1); graph.create()->setTag(2); Node* found = graph.findByTag(999); TEST_ASSERT_NULL(found); } // --------------------------------------------------------------------------- // 遍历测试 // --------------------------------------------------------------------------- TEST(SceneGraph, Traverse) { SceneGraph graph; auto node1 = graph.create(); node1->setName("Node1"); auto node2 = graph.create(); node2->setName("Node2"); auto child = ptr::make(); child->setName("Child"); node1->addChild(child); std::vector visited; graph.traverse([&visited](Node* node) { visited.push_back(node->name()); }); TEST_ASSERT_EQ(3u, visited.size()); bool foundNode1 = false, foundNode2 = false, foundChild = false; for (const auto& name : visited) { if (name == "Node1") foundNode1 = true; if (name == "Node2") foundNode2 = true; if (name == "Child") foundChild = true; } TEST_ASSERT_TRUE(foundNode1); TEST_ASSERT_TRUE(foundNode2); TEST_ASSERT_TRUE(foundChild); } TEST(SceneGraph, TraverseRecursive) { SceneGraph graph; auto root = graph.create(); root->setName("Root"); auto child1 = ptr::make(); child1->setName("Child1"); root->addChild(child1); auto grandchild = ptr::make(); grandchild->setName("Grandchild"); child1->addChild(grandchild); std::vector visited; graph.traverseRecursive(root.get(), [&visited](Node* node) { visited.push_back(node->name()); }); TEST_ASSERT_EQ(3u, visited.size()); TEST_ASSERT_EQ("Root", visited[0]); TEST_ASSERT_EQ("Child1", visited[1]); TEST_ASSERT_EQ("Grandchild", visited[2]); } // --------------------------------------------------------------------------- // 更新测试 // --------------------------------------------------------------------------- class TestUpdateNode : public Node { public: void onUpdate(f32 dt) override { updateCount++; lastDt = dt; } int updateCount = 0; f32 lastDt = 0.0f; }; TEST(SceneGraph, Update) { SceneGraph graph; auto node = graph.create(); graph.update(0.016f); TEST_ASSERT_EQ(1, node->updateCount); TEST_ASSERT_TRUE(std::abs(node->lastDt - 0.016f) < EPSILON); } TEST(SceneGraph, UpdateMultipleNodes) { SceneGraph graph; auto node1 = graph.create(); auto node2 = graph.create(); auto node3 = graph.create(); graph.update(0.033f); TEST_ASSERT_EQ(1, node1->updateCount); TEST_ASSERT_EQ(1, node2->updateCount); TEST_ASSERT_EQ(1, node3->updateCount); } // --------------------------------------------------------------------------- // 层级结构测试 // --------------------------------------------------------------------------- TEST(SceneGraph, HierarchyWithChildren) { SceneGraph graph; auto parent = graph.create(); parent->setName("Parent"); auto child1 = ptr::make(); child1->setName("Child1"); parent->addChild(child1); auto child2 = ptr::make(); child2->setName("Child2"); parent->addChild(child2); TEST_ASSERT_EQ(1u, graph.nodeCount()); TEST_ASSERT_EQ(2u, parent->children().size()); } TEST(SceneGraph, DeepHierarchy) { SceneGraph graph; auto root = graph.create(); root->setPos(100, 100); auto level1 = ptr::make(); level1->setPos(50, 50); root->addChild(level1); auto level2 = ptr::make(); level2->setPos(25, 25); level1->addChild(level2); auto level3 = ptr::make(); level3->setPos(10, 10); level2->addChild(level3); Vec2 worldPos = level3->worldPos(); TEST_ASSERT_TRUE(vec2Equal(worldPos, Vec2(185, 185))); } // --------------------------------------------------------------------------- // 自定义节点类型测试 // --------------------------------------------------------------------------- class CustomNode : public Node { public: CustomNode() : value(0) {} explicit CustomNode(int v) : value(v) {} int value; protected: Vec2 defaultAnchor() const override { return Vec2(0.0f, 0.0f); } }; TEST(SceneGraph, CreateCustomNode) { SceneGraph graph; auto node = graph.create(42); TEST_ASSERT_NOT_NULL(node.get()); TEST_ASSERT_EQ(42, node->value); TEST_ASSERT_TRUE(vec2Equal(node->anchor, Vec2(0, 0))); } // --------------------------------------------------------------------------- // 节点可见性测试 // --------------------------------------------------------------------------- TEST(SceneGraph, NodeVisibility) { SceneGraph graph; auto node = graph.create(); TEST_ASSERT_TRUE(node->visible()); node->setVisible(false); TEST_ASSERT_FALSE(node->visible()); }