[tarantool-patches] [PATCH] json: improve error messages
Roman Khabibov
roman.habibov at tarantool.org
Tue Oct 15 18:59:53 MSK 2019
Remove token names "T_*" from error messages and print a context
with "^^^".
Closes #4339
---
Branch: https://github.com/tarantool/tarantool/tree/romanhabibov/gh-4339-json-err
Issue: https://github.com/tarantool/tarantool/issues/4339
test/app-tap/json.test.lua | 55 ++++++++++++++++++++++-
third_party/lua-cjson/lua_cjson.c | 74 ++++++++++++++++++++-----------
2 files changed, 102 insertions(+), 27 deletions(-)
diff --git a/test/app-tap/json.test.lua b/test/app-tap/json.test.lua
index fadfc74ec..539ff4f59 100755
--- a/test/app-tap/json.test.lua
+++ b/test/app-tap/json.test.lua
@@ -22,7 +22,7 @@ end
tap.test("json", function(test)
local serializer = require('json')
- test:plan(40)
+ test:plan(52)
test:test("unsigned", common.test_unsigned, serializer)
test:test("signed", common.test_signed, serializer)
@@ -154,4 +154,57 @@ tap.test("json", function(test)
_, err_msg = pcall(serializer.decode, '{"hello": "world",\n 100: 200}')
test:ok(string.find(err_msg, 'line 2 at character 2') ~= nil,
'mistake on second line')
+
+ --
+ -- gh-3316: Make sure that tokens 'T_*' are absent in error
+ -- messages and a context is printed.
+ --
+ _, err_msg = pcall(serializer.decode, '{')
+ test:ok(string.find(err_msg, '\\0') ~= nil and
+ string.find(err_msg, 'here ^^^') ~= nil,
+ '"\\0" instead of T_END and context')
+ _, err_msg = pcall(serializer.decode, '{{: "world"}')
+ test:ok(string.find(err_msg, '\'{\'') ~= nil and
+ string.find(err_msg, 'here ^^^') ~= nil,
+ '"{" instead of T_OBJ_BEGIN and context')
+ _, err_msg = pcall(serializer.decode, '{"a": "world"}}')
+ test:ok(string.find(err_msg, '\'}\'') ~= nil and
+ string.find(err_msg, 'here ^^^') ~= nil,
+ '"}" instead of T_OBJ_END and context')
+ _, err_msg = pcall(serializer.decode, '{[: "world"}')
+ test:ok(string.find(err_msg, '\'[\'', 1, true) ~= nil and
+ string.find(err_msg, 'here ^^^') ~= nil,
+ '"[" instead of T_ARR_BEGIN and context')
+ _, err_msg = pcall(serializer.decode, '{]: "world"}')
+ test:ok(string.find(err_msg, '\']\'', 1, true) ~= nil and
+ string.find(err_msg, 'here ^^^') ~= nil,
+ '"}" instead of T_ARR_END and context')
+ _, err_msg = pcall(serializer.decode, '{,: "world"}')
+ test:ok(string.find(err_msg, '\',\'') ~= nil and
+ string.find(err_msg, 'here ^^^') ~= nil,
+ '"," instead of T_COMMA and context')
+ _, err_msg = pcall(serializer.decode, '{:: "world"}')
+ test:ok(string.find(err_msg, '\':\'') ~= nil and
+ string.find(err_msg, 'here ^^^') ~= nil,
+ '":" instead of T_COLON and context')
+ _, err_msg = pcall(serializer.decode, '{1: "world"}')
+ test:ok(string.find(err_msg, 'int') ~= nil and
+ string.find(err_msg, 'here ^^^') ~= nil,
+ '"int" instead of T_INT and context')
+ _, err_msg = pcall(serializer.decode, '{1.0: "world"}')
+ test:ok(string.find(err_msg, 'number') ~= nil and
+ string.find(err_msg, 'here ^^^') ~= nil,
+ '"number" instead of T_NUMBER and context')
+ _, err_msg = pcall(serializer.decode, '{true: "world"}')
+ test:ok(string.find(err_msg, 'boolean') ~= nil and
+ string.find(err_msg, 'here ^^^') ~= nil,
+ '"boolean" instead of T_BOOLEAN and context')
+ _, err_msg = pcall(serializer.decode, '{null: "world"}')
+ test:ok(string.find(err_msg, 'null') ~= nil and
+ string.find(err_msg, 'here ^^^') ~= nil,
+ '"null" instead of T_NULL and context')
+ serializer.cfg{decode_max_depth = 1}
+ _, err_msg = pcall(serializer.decode, '{{{}}}')
+ test:ok(string.find(err_msg, 'here ^^^') ~= nil,
+ 'context when too many nested structures')
end)
diff --git a/third_party/lua-cjson/lua_cjson.c b/third_party/lua-cjson/lua_cjson.c
index 3d7edbf28..aab662585 100644
--- a/third_party/lua-cjson/lua_cjson.c
+++ b/third_party/lua-cjson/lua_cjson.c
@@ -72,23 +72,23 @@ typedef enum {
} json_token_type_t;
static const char *json_token_type_name[] = {
- "T_OBJ_BEGIN",
- "T_OBJ_END",
- "T_ARR_BEGIN",
- "T_ARR_END",
- "T_STRING",
- "T_UINT",
- "T_INT",
- "T_NUMBER",
- "T_BOOLEAN",
- "T_NULL",
- "T_COLON",
- "T_COMMA",
- "T_END",
- "T_WHITESPACE",
- "T_LINEFEED",
- "T_ERROR",
- "T_UNKNOWN",
+ "'{'",
+ "'}'",
+ "'['",
+ "']'",
+ "string",
+ "unsigned int",
+ "int",
+ "number",
+ "boolean",
+ "null",
+ "':'",
+ "','",
+ "'\\0'",
+ "whitespace",
+ "'\\n'",
+ "error",
+ "unknown symbol",
NULL
};
@@ -825,6 +825,21 @@ static void json_next_token(json_parse_t *json, json_token_t *token)
json_set_token_error(token, json, "invalid token");
}
+/*
+ * Copy 10 or less (if string @a ptr is shorter than 10)
+ * characters to static string buffer @a aux_str.
+ *
+ * @param aux_str String static buffer to fill.
+ * @param ptr String with the context.
+ */
+static void fill_context(char *aux_str, const char *ptr)
+{
+ int i = 0;
+ for(; ptr[i] != '\0' && i < 10; i++)
+ aux_str[i] = ptr[i];
+ aux_str[i] = '\0';
+}
+
/* This function does not return.
* DO NOT CALL WITH DYNAMIC MEMORY ALLOCATED.
* The only supported exception is the temporary parser string
@@ -843,9 +858,13 @@ static void json_throw_parse_error(lua_State *l, json_parse_t *json,
else
found = json_token_type_name[token->type];
+ char context[11];
+ fill_context(context, json->ptr);
+
/* Note: token->column_index is 0 based, display starting from 1 */
- luaL_error(l, "Expected %s but found %s on line %d at character %d", exp,
- found, json->line_count, token->column_index + 1);
+ luaL_error(l, "Expected %s but found %s on line %d at character %d here ^^^"
+ "%s...", exp, found, json->line_count, token->column_index + 1,
+ context);
}
static inline void json_decode_ascend(json_parse_t *json)
@@ -862,10 +881,13 @@ static void json_decode_descend(lua_State *l, json_parse_t *json, int slots)
return;
}
+ char context[11];
+ fill_context(context, json->ptr);
+
strbuf_free(json->tmp);
- luaL_error(l, "Found too many nested data structures (%d) on line %d at "
- "character %d", json->current_depth, json->line_count,
- json->ptr - json->cur_line_ptr);
+ luaL_error(l, "Found too many nested data structures (%d) on line %d at cha"
+ "racter %d here ^^^%s...", json->current_depth, json->line_count,
+ json->ptr - json->cur_line_ptr, context);
}
static void json_parse_object_context(lua_State *l, json_parse_t *json)
@@ -897,7 +919,7 @@ static void json_parse_object_context(lua_State *l, json_parse_t *json)
json_next_token(json, &token);
if (token.type != T_COLON)
- json_throw_parse_error(l, json, "colon", &token);
+ json_throw_parse_error(l, json, "':'", &token);
/* Fetch value */
json_next_token(json, &token);
@@ -914,7 +936,7 @@ static void json_parse_object_context(lua_State *l, json_parse_t *json)
}
if (token.type != T_COMMA)
- json_throw_parse_error(l, json, "comma or object end", &token);
+ json_throw_parse_error(l, json, "',' or '}'", &token);
json_next_token(json, &token);
}
@@ -954,7 +976,7 @@ static void json_parse_array_context(lua_State *l, json_parse_t *json)
}
if (token.type != T_COMMA)
- json_throw_parse_error(l, json, "comma or array end", &token);
+ json_throw_parse_error(l, json, "',' or ']'", &token);
json_next_token(json, &token);
}
@@ -1039,7 +1061,7 @@ static int json_decode(lua_State *l)
json_next_token(&json, &token);
if (token.type != T_END)
- json_throw_parse_error(l, &json, "the end", &token);
+ json_throw_parse_error(l, &json, "\\0", &token);
strbuf_free(json.tmp);
--
2.17.2 (Apple Git-113)
More information about the Tarantool-patches
mailing list