fix(data): buildStructTree 用 visited 集防环(不可信结构数据避免无限递归)
This commit is contained in:
parent
2bc22a55d6
commit
695aa8c310
|
|
@ -91,13 +91,17 @@ std::vector<StructTreeNode> buildStructTree(const std::vector<StructNode>& flat)
|
||||||
auto isRootLevel = [&](const StructNode& n) {
|
auto isRootLevel = [&](const StructNode& n) {
|
||||||
return n.parentId.empty() || ids.find(n.parentId) == ids.end();
|
return n.parentId.empty() || ids.find(n.parentId) == ids.end();
|
||||||
};
|
};
|
||||||
|
// visited 防环:每个 id 最多进树一次。对正常树(单父)等价于原逻辑;
|
||||||
|
// 对不可信后端数据的多节点环 / 重复 id 环,避免无限递归(规约:永不信任外部数据)。
|
||||||
|
std::set<std::string> visited;
|
||||||
std::function<std::vector<StructTreeNode>(const std::string&, bool)> build =
|
std::function<std::vector<StructTreeNode>(const std::string&, bool)> build =
|
||||||
[&](const std::string& parentId, bool root) {
|
[&](const std::string& parentId, bool root) {
|
||||||
std::vector<StructTreeNode> out;
|
std::vector<StructTreeNode> out;
|
||||||
for (const auto& n : flat) {
|
for (const auto& n : flat) {
|
||||||
const bool belongs = root ? isRootLevel(n) : (n.parentId == parentId);
|
const bool belongs = root ? isRootLevel(n) : (n.parentId == parentId);
|
||||||
if (!belongs) continue;
|
if (!belongs) continue;
|
||||||
if (n.id == parentId) continue; // 防自环
|
if (visited.count(n.id)) continue; // 已进树 → 跳过,防环/防重复
|
||||||
|
visited.insert(n.id);
|
||||||
StructTreeNode t;
|
StructTreeNode t;
|
||||||
t.node = n;
|
t.node = n;
|
||||||
t.isTm = isLeaf(n.id);
|
t.isTm = isLeaf(n.id);
|
||||||
|
|
|
||||||
|
|
@ -106,3 +106,16 @@ TEST(NavDto, BuildStructTreeOrphanParentBecomesRoot) {
|
||||||
TEST(NavDto, BuildStructTreeEmpty) {
|
TEST(NavDto, BuildStructTreeEmpty) {
|
||||||
EXPECT_TRUE(dto::buildStructTree({}).empty());
|
EXPECT_TRUE(dto::buildStructTree({}).empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(NavDto, BuildStructTreeHandlesCycleWithoutInfiniteRecursion) {
|
||||||
|
// 不可信数据:重复 id 形成可达环(R→X→Y→重复X…)。必须终止、不崩。
|
||||||
|
const std::vector<StructNode> flat = {
|
||||||
|
{"R", "根", "", "GS", "", 1},
|
||||||
|
{"X", "x", "R", "GS", "", 1},
|
||||||
|
{"Y", "y", "X", "GS", "", 1},
|
||||||
|
{"X", "x2", "Y", "TM", "", 2}, // 重复 id X,父=Y → 若不防环将无限递归
|
||||||
|
};
|
||||||
|
const auto roots = dto::buildStructTree(flat); // 不挂起即通过
|
||||||
|
ASSERT_EQ(roots.size(), 1u);
|
||||||
|
EXPECT_EQ(roots[0].node.id, "R");
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue