changeset 19687:2166e0f25e43

lib: Code cleanup to json-parser - assume less that the root is an object
author Timo Sirainen <timo.sirainen@dovecot.fi>
date Mon, 01 Feb 2016 17:00:11 +0200
parents d3aa060852e6
children 0869e8023eab
files src/lib/json-parser.c src/lib/test-json-parser.c
diffstat 2 files changed, 55 insertions(+), 16 deletions(-) [+]
line wrap: on
line diff
--- a/src/lib/json-parser.c	Fri Jan 29 00:08:33 2016 +0200
+++ b/src/lib/json-parser.c	Mon Feb 01 17:00:11 2016 +0200
@@ -335,21 +335,16 @@
 	json_parser_update_input_pos(parser);
 
 	nested_states = array_get(&parser->nesting, &count);
-	if (count == 0) {
+	i_assert(count > 0);
+	if (count == 1) {
 		/* closing root */
 		parser->state = JSON_STATE_DONE;
 		return 0;
 	}
 
 	/* closing a nested object */
-	if (count == 1) {
-		/* we're back to root */
-		parser->state = JSON_STATE_OBJECT_NEXT;
-	} else {
-		/* back to previous nested object */
-		parser->state = nested_states[count-2] == JSON_STATE_OBJECT_OPEN ?
-			JSON_STATE_OBJECT_NEXT : JSON_STATE_ARRAY_NEXT;
-	}
+	parser->state = nested_states[count-2] == JSON_STATE_OBJECT_OPEN ?
+		JSON_STATE_OBJECT_NEXT : JSON_STATE_ARRAY_NEXT;
 	array_delete(&parser->nesting, count-1, 1);
 
 	if (parser->nested_skip_count > 0) {
@@ -377,6 +372,14 @@
 	return 1;
 }
 
+static void json_parser_object_open(struct json_parser *parser)
+{
+	parser->data++;
+	parser->state = JSON_STATE_OBJECT_OPEN;
+	array_append(&parser->nesting, &parser->state, 1);
+	json_parser_update_input_pos(parser);
+}
+
 static int
 json_try_parse_next(struct json_parser *parser, enum json_type *type_r,
 		    const char **value_r)
@@ -393,17 +396,12 @@
 			parser->error = "Object doesn't begin with '{'";
 			return -1;
 		}
-		parser->data++;
-		parser->state = JSON_STATE_OBJECT_OPEN;
-		json_parser_update_input_pos(parser);
+		json_parser_object_open(parser);
 		return 0;
 	case JSON_STATE_OBJECT_VALUE:
 	case JSON_STATE_ARRAY_VALUE:
 		if (*parser->data == '{') {
-			parser->data++;
-			parser->state = JSON_STATE_OBJECT_OPEN;
-			array_append(&parser->nesting, &parser->state, 1);
-			json_parser_update_input_pos(parser);
+			json_parser_object_open(parser);
 
 			if (parser->skipping) {
 				parser->nested_skip_count++;
--- a/src/lib/test-json-parser.c	Fri Jan 29 00:08:33 2016 +0200
+++ b/src/lib/test-json-parser.c	Mon Feb 01 17:00:11 2016 +0200
@@ -163,6 +163,46 @@
 	test_end();
 }
 
+static int test_json_parse_input(const char *test_input)
+{
+	struct json_parser *parser;
+	struct istream *input;
+	enum json_type type;
+	const char *value, *error;
+	int ret = 0;
+
+	input = test_istream_create_data(test_input, strlen(test_input));
+	parser = json_parser_init(input);
+	while (json_parse_next(parser, &type, &value) > 0)
+		ret++;
+	if (json_parser_deinit(&parser, &error) < 0)
+		ret = -1;
+	i_stream_unref(&input);
+	return ret;
+}
+
+static void test_json_parser_errors(void)
+{
+	static const char *test_inputs[] = {
+		"{",
+		"{:}",
+		"{\"foo\":}",
+		"{\"foo\" []}",
+		"{\"foo\": [1}",
+		"{\"foo\": [1,]}",
+		"{\"foo\": [1,]}",
+		"{\"foo\": 1,}",
+		"{\"foo\": 1.}}",
+		"{\"foo\": 1},{}"
+	};
+	unsigned int i;
+
+	test_begin("json parser error handling");
+	for (i = 0; i < N_ELEMENTS(test_inputs); i++)
+		test_assert_idx(test_json_parse_input(test_inputs[i]) < 0, i);
+	test_end();
+}
+
 static void test_json_append_escaped(void)
 {
 	string_t *str = t_str_new(32);
@@ -189,6 +229,7 @@
 {
 	test_json_parser_success(TRUE);
 	test_json_parser_success(FALSE);
+	test_json_parser_errors();
 	test_json_append_escaped();
 	test_json_append_escaped_data();
 }