bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2013-2018 Dovecot authors, see the included COPYING file */
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen#include "test-lib.h"
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen#include "str.h"
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen#include "istream-private.h"
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen#include "json-parser.h"
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen
2eccb2637d0153bb7f9ad39a70f254cece74342cTimo Sirainen#define TYPE_SKIP 100
2eccb2637d0153bb7f9ad39a70f254cece74342cTimo Sirainen#define TYPE_STREAM 101
7877db7b5daad125b6cb3e015574f33871c9a51bTimo Sirainen
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainenstatic const char json_input[] =
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen "{\n"
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen "\t\"key\"\t:\t\t\"string\","
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen " \"key2\" : 1234, \n"
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen "\"key3\":true,"
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen "\"key4\":false,"
2eccb2637d0153bb7f9ad39a70f254cece74342cTimo Sirainen "\"skip1\": \"jsifjaisfjiasji\","
86bdb644d147a73df85abce4325254d694217a5fTimo Sirainen "\"skip2\": { \"x\":{ \"y\":123}, \"z\":[5,[6],{\"k\":0},3]},"
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen "\"key5\":null,"
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen "\"key6\": {},"
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen "\"key7\": {"
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen " \"sub1\":\"value\""
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen "},"
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen "\"key8\": {"
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen " \"sub2\":-12.456,\n"
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen " \"sub3\":12.456e9,\n"
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen " \"sub4\":0.456e-789"
4e8e7a93628b4ed60aaaa47c6f72c1433f21e81dTimo Sirainen "},"
a01faca549a403b2eda938cea0b1fb76c3ff44b6Aki Tuomi "\"key9\": \"foo\\\\\\\"\\b\\f\\n\\r\\t\\u0001\\u10ff\","
a01faca549a403b2eda938cea0b1fb76c3ff44b6Aki Tuomi "\"key10\": \"foo\\\\\\\"\\b\\f\\n\\r\\t\\u0001\\u10ff\","
86bdb644d147a73df85abce4325254d694217a5fTimo Sirainen "\"key11\": [],"
a01faca549a403b2eda938cea0b1fb76c3ff44b6Aki Tuomi "\"key12\": [ \"foo\" , 5.24,[true],{\"aobj\":[]}],"
a01faca549a403b2eda938cea0b1fb76c3ff44b6Aki Tuomi "\"key13\": \"\\ud801\\udc37\""
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen "}\n";
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen
b7324e421e2132cbbf753e6fdbe675bbaecdf929Timo Sirainenstatic const struct {
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen enum json_type type;
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen const char *value;
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen} json_output[] = {
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen { JSON_TYPE_OBJECT_KEY, "key" },
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen { JSON_TYPE_STRING, "string" },
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen { JSON_TYPE_OBJECT_KEY, "key2" },
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen { JSON_TYPE_NUMBER, "1234" },
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen { JSON_TYPE_OBJECT_KEY, "key3" },
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen { JSON_TYPE_TRUE, "true" },
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen { JSON_TYPE_OBJECT_KEY, "key4" },
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen { JSON_TYPE_FALSE, "false" },
2eccb2637d0153bb7f9ad39a70f254cece74342cTimo Sirainen { JSON_TYPE_OBJECT_KEY, "skip1" },
2eccb2637d0153bb7f9ad39a70f254cece74342cTimo Sirainen { TYPE_SKIP, NULL },
2eccb2637d0153bb7f9ad39a70f254cece74342cTimo Sirainen { JSON_TYPE_OBJECT_KEY, "skip2" },
2eccb2637d0153bb7f9ad39a70f254cece74342cTimo Sirainen { TYPE_SKIP, NULL },
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen { JSON_TYPE_OBJECT_KEY, "key5" },
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen { JSON_TYPE_NULL, NULL },
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen { JSON_TYPE_OBJECT_KEY, "key6" },
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen { JSON_TYPE_OBJECT, NULL },
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen { JSON_TYPE_OBJECT_END, NULL },
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen { JSON_TYPE_OBJECT_KEY, "key7" },
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen { JSON_TYPE_OBJECT, NULL },
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen { JSON_TYPE_OBJECT_KEY, "sub1" },
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen { JSON_TYPE_STRING, "value" },
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen { JSON_TYPE_OBJECT_END, NULL },
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen { JSON_TYPE_OBJECT_KEY, "key8" },
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen { JSON_TYPE_OBJECT, NULL },
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen { JSON_TYPE_OBJECT_KEY, "sub2" },
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen { JSON_TYPE_NUMBER, "-12.456" },
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen { JSON_TYPE_OBJECT_KEY, "sub3" },
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen { JSON_TYPE_NUMBER, "12.456e9" },
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen { JSON_TYPE_OBJECT_KEY, "sub4" },
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen { JSON_TYPE_NUMBER, "0.456e-789" },
4e8e7a93628b4ed60aaaa47c6f72c1433f21e81dTimo Sirainen { JSON_TYPE_OBJECT_END, NULL },
4e8e7a93628b4ed60aaaa47c6f72c1433f21e81dTimo Sirainen { JSON_TYPE_OBJECT_KEY, "key9" },
a01faca549a403b2eda938cea0b1fb76c3ff44b6Aki Tuomi { JSON_TYPE_STRING, "foo\\\"\b\f\n\r\t\001\xe1\x83\xbf" },
7877db7b5daad125b6cb3e015574f33871c9a51bTimo Sirainen { JSON_TYPE_OBJECT_KEY, "key10" },
a01faca549a403b2eda938cea0b1fb76c3ff44b6Aki Tuomi { TYPE_STREAM, "foo\\\"\b\f\n\r\t\001\xe1\x83\xbf" },
86bdb644d147a73df85abce4325254d694217a5fTimo Sirainen { JSON_TYPE_OBJECT_KEY, "key11" },
86bdb644d147a73df85abce4325254d694217a5fTimo Sirainen { JSON_TYPE_ARRAY, NULL },
86bdb644d147a73df85abce4325254d694217a5fTimo Sirainen { JSON_TYPE_ARRAY_END, NULL },
86bdb644d147a73df85abce4325254d694217a5fTimo Sirainen { JSON_TYPE_OBJECT_KEY, "key12" },
86bdb644d147a73df85abce4325254d694217a5fTimo Sirainen { JSON_TYPE_ARRAY, NULL },
86bdb644d147a73df85abce4325254d694217a5fTimo Sirainen { JSON_TYPE_STRING, "foo" },
86bdb644d147a73df85abce4325254d694217a5fTimo Sirainen { JSON_TYPE_NUMBER, "5.24" },
86bdb644d147a73df85abce4325254d694217a5fTimo Sirainen { JSON_TYPE_ARRAY, NULL },
86bdb644d147a73df85abce4325254d694217a5fTimo Sirainen { JSON_TYPE_TRUE, "true" },
86bdb644d147a73df85abce4325254d694217a5fTimo Sirainen { JSON_TYPE_ARRAY_END, NULL },
86bdb644d147a73df85abce4325254d694217a5fTimo Sirainen { JSON_TYPE_OBJECT, NULL },
86bdb644d147a73df85abce4325254d694217a5fTimo Sirainen { JSON_TYPE_OBJECT_KEY, "aobj" },
86bdb644d147a73df85abce4325254d694217a5fTimo Sirainen { JSON_TYPE_ARRAY, NULL },
86bdb644d147a73df85abce4325254d694217a5fTimo Sirainen { JSON_TYPE_ARRAY_END, NULL },
86bdb644d147a73df85abce4325254d694217a5fTimo Sirainen { JSON_TYPE_OBJECT_END, NULL },
a01faca549a403b2eda938cea0b1fb76c3ff44b6Aki Tuomi { JSON_TYPE_ARRAY_END, NULL },
a01faca549a403b2eda938cea0b1fb76c3ff44b6Aki Tuomi { JSON_TYPE_OBJECT_KEY, "key13" },
a01faca549a403b2eda938cea0b1fb76c3ff44b6Aki Tuomi { JSON_TYPE_STRING, "\xf0\x90\x90\xb7" }
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen};
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen
7877db7b5daad125b6cb3e015574f33871c9a51bTimo Sirainenstatic int
7877db7b5daad125b6cb3e015574f33871c9a51bTimo Sirainenstream_read_value(struct istream **input, const char **value_r)
7877db7b5daad125b6cb3e015574f33871c9a51bTimo Sirainen{
7877db7b5daad125b6cb3e015574f33871c9a51bTimo Sirainen const unsigned char *data;
7877db7b5daad125b6cb3e015574f33871c9a51bTimo Sirainen size_t size;
7877db7b5daad125b6cb3e015574f33871c9a51bTimo Sirainen ssize_t ret;
7877db7b5daad125b6cb3e015574f33871c9a51bTimo Sirainen
7877db7b5daad125b6cb3e015574f33871c9a51bTimo Sirainen while ((ret = i_stream_read(*input)) > 0) ;
7877db7b5daad125b6cb3e015574f33871c9a51bTimo Sirainen if (ret == 0)
7877db7b5daad125b6cb3e015574f33871c9a51bTimo Sirainen return 0;
7877db7b5daad125b6cb3e015574f33871c9a51bTimo Sirainen i_assert(ret == -1);
7877db7b5daad125b6cb3e015574f33871c9a51bTimo Sirainen if ((*input)->stream_errno != 0)
7877db7b5daad125b6cb3e015574f33871c9a51bTimo Sirainen return -1;
7877db7b5daad125b6cb3e015574f33871c9a51bTimo Sirainen
7877db7b5daad125b6cb3e015574f33871c9a51bTimo Sirainen data = i_stream_get_data(*input, &size);
7877db7b5daad125b6cb3e015574f33871c9a51bTimo Sirainen *value_r = t_strndup(data, size);
7877db7b5daad125b6cb3e015574f33871c9a51bTimo Sirainen i_stream_unref(input);
7877db7b5daad125b6cb3e015574f33871c9a51bTimo Sirainen return 1;
7877db7b5daad125b6cb3e015574f33871c9a51bTimo Sirainen}
7877db7b5daad125b6cb3e015574f33871c9a51bTimo Sirainen
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainenstatic void test_json_parser_success(bool full_size)
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen{
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen struct json_parser *parser;
7877db7b5daad125b6cb3e015574f33871c9a51bTimo Sirainen struct istream *input, *jsoninput = NULL;
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen enum json_type type;
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen const char *value, *error;
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen unsigned int i, pos, json_input_len = strlen(json_input);
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen int ret = 0;
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen
7877db7b5daad125b6cb3e015574f33871c9a51bTimo Sirainen test_begin(full_size ? "json parser" : "json parser (nonblocking)");
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen input = test_istream_create_data(json_input, json_input_len);
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen test_istream_set_allow_eof(input, FALSE);
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen parser = json_parser_init(input);
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen i = full_size ? json_input_len : 0;
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen for (pos = 0; i <= json_input_len; i++) {
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen test_istream_set_size(input, i);
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen
7877db7b5daad125b6cb3e015574f33871c9a51bTimo Sirainen for (;;) {
791fb70b3255a11a91ce0c2dc3ae1460d4cf8459Timo Sirainen value = NULL;
a18e2525cb076066784967d6c8118a01dd38ac6bTimo Sirainen if (pos < N_ELEMENTS(json_output) &&
a18e2525cb076066784967d6c8118a01dd38ac6bTimo Sirainen json_output[pos].type == (enum json_type)TYPE_SKIP) {
2eccb2637d0153bb7f9ad39a70f254cece74342cTimo Sirainen json_parse_skip_next(parser);
2eccb2637d0153bb7f9ad39a70f254cece74342cTimo Sirainen pos++;
2eccb2637d0153bb7f9ad39a70f254cece74342cTimo Sirainen continue;
a18e2525cb076066784967d6c8118a01dd38ac6bTimo Sirainen } else if (pos == N_ELEMENTS(json_output) ||
a18e2525cb076066784967d6c8118a01dd38ac6bTimo Sirainen json_output[pos].type != (enum json_type)TYPE_STREAM) {
7877db7b5daad125b6cb3e015574f33871c9a51bTimo Sirainen ret = json_parse_next(parser, &type, &value);
2eccb2637d0153bb7f9ad39a70f254cece74342cTimo Sirainen } else {
7877db7b5daad125b6cb3e015574f33871c9a51bTimo Sirainen ret = jsoninput != NULL ? 1 :
7877db7b5daad125b6cb3e015574f33871c9a51bTimo Sirainen json_parse_next_stream(parser, &jsoninput);
202b4674243a4a4826c35ed4d089831985c47256Timo Sirainen if (ret > 0 && jsoninput != NULL)
7877db7b5daad125b6cb3e015574f33871c9a51bTimo Sirainen ret = stream_read_value(&jsoninput, &value);
7877db7b5daad125b6cb3e015574f33871c9a51bTimo Sirainen type = TYPE_STREAM;
7877db7b5daad125b6cb3e015574f33871c9a51bTimo Sirainen }
7877db7b5daad125b6cb3e015574f33871c9a51bTimo Sirainen if (ret <= 0)
7877db7b5daad125b6cb3e015574f33871c9a51bTimo Sirainen break;
7877db7b5daad125b6cb3e015574f33871c9a51bTimo Sirainen
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen i_assert(pos < N_ELEMENTS(json_output));
95f5b08fa73ddd9a9de40a97aa141e9c74e0645eAki Tuomi test_assert_idx(json_output[pos].type == type, pos);
95f5b08fa73ddd9a9de40a97aa141e9c74e0645eAki Tuomi test_assert_idx(null_strcmp(json_output[pos].value, value) == 0, pos);
a01faca549a403b2eda938cea0b1fb76c3ff44b6Aki Tuomi
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen pos++;
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen }
95f5b08fa73ddd9a9de40a97aa141e9c74e0645eAki Tuomi test_assert_idx(ret == 0, pos);
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen }
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen test_assert(pos == N_ELEMENTS(json_output));
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen test_istream_set_allow_eof(input, TRUE);
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen test_assert(json_parse_next(parser, &type, &value) == -1);
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen i_stream_unref(&input);
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen test_assert(json_parser_deinit(&parser, &error) == 0);
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen test_end();
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen}
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen
f6497ac81e6de57870936d538acccb75ce408fc1Timo Sirainenstatic void test_json_parser_skip_array(void)
f6497ac81e6de57870936d538acccb75ce408fc1Timo Sirainen{
f6497ac81e6de57870936d538acccb75ce408fc1Timo Sirainen static const char *test_input =
f6497ac81e6de57870936d538acccb75ce408fc1Timo Sirainen "[ 1, {\"foo\": 1 }, 2, \"bar\", 3, 1.234, 4, [], 5, [[]], 6, true ]";
f6497ac81e6de57870936d538acccb75ce408fc1Timo Sirainen struct json_parser *parser;
f6497ac81e6de57870936d538acccb75ce408fc1Timo Sirainen struct istream *input;
f6497ac81e6de57870936d538acccb75ce408fc1Timo Sirainen enum json_type type;
f6497ac81e6de57870936d538acccb75ce408fc1Timo Sirainen const char *value, *error;
f6497ac81e6de57870936d538acccb75ce408fc1Timo Sirainen int i;
f6497ac81e6de57870936d538acccb75ce408fc1Timo Sirainen
f6497ac81e6de57870936d538acccb75ce408fc1Timo Sirainen test_begin("json parser skip array");
f6497ac81e6de57870936d538acccb75ce408fc1Timo Sirainen
f6497ac81e6de57870936d538acccb75ce408fc1Timo Sirainen input = test_istream_create_data(test_input, strlen(test_input));
f6497ac81e6de57870936d538acccb75ce408fc1Timo Sirainen parser = json_parser_init_flags(input, JSON_PARSER_NO_ROOT_OBJECT);
f6497ac81e6de57870936d538acccb75ce408fc1Timo Sirainen test_assert(json_parse_next(parser, &type, &value) > 0 &&
f6497ac81e6de57870936d538acccb75ce408fc1Timo Sirainen type == JSON_TYPE_ARRAY);
f6497ac81e6de57870936d538acccb75ce408fc1Timo Sirainen for (i = 1; i <= 6; i++) {
f6497ac81e6de57870936d538acccb75ce408fc1Timo Sirainen test_assert(json_parse_next(parser, &type, &value) > 0 &&
f6497ac81e6de57870936d538acccb75ce408fc1Timo Sirainen type == JSON_TYPE_NUMBER && atoi(value) == i);
f6497ac81e6de57870936d538acccb75ce408fc1Timo Sirainen json_parse_skip_next(parser);
f6497ac81e6de57870936d538acccb75ce408fc1Timo Sirainen }
f6497ac81e6de57870936d538acccb75ce408fc1Timo Sirainen test_assert(json_parse_next(parser, &type, &value) > 0 &&
f6497ac81e6de57870936d538acccb75ce408fc1Timo Sirainen type == JSON_TYPE_ARRAY_END);
f6497ac81e6de57870936d538acccb75ce408fc1Timo Sirainen test_assert(json_parser_deinit(&parser, &error) == 0);
f6497ac81e6de57870936d538acccb75ce408fc1Timo Sirainen i_stream_unref(&input);
f6497ac81e6de57870936d538acccb75ce408fc1Timo Sirainen test_end();
f6497ac81e6de57870936d538acccb75ce408fc1Timo Sirainen}
f6497ac81e6de57870936d538acccb75ce408fc1Timo Sirainen
f6ae9ae80a1fcf6c8f45ab759f0074caaa66c9c8Timo Sirainenstatic int
f6ae9ae80a1fcf6c8f45ab759f0074caaa66c9c8Timo Sirainentest_json_parse_input(const char *test_input, enum json_parser_flags flags)
736b1800b0409ba7443d33ecb8d0fb9f8b091660Timo Sirainen{
736b1800b0409ba7443d33ecb8d0fb9f8b091660Timo Sirainen struct json_parser *parser;
736b1800b0409ba7443d33ecb8d0fb9f8b091660Timo Sirainen struct istream *input;
736b1800b0409ba7443d33ecb8d0fb9f8b091660Timo Sirainen enum json_type type;
736b1800b0409ba7443d33ecb8d0fb9f8b091660Timo Sirainen const char *value, *error;
736b1800b0409ba7443d33ecb8d0fb9f8b091660Timo Sirainen int ret = 0;
736b1800b0409ba7443d33ecb8d0fb9f8b091660Timo Sirainen
736b1800b0409ba7443d33ecb8d0fb9f8b091660Timo Sirainen input = test_istream_create_data(test_input, strlen(test_input));
f6ae9ae80a1fcf6c8f45ab759f0074caaa66c9c8Timo Sirainen parser = json_parser_init_flags(input, flags);
736b1800b0409ba7443d33ecb8d0fb9f8b091660Timo Sirainen while (json_parse_next(parser, &type, &value) > 0)
736b1800b0409ba7443d33ecb8d0fb9f8b091660Timo Sirainen ret++;
736b1800b0409ba7443d33ecb8d0fb9f8b091660Timo Sirainen if (json_parser_deinit(&parser, &error) < 0)
736b1800b0409ba7443d33ecb8d0fb9f8b091660Timo Sirainen ret = -1;
736b1800b0409ba7443d33ecb8d0fb9f8b091660Timo Sirainen i_stream_unref(&input);
736b1800b0409ba7443d33ecb8d0fb9f8b091660Timo Sirainen return ret;
736b1800b0409ba7443d33ecb8d0fb9f8b091660Timo Sirainen}
736b1800b0409ba7443d33ecb8d0fb9f8b091660Timo Sirainen
f6ae9ae80a1fcf6c8f45ab759f0074caaa66c9c8Timo Sirainenstatic void test_json_parser_primitive_values(void)
f6ae9ae80a1fcf6c8f45ab759f0074caaa66c9c8Timo Sirainen{
b7324e421e2132cbbf753e6fdbe675bbaecdf929Timo Sirainen static const struct {
a18503d5dc0751a1f9785e48438a219d95c0b9c2Timo Sirainen const char *str;
a18503d5dc0751a1f9785e48438a219d95c0b9c2Timo Sirainen int ret;
a18503d5dc0751a1f9785e48438a219d95c0b9c2Timo Sirainen } test_inputs[] = {
a18503d5dc0751a1f9785e48438a219d95c0b9c2Timo Sirainen { "\"hello\"", 1 },
a18503d5dc0751a1f9785e48438a219d95c0b9c2Timo Sirainen { "null", 1 },
a18503d5dc0751a1f9785e48438a219d95c0b9c2Timo Sirainen { "1234", 1 },
a18503d5dc0751a1f9785e48438a219d95c0b9c2Timo Sirainen { "1234.1234", 1 },
a18503d5dc0751a1f9785e48438a219d95c0b9c2Timo Sirainen { "{}", 2 },
a18503d5dc0751a1f9785e48438a219d95c0b9c2Timo Sirainen { "[]", 2 },
a18503d5dc0751a1f9785e48438a219d95c0b9c2Timo Sirainen { "true", 1 },
a18503d5dc0751a1f9785e48438a219d95c0b9c2Timo Sirainen { "false", 1 }
f6ae9ae80a1fcf6c8f45ab759f0074caaa66c9c8Timo Sirainen };
f6ae9ae80a1fcf6c8f45ab759f0074caaa66c9c8Timo Sirainen unsigned int i;
f6ae9ae80a1fcf6c8f45ab759f0074caaa66c9c8Timo Sirainen
f6ae9ae80a1fcf6c8f45ab759f0074caaa66c9c8Timo Sirainen test_begin("json_parser (primitives)");
f6ae9ae80a1fcf6c8f45ab759f0074caaa66c9c8Timo Sirainen for (i = 0; i < N_ELEMENTS(test_inputs); i++)
a18503d5dc0751a1f9785e48438a219d95c0b9c2Timo Sirainen test_assert_idx(test_json_parse_input(test_inputs[i].str, JSON_PARSER_NO_ROOT_OBJECT) == test_inputs[i].ret, i);
f6ae9ae80a1fcf6c8f45ab759f0074caaa66c9c8Timo Sirainen test_end();
f6ae9ae80a1fcf6c8f45ab759f0074caaa66c9c8Timo Sirainen}
f6ae9ae80a1fcf6c8f45ab759f0074caaa66c9c8Timo Sirainen
736b1800b0409ba7443d33ecb8d0fb9f8b091660Timo Sirainenstatic void test_json_parser_errors(void)
736b1800b0409ba7443d33ecb8d0fb9f8b091660Timo Sirainen{
736b1800b0409ba7443d33ecb8d0fb9f8b091660Timo Sirainen static const char *test_inputs[] = {
736b1800b0409ba7443d33ecb8d0fb9f8b091660Timo Sirainen "{",
736b1800b0409ba7443d33ecb8d0fb9f8b091660Timo Sirainen "{:}",
736b1800b0409ba7443d33ecb8d0fb9f8b091660Timo Sirainen "{\"foo\":}",
736b1800b0409ba7443d33ecb8d0fb9f8b091660Timo Sirainen "{\"foo\" []}",
736b1800b0409ba7443d33ecb8d0fb9f8b091660Timo Sirainen "{\"foo\": [1}",
736b1800b0409ba7443d33ecb8d0fb9f8b091660Timo Sirainen "{\"foo\": [1,]}",
736b1800b0409ba7443d33ecb8d0fb9f8b091660Timo Sirainen "{\"foo\": [1,]}",
736b1800b0409ba7443d33ecb8d0fb9f8b091660Timo Sirainen "{\"foo\": 1,}",
736b1800b0409ba7443d33ecb8d0fb9f8b091660Timo Sirainen "{\"foo\": 1.}}",
a01faca549a403b2eda938cea0b1fb76c3ff44b6Aki Tuomi "{\"foo\": 1},{}",
a01faca549a403b2eda938cea0b1fb76c3ff44b6Aki Tuomi "{\"foo\": \"\\ud808\"}",
a01faca549a403b2eda938cea0b1fb76c3ff44b6Aki Tuomi "{\"foo\": \"\\udfff\"}",
c980536af173efb82839bdd3d5ce2bfddac9fd9bAki Tuomi "{\"foo\": \"\\uyyyy\"}",
736b1800b0409ba7443d33ecb8d0fb9f8b091660Timo Sirainen };
736b1800b0409ba7443d33ecb8d0fb9f8b091660Timo Sirainen unsigned int i;
736b1800b0409ba7443d33ecb8d0fb9f8b091660Timo Sirainen
736b1800b0409ba7443d33ecb8d0fb9f8b091660Timo Sirainen test_begin("json parser error handling");
736b1800b0409ba7443d33ecb8d0fb9f8b091660Timo Sirainen for (i = 0; i < N_ELEMENTS(test_inputs); i++)
f6ae9ae80a1fcf6c8f45ab759f0074caaa66c9c8Timo Sirainen test_assert_idx(test_json_parse_input(test_inputs[i], 0) < 0, i);
736b1800b0409ba7443d33ecb8d0fb9f8b091660Timo Sirainen test_end();
736b1800b0409ba7443d33ecb8d0fb9f8b091660Timo Sirainen}
736b1800b0409ba7443d33ecb8d0fb9f8b091660Timo Sirainen
10972f2a15f5538860fcc1d4adda227d59d2d757Timo Sirainenstatic void test_json_append_escaped(void)
10972f2a15f5538860fcc1d4adda227d59d2d757Timo Sirainen{
10972f2a15f5538860fcc1d4adda227d59d2d757Timo Sirainen string_t *str = t_str_new(32);
10972f2a15f5538860fcc1d4adda227d59d2d757Timo Sirainen
10972f2a15f5538860fcc1d4adda227d59d2d757Timo Sirainen test_begin("json_append_escaped()");
32bd32dcc845cd0c00d5617aea1ffbe45522b413Aki Tuomi json_append_escaped(str, "\b\f\r\n\t\"\\\001\002-\xC3\xA4\xf0\x90\x90\xb7");
32bd32dcc845cd0c00d5617aea1ffbe45522b413Aki Tuomi test_assert(strcmp(str_c(str), "\\b\\f\\r\\n\\t\\\"\\\\\\u0001\\u0002-\\u00e4\\ud801\\udc37") == 0);
10972f2a15f5538860fcc1d4adda227d59d2d757Timo Sirainen test_end();
10972f2a15f5538860fcc1d4adda227d59d2d757Timo Sirainen}
10972f2a15f5538860fcc1d4adda227d59d2d757Timo Sirainen
bb869cc24b24a8df84a43154c628785d6aee784cTimo Sirainenstatic void test_json_append_escaped_data(void)
bb869cc24b24a8df84a43154c628785d6aee784cTimo Sirainen{
bb869cc24b24a8df84a43154c628785d6aee784cTimo Sirainen static const unsigned char test_input[] =
32bd32dcc845cd0c00d5617aea1ffbe45522b413Aki Tuomi "\b\f\r\n\t\"\\\000\001\002-\xC3\xA4\xf0\x90\x90\xb7";
bb869cc24b24a8df84a43154c628785d6aee784cTimo Sirainen string_t *str = t_str_new(32);
bb869cc24b24a8df84a43154c628785d6aee784cTimo Sirainen
bb869cc24b24a8df84a43154c628785d6aee784cTimo Sirainen test_begin("json_append_escaped()");
bb869cc24b24a8df84a43154c628785d6aee784cTimo Sirainen json_append_escaped_data(str, test_input, sizeof(test_input)-1);
32bd32dcc845cd0c00d5617aea1ffbe45522b413Aki Tuomi test_assert(strcmp(str_c(str), "\\b\\f\\r\\n\\t\\\"\\\\\\u0000\\u0001\\u0002-\\u00e4\\ud801\\udc37") == 0);
bb869cc24b24a8df84a43154c628785d6aee784cTimo Sirainen test_end();
bb869cc24b24a8df84a43154c628785d6aee784cTimo Sirainen}
bb869cc24b24a8df84a43154c628785d6aee784cTimo Sirainen
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainenvoid test_json_parser(void)
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen{
4e8e7a93628b4ed60aaaa47c6f72c1433f21e81dTimo Sirainen test_json_parser_success(TRUE);
7877db7b5daad125b6cb3e015574f33871c9a51bTimo Sirainen test_json_parser_success(FALSE);
f6497ac81e6de57870936d538acccb75ce408fc1Timo Sirainen test_json_parser_skip_array();
f6ae9ae80a1fcf6c8f45ab759f0074caaa66c9c8Timo Sirainen test_json_parser_primitive_values();
736b1800b0409ba7443d33ecb8d0fb9f8b091660Timo Sirainen test_json_parser_errors();
10972f2a15f5538860fcc1d4adda227d59d2d757Timo Sirainen test_json_append_escaped();
bb869cc24b24a8df84a43154c628785d6aee784cTimo Sirainen test_json_append_escaped_data();
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen}