1 /* 2 * test-bytecode.c 3 * Tests for the public libpkgconf bytecode API: 4 * pkgconf_bytecode_compile and pkgconf_bytecode_eval_str. 5 * 6 * SPDX-License-Identifier: pkgconf 7 * 8 * Copyright (c) 2025 pkgconf authors (see AUTHORS). 9 * 10 * Permission to use, copy, modify, and/or distribute this software for any 11 * purpose with or without fee is hereby granted, provided that the above 12 * copyright notice and this permission notice appear in all copies. 13 * 14 * This software is provided 'as is' and without any warranty, express or 15 * implied. In no event shall the authors be liable for any damages arising 16 * from the use of this software. 17 */ 18 19 #include <libpkgconf/stdinc.h> 20 #include <libpkgconf/libpkgconf.h> 21 #include "test-api.h" 22 23 /* 24 * Build a variable list with the given key/value pairs. Caller frees 25 * with pkgconf_variable_list_free(). 26 * 27 * The key/value pairs are stored by compiling `value` as bytecode and 28 * stashing the result on a pkgconf_variable_t inside the list, which 29 * is how the parser builds variable scopes for real .pc files. 30 */ 31 static void 32 seed_variable(pkgconf_list_t *vars, const char *key, const char *value) 33 { 34 pkgconf_variable_t *v = pkgconf_variable_get_or_create(vars, key); 35 TEST_ASSERT_NONNULL(v); 36 37 pkgconf_buffer_reset(&v->bcbuf); 38 pkgconf_bytecode_compile(&v->bcbuf, value); 39 pkgconf_bytecode_from_buffer(&v->bc, &v->bcbuf); 40 } 41 42 static void 43 test_emit_text_and_eval(void) 44 { 45 pkgconf_client_t *client = test_client_new(); 46 pkgconf_list_t vars = PKGCONF_LIST_INITIALIZER; 47 pkgconf_buffer_t bcbuf = PKGCONF_BUFFER_INITIALIZER; 48 pkgconf_bytecode_t bc; 49 bool saw_sysroot = false; 50 51 TEST_ASSERT_TRUE(pkgconf_bytecode_emit_text(&bcbuf, "plain", 5)); 52 pkgconf_bytecode_from_buffer(&bc, &bcbuf); 53 54 pkgconf_buffer_t out = PKGCONF_BUFFER_INITIALIZER; 55 TEST_ASSERT_TRUE(pkgconf_bytecode_eval(client, &vars, &bc, &out, &saw_sysroot)); 56 TEST_ASSERT_STRCMP_EQ(pkgconf_buffer_str_or_empty(&out), "plain"); 57 58 pkgconf_buffer_finalize(&out); 59 pkgconf_buffer_finalize(&bcbuf); 60 pkgconf_variable_list_free(&vars); 61 pkgconf_client_free(client); 62 } 63 64 static void 65 test_emit_guards(void) 66 { 67 pkgconf_buffer_t bcbuf = PKGCONF_BUFFER_INITIALIZER; 68 69 TEST_ASSERT_TRUE(pkgconf_bytecode_emit_text(&bcbuf, NULL, 5)); 70 TEST_ASSERT_TRUE(pkgconf_bytecode_emit_text(&bcbuf, "x", 0)); 71 TEST_ASSERT_TRUE(pkgconf_bytecode_emit_var(&bcbuf, NULL, 3)); 72 TEST_ASSERT_TRUE(pkgconf_bytecode_emit_var(&bcbuf, "x", 0)); 73 74 TEST_ASSERT_EQ(pkgconf_buffer_len(&bcbuf), 0); 75 76 pkgconf_buffer_finalize(&bcbuf); 77 } 78 79 static void 80 test_emit_var_and_eval(void) 81 { 82 pkgconf_client_t *client = test_client_new(); 83 pkgconf_list_t vars = PKGCONF_LIST_INITIALIZER; 84 pkgconf_buffer_t bcbuf = PKGCONF_BUFFER_INITIALIZER; 85 pkgconf_bytecode_t bc; 86 bool saw_sysroot = false; 87 88 seed_variable(&vars, "name", "world"); 89 90 TEST_ASSERT_TRUE(pkgconf_bytecode_emit_text(&bcbuf, "hello ", 6)); 91 TEST_ASSERT_TRUE(pkgconf_bytecode_emit_var(&bcbuf, "name", 4)); 92 pkgconf_bytecode_from_buffer(&bc, &bcbuf); 93 94 pkgconf_buffer_t out = PKGCONF_BUFFER_INITIALIZER; 95 TEST_ASSERT_TRUE(pkgconf_bytecode_eval(client, &vars, &bc, &out, &saw_sysroot)); 96 TEST_ASSERT_STRCMP_EQ(pkgconf_buffer_str_or_empty(&out), "hello world"); 97 98 pkgconf_buffer_finalize(&out); 99 pkgconf_buffer_finalize(&bcbuf); 100 pkgconf_variable_list_free(&vars); 101 pkgconf_client_free(client); 102 } 103 104 static void 105 test_emit_sysroot_and_eval(void) 106 { 107 pkgconf_client_t *client = test_client_new(); 108 pkgconf_list_t vars = PKGCONF_LIST_INITIALIZER; 109 pkgconf_buffer_t bcbuf = PKGCONF_BUFFER_INITIALIZER; 110 pkgconf_bytecode_t bc; 111 bool saw_sysroot = false; 112 113 pkgconf_client_set_sysroot_dir(client, "/sysroot"); 114 115 TEST_ASSERT_TRUE(pkgconf_bytecode_emit_sysroot(&bcbuf)); 116 TEST_ASSERT_TRUE(pkgconf_bytecode_emit_text(&bcbuf, "/usr/include", 12)); 117 pkgconf_bytecode_from_buffer(&bc, &bcbuf); 118 119 pkgconf_buffer_t out = PKGCONF_BUFFER_INITIALIZER; 120 TEST_ASSERT_TRUE(pkgconf_bytecode_eval(client, &vars, &bc, &out, &saw_sysroot)); 121 TEST_ASSERT_TRUE(saw_sysroot); 122 TEST_ASSERT_STRCMP_EQ(pkgconf_buffer_str_or_empty(&out), "/sysroot/usr/include"); 123 124 pkgconf_buffer_finalize(&out); 125 pkgconf_buffer_finalize(&bcbuf); 126 pkgconf_variable_list_free(&vars); 127 pkgconf_client_free(client); 128 } 129 130 static void 131 test_eval_null_args(void) 132 { 133 pkgconf_client_t *client = test_client_new(); 134 pkgconf_list_t vars = PKGCONF_LIST_INITIALIZER; 135 pkgconf_buffer_t out = PKGCONF_BUFFER_INITIALIZER; 136 pkgconf_bytecode_t bc = { NULL, 0 }; 137 138 // NULL client, bc, or out all return false. 139 TEST_ASSERT_FALSE(pkgconf_bytecode_eval(NULL, &vars, &bc, &out, NULL)); 140 TEST_ASSERT_FALSE(pkgconf_bytecode_eval(client, &vars, NULL, &out, NULL)); 141 TEST_ASSERT_FALSE(pkgconf_bytecode_eval(client, &vars, &bc, NULL, NULL)); 142 143 pkgconf_buffer_finalize(&out); 144 pkgconf_variable_list_free(&vars); 145 pkgconf_client_free(client); 146 } 147 148 static void 149 test_compile_null_args(void) 150 { 151 pkgconf_buffer_t out = PKGCONF_BUFFER_INITIALIZER; 152 153 TEST_ASSERT_FALSE(pkgconf_bytecode_compile(NULL, "x")); 154 TEST_ASSERT_FALSE(pkgconf_bytecode_compile(&out, NULL)); 155 156 pkgconf_buffer_finalize(&out); 157 } 158 159 static void 160 test_dollar_escape(void) 161 { 162 pkgconf_client_t *client = test_client_new(); 163 pkgconf_list_t vars = PKGCONF_LIST_INITIALIZER; 164 bool saw_sysroot = false; 165 166 // $$ collapses to a literal $; the following text is NOT treated as a variable reference 167 char *out = pkgconf_bytecode_eval_str(client, &vars, "price: $$5 and $${notavar}", &saw_sysroot); 168 TEST_ASSERT_NONNULL(out); 169 TEST_ASSERT_STRCMP_EQ(out, "price: $5 and ${notavar}"); 170 171 free(out); 172 pkgconf_variable_list_free(&vars); 173 pkgconf_client_free(client); 174 } 175 176 static void 177 test_malformed_unclosed(void) 178 { 179 pkgconf_client_t *client = test_client_new(); 180 pkgconf_list_t vars = PKGCONF_LIST_INITIALIZER; 181 bool saw_sysroot = false; 182 183 // A ${ with no closing } is emitted as literal text 184 char *out = pkgconf_bytecode_eval_str(client, &vars, "broken ${unclosed", &saw_sysroot); 185 TEST_ASSERT_NONNULL(out); 186 TEST_ASSERT_STRCMP_EQ(out, "broken ${unclosed"); 187 188 free(out); 189 pkgconf_variable_list_free(&vars); 190 pkgconf_client_free(client); 191 } 192 193 static void 194 test_empty_braces(void) 195 { 196 pkgconf_client_t *client = test_client_new(); 197 pkgconf_list_t vars = PKGCONF_LIST_INITIALIZER; 198 bool saw_sysroot = false; 199 200 // ${} has a zero-length name; it's emitted as literal text rather than treated as a variable 201 char *out = pkgconf_bytecode_eval_str(client, &vars, "empty ${} here", &saw_sysroot); 202 TEST_ASSERT_NONNULL(out); 203 TEST_ASSERT_STRCMP_EQ(out, "empty ${} here"); 204 205 free(out); 206 pkgconf_variable_list_free(&vars); 207 pkgconf_client_free(client); 208 } 209 210 static void 211 test_compile_time_sysroot(void) 212 { 213 pkgconf_client_t *client = test_client_new(); 214 pkgconf_list_t vars = PKGCONF_LIST_INITIALIZER; 215 bool saw_sysroot = false; 216 217 pkgconf_client_set_sysroot_dir(client, "/sysroot"); 218 219 // ${pc_sysrootdir} is special-cased at compile time into an OP_SYSROOT op rather than a variable lookup 220 char *out = pkgconf_bytecode_eval_str(client, &vars, "${pc_sysrootdir}/usr/lib", &saw_sysroot); 221 TEST_ASSERT_NONNULL(out); 222 TEST_ASSERT_TRUE(saw_sysroot); 223 TEST_ASSERT_STRCMP_EQ(out, "/sysroot/usr/lib"); 224 225 free(out); 226 pkgconf_variable_list_free(&vars); 227 pkgconf_client_free(client); 228 } 229 230 static void 231 test_sysroot_dot_disables(void) 232 { 233 pkgconf_client_t *client = test_client_new(); 234 pkgconf_list_t vars = PKGCONF_LIST_INITIALIZER; 235 bool saw_sysroot = false; 236 237 // A sysroot of "." disables sysroot rewriting: ${pc_sysrootdir} expands to empty 238 pkgconf_client_set_sysroot_dir(client, "."); 239 240 char *out = pkgconf_bytecode_eval_str(client, &vars, "${pc_sysrootdir}/usr/lib", &saw_sysroot); 241 TEST_ASSERT_NONNULL(out); 242 TEST_ASSERT_STRCMP_EQ(out, "/usr/lib"); 243 244 free(out); 245 pkgconf_variable_list_free(&vars); 246 pkgconf_client_free(client); 247 } 248 249 static void 250 test_sysroot_root_disables(void) 251 { 252 pkgconf_client_t *client = test_client_new(); 253 pkgconf_list_t vars = PKGCONF_LIST_INITIALIZER; 254 bool saw_sysroot = false; 255 256 // A sysroot of "/" (the root dir) disables rewriting. 257 pkgconf_client_set_sysroot_dir(client, "/"); 258 259 char *out = pkgconf_bytecode_eval_str(client, &vars, "${pc_sysrootdir}/usr/lib", &saw_sysroot); 260 TEST_ASSERT_NONNULL(out); 261 TEST_ASSERT_STRCMP_EQ(out, "/usr/lib"); 262 263 free(out); 264 pkgconf_variable_list_free(&vars); 265 pkgconf_client_free(client); 266 } 267 268 static void 269 test_sysroot_trailing_slash_trimmed(void) 270 { 271 pkgconf_client_t *client = test_client_new(); 272 pkgconf_list_t vars = PKGCONF_LIST_INITIALIZER; 273 bool saw_sysroot = false; 274 275 // Trailing slashes on the sysroot are normalized away, so the result doesn't get a doubled slash 276 pkgconf_client_set_sysroot_dir(client, "/sysroot///"); 277 278 char *out = pkgconf_bytecode_eval_str(client, &vars, "${pc_sysrootdir}/usr/lib", &saw_sysroot); 279 TEST_ASSERT_NONNULL(out); 280 TEST_ASSERT_TRUE(saw_sysroot); 281 TEST_ASSERT_STRCMP_EQ(out, "/sysroot/usr/lib"); 282 283 free(out); 284 pkgconf_variable_list_free(&vars); 285 pkgconf_client_free(client); 286 } 287 288 static void 289 test_sysroot_normalizes_to_root_disables(void) 290 { 291 pkgconf_client_t *client = test_client_new(); 292 pkgconf_list_t vars = PKGCONF_LIST_INITIALIZER; 293 bool saw_sysroot = false; 294 295 /* A sysroot of "//" survives the bare-"/" early check but normalizes down to "/" after 296 * trailing-slash trimming, which then disables rewriting (empty sysroot) */ 297 pkgconf_client_set_sysroot_dir(client, "//"); 298 299 char *out = pkgconf_bytecode_eval_str(client, &vars, "${pc_sysrootdir}/usr/lib", &saw_sysroot); 300 TEST_ASSERT_NONNULL(out); 301 TEST_ASSERT_STRCMP_EQ(out, "/usr/lib"); 302 303 free(out); 304 pkgconf_variable_list_free(&vars); 305 pkgconf_client_free(client); 306 } 307 308 static void 309 test_circular_reference(void) 310 { 311 pkgconf_client_t *client = test_client_new(); 312 pkgconf_list_t vars = PKGCONF_LIST_INITIALIZER; 313 bool saw_sysroot = false; 314 315 // A variable that references itself must not infinite-loop: the `expanding` guard breaks the cycle 316 seed_variable(&vars, "loop", "${loop}"); 317 318 char *out = pkgconf_bytecode_eval_str(client, &vars, "${loop}", &saw_sysroot); 319 320 /* The self-reference is broken; behavior is "expands to nothing further" 321 * We mostly care that it returns rather than hanging or crashing */ 322 if (out != NULL) 323 free(out); 324 325 pkgconf_variable_list_free(&vars); 326 pkgconf_client_free(client); 327 } 328 329 static void 330 test_references_var(void) 331 { 332 pkgconf_buffer_t bcbuf = PKGCONF_BUFFER_INITIALIZER; 333 334 pkgconf_bytecode_compile(&bcbuf, "-I${includedir} -L${libdir}"); 335 336 TEST_ASSERT_TRUE(pkgconf_bytecode_references_var(&bcbuf, "includedir")); 337 TEST_ASSERT_TRUE(pkgconf_bytecode_references_var(&bcbuf, "libdir")); 338 TEST_ASSERT_FALSE(pkgconf_bytecode_references_var(&bcbuf, "prefix")); 339 340 TEST_ASSERT_FALSE(pkgconf_bytecode_references_var(NULL, "x")); 341 TEST_ASSERT_FALSE(pkgconf_bytecode_references_var(&bcbuf, NULL)); 342 343 pkgconf_buffer_finalize(&bcbuf); 344 } 345 346 static void 347 test_references_var_text_only(void) 348 { 349 pkgconf_buffer_t bcbuf = PKGCONF_BUFFER_INITIALIZER; 350 351 pkgconf_bytecode_compile(&bcbuf, "just plain text"); 352 353 TEST_ASSERT_FALSE(pkgconf_bytecode_references_var(&bcbuf, "anything")); 354 355 pkgconf_buffer_finalize(&bcbuf); 356 } 357 358 static void 359 test_rewrite_selfrefs(void) 360 { 361 pkgconf_client_t *client = test_client_new(); 362 pkgconf_list_t vars = PKGCONF_LIST_INITIALIZER; 363 bool saw_sysroot = false; 364 365 pkgconf_buffer_t prev = PKGCONF_BUFFER_INITIALIZER; 366 pkgconf_bytecode_compile(&prev, "old"); 367 368 pkgconf_buffer_t rhs = PKGCONF_BUFFER_INITIALIZER; 369 pkgconf_bytecode_compile(&rhs, "${foo} new"); 370 371 pkgconf_buffer_t rewritten = PKGCONF_BUFFER_INITIALIZER; 372 TEST_ASSERT_TRUE(pkgconf_bytecode_rewrite_selfrefs(&rewritten, &rhs, "foo", &prev)); 373 374 pkgconf_bytecode_t bc; 375 pkgconf_bytecode_from_buffer(&bc, &rewritten); 376 377 pkgconf_buffer_t out = PKGCONF_BUFFER_INITIALIZER; 378 TEST_ASSERT_TRUE(pkgconf_bytecode_eval(client, &vars, &bc, &out, &saw_sysroot)); 379 TEST_ASSERT_STRCMP_EQ(pkgconf_buffer_str_or_empty(&out), "old new"); 380 381 pkgconf_buffer_finalize(&out); 382 pkgconf_buffer_finalize(&rewritten); 383 pkgconf_buffer_finalize(&rhs); 384 pkgconf_buffer_finalize(&prev); 385 pkgconf_variable_list_free(&vars); 386 pkgconf_client_free(client); 387 } 388 389 static void 390 test_rewrite_selfrefs_no_match(void) 391 { 392 pkgconf_client_t *client = test_client_new(); 393 pkgconf_list_t vars = PKGCONF_LIST_INITIALIZER; 394 bool saw_sysroot = false; 395 396 pkgconf_buffer_t prev = PKGCONF_BUFFER_INITIALIZER; 397 pkgconf_bytecode_compile(&prev, "PREV"); 398 399 pkgconf_buffer_t rhs = PKGCONF_BUFFER_INITIALIZER; 400 pkgconf_bytecode_compile(&rhs, "${other} tail"); 401 402 pkgconf_buffer_t rewritten = PKGCONF_BUFFER_INITIALIZER; 403 TEST_ASSERT_TRUE(pkgconf_bytecode_rewrite_selfrefs(&rewritten, &rhs, "foo", &prev)); 404 405 // ${other} survives; seed it so eval can resolve it 406 seed_variable(&vars, "other", "OTHER"); 407 408 pkgconf_bytecode_t bc; 409 pkgconf_bytecode_from_buffer(&bc, &rewritten); 410 411 pkgconf_buffer_t out = PKGCONF_BUFFER_INITIALIZER; 412 TEST_ASSERT_TRUE(pkgconf_bytecode_eval(client, &vars, &bc, &out, &saw_sysroot)); 413 TEST_ASSERT_STRCMP_EQ(pkgconf_buffer_str_or_empty(&out), "OTHER tail"); 414 415 pkgconf_buffer_finalize(&out); 416 pkgconf_buffer_finalize(&rewritten); 417 pkgconf_buffer_finalize(&rhs); 418 pkgconf_buffer_finalize(&prev); 419 pkgconf_variable_list_free(&vars); 420 pkgconf_client_free(client); 421 } 422 423 static void 424 test_eval_plain_text(void) 425 { 426 pkgconf_client_t *client = test_client_new(); 427 pkgconf_list_t vars = PKGCONF_LIST_INITIALIZER; 428 bool saw_sysroot = false; 429 430 // A string with no variable references should round-trip unchanged. 431 char *out = pkgconf_bytecode_eval_str(client, &vars, "plain text value", &saw_sysroot); 432 433 TEST_ASSERT_NONNULL(out); 434 TEST_ASSERT_STRCMP_EQ(out, "plain text value"); 435 TEST_ASSERT_FALSE(saw_sysroot); 436 437 free(out); 438 pkgconf_variable_list_free(&vars); 439 pkgconf_client_free(client); 440 } 441 442 static void 443 test_eval_variable_substitution(void) 444 { 445 pkgconf_client_t *client = test_client_new(); 446 pkgconf_list_t vars = PKGCONF_LIST_INITIALIZER; 447 bool saw_sysroot = false; 448 449 seed_variable(&vars, "prefix", "/opt/foo"); 450 451 char *out = pkgconf_bytecode_eval_str(client, &vars, "${prefix}/lib", &saw_sysroot); 452 453 TEST_ASSERT_NONNULL(out); 454 TEST_ASSERT_STRCMP_EQ(out, "/opt/foo/lib"); 455 TEST_ASSERT_FALSE(saw_sysroot); 456 457 free(out); 458 pkgconf_variable_list_free(&vars); 459 pkgconf_client_free(client); 460 } 461 462 static void 463 test_eval_nested_variables(void) 464 { 465 pkgconf_client_t *client = test_client_new(); 466 pkgconf_list_t vars = PKGCONF_LIST_INITIALIZER; 467 bool saw_sysroot = false; 468 469 // Recursive expansion: libdir references prefix. 470 seed_variable(&vars, "prefix", "/usr/local"); 471 seed_variable(&vars, "libdir", "${prefix}/lib"); 472 473 char *out = pkgconf_bytecode_eval_str(client, &vars, "-L${libdir}", &saw_sysroot); 474 475 TEST_ASSERT_NONNULL(out); 476 TEST_ASSERT_STRCMP_EQ(out, "-L/usr/local/lib"); 477 478 free(out); 479 pkgconf_variable_list_free(&vars); 480 pkgconf_client_free(client); 481 } 482 483 static void 484 test_eval_undefined_variable(void) 485 { 486 pkgconf_client_t *client = test_client_new(); 487 pkgconf_list_t vars = PKGCONF_LIST_INITIALIZER; 488 bool saw_sysroot = false; 489 490 // Referencing an undefined variable should produce empty substitution, not failure 491 char *out = pkgconf_bytecode_eval_str(client, &vars, "prefix=${nonexistent}/end", &saw_sysroot); 492 493 TEST_ASSERT_NONNULL(out); 494 TEST_ASSERT_STRCMP_EQ(out, "prefix=/end"); 495 496 free(out); 497 pkgconf_variable_list_free(&vars); 498 pkgconf_client_free(client); 499 } 500 501 static void 502 test_eval_multiple_variables(void) 503 { 504 pkgconf_client_t *client = test_client_new(); 505 pkgconf_list_t vars = PKGCONF_LIST_INITIALIZER; 506 bool saw_sysroot = false; 507 508 seed_variable(&vars, "prefix", "/usr"); 509 seed_variable(&vars, "exec_prefix", "/usr/local"); 510 511 char *out = pkgconf_bytecode_eval_str(client, &vars, "-I${prefix}/include -L${exec_prefix}/lib", &saw_sysroot); 512 513 TEST_ASSERT_NONNULL(out); 514 TEST_ASSERT_STRCMP_EQ(out, "-I/usr/include -L/usr/local/lib"); 515 516 free(out); 517 pkgconf_variable_list_free(&vars); 518 pkgconf_client_free(client); 519 } 520 521 static void 522 test_eval_empty_input(void) 523 { 524 pkgconf_client_t *client = test_client_new(); 525 pkgconf_list_t vars = PKGCONF_LIST_INITIALIZER; 526 bool saw_sysroot = false; 527 528 char *out = pkgconf_bytecode_eval_str(client, &vars, "", &saw_sysroot); 529 530 // An empty input may evaluate to either NULL or an empty string 531 if (out != NULL) 532 { 533 TEST_ASSERT_STRCMP_EQ(out, ""); 534 free(out); 535 } 536 537 pkgconf_variable_list_free(&vars); 538 pkgconf_client_free(client); 539 } 540 541 static void 542 test_eval_sysroot_detection(void) 543 { 544 pkgconf_client_t *client = test_client_new(); 545 pkgconf_list_t vars = PKGCONF_LIST_INITIALIZER; 546 bool saw_sysroot = false; 547 548 pkgconf_client_set_sysroot_dir(client, "/sysroot"); 549 550 seed_variable(&vars, "pc_sysrootdir", "/sysroot"); 551 seed_variable(&vars, "includedir", "${pc_sysrootdir}/usr/include"); 552 553 char *out = pkgconf_bytecode_eval_str(client, &vars, "${includedir}", &saw_sysroot); 554 555 TEST_ASSERT_NONNULL(out); 556 TEST_ASSERT_TRUE(saw_sysroot); 557 558 free(out); 559 pkgconf_variable_list_free(&vars); 560 pkgconf_client_free(client); 561 } 562 563 static void 564 test_compile_produces_nonempty_buffer(void) 565 { 566 pkgconf_buffer_t bc = PKGCONF_BUFFER_INITIALIZER; 567 568 pkgconf_bytecode_compile(&bc, "hello ${world}"); 569 570 // The compiled bytecode buffer should be non-empty 571 TEST_ASSERT_NE(pkgconf_buffer_len(&bc), 0); 572 573 pkgconf_buffer_finalize(&bc); 574 } 575 576 static void 577 test_compile_eval_roundtrip(void) 578 { 579 pkgconf_client_t *client = test_client_new(); 580 pkgconf_list_t vars = PKGCONF_LIST_INITIALIZER; 581 bool saw_sysroot = false; 582 583 // Compile directly, then evaluate via the bc field on a variable 584 seed_variable(&vars, "name", "world"); 585 586 pkgconf_variable_t *v = pkgconf_variable_get_or_create(&vars, "greeting"); 587 TEST_ASSERT_NONNULL(v); 588 pkgconf_buffer_reset(&v->bcbuf); 589 pkgconf_bytecode_compile(&v->bcbuf, "hello ${name}"); 590 pkgconf_bytecode_from_buffer(&v->bc, &v->bcbuf); 591 592 char *out = pkgconf_variable_eval_str(client, &vars, v, &saw_sysroot); 593 TEST_ASSERT_NONNULL(out); 594 TEST_ASSERT_STRCMP_EQ(out, "hello world"); 595 596 free(out); 597 pkgconf_variable_list_free(&vars); 598 pkgconf_client_free(client); 599 } 600 601 int 602 main(int argc, char *argv[]) 603 { 604 (void) argc; 605 const char *basename = pkgconf_path_find_basename(argv[0]); 606 607 TEST_RUN(basename, test_eval_plain_text); 608 TEST_RUN(basename, test_eval_empty_input); 609 TEST_RUN(basename, test_eval_variable_substitution); 610 TEST_RUN(basename, test_eval_nested_variables); 611 TEST_RUN(basename, test_eval_multiple_variables); 612 TEST_RUN(basename, test_eval_undefined_variable); 613 TEST_RUN(basename, test_eval_sysroot_detection); 614 TEST_RUN(basename, test_eval_null_args); 615 616 TEST_RUN(basename, test_emit_guards); 617 TEST_RUN(basename, test_emit_text_and_eval); 618 TEST_RUN(basename, test_emit_var_and_eval); 619 TEST_RUN(basename, test_emit_sysroot_and_eval); 620 621 TEST_RUN(basename, test_dollar_escape); 622 TEST_RUN(basename, test_malformed_unclosed); 623 TEST_RUN(basename, test_empty_braces); 624 625 TEST_RUN(basename, test_circular_reference); 626 TEST_RUN(basename, test_references_var); 627 TEST_RUN(basename, test_references_var_text_only); 628 629 TEST_RUN(basename, test_compile_time_sysroot); 630 TEST_RUN(basename, test_sysroot_dot_disables); 631 TEST_RUN(basename, test_sysroot_root_disables); 632 TEST_RUN(basename, test_sysroot_trailing_slash_trimmed); 633 TEST_RUN(basename, test_sysroot_normalizes_to_root_disables); 634 635 TEST_RUN(basename, test_rewrite_selfrefs); 636 TEST_RUN(basename, test_rewrite_selfrefs_no_match); 637 638 TEST_RUN(basename, test_compile_eval_roundtrip); 639 TEST_RUN(basename, test_compile_produces_nonempty_buffer); 640 TEST_RUN(basename, test_compile_null_args); 641 642 return EXIT_SUCCESS; 643 } 644