1 /* Copyright (c) 2009-2018 Dovecot authors, see the included COPYING file */
2
3 #include "test-lib.h"
4 #include "str.h"
5 #include "strescape.h"
6
7 struct strinput {
8 const char *input;
9 const char *output;
10 };
11
12 static const char tabescaped_input[] = "\0011\001t\001r\001nplip\001n";
13 static const char tabescaped_input_with_nul[] = "\0011\001t\001r\001nplip\001n\0010";
14 static const char tabunescaped_input[] = "\001\t\r\nplip\n";
15
16 static const char *wrong_tabescaped_input = "a\001\001b\001\nc\0011\001t\001r\001nplip\001n";
17 static const char *wrong_tabescaped_output = "a\001b\nc\001\t\r\nplip\n";
18
19 static struct {
20 const char *input;
21 const char *const *output;
22 } strsplit_tests[] = {
23 { /*tabescaped_input3*/NULL, (const char *const []) {
24 tabunescaped_input,
25 tabunescaped_input,
26 tabunescaped_input,
27 "",
28 NULL
29 } },
30 { "", (const char *const []) { NULL } },
31 { "\t", (const char *const []) { "", "", NULL } },
32 { tabescaped_input, (const char *const []) {
33 tabunescaped_input,
34 NULL
35 } },
36 };
37
test_str_escape(void)38 static void test_str_escape(void)
39 {
40 static const struct strinput unesc[] = {
41 { "foo", "foo" },
42 { "\\\\\\\\\\\"\\\"\\\'\\\'", "\\\\\"\"\'\'" },
43 { "\\a\\n\\r\\", "anr" }
44 };
45 static const struct strinput tabesc[] = {
46 { "foo", "foo" },
47 { "\001", "\0011" },
48 { "\t", "\001t" },
49 { "\r", "\001r" },
50 { "\n", "\001n" },
51 { "\001\001\t\t\r\r\n\n", "\0011\0011\001t\001t\001r\001r\001n\001n" }
52 };
53 unsigned char buf[1 << CHAR_BIT];
54 const char *escaped, *tabstr, *unesc_str;
55 string_t *str;
56 unsigned int i;
57
58 test_begin("str_escape");
59 for (i = 1; i < sizeof(buf); i++)
60 buf[i-1] = i;
61 buf[i-1] = '\0';
62
63 escaped = str_escape((char *)buf);
64 test_assert(strlen(escaped) == (1 << CHAR_BIT) - 1 + 3);
65 test_assert(escaped['\"'-1] == '\\'); /* 34 */
66 test_assert(escaped['\"'] == '\"');
67 test_assert(escaped['\''+1-1] == '\\'); /* 39 */
68 test_assert(escaped['\''+1] == '\'');
69 test_assert(escaped['\\'+2-1] == '\\'); /* 92 */
70 test_assert(escaped['\\'+2] == '\\');
71 test_assert(strcmp(str_escape("\\\\\"\"\'\'"),
72 "\\\\\\\\\\\"\\\"\\\'\\\'") == 0);
73 test_end();
74
75 test_begin("str_nescape");
76
77 escaped = str_nescape("\"escape only first but not 'this'", 10);
78 test_assert(strcmp(escaped, "\\\"escape on") == 0);
79
80 escaped = str_nescape("\"hello\"\0\"world\"", 15);
81 test_assert(memcmp(escaped, "\\\"hello\\\"\0\\\"world\\\"", 19) == 0);
82
83 test_end();
84
85 str = t_str_new(256);
86 test_begin("str_unescape");
87 for (i = 0; i < N_ELEMENTS(unesc); i++) {
88 test_assert(strcmp(str_unescape(t_strdup_noconst(unesc[i].input)),
89 unesc[i].output) == 0);
90 str_truncate(str, 0);
91 str_append_unescaped(str, unesc[i].input, strlen(unesc[i].input));
92 test_assert(strcmp(str_c(str), unesc[i].output) == 0);
93 }
94 test_end();
95
96 test_begin("str_unescape_next");
97 escaped = "foo\"bar\\\"b\\\\az\"plop";
98 test_assert(str_unescape_next(&escaped, &unesc_str) == 0);
99 test_assert(strcmp(unesc_str, "foo") == 0);
100 test_assert(str_unescape_next(&escaped, &unesc_str) == 0);
101 test_assert(strcmp(unesc_str, "bar\"b\\az") == 0);
102 test_assert(str_unescape_next(&escaped, &unesc_str) == -1);
103 escaped = "foo\\";
104 test_assert(str_unescape_next(&escaped, &unesc_str) == -1);
105 test_end();
106
107 test_begin("str_tabescape");
108 for (i = 0; i < N_ELEMENTS(tabesc); i++) {
109 test_assert(strcmp(t_str_tabunescape(tabesc[i].output),
110 tabesc[i].input) == 0);
111 test_assert(strcmp(str_tabunescape(t_strdup_noconst(tabesc[i].output)),
112 tabesc[i].input) == 0);
113 test_assert(strcmp(str_tabescape(tabesc[i].input),
114 tabesc[i].output) == 0);
115 str_truncate(str, 0);
116 str_append_tabunescaped(str, tabesc[i].output, strlen(tabesc[i].output));
117 test_assert(strcmp(str_c(str), tabesc[i].input) == 0);
118 }
119 str_truncate(str, 0);
120 tabstr = "\0012\001l\001";
121 str_append_tabunescaped(str, tabstr, strlen(tabstr));
122 test_assert(strcmp(str_c(str), "2l") == 0);
123 test_assert(strcmp(str_c(str), str_tabunescape(t_strdup_noconst(tabstr))) == 0);
124 test_end();
125 }
126
test_tabescape(void)127 static void test_tabescape(void)
128 {
129 string_t *str = t_str_new(128);
130
131 test_begin("string tabescaping");
132 test_assert(strcmp(str_tabescape(tabunescaped_input), tabescaped_input) == 0);
133
134 str_append_tabescaped(str, tabunescaped_input);
135 test_assert(strcmp(str_c(str), tabescaped_input) == 0);
136
137 /* test escaping the trailing NUL as well */
138 str_truncate(str, 0);
139 str_append_tabescaped_n(str, (const unsigned char *)tabunescaped_input,
140 strlen(tabunescaped_input)+1);
141 test_assert_strcmp(str_c(str), tabescaped_input_with_nul);
142
143 /* unescaping */
144 str_truncate(str, 0);
145 str_append_tabunescaped(str, tabescaped_input, strlen(tabescaped_input));
146 test_assert(strcmp(str_c(str), tabunescaped_input) == 0);
147
148 test_assert(strcmp(str_tabunescape(t_strdup_noconst(tabescaped_input)), tabunescaped_input) == 0);
149 test_assert(strcmp(t_str_tabunescape(tabescaped_input), tabunescaped_input) == 0);
150
151 /* unescaping with wrongly written tabescape-input */
152 str_truncate(str, 0);
153 str_append_tabunescaped(str, wrong_tabescaped_input, strlen(wrong_tabescaped_input));
154 test_assert(strcmp(str_c(str), wrong_tabescaped_output) == 0);
155
156 test_assert(strcmp(str_tabunescape(t_strdup_noconst(wrong_tabescaped_input)), wrong_tabescaped_output) == 0);
157 test_assert(strcmp(t_str_tabunescape(wrong_tabescaped_input), wrong_tabescaped_output) == 0);
158
159 test_end();
160 }
161
test_strsplit_tabescaped(void)162 static void test_strsplit_tabescaped(void)
163 {
164 const char *const *args;
165
166 test_begin("*_strsplit_tabescaped()");
167 for (unsigned int i = 0; i < N_ELEMENTS(strsplit_tests); i++) {
168 args = t_strsplit_tabescaped(strsplit_tests[i].input);
169 for (unsigned int j = 0; strsplit_tests[i].output[j] != NULL; j++)
170 test_assert_idx(null_strcmp(strsplit_tests[i].output[j], args[j]) == 0, i);
171 }
172 test_end();
173 }
174
test_strsplit_tabescaped_inplace(void)175 static void test_strsplit_tabescaped_inplace(void)
176 {
177 const char *const *args;
178
179 test_begin("*_strsplit_tabescaped_inplace()");
180 for (unsigned int i = 0; i < N_ELEMENTS(strsplit_tests); i++) {
181 char *input = t_strdup_noconst(strsplit_tests[i].input);
182 args = t_strsplit_tabescaped_inplace(input);
183 for (unsigned int j = 0; strsplit_tests[i].output[j] != NULL; j++)
184 test_assert_idx(null_strcmp(strsplit_tests[i].output[j], args[j]) == 0, i);
185 }
186 test_end();
187 }
188
test_strescape(void)189 void test_strescape(void)
190 {
191 strsplit_tests[0].input = t_strdup_printf("%s\t%s\t%s\t",
192 tabescaped_input, tabescaped_input, tabescaped_input);
193 test_str_escape();
194 test_tabescape();
195 test_strsplit_tabescaped();
196 test_strsplit_tabescaped_inplace();
197 }
198