@@ -8968,6 +8968,28 @@ test_sort_tables_errors(void)
8968
8968
ret = tsk_table_collection_sort (& tables , & pos , 0 );
8969
8969
CU_ASSERT_EQUAL_FATAL (ret , TSK_ERR_SORT_OFFSET_NOT_SUPPORTED );
8970
8970
8971
+ /* Test TSK_ERR_MUTATION_PARENT_INCONSISTENT */
8972
+ ret = tsk_table_collection_clear (& tables , 0 );
8973
+ CU_ASSERT_EQUAL_FATAL (ret , 0 );
8974
+ tables .sequence_length = 1.0 ;
8975
+
8976
+ ret = tsk_node_table_add_row (& tables .nodes , 0 , 0.0 , TSK_NULL , TSK_NULL , NULL , 0 );
8977
+ CU_ASSERT_FATAL (ret >= 0 );
8978
+ ret = tsk_site_table_add_row (& tables .sites , 0.0 , "x" , 1 , NULL , 0 );
8979
+ CU_ASSERT_FATAL (ret >= 0 );
8980
+
8981
+ ret = tsk_mutation_table_add_row (& tables .mutations , 0 , 0 , 2 , 0.0 , "a" , 1 , NULL , 0 );
8982
+ CU_ASSERT_FATAL (ret >= 0 );
8983
+ ret = tsk_mutation_table_add_row (& tables .mutations , 0 , 0 , 3 , 0.0 , "b" , 1 , NULL , 0 );
8984
+ CU_ASSERT_FATAL (ret >= 0 );
8985
+ ret = tsk_mutation_table_add_row (& tables .mutations , 0 , 0 , 1 , 0.0 , "c" , 1 , NULL , 0 );
8986
+ CU_ASSERT_FATAL (ret >= 0 );
8987
+ ret = tsk_mutation_table_add_row (& tables .mutations , 0 , 0 , 2 , 0.0 , "d" , 1 , NULL , 0 );
8988
+ CU_ASSERT_FATAL (ret >= 0 );
8989
+
8990
+ ret = tsk_table_collection_sort (& tables , NULL , 0 );
8991
+ CU_ASSERT_EQUAL_FATAL (ret , TSK_ERR_MUTATION_PARENT_INCONSISTENT );
8992
+
8971
8993
tsk_table_collection_free (& tables );
8972
8994
tsk_treeseq_free (& ts );
8973
8995
}
@@ -9032,6 +9054,120 @@ test_sort_tables_mutation_times(void)
9032
9054
tsk_treeseq_free (& ts );
9033
9055
}
9034
9056
9057
+ static void
9058
+ test_sort_tables_mutations (void )
9059
+ {
9060
+ int ret ;
9061
+ tsk_table_collection_t tables ;
9062
+
9063
+ /* Sorting hierarchy:
9064
+ * 1. site
9065
+ * 2. time (when known)
9066
+ * 3. node_time
9067
+ * 4. num_descendants: parent mutations first
9068
+ * 5. node_id
9069
+ * 6. mutation_id
9070
+ */
9071
+
9072
+ const char * sites = "0.0 A\n"
9073
+ "0.5 T\n"
9074
+ "0.75 G\n" ;
9075
+
9076
+ const char * mutations_unsorted =
9077
+ /* Test site criterion (primary) - site 1 should come after site 0 */
9078
+ "1 0 X -1 0.0\n" /* mut 0: site 1, will be sorted after site 0 mutations */
9079
+ "0 0 Y -1 0.0\n" /* mut 1: site 0, will be sorted before site 1 mutations */
9080
+
9081
+ /* Test time criterion - within same site, earlier time first */
9082
+ "0 4 B -1 2.0\n" /* mut 2: site 0, node 4 (time 1.0), time 2.0 (later time)
9083
+ */
9084
+ "0 5 A -1 2.5\n" /* mut 3: site 0, node 5 (time 2.0), time 2.5 (earlier
9085
+ relative) */
9086
+
9087
+ /* Test unknown vs known times - unknown times at site 2, fall back to node_time
9088
+ sorting */
9089
+ "2 4 U2 -1\n" /* mut 4: site 2, node 4 (time 1.0), unknown time - falls back
9090
+ to node_time */
9091
+ "2 4 U3 -1\n" /* mut 5: site 2, node 4 (time 1.0), unknown time - should use
9092
+ mutation_id as tiebreaker */
9093
+ "2 5 U1 -1\n" /* mut 6: site 2, node 5 (time 2.0), unknown time - falls back
9094
+ to node_time */
9095
+
9096
+ /* Test node_time criterion - same site, same mut time, different node times */
9097
+ "0 4 D -1 1.5\n" /* mut 7: site 0, node 4 (time 1.0), mut time 1.5 */
9098
+ "0 5 C -1 2.5\n" /* mut 8: site 0, node 5 (time 2.0), mut time 2.5 - same
9099
+ mut time */
9100
+
9101
+ /* Test num_descendants criterion with mutation parent-child relationships */
9102
+ "0 2 P -1 0.0\n" /* mut 9: site 0, node 2, parent mutation (0 descendants
9103
+ initially) */
9104
+ "0 1 C1 9 0.0\n" /* mut 10: site 0, node 1, child of mut 9 (parent now has
9105
+ 1+ descendants) */
9106
+ "0 1 C2 9 0.0\n" /* mut 11: site 0, node 1, another child of mut 9 (parent
9107
+ now has 2+ descendants) */
9108
+ "0 3 Q -1 0.0\n" /* mut 12: site 0, node 3, no children (0 descendants) */
9109
+ "0 0 C3 10 0.0\n" /* mut 13: site 0, node 0, child of mut 10 (making mut 9 a
9110
+ grandparent) */
9111
+
9112
+ /* Test node and mutation_id criteria for final tiebreaking */
9113
+ "0 0 Z1 -1 0.0\n" /* mut 14: site 0, node 0, no parent, will test node+id
9114
+ ordering */
9115
+ "0 0 Z2 -1 0.0\n" ; /* mut 15: site 0, node 0, no parent, later in input =
9116
+ higher ID */
9117
+
9118
+ const char * mutations_sorted =
9119
+ /* Site 0 mutations - known times first, sorted by time */
9120
+ "0 5 A -1 2.5\n"
9121
+ "0 5 C -1 2.5\n"
9122
+ "0 4 B -1 2.0\n"
9123
+ "0 4 D -1 1.5\n"
9124
+ "0 2 P -1 0.0\n"
9125
+ "0 1 C1 4 0.0\n"
9126
+ "0 0 Y -1 0.0\n"
9127
+ "0 0 C3 5 0.0\n"
9128
+ "0 0 Z1 -1 0.0\n"
9129
+ "0 0 Z2 -1 0.0\n"
9130
+ "0 1 C2 4 0.0\n"
9131
+ "0 3 Q -1 0.0\n"
9132
+
9133
+ /* Site 1 mutations */
9134
+ "1 0 X -1 0.0\n"
9135
+
9136
+ /* Site 2 mutations - unknown times, sorted by node_time then other criteria */
9137
+ "2 5 U1 -1\n"
9138
+ "2 4 U2 -1\n"
9139
+ "2 4 U3 -1\n" ;
9140
+
9141
+ ret = tsk_table_collection_init (& tables , 0 );
9142
+ CU_ASSERT_EQUAL_FATAL (ret , 0 );
9143
+ tables .sequence_length = 1.0 ;
9144
+ parse_nodes (single_tree_ex_nodes , & tables .nodes );
9145
+ parse_edges (single_tree_ex_edges , & tables .edges );
9146
+
9147
+ parse_sites (sites , & tables .sites );
9148
+ CU_ASSERT_EQUAL_FATAL (tables .sites .num_rows , 3 );
9149
+
9150
+ parse_mutations (mutations_unsorted , & tables .mutations );
9151
+ CU_ASSERT_EQUAL_FATAL (tables .mutations .num_rows , 16 );
9152
+
9153
+ ret = tsk_table_collection_sort (& tables , NULL , 0 );
9154
+ CU_ASSERT_EQUAL_FATAL (ret , 0 );
9155
+
9156
+ tsk_table_collection_t expected ;
9157
+ ret = tsk_table_collection_init (& expected , 0 );
9158
+ CU_ASSERT_EQUAL_FATAL (ret , 0 );
9159
+ expected .sequence_length = 1.0 ;
9160
+ parse_nodes (single_tree_ex_nodes , & expected .nodes );
9161
+ parse_edges (single_tree_ex_edges , & expected .edges );
9162
+ parse_sites (sites , & expected .sites );
9163
+ parse_mutations (mutations_sorted , & expected .mutations );
9164
+
9165
+ CU_ASSERT_TRUE (tsk_mutation_table_equals (& tables .mutations , & expected .mutations , 0 ));
9166
+
9167
+ tsk_table_collection_free (& expected );
9168
+ tsk_table_collection_free (& tables );
9169
+ }
9170
+
9035
9171
static void
9036
9172
test_sort_tables_canonical_errors (void )
9037
9173
{
@@ -11608,6 +11744,7 @@ main(int argc, char **argv)
11608
11744
{ "test_sort_tables_errors" , test_sort_tables_errors },
11609
11745
{ "test_sort_tables_individuals" , test_sort_tables_individuals },
11610
11746
{ "test_sort_tables_mutation_times" , test_sort_tables_mutation_times },
11747
+ { "test_sort_tables_mutations" , test_sort_tables_mutations },
11611
11748
{ "test_sort_tables_migrations" , test_sort_tables_migrations },
11612
11749
{ "test_sort_tables_no_edge_metadata" , test_sort_tables_no_edge_metadata },
11613
11750
{ "test_sort_tables_offsets" , test_sort_tables_offsets },
0 commit comments