From f5e4d17cf3f3f6717f14588c7e5954a07ae4d15f Mon Sep 17 00:00:00 2001 From: Delyan Angelov Date: Tue, 5 Apr 2022 12:06:00 +0300 Subject: [PATCH] json: return errors with more context, on failed json.decode() calls. --- vlib/json/json_decode_test.v | 46 ++++++++++++++++++++++++++++++++++++ vlib/v/gen/c/json.v | 25 +++++++++++++++++--- 2 files changed, 68 insertions(+), 3 deletions(-) diff --git a/vlib/json/json_decode_test.v b/vlib/json/json_decode_test.v index 56cbcad7e4..7e69ebdb63 100644 --- a/vlib/json/json_decode_test.v +++ b/vlib/json/json_decode_test.v @@ -69,3 +69,49 @@ fn test_skip_fields_should_be_initialised_by_json_decode() ? { assert task.total_comments == 55 assert task.comments == [] } + +// + +struct DbConfig { + host string + dbname string + user string +} + +fn test_decode_error_message_should_have_enough_context_empty() { + json.decode(DbConfig, '') or { + assert err.msg().len < 2 + return + } + assert false +} + +fn test_decode_error_message_should_have_enough_context_just_brace() { + json.decode(DbConfig, '{') or { + assert err.msg() == '{' + return + } + assert false +} + +fn test_decode_error_message_should_have_enough_context_trailing_comma_at_end() { + txt := '{ + "host": "localhost", + "dbname": "alex", + "user": "alex", +}' + json.decode(DbConfig, txt) or { + assert err.msg() == ' "user": "alex",\n}' + return + } + assert false +} + +fn test_decode_error_message_should_have_enough_context_in_the_middle() { + txt := '{"host": "localhost", "dbname": "alex" "user": "alex", "port": "1234"}' + json.decode(DbConfig, txt) or { + assert err.msg() == 'ost", "dbname": "alex" "user":' + return + } + assert false +} diff --git a/vlib/v/gen/c/json.v b/vlib/v/gen/c/json.v index 66ee88a9ab..0a1511f6e7 100644 --- a/vlib/v/gen/c/json.v +++ b/vlib/v/gen/c/json.v @@ -73,9 +73,28 @@ $dec_fn_dec { if (!root) { const char *error_ptr = cJSON_GetErrorPtr(); if (error_ptr != NULL) { - // fprintf(stderr, "Error in decode() for $styp error_ptr=: %s\\n", error_ptr); - // printf("\\nbad js=%%s\\n", js.str); - return (Option_$styp){.state = 2,.err = _v_error(tos2((byteptr)error_ptr)),.data = {0}}; + char *prevline_ptr = (char*)error_ptr; + int maxcontext_chars = 30; + int backlines = 1; + int backchars = maxcontext_chars-7; + while(backchars--){ + char prevc = *(prevline_ptr - 1); + if(0==prevc){ + break; + } + if(10==prevc && !backlines--){ + break; + } + prevline_ptr--; + if(123==prevc) { + break; // stop at `{` too + } + } + byte *buf = _v_malloc(maxcontext_chars + 10); + vmemset(buf, 0, maxcontext_chars+10); + vmemcpy(buf, prevline_ptr, maxcontext_chars); + // for(int x=-10;x<10;x++){ char *xx = prevline_ptr+x; fprintf(stderr, "2 prevline_ptr + %d: %p | %c | %d \\n", x, xx, (int)(*(xx)), (int)(*(xx))); } fprintf(stderr, "--------\\n"); + return (Option_$styp){.state = 2,.err = _v_error(tos2(buf)),.data = {0}}; } } ')