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 */ 38ISC_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 */ 64ISC_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 104static 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 */ 188ISC_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 */ 242ISC_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 */ 297ISC_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 348ISC_TEST_LIST_START 349ISC_TEST_ENTRY(lex_0xff) 350ISC_TEST_ENTRY(lex_keypair) 351ISC_TEST_ENTRY(lex_setline) 352ISC_TEST_ENTRY(lex_string) 353ISC_TEST_ENTRY(lex_qstring) 354 355ISC_TEST_LIST_END 356 357ISC_TEST_MAIN 358