Home | History | Annotate | Line # | Download | only in isc
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