test-istream-jsonstr.c revision bcb4e51a409d94ae670de96afb8483a4f7855294
bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2016-2018 Dovecot authors, see the included COPYING file */
ddf9529d37056f8817825f6265c27d8070123013Timo Sirainen
ddf9529d37056f8817825f6265c27d8070123013Timo Sirainen#include "test-lib.h"
ddf9529d37056f8817825f6265c27d8070123013Timo Sirainen#include "str.h"
ddf9529d37056f8817825f6265c27d8070123013Timo Sirainen#include "istream-private.h"
ddf9529d37056f8817825f6265c27d8070123013Timo Sirainen#include "istream-jsonstr.h"
ddf9529d37056f8817825f6265c27d8070123013Timo Sirainen
ddf9529d37056f8817825f6265c27d8070123013Timo Sirainenstatic const struct {
ddf9529d37056f8817825f6265c27d8070123013Timo Sirainen const char *input;
ddf9529d37056f8817825f6265c27d8070123013Timo Sirainen const char *output;
ddf9529d37056f8817825f6265c27d8070123013Timo Sirainen int stream_errno;
ddf9529d37056f8817825f6265c27d8070123013Timo Sirainen} tests[] = {
ddf9529d37056f8817825f6265c27d8070123013Timo Sirainen { "foo\\\\\\\"\\b\\f\\n\\r\\t\\u0001\\uffff\"",
ddf9529d37056f8817825f6265c27d8070123013Timo Sirainen "foo\\\"\b\f\n\r\t\001\xEF\xBF\xBF", 0 },
c3393007354b7ab607449fea0c3d7088193ab208Aki Tuomi { "\\ud801\\udc37\"", "\xf0\x90\x90\xb7", 0 }, /* valid codepoint */
ddf9529d37056f8817825f6265c27d8070123013Timo Sirainen { "\"", "", 0 },
ddf9529d37056f8817825f6265c27d8070123013Timo Sirainen { "foo\\?\"", "foo", EINVAL },
ddf9529d37056f8817825f6265c27d8070123013Timo Sirainen { "foo\\?\"", "foo", EINVAL },
1547bafeb11368eb80168fe2899283e8bdcb8528Timo Sirainen { "", "", EPIPE },
1547bafeb11368eb80168fe2899283e8bdcb8528Timo Sirainen { "\\\"", "\"", EPIPE },
1547bafeb11368eb80168fe2899283e8bdcb8528Timo Sirainen { "foo", "foo", EPIPE },
c3393007354b7ab607449fea0c3d7088193ab208Aki Tuomi { "\\ud801", "", EPIPE }, /* high surrogate alone */
c3393007354b7ab607449fea0c3d7088193ab208Aki Tuomi { "\\udced\\udc37\"", "", EINVAL }, /* low surrogate before high */
c3393007354b7ab607449fea0c3d7088193ab208Aki Tuomi { "\\ud8011\\udc37\"", "", EINVAL }, /* has extra 1 in middle */
c3393007354b7ab607449fea0c3d7088193ab208Aki Tuomi { "hello \\udc37\"", "hello ", EINVAL }, /* low surrogate before high with valid prefix*/
c3393007354b7ab607449fea0c3d7088193ab208Aki Tuomi { "hello \\ud801", "hello ", EPIPE }, /* high surrogate alone with valid prefix */
c3393007354b7ab607449fea0c3d7088193ab208Aki Tuomi { "\\uabcg", "", EINVAL }, /* invalid hex value */
ddf9529d37056f8817825f6265c27d8070123013Timo Sirainen};
ddf9529d37056f8817825f6265c27d8070123013Timo Sirainen
ddf9529d37056f8817825f6265c27d8070123013Timo Sirainenstatic void
07ca0c75daa9da0bd6ef987b5c3622d83fe2fe7eTimo Sirainenrun_test_buffer(const char *json_input, const char *output, int stream_errno,
07ca0c75daa9da0bd6ef987b5c3622d83fe2fe7eTimo Sirainen unsigned int skip_count)
ddf9529d37056f8817825f6265c27d8070123013Timo Sirainen{
ddf9529d37056f8817825f6265c27d8070123013Timo Sirainen size_t json_input_len = strlen(json_input);
ddf9529d37056f8817825f6265c27d8070123013Timo Sirainen struct istream *input_data, *input;
ddf9529d37056f8817825f6265c27d8070123013Timo Sirainen const unsigned char *data;
ddf9529d37056f8817825f6265c27d8070123013Timo Sirainen size_t i, size;
ddf9529d37056f8817825f6265c27d8070123013Timo Sirainen ssize_t ret = 0;
ddf9529d37056f8817825f6265c27d8070123013Timo Sirainen
ddf9529d37056f8817825f6265c27d8070123013Timo Sirainen input_data = test_istream_create_data(json_input, json_input_len);
ddf9529d37056f8817825f6265c27d8070123013Timo Sirainen test_istream_set_allow_eof(input_data, FALSE);
ddf9529d37056f8817825f6265c27d8070123013Timo Sirainen input = i_stream_create_jsonstr(input_data);
ddf9529d37056f8817825f6265c27d8070123013Timo Sirainen
07ca0c75daa9da0bd6ef987b5c3622d83fe2fe7eTimo Sirainen for (i = 1; i < json_input_len;) {
ddf9529d37056f8817825f6265c27d8070123013Timo Sirainen test_istream_set_size(input_data, i);
ddf9529d37056f8817825f6265c27d8070123013Timo Sirainen while ((ret = i_stream_read(input)) > 0) ;
ddf9529d37056f8817825f6265c27d8070123013Timo Sirainen if (ret == -1 && stream_errno != 0)
ddf9529d37056f8817825f6265c27d8070123013Timo Sirainen break;
ddf9529d37056f8817825f6265c27d8070123013Timo Sirainen test_assert_idx(ret == 0, i);
07ca0c75daa9da0bd6ef987b5c3622d83fe2fe7eTimo Sirainen if (i + skip_count < json_input_len)
07ca0c75daa9da0bd6ef987b5c3622d83fe2fe7eTimo Sirainen i += skip_count;
07ca0c75daa9da0bd6ef987b5c3622d83fe2fe7eTimo Sirainen else
07ca0c75daa9da0bd6ef987b5c3622d83fe2fe7eTimo Sirainen i++;
ddf9529d37056f8817825f6265c27d8070123013Timo Sirainen }
ddf9529d37056f8817825f6265c27d8070123013Timo Sirainen test_istream_set_allow_eof(input_data, TRUE);
ddf9529d37056f8817825f6265c27d8070123013Timo Sirainen test_istream_set_size(input_data, json_input_len);
ddf9529d37056f8817825f6265c27d8070123013Timo Sirainen ret = i_stream_read(input);
ddf9529d37056f8817825f6265c27d8070123013Timo Sirainen while (ret > 0 && stream_errno != 0)
ddf9529d37056f8817825f6265c27d8070123013Timo Sirainen ret = i_stream_read(input);
ddf9529d37056f8817825f6265c27d8070123013Timo Sirainen test_assert(ret == -1);
ddf9529d37056f8817825f6265c27d8070123013Timo Sirainen test_assert(input->stream_errno == stream_errno);
ddf9529d37056f8817825f6265c27d8070123013Timo Sirainen
07ca0c75daa9da0bd6ef987b5c3622d83fe2fe7eTimo Sirainen if (stream_errno == 0) {
07ca0c75daa9da0bd6ef987b5c3622d83fe2fe7eTimo Sirainen data = i_stream_get_data(input, &size);
07ca0c75daa9da0bd6ef987b5c3622d83fe2fe7eTimo Sirainen test_assert(size == strlen(output));
07ca0c75daa9da0bd6ef987b5c3622d83fe2fe7eTimo Sirainen if (size > 0)
07ca0c75daa9da0bd6ef987b5c3622d83fe2fe7eTimo Sirainen test_assert(memcmp(data, output, size) == 0);
07ca0c75daa9da0bd6ef987b5c3622d83fe2fe7eTimo Sirainen }
ddf9529d37056f8817825f6265c27d8070123013Timo Sirainen i_stream_unref(&input);
ddf9529d37056f8817825f6265c27d8070123013Timo Sirainen i_stream_unref(&input_data);
ddf9529d37056f8817825f6265c27d8070123013Timo Sirainen}
ddf9529d37056f8817825f6265c27d8070123013Timo Sirainen
07ca0c75daa9da0bd6ef987b5c3622d83fe2fe7eTimo Sirainenstatic void
07ca0c75daa9da0bd6ef987b5c3622d83fe2fe7eTimo Sirainenrun_test(const char *json_input, const char *output, int stream_errno)
07ca0c75daa9da0bd6ef987b5c3622d83fe2fe7eTimo Sirainen{
07ca0c75daa9da0bd6ef987b5c3622d83fe2fe7eTimo Sirainen for (unsigned int i = 1; i <= 5; i++)
07ca0c75daa9da0bd6ef987b5c3622d83fe2fe7eTimo Sirainen run_test_buffer(json_input, output, stream_errno, i);
07ca0c75daa9da0bd6ef987b5c3622d83fe2fe7eTimo Sirainen}
07ca0c75daa9da0bd6ef987b5c3622d83fe2fe7eTimo Sirainen
ddf9529d37056f8817825f6265c27d8070123013Timo Sirainenstatic void test_istream_jsonstr_autoretry(void)
ddf9529d37056f8817825f6265c27d8070123013Timo Sirainen{
ddf9529d37056f8817825f6265c27d8070123013Timo Sirainen const char *json_input = "\\u0001\"";
ddf9529d37056f8817825f6265c27d8070123013Timo Sirainen const size_t json_input_len = strlen(json_input);
ddf9529d37056f8817825f6265c27d8070123013Timo Sirainen struct istream *input_data, *input;
ddf9529d37056f8817825f6265c27d8070123013Timo Sirainen
ddf9529d37056f8817825f6265c27d8070123013Timo Sirainen test_begin("istream-jsonstr autoretry");
ddf9529d37056f8817825f6265c27d8070123013Timo Sirainen input_data = test_istream_create_data(json_input, json_input_len);
ddf9529d37056f8817825f6265c27d8070123013Timo Sirainen input = i_stream_create_jsonstr(input_data);
ddf9529d37056f8817825f6265c27d8070123013Timo Sirainen
ddf9529d37056f8817825f6265c27d8070123013Timo Sirainen test_istream_set_size(input_data, 2);
ddf9529d37056f8817825f6265c27d8070123013Timo Sirainen test_assert(i_stream_read(input_data) == 2);
ddf9529d37056f8817825f6265c27d8070123013Timo Sirainen test_istream_set_size(input_data, json_input_len);
ddf9529d37056f8817825f6265c27d8070123013Timo Sirainen test_assert(i_stream_read(input) == 1);
ddf9529d37056f8817825f6265c27d8070123013Timo Sirainen test_assert(i_stream_read(input) == -1);
ddf9529d37056f8817825f6265c27d8070123013Timo Sirainen
ddf9529d37056f8817825f6265c27d8070123013Timo Sirainen i_stream_unref(&input);
ddf9529d37056f8817825f6265c27d8070123013Timo Sirainen i_stream_unref(&input_data);
ddf9529d37056f8817825f6265c27d8070123013Timo Sirainen test_end();
ddf9529d37056f8817825f6265c27d8070123013Timo Sirainen}
ddf9529d37056f8817825f6265c27d8070123013Timo Sirainen
c3393007354b7ab607449fea0c3d7088193ab208Aki Tuomistatic void test_istream_jsonstr_partial(void)
c3393007354b7ab607449fea0c3d7088193ab208Aki Tuomi{
c3393007354b7ab607449fea0c3d7088193ab208Aki Tuomi size_t len = 0;
c3393007354b7ab607449fea0c3d7088193ab208Aki Tuomi const char *json_input = "hello\\u0060x\"";
c3393007354b7ab607449fea0c3d7088193ab208Aki Tuomi const char *output = "hello`x";
c3393007354b7ab607449fea0c3d7088193ab208Aki Tuomi const size_t json_input_len = strlen(json_input);
c3393007354b7ab607449fea0c3d7088193ab208Aki Tuomi struct istream *input_data, *input;
c3393007354b7ab607449fea0c3d7088193ab208Aki Tuomi
c3393007354b7ab607449fea0c3d7088193ab208Aki Tuomi test_begin("istream-jsonstr partial");
c3393007354b7ab607449fea0c3d7088193ab208Aki Tuomi
c3393007354b7ab607449fea0c3d7088193ab208Aki Tuomi input_data = test_istream_create_data(json_input, json_input_len);
c3393007354b7ab607449fea0c3d7088193ab208Aki Tuomi input = i_stream_create_jsonstr(input_data);
c3393007354b7ab607449fea0c3d7088193ab208Aki Tuomi test_istream_set_size(input_data, 9);
c3393007354b7ab607449fea0c3d7088193ab208Aki Tuomi test_assert(i_stream_read(input) == 5);
c3393007354b7ab607449fea0c3d7088193ab208Aki Tuomi test_istream_set_size(input_data, json_input_len);
c3393007354b7ab607449fea0c3d7088193ab208Aki Tuomi test_assert(i_stream_read(input) == 2);
c3393007354b7ab607449fea0c3d7088193ab208Aki Tuomi test_assert(i_stream_read(input) == -1);
c3393007354b7ab607449fea0c3d7088193ab208Aki Tuomi
c3393007354b7ab607449fea0c3d7088193ab208Aki Tuomi test_assert(memcmp(i_stream_get_data(input, &len), output, I_MIN(len, strlen(output))) == 0 &&
c3393007354b7ab607449fea0c3d7088193ab208Aki Tuomi len == strlen(output));
c3393007354b7ab607449fea0c3d7088193ab208Aki Tuomi
c3393007354b7ab607449fea0c3d7088193ab208Aki Tuomi i_stream_unref(&input);
c3393007354b7ab607449fea0c3d7088193ab208Aki Tuomi i_stream_unref(&input_data);
c3393007354b7ab607449fea0c3d7088193ab208Aki Tuomi
c3393007354b7ab607449fea0c3d7088193ab208Aki Tuomi test_end();
c3393007354b7ab607449fea0c3d7088193ab208Aki Tuomi}
c3393007354b7ab607449fea0c3d7088193ab208Aki Tuomi
ddf9529d37056f8817825f6265c27d8070123013Timo Sirainenvoid test_istream_jsonstr(void)
ddf9529d37056f8817825f6265c27d8070123013Timo Sirainen{
ddf9529d37056f8817825f6265c27d8070123013Timo Sirainen unsigned int i;
ddf9529d37056f8817825f6265c27d8070123013Timo Sirainen
ddf9529d37056f8817825f6265c27d8070123013Timo Sirainen for (i = 0; i < N_ELEMENTS(tests); i++) {
ddf9529d37056f8817825f6265c27d8070123013Timo Sirainen test_begin(t_strdup_printf("istream-jsonstr %u", i+1));
ddf9529d37056f8817825f6265c27d8070123013Timo Sirainen run_test(tests[i].input, tests[i].output, tests[i].stream_errno);
ddf9529d37056f8817825f6265c27d8070123013Timo Sirainen test_end();
ddf9529d37056f8817825f6265c27d8070123013Timo Sirainen }
ddf9529d37056f8817825f6265c27d8070123013Timo Sirainen test_istream_jsonstr_autoretry();
c3393007354b7ab607449fea0c3d7088193ab208Aki Tuomi test_istream_jsonstr_partial();
ddf9529d37056f8817825f6265c27d8070123013Timo Sirainen}