lex_test.c revision 1.2 1 /* $NetBSD: lex_test.c,v 1.2 2024/02/21 22:52:50 christos Exp $ */
2
3 /*
4 * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
5 *
6 * SPDX-License-Identifier: MPL-2.0
7 *
8 * This Source Code Form is subject to the terms of the Mozilla Public
9 * License, v. 2.0. If a copy of the MPL was not distributed with this
10 * file, you can obtain one at https://mozilla.org/MPL/2.0/.
11 *
12 * See the COPYRIGHT file distributed with this work for additional
13 * information regarding copyright ownership.
14 */
15
16 #include <inttypes.h>
17 #include <sched.h> /* IWYU pragma: keep */
18 #include <setjmp.h>
19 #include <stdarg.h>
20 #include <stddef.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <unistd.h>
24
25 #define UNIT_TESTING
26 #include <cmocka.h>
27
28 #include <isc/buffer.h>
29 #include <isc/lex.h>
30 #include <isc/mem.h>
31 #include <isc/util.h>
32
33 #include <tests/isc.h>
34
35 #define AS_STR(x) (x).value.as_textregion.base
36
37 /* check handling of 0xff */
38 ISC_RUN_TEST_IMPL(lex_0xff) {
39 isc_result_t result;
40 isc_lex_t *lex = NULL;
41 isc_buffer_t death_buf;
42 isc_token_t token;
43
44 unsigned char death[] = { EOF, 'A' };
45
46 UNUSED(state);
47
48 result = isc_lex_create(mctx, 1024, &lex);
49 assert_int_equal(result, ISC_R_SUCCESS);
50
51 isc_buffer_init(&death_buf, &death[0], sizeof(death));
52 isc_buffer_add(&death_buf, sizeof(death));
53
54 result = isc_lex_openbuffer(lex, &death_buf);
55 assert_int_equal(result, ISC_R_SUCCESS);
56
57 result = isc_lex_gettoken(lex, 0, &token);
58 assert_int_equal(result, ISC_R_SUCCESS);
59
60 isc_lex_destroy(&lex);
61 }
62
63 /* check setting of source line */
64 ISC_RUN_TEST_IMPL(lex_setline) {
65 isc_result_t result;
66 isc_lex_t *lex = NULL;
67 unsigned char text[] = "text\nto\nbe\nprocessed\nby\nlexer";
68 isc_buffer_t buf;
69 isc_token_t token;
70 unsigned long line;
71 int i;
72
73 UNUSED(state);
74
75 result = isc_lex_create(mctx, 1024, &lex);
76 assert_int_equal(result, ISC_R_SUCCESS);
77
78 isc_buffer_init(&buf, &text[0], sizeof(text));
79 isc_buffer_add(&buf, sizeof(text));
80
81 result = isc_lex_openbuffer(lex, &buf);
82 assert_int_equal(result, ISC_R_SUCCESS);
83
84 result = isc_lex_setsourceline(lex, 100);
85 assert_int_equal(result, ISC_R_SUCCESS);
86
87 for (i = 0; i < 6; i++) {
88 result = isc_lex_gettoken(lex, 0, &token);
89 assert_int_equal(result, ISC_R_SUCCESS);
90
91 line = isc_lex_getsourceline(lex);
92 assert_int_equal(line, 100U + i);
93 }
94
95 result = isc_lex_gettoken(lex, 0, &token);
96 assert_int_equal(result, ISC_R_EOF);
97
98 line = isc_lex_getsourceline(lex);
99 assert_int_equal(line, 105U);
100
101 isc_lex_destroy(&lex);
102 }
103
104 static struct {
105 const char *text;
106 const char *string_value;
107 isc_result_t string_result;
108 isc_tokentype_t string_type;
109 const char *qstring_value;
110 isc_result_t qstring_result;
111 isc_tokentype_t qstring_type;
112 const char *qvpair_value;
113 isc_result_t qvpair_result;
114 isc_tokentype_t qvpair_type;
115 } parse_tests[] = {
116 { "", "", ISC_R_SUCCESS, isc_tokentype_eof, "", ISC_R_SUCCESS,
117 isc_tokentype_eof, "", ISC_R_SUCCESS, isc_tokentype_eof },
118 { "1234", "1234", ISC_R_SUCCESS, isc_tokentype_string, "1234",
119 ISC_R_SUCCESS, isc_tokentype_string, "1234", ISC_R_SUCCESS,
120 isc_tokentype_string },
121 { "1234=", "1234=", ISC_R_SUCCESS, isc_tokentype_string,
122 "1234=", ISC_R_SUCCESS, isc_tokentype_string, "1234=", ISC_R_SUCCESS,
123 isc_tokentype_vpair },
124 { "1234=foo", "1234=foo", ISC_R_SUCCESS, isc_tokentype_string,
125 "1234=foo", ISC_R_SUCCESS, isc_tokentype_string, "1234=foo",
126 ISC_R_SUCCESS, isc_tokentype_vpair },
127 { "1234=\"foo", "1234=\"foo", ISC_R_SUCCESS, isc_tokentype_string,
128 "1234=\"foo", ISC_R_SUCCESS, isc_tokentype_string, NULL,
129 ISC_R_UNEXPECTEDEND, 0 },
130 { "1234=\"foo\"", "1234=\"foo\"", ISC_R_SUCCESS, isc_tokentype_string,
131 "1234=\"foo\"", ISC_R_SUCCESS, isc_tokentype_string, "1234=foo",
132 ISC_R_SUCCESS, isc_tokentype_qvpair },
133 { "key", "key", ISC_R_SUCCESS, isc_tokentype_string, "key",
134 ISC_R_SUCCESS, isc_tokentype_string, "key", ISC_R_SUCCESS,
135 isc_tokentype_string },
136 { "\"key=", "\"key=", ISC_R_SUCCESS, isc_tokentype_string, NULL,
137 ISC_R_UNEXPECTEDEND, 0, "\"key=", ISC_R_SUCCESS,
138 isc_tokentype_vpair },
139 { "\"key=\"", "\"key=\"", ISC_R_SUCCESS, isc_tokentype_string, "key=",
140 ISC_R_SUCCESS, isc_tokentype_qstring, NULL, ISC_R_UNEXPECTEDEND, 0 },
141 { "key=\"\"", "key=\"\"", ISC_R_SUCCESS, isc_tokentype_string,
142 "key=\"\"", ISC_R_SUCCESS, isc_tokentype_string,
143 "key=", ISC_R_SUCCESS, isc_tokentype_qvpair },
144 { "key=\"a b\"", "key=\"a", ISC_R_SUCCESS, isc_tokentype_string,
145 "key=\"a", ISC_R_SUCCESS, isc_tokentype_string, "key=a b",
146 ISC_R_SUCCESS, isc_tokentype_qvpair },
147 { "key=\"a\tb\"", "key=\"a", ISC_R_SUCCESS, isc_tokentype_string,
148 "key=\"a", ISC_R_SUCCESS, isc_tokentype_string, "key=a\tb",
149 ISC_R_SUCCESS, isc_tokentype_qvpair },
150 /* double quote not immediately after '=' is not special. */
151 { "key=c\"a b\"", "key=c\"a", ISC_R_SUCCESS, isc_tokentype_string,
152 "key=c\"a", ISC_R_SUCCESS, isc_tokentype_string, "key=c\"a",
153 ISC_R_SUCCESS, isc_tokentype_vpair },
154 /* remove special meaning for '=' by escaping */
155 { "key\\=", "key\\=", ISC_R_SUCCESS, isc_tokentype_string,
156 "key\\=", ISC_R_SUCCESS, isc_tokentype_string,
157 "key\\=", ISC_R_SUCCESS, isc_tokentype_string },
158 { "key\\=\"a\"", "key\\=\"a\"", ISC_R_SUCCESS, isc_tokentype_string,
159 "key\\=\"a\"", ISC_R_SUCCESS, isc_tokentype_string, "key\\=\"a\"",
160 ISC_R_SUCCESS, isc_tokentype_string },
161 { "key\\=\"a \"", "key\\=\"a", ISC_R_SUCCESS, isc_tokentype_string,
162 "key\\=\"a", ISC_R_SUCCESS, isc_tokentype_string, "key\\=\"a",
163 ISC_R_SUCCESS, isc_tokentype_string },
164 /* vpair with a key of 'key\=' (would need to be deescaped) */
165 { "key\\==", "key\\==", ISC_R_SUCCESS, isc_tokentype_string,
166 "key\\==", ISC_R_SUCCESS, isc_tokentype_string,
167 "key\\==", ISC_R_SUCCESS, isc_tokentype_vpair },
168 { "key\\==\"\"", "key\\==\"\"", ISC_R_SUCCESS, isc_tokentype_string,
169 "key\\==\"\"", ISC_R_SUCCESS, isc_tokentype_string,
170 "key\\==", ISC_R_SUCCESS, isc_tokentype_qvpair },
171 { "key=\\\\\\\\", "key=\\\\\\\\", ISC_R_SUCCESS, isc_tokentype_string,
172 "key=\\\\\\\\", ISC_R_SUCCESS, isc_tokentype_string, "key=\\\\\\\\",
173 ISC_R_SUCCESS, isc_tokentype_vpair },
174 { "key=\\\\\\\"", "key=\\\\\\\"", ISC_R_SUCCESS, isc_tokentype_string,
175 "key=\\\\\\\"", ISC_R_SUCCESS, isc_tokentype_string, "key=\\\\\\\"",
176 ISC_R_SUCCESS, isc_tokentype_vpair },
177 /* incomplete escape sequence */
178 { "key=\\\"\\", NULL, ISC_R_UNEXPECTEDEND, isc_tokentype_string, NULL,
179 ISC_R_UNEXPECTEDEND, 0, NULL, ISC_R_UNEXPECTEDEND, 0 },
180 /* incomplete escape sequence */
181 { "key=\\", NULL, ISC_R_UNEXPECTEDEND, isc_tokentype_string, NULL,
182 ISC_R_UNEXPECTEDEND, 0, NULL, ISC_R_UNEXPECTEDEND, 0 },
183 };
184
185 /*%
186 * string
187 */
188 ISC_RUN_TEST_IMPL(lex_string) {
189 isc_buffer_t buf;
190 isc_lex_t *lex = NULL;
191 isc_result_t result;
192 isc_token_t token;
193 size_t i;
194
195 UNUSED(state);
196
197 for (i = 0; i < ARRAY_SIZE(parse_tests); i++) {
198 result = isc_lex_create(mctx, 1024, &lex);
199 assert_int_equal(result, ISC_R_SUCCESS);
200
201 isc_buffer_constinit(&buf, parse_tests[i].text,
202 strlen(parse_tests[i].text));
203 isc_buffer_add(&buf, strlen(parse_tests[i].text));
204
205 result = isc_lex_openbuffer(lex, &buf);
206 assert_int_equal(result, ISC_R_SUCCESS);
207
208 result = isc_lex_setsourceline(lex, 100);
209 assert_int_equal(result, ISC_R_SUCCESS);
210
211 memset(&token, 0, sizeof(token));
212 result = isc_lex_getmastertoken(lex, &token,
213 isc_tokentype_string, true);
214
215 assert_int_equal(result, parse_tests[i].string_result);
216 if (result == ISC_R_SUCCESS) {
217 switch (token.type) {
218 case isc_tokentype_string:
219 case isc_tokentype_qstring:
220 case isc_tokentype_vpair:
221 case isc_tokentype_qvpair:
222 assert_int_equal(token.type,
223 parse_tests[i].string_type);
224 assert_string_equal(
225 AS_STR(token),
226 parse_tests[i].string_value);
227 break;
228 default:
229 assert_int_equal(token.type,
230 parse_tests[i].string_type);
231 break;
232 }
233 }
234
235 isc_lex_destroy(&lex);
236 }
237 }
238
239 /*%
240 * qstring
241 */
242 ISC_RUN_TEST_IMPL(lex_qstring) {
243 isc_buffer_t buf;
244 isc_lex_t *lex = NULL;
245 isc_result_t result;
246 isc_token_t token;
247 size_t i;
248
249 UNUSED(state);
250
251 for (i = 0; i < ARRAY_SIZE(parse_tests); i++) {
252 result = isc_lex_create(mctx, 1024, &lex);
253 assert_int_equal(result, ISC_R_SUCCESS);
254
255 isc_buffer_constinit(&buf, parse_tests[i].text,
256 strlen(parse_tests[i].text));
257 isc_buffer_add(&buf, strlen(parse_tests[i].text));
258
259 result = isc_lex_openbuffer(lex, &buf);
260 assert_int_equal(result, ISC_R_SUCCESS);
261
262 result = isc_lex_setsourceline(lex, 100);
263 assert_int_equal(result, ISC_R_SUCCESS);
264
265 memset(&token, 0, sizeof(token));
266 result = isc_lex_getmastertoken(lex, &token,
267 isc_tokentype_qstring, true);
268
269 assert_int_equal(result, parse_tests[i].qstring_result);
270 if (result == ISC_R_SUCCESS) {
271 switch (token.type) {
272 case isc_tokentype_string:
273 case isc_tokentype_qstring:
274 case isc_tokentype_vpair:
275 case isc_tokentype_qvpair:
276 assert_int_equal(token.type,
277 parse_tests[i].qstring_type);
278 assert_string_equal(
279 AS_STR(token),
280 parse_tests[i].qstring_value);
281 break;
282 default:
283 assert_int_equal(token.type,
284 parse_tests[i].qstring_type);
285 break;
286 }
287 }
288
289 isc_lex_destroy(&lex);
290 }
291 }
292
293 /*%
294 * keypair is <string>=<qstring>. This has implications double quotes
295 * in key names.
296 */
297 ISC_RUN_TEST_IMPL(lex_keypair) {
298 isc_buffer_t buf;
299 isc_lex_t *lex = NULL;
300 isc_result_t result;
301 isc_token_t token;
302 size_t i;
303
304 UNUSED(state);
305
306 for (i = 0; i < ARRAY_SIZE(parse_tests); i++) {
307 result = isc_lex_create(mctx, 1024, &lex);
308 assert_int_equal(result, ISC_R_SUCCESS);
309
310 isc_buffer_constinit(&buf, parse_tests[i].text,
311 strlen(parse_tests[i].text));
312 isc_buffer_add(&buf, strlen(parse_tests[i].text));
313
314 result = isc_lex_openbuffer(lex, &buf);
315 assert_int_equal(result, ISC_R_SUCCESS);
316
317 result = isc_lex_setsourceline(lex, 100);
318 assert_int_equal(result, ISC_R_SUCCESS);
319
320 memset(&token, 0, sizeof(token));
321 result = isc_lex_getmastertoken(lex, &token,
322 isc_tokentype_qvpair, true);
323
324 assert_int_equal(result, parse_tests[i].qvpair_result);
325 if (result == ISC_R_SUCCESS) {
326 switch (token.type) {
327 case isc_tokentype_string:
328 case isc_tokentype_qstring:
329 case isc_tokentype_vpair:
330 case isc_tokentype_qvpair:
331 assert_int_equal(token.type,
332 parse_tests[i].qvpair_type);
333 assert_string_equal(
334 AS_STR(token),
335 parse_tests[i].qvpair_value);
336 break;
337 default:
338 assert_int_equal(token.type,
339 parse_tests[i].qvpair_type);
340 break;
341 }
342 }
343
344 isc_lex_destroy(&lex);
345 }
346 }
347
348 ISC_TEST_LIST_START
349 ISC_TEST_ENTRY(lex_0xff)
350 ISC_TEST_ENTRY(lex_keypair)
351 ISC_TEST_ENTRY(lex_setline)
352 ISC_TEST_ENTRY(lex_string)
353 ISC_TEST_ENTRY(lex_qstring)
354
355 ISC_TEST_LIST_END
356
357 ISC_TEST_MAIN
358