lex_test.c revision 1.1.1.2 1 /* $NetBSD: lex_test.c,v 1.1.1.2 2025/01/26 16:12:36 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 isc_lex_create(mctx, 1024, &lex);
49
50 isc_buffer_init(&death_buf, &death[0], sizeof(death));
51 isc_buffer_add(&death_buf, sizeof(death));
52
53 result = isc_lex_openbuffer(lex, &death_buf);
54 assert_int_equal(result, ISC_R_SUCCESS);
55
56 result = isc_lex_gettoken(lex, 0, &token);
57 assert_int_equal(result, ISC_R_SUCCESS);
58
59 isc_lex_destroy(&lex);
60 }
61
62 /* check setting of source line */
63 ISC_RUN_TEST_IMPL(lex_setline) {
64 isc_result_t result;
65 isc_lex_t *lex = NULL;
66 unsigned char text[] = "text\nto\nbe\nprocessed\nby\nlexer";
67 isc_buffer_t buf;
68 isc_token_t token;
69 unsigned long line;
70 int i;
71
72 UNUSED(state);
73
74 isc_lex_create(mctx, 1024, &lex);
75
76 isc_buffer_init(&buf, &text[0], sizeof(text));
77 isc_buffer_add(&buf, sizeof(text));
78
79 result = isc_lex_openbuffer(lex, &buf);
80 assert_int_equal(result, ISC_R_SUCCESS);
81
82 result = isc_lex_setsourceline(lex, 100);
83 assert_int_equal(result, ISC_R_SUCCESS);
84
85 for (i = 0; i < 6; i++) {
86 result = isc_lex_gettoken(lex, 0, &token);
87 assert_int_equal(result, ISC_R_SUCCESS);
88
89 line = isc_lex_getsourceline(lex);
90 assert_int_equal(line, 100U + i);
91 }
92
93 result = isc_lex_gettoken(lex, 0, &token);
94 assert_int_equal(result, ISC_R_EOF);
95
96 line = isc_lex_getsourceline(lex);
97 assert_int_equal(line, 105U);
98
99 isc_lex_destroy(&lex);
100 }
101
102 static struct {
103 const char *text;
104 const char *string_value;
105 isc_result_t string_result;
106 isc_tokentype_t string_type;
107 const char *qstring_value;
108 isc_result_t qstring_result;
109 isc_tokentype_t qstring_type;
110 const char *qvpair_value;
111 isc_result_t qvpair_result;
112 isc_tokentype_t qvpair_type;
113 } parse_tests[] = {
114 { "", "", ISC_R_SUCCESS, isc_tokentype_eof, "", ISC_R_SUCCESS,
115 isc_tokentype_eof, "", ISC_R_SUCCESS, isc_tokentype_eof },
116 { "1234", "1234", ISC_R_SUCCESS, isc_tokentype_string, "1234",
117 ISC_R_SUCCESS, isc_tokentype_string, "1234", ISC_R_SUCCESS,
118 isc_tokentype_string },
119 { "1234=", "1234=", ISC_R_SUCCESS, isc_tokentype_string,
120 "1234=", ISC_R_SUCCESS, isc_tokentype_string, "1234=", ISC_R_SUCCESS,
121 isc_tokentype_vpair },
122 { "1234=foo", "1234=foo", ISC_R_SUCCESS, isc_tokentype_string,
123 "1234=foo", ISC_R_SUCCESS, isc_tokentype_string, "1234=foo",
124 ISC_R_SUCCESS, isc_tokentype_vpair },
125 { "1234=\"foo", "1234=\"foo", ISC_R_SUCCESS, isc_tokentype_string,
126 "1234=\"foo", ISC_R_SUCCESS, isc_tokentype_string, NULL,
127 ISC_R_UNEXPECTEDEND, 0 },
128 { "1234=\"foo\"", "1234=\"foo\"", ISC_R_SUCCESS, isc_tokentype_string,
129 "1234=\"foo\"", ISC_R_SUCCESS, isc_tokentype_string, "1234=foo",
130 ISC_R_SUCCESS, isc_tokentype_qvpair },
131 { "key", "key", ISC_R_SUCCESS, isc_tokentype_string, "key",
132 ISC_R_SUCCESS, isc_tokentype_string, "key", ISC_R_SUCCESS,
133 isc_tokentype_string },
134 { "\"key=", "\"key=", ISC_R_SUCCESS, isc_tokentype_string, NULL,
135 ISC_R_UNEXPECTEDEND, 0, "\"key=", ISC_R_SUCCESS,
136 isc_tokentype_vpair },
137 { "\"key=\"", "\"key=\"", ISC_R_SUCCESS, isc_tokentype_string, "key=",
138 ISC_R_SUCCESS, isc_tokentype_qstring, NULL, ISC_R_UNEXPECTEDEND, 0 },
139 { "key=\"\"", "key=\"\"", ISC_R_SUCCESS, isc_tokentype_string,
140 "key=\"\"", ISC_R_SUCCESS, isc_tokentype_string,
141 "key=", ISC_R_SUCCESS, isc_tokentype_qvpair },
142 { "key=\"a b\"", "key=\"a", ISC_R_SUCCESS, isc_tokentype_string,
143 "key=\"a", ISC_R_SUCCESS, isc_tokentype_string, "key=a b",
144 ISC_R_SUCCESS, isc_tokentype_qvpair },
145 { "key=\"a\tb\"", "key=\"a", ISC_R_SUCCESS, isc_tokentype_string,
146 "key=\"a", ISC_R_SUCCESS, isc_tokentype_string, "key=a\tb",
147 ISC_R_SUCCESS, isc_tokentype_qvpair },
148 /* double quote not immediately after '=' is not special. */
149 { "key=c\"a b\"", "key=c\"a", ISC_R_SUCCESS, isc_tokentype_string,
150 "key=c\"a", ISC_R_SUCCESS, isc_tokentype_string, "key=c\"a",
151 ISC_R_SUCCESS, isc_tokentype_vpair },
152 /* remove special meaning for '=' by escaping */
153 { "key\\=", "key\\=", ISC_R_SUCCESS, isc_tokentype_string,
154 "key\\=", ISC_R_SUCCESS, isc_tokentype_string,
155 "key\\=", ISC_R_SUCCESS, isc_tokentype_string },
156 { "key\\=\"a\"", "key\\=\"a\"", ISC_R_SUCCESS, isc_tokentype_string,
157 "key\\=\"a\"", ISC_R_SUCCESS, isc_tokentype_string, "key\\=\"a\"",
158 ISC_R_SUCCESS, isc_tokentype_string },
159 { "key\\=\"a \"", "key\\=\"a", ISC_R_SUCCESS, isc_tokentype_string,
160 "key\\=\"a", ISC_R_SUCCESS, isc_tokentype_string, "key\\=\"a",
161 ISC_R_SUCCESS, isc_tokentype_string },
162 /* vpair with a key of 'key\=' (would need to be deescaped) */
163 { "key\\==", "key\\==", ISC_R_SUCCESS, isc_tokentype_string,
164 "key\\==", ISC_R_SUCCESS, isc_tokentype_string,
165 "key\\==", ISC_R_SUCCESS, isc_tokentype_vpair },
166 { "key\\==\"\"", "key\\==\"\"", ISC_R_SUCCESS, isc_tokentype_string,
167 "key\\==\"\"", ISC_R_SUCCESS, isc_tokentype_string,
168 "key\\==", ISC_R_SUCCESS, isc_tokentype_qvpair },
169 { "key=\\\\\\\\", "key=\\\\\\\\", ISC_R_SUCCESS, isc_tokentype_string,
170 "key=\\\\\\\\", ISC_R_SUCCESS, isc_tokentype_string, "key=\\\\\\\\",
171 ISC_R_SUCCESS, isc_tokentype_vpair },
172 { "key=\\\\\\\"", "key=\\\\\\\"", ISC_R_SUCCESS, isc_tokentype_string,
173 "key=\\\\\\\"", ISC_R_SUCCESS, isc_tokentype_string, "key=\\\\\\\"",
174 ISC_R_SUCCESS, isc_tokentype_vpair },
175 /* incomplete escape sequence */
176 { "key=\\\"\\", NULL, ISC_R_UNEXPECTEDEND, isc_tokentype_string, NULL,
177 ISC_R_UNEXPECTEDEND, 0, NULL, ISC_R_UNEXPECTEDEND, 0 },
178 /* incomplete escape sequence */
179 { "key=\\", NULL, ISC_R_UNEXPECTEDEND, isc_tokentype_string, NULL,
180 ISC_R_UNEXPECTEDEND, 0, NULL, ISC_R_UNEXPECTEDEND, 0 },
181 };
182
183 /*%
184 * string
185 */
186 ISC_RUN_TEST_IMPL(lex_string) {
187 isc_buffer_t buf;
188 isc_lex_t *lex = NULL;
189 isc_result_t result;
190 isc_token_t token;
191 size_t i;
192
193 UNUSED(state);
194
195 for (i = 0; i < ARRAY_SIZE(parse_tests); i++) {
196 isc_lex_create(mctx, 1024, &lex);
197
198 isc_buffer_constinit(&buf, parse_tests[i].text,
199 strlen(parse_tests[i].text));
200 isc_buffer_add(&buf, strlen(parse_tests[i].text));
201
202 result = isc_lex_openbuffer(lex, &buf);
203 assert_int_equal(result, ISC_R_SUCCESS);
204
205 result = isc_lex_setsourceline(lex, 100);
206 assert_int_equal(result, ISC_R_SUCCESS);
207
208 memset(&token, 0, sizeof(token));
209 result = isc_lex_getmastertoken(lex, &token,
210 isc_tokentype_string, true);
211
212 assert_int_equal(result, parse_tests[i].string_result);
213 if (result == ISC_R_SUCCESS) {
214 switch (token.type) {
215 case isc_tokentype_string:
216 case isc_tokentype_qstring:
217 case isc_tokentype_vpair:
218 case isc_tokentype_qvpair:
219 assert_int_equal(token.type,
220 parse_tests[i].string_type);
221 assert_string_equal(
222 AS_STR(token),
223 parse_tests[i].string_value);
224 break;
225 default:
226 assert_int_equal(token.type,
227 parse_tests[i].string_type);
228 break;
229 }
230 }
231
232 isc_lex_destroy(&lex);
233 }
234 }
235
236 /*%
237 * qstring
238 */
239 ISC_RUN_TEST_IMPL(lex_qstring) {
240 isc_buffer_t buf;
241 isc_lex_t *lex = NULL;
242 isc_result_t result;
243 isc_token_t token;
244 size_t i;
245
246 UNUSED(state);
247
248 for (i = 0; i < ARRAY_SIZE(parse_tests); i++) {
249 isc_lex_create(mctx, 1024, &lex);
250
251 isc_buffer_constinit(&buf, parse_tests[i].text,
252 strlen(parse_tests[i].text));
253 isc_buffer_add(&buf, strlen(parse_tests[i].text));
254
255 result = isc_lex_openbuffer(lex, &buf);
256 assert_int_equal(result, ISC_R_SUCCESS);
257
258 result = isc_lex_setsourceline(lex, 100);
259 assert_int_equal(result, ISC_R_SUCCESS);
260
261 memset(&token, 0, sizeof(token));
262 result = isc_lex_getmastertoken(lex, &token,
263 isc_tokentype_qstring, true);
264
265 assert_int_equal(result, parse_tests[i].qstring_result);
266 if (result == ISC_R_SUCCESS) {
267 switch (token.type) {
268 case isc_tokentype_string:
269 case isc_tokentype_qstring:
270 case isc_tokentype_vpair:
271 case isc_tokentype_qvpair:
272 assert_int_equal(token.type,
273 parse_tests[i].qstring_type);
274 assert_string_equal(
275 AS_STR(token),
276 parse_tests[i].qstring_value);
277 break;
278 default:
279 assert_int_equal(token.type,
280 parse_tests[i].qstring_type);
281 break;
282 }
283 }
284
285 isc_lex_destroy(&lex);
286 }
287 }
288
289 /*%
290 * keypair is <string>=<qstring>. This has implications double quotes
291 * in key names.
292 */
293 ISC_RUN_TEST_IMPL(lex_keypair) {
294 isc_buffer_t buf;
295 isc_lex_t *lex = NULL;
296 isc_result_t result;
297 isc_token_t token;
298 size_t i;
299
300 UNUSED(state);
301
302 for (i = 0; i < ARRAY_SIZE(parse_tests); i++) {
303 isc_lex_create(mctx, 1024, &lex);
304
305 isc_buffer_constinit(&buf, parse_tests[i].text,
306 strlen(parse_tests[i].text));
307 isc_buffer_add(&buf, strlen(parse_tests[i].text));
308
309 result = isc_lex_openbuffer(lex, &buf);
310 assert_int_equal(result, ISC_R_SUCCESS);
311
312 result = isc_lex_setsourceline(lex, 100);
313 assert_int_equal(result, ISC_R_SUCCESS);
314
315 memset(&token, 0, sizeof(token));
316 result = isc_lex_getmastertoken(lex, &token,
317 isc_tokentype_qvpair, true);
318
319 assert_int_equal(result, parse_tests[i].qvpair_result);
320 if (result == ISC_R_SUCCESS) {
321 switch (token.type) {
322 case isc_tokentype_string:
323 case isc_tokentype_qstring:
324 case isc_tokentype_vpair:
325 case isc_tokentype_qvpair:
326 assert_int_equal(token.type,
327 parse_tests[i].qvpair_type);
328 assert_string_equal(
329 AS_STR(token),
330 parse_tests[i].qvpair_value);
331 break;
332 default:
333 assert_int_equal(token.type,
334 parse_tests[i].qvpair_type);
335 break;
336 }
337 }
338
339 isc_lex_destroy(&lex);
340 }
341 }
342
343 ISC_TEST_LIST_START
344 ISC_TEST_ENTRY(lex_0xff)
345 ISC_TEST_ENTRY(lex_keypair)
346 ISC_TEST_ENTRY(lex_setline)
347 ISC_TEST_ENTRY(lex_string)
348 ISC_TEST_ENTRY(lex_qstring)
349 ISC_TEST_LIST_END
350
351 ISC_TEST_MAIN
352