diff --git a/src/pack_unpack.c b/src/pack_unpack.c index 2a956e4..617b3c0 100644 --- a/src/pack_unpack.c +++ b/src/pack_unpack.c @@ -436,6 +436,8 @@ static int unpack_object(scanner_t *s, json_t *root, va_list *ap) if(root && strict == 1) { /* We need to check that all non optional items have been parsed */ const char *key; + int have_unrecognized_keys = 0; + strbuffer_t unrecognized_keys; json_t *value; long unpacked = 0; if (gotopt) { @@ -443,6 +445,14 @@ static int unpack_object(scanner_t *s, json_t *root, va_list *ap) json_object_foreach(root, key, value) { if(!hashtable_get(&key_set, key)) { unpacked++; + + if (!have_unrecognized_keys) { + strbuffer_init(&unrecognized_keys); + have_unrecognized_keys = 1; + } else { + strbuffer_append_bytes(&unrecognized_keys, ", ", 2); + } + strbuffer_append_bytes(&unrecognized_keys, key, strlen(key)); } } } else { @@ -450,7 +460,24 @@ static int unpack_object(scanner_t *s, json_t *root, va_list *ap) unpacked = (long)json_object_size(root) - (long)key_set.size; } if (unpacked) { - set_error(s, "", "%li object item(s) left unpacked", unpacked); + if (!gotopt) { + /* Find the first unrecognized key */ + json_object_foreach(root, key, value) { + if(!hashtable_get(&key_set, key)) { + if (!have_unrecognized_keys) { + strbuffer_init(&unrecognized_keys); + have_unrecognized_keys = 1; + } else { + strbuffer_append_bytes(&unrecognized_keys, ", ", 2); + } + strbuffer_append_bytes(&unrecognized_keys, key, strlen(key)); + } + } + } + set_error(s, "", + "%li object item(s) left unpacked: %s", + unpacked, strbuffer_value(&unrecognized_keys)); + strbuffer_close(&unrecognized_keys); goto out; } } diff --git a/test/suites/api/test_unpack.c b/test/suites/api/test_unpack.c index 6b76106..babe0dd 100644 --- a/test/suites/api/test_unpack.c +++ b/test/suites/api/test_unpack.c @@ -298,10 +298,16 @@ static void run_tests() json_decref(j); /* Unpack the same item twice */ - j = json_pack("{s:s, s:i}", "foo", "bar", "baz", 42); + j = json_pack("{s:s, s:i, s:b}", "foo", "bar", "baz", 42, "quux", 1); if(!json_unpack_ex(j, &error, 0, "{s:s,s:s!}", "foo", &s, "foo", &s)) fail("json_unpack object with strict validation failed"); - check_error("1 object item(s) left unpacked", "", 1, 10, 10); + { + const char *possible_errors[] = { + "2 object item(s) left unpacked: baz, quux", + "2 object item(s) left unpacked: quux, baz" + }; + check_errors(possible_errors, 2, "", 1, 10, 10); + } json_decref(j); j = json_pack("[i,{s:i,s:n},[i,i]]", 1, "foo", 2, "bar", 3, 4); @@ -335,7 +341,7 @@ static void run_tests() j = json_pack("{s{snsn}}", "foo", "bar", "baz"); if(!json_unpack_ex(j, &error, 0, "{s{sn!}}", "foo", "bar")) fail("json_unpack nested object with strict validation failed"); - check_error("1 object item(s) left unpacked", "", 1, 7, 7); + check_error("1 object item(s) left unpacked: baz", "", 1, 7, 7); json_decref(j); /* Error in nested array */ @@ -395,6 +401,6 @@ static void run_tests() i1 = i2 = i3 = 0; if(!json_unpack_ex(j, &error, 0, "{sis?i!}", "foo", &i1, "bar", &i2)) fail("json_unpack failed for optional values with strict mode and compensation"); - check_error("1 object item(s) left unpacked", "", 1, 8, 8); + check_error("1 object item(s) left unpacked: baz", "", 1, 8, 8); json_decref(j); } diff --git a/test/suites/api/util.h b/test/suites/api/util.h index 1bc4c9c..ea0be34 100644 --- a/test/suites/api/util.h +++ b/test/suites/api/util.h @@ -30,11 +30,22 @@ } while(0) /* Assumes json_error_t error */ -#define check_error(text_, source_, line_, column_, position_) \ +#define check_errors(texts_, num_, source_, line_, column_, position_) \ do { \ - if(strcmp(error.text, text_) != 0) { \ + int i_, found_ = 0; \ + for(i_ = 0; i_ < num_; i_++) { \ + if(strcmp(error.text, texts_[i_]) == 0) { \ + found_ = 1; \ + break; \ + } \ + } \ + if (!found_) { \ failhdr; \ - fprintf(stderr, "text: \"%s\" != \"%s\"\n", error.text, text_); \ + if (num_ == 1) { \ + fprintf(stderr, "text: \"%s\" != \"%s\"\n", error.text, texts_[0]); \ + } else { \ + fprintf(stderr, "text: \"%s\" does not match\n", error.text); \ + } \ exit(1); \ } \ if(strcmp(error.source, source_) != 0) { \ @@ -61,6 +72,11 @@ } while(0) +/* Assumes json_error_t error */ +#define check_error(text_, source_, line_, column_, position_) \ + check_errors(&text_, 1, source_, line_, column_, position_) + + static void run_tests(); int main() {