1 /* Copyright (c) 2016-2018 Dovecot authors, see the included COPYING file */
2
3 #include "test-lib.h"
4 #include "str.h"
5 #include "istream-private.h"
6 #include "istream-jsonstr.h"
7
8 static const struct {
9 const char *input;
10 const char *output;
11 int stream_errno;
12 } tests[] = {
13 { "foo\\\\\\\"\\b\\f\\n\\r\\t\\u0001\\uffff\"",
14 "foo\\\"\b\f\n\r\t\001\xEF\xBF\xBF", 0 },
15 { "\\ud801\\udc37\"", "\xf0\x90\x90\xb7", 0 }, /* valid codepoint */
16 { "\"", "", 0 },
17 { "foo\\?\"", "foo", EINVAL },
18 { "foo\\?\"", "foo", EINVAL },
19 { "", "", EPIPE },
20 { "\\\"", "\"", EPIPE },
21 { "foo", "foo", EPIPE },
22 { "\\ud801", "", EPIPE }, /* high surrogate alone */
23 { "\\udced\\udc37\"", "", EINVAL }, /* low surrogate before high */
24 { "\\ud8011\\udc37\"", "", EINVAL }, /* has extra 1 in middle */
25 { "hello \\udc37\"", "hello ", EINVAL }, /* low surrogate before high with valid prefix*/
26 { "hello \\ud801", "hello ", EPIPE }, /* high surrogate alone with valid prefix */
27 { "\\uabcg", "", EINVAL }, /* invalid hex value */
28 };
29
30 static void
run_test_buffer(const char * json_input,const char * output,int stream_errno,unsigned int skip_count)31 run_test_buffer(const char *json_input, const char *output, int stream_errno,
32 unsigned int skip_count)
33 {
34 size_t json_input_len = strlen(json_input);
35 struct istream *input_data, *input;
36 const unsigned char *data;
37 size_t i, size;
38 ssize_t ret = 0;
39
40 input_data = test_istream_create_data(json_input, json_input_len);
41 test_istream_set_allow_eof(input_data, FALSE);
42 input = i_stream_create_jsonstr(input_data);
43
44 for (i = 1; i < json_input_len;) {
45 test_istream_set_size(input_data, i);
46 while ((ret = i_stream_read(input)) > 0) ;
47 if (ret == -1 && stream_errno != 0)
48 break;
49 test_assert_idx(ret == 0, i);
50 if (i + skip_count < json_input_len)
51 i += skip_count;
52 else
53 i++;
54 }
55 test_istream_set_allow_eof(input_data, TRUE);
56 test_istream_set_size(input_data, json_input_len);
57 ret = i_stream_read(input);
58 while (ret > 0 && stream_errno != 0)
59 ret = i_stream_read(input);
60 test_assert(ret == -1);
61 test_assert(input->stream_errno == stream_errno);
62
63 if (stream_errno == 0) {
64 data = i_stream_get_data(input, &size);
65 test_assert(size == strlen(output));
66 if (size > 0)
67 test_assert(memcmp(data, output, size) == 0);
68 }
69 i_stream_unref(&input);
70 i_stream_unref(&input_data);
71 }
72
73 static void
run_test(const char * json_input,const char * output,int stream_errno)74 run_test(const char *json_input, const char *output, int stream_errno)
75 {
76 for (unsigned int i = 1; i <= 5; i++)
77 run_test_buffer(json_input, output, stream_errno, i);
78 }
79
test_istream_jsonstr_autoretry(void)80 static void test_istream_jsonstr_autoretry(void)
81 {
82 const char *json_input = "\\u0001\"";
83 const size_t json_input_len = strlen(json_input);
84 struct istream *input_data, *input;
85
86 test_begin("istream-jsonstr autoretry");
87 input_data = test_istream_create_data(json_input, json_input_len);
88 input = i_stream_create_jsonstr(input_data);
89
90 test_istream_set_size(input_data, 2);
91 test_assert(i_stream_read(input_data) == 2);
92 test_istream_set_size(input_data, json_input_len);
93 test_assert(i_stream_read(input) == 1);
94 test_assert(i_stream_read(input) == -1);
95
96 i_stream_unref(&input);
97 i_stream_unref(&input_data);
98 test_end();
99 }
100
test_istream_jsonstr_partial(void)101 static void test_istream_jsonstr_partial(void)
102 {
103 size_t len = 0;
104 const char *json_input = "hello\\u0060x\"";
105 const char *output = "hello`x";
106 const size_t json_input_len = strlen(json_input);
107 struct istream *input_data, *input;
108
109 test_begin("istream-jsonstr partial");
110
111 input_data = test_istream_create_data(json_input, json_input_len);
112 input = i_stream_create_jsonstr(input_data);
113 test_istream_set_size(input_data, 9);
114 test_assert(i_stream_read(input) == 5);
115 test_istream_set_size(input_data, json_input_len);
116 test_assert(i_stream_read(input) == 2);
117 test_assert(i_stream_read(input) == -1);
118
119 test_assert(memcmp(i_stream_get_data(input, &len), output, I_MIN(len, strlen(output))) == 0 &&
120 len == strlen(output));
121
122 i_stream_unref(&input);
123 i_stream_unref(&input_data);
124
125 test_end();
126 }
127
test_istream_jsonstr(void)128 void test_istream_jsonstr(void)
129 {
130 unsigned int i;
131
132 for (i = 0; i < N_ELEMENTS(tests); i++) {
133 test_begin(t_strdup_printf("istream-jsonstr %u", i+1));
134 run_test(tests[i].input, tests[i].output, tests[i].stream_errno);
135 test_end();
136 }
137 test_istream_jsonstr_autoretry();
138 test_istream_jsonstr_partial();
139 }
140