Skip to content

Commit a2b28d8

Browse files
committed
feat(silo): improve error handling - error if duplicate nodeIds in newick or auspiceJson
1 parent cddfe66 commit a2b28d8

3 files changed

Lines changed: 42 additions & 3 deletions

File tree

src/silo/common/phylo_tree.cpp

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,11 @@ std::shared_ptr<TreeNode> parse_auspice_tree(
3535
}
3636

3737
// Insert node into the map *after* children so it's fully constructed
38+
if (node_map.find(node->node_id) != node_map.end()) {
39+
throw silo::preprocessing::PreprocessingException(
40+
fmt::format("Duplicate node ID found in Newick string: '{}'", node->node_id.string)
41+
);
42+
}
3843
node_map[node->node_id] = node;
3944
return node;
4045
}
@@ -150,6 +155,11 @@ std::shared_ptr<TreeNode> parseSubtree(
150155
node->node_id = parseLabel(sv);
151156
skipWhitespace(sv);
152157

158+
if (node_map.find(node->node_id) != node_map.end()) {
159+
throw silo::preprocessing::PreprocessingException(
160+
fmt::format("Duplicate node ID found in Newick string: '{}'", node->node_id.string)
161+
);
162+
}
153163
node_map[node->node_id] = node;
154164

155165
return node;
@@ -179,7 +189,7 @@ PhyloTree PhyloTree::fromNewickString(const std::string& newick_string) {
179189
}
180190
} catch (const std::exception& e) {
181191
throw silo::preprocessing::PreprocessingException(
182-
fmt::format("Error when parsing the Newick string: '{}'", newick_string)
192+
fmt::format("Error when parsing the Newick string '{}': {}", newick_string, e.what())
183193
);
184194
}
185195

@@ -207,7 +217,7 @@ PhyloTree PhyloTree::fromNewickFile(const std::filesystem::path& newick_path) {
207217
return fromNewickString(contents.str());
208218
} catch (const std::exception& e) {
209219
throw silo::preprocessing::PreprocessingException(
210-
fmt::format("Error when parsing the Newick file: '{}'", newick_path.string())
220+
fmt::format("Error when parsing the Newick file '{}': {}", newick_path.string(), e.what())
211221
);
212222
}
213223
}

src/silo/common/phylo_tree.test.cpp

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,29 @@ TEST(PhyloTree, throwsOnInvalidJSON) {
5050
);
5151
}
5252

53+
TEST(PhyloTree, throwsOnInvalidAuspiceJSONDuplicateNodeId) {
54+
EXPECT_THROW(
55+
PhyloTree::fromAuspiceJSONString(R"({
56+
"version": "schema version",
57+
"meta": {},
58+
"tree": {
59+
"name": "ROOT",
60+
"children": [
61+
{
62+
"name": "CHILD",
63+
"children": [
64+
{
65+
"name": "CHILD"
66+
}
67+
]
68+
}
69+
]
70+
}
71+
})"),
72+
silo::preprocessing::PreprocessingException
73+
);
74+
}
75+
5376
TEST(PhyloTree, correctlyParsesFromNewick) {
5477
auto phylo_tree_file = PhyloTree::fromNewickString("((CHILD2)CHILD)ROOT;");
5578
ASSERT_EQ(phylo_tree_file.nodes.size(), 3);
@@ -95,3 +118,9 @@ TEST(PhyloTree, throwsOnInvalidNewickNoSemicolon) {
95118
silo::preprocessing::PreprocessingException
96119
);
97120
}
121+
122+
TEST(PhyloTree, throwsOnInvalidNewickWithDuplicateNodeId) {
123+
EXPECT_THROW(
124+
PhyloTree::fromNewickString("((CHILD)CHILD)ROOT"), silo::preprocessing::PreprocessingException
125+
);
126+
}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
((key1, key2), ((key3, key4), key5));
1+
((key1, key2)inner1, ((key3, key4)inner2, key5)inner3)root;

0 commit comments

Comments
 (0)