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