xref: /netbsd-src/external/mpl/bind/dist/tests/isc/lex_test.c (revision bcda20f65a8566e103791ec395f7f499ef322704)
1 /*	$NetBSD: lex_test.c,v 1.3 2025/01/26 16:25:49 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