Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions src/tomlc17.c
Original file line number Diff line number Diff line change
Expand Up @@ -665,9 +665,13 @@ static int datum_copy(toml_datum_t *dst, toml_datum_t src, srcmap_t *sm,
return -1;
}

// Check if datum is an array of tables.
// Check if datum is an array of tables. An empty array is deliberately
// excluded: it has no elements to type-check, so treating it as an array
// of tables here would be true only vacuously, and datum_merge's caller
// relies on this to distinguish "override with an empty array" from
// "append zero table elements" (see below).
static inline bool is_array_of_tables(toml_datum_t datum) {
bool ret = (datum.type == TOML_ARRAY);
bool ret = (datum.type == TOML_ARRAY) && (datum.u.arr.size > 0);
for (int i = 0; ret && i < datum.u.arr.size; i++) {
ret = (datum.u.arr.elem[i].type == TOML_TABLE);
}
Expand Down
29 changes: 29 additions & 0 deletions test/merge/test1.c
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,33 @@ static void test_array_of_tables_overridden_by_plain_array() {
check(doc1, doc2, expected);
}

// An array of tables overridden by an empty array must be replaced with
// the empty array, not left untouched. is_array_of_tables() used to treat
// an empty array as vacuously true (no elements fail the table check), so
// merging in an empty array hit the append branch instead of the override
// branch and appended zero elements onto the untouched destination.
static void test_array_of_tables_overridden_by_empty_array() {
printf("Running test_array_of_tables_overridden_by_empty_array...\n");
const char *doc1 = "[[arr]]\n"
"x = 1";
const char *doc2 = "arr = []";
const char *expected = "arr = []";
check(doc1, doc2, expected);
}

// The reverse direction, for completeness: an empty array overridden by a
// real array of tables must end up with the array of tables, whether the
// merge takes the append path or the override path.
static void test_empty_array_overridden_by_array_of_tables() {
printf("Running test_empty_array_overridden_by_array_of_tables...\n");
const char *doc1 = "arr = []";
const char *doc2 = "[[arr]]\n"
"x = 1";
const char *expected = "[[arr]]\n"
"x = 1";
check(doc1, doc2, expected);
}

static void test_type_conflicts() {
printf("Running test_type_conflicts...\n");
const char *doc1 = "value = 42";
Expand Down Expand Up @@ -217,6 +244,8 @@ int main() {
test_array_of_tables();
test_plain_array_overridden_by_array_of_tables();
test_array_of_tables_overridden_by_plain_array();
test_array_of_tables_overridden_by_empty_array();
test_empty_array_overridden_by_array_of_tables();
test_type_conflicts();
test_empty_documents();
test_keys_outlive_inputs();
Expand Down