Mercurial > dovecot > core-2.2
view src/lib/test-json-parser.c @ 23007:36e01285b5b8
lib: buffer - Improve header comment for buffer_insert() and buffer_delete().
author | Stephan Bosch <stephan.bosch@dovecot.fi> |
---|---|
date | Mon, 18 Mar 2019 00:52:37 +0100 |
parents | cb108f786fb4 |
children |
line wrap: on
line source
/* Copyright (c) 2013-2018 Dovecot authors, see the included COPYING file */ #include "test-lib.h" #include "str.h" #include "istream-private.h" #include "json-parser.h" #define TYPE_SKIP 100 #define TYPE_STREAM 101 static const char json_input[] = "{\n" "\t\"key\"\t:\t\t\"string\"," " \"key2\" : 1234, \n" "\"key3\":true," "\"key4\":false," "\"skip1\": \"jsifjaisfjiasji\"," "\"skip2\": { \"x\":{ \"y\":123}, \"z\":[5,[6],{\"k\":0},3]}," "\"key5\":null," "\"key6\": {}," "\"key7\": {" " \"sub1\":\"value\"" "}," "\"key8\": {" " \"sub2\":-12.456,\n" " \"sub3\":12.456e9,\n" " \"sub4\":0.456e-789" "}," "\"key9\": \"foo\\\\\\\"\\b\\f\\n\\r\\t\\u0001\\uffff\"," "\"key10\": \"foo\\\\\\\"\\b\\f\\n\\r\\t\\u0001\\uffff\"," "\"key11\": []," "\"key12\": [ \"foo\" , 5.24,[true],{\"aobj\":[]}]" "}\n"; static struct { enum json_type type; const char *value; } json_output[] = { { JSON_TYPE_OBJECT_KEY, "key" }, { JSON_TYPE_STRING, "string" }, { JSON_TYPE_OBJECT_KEY, "key2" }, { JSON_TYPE_NUMBER, "1234" }, { JSON_TYPE_OBJECT_KEY, "key3" }, { JSON_TYPE_TRUE, "true" }, { JSON_TYPE_OBJECT_KEY, "key4" }, { JSON_TYPE_FALSE, "false" }, { JSON_TYPE_OBJECT_KEY, "skip1" }, { TYPE_SKIP, NULL }, { JSON_TYPE_OBJECT_KEY, "skip2" }, { TYPE_SKIP, NULL }, { JSON_TYPE_OBJECT_KEY, "key5" }, { JSON_TYPE_NULL, NULL }, { JSON_TYPE_OBJECT_KEY, "key6" }, { JSON_TYPE_OBJECT, NULL }, { JSON_TYPE_OBJECT_END, NULL }, { JSON_TYPE_OBJECT_KEY, "key7" }, { JSON_TYPE_OBJECT, NULL }, { JSON_TYPE_OBJECT_KEY, "sub1" }, { JSON_TYPE_STRING, "value" }, { JSON_TYPE_OBJECT_END, NULL }, { JSON_TYPE_OBJECT_KEY, "key8" }, { JSON_TYPE_OBJECT, NULL }, { JSON_TYPE_OBJECT_KEY, "sub2" }, { JSON_TYPE_NUMBER, "-12.456" }, { JSON_TYPE_OBJECT_KEY, "sub3" }, { JSON_TYPE_NUMBER, "12.456e9" }, { JSON_TYPE_OBJECT_KEY, "sub4" }, { JSON_TYPE_NUMBER, "0.456e-789" }, { JSON_TYPE_OBJECT_END, NULL }, { JSON_TYPE_OBJECT_KEY, "key9" }, { JSON_TYPE_STRING, "foo\\\"\b\f\n\r\t\001\xef\xbf\xbf" }, { JSON_TYPE_OBJECT_KEY, "key10" }, { TYPE_STREAM, "foo\\\"\b\f\n\r\t\001\xef\xbf\xbf" }, { JSON_TYPE_OBJECT_KEY, "key11" }, { JSON_TYPE_ARRAY, NULL }, { JSON_TYPE_ARRAY_END, NULL }, { JSON_TYPE_OBJECT_KEY, "key12" }, { JSON_TYPE_ARRAY, NULL }, { JSON_TYPE_STRING, "foo" }, { JSON_TYPE_NUMBER, "5.24" }, { JSON_TYPE_ARRAY, NULL }, { JSON_TYPE_TRUE, "true" }, { JSON_TYPE_ARRAY_END, NULL }, { JSON_TYPE_OBJECT, NULL }, { JSON_TYPE_OBJECT_KEY, "aobj" }, { JSON_TYPE_ARRAY, NULL }, { JSON_TYPE_ARRAY_END, NULL }, { JSON_TYPE_OBJECT_END, NULL }, { JSON_TYPE_ARRAY_END, NULL } }; static int stream_read_value(struct istream **input, const char **value_r) { const unsigned char *data; size_t size; ssize_t ret; while ((ret = i_stream_read(*input)) > 0) ; if (ret == 0) return 0; i_assert(ret == -1); if ((*input)->stream_errno != 0) return -1; data = i_stream_get_data(*input, &size); *value_r = t_strndup(data, size); i_stream_unref(input); return 1; } static void test_json_parser_success(bool full_size) { struct json_parser *parser; struct istream *input, *jsoninput = NULL; enum json_type type; const char *value, *error; unsigned int i, pos, json_input_len = strlen(json_input); int ret = 0; test_begin(full_size ? "json parser" : "json parser (nonblocking)"); input = test_istream_create_data(json_input, json_input_len); test_istream_set_allow_eof(input, FALSE); parser = json_parser_init(input); i = full_size ? json_input_len : 0; for (pos = 0; i <= json_input_len; i++) { test_istream_set_size(input, i); for (;;) { value = NULL; if (pos < N_ELEMENTS(json_output) && json_output[pos].type == (enum json_type)TYPE_SKIP) { json_parse_skip_next(parser); pos++; continue; } else if (pos == N_ELEMENTS(json_output) || json_output[pos].type != (enum json_type)TYPE_STREAM) { ret = json_parse_next(parser, &type, &value); } else { ret = jsoninput != NULL ? 1 : json_parse_next_stream(parser, &jsoninput); if (ret > 0 && jsoninput != NULL) ret = stream_read_value(&jsoninput, &value); type = TYPE_STREAM; } if (ret <= 0) break; i_assert(pos < N_ELEMENTS(json_output)); test_assert(json_output[pos].type == type); test_assert(null_strcmp(json_output[pos].value, value) == 0); pos++; } test_assert(ret == 0); } test_assert(pos == N_ELEMENTS(json_output)); test_istream_set_allow_eof(input, TRUE); test_assert(json_parse_next(parser, &type, &value) == -1); i_stream_unref(&input); test_assert(json_parser_deinit(&parser, &error) == 0); test_end(); } static void test_json_parser_skip_array(void) { static const char *test_input = "[ 1, {\"foo\": 1 }, 2, \"bar\", 3, 1.234, 4, [], 5, [[]], 6, true ]"; struct json_parser *parser; struct istream *input; enum json_type type; const char *value, *error; int i; test_begin("json parser skip array"); input = test_istream_create_data(test_input, strlen(test_input)); parser = json_parser_init_flags(input, JSON_PARSER_NO_ROOT_OBJECT); test_assert(json_parse_next(parser, &type, &value) > 0 && type == JSON_TYPE_ARRAY); for (i = 1; i <= 6; i++) { test_assert(json_parse_next(parser, &type, &value) > 0 && type == JSON_TYPE_NUMBER && atoi(value) == i); json_parse_skip_next(parser); } test_assert(json_parse_next(parser, &type, &value) > 0 && type == JSON_TYPE_ARRAY_END); test_assert(json_parser_deinit(&parser, &error) == 0); i_stream_unref(&input); test_end(); } static int test_json_parse_input(const char *test_input, enum json_parser_flags flags) { 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_flags(input, flags); 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_primitive_values(void) { static struct { const char *str; int ret; } test_inputs[] = { { "\"hello\"", 1 }, { "null", 1 }, { "1234", 1 }, { "1234.1234", 1 }, { "{}", 2 }, { "[]", 2 }, { "true", 1 }, { "false", 1 } }; unsigned int i; test_begin("json_parser (primitives)"); for (i = 0; i < N_ELEMENTS(test_inputs); i++) test_assert_idx(test_json_parse_input(test_inputs[i].str, JSON_PARSER_NO_ROOT_OBJECT) == test_inputs[i].ret, i); test_end(); } 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) < 0, i); test_end(); } static void test_json_append_escaped(void) { string_t *str = t_str_new(32); test_begin("json_append_escaped()"); json_append_escaped(str, "\b\f\r\n\t\"\\\001\002-\xC3\xA4"); test_assert(strcmp(str_c(str), "\\b\\f\\r\\n\\t\\\"\\\\\\u0001\\u0002-\xC3\xA4") == 0); test_end(); } static void test_json_append_escaped_data(void) { static const unsigned char test_input[] = "\b\f\r\n\t\"\\\000\001\002-\xC3\xA4"; string_t *str = t_str_new(32); test_begin("json_append_escaped()"); json_append_escaped_data(str, test_input, sizeof(test_input)-1); test_assert(strcmp(str_c(str), "\\b\\f\\r\\n\\t\\\"\\\\\\u0000\\u0001\\u0002-\xC3\xA4") == 0); test_end(); } void test_json_parser(void) { test_json_parser_success(TRUE); test_json_parser_success(FALSE); test_json_parser_skip_array(); test_json_parser_primitive_values(); test_json_parser_errors(); test_json_append_escaped(); test_json_append_escaped_data(); }