diff options
| author | Pierre Pronchery <khorben@FreeBSD.org> | 2026-06-24 19:47:19 +0000 |
|---|---|---|
| committer | Pierre Pronchery <khorben@FreeBSD.org> | 2026-06-29 05:21:29 +0000 |
| commit | ebcc78644e0cbc4141807c0887ef8d902cb91bb4 (patch) | |
| tree | da5efe7c3c9ae0f140e24a1b69833a476fb09f01 /tests | |
| parent | 6294b6ab217a2d5f1d2bc23a64505a228294c508 (diff) | |
Diffstat (limited to 'tests')
71 files changed, 7464 insertions, 2083 deletions
diff --git a/tests/Kyuafile.in b/tests/Kyuafile.in deleted file mode 100644 index f50b749fd717..000000000000 --- a/tests/Kyuafile.in +++ /dev/null @@ -1,14 +0,0 @@ -syntax(2) - -test_suite('pkgconf') - -atf_test_program{name='basic'} -atf_test_program{name='requires'} -atf_test_program{name='regress'} -atf_test_program{name='parser'} -atf_test_program{name='sysroot'} -atf_test_program{name='conflicts'} -atf_test_program{name='version'} -atf_test_program{name='framework'} -atf_test_program{name='provides'} -atf_test_program{name='symlink'} diff --git a/tests/api/test-api.h b/tests/api/test-api.h new file mode 100644 index 000000000000..cbe6598c846e --- /dev/null +++ b/tests/api/test-api.h @@ -0,0 +1,186 @@ +/* + * test-api.h + * test API macros and functions. + * + * SPDX-License-Identifier: pkgconf + * + * Copyright (c) 2026 pkgconf authors (see AUTHORS). + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * This software is provided 'as is' and without any warranty, express or + * implied. In no event shall the authors be liable for any damages arising + * from the use of this software. + */ + +#ifndef TEST_API_H +#define TEST_API_H + +#include <libpkgconf/stdinc.h> +#include <libpkgconf/libpkgconf.h> +#include <libpkgconf/path.h> +#include <tests/win-shim.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#if defined(__GNUC__) && !defined(__clang__) +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wpragmas" // older gcc may not know the next one + // Stop false-positive warnings for test cases +# pragma GCC diagnostic ignored "-Wanalyzer-tainted-assertion" +#endif + +#define TEST_FAIL_(fmt, ...) \ + do { \ + fprintf(stderr, "FAIL: %s:%d: " fmt "\n", \ + __FILE__, __LINE__, __VA_ARGS__); \ + exit(EXIT_FAILURE); \ + } while (0) + +#define TEST_ASSERT_TRUE(expr) \ + do { \ + if (!(expr)) \ + TEST_FAIL_("TEST_ASSERT_TRUE(%s) was false", #expr); \ + } while (0) + +#define TEST_ASSERT_FALSE(expr) \ + do { \ + if ((expr)) \ + TEST_FAIL_("TEST_ASSERT_FALSE(%s) was true", #expr); \ + } while (0) + +#define TEST_ASSERT_NULL(expr) \ + do { \ + const void *_v = (const void *)(expr); \ + if (_v != NULL) \ + TEST_FAIL_("TEST_ASSERT_NULL(%s) was %p", #expr, _v); \ + } while (0) + +#define TEST_ASSERT_NONNULL(expr) \ + do { \ + if ((expr) == NULL) \ + TEST_FAIL_("TEST_ASSERT_NONNULL(%s) was NULL", #expr); \ + } while (0) + +#define TEST_ASSERT_EQ(a, b) \ + do { \ + long long _a = (long long)(a); \ + long long _b = (long long)(b); \ + if (_a != _b) \ + TEST_FAIL_("TEST_ASSERT_EQ(%s, %s): %lld != %lld", \ + #a, #b, _a, _b); \ + } while (0) + +#define TEST_ASSERT_LT(a, b) \ + do { \ + long long _a = (long long)(a); \ + long long _b = (long long)(b); \ + if (_a >= _b) \ + TEST_FAIL_("TEST_ASSERT_LT(%s, %s): %lld >= %lld", \ + #a, #b, _a, _b); \ + } while (0) + +#define TEST_ASSERT_LE(a, b) \ + do { \ + long long _a = (long long)(a); \ + long long _b = (long long)(b); \ + if (_a > _b) \ + TEST_FAIL_("TEST_ASSERT_LE(%s, %s): %lld > %lld", \ + #a, #b, _a, _b); \ + } while (0) + +#define TEST_ASSERT_GT(a, b) \ + do { \ + long long _a = (long long)(a); \ + long long _b = (long long)(b); \ + if (_a <= _b) \ + TEST_FAIL_("TEST_ASSERT_GT(%s, %s): %lld <= %lld", \ + #a, #b, _a, _b); \ + } while (0) + +#define TEST_ASSERT_GE(a, b) \ + do { \ + long long _a = (long long)(a); \ + long long _b = (long long)(b); \ + if (_a < _b) \ + TEST_FAIL_("TEST_ASSERT_GE(%s, %s): %lld < %lld", \ + #a, #b, _a, _b); \ + } while (0) + +#define TEST_ASSERT_NE(a, b) \ + do { \ + long long _a = (long long)(a); \ + long long _b = (long long)(b); \ + if (_a == _b) \ + TEST_FAIL_("TEST_ASSERT_NE(%s, %s): both %lld", \ + #a, #b, _a); \ + } while (0) + +#define TEST_ASSERT_STRCMP_EQ(actual, expected) \ + do { \ + const char *_a = (actual); \ + const char *_e = (expected); \ + if (_a == NULL || _e == NULL || strcmp(_a, _e) != 0) \ + TEST_FAIL_("TEST_ASSERT_STRCMP_EQ(%s, %s): [%s] != [%s]", \ + #actual, #expected, \ + _a ? _a : "(null)", _e ? _e : "(null)"); \ + } while (0) + +#define TEST_ASSERT_STRCASECMP_EQ(actual, expected) \ + do { \ + const char *_a = (actual); \ + const char *_e = (expected); \ + if (_a == NULL || _e == NULL || strcasecmp(_a, _e) != 0) \ + TEST_FAIL_("TEST_ASSERT_STRCASECMP_EQ(%s, %s): [%s] !~ [%s]", \ + #actual, #expected, \ + _a ? _a : "(null)", _e ? _e : "(null)"); \ + } while (0) + +#define TEST_ASSERT_STRNCMP_EQ(actual, expected, n) \ + do { \ + const char *_a = (actual); \ + const char *_e = (expected); \ + size_t _n = (size_t)(n); \ + if (_a == NULL || _e == NULL || strncmp(_a, _e, _n) != 0) \ + TEST_FAIL_("TEST_ASSERT_STRNCMP_EQ(%s, %s, %zu): [%s] != [%s]", \ + #actual, #expected, _n, \ + _a ? _a : "(null)", _e ? _e : "(null)"); \ + } while (0) + +#define TEST_ASSERT_STRSTR(haystack, needle) \ + do { \ + const char *_h = (haystack); \ + const char *_n = (needle); \ + if (_h == NULL || _n == NULL || strstr(_h, _n) == NULL) \ + TEST_FAIL_("TEST_ASSERT_STRSTR(%s, %s): [%s] does not contain [%s]", \ + #haystack, #needle, \ + _h ? _h : "(null)", _n ? _n : "(null)"); \ + } while (0) + +#define TEST_ASSERT_EMPTY_STRING(expr) \ + do { \ + const char *_s = (expr); \ + if (_s == NULL) \ + TEST_FAIL_("TEST_ASSERT_EMPTY_STRING(%s) was NULL", #expr); \ + if (_s[0] != '\0') \ + TEST_FAIL_("TEST_ASSERT_EMPTY_STRING(%s) was [%s]", #expr, _s); \ + } while (0) + +#define TEST_RUN(name, fn) \ + do { \ + fprintf(stderr, "%s -> %s:", name, #fn); \ + fn(); \ + fprintf(stderr, " PASS\n"); \ + } while (0) + +static inline pkgconf_client_t * +test_client_new(void) +{ + pkgconf_cross_personality_t *pers = pkgconf_cross_personality_default(); + return pkgconf_client_new(NULL, NULL, pers, NULL, NULL); +} + +#endif // TEST_API_H diff --git a/tests/api/test-audit.c b/tests/api/test-audit.c new file mode 100644 index 000000000000..12f9f31e0dda --- /dev/null +++ b/tests/api/test-audit.c @@ -0,0 +1,171 @@ +/* + * test-audit.c + * Tests for the public libpkgconf audit API. + * + * SPDX-License-Identifier: pkgconf + * + * Copyright (c) 2026 pkgconf authors (see AUTHORS). + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * This software is provided 'as is' and without any warranty, express or + * implied. In no event shall the authors be liable for any damages arising + * from the use of this software. + */ + +#include "test-api.h" + +/* + * Read the entire contents of f (from the start) into buf. + * buf must be large enough; we keep test inputs small. + */ +static void +slurp(FILE *f, char *buf, size_t bufsz) +{ + rewind(f); + size_t n = fread(buf, 1, bufsz - 1, f); + buf[n] = '\0'; +} + +static void +test_audit_log_no_logfile_is_noop(void) +{ + pkgconf_client_t *client = test_client_new(); + + // With no audit log set, logging must be a silent no-op and must not crash. + pkgconf_audit_log(client, "should go nowhere\n"); + + pkgconf_client_free(client); +} + +static void +test_audit_set_log_and_write(void) +{ + pkgconf_client_t *client = test_client_new(); + FILE *logf = tmpfile(); + TEST_ASSERT_NONNULL(logf); + + pkgconf_audit_set_log(client, logf); + pkgconf_audit_log(client, "hello %s\n", "world"); + + char buf[256]; + slurp(logf, buf, sizeof(buf)); + TEST_ASSERT_STRCMP_EQ(buf, "hello world\n"); + + fclose(logf); + pkgconf_client_free(client); +} + +static void +test_audit_log_multiple_writes(void) +{ + pkgconf_client_t *client = test_client_new(); + FILE *logf = tmpfile(); + TEST_ASSERT_NONNULL(logf); + + pkgconf_audit_set_log(client, logf); + pkgconf_audit_log(client, "first\n"); + pkgconf_audit_log(client, "second %d\n", 2); + + char buf[256]; + slurp(logf, buf, sizeof(buf)); + TEST_ASSERT_STRCMP_EQ(buf, "first\nsecond 2\n"); + + fclose(logf); + pkgconf_client_free(client); +} + +static void +test_audit_log_dependency_versionless(void) +{ + pkgconf_client_t *client = test_client_new(); + FILE *logf = tmpfile(); + TEST_ASSERT_NONNULL(logf); + + pkgconf_audit_set_log(client, logf); + + // A minimal package: only the fields the logger reads + pkgconf_pkg_t pkg = { 0 }; + pkg.id = (char *) "foo"; + pkg.version = (char *) "1.2.3"; + + /* A dependency with PKGCONF_CMP_ANY and no version: the logger + * should emit only "id [version]", skipping the comparator */ + pkgconf_dependency_t dep = { 0 }; + dep.compare = PKGCONF_CMP_ANY; + dep.version = NULL; + + pkgconf_audit_log_dependency(client, &pkg, &dep); + + char buf[256]; + slurp(logf, buf, sizeof(buf)); + TEST_ASSERT_STRCMP_EQ(buf, "foo [1.2.3]\n"); + + fclose(logf); + pkgconf_client_free(client); +} + +static void +test_audit_log_dependency_versioned(void) +{ + pkgconf_client_t *client = test_client_new(); + FILE *logf = tmpfile(); + TEST_ASSERT_NONNULL(logf); + + pkgconf_audit_set_log(client, logf); + + pkgconf_pkg_t pkg = { 0 }; + pkg.id = (char *) "bar"; + pkg.version = (char *) "2.0"; + + /* version set AND compare != ANY: the logger emits the + * comparator and required version between id and [version] */ + pkgconf_dependency_t dep = { 0 }; + dep.compare = PKGCONF_CMP_GREATER_THAN_EQUAL; + dep.version = (char *) "1.5"; + + pkgconf_audit_log_dependency(client, &pkg, &dep); + + char buf[256]; + slurp(logf, buf, sizeof(buf)); + TEST_ASSERT_STRCMP_EQ(buf, "bar >= 1.5 [2.0]\n"); + + fclose(logf); + pkgconf_client_free(client); +} + +static void +test_audit_log_dependency_no_logfile_is_noop(void) +{ + pkgconf_client_t *client = test_client_new(); + + pkgconf_pkg_t pkg = { 0 }; + pkg.id = (char *) "foo"; + pkg.version = (char *) "1.0"; + + pkgconf_dependency_t dep = { 0 }; + dep.compare = PKGCONF_CMP_ANY; + + // No log set: must be a silent no-op + pkgconf_audit_log_dependency(client, &pkg, &dep); + + pkgconf_client_free(client); +} + +int +main(int argc, char *argv[]) +{ + (void) argc; + const char *basename = pkgconf_path_find_basename(argv[0]); + + TEST_RUN(basename, test_audit_log_no_logfile_is_noop); + TEST_RUN(basename, test_audit_set_log_and_write); + TEST_RUN(basename, test_audit_log_multiple_writes); + TEST_RUN(basename, test_audit_log_dependency_versionless); + TEST_RUN(basename, test_audit_log_dependency_versioned); + TEST_RUN(basename, test_audit_log_dependency_no_logfile_is_noop); + + return EXIT_SUCCESS; +} diff --git a/tests/api/test-buffer.c b/tests/api/test-buffer.c new file mode 100644 index 000000000000..c17818ba3b4b --- /dev/null +++ b/tests/api/test-buffer.c @@ -0,0 +1,417 @@ +/* + * test-buffer.c + * Tests for libpkgconf buffer API. + * + * SPDX-License-Identifier: pkgconf + * + * Copyright (c) 2025 pkgconf authors (see AUTHORS). + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * This software is provided 'as is' and without any warranty, express or + * implied. In no event shall the authors be liable for any damages arising + * from the use of this software. + */ + +#include <libpkgconf/stdinc.h> +#include <libpkgconf/libpkgconf.h> +#include "test-api.h" + +static void +test_buffer_empty(void) +{ + pkgconf_buffer_t buf = PKGCONF_BUFFER_INITIALIZER; + + TEST_ASSERT_EQ(pkgconf_buffer_len(&buf), 0); + TEST_ASSERT_NULL(pkgconf_buffer_str(&buf)); + TEST_ASSERT_EMPTY_STRING(pkgconf_buffer_str_or_empty(&buf)); + TEST_ASSERT_EQ(pkgconf_buffer_lastc(&buf), '\0'); + + pkgconf_buffer_finalize(&buf); +} + +static void +test_buffer_append(void) +{ + pkgconf_buffer_t buf = PKGCONF_BUFFER_INITIALIZER; + + TEST_ASSERT_TRUE(pkgconf_buffer_append(&buf, "hello")); + TEST_ASSERT_STRCMP_EQ(pkgconf_buffer_str(&buf), "hello"); + TEST_ASSERT_EQ(pkgconf_buffer_len(&buf), 5); + + TEST_ASSERT_TRUE(pkgconf_buffer_append(&buf, " world")); + TEST_ASSERT_STRCMP_EQ(pkgconf_buffer_str(&buf), "hello world"); + TEST_ASSERT_EQ(pkgconf_buffer_len(&buf), 11); + + TEST_ASSERT_EQ(pkgconf_buffer_lastc(&buf), 'd'); + + pkgconf_buffer_finalize(&buf); +} + +static void +test_buffer_append_slice(void) +{ + pkgconf_buffer_t buf = PKGCONF_BUFFER_INITIALIZER; + + TEST_ASSERT_TRUE(pkgconf_buffer_append_slice(&buf, "abcdefgh", 3)); + TEST_ASSERT_STRCMP_EQ(pkgconf_buffer_str(&buf), "abc"); + + TEST_ASSERT_TRUE(pkgconf_buffer_append_slice(&buf, "xyz", 0)); + TEST_ASSERT_STRCMP_EQ(pkgconf_buffer_str(&buf), "abc"); + + pkgconf_buffer_finalize(&buf); +} + +static void +test_buffer_append_fmt(void) +{ + pkgconf_buffer_t buf = PKGCONF_BUFFER_INITIALIZER; + + TEST_ASSERT_TRUE(pkgconf_buffer_append_fmt(&buf, "%s=%d", "x", 42)); + TEST_ASSERT_STRCMP_EQ(pkgconf_buffer_str(&buf), "x=42"); + + TEST_ASSERT_TRUE(pkgconf_buffer_append_fmt(&buf, " %s", "ok")); + TEST_ASSERT_STRCMP_EQ(pkgconf_buffer_str(&buf), "x=42 ok"); + + pkgconf_buffer_finalize(&buf); +} + +static void +test_buffer_prepend(void) +{ + pkgconf_buffer_t buf = PKGCONF_BUFFER_INITIALIZER; + + pkgconf_buffer_append(&buf, "world"); + TEST_ASSERT_TRUE(pkgconf_buffer_prepend(&buf, "hello ")); + TEST_ASSERT_STRCMP_EQ(pkgconf_buffer_str(&buf), "hello world"); + + pkgconf_buffer_finalize(&buf); +} + +static void +test_buffer_push_byte(void) +{ + pkgconf_buffer_t buf = PKGCONF_BUFFER_INITIALIZER; + + TEST_ASSERT_TRUE(pkgconf_buffer_push_byte(&buf, 'a')); + TEST_ASSERT_TRUE(pkgconf_buffer_push_byte(&buf, 'b')); + TEST_ASSERT_TRUE(pkgconf_buffer_push_byte(&buf, 'c')); + TEST_ASSERT_STRCMP_EQ(pkgconf_buffer_str(&buf), "abc"); + TEST_ASSERT_EQ(pkgconf_buffer_len(&buf), 3); + + pkgconf_buffer_finalize(&buf); +} + +static void +test_buffer_trim_byte(void) +{ + pkgconf_buffer_t buf = PKGCONF_BUFFER_INITIALIZER; + + pkgconf_buffer_append(&buf, "hello\n"); + TEST_ASSERT_TRUE(pkgconf_buffer_trim_byte(&buf)); + TEST_ASSERT_STRCMP_EQ(pkgconf_buffer_str(&buf), "hello"); + + pkgconf_buffer_reset(&buf); + pkgconf_buffer_push_byte(&buf, 'x'); + TEST_ASSERT_TRUE(pkgconf_buffer_trim_byte(&buf)); + TEST_ASSERT_EQ(pkgconf_buffer_len(&buf), 0); + TEST_ASSERT_FALSE(pkgconf_buffer_trim_byte(&buf)); + + pkgconf_buffer_finalize(&buf); +} + +static void +test_buffer_reset(void) +{ + pkgconf_buffer_t buf = PKGCONF_BUFFER_INITIALIZER; + + pkgconf_buffer_append(&buf, "some content"); + TEST_ASSERT_NE(pkgconf_buffer_len(&buf), 0); + + pkgconf_buffer_reset(&buf); + TEST_ASSERT_EQ(pkgconf_buffer_len(&buf), 0); + TEST_ASSERT_NULL(pkgconf_buffer_str(&buf)); + + TEST_ASSERT_TRUE(pkgconf_buffer_append(&buf, "fresh")); + TEST_ASSERT_STRCMP_EQ(pkgconf_buffer_str(&buf), "fresh"); + + pkgconf_buffer_finalize(&buf); +} + +static void +test_buffer_freeze(void) +{ + pkgconf_buffer_t buf = PKGCONF_BUFFER_INITIALIZER; + + pkgconf_buffer_append(&buf, "frozen"); + char *out = pkgconf_buffer_freeze(&buf); + TEST_ASSERT_NONNULL(out); + TEST_ASSERT_STRCMP_EQ(out, "frozen"); + TEST_ASSERT_EQ(pkgconf_buffer_len(&buf), 0); + + TEST_ASSERT_NULL(pkgconf_buffer_freeze(&buf)); + + free(out); + pkgconf_buffer_finalize(&buf); +} + +static void +test_buffer_copy(void) +{ + pkgconf_buffer_t src = PKGCONF_BUFFER_INITIALIZER; + pkgconf_buffer_t dst = PKGCONF_BUFFER_INITIALIZER; + + pkgconf_buffer_append(&src, "original"); + pkgconf_buffer_append(&dst, "to be replaced"); + TEST_ASSERT_TRUE(pkgconf_buffer_copy(&src, &dst)); + TEST_ASSERT_STRCMP_EQ(pkgconf_buffer_str(&dst), "original"); + TEST_ASSERT_STRCMP_EQ(pkgconf_buffer_str(&src), "original"); // src is unchanged + + pkgconf_buffer_finalize(&src); + pkgconf_buffer_finalize(&dst); +} + +static void +test_buffer_join(void) +{ + pkgconf_buffer_t buf = PKGCONF_BUFFER_INITIALIZER; + + TEST_ASSERT_TRUE(pkgconf_buffer_join(&buf, '/', "usr", "local", "lib", NULL)); + TEST_ASSERT_STRCMP_EQ(pkgconf_buffer_str(&buf), "usr/local/lib"); + + pkgconf_buffer_finalize(&buf); +} + +static void +test_buffer_contains(void) +{ + pkgconf_buffer_t hay = PKGCONF_BUFFER_INITIALIZER; + pkgconf_buffer_t needle = PKGCONF_BUFFER_INITIALIZER; + + pkgconf_buffer_append(&hay, "the quick brown fox"); + + pkgconf_buffer_append(&needle, "quick"); + TEST_ASSERT_TRUE(pkgconf_buffer_contains(&hay, &needle)); + + pkgconf_buffer_reset(&needle); + pkgconf_buffer_append(&needle, "slow"); + TEST_ASSERT_FALSE(pkgconf_buffer_contains(&hay, &needle)); + + TEST_ASSERT_TRUE(pkgconf_buffer_contains_byte(&hay, 'q')); + TEST_ASSERT_FALSE(pkgconf_buffer_contains_byte(&hay, 'z')); + + pkgconf_buffer_finalize(&hay); + pkgconf_buffer_finalize(&needle); +} + +static void +test_buffer_match(void) +{ + pkgconf_buffer_t a = PKGCONF_BUFFER_INITIALIZER; + pkgconf_buffer_t b = PKGCONF_BUFFER_INITIALIZER; + + pkgconf_buffer_append(&a, "identical"); + pkgconf_buffer_append(&b, "identical"); + TEST_ASSERT_TRUE(pkgconf_buffer_match(&a, &b)); + + // Identical length, but different contents + pkgconf_buffer_reset(&b); + pkgconf_buffer_append(&b, "different"); + TEST_ASSERT_FALSE(pkgconf_buffer_match(&a, &b)); + + // Different length and contents + pkgconf_buffer_reset(&b); + pkgconf_buffer_append(&b, "different!"); + TEST_ASSERT_FALSE(pkgconf_buffer_match(&a, &b)); + + pkgconf_buffer_finalize(&a); + pkgconf_buffer_finalize(&b); +} + +static void +test_buffer_has_prefix(void) +{ + pkgconf_buffer_t hay = PKGCONF_BUFFER_INITIALIZER; + pkgconf_buffer_t pre = PKGCONF_BUFFER_INITIALIZER; + + pkgconf_buffer_append(&hay, "/usr/local/lib"); + + pkgconf_buffer_append(&pre, "/usr"); + TEST_ASSERT_TRUE(pkgconf_buffer_has_prefix(&hay, &pre)); + + pkgconf_buffer_reset(&pre); + pkgconf_buffer_append(&pre, "/opt"); + TEST_ASSERT_FALSE(pkgconf_buffer_has_prefix(&hay, &pre)); + + pkgconf_buffer_finalize(&hay); + pkgconf_buffer_finalize(&pre); +} + +static void +test_buffer_subst(void) +{ + pkgconf_buffer_t src = PKGCONF_BUFFER_INITIALIZER; + pkgconf_buffer_t dst = PKGCONF_BUFFER_INITIALIZER; + + pkgconf_buffer_append(&src, "prefix=${PREFIX}/share"); + TEST_ASSERT_TRUE(pkgconf_buffer_subst(&dst, &src, "${PREFIX}", "/opt/foo")); + TEST_ASSERT_STRCMP_EQ(pkgconf_buffer_str(&dst), "prefix=/opt/foo/share"); + + pkgconf_buffer_finalize(&src); + pkgconf_buffer_finalize(&dst); +} + +static void +test_buffer_subst_empty_pattern(void) +{ + pkgconf_buffer_t src = PKGCONF_BUFFER_INITIALIZER; + pkgconf_buffer_t dst0 = PKGCONF_BUFFER_INITIALIZER; + pkgconf_buffer_t dst1 = PKGCONF_BUFFER_INITIALIZER; + pkgconf_buffer_t dst2 = PKGCONF_BUFFER_INITIALIZER; + pkgconf_buffer_t dst3 = PKGCONF_BUFFER_INITIALIZER; + pkgconf_buffer_t dst4 = PKGCONF_BUFFER_INITIALIZER; + pkgconf_buffer_t dst5 = PKGCONF_BUFFER_INITIALIZER; + + pkgconf_buffer_append(&src, "prefix=${PREFIX}/share"); + + TEST_ASSERT_TRUE(pkgconf_buffer_subst(&dst0, &src, "", "foo")); + TEST_ASSERT_TRUE(pkgconf_buffer_subst(&dst1, &src, "", "")); + TEST_ASSERT_TRUE(pkgconf_buffer_subst(&dst2, &src, "", NULL)); + TEST_ASSERT_TRUE(pkgconf_buffer_subst(&dst3, &src, NULL, "foo")); + TEST_ASSERT_TRUE(pkgconf_buffer_subst(&dst4, &src, NULL, "")); + TEST_ASSERT_TRUE(pkgconf_buffer_subst(&dst5, &src, NULL, NULL)); + + TEST_ASSERT_STRCMP_EQ(pkgconf_buffer_str(&dst0), "prefix=${PREFIX}/share"); + TEST_ASSERT_STRCMP_EQ(pkgconf_buffer_str(&dst1), "prefix=${PREFIX}/share"); + TEST_ASSERT_STRCMP_EQ(pkgconf_buffer_str(&dst2), "prefix=${PREFIX}/share"); + TEST_ASSERT_STRCMP_EQ(pkgconf_buffer_str(&dst3), "prefix=${PREFIX}/share"); + TEST_ASSERT_STRCMP_EQ(pkgconf_buffer_str(&dst4), "prefix=${PREFIX}/share"); + TEST_ASSERT_STRCMP_EQ(pkgconf_buffer_str(&dst5), "prefix=${PREFIX}/share"); + + pkgconf_buffer_finalize(&src); + pkgconf_buffer_finalize(&dst0); + pkgconf_buffer_finalize(&dst1); + pkgconf_buffer_finalize(&dst2); + pkgconf_buffer_finalize(&dst3); + pkgconf_buffer_finalize(&dst4); + pkgconf_buffer_finalize(&dst5); +} + +static void +test_buffer_escape(void) +{ + pkgconf_buffer_t src = PKGCONF_BUFFER_INITIALIZER; + pkgconf_buffer_t dst = PKGCONF_BUFFER_INITIALIZER; + + pkgconf_span_t spans[] = { + { ' ', ' ' }, + { '\t', '\t' }, + }; + + pkgconf_buffer_append(&src, "a b\tc"); + TEST_ASSERT_TRUE(pkgconf_buffer_escape(&dst, &src, spans, PKGCONF_ARRAY_SIZE(spans))); + TEST_ASSERT_STRCMP_EQ(pkgconf_buffer_str(&dst), "a\\ b\\\tc"); + + pkgconf_buffer_finalize(&src); + pkgconf_buffer_finalize(&dst); +} + +static void +test_str_eq_slice(void) +{ + TEST_ASSERT_TRUE(pkgconf_str_eq_slice("hello", "hello", 5)); + TEST_ASSERT_FALSE(pkgconf_str_eq_slice("hello!", "hello", 5)); + TEST_ASSERT_FALSE(pkgconf_str_eq_slice("hello", "world", 5)); + TEST_ASSERT_FALSE(pkgconf_str_eq_slice(NULL, "hello", 5)); +} + +static void +test_span_contains(void) +{ + pkgconf_span_t spans[] = { + { '0', '9' }, + { 'a', 'z' }, + }; + + TEST_ASSERT_TRUE(pkgconf_span_contains('5', spans, PKGCONF_ARRAY_SIZE(spans))); + TEST_ASSERT_TRUE(pkgconf_span_contains('m', spans, PKGCONF_ARRAY_SIZE(spans))); + TEST_ASSERT_FALSE(pkgconf_span_contains('A', spans, PKGCONF_ARRAY_SIZE(spans))); + TEST_ASSERT_FALSE(pkgconf_span_contains('!', spans, PKGCONF_ARRAY_SIZE(spans))); +} + +static void +test_buffer_fputs_nonempty(void) +{ + pkgconf_buffer_t buf = PKGCONF_BUFFER_INITIALIZER; + FILE *f = tmpfile(); + TEST_ASSERT_NONNULL(f); + + pkgconf_buffer_append(&buf, "hello world"); + TEST_ASSERT_TRUE(pkgconf_buffer_fputs(&buf, f)); + + char out[64]; + rewind(f); + size_t n = fread(out, 1, sizeof(out) - 1, f); + out[n] = '\0'; + + // Buffer contents followed by a newline. + TEST_ASSERT_STRCMP_EQ(out, "hello world\n"); + + fclose(f); + pkgconf_buffer_finalize(&buf); +} + +static void +test_buffer_fputs_empty(void) +{ + pkgconf_buffer_t buf = PKGCONF_BUFFER_INITIALIZER; + FILE *f = tmpfile(); + TEST_ASSERT_NONNULL(f); + + // An empty buffer writes only a newline. + TEST_ASSERT_TRUE(pkgconf_buffer_fputs(&buf, f)); + + char out[64]; + rewind(f); + size_t n = fread(out, 1, sizeof(out) - 1, f); + out[n] = '\0'; + + TEST_ASSERT_STRCMP_EQ(out, "\n"); + + fclose(f); + pkgconf_buffer_finalize(&buf); +} + +int +main(int argc, const char **argv) +{ + (void) argc; + + const char *basename = pkgconf_path_find_basename(argv[0]); + + TEST_RUN(basename, test_buffer_empty); + TEST_RUN(basename, test_buffer_append); + TEST_RUN(basename, test_buffer_append_slice); + TEST_RUN(basename, test_buffer_append_fmt); + TEST_RUN(basename, test_buffer_prepend); + TEST_RUN(basename, test_buffer_push_byte); + TEST_RUN(basename, test_buffer_trim_byte); + TEST_RUN(basename, test_buffer_reset); + TEST_RUN(basename, test_buffer_freeze); + TEST_RUN(basename, test_buffer_copy); + TEST_RUN(basename, test_buffer_join); + TEST_RUN(basename, test_buffer_contains); + TEST_RUN(basename, test_buffer_match); + TEST_RUN(basename, test_buffer_has_prefix); + TEST_RUN(basename, test_buffer_subst); + TEST_RUN(basename, test_buffer_subst_empty_pattern); + TEST_RUN(basename, test_buffer_escape); + TEST_RUN(basename, test_str_eq_slice); + TEST_RUN(basename, test_span_contains); + TEST_RUN(basename, test_buffer_fputs_nonempty); + TEST_RUN(basename, test_buffer_fputs_empty); + + return EXIT_SUCCESS; +} diff --git a/tests/api/test-bytecode.c b/tests/api/test-bytecode.c new file mode 100644 index 000000000000..7be48941eed9 --- /dev/null +++ b/tests/api/test-bytecode.c @@ -0,0 +1,643 @@ +/* + * test-bytecode.c + * Tests for the public libpkgconf bytecode API: + * pkgconf_bytecode_compile and pkgconf_bytecode_eval_str. + * + * SPDX-License-Identifier: pkgconf + * + * Copyright (c) 2025 pkgconf authors (see AUTHORS). + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * This software is provided 'as is' and without any warranty, express or + * implied. In no event shall the authors be liable for any damages arising + * from the use of this software. + */ + +#include <libpkgconf/stdinc.h> +#include <libpkgconf/libpkgconf.h> +#include "test-api.h" + +/* + * Build a variable list with the given key/value pairs. Caller frees + * with pkgconf_variable_list_free(). + * + * The key/value pairs are stored by compiling `value` as bytecode and + * stashing the result on a pkgconf_variable_t inside the list, which + * is how the parser builds variable scopes for real .pc files. + */ +static void +seed_variable(pkgconf_list_t *vars, const char *key, const char *value) +{ + pkgconf_variable_t *v = pkgconf_variable_get_or_create(vars, key); + TEST_ASSERT_NONNULL(v); + + pkgconf_buffer_reset(&v->bcbuf); + pkgconf_bytecode_compile(&v->bcbuf, value); + pkgconf_bytecode_from_buffer(&v->bc, &v->bcbuf); +} + +static void +test_emit_text_and_eval(void) +{ + pkgconf_client_t *client = test_client_new(); + pkgconf_list_t vars = PKGCONF_LIST_INITIALIZER; + pkgconf_buffer_t bcbuf = PKGCONF_BUFFER_INITIALIZER; + pkgconf_bytecode_t bc; + bool saw_sysroot = false; + + TEST_ASSERT_TRUE(pkgconf_bytecode_emit_text(&bcbuf, "plain", 5)); + pkgconf_bytecode_from_buffer(&bc, &bcbuf); + + pkgconf_buffer_t out = PKGCONF_BUFFER_INITIALIZER; + TEST_ASSERT_TRUE(pkgconf_bytecode_eval(client, &vars, &bc, &out, &saw_sysroot)); + TEST_ASSERT_STRCMP_EQ(pkgconf_buffer_str_or_empty(&out), "plain"); + + pkgconf_buffer_finalize(&out); + pkgconf_buffer_finalize(&bcbuf); + pkgconf_variable_list_free(&vars); + pkgconf_client_free(client); +} + +static void +test_emit_guards(void) +{ + pkgconf_buffer_t bcbuf = PKGCONF_BUFFER_INITIALIZER; + + TEST_ASSERT_TRUE(pkgconf_bytecode_emit_text(&bcbuf, NULL, 5)); + TEST_ASSERT_TRUE(pkgconf_bytecode_emit_text(&bcbuf, "x", 0)); + TEST_ASSERT_TRUE(pkgconf_bytecode_emit_var(&bcbuf, NULL, 3)); + TEST_ASSERT_TRUE(pkgconf_bytecode_emit_var(&bcbuf, "x", 0)); + + TEST_ASSERT_EQ(pkgconf_buffer_len(&bcbuf), 0); + + pkgconf_buffer_finalize(&bcbuf); +} + +static void +test_emit_var_and_eval(void) +{ + pkgconf_client_t *client = test_client_new(); + pkgconf_list_t vars = PKGCONF_LIST_INITIALIZER; + pkgconf_buffer_t bcbuf = PKGCONF_BUFFER_INITIALIZER; + pkgconf_bytecode_t bc; + bool saw_sysroot = false; + + seed_variable(&vars, "name", "world"); + + TEST_ASSERT_TRUE(pkgconf_bytecode_emit_text(&bcbuf, "hello ", 6)); + TEST_ASSERT_TRUE(pkgconf_bytecode_emit_var(&bcbuf, "name", 4)); + pkgconf_bytecode_from_buffer(&bc, &bcbuf); + + pkgconf_buffer_t out = PKGCONF_BUFFER_INITIALIZER; + TEST_ASSERT_TRUE(pkgconf_bytecode_eval(client, &vars, &bc, &out, &saw_sysroot)); + TEST_ASSERT_STRCMP_EQ(pkgconf_buffer_str_or_empty(&out), "hello world"); + + pkgconf_buffer_finalize(&out); + pkgconf_buffer_finalize(&bcbuf); + pkgconf_variable_list_free(&vars); + pkgconf_client_free(client); +} + +static void +test_emit_sysroot_and_eval(void) +{ + pkgconf_client_t *client = test_client_new(); + pkgconf_list_t vars = PKGCONF_LIST_INITIALIZER; + pkgconf_buffer_t bcbuf = PKGCONF_BUFFER_INITIALIZER; + pkgconf_bytecode_t bc; + bool saw_sysroot = false; + + pkgconf_client_set_sysroot_dir(client, "/sysroot"); + + TEST_ASSERT_TRUE(pkgconf_bytecode_emit_sysroot(&bcbuf)); + TEST_ASSERT_TRUE(pkgconf_bytecode_emit_text(&bcbuf, "/usr/include", 12)); + pkgconf_bytecode_from_buffer(&bc, &bcbuf); + + pkgconf_buffer_t out = PKGCONF_BUFFER_INITIALIZER; + TEST_ASSERT_TRUE(pkgconf_bytecode_eval(client, &vars, &bc, &out, &saw_sysroot)); + TEST_ASSERT_TRUE(saw_sysroot); + TEST_ASSERT_STRCMP_EQ(pkgconf_buffer_str_or_empty(&out), "/sysroot/usr/include"); + + pkgconf_buffer_finalize(&out); + pkgconf_buffer_finalize(&bcbuf); + pkgconf_variable_list_free(&vars); + pkgconf_client_free(client); +} + +static void +test_eval_null_args(void) +{ + pkgconf_client_t *client = test_client_new(); + pkgconf_list_t vars = PKGCONF_LIST_INITIALIZER; + pkgconf_buffer_t out = PKGCONF_BUFFER_INITIALIZER; + pkgconf_bytecode_t bc = { NULL, 0 }; + + // NULL client, bc, or out all return false. + TEST_ASSERT_FALSE(pkgconf_bytecode_eval(NULL, &vars, &bc, &out, NULL)); + TEST_ASSERT_FALSE(pkgconf_bytecode_eval(client, &vars, NULL, &out, NULL)); + TEST_ASSERT_FALSE(pkgconf_bytecode_eval(client, &vars, &bc, NULL, NULL)); + + pkgconf_buffer_finalize(&out); + pkgconf_variable_list_free(&vars); + pkgconf_client_free(client); +} + +static void +test_compile_null_args(void) +{ + pkgconf_buffer_t out = PKGCONF_BUFFER_INITIALIZER; + + TEST_ASSERT_FALSE(pkgconf_bytecode_compile(NULL, "x")); + TEST_ASSERT_FALSE(pkgconf_bytecode_compile(&out, NULL)); + + pkgconf_buffer_finalize(&out); +} + +static void +test_dollar_escape(void) +{ + pkgconf_client_t *client = test_client_new(); + pkgconf_list_t vars = PKGCONF_LIST_INITIALIZER; + bool saw_sysroot = false; + + // $$ collapses to a literal $; the following text is NOT treated as a variable reference + char *out = pkgconf_bytecode_eval_str(client, &vars, "price: $$5 and $${notavar}", &saw_sysroot); + TEST_ASSERT_NONNULL(out); + TEST_ASSERT_STRCMP_EQ(out, "price: $5 and ${notavar}"); + + free(out); + pkgconf_variable_list_free(&vars); + pkgconf_client_free(client); +} + +static void +test_malformed_unclosed(void) +{ + pkgconf_client_t *client = test_client_new(); + pkgconf_list_t vars = PKGCONF_LIST_INITIALIZER; + bool saw_sysroot = false; + + // A ${ with no closing } is emitted as literal text + char *out = pkgconf_bytecode_eval_str(client, &vars, "broken ${unclosed", &saw_sysroot); + TEST_ASSERT_NONNULL(out); + TEST_ASSERT_STRCMP_EQ(out, "broken ${unclosed"); + + free(out); + pkgconf_variable_list_free(&vars); + pkgconf_client_free(client); +} + +static void +test_empty_braces(void) +{ + pkgconf_client_t *client = test_client_new(); + pkgconf_list_t vars = PKGCONF_LIST_INITIALIZER; + bool saw_sysroot = false; + + // ${} has a zero-length name; it's emitted as literal text rather than treated as a variable + char *out = pkgconf_bytecode_eval_str(client, &vars, "empty ${} here", &saw_sysroot); + TEST_ASSERT_NONNULL(out); + TEST_ASSERT_STRCMP_EQ(out, "empty ${} here"); + + free(out); + pkgconf_variable_list_free(&vars); + pkgconf_client_free(client); +} + +static void +test_compile_time_sysroot(void) +{ + pkgconf_client_t *client = test_client_new(); + pkgconf_list_t vars = PKGCONF_LIST_INITIALIZER; + bool saw_sysroot = false; + + pkgconf_client_set_sysroot_dir(client, "/sysroot"); + + // ${pc_sysrootdir} is special-cased at compile time into an OP_SYSROOT op rather than a variable lookup + char *out = pkgconf_bytecode_eval_str(client, &vars, "${pc_sysrootdir}/usr/lib", &saw_sysroot); + TEST_ASSERT_NONNULL(out); + TEST_ASSERT_TRUE(saw_sysroot); + TEST_ASSERT_STRCMP_EQ(out, "/sysroot/usr/lib"); + + free(out); + pkgconf_variable_list_free(&vars); + pkgconf_client_free(client); +} + +static void +test_sysroot_dot_disables(void) +{ + pkgconf_client_t *client = test_client_new(); + pkgconf_list_t vars = PKGCONF_LIST_INITIALIZER; + bool saw_sysroot = false; + + // A sysroot of "." disables sysroot rewriting: ${pc_sysrootdir} expands to empty + pkgconf_client_set_sysroot_dir(client, "."); + + char *out = pkgconf_bytecode_eval_str(client, &vars, "${pc_sysrootdir}/usr/lib", &saw_sysroot); + TEST_ASSERT_NONNULL(out); + TEST_ASSERT_STRCMP_EQ(out, "/usr/lib"); + + free(out); + pkgconf_variable_list_free(&vars); + pkgconf_client_free(client); +} + +static void +test_sysroot_root_disables(void) +{ + pkgconf_client_t *client = test_client_new(); + pkgconf_list_t vars = PKGCONF_LIST_INITIALIZER; + bool saw_sysroot = false; + + // A sysroot of "/" (the root dir) disables rewriting. + pkgconf_client_set_sysroot_dir(client, "/"); + + char *out = pkgconf_bytecode_eval_str(client, &vars, "${pc_sysrootdir}/usr/lib", &saw_sysroot); + TEST_ASSERT_NONNULL(out); + TEST_ASSERT_STRCMP_EQ(out, "/usr/lib"); + + free(out); + pkgconf_variable_list_free(&vars); + pkgconf_client_free(client); +} + +static void +test_sysroot_trailing_slash_trimmed(void) +{ + pkgconf_client_t *client = test_client_new(); + pkgconf_list_t vars = PKGCONF_LIST_INITIALIZER; + bool saw_sysroot = false; + + // Trailing slashes on the sysroot are normalized away, so the result doesn't get a doubled slash + pkgconf_client_set_sysroot_dir(client, "/sysroot///"); + + char *out = pkgconf_bytecode_eval_str(client, &vars, "${pc_sysrootdir}/usr/lib", &saw_sysroot); + TEST_ASSERT_NONNULL(out); + TEST_ASSERT_TRUE(saw_sysroot); + TEST_ASSERT_STRCMP_EQ(out, "/sysroot/usr/lib"); + + free(out); + pkgconf_variable_list_free(&vars); + pkgconf_client_free(client); +} + +static void +test_sysroot_normalizes_to_root_disables(void) +{ + pkgconf_client_t *client = test_client_new(); + pkgconf_list_t vars = PKGCONF_LIST_INITIALIZER; + bool saw_sysroot = false; + + /* A sysroot of "//" survives the bare-"/" early check but normalizes down to "/" after + * trailing-slash trimming, which then disables rewriting (empty sysroot) */ + pkgconf_client_set_sysroot_dir(client, "//"); + + char *out = pkgconf_bytecode_eval_str(client, &vars, "${pc_sysrootdir}/usr/lib", &saw_sysroot); + TEST_ASSERT_NONNULL(out); + TEST_ASSERT_STRCMP_EQ(out, "/usr/lib"); + + free(out); + pkgconf_variable_list_free(&vars); + pkgconf_client_free(client); +} + +static void +test_circular_reference(void) +{ + pkgconf_client_t *client = test_client_new(); + pkgconf_list_t vars = PKGCONF_LIST_INITIALIZER; + bool saw_sysroot = false; + + // A variable that references itself must not infinite-loop: the `expanding` guard breaks the cycle + seed_variable(&vars, "loop", "${loop}"); + + char *out = pkgconf_bytecode_eval_str(client, &vars, "${loop}", &saw_sysroot); + + /* The self-reference is broken; behavior is "expands to nothing further" + * We mostly care that it returns rather than hanging or crashing */ + if (out != NULL) + free(out); + + pkgconf_variable_list_free(&vars); + pkgconf_client_free(client); +} + +static void +test_references_var(void) +{ + pkgconf_buffer_t bcbuf = PKGCONF_BUFFER_INITIALIZER; + + pkgconf_bytecode_compile(&bcbuf, "-I${includedir} -L${libdir}"); + + TEST_ASSERT_TRUE(pkgconf_bytecode_references_var(&bcbuf, "includedir")); + TEST_ASSERT_TRUE(pkgconf_bytecode_references_var(&bcbuf, "libdir")); + TEST_ASSERT_FALSE(pkgconf_bytecode_references_var(&bcbuf, "prefix")); + + TEST_ASSERT_FALSE(pkgconf_bytecode_references_var(NULL, "x")); + TEST_ASSERT_FALSE(pkgconf_bytecode_references_var(&bcbuf, NULL)); + + pkgconf_buffer_finalize(&bcbuf); +} + +static void +test_references_var_text_only(void) +{ + pkgconf_buffer_t bcbuf = PKGCONF_BUFFER_INITIALIZER; + + pkgconf_bytecode_compile(&bcbuf, "just plain text"); + + TEST_ASSERT_FALSE(pkgconf_bytecode_references_var(&bcbuf, "anything")); + + pkgconf_buffer_finalize(&bcbuf); +} + +static void +test_rewrite_selfrefs(void) +{ + pkgconf_client_t *client = test_client_new(); + pkgconf_list_t vars = PKGCONF_LIST_INITIALIZER; + bool saw_sysroot = false; + + pkgconf_buffer_t prev = PKGCONF_BUFFER_INITIALIZER; + pkgconf_bytecode_compile(&prev, "old"); + + pkgconf_buffer_t rhs = PKGCONF_BUFFER_INITIALIZER; + pkgconf_bytecode_compile(&rhs, "${foo} new"); + + pkgconf_buffer_t rewritten = PKGCONF_BUFFER_INITIALIZER; + TEST_ASSERT_TRUE(pkgconf_bytecode_rewrite_selfrefs(&rewritten, &rhs, "foo", &prev)); + + pkgconf_bytecode_t bc; + pkgconf_bytecode_from_buffer(&bc, &rewritten); + + pkgconf_buffer_t out = PKGCONF_BUFFER_INITIALIZER; + TEST_ASSERT_TRUE(pkgconf_bytecode_eval(client, &vars, &bc, &out, &saw_sysroot)); + TEST_ASSERT_STRCMP_EQ(pkgconf_buffer_str_or_empty(&out), "old new"); + + pkgconf_buffer_finalize(&out); + pkgconf_buffer_finalize(&rewritten); + pkgconf_buffer_finalize(&rhs); + pkgconf_buffer_finalize(&prev); + pkgconf_variable_list_free(&vars); + pkgconf_client_free(client); +} + +static void +test_rewrite_selfrefs_no_match(void) +{ + pkgconf_client_t *client = test_client_new(); + pkgconf_list_t vars = PKGCONF_LIST_INITIALIZER; + bool saw_sysroot = false; + + pkgconf_buffer_t prev = PKGCONF_BUFFER_INITIALIZER; + pkgconf_bytecode_compile(&prev, "PREV"); + + pkgconf_buffer_t rhs = PKGCONF_BUFFER_INITIALIZER; + pkgconf_bytecode_compile(&rhs, "${other} tail"); + + pkgconf_buffer_t rewritten = PKGCONF_BUFFER_INITIALIZER; + TEST_ASSERT_TRUE(pkgconf_bytecode_rewrite_selfrefs(&rewritten, &rhs, "foo", &prev)); + + // ${other} survives; seed it so eval can resolve it + seed_variable(&vars, "other", "OTHER"); + + pkgconf_bytecode_t bc; + pkgconf_bytecode_from_buffer(&bc, &rewritten); + + pkgconf_buffer_t out = PKGCONF_BUFFER_INITIALIZER; + TEST_ASSERT_TRUE(pkgconf_bytecode_eval(client, &vars, &bc, &out, &saw_sysroot)); + TEST_ASSERT_STRCMP_EQ(pkgconf_buffer_str_or_empty(&out), "OTHER tail"); + + pkgconf_buffer_finalize(&out); + pkgconf_buffer_finalize(&rewritten); + pkgconf_buffer_finalize(&rhs); + pkgconf_buffer_finalize(&prev); + pkgconf_variable_list_free(&vars); + pkgconf_client_free(client); +} + +static void +test_eval_plain_text(void) +{ + pkgconf_client_t *client = test_client_new(); + pkgconf_list_t vars = PKGCONF_LIST_INITIALIZER; + bool saw_sysroot = false; + + // A string with no variable references should round-trip unchanged. + char *out = pkgconf_bytecode_eval_str(client, &vars, "plain text value", &saw_sysroot); + + TEST_ASSERT_NONNULL(out); + TEST_ASSERT_STRCMP_EQ(out, "plain text value"); + TEST_ASSERT_FALSE(saw_sysroot); + + free(out); + pkgconf_variable_list_free(&vars); + pkgconf_client_free(client); +} + +static void +test_eval_variable_substitution(void) +{ + pkgconf_client_t *client = test_client_new(); + pkgconf_list_t vars = PKGCONF_LIST_INITIALIZER; + bool saw_sysroot = false; + + seed_variable(&vars, "prefix", "/opt/foo"); + + char *out = pkgconf_bytecode_eval_str(client, &vars, "${prefix}/lib", &saw_sysroot); + + TEST_ASSERT_NONNULL(out); + TEST_ASSERT_STRCMP_EQ(out, "/opt/foo/lib"); + TEST_ASSERT_FALSE(saw_sysroot); + + free(out); + pkgconf_variable_list_free(&vars); + pkgconf_client_free(client); +} + +static void +test_eval_nested_variables(void) +{ + pkgconf_client_t *client = test_client_new(); + pkgconf_list_t vars = PKGCONF_LIST_INITIALIZER; + bool saw_sysroot = false; + + // Recursive expansion: libdir references prefix. + seed_variable(&vars, "prefix", "/usr/local"); + seed_variable(&vars, "libdir", "${prefix}/lib"); + + char *out = pkgconf_bytecode_eval_str(client, &vars, "-L${libdir}", &saw_sysroot); + + TEST_ASSERT_NONNULL(out); + TEST_ASSERT_STRCMP_EQ(out, "-L/usr/local/lib"); + + free(out); + pkgconf_variable_list_free(&vars); + pkgconf_client_free(client); +} + +static void +test_eval_undefined_variable(void) +{ + pkgconf_client_t *client = test_client_new(); + pkgconf_list_t vars = PKGCONF_LIST_INITIALIZER; + bool saw_sysroot = false; + + // Referencing an undefined variable should produce empty substitution, not failure + char *out = pkgconf_bytecode_eval_str(client, &vars, "prefix=${nonexistent}/end", &saw_sysroot); + + TEST_ASSERT_NONNULL(out); + TEST_ASSERT_STRCMP_EQ(out, "prefix=/end"); + + free(out); + pkgconf_variable_list_free(&vars); + pkgconf_client_free(client); +} + +static void +test_eval_multiple_variables(void) +{ + pkgconf_client_t *client = test_client_new(); + pkgconf_list_t vars = PKGCONF_LIST_INITIALIZER; + bool saw_sysroot = false; + + seed_variable(&vars, "prefix", "/usr"); + seed_variable(&vars, "exec_prefix", "/usr/local"); + + char *out = pkgconf_bytecode_eval_str(client, &vars, "-I${prefix}/include -L${exec_prefix}/lib", &saw_sysroot); + + TEST_ASSERT_NONNULL(out); + TEST_ASSERT_STRCMP_EQ(out, "-I/usr/include -L/usr/local/lib"); + + free(out); + pkgconf_variable_list_free(&vars); + pkgconf_client_free(client); +} + +static void +test_eval_empty_input(void) +{ + pkgconf_client_t *client = test_client_new(); + pkgconf_list_t vars = PKGCONF_LIST_INITIALIZER; + bool saw_sysroot = false; + + char *out = pkgconf_bytecode_eval_str(client, &vars, "", &saw_sysroot); + + // An empty input may evaluate to either NULL or an empty string + if (out != NULL) + { + TEST_ASSERT_STRCMP_EQ(out, ""); + free(out); + } + + pkgconf_variable_list_free(&vars); + pkgconf_client_free(client); +} + +static void +test_eval_sysroot_detection(void) +{ + pkgconf_client_t *client = test_client_new(); + pkgconf_list_t vars = PKGCONF_LIST_INITIALIZER; + bool saw_sysroot = false; + + pkgconf_client_set_sysroot_dir(client, "/sysroot"); + + seed_variable(&vars, "pc_sysrootdir", "/sysroot"); + seed_variable(&vars, "includedir", "${pc_sysrootdir}/usr/include"); + + char *out = pkgconf_bytecode_eval_str(client, &vars, "${includedir}", &saw_sysroot); + + TEST_ASSERT_NONNULL(out); + TEST_ASSERT_TRUE(saw_sysroot); + + free(out); + pkgconf_variable_list_free(&vars); + pkgconf_client_free(client); +} + +static void +test_compile_produces_nonempty_buffer(void) +{ + pkgconf_buffer_t bc = PKGCONF_BUFFER_INITIALIZER; + + pkgconf_bytecode_compile(&bc, "hello ${world}"); + + // The compiled bytecode buffer should be non-empty + TEST_ASSERT_NE(pkgconf_buffer_len(&bc), 0); + + pkgconf_buffer_finalize(&bc); +} + +static void +test_compile_eval_roundtrip(void) +{ + pkgconf_client_t *client = test_client_new(); + pkgconf_list_t vars = PKGCONF_LIST_INITIALIZER; + bool saw_sysroot = false; + + // Compile directly, then evaluate via the bc field on a variable + seed_variable(&vars, "name", "world"); + + pkgconf_variable_t *v = pkgconf_variable_get_or_create(&vars, "greeting"); + TEST_ASSERT_NONNULL(v); + pkgconf_buffer_reset(&v->bcbuf); + pkgconf_bytecode_compile(&v->bcbuf, "hello ${name}"); + pkgconf_bytecode_from_buffer(&v->bc, &v->bcbuf); + + char *out = pkgconf_variable_eval_str(client, &vars, v, &saw_sysroot); + TEST_ASSERT_NONNULL(out); + TEST_ASSERT_STRCMP_EQ(out, "hello world"); + + free(out); + pkgconf_variable_list_free(&vars); + pkgconf_client_free(client); +} + +int +main(int argc, char *argv[]) +{ + (void) argc; + const char *basename = pkgconf_path_find_basename(argv[0]); + + TEST_RUN(basename, test_eval_plain_text); + TEST_RUN(basename, test_eval_empty_input); + TEST_RUN(basename, test_eval_variable_substitution); + TEST_RUN(basename, test_eval_nested_variables); + TEST_RUN(basename, test_eval_multiple_variables); + TEST_RUN(basename, test_eval_undefined_variable); + TEST_RUN(basename, test_eval_sysroot_detection); + TEST_RUN(basename, test_eval_null_args); + + TEST_RUN(basename, test_emit_guards); + TEST_RUN(basename, test_emit_text_and_eval); + TEST_RUN(basename, test_emit_var_and_eval); + TEST_RUN(basename, test_emit_sysroot_and_eval); + + TEST_RUN(basename, test_dollar_escape); + TEST_RUN(basename, test_malformed_unclosed); + TEST_RUN(basename, test_empty_braces); + + TEST_RUN(basename, test_circular_reference); + TEST_RUN(basename, test_references_var); + TEST_RUN(basename, test_references_var_text_only); + + TEST_RUN(basename, test_compile_time_sysroot); + TEST_RUN(basename, test_sysroot_dot_disables); + TEST_RUN(basename, test_sysroot_root_disables); + TEST_RUN(basename, test_sysroot_trailing_slash_trimmed); + TEST_RUN(basename, test_sysroot_normalizes_to_root_disables); + + TEST_RUN(basename, test_rewrite_selfrefs); + TEST_RUN(basename, test_rewrite_selfrefs_no_match); + + TEST_RUN(basename, test_compile_eval_roundtrip); + TEST_RUN(basename, test_compile_produces_nonempty_buffer); + TEST_RUN(basename, test_compile_null_args); + + return EXIT_SUCCESS; +} diff --git a/tests/api/test-client.c b/tests/api/test-client.c new file mode 100644 index 000000000000..ae8889b658c8 --- /dev/null +++ b/tests/api/test-client.c @@ -0,0 +1,334 @@ +/* + * test-client.c + * Tests for the public libpkgconf client API. + * + * SPDX-License-Identifier: pkgconf + * + * Copyright (c) 2026 pkgconf authors (see AUTHORS). + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * This software is provided 'as is' and without any warranty, express or + * implied. In no event shall the authors be liable for any damages arising + * from the use of this software. + */ + +#include "test-api.h" + +static void +test_client_new_and_free(void) +{ + pkgconf_cross_personality_t *pers = pkgconf_cross_personality_default(); + pkgconf_client_t *client = pkgconf_client_new(NULL, NULL, pers, NULL, NULL); + TEST_ASSERT_NONNULL(client); + + pkgconf_client_free(client); +} + +static void +test_client_init_and_deinit_stack(void) +{ + /* Caller-allocated client, the path the CLI itself uses + * (pkgconf_cli_state_t embeds a pkgconf_client_t by value) */ + pkgconf_client_t client = { 0 }; + pkgconf_cross_personality_t *pers = pkgconf_cross_personality_default(); + + pkgconf_client_init(&client, NULL, NULL, pers, NULL, NULL); + pkgconf_client_deinit(&client); +} + +static void +test_client_sysroot_dir(void) +{ + pkgconf_client_t *client = test_client_new(); + + pkgconf_client_set_sysroot_dir(client, "/tmp/sysroot"); + TEST_ASSERT_STRCMP_EQ(pkgconf_client_get_sysroot_dir(client), "/tmp/sysroot"); + + pkgconf_client_set_sysroot_dir(client, "/opt/sysroot"); + TEST_ASSERT_STRCMP_EQ(pkgconf_client_get_sysroot_dir(client), "/opt/sysroot"); + + pkgconf_client_free(client); +} + +static void +test_client_buildroot_dir(void) +{ + pkgconf_client_t *client = test_client_new(); + + pkgconf_client_set_buildroot_dir(client, "/tmp/buildroot"); + TEST_ASSERT_STRCMP_EQ(pkgconf_client_get_buildroot_dir(client), "/tmp/buildroot"); + + pkgconf_client_free(client); +} + +static void +test_client_flags(void) +{ + pkgconf_client_t *client = test_client_new(); + + pkgconf_client_set_flags(client, PKGCONF_PKG_PKGF_NO_CACHE | PKGCONF_PKG_PKGF_SKIP_CONFLICTS); + + unsigned int flags = pkgconf_client_get_flags(client); + TEST_ASSERT_NE(flags & PKGCONF_PKG_PKGF_NO_CACHE, 0); + TEST_ASSERT_NE(flags & PKGCONF_PKG_PKGF_SKIP_CONFLICTS, 0); + TEST_ASSERT_EQ(flags & PKGCONF_PKG_PKGF_ENV_ONLY, 0); + + pkgconf_client_free(client); +} + +static void +test_client_prefix_varname(void) +{ + pkgconf_client_t *client = test_client_new(); + + pkgconf_client_set_prefix_varname(client, "prefix"); + TEST_ASSERT_STRCMP_EQ(pkgconf_client_get_prefix_varname(client), "prefix"); + + pkgconf_client_set_prefix_varname(client, "custom_prefix"); + TEST_ASSERT_STRCMP_EQ(pkgconf_client_get_prefix_varname(client), "custom_prefix"); + + pkgconf_client_free(client); +} + +/* + * Capture buffer for handler tests. Each handler writes the message + * into this buffer so the test can verify it fired with the expected + * content. Reset before each test that uses it. + */ +static char capture_buf[256]; + +static bool +capture_handler(const char *msg, const pkgconf_client_t *client, void *data) +{ + (void) client; + (void) data; + + strncpy(capture_buf, msg, sizeof(capture_buf) - 1); + capture_buf[sizeof(capture_buf) - 1] = '\0'; + return true; +} + +static void +capture_reset(void) +{ + memset(capture_buf, 0, sizeof(capture_buf)); +} + +static void +test_client_error_handler_fires(void) +{ + pkgconf_client_t *client = test_client_new(); + capture_reset(); + + pkgconf_client_set_error_handler(client, capture_handler, NULL); + + TEST_ASSERT_EQ(pkgconf_client_get_error_handler(client), capture_handler); + + pkgconf_error(client, "test error: %d", 42); + + TEST_ASSERT_NE(capture_buf[0], '\0'); + TEST_ASSERT_STRSTR(capture_buf, "test error: 42"); + + pkgconf_client_free(client); +} + +static void +test_client_warn_handler_fires(void) +{ + pkgconf_client_t *client = test_client_new(); + capture_reset(); + + pkgconf_client_set_warn_handler(client, capture_handler, NULL); + + TEST_ASSERT_EQ(pkgconf_client_get_warn_handler(client), capture_handler); + + pkgconf_warn(client, "test warning: %s", "hello"); + + TEST_ASSERT_NE(capture_buf[0], '\0'); + TEST_ASSERT_STRSTR(capture_buf, "test warning: hello"); + + pkgconf_client_free(client); +} + +#ifndef PKGCONF_LITE +static void +test_client_trace_handler_fires(void) +{ + pkgconf_client_t *client = test_client_new(); + capture_reset(); + + pkgconf_client_set_trace_handler(client, capture_handler, NULL); + + TEST_ASSERT_EQ(pkgconf_client_get_trace_handler(client), capture_handler); + + PKGCONF_TRACE(client, "trace message: %d", 7); + + TEST_ASSERT_NE(capture_buf[0], '\0'); + TEST_ASSERT_STRSTR(capture_buf, "trace message: 7"); + + pkgconf_client_free(client); +} +#endif + +static void +unveil_capture_handler(const pkgconf_client_t *client, const char *path, const char *permissions) +{ + (void) client; + (void) permissions; + + if (path != NULL) + { + strncpy(capture_buf, path, sizeof(capture_buf) - 1); + capture_buf[sizeof(capture_buf) - 1] = '\0'; + } +} + +static void +test_client_unveil_handler_installation(void) +{ + pkgconf_client_t *client = test_client_new(); + + pkgconf_client_set_unveil_handler(client, unveil_capture_handler); + TEST_ASSERT_EQ(pkgconf_client_get_unveil_handler(client), unveil_capture_handler); + + pkgconf_client_free(client); +} + +/* + * Custom environ handler that returns canned values for known keys + * and NULL otherwise. + */ +static const char * +canned_environ_handler(const pkgconf_client_t *client, const char *key) +{ + (void) client; + + if (!strcmp(key, "PKG_TEST_VAR")) + return "the_value"; + if (!strcmp(key, "EMPTY_VAR")) + return ""; + if (!strcmp(key, "PKG_CONFIG_SYSTEM_INCLUDE_PATH")) + return "/custom/include"; + if (!strcmp(key, "PKG_CONFIG_SYSTEM_LIBRARY_PATH")) + return "/custom/lib"; + + return NULL; +} + +static void +test_client_getenv_via_handler(void) +{ + pkgconf_cross_personality_t *pers = pkgconf_cross_personality_default(); + pkgconf_client_t *client = pkgconf_client_new(NULL, NULL, pers, NULL, canned_environ_handler); + TEST_ASSERT_NONNULL(client); + + const char *v = pkgconf_client_getenv(client, "PKG_TEST_VAR"); + TEST_ASSERT_NONNULL(v); + TEST_ASSERT_STRCMP_EQ(v, "the_value"); + + v = pkgconf_client_getenv(client, "EMPTY_VAR"); + TEST_ASSERT_NONNULL(v); + TEST_ASSERT_STRCMP_EQ(v, ""); + + v = pkgconf_client_getenv(client, "UNDEFINED_VAR"); + TEST_ASSERT_NULL(v); + + pkgconf_client_free(client); +} + +static void +test_client_dir_list_build_smoke(void) +{ + pkgconf_cross_personality_t *pers = pkgconf_cross_personality_default(); + pkgconf_client_t *client = pkgconf_client_new(NULL, NULL, pers, NULL, NULL); + TEST_ASSERT_NONNULL(client); + + pkgconf_client_dir_list_build(client, pers); + + /* The personality's default dir list comes from PKG_DEFAULT_PATH + * (set at compile time). After build, the client should have + * SOME directories registered; we don't assert specific paths + * since they vary by build configuration. */ + TEST_ASSERT_NONNULL(client->dir_list.head); + + pkgconf_client_free(client); +} + +static void +test_client_init_system_paths_from_environ(void) +{ + pkgconf_cross_personality_t *pers = pkgconf_cross_personality_default(); + pkgconf_client_t *client = pkgconf_client_new(NULL, NULL, pers, NULL, canned_environ_handler); + TEST_ASSERT_NONNULL(client); + + /* With PKG_CONFIG_SYSTEM_{INCLUDE,LIBRARY}_PATH set, init builds the filter dirs from the + * environment instead of copying the personality's defaults. */ + TEST_ASSERT_TRUE(pkgconf_path_match_list("/custom/include", &client->filter_includedirs)); + TEST_ASSERT_TRUE(pkgconf_path_match_list("/custom/lib", &client->filter_libdirs)); + + pkgconf_client_free(client); +} + +static void +test_client_preload_from_environ(void) +{ + pkgconf_cross_personality_t *pers = pkgconf_cross_personality_default(); + pkgconf_client_t *client = pkgconf_client_new(NULL, NULL, pers, NULL, NULL); + TEST_ASSERT_NONNULL(client); + + /* preload_from_environ reads the named var via getenv directly. + * Point it at a dir; preload_path will try to load .pc files from there. + * An empty/nonexistent dir is fine; we're exercising the split-and-iterate path, not asserting + * loads. */ + setenv("PKG_TEST_PRELOAD", "/nonexistent/dir", 1); + + pkgconf_client_preload_from_environ(client, "PKG_TEST_PRELOAD"); + + unsetenv("PKG_TEST_PRELOAD"); + pkgconf_client_free(client); +} + +#ifndef PKGCONF_LITE +static void +test_client_trace_null_client(void) +{ + TEST_ASSERT_FALSE(pkgconf_trace(NULL, "test.c", 42, "func", "msg %d", 42)); +} +#endif + +int +main(int argc, char *argv[]) +{ + (void) argc; + const char *basename = pkgconf_path_find_basename(argv[0]); + + TEST_RUN(basename, test_client_new_and_free); + TEST_RUN(basename, test_client_init_and_deinit_stack); + TEST_RUN(basename, test_client_init_system_paths_from_environ); + TEST_RUN(basename, test_client_preload_from_environ); + + TEST_RUN(basename, test_client_sysroot_dir); + TEST_RUN(basename, test_client_buildroot_dir); + TEST_RUN(basename, test_client_flags); + TEST_RUN(basename, test_client_prefix_varname); + + TEST_RUN(basename, test_client_error_handler_fires); + TEST_RUN(basename, test_client_warn_handler_fires); +#ifndef PKGCONF_LITE + TEST_RUN(basename, test_client_trace_handler_fires); +#endif + TEST_RUN(basename, test_client_unveil_handler_installation); + + TEST_RUN(basename, test_client_getenv_via_handler); + + TEST_RUN(basename, test_client_dir_list_build_smoke); + +#ifndef PKGCONF_LITE + TEST_RUN(basename, test_client_trace_null_client); +#endif + + return EXIT_SUCCESS; +} diff --git a/tests/api/test-dependency.c b/tests/api/test-dependency.c new file mode 100644 index 000000000000..edd00b620f18 --- /dev/null +++ b/tests/api/test-dependency.c @@ -0,0 +1,551 @@ +/* + * test-dependency.c + * Tests for the public libpkgconf dependency API. + * + * SPDX-License-Identifier: pkgconf + * + * Copyright (c) 2026 pkgconf authors (see AUTHORS). + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * This software is provided 'as is' and without any warranty, express or + * implied. In no event shall the authors be liable for any damages arising + * from the use of this software. + */ + +#include "test-api.h" + +static size_t +dependency_count(const pkgconf_list_t *list) +{ + size_t n = 0; + const pkgconf_node_t *iter; + + PKGCONF_FOREACH_LIST_ENTRY(list->head, iter) + { + n++; + } + + return n; +} + +static const pkgconf_dependency_t * +dependency_at(const pkgconf_list_t *list, size_t index) +{ + const pkgconf_node_t *iter; + size_t i = 0; + + PKGCONF_FOREACH_LIST_ENTRY(list->head, iter) + { + if (i++ == index) + return iter->data; + } + + return NULL; +} + +static void +test_comparator_lookup_known(void) +{ + TEST_ASSERT_EQ(pkgconf_pkg_comparator_lookup_by_name("="), PKGCONF_CMP_EQUAL); + TEST_ASSERT_EQ(pkgconf_pkg_comparator_lookup_by_name("!="), PKGCONF_CMP_NOT_EQUAL); + TEST_ASSERT_EQ(pkgconf_pkg_comparator_lookup_by_name("<"), PKGCONF_CMP_LESS_THAN); + TEST_ASSERT_EQ(pkgconf_pkg_comparator_lookup_by_name("<="), PKGCONF_CMP_LESS_THAN_EQUAL); + TEST_ASSERT_EQ(pkgconf_pkg_comparator_lookup_by_name(">"), PKGCONF_CMP_GREATER_THAN); + TEST_ASSERT_EQ(pkgconf_pkg_comparator_lookup_by_name(">="), PKGCONF_CMP_GREATER_THAN_EQUAL); +} + +static void +test_comparator_lookup_unknown(void) +{ + TEST_ASSERT_EQ(pkgconf_pkg_comparator_lookup_by_name("~~"), PKGCONF_CMP_ANY); + TEST_ASSERT_EQ(pkgconf_pkg_comparator_lookup_by_name(""), PKGCONF_CMP_ANY); +} + +static void +test_comparator_roundtrip(void) +{ + pkgconf_pkg_comparator_t values[] = + { + PKGCONF_CMP_NOT_EQUAL, + PKGCONF_CMP_ANY, + PKGCONF_CMP_LESS_THAN, + PKGCONF_CMP_LESS_THAN_EQUAL, + PKGCONF_CMP_EQUAL, + PKGCONF_CMP_GREATER_THAN, + PKGCONF_CMP_GREATER_THAN_EQUAL, + }; + + for (size_t i = 0; i < PKGCONF_ARRAY_SIZE(values); i++) + { + pkgconf_dependency_t dep = { 0 }; + dep.compare = values[i]; + + const char *str = pkgconf_pkg_get_comparator(&dep); + TEST_ASSERT_NONNULL(str); + + // ANY's value does not round-trip so do not check + if (values[i] == PKGCONF_CMP_ANY) + continue; + + pkgconf_pkg_comparator_t back = pkgconf_pkg_comparator_lookup_by_name(str); + TEST_ASSERT_EQ(back, values[i]); + } +} + +static void +test_parse_str_single(void) +{ + pkgconf_client_t *client = test_client_new(); + pkgconf_list_t deps = PKGCONF_LIST_INITIALIZER; + + pkgconf_dependency_parse_str(client, &deps, "foo", 0); + + TEST_ASSERT_EQ(dependency_count(&deps), 1); + const pkgconf_dependency_t *d = dependency_at(&deps, 0); + TEST_ASSERT_NONNULL(d); + TEST_ASSERT_STRCMP_EQ(d->package, "foo"); + TEST_ASSERT_EQ(d->compare, PKGCONF_CMP_ANY); + TEST_ASSERT_NULL(d->version); + + pkgconf_dependency_free(&deps); + pkgconf_client_free(client); +} + +static void +test_parse_str_versioned(void) +{ + pkgconf_client_t *client = test_client_new(); + pkgconf_list_t deps = PKGCONF_LIST_INITIALIZER; + + pkgconf_dependency_parse_str(client, &deps, "foo >= 1.2.3", 0); + + TEST_ASSERT_EQ(dependency_count(&deps), 1); + const pkgconf_dependency_t *d = dependency_at(&deps, 0); + TEST_ASSERT_NONNULL(d); + TEST_ASSERT_STRCMP_EQ(d->package, "foo"); + TEST_ASSERT_EQ(d->compare, PKGCONF_CMP_GREATER_THAN_EQUAL); + TEST_ASSERT_STRCMP_EQ(d->version, "1.2.3"); + + pkgconf_dependency_free(&deps); + pkgconf_client_free(client); +} + +static void +test_parse_str_multiple_space_separated(void) +{ + pkgconf_client_t *client = test_client_new(); + pkgconf_list_t deps = PKGCONF_LIST_INITIALIZER; + + pkgconf_dependency_parse_str(client, &deps, "foo bar baz", 0); + + TEST_ASSERT_EQ(dependency_count(&deps), 3); + + const pkgconf_dependency_t *d0 = dependency_at(&deps, 0); + const pkgconf_dependency_t *d1 = dependency_at(&deps, 1); + const pkgconf_dependency_t *d2 = dependency_at(&deps, 2); + TEST_ASSERT_NONNULL(d0); + TEST_ASSERT_NONNULL(d1); + TEST_ASSERT_NONNULL(d2); + TEST_ASSERT_STRCMP_EQ(d0->package, "foo"); + TEST_ASSERT_STRCMP_EQ(d1->package, "bar"); + TEST_ASSERT_STRCMP_EQ(d2->package, "baz"); + + pkgconf_dependency_free(&deps); + pkgconf_client_free(client); +} + +static void +test_parse_str_multiple_comma_separated(void) +{ + pkgconf_client_t *client = test_client_new(); + pkgconf_list_t deps = PKGCONF_LIST_INITIALIZER; + + pkgconf_dependency_parse_str(client, &deps, "foo, bar, baz", 0); + + TEST_ASSERT_EQ(dependency_count(&deps), 3); + + const pkgconf_dependency_t *d0 = dependency_at(&deps, 0); + const pkgconf_dependency_t *d1 = dependency_at(&deps, 1); + const pkgconf_dependency_t *d2 = dependency_at(&deps, 2); + TEST_ASSERT_NONNULL(d0); + TEST_ASSERT_NONNULL(d1); + TEST_ASSERT_NONNULL(d2); + TEST_ASSERT_STRCMP_EQ(d0->package, "foo"); + TEST_ASSERT_STRCMP_EQ(d1->package, "bar"); + TEST_ASSERT_STRCMP_EQ(d2->package, "baz"); + + pkgconf_dependency_free(&deps); + pkgconf_client_free(client); +} + +static void +test_parse_str_mixed_versioned_and_bare(void) +{ + pkgconf_client_t *client = test_client_new(); + pkgconf_list_t deps = PKGCONF_LIST_INITIALIZER; + + pkgconf_dependency_parse_str(client, &deps, "foo >= 1.0, bar, baz < 2.0", 0); + + TEST_ASSERT_EQ(dependency_count(&deps), 3); + + const pkgconf_dependency_t *d0 = dependency_at(&deps, 0); + const pkgconf_dependency_t *d1 = dependency_at(&deps, 1); + const pkgconf_dependency_t *d2 = dependency_at(&deps, 2); + + TEST_ASSERT_NONNULL(d0); + TEST_ASSERT_NONNULL(d1); + TEST_ASSERT_NONNULL(d2); + + TEST_ASSERT_STRCMP_EQ(d0->package, "foo"); + TEST_ASSERT_EQ(d0->compare, PKGCONF_CMP_GREATER_THAN_EQUAL); + TEST_ASSERT_STRCMP_EQ(d0->version, "1.0"); + + TEST_ASSERT_STRCMP_EQ(d1->package, "bar"); + TEST_ASSERT_EQ(d1->compare, PKGCONF_CMP_ANY); + + TEST_ASSERT_STRCMP_EQ(d2->package, "baz"); + TEST_ASSERT_EQ(d2->compare, PKGCONF_CMP_LESS_THAN); + TEST_ASSERT_STRCMP_EQ(d2->version, "2.0"); + + pkgconf_dependency_free(&deps); + pkgconf_client_free(client); +} + +static void +test_parse_str_empty(void) +{ + pkgconf_client_t *client = test_client_new(); + pkgconf_list_t deps = PKGCONF_LIST_INITIALIZER; + + pkgconf_dependency_parse_str(client, &deps, "", 0); + TEST_ASSERT_EQ(dependency_count(&deps), 0); + + pkgconf_dependency_free(&deps); + pkgconf_client_free(client); +} + +static void +test_parse_str_all_comparators(void) +{ + pkgconf_client_t *client = test_client_new(); + pkgconf_list_t deps = PKGCONF_LIST_INITIALIZER; + + pkgconf_dependency_parse_str(client, &deps, "a = 1, b != 2, c < 3, d <= 4, e > 5, f >= 6", 0); + + TEST_ASSERT_EQ(dependency_count(&deps), 6); + + const pkgconf_dependency_t *d0 = dependency_at(&deps, 0); + const pkgconf_dependency_t *d1 = dependency_at(&deps, 1); + const pkgconf_dependency_t *d2 = dependency_at(&deps, 2); + const pkgconf_dependency_t *d3 = dependency_at(&deps, 3); + const pkgconf_dependency_t *d4 = dependency_at(&deps, 4); + const pkgconf_dependency_t *d5 = dependency_at(&deps, 5); + + TEST_ASSERT_NONNULL(d0); + TEST_ASSERT_NONNULL(d1); + TEST_ASSERT_NONNULL(d2); + TEST_ASSERT_NONNULL(d3); + TEST_ASSERT_NONNULL(d4); + TEST_ASSERT_NONNULL(d5); + + TEST_ASSERT_EQ(d0->compare, PKGCONF_CMP_EQUAL); + TEST_ASSERT_EQ(d1->compare, PKGCONF_CMP_NOT_EQUAL); + TEST_ASSERT_EQ(d2->compare, PKGCONF_CMP_LESS_THAN); + TEST_ASSERT_EQ(d3->compare, PKGCONF_CMP_LESS_THAN_EQUAL); + TEST_ASSERT_EQ(d4->compare, PKGCONF_CMP_GREATER_THAN); + TEST_ASSERT_EQ(d5->compare, PKGCONF_CMP_GREATER_THAN_EQUAL); + + pkgconf_dependency_free(&deps); + pkgconf_client_free(client); +} + +static void +test_dependency_add(void) +{ + pkgconf_client_t *client = test_client_new(); + pkgconf_list_t deps = PKGCONF_LIST_INITIALIZER; + + pkgconf_dependency_t *d = pkgconf_dependency_add(client, &deps, "foo", "1.0", PKGCONF_CMP_GREATER_THAN_EQUAL, 0); + TEST_ASSERT_NONNULL(d); + TEST_ASSERT_STRCMP_EQ(d->package, "foo"); + TEST_ASSERT_STRCMP_EQ(d->version, "1.0"); + TEST_ASSERT_EQ(d->compare, PKGCONF_CMP_GREATER_THAN_EQUAL); + + TEST_ASSERT_EQ(dependency_count(&deps), 1); + + pkgconf_dependency_unref(client, d); + pkgconf_dependency_free(&deps); + pkgconf_client_free(client); +} + +static void +test_dependency_add_no_version(void) +{ + pkgconf_client_t *client = test_client_new(); + pkgconf_list_t deps = PKGCONF_LIST_INITIALIZER; + + pkgconf_dependency_t *d = pkgconf_dependency_add(client, &deps, "foo", NULL, PKGCONF_CMP_ANY, 0); + TEST_ASSERT_NONNULL(d); + TEST_ASSERT_STRCMP_EQ(d->package, "foo"); + TEST_ASSERT_EQ(d->compare, PKGCONF_CMP_ANY); + + pkgconf_dependency_unref(client, d); + pkgconf_dependency_free(&deps); + pkgconf_client_free(client); +} + +static void +test_dependency_add_multiple(void) +{ + pkgconf_client_t *client = test_client_new(); + pkgconf_list_t deps = PKGCONF_LIST_INITIALIZER; + + pkgconf_dependency_t *d0 = pkgconf_dependency_add(client, &deps, "foo", NULL, PKGCONF_CMP_ANY, 0); + pkgconf_dependency_t *d1 = pkgconf_dependency_add(client, &deps, "bar", "2.0", PKGCONF_CMP_EQUAL, 0); + pkgconf_dependency_t *d2 = pkgconf_dependency_add(client, &deps, "baz", "3.0", PKGCONF_CMP_LESS_THAN, 0); + + TEST_ASSERT_NONNULL(d0); + TEST_ASSERT_NONNULL(d1); + TEST_ASSERT_NONNULL(d2); + + TEST_ASSERT_EQ(dependency_count(&deps), 3); + + pkgconf_dependency_unref(client, d0); + pkgconf_dependency_unref(client, d1); + pkgconf_dependency_unref(client, d2); + pkgconf_dependency_free(&deps); + pkgconf_client_free(client); +} + +static void +test_dependency_collision_drops_flagged_newcomer(void) +{ + pkgconf_client_t *client = test_client_new(); + pkgconf_list_t deps = PKGCONF_LIST_INITIALIZER; + + pkgconf_dependency_t *first = pkgconf_dependency_add(client, &deps, "foo", "1.0", PKGCONF_CMP_EQUAL, 0); + TEST_ASSERT_NONNULL(first); + TEST_ASSERT_EQ(dependency_count(&deps), 1); + + /* Adding the same dep WITH flags collides; the flagged newcomer + * is dropped in favour of the existing unflagged node, so _add + * returns NULL and the count stays at 1 */ + pkgconf_dependency_t *second = pkgconf_dependency_add(client, &deps, "foo", "1.0", PKGCONF_CMP_EQUAL, PKGCONF_PKG_DEPF_INTERNAL); + TEST_ASSERT_NULL(second); + TEST_ASSERT_EQ(dependency_count(&deps), 1); + + pkgconf_dependency_unref(client, first); + pkgconf_dependency_free(&deps); + pkgconf_client_free(client); +} + +static void +test_dependency_collision_drops_flagged_existing(void) +{ + pkgconf_client_t *client = test_client_new(); + pkgconf_list_t deps = PKGCONF_LIST_INITIALIZER; + + pkgconf_dependency_t *first = pkgconf_dependency_add(client, &deps, "foo", "1.0", PKGCONF_CMP_EQUAL, PKGCONF_PKG_DEPF_INTERNAL); + TEST_ASSERT_NONNULL(first); + TEST_ASSERT_EQ(dependency_count(&deps), 1); + + /* Adding the same dep UNFLAGGED collides; the existing flagged + * node is deleted and unref'd, the unflagged newcomer takes its + * place; count stays at 1, but the node is now the new one */ + pkgconf_dependency_t *second = pkgconf_dependency_add(client, &deps, "foo", "1.0", PKGCONF_CMP_EQUAL, 0); + TEST_ASSERT_NONNULL(second); + TEST_ASSERT_EQ(dependency_count(&deps), 1); + TEST_ASSERT_EQ(second->flags, 0); + + pkgconf_dependency_unref(client, first); + pkgconf_dependency_unref(client, second); + pkgconf_dependency_free(&deps); + pkgconf_client_free(client); +} + +static void +test_version_equal(void) +{ + TEST_ASSERT_EQ(pkgconf_compare_version("1.0", "1.0"), 0); + TEST_ASSERT_EQ(pkgconf_compare_version("1.2.3", "1.2.3"), 0); + TEST_ASSERT_EQ(pkgconf_compare_version("", ""), 0); +} + +static void +test_version_simple_numeric(void) +{ + TEST_ASSERT_LT(pkgconf_compare_version("1.0", "1.1"), 0); + TEST_ASSERT_GT(pkgconf_compare_version("1.1", "1.0"), 0); + + TEST_ASSERT_LT(pkgconf_compare_version("1.0", "2.0"), 0); + TEST_ASSERT_GT(pkgconf_compare_version("2.0", "1.0"), 0); + + TEST_ASSERT_LT(pkgconf_compare_version("1.2.3", "1.2.4"), 0); + TEST_ASSERT_LT(pkgconf_compare_version("1.2.3", "1.3.0"), 0); + TEST_ASSERT_LT(pkgconf_compare_version("1.2.3", "2.0.0"), 0); +} + +static void +test_version_numeric_segments_not_lexical(void) +{ + TEST_ASSERT_GT(pkgconf_compare_version("1.10", "1.9"), 0); + TEST_ASSERT_GT(pkgconf_compare_version("1.100", "1.99"), 0); +} + +static void +test_version_different_lengths(void) +{ + TEST_ASSERT_LT(pkgconf_compare_version("1.0", "1.0.1"), 0); + TEST_ASSERT_GT(pkgconf_compare_version("1.0.1", "1.0"), 0); +} + +static void +test_version_alpha_suffix(void) +{ + TEST_ASSERT_GT(pkgconf_compare_version("1.0a", "1.0"), 0); + TEST_ASSERT_GT(pkgconf_compare_version("1.0alpha", "1.0"), 0); + TEST_ASSERT_GT(pkgconf_compare_version("1.0rc1", "1.0"), 0); + + TEST_ASSERT_LT(pkgconf_compare_version("1.0alpha", "1.0beta"), 0); + TEST_ASSERT_LT(pkgconf_compare_version("1.0beta", "1.0rc"), 0); +} + +static void +test_version_tilde_prerelease(void) +{ + TEST_ASSERT_LT(pkgconf_compare_version("1.0~rc1", "1.0"), 0); + TEST_ASSERT_LT(pkgconf_compare_version("1.0~alpha", "1.0"), 0); + TEST_ASSERT_LT(pkgconf_compare_version("1.0~beta", "1.0~rc"), 0); + + TEST_ASSERT_LT(pkgconf_compare_version("1.0~rc1", "1.0rc1"), 0); +} + +static void +test_version_numeric_beats_alpha(void) +{ + TEST_ASSERT_GT(pkgconf_compare_version("1.0.1", "1.0a"), 0); + TEST_ASSERT_LT(pkgconf_compare_version("1.0a", "1.0.1"), 0); +} + +static void +test_version_alpha_ordering(void) +{ + TEST_ASSERT_LT(pkgconf_compare_version("1.0a", "1.0b"), 0); + TEST_ASSERT_GT(pkgconf_compare_version("1.0b", "1.0a"), 0); +} + +static void +test_version_dotted_vs_hyphenated(void) +{ + TEST_ASSERT_EQ(pkgconf_compare_version("1.0-1", "1.0.1"), 0); +} + +static void +test_version_leading_zeros(void) +{ + TEST_ASSERT_EQ(pkgconf_compare_version("1.01", "1.1"), 0); + TEST_ASSERT_EQ(pkgconf_compare_version("01.0", "1.0"), 0); +} + +static void +test_version_trailing_zero_segments(void) +{ + /* Pkgconf does NOT treat "1.0" and "1.0.0" as equivalent. + * Even a zero trailing numeric segment is additional content that makes the version greater. + */ + TEST_ASSERT_LT(pkgconf_compare_version("1.0", "1.0.0"), 0); + TEST_ASSERT_GT(pkgconf_compare_version("1.0.0", "1.0"), 0); + TEST_ASSERT_LT(pkgconf_compare_version("1", "1.0"), 0); + TEST_ASSERT_LT(pkgconf_compare_version("1", "1.0.0.0"), 0); +} + +static void +test_version_null_handling(void) +{ + TEST_ASSERT_LT(pkgconf_compare_version(NULL, "1.0"), 0); + TEST_ASSERT_GT(pkgconf_compare_version("1.0", NULL), 0); + TEST_ASSERT_LT(pkgconf_compare_version(NULL, NULL), 0); +} + +static void +test_version_tilde_both_sides(void) +{ + TEST_ASSERT_LT(pkgconf_compare_version("1.0~", "1.0a"), 0); + TEST_ASSERT_GT(pkgconf_compare_version("1.0a", "1.0~"), 0); + + TEST_ASSERT_EQ(pkgconf_compare_version("1.0~rc", "1.0~rc"), 0); + TEST_ASSERT_LT(pkgconf_compare_version("1.0~a", "1.0~b"), 0); + TEST_ASSERT_LT(pkgconf_compare_version("1.0~1", "1.0~2"), 0); +} + +static void +test_version_separator_equivalence(void) +{ + TEST_ASSERT_EQ(pkgconf_compare_version("1.0", "1-0"), 0); + TEST_ASSERT_EQ(pkgconf_compare_version("1.2.3", "1_2_3"), 0); + TEST_ASSERT_EQ(pkgconf_compare_version("1..2", "1.2"), 0); +} + +static void +test_version_case_insensitive(void) +{ + TEST_ASSERT_EQ(pkgconf_compare_version("1.0RC1", "1.0rc1"), 0); + TEST_ASSERT_EQ(pkgconf_compare_version("1.0A", "1.0a"), 0); +} + +static void +test_version_alpha_prefix(void) +{ + TEST_ASSERT_LT(pkgconf_compare_version("1.0alpha", "1.0alphabeta"), 0); + TEST_ASSERT_GT(pkgconf_compare_version("1.0alphabeta", "1.0alpha"), 0); + + TEST_ASSERT_LT(pkgconf_compare_version("1.0a", "1.0ab"), 0); + TEST_ASSERT_GT(pkgconf_compare_version("1.0ab", "1.0a"), 0); +} + +int +main(int argc, char *argv[]) +{ + (void) argc; + const char *basename = pkgconf_path_find_basename(argv[0]); + + TEST_RUN(basename, test_comparator_lookup_known); + TEST_RUN(basename, test_comparator_lookup_unknown); + TEST_RUN(basename, test_comparator_roundtrip); + + TEST_RUN(basename, test_parse_str_empty); + TEST_RUN(basename, test_parse_str_single); + TEST_RUN(basename, test_parse_str_versioned); + TEST_RUN(basename, test_parse_str_multiple_space_separated); + TEST_RUN(basename, test_parse_str_multiple_comma_separated); + TEST_RUN(basename, test_parse_str_mixed_versioned_and_bare); + TEST_RUN(basename, test_parse_str_all_comparators); + + TEST_RUN(basename, test_dependency_add); + TEST_RUN(basename, test_dependency_add_no_version); + TEST_RUN(basename, test_dependency_add_multiple); + TEST_RUN(basename, test_dependency_collision_drops_flagged_newcomer); + TEST_RUN(basename, test_dependency_collision_drops_flagged_existing); + + TEST_RUN(basename, test_version_equal); + TEST_RUN(basename, test_version_simple_numeric); + TEST_RUN(basename, test_version_numeric_segments_not_lexical); + TEST_RUN(basename, test_version_different_lengths); + TEST_RUN(basename, test_version_alpha_suffix); + TEST_RUN(basename, test_version_tilde_prerelease); + TEST_RUN(basename, test_version_numeric_beats_alpha); + TEST_RUN(basename, test_version_alpha_ordering); + TEST_RUN(basename, test_version_dotted_vs_hyphenated); + TEST_RUN(basename, test_version_leading_zeros); + TEST_RUN(basename, test_version_trailing_zero_segments); + TEST_RUN(basename, test_version_null_handling); + TEST_RUN(basename, test_version_tilde_both_sides); + TEST_RUN(basename, test_version_separator_equivalence); + TEST_RUN(basename, test_version_case_insensitive); + TEST_RUN(basename, test_version_alpha_prefix); + + return EXIT_SUCCESS; +} diff --git a/tests/api/test-fileio.c b/tests/api/test-fileio.c new file mode 100644 index 000000000000..a4d5f81679a6 --- /dev/null +++ b/tests/api/test-fileio.c @@ -0,0 +1,236 @@ +/* + * test-fileio.c + * Tests for the public libpkgconf file i/o API. + * + * SPDX-License-Identifier: pkgconf + * + * Copyright (c) 2026 pkgconf authors (see AUTHORS). + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * This software is provided 'as is' and without any warranty, express or + * implied. In no event shall the authors be liable for any damages arising + * from the use of this software. + */ + +#include "test-api.h" + +static FILE * +fmemstream(const char *contents) +{ + FILE *f = tmpfile(); + + TEST_ASSERT_NONNULL(f); + + fwrite(contents, 1, strlen(contents), f); + rewind(f); + + return f; +} + +static void +test_fgetline_no_trailing_newline(void) +{ + pkgconf_buffer_t buf = PKGCONF_BUFFER_INITIALIZER; + FILE *f = fmemstream("hello"); + + TEST_ASSERT_TRUE(pkgconf_fgetline(&buf, f)); + TEST_ASSERT_STRCMP_EQ(pkgconf_buffer_str(&buf), "hello"); + + pkgconf_buffer_reset(&buf); + TEST_ASSERT_FALSE(pkgconf_fgetline(&buf, f)); + + fclose(f); + pkgconf_buffer_finalize(&buf); +} + +static void +test_fgetline_empty_stream(void) +{ + pkgconf_buffer_t buf = PKGCONF_BUFFER_INITIALIZER; + FILE *f = fmemstream(""); + + TEST_ASSERT_FALSE(pkgconf_fgetline(&buf, f)); + + fclose(f); + pkgconf_buffer_finalize(&buf); +} + +static void +test_fgetline_lf(void) +{ + pkgconf_buffer_t buf = PKGCONF_BUFFER_INITIALIZER; + FILE *f = fmemstream("hello\nworld\n"); + + TEST_ASSERT_TRUE(pkgconf_fgetline(&buf, f)); + TEST_ASSERT_STRCMP_EQ(pkgconf_buffer_str(&buf), "hello"); + + pkgconf_buffer_reset(&buf); + TEST_ASSERT_TRUE(pkgconf_fgetline(&buf, f)); + TEST_ASSERT_STRCMP_EQ(pkgconf_buffer_str(&buf), "world"); + + pkgconf_buffer_reset(&buf); + TEST_ASSERT_FALSE(pkgconf_fgetline(&buf, f)); + + fclose(f); + pkgconf_buffer_finalize(&buf); +} + +static void +test_fgetline_crlf(void) +{ + pkgconf_buffer_t buf = PKGCONF_BUFFER_INITIALIZER; + FILE *f = fmemstream("hello\r\nworld\r\n"); + + TEST_ASSERT_TRUE(pkgconf_fgetline(&buf, f)); + TEST_ASSERT_STRCMP_EQ(pkgconf_buffer_str(&buf), "hello"); + + pkgconf_buffer_reset(&buf); + TEST_ASSERT_TRUE(pkgconf_fgetline(&buf, f)); + TEST_ASSERT_STRCMP_EQ(pkgconf_buffer_str(&buf), "world"); + + pkgconf_buffer_reset(&buf); + TEST_ASSERT_FALSE(pkgconf_fgetline(&buf, f)); + + fclose(f); + pkgconf_buffer_finalize(&buf); +} + +static void +test_fgetline_lone_cr(void) +{ + pkgconf_buffer_t buf = PKGCONF_BUFFER_INITIALIZER; + FILE *f = fmemstream("hello\rworld\r"); + + TEST_ASSERT_TRUE(pkgconf_fgetline(&buf, f)); + TEST_ASSERT_STRCMP_EQ(pkgconf_buffer_str(&buf), "hello"); + + pkgconf_buffer_reset(&buf); + TEST_ASSERT_TRUE(pkgconf_fgetline(&buf, f)); + TEST_ASSERT_STRCMP_EQ(pkgconf_buffer_str(&buf), "world"); + + pkgconf_buffer_reset(&buf); + TEST_ASSERT_FALSE(pkgconf_fgetline(&buf, f)); + + fclose(f); + pkgconf_buffer_finalize(&buf); +} + +static void +test_fgetline_backslash_continuation_lf(void) +{ + pkgconf_buffer_t buf = PKGCONF_BUFFER_INITIALIZER; + FILE *f = fmemstream("foo\\\nbar\n"); + + TEST_ASSERT_TRUE(pkgconf_fgetline(&buf, f)); + TEST_ASSERT_STRCMP_EQ(pkgconf_buffer_str(&buf), "foobar"); + + fclose(f); + pkgconf_buffer_finalize(&buf); +} + +static void +test_fgetline_backslash_continuation_crlf(void) +{ + pkgconf_buffer_t buf = PKGCONF_BUFFER_INITIALIZER; + FILE *f = fmemstream("foo\\\r\nbar\r\n"); + + TEST_ASSERT_TRUE(pkgconf_fgetline(&buf, f)); + TEST_ASSERT_STRCMP_EQ(pkgconf_buffer_str(&buf), "foobar"); + + pkgconf_buffer_reset(&buf); + TEST_ASSERT_FALSE(pkgconf_fgetline(&buf, f)); + + fclose(f); + pkgconf_buffer_finalize(&buf); +} + +static void +test_fgetline_backslash_continuation_lone_cr(void) +{ + pkgconf_buffer_t buf = PKGCONF_BUFFER_INITIALIZER; + FILE *f = fmemstream("foo\\\rbar\r"); + + TEST_ASSERT_TRUE(pkgconf_fgetline(&buf, f)); + TEST_ASSERT_STRCMP_EQ(pkgconf_buffer_str(&buf), "foobar"); + + pkgconf_buffer_reset(&buf); + TEST_ASSERT_FALSE(pkgconf_fgetline(&buf, f)); + + fclose(f); + pkgconf_buffer_finalize(&buf); +} + +// A backslash not immediately followed by a newline is not a continuation, +// so it must be preserved literally in the output. +static void +test_fgetline_backslash_not_continuation(void) +{ + pkgconf_buffer_t buf = PKGCONF_BUFFER_INITIALIZER; + FILE *f = fmemstream("foo\\bar\n"); + + TEST_ASSERT_TRUE(pkgconf_fgetline(&buf, f)); + TEST_ASSERT_STRCMP_EQ(pkgconf_buffer_str(&buf), "foo\\bar"); + + pkgconf_buffer_reset(&buf); + TEST_ASSERT_FALSE(pkgconf_fgetline(&buf, f)); + + fclose(f); + pkgconf_buffer_finalize(&buf); +} + +// fgets() only stops on '\n', a full read buffer, or EOF. NOT on on a lone '\r'. +// If a '\r' happens to be the very last byte fgets() manages to read +// before the buffer fills up, the matching '\n' is still unread in the +// stream and isn't visible to pkgconf_fgetline()'s lookahead, so the CRLF +// pair gets split across two fgets() calls and is misparsed as two lines. +static void +test_fgetline_crlf_split_across_fgets_buffer(void) +{ + pkgconf_buffer_t buf = PKGCONF_BUFFER_INITIALIZER; + size_t prefix_len = PKGCONF_ITEM_SIZE - 2; + char *content = malloc(prefix_len + strlen("\r\nworld\n") + 1); + FILE *f; + + TEST_ASSERT_NONNULL(content); + memset(content, 'a', prefix_len); + strcpy(content + prefix_len, "\r\nworld\n"); + + f = fmemstream(content); + free(content); + + TEST_ASSERT_TRUE(pkgconf_fgetline(&buf, f)); + TEST_ASSERT_EQ(strlen(pkgconf_buffer_str(&buf)), prefix_len); + + pkgconf_buffer_reset(&buf); + TEST_ASSERT_TRUE(pkgconf_fgetline(&buf, f)); + TEST_ASSERT_STRCMP_EQ(pkgconf_buffer_str(&buf), "world"); + + pkgconf_buffer_reset(&buf); + TEST_ASSERT_FALSE(pkgconf_fgetline(&buf, f)); + + fclose(f); + pkgconf_buffer_finalize(&buf); +} + +int +main(int argc, const char **argv) +{ + (void) argc; + const char *basename = pkgconf_path_find_basename(argv[0]); + + TEST_RUN(basename, test_fgetline_no_trailing_newline); + TEST_RUN(basename, test_fgetline_empty_stream); + TEST_RUN(basename, test_fgetline_lf); + TEST_RUN(basename, test_fgetline_crlf); + TEST_RUN(basename, test_fgetline_lone_cr); + TEST_RUN(basename, test_fgetline_backslash_continuation_lf); + TEST_RUN(basename, test_fgetline_backslash_continuation_crlf); + TEST_RUN(basename, test_fgetline_backslash_continuation_lone_cr); + TEST_RUN(basename, test_fgetline_backslash_not_continuation); + TEST_RUN(basename, test_fgetline_crlf_split_across_fgets_buffer); + + return EXIT_SUCCESS; +} diff --git a/tests/api/test-fragment.c b/tests/api/test-fragment.c new file mode 100644 index 000000000000..3d49145ae518 --- /dev/null +++ b/tests/api/test-fragment.c @@ -0,0 +1,376 @@ +/* + * test-fragment.c + * Tests for the public libpkgconf fragment API. + * + * SPDX-License-Identifier: pkgconf + * + * Copyright (c) 2026 pkgconf authors (see AUTHORS). + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * This software is provided 'as is' and without any warranty, express or + * implied. In no event shall the authors be liable for any damages arising + * from the use of this software. + */ + +#include "test-api.h" + +static size_t +fragment_count(const pkgconf_list_t *list) +{ + size_t n = 0; + const pkgconf_node_t *iter; + + PKGCONF_FOREACH_LIST_ENTRY(list->head, iter) + { + n++; + } + + return n; +} + +static const pkgconf_fragment_t * +fragment_at(const pkgconf_list_t *list, size_t index) +{ + const pkgconf_node_t *iter; + size_t i = 0; + + PKGCONF_FOREACH_LIST_ENTRY(list->head, iter) + { + if (i++ == index) + return iter->data; + } + + return NULL; +} + +/* + * Render a fragment list to a newly-allocated C string for assertions. + * Caller frees. + */ +static char * +render_to_string(const pkgconf_list_t *list) +{ + pkgconf_buffer_t buf = PKGCONF_BUFFER_INITIALIZER; + pkgconf_fragment_render_buf(list, &buf, false, NULL, ' '); + + if (pkgconf_buffer_str(&buf) == NULL) + return strdup(""); + + char *out = strdup(pkgconf_buffer_str(&buf)); + pkgconf_buffer_finalize(&buf); + return out; +} + +static void +test_fragment_parse_cflags(void) +{ + pkgconf_client_t *client = test_client_new(); + pkgconf_list_t frags = PKGCONF_LIST_INITIALIZER; + pkgconf_list_t vars = PKGCONF_LIST_INITIALIZER; + + TEST_ASSERT_TRUE(pkgconf_fragment_parse(client, &frags, &vars, "-I/usr/include -DFOO=1", 0)); + TEST_ASSERT_EQ(fragment_count(&frags), 2); + + const pkgconf_fragment_t *first = fragment_at(&frags, 0); + TEST_ASSERT_NONNULL(first); + TEST_ASSERT_EQ(first->type, 'I'); + TEST_ASSERT_STRCMP_EQ(first->data, "/usr/include"); + + pkgconf_fragment_free(&frags); + pkgconf_variable_list_free(&vars); + pkgconf_client_free(client); +} + +static void +test_fragment_parse_libs(void) +{ + pkgconf_client_t *client = test_client_new(); + pkgconf_list_t frags = PKGCONF_LIST_INITIALIZER; + pkgconf_list_t vars = PKGCONF_LIST_INITIALIZER; + + TEST_ASSERT_TRUE(pkgconf_fragment_parse(client, &frags, &vars, "-L/usr/lib -lfoo -lbar", 0)); + TEST_ASSERT_EQ(fragment_count(&frags), 3); + + const pkgconf_fragment_t *f0 = fragment_at(&frags, 0); + const pkgconf_fragment_t *f1 = fragment_at(&frags, 1); + const pkgconf_fragment_t *f2 = fragment_at(&frags, 2); + + TEST_ASSERT_NONNULL(f0); + TEST_ASSERT_NONNULL(f1); + TEST_ASSERT_NONNULL(f2); + + TEST_ASSERT_EQ(f0->type, 'L'); + TEST_ASSERT_STRCMP_EQ(f0->data, "/usr/lib"); + TEST_ASSERT_EQ(f1->type, 'l'); + TEST_ASSERT_STRCMP_EQ(f1->data, "foo"); + TEST_ASSERT_EQ(f2->type, 'l'); + TEST_ASSERT_STRCMP_EQ(f2->data, "bar"); + + pkgconf_fragment_free(&frags); + pkgconf_variable_list_free(&vars); + pkgconf_client_free(client); +} + +static void +test_fragment_parse_empty(void) +{ + pkgconf_client_t *client = test_client_new(); + pkgconf_list_t frags = PKGCONF_LIST_INITIALIZER; + pkgconf_list_t vars = PKGCONF_LIST_INITIALIZER; + + TEST_ASSERT_TRUE(pkgconf_fragment_parse(client, &frags, &vars, "", 0)); + TEST_ASSERT_EQ(fragment_count(&frags), 0); + + pkgconf_fragment_free(&frags); + pkgconf_variable_list_free(&vars); + pkgconf_client_free(client); +} + +static void +test_fragment_add_single(void) +{ + pkgconf_client_t *client = test_client_new(); + pkgconf_list_t frags = PKGCONF_LIST_INITIALIZER; + pkgconf_list_t vars = PKGCONF_LIST_INITIALIZER; + + pkgconf_fragment_add(client, &frags, &vars, "-I/opt/include", 0); + + TEST_ASSERT_EQ(fragment_count(&frags), 1); + + const pkgconf_fragment_t *f = fragment_at(&frags, 0); + TEST_ASSERT_NONNULL(f); + TEST_ASSERT_EQ(f->type, 'I'); + TEST_ASSERT_STRCMP_EQ(f->data, "/opt/include"); + + pkgconf_fragment_free(&frags); + pkgconf_variable_list_free(&vars); + pkgconf_client_free(client); +} + +static void +test_fragment_render_cflags(void) +{ + pkgconf_client_t *client = test_client_new(); + pkgconf_list_t frags = PKGCONF_LIST_INITIALIZER; + pkgconf_list_t vars = PKGCONF_LIST_INITIALIZER; + + pkgconf_fragment_parse(client, &frags, &vars, "-I/usr/include -I/opt/include", 0); + + char *rendered = render_to_string(&frags); + TEST_ASSERT_NONNULL(rendered); + TEST_ASSERT_STRCMP_EQ(rendered, "-I/usr/include -I/opt/include"); + + free(rendered); + pkgconf_fragment_free(&frags); + pkgconf_variable_list_free(&vars); + pkgconf_client_free(client); +} + +static void +test_fragment_render_libs(void) +{ + pkgconf_client_t *client = test_client_new(); + pkgconf_list_t frags = PKGCONF_LIST_INITIALIZER; + pkgconf_list_t vars = PKGCONF_LIST_INITIALIZER; + + pkgconf_fragment_parse(client, &frags, &vars, "-L/usr/lib -lfoo", 0); + + char *rendered = render_to_string(&frags); + TEST_ASSERT_NONNULL(rendered); + TEST_ASSERT_STRCMP_EQ(rendered, "-L/usr/lib -lfoo"); + + free(rendered); + pkgconf_fragment_free(&frags); + pkgconf_variable_list_free(&vars); + pkgconf_client_free(client); +} + +static void +test_fragment_render_empty(void) +{ + pkgconf_list_t frags = PKGCONF_LIST_INITIALIZER; + + char *rendered = render_to_string(&frags); + TEST_ASSERT_NONNULL(rendered); + TEST_ASSERT_EMPTY_STRING(rendered); + + free(rendered); +} + +// Filter predicate: keep only -I (include) fragments. +static bool +filter_only_includes(const pkgconf_client_t *client, const pkgconf_fragment_t *frag, void *data) +{ + (void) client; + (void) data; + return frag->type == 'I'; +} + +// Filter predicate: keep only -l (library name) fragments. +static bool +filter_only_libnames(const pkgconf_client_t *client, const pkgconf_fragment_t *frag, void *data) +{ + (void) client; + (void) data; + return frag->type == 'l'; +} + +// Filter predicate: keep nothing. +static bool +filter_nothing(const pkgconf_client_t *client, const pkgconf_fragment_t *frag, void *data) +{ + (void) client; + (void) frag; + (void) data; + return false; +} + +static void +test_fragment_filter_only_includes(void) +{ + pkgconf_client_t *client = test_client_new(); + pkgconf_list_t src = PKGCONF_LIST_INITIALIZER; + pkgconf_list_t dst = PKGCONF_LIST_INITIALIZER; + pkgconf_list_t vars = PKGCONF_LIST_INITIALIZER; + + pkgconf_fragment_parse(client, &src, &vars, "-I/usr/include -L/usr/lib -lfoo -I/opt/include", 0); + + pkgconf_fragment_filter(client, &dst, &src, filter_only_includes, NULL); + TEST_ASSERT_EQ(fragment_count(&dst), 2); + + const pkgconf_fragment_t *f0 = fragment_at(&dst, 0); + const pkgconf_fragment_t *f1 = fragment_at(&dst, 1); + TEST_ASSERT_NONNULL(f0); + TEST_ASSERT_NONNULL(f1); + TEST_ASSERT_EQ(f0->type, 'I'); + TEST_ASSERT_STRCMP_EQ(f0->data, "/usr/include"); + TEST_ASSERT_EQ(f1->type, 'I'); + TEST_ASSERT_STRCMP_EQ(f1->data, "/opt/include"); + + pkgconf_fragment_free(&dst); + pkgconf_fragment_free(&src); + pkgconf_variable_list_free(&vars); + pkgconf_client_free(client); +} + +static void +test_fragment_filter_only_libnames(void) +{ + pkgconf_client_t *client = test_client_new(); + pkgconf_list_t src = PKGCONF_LIST_INITIALIZER; + pkgconf_list_t dst = PKGCONF_LIST_INITIALIZER; + pkgconf_list_t vars = PKGCONF_LIST_INITIALIZER; + + pkgconf_fragment_parse(client, &src, &vars, "-L/usr/lib -lfoo -lbar -I/usr/include", 0); + + pkgconf_fragment_filter(client, &dst, &src, filter_only_libnames, NULL); + + TEST_ASSERT_EQ(fragment_count(&dst), 2); + + const pkgconf_fragment_t *f0 = fragment_at(&dst, 0); + const pkgconf_fragment_t *f1 = fragment_at(&dst, 1); + TEST_ASSERT_NONNULL(f0); + TEST_ASSERT_NONNULL(f1); + TEST_ASSERT_EQ(f0->type, 'l'); + TEST_ASSERT_STRCMP_EQ(f0->data, "foo"); + TEST_ASSERT_EQ(f1->type, 'l'); + TEST_ASSERT_STRCMP_EQ(f1->data, "bar"); + + pkgconf_fragment_free(&dst); + pkgconf_fragment_free(&src); + pkgconf_variable_list_free(&vars); + pkgconf_client_free(client); +} + +static void +test_fragment_filter_keeps_nothing(void) +{ + pkgconf_client_t *client = test_client_new(); + pkgconf_list_t src = PKGCONF_LIST_INITIALIZER; + pkgconf_list_t dst = PKGCONF_LIST_INITIALIZER; + pkgconf_list_t vars = PKGCONF_LIST_INITIALIZER; + + pkgconf_fragment_parse(client, &src, &vars, "-I/usr/include -lfoo", 0); + + pkgconf_fragment_filter(client, &dst, &src, filter_nothing, NULL); + + TEST_ASSERT_EQ(fragment_count(&dst), 0); + + pkgconf_fragment_free(&dst); + pkgconf_fragment_free(&src); + pkgconf_variable_list_free(&vars); + pkgconf_client_free(client); +} + +static void +test_fragment_has_system_dir_matches(void) +{ + pkgconf_client_t *client = test_client_new(); + pkgconf_list_t frags = PKGCONF_LIST_INITIALIZER; + pkgconf_list_t vars = PKGCONF_LIST_INITIALIZER; + + pkgconf_path_add("/usr/include", &client->filter_includedirs, false); + + pkgconf_fragment_parse(client, &frags, &vars, "-I/usr/include -I/opt/include", 0); + + const pkgconf_fragment_t *system = fragment_at(&frags, 0); + const pkgconf_fragment_t *other = fragment_at(&frags, 1); + TEST_ASSERT_NONNULL(system); + TEST_ASSERT_NONNULL(other); + + TEST_ASSERT_TRUE(pkgconf_fragment_has_system_dir(client, system)); + TEST_ASSERT_FALSE(pkgconf_fragment_has_system_dir(client, other)); + + pkgconf_fragment_free(&frags); + pkgconf_variable_list_free(&vars); + pkgconf_client_free(client); +} + +static void +test_fragment_has_system_dir_libs(void) +{ + pkgconf_client_t *client = test_client_new(); + pkgconf_list_t frags = PKGCONF_LIST_INITIALIZER; + pkgconf_list_t vars = PKGCONF_LIST_INITIALIZER; + + pkgconf_path_add("/usr/lib", &client->filter_libdirs, false); + + pkgconf_fragment_parse(client, &frags, &vars, "-L/usr/lib -L/opt/lib", 0); + + const pkgconf_fragment_t *system = fragment_at(&frags, 0); + const pkgconf_fragment_t *other = fragment_at(&frags, 1); + TEST_ASSERT_NONNULL(system); + TEST_ASSERT_NONNULL(other); + + TEST_ASSERT_TRUE(pkgconf_fragment_has_system_dir(client, system)); + TEST_ASSERT_FALSE(pkgconf_fragment_has_system_dir(client, other)); + + pkgconf_fragment_free(&frags); + pkgconf_variable_list_free(&vars); + pkgconf_client_free(client); +} + +int +main(int argc, char *argv[]) +{ + (void) argc; + const char *basename = pkgconf_path_find_basename(argv[0]); + + TEST_RUN(basename, test_fragment_parse_empty); + TEST_RUN(basename, test_fragment_parse_cflags); + TEST_RUN(basename, test_fragment_parse_libs); + TEST_RUN(basename, test_fragment_add_single); + TEST_RUN(basename, test_fragment_render_empty); + TEST_RUN(basename, test_fragment_render_cflags); + TEST_RUN(basename, test_fragment_render_libs); + TEST_RUN(basename, test_fragment_filter_only_includes); + TEST_RUN(basename, test_fragment_filter_only_libnames); + TEST_RUN(basename, test_fragment_filter_keeps_nothing); + TEST_RUN(basename, test_fragment_has_system_dir_matches); + TEST_RUN(basename, test_fragment_has_system_dir_libs); + + return EXIT_SUCCESS; +} diff --git a/tests/api/test-license.c b/tests/api/test-license.c new file mode 100644 index 000000000000..d77ed21a4c86 --- /dev/null +++ b/tests/api/test-license.c @@ -0,0 +1,311 @@ +/* + * test-license.c + * Tests for the public libpkgconf license API. + * + * SPDX-License-Identifier: pkgconf + * + * Copyright (c) 2026 pkgconf authors (see AUTHORS). + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * This software is provided 'as is' and without any warranty, express or + * implied. In no event shall the authors be liable for any damages arising + * from the use of this software. + */ + +#include "test-api.h" + +static size_t +license_count(const pkgconf_list_t *list) +{ + size_t n = 0; + const pkgconf_node_t *iter; + + PKGCONF_FOREACH_LIST_ENTRY(list->head, iter) + { + n++; + } + + return n; +} + +static char * +render_to_string(pkgconf_client_t *client, const pkgconf_list_t *list) +{ + pkgconf_buffer_t buf = PKGCONF_BUFFER_INITIALIZER; + pkgconf_license_render(client, list, &buf); + + char *out = strdup(pkgconf_buffer_str_or_empty(&buf)); + pkgconf_buffer_finalize(&buf); + return out; +} + +static void +test_license_insert_and_free(void) +{ + pkgconf_client_t *client = test_client_new(); + pkgconf_list_t licenses = PKGCONF_LIST_INITIALIZER; + + pkgconf_license_insert(client, &licenses, PKGCONF_LICENSE_EXPRESSION, "BSD-3-Clause"); + TEST_ASSERT_EQ(license_count(&licenses), 1); + + const pkgconf_license_t *l = licenses.head->data; + TEST_ASSERT_NONNULL(l); + TEST_ASSERT_EQ(l->type, PKGCONF_LICENSE_EXPRESSION); + TEST_ASSERT_STRCMP_EQ(l->data, "BSD-3-Clause"); + + pkgconf_license_free(&licenses); + pkgconf_client_free(client); +} + +static void +test_license_free_empty(void) +{ + pkgconf_list_t licenses = PKGCONF_LIST_INITIALIZER; + + // Freeing an empty list is a no-op. Smoke test. + pkgconf_license_free(&licenses); + + // Smoke test + pkgconf_license_free(NULL); +} + +static void +test_license_evaluate_single(void) +{ + pkgconf_client_t *client = test_client_new(); + pkgconf_list_t licenses = PKGCONF_LIST_INITIALIZER; + + pkgconf_license_evaluate_str(client, &licenses, "BSD-3-Clause", 0); + + TEST_ASSERT_EQ(license_count(&licenses), 1); + const pkgconf_license_t *l = licenses.head->data; + TEST_ASSERT_EQ(l->type, PKGCONF_LICENSE_EXPRESSION); + TEST_ASSERT_STRCMP_EQ(l->data, "BSD-3-Clause"); + + pkgconf_license_free(&licenses); + pkgconf_client_free(client); +} + +static void +test_license_evaluate_or(void) +{ + pkgconf_client_t *client = test_client_new(); + pkgconf_list_t licenses = PKGCONF_LIST_INITIALIZER; + + pkgconf_license_evaluate_str(client, &licenses, "MIT OR ISC", 0); + + TEST_ASSERT_EQ(license_count(&licenses), 3); + + char *rendered = render_to_string(client, &licenses); + TEST_ASSERT_STRCMP_EQ(rendered, "MIT OR ISC"); + free(rendered); + + pkgconf_license_free(&licenses); + pkgconf_client_free(client); +} + +static void +test_license_evaluate_and(void) +{ + pkgconf_client_t *client = test_client_new(); + pkgconf_list_t licenses = PKGCONF_LIST_INITIALIZER; + + pkgconf_license_evaluate_str(client, &licenses, "LGPL-2.1-only AND MIT", 0); + + char *rendered = render_to_string(client, &licenses); + TEST_ASSERT_STRCMP_EQ(rendered, "LGPL-2.1-only AND MIT"); + free(rendered); + + pkgconf_license_free(&licenses); + pkgconf_client_free(client); +} + +static void +test_license_evaluate_multiple_keys_implicit_and(void) +{ + pkgconf_client_t *client = test_client_new(); + pkgconf_list_t licenses = PKGCONF_LIST_INITIALIZER; + + pkgconf_license_evaluate_str(client, &licenses, "BSD-3-Clause", 0); + pkgconf_license_evaluate_str(client, &licenses, "BSD-2-Clause", 0); + + char *rendered = render_to_string(client, &licenses); + TEST_ASSERT_STRCMP_EQ(rendered, "BSD-3-Clause AND BSD-2-Clause"); + free(rendered); + + pkgconf_license_free(&licenses); + pkgconf_client_free(client); +} + +static void +test_license_evaluate_brackets(void) +{ + pkgconf_client_t *client = test_client_new(); + pkgconf_list_t licenses = PKGCONF_LIST_INITIALIZER; + + pkgconf_license_evaluate_str(client, &licenses, "ISC AND (BSD-3-Clause AND BSD-2-Clause)", 0); + + char *rendered = render_to_string(client, &licenses); + TEST_ASSERT_STRCMP_EQ(rendered, "ISC AND (BSD-3-Clause AND BSD-2-Clause)"); + free(rendered); + + pkgconf_license_free(&licenses); + pkgconf_client_free(client); +} + +static void +test_license_evaluate_empty(void) +{ + pkgconf_client_t *client = test_client_new(); + pkgconf_list_t licenses = PKGCONF_LIST_INITIALIZER; + + pkgconf_license_evaluate_str(client, &licenses, "", 0); + TEST_ASSERT_EQ(license_count(&licenses), 0); + + pkgconf_license_free(&licenses); + pkgconf_client_free(client); +} + +static void +test_license_evaluate_sanitizes(void) +{ + pkgconf_client_t *client = test_client_new(); + pkgconf_list_t licenses = PKGCONF_LIST_INITIALIZER; + + /* The sanitiser strips characters outside the allowed set + * (alnum, '-', '+', '(', ')', '.', ':'). A token of pure + * junk should sanitise to empty and be skipped. */ + pkgconf_license_evaluate_str(client, &licenses, "BSD-3-Clause", 0); + + const pkgconf_license_t *l = licenses.head->data; + TEST_ASSERT_STRCMP_EQ(l->data, "BSD-3-Clause"); + + pkgconf_license_free(&licenses); + pkgconf_client_free(client); +} + +static void +test_license_render_empty(void) +{ + pkgconf_client_t *client = test_client_new(); + pkgconf_list_t licenses = PKGCONF_LIST_INITIALIZER; + + char *rendered = render_to_string(client, &licenses); + TEST_ASSERT_EMPTY_STRING(rendered); + free(rendered); + + pkgconf_license_free(&licenses); + pkgconf_client_free(client); +} + +static void +test_license_render_single(void) +{ + pkgconf_client_t *client = test_client_new(); + pkgconf_list_t licenses = PKGCONF_LIST_INITIALIZER; + + pkgconf_license_insert(client, &licenses, PKGCONF_LICENSE_EXPRESSION, "MIT"); + + char *rendered = render_to_string(client, &licenses); + TEST_ASSERT_STRCMP_EQ(rendered, "MIT"); + free(rendered); + + pkgconf_license_free(&licenses); + pkgconf_client_free(client); +} + +static void +test_license_copy_list(void) +{ + pkgconf_client_t *client = test_client_new(); + pkgconf_list_t src = PKGCONF_LIST_INITIALIZER; + pkgconf_list_t dst = PKGCONF_LIST_INITIALIZER; + + pkgconf_license_evaluate_str(client, &src, "MIT OR ISC", 0); + size_t src_count = license_count(&src); + + pkgconf_license_copy_list(client, &dst, &src); + TEST_ASSERT_EQ(license_count(&dst), src_count); + + /* The copy is independent: freeing the source must not affect + * the destination's rendered output. */ + pkgconf_license_free(&src); + + char *rendered = render_to_string(client, &dst); + TEST_ASSERT_STRCMP_EQ(rendered, "MIT OR ISC"); + free(rendered); + + pkgconf_license_free(&dst); + pkgconf_client_free(client); +} + +static void +test_license_evaluate_long_sanitized_token(void) +{ + pkgconf_client_t *client = test_client_new(); + pkgconf_list_t licenses = PKGCONF_LIST_INITIALIZER; + + char token[512]; + token[0] = 'A'; + memset(token + 1, '_', 400); + token[401] = '\0'; + + pkgconf_license_evaluate_str(client, &licenses, token, 0); + + TEST_ASSERT_EQ(license_count(&licenses), 1); + const pkgconf_license_t *l = licenses.head->data; + TEST_ASSERT_EQ(l->type, PKGCONF_LICENSE_EXPRESSION); + TEST_ASSERT_STRCMP_EQ(l->data, "A"); + + pkgconf_license_free(&licenses); + pkgconf_client_free(client); +} + +static void +test_license_evaluate_unterminated_quote(void) +{ + pkgconf_client_t *client = test_client_new(); + pkgconf_list_t licenses = PKGCONF_LIST_INITIALIZER; + + pkgconf_license_evaluate_str(client, &licenses, "\"", 0); + TEST_ASSERT_EQ(license_count(&licenses), 0); + + pkgconf_license_evaluate_str(client, &licenses, "MIT \"unterminated", 0); + TEST_ASSERT_EQ(license_count(&licenses), 0); + + pkgconf_license_evaluate_str(client, &licenses, "\\", 0); + TEST_ASSERT_EQ(license_count(&licenses), 0); + + pkgconf_license_free(&licenses); + pkgconf_client_free(client); +} + +int +main(int argc, char *argv[]) +{ + (void) argc; + const char *basename = pkgconf_path_find_basename(argv[0]); + + TEST_RUN(basename, test_license_insert_and_free); + TEST_RUN(basename, test_license_free_empty); + + TEST_RUN(basename, test_license_evaluate_single); + TEST_RUN(basename, test_license_evaluate_or); + TEST_RUN(basename, test_license_evaluate_and); + TEST_RUN(basename, test_license_evaluate_multiple_keys_implicit_and); + TEST_RUN(basename, test_license_evaluate_brackets); + TEST_RUN(basename, test_license_evaluate_empty); + TEST_RUN(basename, test_license_evaluate_sanitizes); + TEST_RUN(basename, test_license_evaluate_long_sanitized_token); + TEST_RUN(basename, test_license_evaluate_unterminated_quote); + + TEST_RUN(basename, test_license_render_empty); + TEST_RUN(basename, test_license_render_single); + + TEST_RUN(basename, test_license_copy_list); + + return EXIT_SUCCESS; +} diff --git a/tests/api/test-path-utils.c b/tests/api/test-path-utils.c new file mode 100644 index 000000000000..519cadb6f639 --- /dev/null +++ b/tests/api/test-path-utils.c @@ -0,0 +1,119 @@ +/* + * test-path-utils.c + * Tests for libpkgconf internal path utility functions. + * + * SPDX-License-Identifier: pkgconf + * + * Copyright (c) 2025-2026 pkgconf authors (see AUTHORS). + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * This software is provided 'as is' and without any warranty, express or + * implied. In no event shall the authors be liable for any damages arising + * from the use of this software. + */ + +#include <libpkgconf/stdinc.h> +#include <libpkgconf/libpkgconf.h> +#include <libpkgconf/path.h> +#include "test-api.h" + +static void +test_path_find_basename(void) +{ + TEST_ASSERT_STRCMP_EQ(pkgconf_path_find_basename("/usr/lib/pkgconfig/foo.pc"), "foo.pc"); + TEST_ASSERT_STRCMP_EQ(pkgconf_path_find_basename("/usr/lib/pkgconfig"), "pkgconfig"); + TEST_ASSERT_STRCMP_EQ(pkgconf_path_find_basename("foo.pc"), "foo.pc"); + TEST_ASSERT_STRCMP_EQ(pkgconf_path_find_basename("/foo.pc"), "foo.pc"); + TEST_ASSERT_EMPTY_STRING(pkgconf_path_find_basename("/")); + TEST_ASSERT_EMPTY_STRING(pkgconf_path_find_basename("")); + TEST_ASSERT_EMPTY_STRING(pkgconf_path_find_basename("/usr/")); + TEST_ASSERT_EMPTY_STRING(pkgconf_path_find_basename("usr/")); + TEST_ASSERT_STRCMP_EQ(pkgconf_path_find_basename("///usr/lib///pkgconfig///foo.pc"), "foo.pc"); +#ifdef _WIN32 + TEST_ASSERT_STRCMP_EQ(pkgconf_path_find_basename("C:\\lib\\pkgconfig\\foo.pc"), "foo.pc"); + TEST_ASSERT_STRCMP_EQ(pkgconf_path_find_basename("C:/lib/pkgconfig/foo.pc"), "foo.pc"); + TEST_ASSERT_STRCMP_EQ(pkgconf_path_find_basename("C:/lib\\pkgconfig/foo.pc"), "foo.pc"); + TEST_ASSERT_STRCMP_EQ(pkgconf_path_find_basename("C:\\lib/pkgconfig\\foo.pc"), "foo.pc"); +#endif +} + +static void +test_path_trim_basename(void) +{ + pkgconf_buffer_t buf = PKGCONF_BUFFER_INITIALIZER; + + pkgconf_buffer_append(&buf, "/usr/lib/pkgconfig/foo.pc"); + TEST_ASSERT_TRUE(pkgconf_path_trim_basename(&buf)); + TEST_ASSERT_STRCMP_EQ(pkgconf_buffer_str(&buf), "/usr/lib/pkgconfig"); + TEST_ASSERT_TRUE(pkgconf_path_trim_basename(&buf)); + TEST_ASSERT_STRCMP_EQ(pkgconf_buffer_str(&buf), "/usr/lib"); + TEST_ASSERT_TRUE(pkgconf_path_trim_basename(&buf)); + TEST_ASSERT_STRCMP_EQ(pkgconf_buffer_str(&buf), "/usr"); + TEST_ASSERT_TRUE(pkgconf_path_trim_basename(&buf)); + TEST_ASSERT_STRCMP_EQ(pkgconf_buffer_str(&buf), ""); + TEST_ASSERT_FALSE(pkgconf_path_trim_basename(&buf)); + TEST_ASSERT_STRCMP_EQ(pkgconf_buffer_str(&buf), ""); + + pkgconf_buffer_reset(&buf); + pkgconf_buffer_append(&buf, "foo.pc"); + TEST_ASSERT_FALSE(pkgconf_path_trim_basename(&buf)); + TEST_ASSERT_STRCMP_EQ(pkgconf_buffer_str(&buf), "foo.pc"); + + pkgconf_buffer_finalize(&buf); +} + +static void +test_determine_prefix_logic(void) +{ + pkgconf_buffer_t buf = PKGCONF_BUFFER_INITIALIZER; + + // Normal case + pkgconf_buffer_append(&buf, "/opt/foo/lib/pkgconfig/bar.pc"); + TEST_ASSERT_TRUE(pkgconf_path_trim_basename(&buf)); + TEST_ASSERT_STRCMP_EQ(pkgconf_path_find_basename(pkgconf_buffer_str(&buf)), "pkgconfig"); + TEST_ASSERT_TRUE(pkgconf_path_trim_basename(&buf)); + TEST_ASSERT_TRUE(pkgconf_path_trim_basename(&buf)); + TEST_ASSERT_STRCMP_EQ(pkgconf_buffer_str(&buf), "/opt/foo"); + + // Short path: /pkgconfig/foo.pc + pkgconf_buffer_reset(&buf); + pkgconf_buffer_append(&buf, "/pkgconfig/foo.pc"); + TEST_ASSERT_TRUE(pkgconf_path_trim_basename(&buf)); + TEST_ASSERT_STRCMP_EQ(pkgconf_path_find_basename(pkgconf_buffer_str(&buf)), "pkgconfig"); + TEST_ASSERT_TRUE(pkgconf_path_trim_basename(&buf)); // trims pkgconfig, returns true because of / + TEST_ASSERT_FALSE(pkgconf_path_trim_basename(&buf)); // fails to trim further + + // Another short path: lib/pkgconfig/foo.pc + pkgconf_buffer_reset(&buf); + pkgconf_buffer_append(&buf, "lib/pkgconfig/foo.pc"); + TEST_ASSERT_TRUE(pkgconf_path_trim_basename(&buf)); + TEST_ASSERT_STRCMP_EQ(pkgconf_path_find_basename(pkgconf_buffer_str(&buf)), "pkgconfig"); + TEST_ASSERT_TRUE(pkgconf_path_trim_basename(&buf)); + TEST_ASSERT_FALSE(pkgconf_path_trim_basename(&buf)); + + // Trailing slash + pkgconf_buffer_reset(&buf); + pkgconf_buffer_append(&buf, "/usr/lib/pkgconfig/"); + TEST_ASSERT_TRUE(pkgconf_path_trim_basename(&buf)); + TEST_ASSERT_STRCMP_EQ(pkgconf_buffer_str(&buf), "/usr/lib/pkgconfig"); + TEST_ASSERT_TRUE(pkgconf_path_trim_basename(&buf)); + TEST_ASSERT_STRCMP_EQ(pkgconf_buffer_str(&buf), "/usr/lib"); + + pkgconf_buffer_finalize(&buf); +} + +int +main(int argc, char *argv[]) +{ + (void) argc; + const char *basename = pkgconf_path_find_basename(argv[0]); + + TEST_RUN(basename, test_path_find_basename); + TEST_RUN(basename, test_path_trim_basename); + TEST_RUN(basename, test_determine_prefix_logic); + + return EXIT_SUCCESS; +} diff --git a/tests/api/test-tuple.c b/tests/api/test-tuple.c new file mode 100644 index 000000000000..b648abffe3f3 --- /dev/null +++ b/tests/api/test-tuple.c @@ -0,0 +1,258 @@ +/* + * test-tuple.c + * Tests for the public libpkgconf tuple API. + * + * SPDX-License-Identifier: pkgconf + * + * Copyright (c) 2025 pkgconf authors (see AUTHORS). + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * This software is provided 'as is' and without any warranty, express or + * implied. In no event shall the authors be liable for any damages arising + * from the use of this software. + */ + +#include <libpkgconf/stdinc.h> +#include <libpkgconf/libpkgconf.h> +#include "test-api.h" + +static void +test_tuple_add_and_find(void) +{ + pkgconf_client_t *client = test_client_new(); + pkgconf_list_t tuples = PKGCONF_LIST_INITIALIZER; + + /* parse=false means store the value verbatim, no bytecode compile. + * That's the right mode for storing already-evaluated values. */ + pkgconf_tuple_t *t = pkgconf_tuple_add(client, &tuples, "prefix", "/opt/foo", false, 0); + TEST_ASSERT_NONNULL(t); + + const char *found = pkgconf_tuple_find(client, &tuples, "prefix"); + TEST_ASSERT_NONNULL(found); + TEST_ASSERT_STRCMP_EQ(found, "/opt/foo"); + + pkgconf_tuple_free(&tuples); + pkgconf_client_free(client); +} + +static void +test_tuple_find_absent(void) +{ + pkgconf_client_t *client = test_client_new(); + pkgconf_list_t tuples = PKGCONF_LIST_INITIALIZER; + + const char *found = pkgconf_tuple_find(client, &tuples, "nonexistent"); + TEST_ASSERT_EMPTY_STRING(found); + + pkgconf_tuple_free(&tuples); + pkgconf_client_free(client); +} + +static void +test_tuple_add_multiple(void) +{ + pkgconf_client_t *client = test_client_new(); + pkgconf_list_t tuples = PKGCONF_LIST_INITIALIZER; + + pkgconf_tuple_add(client, &tuples, "prefix", "/usr", false, 0); + pkgconf_tuple_add(client, &tuples, "exec_prefix", "/usr/local", false, 0); + pkgconf_tuple_add(client, &tuples, "libdir", "/usr/lib", false, 0); + + TEST_ASSERT_STRCMP_EQ(pkgconf_tuple_find(client, &tuples, "prefix"), "/usr"); + TEST_ASSERT_STRCMP_EQ(pkgconf_tuple_find(client, &tuples, "exec_prefix"), "/usr/local"); + TEST_ASSERT_STRCMP_EQ(pkgconf_tuple_find(client, &tuples, "libdir"), "/usr/lib"); + TEST_ASSERT_EMPTY_STRING(pkgconf_tuple_find(client, &tuples, "datadir")); + + pkgconf_tuple_free(&tuples); + pkgconf_client_free(client); +} + +static void +test_tuple_global_add_and_find(void) +{ + pkgconf_client_t *client = test_client_new(); + + pkgconf_tuple_add_global(client, "PKG_TEST_KEY", "test_value"); + + const char *found = pkgconf_tuple_find_global(client, "PKG_TEST_KEY"); + TEST_ASSERT_NONNULL(found); + TEST_ASSERT_STRCMP_EQ(found, "test_value"); + + pkgconf_tuple_free_global(client); + pkgconf_client_free(client); +} + +static void +test_tuple_global_find_absent(void) +{ + pkgconf_client_t *client = test_client_new(); + + const char *found = pkgconf_tuple_find_global(client, "DOES_NOT_EXIST"); + TEST_ASSERT_EMPTY_STRING(found); + + pkgconf_client_free(client); +} + +static void +test_tuple_define_global_kv_form(void) +{ + pkgconf_client_t *client = test_client_new(); + + /* This is the exact path --define-variable=KEY=VALUE takes + * pkgconf_tuple_define_global parses the "key=value" form and inserts it as a global tuple. */ + pkgconf_tuple_define_global(client, "myvar=myvalue"); + + const char *found = pkgconf_tuple_find_global(client, "myvar"); + TEST_ASSERT_NONNULL(found); + TEST_ASSERT_STRCMP_EQ(found, "myvalue"); + + pkgconf_tuple_free_global(client); + pkgconf_client_free(client); +} + +static void +test_tuple_define_global_with_equals_in_value(void) +{ + pkgconf_client_t *client = test_client_new(); + + // Only the first '=' should split key from value; subsequent '=' characters belong to the value. + pkgconf_tuple_define_global(client, "CFLAGS=-DFOO=bar"); + + const char *found = pkgconf_tuple_find_global(client, "CFLAGS"); + TEST_ASSERT_NONNULL(found); + TEST_ASSERT_STRCMP_EQ(found, "-DFOO=bar"); + + pkgconf_tuple_free_global(client); + pkgconf_client_free(client); +} + +static void +test_tuple_global_multiple(void) +{ + pkgconf_client_t *client = test_client_new(); + + pkgconf_tuple_define_global(client, "a=1"); + pkgconf_tuple_define_global(client, "b=2"); + pkgconf_tuple_define_global(client, "c=3"); + + TEST_ASSERT_STRCMP_EQ(pkgconf_tuple_find_global(client, "a"), "1"); + TEST_ASSERT_STRCMP_EQ(pkgconf_tuple_find_global(client, "b"), "2"); + TEST_ASSERT_STRCMP_EQ(pkgconf_tuple_find_global(client, "c"), "3"); + + pkgconf_tuple_free_global(client); + pkgconf_client_free(client); +} + +static void +test_tuple_global_free_resets(void) +{ + pkgconf_client_t *client = test_client_new(); + + pkgconf_tuple_define_global(client, "temp=value"); + TEST_ASSERT_NONNULL(pkgconf_tuple_find_global(client, "temp")); + + pkgconf_tuple_free_global(client); + TEST_ASSERT_EMPTY_STRING(pkgconf_tuple_find_global(client, "temp")); + + pkgconf_client_free(client); +} + +static void +test_tuple_free_empty(void) +{ + pkgconf_list_t tuples = PKGCONF_LIST_INITIALIZER; + + // Freeing an empty list should be a no-op. Mostly an ASan/leak check smoke test. + pkgconf_tuple_free(&tuples); +} + +static void +test_tuple_define_variable_end_to_end(void) +{ + pkgconf_client_t *client = test_client_new(); + pkgconf_list_t vars = PKGCONF_LIST_INITIALIZER; + bool saw_sysroot = false; + + pkgconf_tuple_define_global(client, "myprefix=/opt/custom"); + + char *out = pkgconf_bytecode_eval_str(client, &vars, "-I${myprefix}/include", &saw_sysroot); + + TEST_ASSERT_NONNULL(out); + TEST_ASSERT_STRCMP_EQ(out, "-I/opt/custom/include"); + + free(out); + pkgconf_variable_list_free(&vars); + pkgconf_tuple_free_global(client); + pkgconf_client_free(client); +} + +static void +test_tuple_define_variable_overrides_local(void) +{ + pkgconf_client_t *client = test_client_new(); + pkgconf_list_t vars = PKGCONF_LIST_INITIALIZER; + bool saw_sysroot = false; + + pkgconf_variable_t *v = pkgconf_variable_get_or_create(&vars, "prefix"); + TEST_ASSERT_NONNULL(v); + pkgconf_buffer_reset(&v->bcbuf); + pkgconf_bytecode_compile(&v->bcbuf, "/usr"); + pkgconf_bytecode_from_buffer(&v->bc, &v->bcbuf); + + // Simulate user passing --define-variable=prefix=/custom. + pkgconf_tuple_define_global(client, "prefix=/custom"); + + char *out = pkgconf_bytecode_eval_str(client, &vars, "${prefix}/lib", &saw_sysroot); + + TEST_ASSERT_NONNULL(out); + TEST_ASSERT_STRCMP_EQ(out, "/custom/lib"); + + free(out); + pkgconf_variable_list_free(&vars); + pkgconf_tuple_free_global(client); + pkgconf_client_free(client); +} + +static void +test_tuple_escaped_quote(void) +{ + pkgconf_client_t *client = test_client_new(); + pkgconf_list_t tuples = PKGCONF_LIST_INITIALIZER; + + // A double-quoted value containing an escaped double-quote + pkgconf_tuple_t *t = pkgconf_tuple_add(client, &tuples, "key", "\"a\\\"b\"", true, 0); + TEST_ASSERT_NONNULL(t); + + const char *found = pkgconf_tuple_find(client, &tuples, "key"); + TEST_ASSERT_NONNULL(found); + TEST_ASSERT_STRCMP_EQ(found, "a\"b"); + + pkgconf_tuple_free(&tuples); + pkgconf_client_free(client); +} + +int +main(int argc, char *argv[]) +{ + (void) argc; + const char *basename = pkgconf_path_find_basename(argv[0]); + + TEST_RUN(basename, test_tuple_add_and_find); + TEST_RUN(basename, test_tuple_find_absent); + TEST_RUN(basename, test_tuple_add_multiple); + TEST_RUN(basename, test_tuple_free_empty); + TEST_RUN(basename, test_tuple_global_add_and_find); + TEST_RUN(basename, test_tuple_global_find_absent); + TEST_RUN(basename, test_tuple_define_global_kv_form); + TEST_RUN(basename, test_tuple_define_global_with_equals_in_value); + TEST_RUN(basename, test_tuple_global_multiple); + TEST_RUN(basename, test_tuple_global_free_resets); + TEST_RUN(basename, test_tuple_define_variable_end_to_end); + TEST_RUN(basename, test_tuple_define_variable_overrides_local); + TEST_RUN(basename, test_tuple_escaped_quote); + + return EXIT_SUCCESS; +} diff --git a/tests/api/test-variable.c b/tests/api/test-variable.c new file mode 100644 index 000000000000..ec65df3ae5a8 --- /dev/null +++ b/tests/api/test-variable.c @@ -0,0 +1,247 @@ +/* + * test-variable.c + * Tests for the public libpkgconf variable API. + * + * SPDX-License-Identifier: pkgconf + * + * Copyright (c) 2025 pkgconf authors (see AUTHORS). + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * This software is provided 'as is' and without any warranty, express or + * implied. In no event shall the authors be liable for any damages arising + * from the use of this software. + */ + +#include <libpkgconf/stdinc.h> +#include <libpkgconf/libpkgconf.h> +#include "test-api.h" + +/* + * Install a value on a variable by compiling it as bytecode. + * Mirrors what the parser does when it reads a .pc field. + */ +static void +seed_variable(pkgconf_list_t *vars, const char *key, const char *value) +{ + pkgconf_variable_t *v = pkgconf_variable_get_or_create(vars, key); + TEST_ASSERT_NONNULL(v); + + pkgconf_buffer_reset(&v->bcbuf); + pkgconf_bytecode_compile(&v->bcbuf, value); + pkgconf_bytecode_from_buffer(&v->bc, &v->bcbuf); +} + +static void +test_variable_new_and_free(void) +{ + pkgconf_variable_t *v = pkgconf_variable_new("prefix"); + + TEST_ASSERT_NONNULL(v); + TEST_ASSERT_STRCMP_EQ(v->key, "prefix"); + + pkgconf_variable_free(v); +} + +static void +test_variable_get_or_create_creates(void) +{ + pkgconf_list_t vars = PKGCONF_LIST_INITIALIZER; + + pkgconf_variable_t *v = pkgconf_variable_get_or_create(&vars, "prefix"); + TEST_ASSERT_NONNULL(v); + TEST_ASSERT_STRCMP_EQ(v->key, "prefix"); + + pkgconf_variable_list_free(&vars); +} + +static void +test_variable_get_or_create_returns_existing(void) +{ + pkgconf_list_t vars = PKGCONF_LIST_INITIALIZER; + + pkgconf_variable_t *first = pkgconf_variable_get_or_create(&vars, "libdir"); + TEST_ASSERT_NONNULL(first); + + // A second call with the same key should return the same object, not create a duplicate. + pkgconf_variable_t *second = pkgconf_variable_get_or_create(&vars, "libdir"); + TEST_ASSERT_NONNULL(second); + TEST_ASSERT_EQ(first, second); + + pkgconf_variable_list_free(&vars); +} + +static void +test_variable_find_present(void) +{ + pkgconf_list_t vars = PKGCONF_LIST_INITIALIZER; + + pkgconf_variable_t *created = pkgconf_variable_get_or_create(&vars, "prefix"); + TEST_ASSERT_NONNULL(created); + + pkgconf_variable_t *found = pkgconf_variable_find(&vars, "prefix"); + TEST_ASSERT_NONNULL(found); + TEST_ASSERT_EQ(created, found); + + pkgconf_variable_list_free(&vars); +} + +static void +test_variable_find_absent(void) +{ + pkgconf_list_t vars = PKGCONF_LIST_INITIALIZER; + + pkgconf_variable_t *found = pkgconf_variable_find(&vars, "nonexistent"); + TEST_ASSERT_NULL(found); + + pkgconf_variable_list_free(&vars); +} + +static void +test_variable_find_among_many(void) +{ + pkgconf_list_t vars = PKGCONF_LIST_INITIALIZER; + + pkgconf_variable_get_or_create(&vars, "prefix"); + pkgconf_variable_get_or_create(&vars, "exec_prefix"); + pkgconf_variable_get_or_create(&vars, "libdir"); + pkgconf_variable_get_or_create(&vars, "includedir"); + + TEST_ASSERT_NONNULL(pkgconf_variable_find(&vars, "prefix")); + TEST_ASSERT_NONNULL(pkgconf_variable_find(&vars, "exec_prefix")); + TEST_ASSERT_NONNULL(pkgconf_variable_find(&vars, "libdir")); + TEST_ASSERT_NONNULL(pkgconf_variable_find(&vars, "includedir")); + TEST_ASSERT_NULL(pkgconf_variable_find(&vars, "notpresent")); + + pkgconf_variable_list_free(&vars); +} + +static void +test_variable_delete(void) +{ + pkgconf_list_t vars = PKGCONF_LIST_INITIALIZER; + + pkgconf_variable_t *v = pkgconf_variable_get_or_create(&vars, "prefix"); + TEST_ASSERT_NONNULL(v); + TEST_ASSERT_NONNULL(pkgconf_variable_find(&vars, "prefix")); + + pkgconf_variable_delete(&vars, v); + TEST_ASSERT_NULL(pkgconf_variable_find(&vars, "prefix")); + + pkgconf_variable_list_free(&vars); +} + +static void +test_variable_eval_str_plain(void) +{ + pkgconf_client_t *client = test_client_new(); + pkgconf_list_t vars = PKGCONF_LIST_INITIALIZER; + bool saw_sysroot = false; + + seed_variable(&vars, "version", "1.2.3"); + + pkgconf_variable_t *v = pkgconf_variable_find(&vars, "version"); + TEST_ASSERT_NONNULL(v); + + char *out = pkgconf_variable_eval_str(client, &vars, v, &saw_sysroot); + TEST_ASSERT_NONNULL(out); + TEST_ASSERT_STRCMP_EQ(out, "1.2.3"); + + free(out); + pkgconf_variable_list_free(&vars); + pkgconf_client_free(client); +} + +static void +test_variable_eval_str_with_reference(void) +{ + pkgconf_client_t *client = test_client_new(); + pkgconf_list_t vars = PKGCONF_LIST_INITIALIZER; + bool saw_sysroot = false; + + // Standard pkg-config layout: libdir is derived from prefix. + seed_variable(&vars, "prefix", "/opt/foo"); + seed_variable(&vars, "libdir", "${prefix}/lib"); + + pkgconf_variable_t *libdir = pkgconf_variable_find(&vars, "libdir"); + TEST_ASSERT_NONNULL(libdir); + + char *out = pkgconf_variable_eval_str(client, &vars, libdir, &saw_sysroot); + TEST_ASSERT_NONNULL(out); + TEST_ASSERT_STRCMP_EQ(out, "/opt/foo/lib"); + + free(out); + pkgconf_variable_list_free(&vars); + pkgconf_client_free(client); +} + +static void +test_variable_eval_str_chained(void) +{ + pkgconf_client_t *client = test_client_new(); + pkgconf_list_t vars = PKGCONF_LIST_INITIALIZER; + bool saw_sysroot = false; + + seed_variable(&vars, "prefix", "/usr/local"); + seed_variable(&vars, "exec_prefix", "${prefix}"); + seed_variable(&vars, "includedir", "${exec_prefix}/include"); + + pkgconf_variable_t *includedir = pkgconf_variable_find(&vars, "includedir"); + TEST_ASSERT_NONNULL(includedir); + + char *out = pkgconf_variable_eval_str(client, &vars, includedir, &saw_sysroot); + TEST_ASSERT_NONNULL(out); + TEST_ASSERT_STRCMP_EQ(out, "/usr/local/include"); + + free(out); + pkgconf_variable_list_free(&vars); + pkgconf_client_free(client); +} + +static void +test_variable_list_free_handles_empty(void) +{ + pkgconf_list_t vars = PKGCONF_LIST_INITIALIZER; + + // Freeing an empty list should be a no-op and not crash. Mostly an ASan/leak smoke test. + pkgconf_variable_list_free(&vars); +} + +static void +test_variable_list_free_handles_many(void) +{ + pkgconf_list_t vars = PKGCONF_LIST_INITIALIZER; + + /* Add a mix of bare and value-carrying variables, then free the whole list at once. + * Mostly an ASan/leak smoke test. */ + pkgconf_variable_get_or_create(&vars, "a"); + seed_variable(&vars, "b", "/path/b"); + pkgconf_variable_get_or_create(&vars, "c"); + seed_variable(&vars, "d", "${b}/sub"); + + pkgconf_variable_list_free(&vars); +} + +int +main(int argc, char *argv[]) +{ + (void) argc; + const char *basename = pkgconf_path_find_basename(argv[0]); + + TEST_RUN(basename, test_variable_new_and_free); + TEST_RUN(basename, test_variable_get_or_create_creates); + TEST_RUN(basename, test_variable_get_or_create_returns_existing); + TEST_RUN(basename, test_variable_find_present); + TEST_RUN(basename, test_variable_find_absent); + TEST_RUN(basename, test_variable_find_among_many); + TEST_RUN(basename, test_variable_delete); + TEST_RUN(basename, test_variable_eval_str_plain); + TEST_RUN(basename, test_variable_eval_str_with_reference); + TEST_RUN(basename, test_variable_eval_str_chained); + TEST_RUN(basename, test_variable_list_free_handles_empty); + TEST_RUN(basename, test_variable_list_free_handles_many); + + return EXIT_SUCCESS; +} diff --git a/tests/basic.sh b/tests/basic.sh deleted file mode 100755 index 8debb32f2b38..000000000000 --- a/tests/basic.sh +++ /dev/null @@ -1,391 +0,0 @@ -#!/usr/bin/env atf-sh - -. $(atf_get_srcdir)/test_env.sh - -tests_init \ - noargs \ - libs \ - libs_cflags \ - libs_cflags_version \ - libs_cflags_version_multiple \ - libs_cflags_version_alt \ - libs_cflags_version_different \ - libs_cflags_version_different_bad \ - libs_env \ - exists_nonexitent \ - nonexitent \ - exists_version \ - exists_version_bad \ - exists_version_bad2 \ - exists_version_bad3 \ - exists \ - exists2 \ - exists3 \ - exists_version_alt \ - exists_cflags \ - exists_cflags_env \ - uninstalled_bad \ - uninstalled \ - libs_intermediary \ - libs_circular1 \ - libs_circular2 \ - libs_circular_directpc \ - libs_static \ - libs_static_ordering \ - libs_metapackage \ - license_isc \ - license_noassertion \ - modversion_noflatten \ - pkg_config_path \ - nolibs \ - nocflags \ - arbitary_path \ - with_path \ - relocatable \ - single_depth_selectors \ - print_variables_env \ - variable_env \ - variable_no_recurse - -noargs_body() -{ - export PKG_CONFIG_PATH="${selfdir}/lib1" - atf_check -s exit:1 -e ignore pkgconf -} - -libs_body() -{ - export PKG_CONFIG_PATH="${selfdir}/lib1" - atf_check \ - -o inline:"-L/test/lib -lfoo\n" \ - pkgconf --libs foo -} - -libs_cflags_body() -{ - export PKG_CONFIG_PATH="${selfdir}/lib1" - atf_check \ - -o inline:"-fPIC -I/test/include/foo -L/test/lib -lfoo\n" \ - pkgconf --cflags --libs foo -} - -atf_test_case basic_libs_cflags_version -libs_cflags_version_body() -{ - export PKG_CONFIG_PATH="${selfdir}/lib1" - atf_check \ - -o inline:"-fPIC -I/test/include/foo -L/test/lib -lfoo\n" \ - pkgconf --cflags --libs 'foo > 1.2' -} - -libs_cflags_version_multiple_body() -{ - export PKG_CONFIG_PATH="${selfdir}/lib1" - atf_check \ - -o inline:"-fPIC -I/test/include/foo -L/test/lib -lbar -lfoo\n" \ - pkgconf --cflags --libs 'foo > 1.2 bar >= 1.3' -} - -libs_cflags_version_multiple_coma_body() -{ - export PKG_CONFIG_PATH="${selfdir}/lib1" - atf_check \ - -o inline:"-fPIC -I/test/include/foo -L/test/lib -lbar -lfoo\n" \ - pkgconf --cflags --libs 'foo > 1.2,bar >= 1.3' -} - -libs_cflags_version_alt_body() -{ - export PKG_CONFIG_PATH="${selfdir}/lib1" - atf_check \ - -o inline:"-fPIC -I/test/include/foo -L/test/lib -lfoo\n" \ - pkgconf --cflags --libs 'foo' '>' '1.2' -} - -libs_cflags_version_different_body() -{ - export PKG_CONFIG_PATH="${selfdir}/lib1" - atf_check \ - -o inline:"-fPIC -I/test/include/foo -L/test/lib -lfoo\n" \ - pkgconf --cflags --libs 'foo' '!=' '1.3.0' -} - -atf_test_case basic_libs_cflags_version_different_bad -libs_cflags_version_different_bad_body() -{ - export PKG_CONFIG_PATH="${selfdir}/lib1" - atf_check \ - -s exit:1 \ - -e inline:"Package dependency requirement 'foo != 1.2.3' could not be satisfied.\nPackage 'foo' has version '1.2.3', required version is '!= 1.2.3'\n" \ - pkgconf --cflags --libs 'foo' '!=' '1.2.3' -} - -exists_nonexitent_body() -{ - export PKG_CONFIG_PATH="${selfdir}/lib1" - atf_check \ - -s exit:1 \ - pkgconf --exists nonexistant -} - -nonexitent_body() -{ - export PKG_CONFIG_PATH="${selfdir}/lib1" - atf_check \ - -s exit:1 \ - pkgconf nonexistant -} - -exists_version_body() -{ - export PKG_CONFIG_PATH="${selfdir}/lib1" - atf_check \ - pkgconf --exists 'foo > 1.2' -} - -exists_version_bad_body() -{ - export PKG_CONFIG_PATH="${selfdir}/lib1" - atf_check \ - -s exit:1 \ - pkgconf --exists 'foo > 1.2.3' -} - -exists_version_alt_body() -{ - export PKG_CONFIG_PATH="${selfdir}/lib1" - atf_check \ - pkgconf --exists 'foo' '>' '1.2' -} - -uninstalled_bad_body() -{ - export PKG_CONFIG_PATH="${selfdir}/lib1" - atf_check \ - -s exit:1 \ - pkgconf --uninstalled 'foo' -} - -uninstalled_body() -{ - export PKG_CONFIG_PATH="${selfdir}/lib1" - atf_check \ - pkgconf --uninstalled 'omg' -} - -exists_version_bad2_body() -{ - export PKG_CONFIG_PATH="${selfdir}/lib1" - atf_check \ - -s exit:1 \ - pkgconf --exists 'foo >= ' -} - -exists_version_bad3_body() -{ - export PKG_CONFIG_PATH="${selfdir}/lib1" - atf_check \ - -s exit:1 \ - pkgconf --exists 'tilde >= 1.0.0' -} - -exists_body() -{ - export PKG_CONFIG_PATH="${selfdir}/lib1" - atf_check \ - pkgconf --exists 'tilde = 1.0.0~rc1' -} - -exists2_body() -{ - export PKG_CONFIG_PATH="${selfdir}/lib1" - atf_check \ - pkgconf --exists 'tilde <= 1.0.0' -} - -exists3_body() -{ - export PKG_CONFIG_PATH="${selfdir}/lib1" - atf_check \ - pkgconf --exists '' 'foo' -} - -libs_intermediary_body() -{ - export PKG_CONFIG_PATH="${selfdir}/lib1" - atf_check \ - -o inline:"-lintermediary-1 -lintermediary-2 -lfoo -lbar -lbaz\n" \ - pkgconf --libs intermediary-1 intermediary-2 -} - -libs_circular2_body() -{ - export PKG_CONFIG_PATH="${selfdir}/lib1" - atf_check \ - -o inline:"circular-1: breaking circular reference (circular-1 -> circular-2 -> circular-1)\n" \ - pkgconf circular-2 --validate -} - -libs_circular1_body() -{ - export PKG_CONFIG_PATH="${selfdir}/lib1" - atf_check \ - -o inline:"circular-3: breaking circular reference (circular-3 -> circular-1 -> circular-3)\n" \ - pkgconf circular-1 --validate -} - -libs_circular_directpc_body() -{ - atf_check \ - -o inline:"-lcircular-3 -lcircular-1 -lcircular-2\n" \ - pkgconf --libs ${selfdir}/lib1/circular-3.pc -} - -libs_static_body() -{ - export PKG_CONFIG_PATH="${selfdir}/lib1" - atf_check \ - -o inline:"/libfoo.a -pthread\n" \ - pkgconf --libs static-archive-libs -} - -libs_static_ordering_body() -{ - export PKG_CONFIG_PATH="${selfdir}/lib1" - atf_check \ - -o inline:"-L/test/lib -lbar -lfoo\n" \ - pkgconf --libs foo bar -} - -libs_metapackage_body() -{ - export PKG_CONFIG_PATH="${selfdir}/lib1" - atf_check \ - -o inline:"-L/test/lib -lbar -lfoo\n" \ - pkgconf --static --libs metapackage-3 -} - -pkg_config_path_body() -{ - export PKG_CONFIG_PATH="${selfdir}/lib1${PATH_SEP}${selfdir}/lib2" - atf_check \ - -o inline:"-L/test/lib -lfoo\n" \ - pkgconf --libs foo - atf_check \ - -o inline:"-L/test/lib -lbar -lfoo\n" \ - pkgconf --libs bar -} - -with_path_body() -{ - atf_check \ - -o inline:"-L/test/lib -lfoo\n" \ - pkgconf --with-path=${selfdir}/lib1 --with-path=${selfdir}/lib2 --libs foo - atf_check \ - -o inline:"-L/test/lib -lbar -lfoo\n" \ - pkgconf --with-path=${selfdir}/lib1 --with-path=${selfdir}/lib2 --libs bar -} - -nolibs_body() -{ - export PKG_CONFIG_PATH="${selfdir}/lib1" - atf_check \ - -o inline:"\n" \ - pkgconf --libs nolib -} - -nocflags_body() -{ - export PKG_CONFIG_PATH="${selfdir}/lib1" - atf_check \ - -o inline:"\n" \ - pkgconf --cflags nocflag -} - -arbitary_path_body() -{ - cp ${selfdir}/lib1/foo.pc . - atf_check \ - -o inline:"-L/test/lib -lfoo\n" \ - pkgconf --libs foo.pc -} - -relocatable_body() -{ - basedir=$(pkgconf --relocate ${selfdir}) - atf_check \ - -o inline:"${basedir}/lib-relocatable\n" \ - pkgconf --define-prefix --variable=prefix ${basedir}/lib-relocatable/lib/pkgconfig/foo.pc -} - -single_depth_selectors_body() -{ - export PKG_CONFIG_MAXIMUM_TRAVERSE_DEPTH=1 - atf_check \ - -o inline:"foo\n" \ - pkgconf --with-path=${selfdir}/lib3 --print-requires bar -} - -license_isc_body() -{ - atf_check \ - -o inline:"foo: ISC\n" \ - pkgconf --with-path=${selfdir}/lib1 --license foo -} - -license_noassertion_body() -{ - atf_check \ - -o inline:"bar: NOASSERTION\nfoo: ISC\n" \ - pkgconf --with-path=${selfdir}/lib1 --license bar -} - -modversion_noflatten_body() -{ - atf_check \ - -o inline:"1.3\n" \ - pkgconf --with-path=${selfdir}/lib1 --modversion bar -} - -exists_cflags_body() -{ - atf_check \ - -o inline:"-DHAVE_FOO\n" \ - pkgconf --with-path=${selfdir}/lib1 --cflags --exists-cflags --fragment-filter=D foo -} - -exists_cflags_env_body() -{ - atf_check \ - -o inline:"FOO_CFLAGS='-DHAVE_FOO'\n" \ - pkgconf --with-path=${selfdir}/lib1 --cflags --exists-cflags --fragment-filter=D --env=FOO foo -} - -libs_env_body() -{ - atf_check \ - -o inline:"FOO_LIBS='-L/test/lib -lfoo'\n" \ - pkgconf --with-path=${selfdir}/lib1 --libs --env=FOO foo -} - -print_variables_env_body() -{ - atf_check \ - -o inline:"FOO_CFLAGS='-fPIC -I/test/include/foo'\nFOO_LIBS='-L/test/lib -lfoo'\nFOO_INCLUDEDIR='/test/include'\nFOO_LIBDIR='/test/lib'\nFOO_EXEC_PREFIX='/test'\nFOO_PREFIX='/test'\nFOO_PCFILEDIR='${selfdir}/lib1'\n" \ - pkgconf --with-path=${selfdir}/lib1 --env=FOO --print-variables --cflags --libs foo - -} - -variable_env_body() -{ - atf_check \ - -o inline:"FOO_INCLUDEDIR='/test/include'\n" \ - pkgconf --with-path=${selfdir}/lib1 --env=FOO --variable=includedir foo -} - -variable_no_recurse_body() -{ - atf_check \ - -o inline:"/test/include\n" \ - pkgconf --with-path=${selfdir}/lib1 --variable=includedir bar -} diff --git a/tests/builtins.sh b/tests/builtins.sh deleted file mode 100755 index cbdea37e0c5f..000000000000 --- a/tests/builtins.sh +++ /dev/null @@ -1,68 +0,0 @@ -#!/usr/bin/env atf-sh - -. $(atf_get_srcdir)/test_env.sh - -tests_init \ - modversion \ - variable \ - define_variable \ - global_variable - -modversion_body() -{ - export PKG_CONFIG_PATH="${selfdir}/lib1" - atf_check \ - -o inline:"1.0.1 \n" \ - pkgconf --modversion pkg-config -} - -variable_body() -{ - export PKG_CONFIG_PATH="${selfdir}/lib1" - atf_check \ - -o inline:"/test \n" \ - pkgconf --variable=prefix foo -} - -define_variable_body() -{ - export PKG_CONFIG_PATH="${selfdir}/lib1" - atf_check \ - -o inline:"/test2 \n" \ - pkgconf --define-variable=prefix=/test2 --variable=prefix foo -} - -global_variable_body() -{ - export PKG_CONFIG_PATH="${selfdir}/lib1" - atf_check \ - -o inline:"${selfdir}/lib1 \n" - pkgconf --exists -foo -} - -argv_parse_3_body() -{ - export PKG_CONFIG_PATH="${selfdir}/lib1" - atf_check \ - -o inline:"-llib-1 -pthread /test/lib/lib2.so \n" \ - pkgconf --libs argv-parse-3 -} - -tilde_quoting_body() -{ - export PKG_CONFIG_PATH="${selfdir}/lib1" - atf_check \ - -o inline:"-L~ -ltilde \n" \ - pkgconf --libs tilde-quoting - atf_check \ - -o inline:"-I~ \n" \ - pkgconf --cflags tilde-quoting -} - -paren_quoting_body() -{ - export PKG_CONFIG_PATH="${selfdir}/lib1" - atf_check \ - -o inline:"-L\$(libdir) -ltilde \n" \ - pkgconf --libs paren-quoting -} diff --git a/tests/conflicts.sh b/tests/conflicts.sh deleted file mode 100755 index da6396f6b42c..000000000000 --- a/tests/conflicts.sh +++ /dev/null @@ -1,23 +0,0 @@ -#!/usr/bin/env atf-sh - -. $(atf_get_srcdir)/test_env.sh - -tests_init \ - libs \ - ignore - -libs_body() -{ - export PKG_CONFIG_PATH="${selfdir}/lib1" - atf_check \ - -o inline:"-L/test/lib -lconflicts\n" \ - pkgconf --libs conflicts -} - -ignore_body() -{ - export PKG_CONFIG_PATH="${selfdir}/lib1" - atf_check \ - -o inline:"-L/test/lib -lconflicts\n" \ - pkgconf --ignore-conflicts --libs conflicts -} diff --git a/tests/framework.sh b/tests/framework.sh deleted file mode 100755 index 367692335746..000000000000 --- a/tests/framework.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/usr/bin/env atf-sh - -. $(atf_get_srcdir)/test_env.sh - -tests_init \ - libs - -libs_body() -{ - export PKG_CONFIG_PATH="${selfdir}/lib1" - atf_check \ - -o inline:"-F/test/lib -framework framework-1\n" \ - pkgconf --libs framework-1 - atf_check \ - -o inline:"-F/test/lib -framework framework-2 -framework framework-1\n" \ - pkgconf --libs framework-2 - atf_check \ - -o inline:"-F/test/lib -framework framework-2 -framework framework-1\n" \ - pkgconf --libs framework-1 framework-2 -} diff --git a/tests/lib-sbom-files/basic-spdx-base-id.json b/tests/lib-sbom-files/basic-spdx-base-id.json new file mode 100644 index 000000000000..f9c67b9b9cfb --- /dev/null +++ b/tests/lib-sbom-files/basic-spdx-base-id.json @@ -0,0 +1,90 @@ +{ + "@context": "https://spdx.org/rdf/3.0.1/spdx-context.jsonld", + "@graph": [ + { + "type": "Agent", + "creationInfo": "_:creationinfo_1", + "spdxId": "https://distfiles.ariadne.space/pkgconf/Agent/default", + "name": "Default" + }, + { + "type": "CreationInfo", + "@id": "_:creationinfo_1", + "created": "test", + "createdBy": [ + "https://distfiles.ariadne.space/pkgconf/Agent/default" + ], + "specVersion": "3.0.1" + }, + { + "type": "simplelicensing_LicenseExpression", + "creationInfo": "_:creationinfo_1", + "spdxId": "https://distfiles.ariadne.space/pkgconf/simplelicensing_LicenseExpression/BSD-4-Clause", + "simplelicensing_licenseExpression": "BSD-4-Clause" + }, + { + "type": "software_Sbom", + "creationInfo": "_:creationinfo_1", + "spdxId": "https://distfiles.ariadne.space/pkgconf/software_Sbom/test3", + "software_sbomType": [ + "build" + ], + "rootElement": [ + "https://distfiles.ariadne.space/pkgconf/Package/test3" + ], + "element": [ + "https://distfiles.ariadne.space/pkgconf/Relationship/test3/hasDeclaredLicense", + "https://distfiles.ariadne.space/pkgconf/Relationship/test3/hasConcludedLicense" + ] + }, + { + "type": "software_Package", + "creationInfo": "_:creationinfo_1", + "spdxId": "https://distfiles.ariadne.space/pkgconf/Package/test3", + "name": "test3", + "originatedBy": [ + "https://distfiles.ariadne.space/pkgconf/Agent/default" + ], + "software_copyrightText": "Test3 copyright text", + "software_homePage": "https://github.com/pkgconf/pkgconf/", + "software_downloadLocation": "https://github.com/pkgconf/pkgconf/archive/refs/tags/pkgconf-2.5.1.tar.gz", + "software_packageVersion": "3.0.0" + }, + { + "type": "Relationship", + "creationInfo": "_:creationinfo_1", + "spdxId": "https://distfiles.ariadne.space/pkgconf/Relationship/test3/hasDeclaredLicense", + "from": "https://distfiles.ariadne.space/pkgconf/Package/test3", + "to": [ + "https://distfiles.ariadne.space/pkgconf/simplelicensing_LicenseExpression/BSD-4-Clause" + ], + "relationshipType": "hasDeclaredLicense" + }, + { + "type": "Relationship", + "creationInfo": "_:creationinfo_1", + "spdxId": "https://distfiles.ariadne.space/pkgconf/Relationship/test3/hasConcludedLicense", + "from": "https://distfiles.ariadne.space/pkgconf/Package/test3", + "to": [ + "https://distfiles.ariadne.space/pkgconf/simplelicensing_LicenseExpression/BSD-4-Clause" + ], + "relationshipType": "hasConcludedLicense" + }, + { + "type": "SpdxDocument", + "creationInfo": "_:creationinfo_1", + "spdxId": "https://distfiles.ariadne.space/pkgconf/spdxDocument/1", + "rootElement": [ + "https://distfiles.ariadne.space/pkgconf/software_Sbom/test3" + ], + "element": [ + "https://distfiles.ariadne.space/pkgconf/Agent/default", + "https://distfiles.ariadne.space/pkgconf/simplelicensing_LicenseExpression/BSD-4-Clause", + "https://distfiles.ariadne.space/pkgconf/Relationship/test3/hasDeclaredLicense", + "https://distfiles.ariadne.space/pkgconf/Relationship/test3/hasConcludedLicense", + "https://distfiles.ariadne.space/pkgconf/software_Sbom/test3", + "https://distfiles.ariadne.space/pkgconf/Package/test3" + ] + } + ] +} diff --git a/tests/lib-sbom-files/basic-use-uri.json b/tests/lib-sbom-files/basic-use-uri.json new file mode 100644 index 000000000000..e9913a92a764 --- /dev/null +++ b/tests/lib-sbom-files/basic-use-uri.json @@ -0,0 +1,90 @@ +{ + "@context": "https://spdx.org/rdf/3.0.1/spdx-context.jsonld", + "@graph": [ + { + "type": "Agent", + "creationInfo": "_:creationinfo_1", + "spdxId": "github.com:pkgconf:pkgconf:Agent:default", + "name": "Default" + }, + { + "type": "CreationInfo", + "@id": "_:creationinfo_1", + "created": "test", + "createdBy": [ + "github.com:pkgconf:pkgconf:Agent:default" + ], + "specVersion": "3.0.1" + }, + { + "type": "simplelicensing_LicenseExpression", + "creationInfo": "_:creationinfo_1", + "spdxId": "github.com:pkgconf:pkgconf:simplelicensing_LicenseExpression:BSD-4-Clause", + "simplelicensing_licenseExpression": "BSD-4-Clause" + }, + { + "type": "software_Sbom", + "creationInfo": "_:creationinfo_1", + "spdxId": "github.com:pkgconf:pkgconf:software_Sbom:test3", + "software_sbomType": [ + "build" + ], + "rootElement": [ + "github.com:pkgconf:pkgconf:Package:test3" + ], + "element": [ + "github.com:pkgconf:pkgconf:Relationship:test3:hasDeclaredLicense", + "github.com:pkgconf:pkgconf:Relationship:test3:hasConcludedLicense" + ] + }, + { + "type": "software_Package", + "creationInfo": "_:creationinfo_1", + "spdxId": "github.com:pkgconf:pkgconf:Package:test3", + "name": "test3", + "originatedBy": [ + "github.com:pkgconf:pkgconf:Agent:default" + ], + "software_copyrightText": "Test3 copyright text", + "software_homePage": "https://github.com/pkgconf/pkgconf/", + "software_downloadLocation": "https://github.com/pkgconf/pkgconf/archive/refs/tags/pkgconf-2.5.1.tar.gz", + "software_packageVersion": "3.0.0" + }, + { + "type": "Relationship", + "creationInfo": "_:creationinfo_1", + "spdxId": "github.com:pkgconf:pkgconf:Relationship:test3:hasDeclaredLicense", + "from": "github.com:pkgconf:pkgconf:Package:test3", + "to": [ + "github.com:pkgconf:pkgconf:simplelicensing_LicenseExpression:BSD-4-Clause" + ], + "relationshipType": "hasDeclaredLicense" + }, + { + "type": "Relationship", + "creationInfo": "_:creationinfo_1", + "spdxId": "github.com:pkgconf:pkgconf:Relationship:test3:hasConcludedLicense", + "from": "github.com:pkgconf:pkgconf:Package:test3", + "to": [ + "github.com:pkgconf:pkgconf:simplelicensing_LicenseExpression:BSD-4-Clause" + ], + "relationshipType": "hasConcludedLicense" + }, + { + "type": "SpdxDocument", + "creationInfo": "_:creationinfo_1", + "spdxId": "github.com:pkgconf:pkgconf:spdxDocument:1", + "rootElement": [ + "github.com:pkgconf:pkgconf:software_Sbom:test3" + ], + "element": [ + "github.com:pkgconf:pkgconf:Agent:default", + "github.com:pkgconf:pkgconf:simplelicensing_LicenseExpression:BSD-4-Clause", + "github.com:pkgconf:pkgconf:Relationship:test3:hasDeclaredLicense", + "github.com:pkgconf:pkgconf:Relationship:test3:hasConcludedLicense", + "github.com:pkgconf:pkgconf:software_Sbom:test3", + "github.com:pkgconf:pkgconf:Package:test3" + ] + } + ] +} diff --git a/tests/lib-sbom-files/basic.json b/tests/lib-sbom-files/basic.json new file mode 100644 index 000000000000..3b241ff3442d --- /dev/null +++ b/tests/lib-sbom-files/basic.json @@ -0,0 +1,90 @@ +{ + "@context": "https://spdx.org/rdf/3.0.1/spdx-context.jsonld", + "@graph": [ + { + "type": "Agent", + "creationInfo": "_:creationinfo_1", + "spdxId": "https://github.com/pkgconf/pkgconf/Agent/default", + "name": "Default" + }, + { + "type": "CreationInfo", + "@id": "_:creationinfo_1", + "created": "test", + "createdBy": [ + "https://github.com/pkgconf/pkgconf/Agent/default" + ], + "specVersion": "3.0.1" + }, + { + "type": "simplelicensing_LicenseExpression", + "creationInfo": "_:creationinfo_1", + "spdxId": "https://github.com/pkgconf/pkgconf/simplelicensing_LicenseExpression/BSD-4-Clause", + "simplelicensing_licenseExpression": "BSD-4-Clause" + }, + { + "type": "software_Sbom", + "creationInfo": "_:creationinfo_1", + "spdxId": "https://github.com/pkgconf/pkgconf/software_Sbom/test3", + "software_sbomType": [ + "build" + ], + "rootElement": [ + "https://github.com/pkgconf/pkgconf/Package/test3" + ], + "element": [ + "https://github.com/pkgconf/pkgconf/Relationship/test3/hasDeclaredLicense", + "https://github.com/pkgconf/pkgconf/Relationship/test3/hasConcludedLicense" + ] + }, + { + "type": "software_Package", + "creationInfo": "_:creationinfo_1", + "spdxId": "https://github.com/pkgconf/pkgconf/Package/test3", + "name": "test3", + "originatedBy": [ + "https://github.com/pkgconf/pkgconf/Agent/default" + ], + "software_copyrightText": "Test3 copyright text", + "software_homePage": "https://github.com/pkgconf/pkgconf/", + "software_downloadLocation": "https://github.com/pkgconf/pkgconf/archive/refs/tags/pkgconf-2.5.1.tar.gz", + "software_packageVersion": "3.0.0" + }, + { + "type": "Relationship", + "creationInfo": "_:creationinfo_1", + "spdxId": "https://github.com/pkgconf/pkgconf/Relationship/test3/hasDeclaredLicense", + "from": "https://github.com/pkgconf/pkgconf/Package/test3", + "to": [ + "https://github.com/pkgconf/pkgconf/simplelicensing_LicenseExpression/BSD-4-Clause" + ], + "relationshipType": "hasDeclaredLicense" + }, + { + "type": "Relationship", + "creationInfo": "_:creationinfo_1", + "spdxId": "https://github.com/pkgconf/pkgconf/Relationship/test3/hasConcludedLicense", + "from": "https://github.com/pkgconf/pkgconf/Package/test3", + "to": [ + "https://github.com/pkgconf/pkgconf/simplelicensing_LicenseExpression/BSD-4-Clause" + ], + "relationshipType": "hasConcludedLicense" + }, + { + "type": "SpdxDocument", + "creationInfo": "_:creationinfo_1", + "spdxId": "https://github.com/pkgconf/pkgconf/spdxDocument/1", + "rootElement": [ + "https://github.com/pkgconf/pkgconf/software_Sbom/test3" + ], + "element": [ + "https://github.com/pkgconf/pkgconf/Agent/default", + "https://github.com/pkgconf/pkgconf/simplelicensing_LicenseExpression/BSD-4-Clause", + "https://github.com/pkgconf/pkgconf/Relationship/test3/hasDeclaredLicense", + "https://github.com/pkgconf/pkgconf/Relationship/test3/hasConcludedLicense", + "https://github.com/pkgconf/pkgconf/software_Sbom/test3", + "https://github.com/pkgconf/pkgconf/Package/test3" + ] + } + ] +} diff --git a/tests/lib-sbom-files/define_variable.json b/tests/lib-sbom-files/define_variable.json new file mode 100644 index 000000000000..bef19f2f3de1 --- /dev/null +++ b/tests/lib-sbom-files/define_variable.json @@ -0,0 +1,90 @@ +{ + "@context": "https://spdx.org/rdf/3.0.1/spdx-context.jsonld", + "@graph": [ + { + "type": "Agent", + "creationInfo": "_:creationinfo_1", + "spdxId": "https://github.com/pkgconf/pkgconf/Agent/default", + "name": "Default" + }, + { + "type": "CreationInfo", + "@id": "_:creationinfo_1", + "created": "test", + "createdBy": [ + "https://github.com/pkgconf/pkgconf/Agent/default" + ], + "specVersion": "3.0.1" + }, + { + "type": "simplelicensing_LicenseExpression", + "creationInfo": "_:creationinfo_1", + "spdxId": "https://github.com/pkgconf/pkgconf/simplelicensing_LicenseExpression/BSD-2-Clause", + "simplelicensing_licenseExpression": "BSD-2-Clause" + }, + { + "type": "software_Sbom", + "creationInfo": "_:creationinfo_1", + "spdxId": "https://github.com/pkgconf/pkgconf/software_Sbom/variable-test1", + "software_sbomType": [ + "build" + ], + "rootElement": [ + "https://github.com/pkgconf/pkgconf/Package/variable-test1" + ], + "element": [ + "https://github.com/pkgconf/pkgconf/Relationship/variable-test1/hasDeclaredLicense", + "https://github.com/pkgconf/pkgconf/Relationship/variable-test1/hasConcludedLicense" + ] + }, + { + "type": "software_Package", + "creationInfo": "_:creationinfo_1", + "spdxId": "https://github.com/pkgconf/pkgconf/Package/variable-test1", + "name": "variable-test1", + "originatedBy": [ + "https://github.com/pkgconf/pkgconf/Agent/default" + ], + "software_copyrightText": "NOASSERTION", + "software_homePage": "https://github.com/pkgconf/pkgconf/releases/", + "software_downloadLocation": "https://github.com/pkgconf/pkgconf/archive/refs/tags/pkgconf-2.5.1.tar.gz", + "software_packageVersion": "1.0-123" + }, + { + "type": "Relationship", + "creationInfo": "_:creationinfo_1", + "spdxId": "https://github.com/pkgconf/pkgconf/Relationship/variable-test1/hasDeclaredLicense", + "from": "https://github.com/pkgconf/pkgconf/Package/variable-test1", + "to": [ + "https://github.com/pkgconf/pkgconf/simplelicensing_LicenseExpression/BSD-2-Clause" + ], + "relationshipType": "hasDeclaredLicense" + }, + { + "type": "Relationship", + "creationInfo": "_:creationinfo_1", + "spdxId": "https://github.com/pkgconf/pkgconf/Relationship/variable-test1/hasConcludedLicense", + "from": "https://github.com/pkgconf/pkgconf/Package/variable-test1", + "to": [ + "https://github.com/pkgconf/pkgconf/simplelicensing_LicenseExpression/BSD-2-Clause" + ], + "relationshipType": "hasConcludedLicense" + }, + { + "type": "SpdxDocument", + "creationInfo": "_:creationinfo_1", + "spdxId": "https://github.com/pkgconf/pkgconf/spdxDocument/1", + "rootElement": [ + "https://github.com/pkgconf/pkgconf/software_Sbom/variable-test1" + ], + "element": [ + "https://github.com/pkgconf/pkgconf/Agent/default", + "https://github.com/pkgconf/pkgconf/simplelicensing_LicenseExpression/BSD-2-Clause", + "https://github.com/pkgconf/pkgconf/Relationship/variable-test1/hasDeclaredLicense", + "https://github.com/pkgconf/pkgconf/Relationship/variable-test1/hasConcludedLicense", + "https://github.com/pkgconf/pkgconf/software_Sbom/variable-test1", + "https://github.com/pkgconf/pkgconf/Package/variable-test1" + ] + } + ] +} diff --git a/tests/lib-sbom-files/define_variable_with_dependency.json b/tests/lib-sbom-files/define_variable_with_dependency.json new file mode 100644 index 000000000000..cad5b0b269b3 --- /dev/null +++ b/tests/lib-sbom-files/define_variable_with_dependency.json @@ -0,0 +1,162 @@ +{ + "@context": "https://spdx.org/rdf/3.0.1/spdx-context.jsonld", + "@graph": [ + { + "type": "Agent", + "creationInfo": "_:creationinfo_1", + "spdxId": "https://github.com/pkgconf/pkgconf/Agent/default", + "name": "Default" + }, + { + "type": "CreationInfo", + "@id": "_:creationinfo_1", + "created": "test", + "createdBy": [ + "https://github.com/pkgconf/pkgconf/Agent/default" + ], + "specVersion": "3.0.1" + }, + { + "type": "simplelicensing_LicenseExpression", + "creationInfo": "_:creationinfo_1", + "spdxId": "https://github.com/pkgconf/pkgconf/simplelicensing_LicenseExpression/MIT", + "simplelicensing_licenseExpression": "MIT" + }, + { + "type": "simplelicensing_LicenseExpression", + "creationInfo": "_:creationinfo_1", + "spdxId": "https://github.com/pkgconf/pkgconf/simplelicensing_LicenseExpression/BSD-2-Clause", + "simplelicensing_licenseExpression": "BSD-2-Clause" + }, + { + "type": "software_Sbom", + "creationInfo": "_:creationinfo_1", + "spdxId": "https://github.com/pkgconf/pkgconf/software_Sbom/variable-test2", + "software_sbomType": [ + "build" + ], + "rootElement": [ + "https://github.com/pkgconf/pkgconf/Package/variable-test2" + ], + "element": [ + "https://github.com/pkgconf/pkgconf/Relationship/variable-test2/dependsOn/variable-test1", + "https://github.com/pkgconf/pkgconf/Relationship/variable-test2/hasDeclaredLicense", + "https://github.com/pkgconf/pkgconf/Relationship/variable-test2/hasConcludedLicense" + ] + }, + { + "type": "software_Sbom", + "creationInfo": "_:creationinfo_1", + "spdxId": "https://github.com/pkgconf/pkgconf/software_Sbom/variable-test1", + "software_sbomType": [ + "build" + ], + "rootElement": [ + "https://github.com/pkgconf/pkgconf/Package/variable-test1" + ], + "element": [ + "https://github.com/pkgconf/pkgconf/Relationship/variable-test1/hasDeclaredLicense", + "https://github.com/pkgconf/pkgconf/Relationship/variable-test1/hasConcludedLicense" + ] + }, + { + "type": "software_Package", + "creationInfo": "_:creationinfo_1", + "spdxId": "https://github.com/pkgconf/pkgconf/Package/variable-test2", + "name": "variable-test2", + "originatedBy": [ + "https://github.com/pkgconf/pkgconf/Agent/default" + ], + "software_copyrightText": "NOASSERTION", + "software_homePage": "https://github.com/pkgconf/pkgconf/releases/", + "software_downloadLocation": "https://github.com/pkgconf/pkgconf/archive/refs/tags/pkgconf-2.5.1.tar.gz", + "software_packageVersion": "2.0" + }, + { + "type": "software_Package", + "creationInfo": "_:creationinfo_1", + "spdxId": "https://github.com/pkgconf/pkgconf/Package/variable-test1", + "name": "variable-test1", + "originatedBy": [ + "https://github.com/pkgconf/pkgconf/Agent/default" + ], + "software_copyrightText": "NOASSERTION", + "software_homePage": "https://github.com/pkgconf/pkgconf/releases/", + "software_downloadLocation": "https://github.com/pkgconf/pkgconf/archive/refs/tags/pkgconf-2.5.1.tar.gz", + "software_packageVersion": "1.0-123" + }, + { + "type": "Relationship", + "creationInfo": "_:creationinfo_1", + "spdxId": "https://github.com/pkgconf/pkgconf/Relationship/variable-test2/hasDeclaredLicense", + "from": "https://github.com/pkgconf/pkgconf/Package/variable-test2", + "to": [ + "https://github.com/pkgconf/pkgconf/simplelicensing_LicenseExpression/MIT" + ], + "relationshipType": "hasDeclaredLicense" + }, + { + "type": "Relationship", + "creationInfo": "_:creationinfo_1", + "spdxId": "https://github.com/pkgconf/pkgconf/Relationship/variable-test2/hasConcludedLicense", + "from": "https://github.com/pkgconf/pkgconf/Package/variable-test2", + "to": [ + "https://github.com/pkgconf/pkgconf/simplelicensing_LicenseExpression/MIT" + ], + "relationshipType": "hasConcludedLicense" + }, + { + "type": "Relationship", + "creationInfo": "_:creationinfo_1", + "spdxId": "https://github.com/pkgconf/pkgconf/Relationship/variable-test2/dependsOn/variable-test1", + "from": "https://github.com/pkgconf/pkgconf/Package/variable-test2", + "to": [ + "https://github.com/pkgconf/pkgconf/Package/variable-test1" + ], + "relationshipType": "dependsOn" + }, + { + "type": "Relationship", + "creationInfo": "_:creationinfo_1", + "spdxId": "https://github.com/pkgconf/pkgconf/Relationship/variable-test1/hasDeclaredLicense", + "from": "https://github.com/pkgconf/pkgconf/Package/variable-test1", + "to": [ + "https://github.com/pkgconf/pkgconf/simplelicensing_LicenseExpression/BSD-2-Clause" + ], + "relationshipType": "hasDeclaredLicense" + }, + { + "type": "Relationship", + "creationInfo": "_:creationinfo_1", + "spdxId": "https://github.com/pkgconf/pkgconf/Relationship/variable-test1/hasConcludedLicense", + "from": "https://github.com/pkgconf/pkgconf/Package/variable-test1", + "to": [ + "https://github.com/pkgconf/pkgconf/simplelicensing_LicenseExpression/BSD-2-Clause" + ], + "relationshipType": "hasConcludedLicense" + }, + { + "type": "SpdxDocument", + "creationInfo": "_:creationinfo_1", + "spdxId": "https://github.com/pkgconf/pkgconf/spdxDocument/1", + "rootElement": [ + "https://github.com/pkgconf/pkgconf/software_Sbom/variable-test2", + "https://github.com/pkgconf/pkgconf/software_Sbom/variable-test1" + ], + "element": [ + "https://github.com/pkgconf/pkgconf/Agent/default", + "https://github.com/pkgconf/pkgconf/simplelicensing_LicenseExpression/MIT", + "https://github.com/pkgconf/pkgconf/simplelicensing_LicenseExpression/BSD-2-Clause", + "https://github.com/pkgconf/pkgconf/Relationship/variable-test2/dependsOn/variable-test1", + "https://github.com/pkgconf/pkgconf/Relationship/variable-test2/hasDeclaredLicense", + "https://github.com/pkgconf/pkgconf/Relationship/variable-test2/hasConcludedLicense", + "https://github.com/pkgconf/pkgconf/Relationship/variable-test1/hasDeclaredLicense", + "https://github.com/pkgconf/pkgconf/Relationship/variable-test1/hasConcludedLicense", + "https://github.com/pkgconf/pkgconf/software_Sbom/variable-test2", + "https://github.com/pkgconf/pkgconf/Package/variable-test2", + "https://github.com/pkgconf/pkgconf/software_Sbom/variable-test1", + "https://github.com/pkgconf/pkgconf/Package/variable-test1" + ] + } + ] +} diff --git a/tests/lib-sbom-files/meta_package-use-uri-spdx-base-id.json b/tests/lib-sbom-files/meta_package-use-uri-spdx-base-id.json new file mode 100644 index 000000000000..ad18ded896c3 --- /dev/null +++ b/tests/lib-sbom-files/meta_package-use-uri-spdx-base-id.json @@ -0,0 +1,544 @@ +{ + "@context": "https://spdx.org/rdf/3.0.1/spdx-context.jsonld", + "@graph": [ + { + "type": "Agent", + "creationInfo": "_:creationinfo_1", + "spdxId": "distfiles.ariadne.space:pkgconf:Agent:default", + "name": "Default" + }, + { + "type": "CreationInfo", + "@id": "_:creationinfo_1", + "created": "test", + "createdBy": [ + "distfiles.ariadne.space:pkgconf:Agent:default" + ], + "specVersion": "3.0.1" + }, + { + "type": "simplelicensing_LicenseExpression", + "creationInfo": "_:creationinfo_1", + "spdxId": "distfiles.ariadne.space:pkgconf:simplelicensing_LicenseExpression:BSD-2-Clause", + "simplelicensing_licenseExpression": "BSD-2-Clause" + }, + { + "type": "simplelicensing_LicenseExpression", + "creationInfo": "_:creationinfo_1", + "spdxId": "distfiles.ariadne.space:pkgconf:simplelicensing_LicenseExpression:BSD-1-Clause", + "simplelicensing_licenseExpression": "BSD-1-Clause" + }, + { + "type": "simplelicensing_LicenseExpression", + "creationInfo": "_:creationinfo_1", + "spdxId": "distfiles.ariadne.space:pkgconf:simplelicensing_LicenseExpression:BSD-4-Clause", + "simplelicensing_licenseExpression": "BSD-4-Clause" + }, + { + "type": "simplelicensing_LicenseExpression", + "creationInfo": "_:creationinfo_1", + "spdxId": "distfiles.ariadne.space:pkgconf:simplelicensing_LicenseExpression:MIT", + "simplelicensing_licenseExpression": "MIT" + }, + { + "type": "simplelicensing_LicenseExpression", + "creationInfo": "_:creationinfo_1", + "spdxId": "distfiles.ariadne.space:pkgconf:simplelicensing_LicenseExpression:Apache-2.0", + "simplelicensing_licenseExpression": "Apache-2.0" + }, + { + "type": "software_Sbom", + "creationInfo": "_:creationinfo_1", + "spdxId": "distfiles.ariadne.space:pkgconf:software_Sbom:meta_package", + "software_sbomType": [ + "build" + ], + "rootElement": [ + "distfiles.ariadne.space:pkgconf:Package:meta_package" + ], + "element": [ + "distfiles.ariadne.space:pkgconf:Relationship:meta_package:dependsOn:test1", + "distfiles.ariadne.space:pkgconf:Relationship:meta_package:dependsOn:test2", + "distfiles.ariadne.space:pkgconf:Relationship:meta_package:dependsOn:test3", + "distfiles.ariadne.space:pkgconf:Relationship:meta_package:dependsOn:test4", + "distfiles.ariadne.space:pkgconf:Relationship:meta_package:dependsOn:test5", + "distfiles.ariadne.space:pkgconf:Relationship:meta_package:dependsOn:test6", + "distfiles.ariadne.space:pkgconf:Relationship:meta_package:hasDeclaredLicense", + "distfiles.ariadne.space:pkgconf:Relationship:meta_package:hasConcludedLicense" + ] + }, + { + "type": "software_Sbom", + "creationInfo": "_:creationinfo_1", + "spdxId": "distfiles.ariadne.space:pkgconf:software_Sbom:test1", + "software_sbomType": [ + "build" + ], + "rootElement": [ + "distfiles.ariadne.space:pkgconf:Package:test1" + ], + "element": [ + "distfiles.ariadne.space:pkgconf:Relationship:test1:hasDeclaredLicense", + "distfiles.ariadne.space:pkgconf:Relationship:test1:hasConcludedLicense" + ] + }, + { + "type": "software_Sbom", + "creationInfo": "_:creationinfo_1", + "spdxId": "distfiles.ariadne.space:pkgconf:software_Sbom:test2", + "software_sbomType": [ + "build" + ], + "rootElement": [ + "distfiles.ariadne.space:pkgconf:Package:test2" + ], + "element": [ + "distfiles.ariadne.space:pkgconf:Relationship:test2:dependsOn:test3", + "distfiles.ariadne.space:pkgconf:Relationship:test2:hasDeclaredLicense", + "distfiles.ariadne.space:pkgconf:Relationship:test2:hasConcludedLicense" + ] + }, + { + "type": "software_Sbom", + "creationInfo": "_:creationinfo_1", + "spdxId": "distfiles.ariadne.space:pkgconf:software_Sbom:test3", + "software_sbomType": [ + "build" + ], + "rootElement": [ + "distfiles.ariadne.space:pkgconf:Package:test3" + ], + "element": [ + "distfiles.ariadne.space:pkgconf:Relationship:test3:hasDeclaredLicense", + "distfiles.ariadne.space:pkgconf:Relationship:test3:hasConcludedLicense" + ] + }, + { + "type": "software_Sbom", + "creationInfo": "_:creationinfo_1", + "spdxId": "distfiles.ariadne.space:pkgconf:software_Sbom:test4", + "software_sbomType": [ + "build" + ], + "rootElement": [ + "distfiles.ariadne.space:pkgconf:Package:test4" + ], + "element": [ + "distfiles.ariadne.space:pkgconf:Relationship:test4:dependsOn:test5", + "distfiles.ariadne.space:pkgconf:Relationship:test4:dependsOn:test6", + "distfiles.ariadne.space:pkgconf:Relationship:test4:hasDeclaredLicense", + "distfiles.ariadne.space:pkgconf:Relationship:test4:hasConcludedLicense" + ] + }, + { + "type": "software_Sbom", + "creationInfo": "_:creationinfo_1", + "spdxId": "distfiles.ariadne.space:pkgconf:software_Sbom:test5", + "software_sbomType": [ + "build" + ], + "rootElement": [ + "distfiles.ariadne.space:pkgconf:Package:test5" + ], + "element": [ + "distfiles.ariadne.space:pkgconf:Relationship:test5:hasDeclaredLicense", + "distfiles.ariadne.space:pkgconf:Relationship:test5:hasConcludedLicense" + ] + }, + { + "type": "software_Sbom", + "creationInfo": "_:creationinfo_1", + "spdxId": "distfiles.ariadne.space:pkgconf:software_Sbom:test6", + "software_sbomType": [ + "build" + ], + "rootElement": [ + "distfiles.ariadne.space:pkgconf:Package:test6" + ], + "element": [ + "distfiles.ariadne.space:pkgconf:Relationship:test6:hasDeclaredLicense", + "distfiles.ariadne.space:pkgconf:Relationship:test6:hasConcludedLicense" + ] + }, + { + "type": "software_Package", + "creationInfo": "_:creationinfo_1", + "spdxId": "distfiles.ariadne.space:pkgconf:Package:meta_package", + "name": "meta_package", + "originatedBy": [ + "distfiles.ariadne.space:pkgconf:Agent:default" + ], + "software_copyrightText": "NOASSERTION", + "software_homePage": "https://github.com/pkgconf/pkgconf", + "software_downloadLocation": "https://github.com/pkgconf/pkgconf/archive/refs/tags/pkgconf-2.5.1.tar.gz", + "software_packageVersion": "1.0.0" + }, + { + "type": "software_Package", + "creationInfo": "_:creationinfo_1", + "spdxId": "distfiles.ariadne.space:pkgconf:Package:test1", + "name": "test1", + "originatedBy": [ + "distfiles.ariadne.space:pkgconf:Agent:default" + ], + "software_copyrightText": "Test1 copyright text", + "software_homePage": "", + "software_downloadLocation": "", + "software_packageVersion": "1.0.0" + }, + { + "type": "software_Package", + "creationInfo": "_:creationinfo_1", + "spdxId": "distfiles.ariadne.space:pkgconf:Package:test2", + "name": "test2", + "originatedBy": [ + "distfiles.ariadne.space:pkgconf:Agent:default" + ], + "software_copyrightText": "NOASSERTION", + "software_homePage": "https://github.com/pkgconf/pkgconf/", + "software_downloadLocation": "https://github.com/pkgconf/pkgconf/archive/refs/tags/pkgconf-2.5.1.tar.gz", + "software_packageVersion": "2.0.0" + }, + { + "type": "software_Package", + "creationInfo": "_:creationinfo_1", + "spdxId": "distfiles.ariadne.space:pkgconf:Package:test3", + "name": "test3", + "originatedBy": [ + "distfiles.ariadne.space:pkgconf:Agent:default" + ], + "software_copyrightText": "Test3 copyright text", + "software_homePage": "https://github.com/pkgconf/pkgconf/", + "software_downloadLocation": "https://github.com/pkgconf/pkgconf/archive/refs/tags/pkgconf-2.5.1.tar.gz", + "software_packageVersion": "3.0.0" + }, + { + "type": "software_Package", + "creationInfo": "_:creationinfo_1", + "spdxId": "distfiles.ariadne.space:pkgconf:Package:test4", + "name": "test4", + "originatedBy": [ + "distfiles.ariadne.space:pkgconf:Agent:default" + ], + "software_copyrightText": "NOASSERTION", + "software_homePage": "https://github.com/pkgconf/pkgconf/", + "software_downloadLocation": "https://github.com/pkgconf/pkgconf/archive/refs/tags/pkgconf-2.5.1.tar.gz", + "software_packageVersion": "4.0.0" + }, + { + "type": "software_Package", + "creationInfo": "_:creationinfo_1", + "spdxId": "distfiles.ariadne.space:pkgconf:Package:test5", + "name": "test5", + "originatedBy": [ + "distfiles.ariadne.space:pkgconf:Agent:default" + ], + "software_copyrightText": "NOASSERTION", + "software_homePage": "https://github.com/pkgconf/pkgconf/", + "software_downloadLocation": "https://github.com/pkgconf/pkgconf/archive/refs/tags/pkgconf-2.5.1.tar.gz", + "software_packageVersion": "5.0.0" + }, + { + "type": "software_Package", + "creationInfo": "_:creationinfo_1", + "spdxId": "distfiles.ariadne.space:pkgconf:Package:test6", + "name": "test6", + "originatedBy": [ + "distfiles.ariadne.space:pkgconf:Agent:default" + ], + "software_copyrightText": "NOASSERTION", + "software_homePage": "https://github.com/pkgconf/pkgconf/releases/", + "software_downloadLocation": "https://github.com/pkgconf/pkgconf/archive/refs/tags/pkgconf-2.5.1.tar.gz", + "software_packageVersion": "6.0.0" + }, + { + "type": "Relationship", + "creationInfo": "_:creationinfo_1", + "spdxId": "distfiles.ariadne.space:pkgconf:Relationship:meta_package:hasDeclaredLicense", + "from": "distfiles.ariadne.space:pkgconf:Package:meta_package", + "to": [ + "distfiles.ariadne.space:pkgconf:simplelicensing_LicenseExpression:BSD-2-Clause" + ], + "relationshipType": "hasDeclaredLicense" + }, + { + "type": "Relationship", + "creationInfo": "_:creationinfo_1", + "spdxId": "distfiles.ariadne.space:pkgconf:Relationship:meta_package:hasConcludedLicense", + "from": "distfiles.ariadne.space:pkgconf:Package:meta_package", + "to": [ + "distfiles.ariadne.space:pkgconf:simplelicensing_LicenseExpression:BSD-2-Clause" + ], + "relationshipType": "hasConcludedLicense" + }, + { + "type": "Relationship", + "creationInfo": "_:creationinfo_1", + "spdxId": "distfiles.ariadne.space:pkgconf:Relationship:meta_package:dependsOn:test1", + "from": "distfiles.ariadne.space:pkgconf:Package:meta_package", + "to": [ + "distfiles.ariadne.space:pkgconf:Package:test1" + ], + "relationshipType": "dependsOn" + }, + { + "type": "Relationship", + "creationInfo": "_:creationinfo_1", + "spdxId": "distfiles.ariadne.space:pkgconf:Relationship:meta_package:dependsOn:test2", + "from": "distfiles.ariadne.space:pkgconf:Package:meta_package", + "to": [ + "distfiles.ariadne.space:pkgconf:Package:test2" + ], + "relationshipType": "dependsOn" + }, + { + "type": "Relationship", + "creationInfo": "_:creationinfo_1", + "spdxId": "distfiles.ariadne.space:pkgconf:Relationship:meta_package:dependsOn:test3", + "from": "distfiles.ariadne.space:pkgconf:Package:meta_package", + "to": [ + "distfiles.ariadne.space:pkgconf:Package:test3" + ], + "relationshipType": "dependsOn" + }, + { + "type": "Relationship", + "creationInfo": "_:creationinfo_1", + "spdxId": "distfiles.ariadne.space:pkgconf:Relationship:meta_package:dependsOn:test4", + "from": "distfiles.ariadne.space:pkgconf:Package:meta_package", + "to": [ + "distfiles.ariadne.space:pkgconf:Package:test4" + ], + "relationshipType": "dependsOn" + }, + { + "type": "Relationship", + "creationInfo": "_:creationinfo_1", + "spdxId": "distfiles.ariadne.space:pkgconf:Relationship:meta_package:dependsOn:test5", + "from": "distfiles.ariadne.space:pkgconf:Package:meta_package", + "to": [ + "distfiles.ariadne.space:pkgconf:Package:test5" + ], + "relationshipType": "dependsOn" + }, + { + "type": "Relationship", + "creationInfo": "_:creationinfo_1", + "spdxId": "distfiles.ariadne.space:pkgconf:Relationship:meta_package:dependsOn:test6", + "from": "distfiles.ariadne.space:pkgconf:Package:meta_package", + "to": [ + "distfiles.ariadne.space:pkgconf:Package:test6" + ], + "relationshipType": "dependsOn" + }, + { + "type": "Relationship", + "creationInfo": "_:creationinfo_1", + "spdxId": "distfiles.ariadne.space:pkgconf:Relationship:test1:hasDeclaredLicense", + "from": "distfiles.ariadne.space:pkgconf:Package:test1", + "to": [ + "distfiles.ariadne.space:pkgconf:simplelicensing_LicenseExpression:BSD-1-Clause" + ], + "relationshipType": "hasDeclaredLicense" + }, + { + "type": "Relationship", + "creationInfo": "_:creationinfo_1", + "spdxId": "distfiles.ariadne.space:pkgconf:Relationship:test1:hasConcludedLicense", + "from": "distfiles.ariadne.space:pkgconf:Package:test1", + "to": [ + "distfiles.ariadne.space:pkgconf:simplelicensing_LicenseExpression:BSD-1-Clause" + ], + "relationshipType": "hasConcludedLicense" + }, + { + "type": "Relationship", + "creationInfo": "_:creationinfo_1", + "spdxId": "distfiles.ariadne.space:pkgconf:Relationship:test2:hasDeclaredLicense", + "from": "distfiles.ariadne.space:pkgconf:Package:test2", + "to": [ + "distfiles.ariadne.space:pkgconf:simplelicensing_LicenseExpression:BSD-2-Clause" + ], + "relationshipType": "hasDeclaredLicense" + }, + { + "type": "Relationship", + "creationInfo": "_:creationinfo_1", + "spdxId": "distfiles.ariadne.space:pkgconf:Relationship:test2:hasConcludedLicense", + "from": "distfiles.ariadne.space:pkgconf:Package:test2", + "to": [ + "distfiles.ariadne.space:pkgconf:simplelicensing_LicenseExpression:BSD-2-Clause" + ], + "relationshipType": "hasConcludedLicense" + }, + { + "type": "Relationship", + "creationInfo": "_:creationinfo_1", + "spdxId": "distfiles.ariadne.space:pkgconf:Relationship:test2:dependsOn:test3", + "from": "distfiles.ariadne.space:pkgconf:Package:test2", + "to": [ + "distfiles.ariadne.space:pkgconf:Package:test3" + ], + "relationshipType": "dependsOn" + }, + { + "type": "Relationship", + "creationInfo": "_:creationinfo_1", + "spdxId": "distfiles.ariadne.space:pkgconf:Relationship:test3:hasDeclaredLicense", + "from": "distfiles.ariadne.space:pkgconf:Package:test3", + "to": [ + "distfiles.ariadne.space:pkgconf:simplelicensing_LicenseExpression:BSD-4-Clause" + ], + "relationshipType": "hasDeclaredLicense" + }, + { + "type": "Relationship", + "creationInfo": "_:creationinfo_1", + "spdxId": "distfiles.ariadne.space:pkgconf:Relationship:test3:hasConcludedLicense", + "from": "distfiles.ariadne.space:pkgconf:Package:test3", + "to": [ + "distfiles.ariadne.space:pkgconf:simplelicensing_LicenseExpression:BSD-4-Clause" + ], + "relationshipType": "hasConcludedLicense" + }, + { + "type": "Relationship", + "creationInfo": "_:creationinfo_1", + "spdxId": "distfiles.ariadne.space:pkgconf:Relationship:test4:hasDeclaredLicense", + "from": "distfiles.ariadne.space:pkgconf:Package:test4", + "to": [ + "distfiles.ariadne.space:pkgconf:simplelicensing_LicenseExpression:MIT" + ], + "relationshipType": "hasDeclaredLicense" + }, + { + "type": "Relationship", + "creationInfo": "_:creationinfo_1", + "spdxId": "distfiles.ariadne.space:pkgconf:Relationship:test4:hasConcludedLicense", + "from": "distfiles.ariadne.space:pkgconf:Package:test4", + "to": [ + "distfiles.ariadne.space:pkgconf:simplelicensing_LicenseExpression:MIT" + ], + "relationshipType": "hasConcludedLicense" + }, + { + "type": "Relationship", + "creationInfo": "_:creationinfo_1", + "spdxId": "distfiles.ariadne.space:pkgconf:Relationship:test4:dependsOn:test5", + "from": "distfiles.ariadne.space:pkgconf:Package:test4", + "to": [ + "distfiles.ariadne.space:pkgconf:Package:test5" + ], + "relationshipType": "dependsOn" + }, + { + "type": "Relationship", + "creationInfo": "_:creationinfo_1", + "spdxId": "distfiles.ariadne.space:pkgconf:Relationship:test4:dependsOn:test6", + "from": "distfiles.ariadne.space:pkgconf:Package:test4", + "to": [ + "distfiles.ariadne.space:pkgconf:Package:test6" + ], + "relationshipType": "dependsOn" + }, + { + "type": "Relationship", + "creationInfo": "_:creationinfo_1", + "spdxId": "distfiles.ariadne.space:pkgconf:Relationship:test5:hasDeclaredLicense", + "from": "distfiles.ariadne.space:pkgconf:Package:test5", + "to": [ + "distfiles.ariadne.space:pkgconf:simplelicensing_LicenseExpression:MIT" + ], + "relationshipType": "hasDeclaredLicense" + }, + { + "type": "Relationship", + "creationInfo": "_:creationinfo_1", + "spdxId": "distfiles.ariadne.space:pkgconf:Relationship:test5:hasConcludedLicense", + "from": "distfiles.ariadne.space:pkgconf:Package:test5", + "to": [ + "distfiles.ariadne.space:pkgconf:simplelicensing_LicenseExpression:MIT" + ], + "relationshipType": "hasConcludedLicense" + }, + { + "type": "Relationship", + "creationInfo": "_:creationinfo_1", + "spdxId": "distfiles.ariadne.space:pkgconf:Relationship:test6:hasDeclaredLicense", + "from": "distfiles.ariadne.space:pkgconf:Package:test6", + "to": [ + "distfiles.ariadne.space:pkgconf:simplelicensing_LicenseExpression:Apache-2.0" + ], + "relationshipType": "hasDeclaredLicense" + }, + { + "type": "Relationship", + "creationInfo": "_:creationinfo_1", + "spdxId": "distfiles.ariadne.space:pkgconf:Relationship:test6:hasConcludedLicense", + "from": "distfiles.ariadne.space:pkgconf:Package:test6", + "to": [ + "distfiles.ariadne.space:pkgconf:simplelicensing_LicenseExpression:Apache-2.0" + ], + "relationshipType": "hasConcludedLicense" + }, + { + "type": "SpdxDocument", + "creationInfo": "_:creationinfo_1", + "spdxId": "distfiles.ariadne.space:pkgconf:spdxDocument:1", + "rootElement": [ + "distfiles.ariadne.space:pkgconf:software_Sbom:meta_package", + "distfiles.ariadne.space:pkgconf:software_Sbom:test1", + "distfiles.ariadne.space:pkgconf:software_Sbom:test2", + "distfiles.ariadne.space:pkgconf:software_Sbom:test3", + "distfiles.ariadne.space:pkgconf:software_Sbom:test4", + "distfiles.ariadne.space:pkgconf:software_Sbom:test5", + "distfiles.ariadne.space:pkgconf:software_Sbom:test6" + ], + "element": [ + "distfiles.ariadne.space:pkgconf:Agent:default", + "distfiles.ariadne.space:pkgconf:simplelicensing_LicenseExpression:BSD-2-Clause", + "distfiles.ariadne.space:pkgconf:simplelicensing_LicenseExpression:BSD-1-Clause", + "distfiles.ariadne.space:pkgconf:simplelicensing_LicenseExpression:BSD-4-Clause", + "distfiles.ariadne.space:pkgconf:simplelicensing_LicenseExpression:MIT", + "distfiles.ariadne.space:pkgconf:simplelicensing_LicenseExpression:Apache-2.0", + "distfiles.ariadne.space:pkgconf:Relationship:meta_package:dependsOn:test1", + "distfiles.ariadne.space:pkgconf:Relationship:meta_package:dependsOn:test2", + "distfiles.ariadne.space:pkgconf:Relationship:meta_package:dependsOn:test3", + "distfiles.ariadne.space:pkgconf:Relationship:meta_package:dependsOn:test4", + "distfiles.ariadne.space:pkgconf:Relationship:meta_package:dependsOn:test5", + "distfiles.ariadne.space:pkgconf:Relationship:meta_package:dependsOn:test6", + "distfiles.ariadne.space:pkgconf:Relationship:meta_package:hasDeclaredLicense", + "distfiles.ariadne.space:pkgconf:Relationship:meta_package:hasConcludedLicense", + "distfiles.ariadne.space:pkgconf:Relationship:test1:hasDeclaredLicense", + "distfiles.ariadne.space:pkgconf:Relationship:test1:hasConcludedLicense", + "distfiles.ariadne.space:pkgconf:Relationship:test2:dependsOn:test3", + "distfiles.ariadne.space:pkgconf:Relationship:test2:hasDeclaredLicense", + "distfiles.ariadne.space:pkgconf:Relationship:test2:hasConcludedLicense", + "distfiles.ariadne.space:pkgconf:Relationship:test3:hasDeclaredLicense", + "distfiles.ariadne.space:pkgconf:Relationship:test3:hasConcludedLicense", + "distfiles.ariadne.space:pkgconf:Relationship:test4:dependsOn:test5", + "distfiles.ariadne.space:pkgconf:Relationship:test4:dependsOn:test6", + "distfiles.ariadne.space:pkgconf:Relationship:test4:hasDeclaredLicense", + "distfiles.ariadne.space:pkgconf:Relationship:test4:hasConcludedLicense", + "distfiles.ariadne.space:pkgconf:Relationship:test5:hasDeclaredLicense", + "distfiles.ariadne.space:pkgconf:Relationship:test5:hasConcludedLicense", + "distfiles.ariadne.space:pkgconf:Relationship:test6:hasDeclaredLicense", + "distfiles.ariadne.space:pkgconf:Relationship:test6:hasConcludedLicense", + "distfiles.ariadne.space:pkgconf:software_Sbom:meta_package", + "distfiles.ariadne.space:pkgconf:Package:meta_package", + "distfiles.ariadne.space:pkgconf:software_Sbom:test1", + "distfiles.ariadne.space:pkgconf:Package:test1", + "distfiles.ariadne.space:pkgconf:software_Sbom:test2", + "distfiles.ariadne.space:pkgconf:Package:test2", + "distfiles.ariadne.space:pkgconf:software_Sbom:test3", + "distfiles.ariadne.space:pkgconf:Package:test3", + "distfiles.ariadne.space:pkgconf:software_Sbom:test4", + "distfiles.ariadne.space:pkgconf:Package:test4", + "distfiles.ariadne.space:pkgconf:software_Sbom:test5", + "distfiles.ariadne.space:pkgconf:Package:test5", + "distfiles.ariadne.space:pkgconf:software_Sbom:test6", + "distfiles.ariadne.space:pkgconf:Package:test6" + ] + } + ] +} diff --git a/tests/lib-sbom-files/meta_package.json b/tests/lib-sbom-files/meta_package.json new file mode 100644 index 000000000000..248d663a6a1e --- /dev/null +++ b/tests/lib-sbom-files/meta_package.json @@ -0,0 +1,544 @@ +{ + "@context": "https://spdx.org/rdf/3.0.1/spdx-context.jsonld", + "@graph": [ + { + "type": "Agent", + "creationInfo": "_:creationinfo_1", + "spdxId": "https://github.com/pkgconf/pkgconf/Agent/default", + "name": "Default" + }, + { + "type": "CreationInfo", + "@id": "_:creationinfo_1", + "created": "test", + "createdBy": [ + "https://github.com/pkgconf/pkgconf/Agent/default" + ], + "specVersion": "3.0.1" + }, + { + "type": "simplelicensing_LicenseExpression", + "creationInfo": "_:creationinfo_1", + "spdxId": "https://github.com/pkgconf/pkgconf/simplelicensing_LicenseExpression/BSD-2-Clause", + "simplelicensing_licenseExpression": "BSD-2-Clause" + }, + { + "type": "simplelicensing_LicenseExpression", + "creationInfo": "_:creationinfo_1", + "spdxId": "https://github.com/pkgconf/pkgconf/simplelicensing_LicenseExpression/BSD-1-Clause", + "simplelicensing_licenseExpression": "BSD-1-Clause" + }, + { + "type": "simplelicensing_LicenseExpression", + "creationInfo": "_:creationinfo_1", + "spdxId": "https://github.com/pkgconf/pkgconf/simplelicensing_LicenseExpression/BSD-4-Clause", + "simplelicensing_licenseExpression": "BSD-4-Clause" + }, + { + "type": "simplelicensing_LicenseExpression", + "creationInfo": "_:creationinfo_1", + "spdxId": "https://github.com/pkgconf/pkgconf/simplelicensing_LicenseExpression/MIT", + "simplelicensing_licenseExpression": "MIT" + }, + { + "type": "simplelicensing_LicenseExpression", + "creationInfo": "_:creationinfo_1", + "spdxId": "https://github.com/pkgconf/pkgconf/simplelicensing_LicenseExpression/Apache-2.0", + "simplelicensing_licenseExpression": "Apache-2.0" + }, + { + "type": "software_Sbom", + "creationInfo": "_:creationinfo_1", + "spdxId": "https://github.com/pkgconf/pkgconf/software_Sbom/meta_package", + "software_sbomType": [ + "build" + ], + "rootElement": [ + "https://github.com/pkgconf/pkgconf/Package/meta_package" + ], + "element": [ + "https://github.com/pkgconf/pkgconf/Relationship/meta_package/dependsOn/test1", + "https://github.com/pkgconf/pkgconf/Relationship/meta_package/dependsOn/test2", + "https://github.com/pkgconf/pkgconf/Relationship/meta_package/dependsOn/test3", + "https://github.com/pkgconf/pkgconf/Relationship/meta_package/dependsOn/test4", + "https://github.com/pkgconf/pkgconf/Relationship/meta_package/dependsOn/test5", + "https://github.com/pkgconf/pkgconf/Relationship/meta_package/dependsOn/test6", + "https://github.com/pkgconf/pkgconf/Relationship/meta_package/hasDeclaredLicense", + "https://github.com/pkgconf/pkgconf/Relationship/meta_package/hasConcludedLicense" + ] + }, + { + "type": "software_Sbom", + "creationInfo": "_:creationinfo_1", + "spdxId": "https://github.com/pkgconf/pkgconf/software_Sbom/test1", + "software_sbomType": [ + "build" + ], + "rootElement": [ + "https://github.com/pkgconf/pkgconf/Package/test1" + ], + "element": [ + "https://github.com/pkgconf/pkgconf/Relationship/test1/hasDeclaredLicense", + "https://github.com/pkgconf/pkgconf/Relationship/test1/hasConcludedLicense" + ] + }, + { + "type": "software_Sbom", + "creationInfo": "_:creationinfo_1", + "spdxId": "https://github.com/pkgconf/pkgconf/software_Sbom/test2", + "software_sbomType": [ + "build" + ], + "rootElement": [ + "https://github.com/pkgconf/pkgconf/Package/test2" + ], + "element": [ + "https://github.com/pkgconf/pkgconf/Relationship/test2/dependsOn/test3", + "https://github.com/pkgconf/pkgconf/Relationship/test2/hasDeclaredLicense", + "https://github.com/pkgconf/pkgconf/Relationship/test2/hasConcludedLicense" + ] + }, + { + "type": "software_Sbom", + "creationInfo": "_:creationinfo_1", + "spdxId": "https://github.com/pkgconf/pkgconf/software_Sbom/test3", + "software_sbomType": [ + "build" + ], + "rootElement": [ + "https://github.com/pkgconf/pkgconf/Package/test3" + ], + "element": [ + "https://github.com/pkgconf/pkgconf/Relationship/test3/hasDeclaredLicense", + "https://github.com/pkgconf/pkgconf/Relationship/test3/hasConcludedLicense" + ] + }, + { + "type": "software_Sbom", + "creationInfo": "_:creationinfo_1", + "spdxId": "https://github.com/pkgconf/pkgconf/software_Sbom/test4", + "software_sbomType": [ + "build" + ], + "rootElement": [ + "https://github.com/pkgconf/pkgconf/Package/test4" + ], + "element": [ + "https://github.com/pkgconf/pkgconf/Relationship/test4/dependsOn/test5", + "https://github.com/pkgconf/pkgconf/Relationship/test4/dependsOn/test6", + "https://github.com/pkgconf/pkgconf/Relationship/test4/hasDeclaredLicense", + "https://github.com/pkgconf/pkgconf/Relationship/test4/hasConcludedLicense" + ] + }, + { + "type": "software_Sbom", + "creationInfo": "_:creationinfo_1", + "spdxId": "https://github.com/pkgconf/pkgconf/software_Sbom/test5", + "software_sbomType": [ + "build" + ], + "rootElement": [ + "https://github.com/pkgconf/pkgconf/Package/test5" + ], + "element": [ + "https://github.com/pkgconf/pkgconf/Relationship/test5/hasDeclaredLicense", + "https://github.com/pkgconf/pkgconf/Relationship/test5/hasConcludedLicense" + ] + }, + { + "type": "software_Sbom", + "creationInfo": "_:creationinfo_1", + "spdxId": "https://github.com/pkgconf/pkgconf/software_Sbom/test6", + "software_sbomType": [ + "build" + ], + "rootElement": [ + "https://github.com/pkgconf/pkgconf/Package/test6" + ], + "element": [ + "https://github.com/pkgconf/pkgconf/Relationship/test6/hasDeclaredLicense", + "https://github.com/pkgconf/pkgconf/Relationship/test6/hasConcludedLicense" + ] + }, + { + "type": "software_Package", + "creationInfo": "_:creationinfo_1", + "spdxId": "https://github.com/pkgconf/pkgconf/Package/meta_package", + "name": "meta_package", + "originatedBy": [ + "https://github.com/pkgconf/pkgconf/Agent/default" + ], + "software_copyrightText": "NOASSERTION", + "software_homePage": "https://github.com/pkgconf/pkgconf", + "software_downloadLocation": "https://github.com/pkgconf/pkgconf/archive/refs/tags/pkgconf-2.5.1.tar.gz", + "software_packageVersion": "1.0.0" + }, + { + "type": "software_Package", + "creationInfo": "_:creationinfo_1", + "spdxId": "https://github.com/pkgconf/pkgconf/Package/test1", + "name": "test1", + "originatedBy": [ + "https://github.com/pkgconf/pkgconf/Agent/default" + ], + "software_copyrightText": "Test1 copyright text", + "software_homePage": "", + "software_downloadLocation": "", + "software_packageVersion": "1.0.0" + }, + { + "type": "software_Package", + "creationInfo": "_:creationinfo_1", + "spdxId": "https://github.com/pkgconf/pkgconf/Package/test2", + "name": "test2", + "originatedBy": [ + "https://github.com/pkgconf/pkgconf/Agent/default" + ], + "software_copyrightText": "NOASSERTION", + "software_homePage": "https://github.com/pkgconf/pkgconf/", + "software_downloadLocation": "https://github.com/pkgconf/pkgconf/archive/refs/tags/pkgconf-2.5.1.tar.gz", + "software_packageVersion": "2.0.0" + }, + { + "type": "software_Package", + "creationInfo": "_:creationinfo_1", + "spdxId": "https://github.com/pkgconf/pkgconf/Package/test3", + "name": "test3", + "originatedBy": [ + "https://github.com/pkgconf/pkgconf/Agent/default" + ], + "software_copyrightText": "Test3 copyright text", + "software_homePage": "https://github.com/pkgconf/pkgconf/", + "software_downloadLocation": "https://github.com/pkgconf/pkgconf/archive/refs/tags/pkgconf-2.5.1.tar.gz", + "software_packageVersion": "3.0.0" + }, + { + "type": "software_Package", + "creationInfo": "_:creationinfo_1", + "spdxId": "https://github.com/pkgconf/pkgconf/Package/test4", + "name": "test4", + "originatedBy": [ + "https://github.com/pkgconf/pkgconf/Agent/default" + ], + "software_copyrightText": "NOASSERTION", + "software_homePage": "https://github.com/pkgconf/pkgconf/", + "software_downloadLocation": "https://github.com/pkgconf/pkgconf/archive/refs/tags/pkgconf-2.5.1.tar.gz", + "software_packageVersion": "4.0.0" + }, + { + "type": "software_Package", + "creationInfo": "_:creationinfo_1", + "spdxId": "https://github.com/pkgconf/pkgconf/Package/test5", + "name": "test5", + "originatedBy": [ + "https://github.com/pkgconf/pkgconf/Agent/default" + ], + "software_copyrightText": "NOASSERTION", + "software_homePage": "https://github.com/pkgconf/pkgconf/", + "software_downloadLocation": "https://github.com/pkgconf/pkgconf/archive/refs/tags/pkgconf-2.5.1.tar.gz", + "software_packageVersion": "5.0.0" + }, + { + "type": "software_Package", + "creationInfo": "_:creationinfo_1", + "spdxId": "https://github.com/pkgconf/pkgconf/Package/test6", + "name": "test6", + "originatedBy": [ + "https://github.com/pkgconf/pkgconf/Agent/default" + ], + "software_copyrightText": "NOASSERTION", + "software_homePage": "https://github.com/pkgconf/pkgconf/releases/", + "software_downloadLocation": "https://github.com/pkgconf/pkgconf/archive/refs/tags/pkgconf-2.5.1.tar.gz", + "software_packageVersion": "6.0.0" + }, + { + "type": "Relationship", + "creationInfo": "_:creationinfo_1", + "spdxId": "https://github.com/pkgconf/pkgconf/Relationship/meta_package/hasDeclaredLicense", + "from": "https://github.com/pkgconf/pkgconf/Package/meta_package", + "to": [ + "https://github.com/pkgconf/pkgconf/simplelicensing_LicenseExpression/BSD-2-Clause" + ], + "relationshipType": "hasDeclaredLicense" + }, + { + "type": "Relationship", + "creationInfo": "_:creationinfo_1", + "spdxId": "https://github.com/pkgconf/pkgconf/Relationship/meta_package/hasConcludedLicense", + "from": "https://github.com/pkgconf/pkgconf/Package/meta_package", + "to": [ + "https://github.com/pkgconf/pkgconf/simplelicensing_LicenseExpression/BSD-2-Clause" + ], + "relationshipType": "hasConcludedLicense" + }, + { + "type": "Relationship", + "creationInfo": "_:creationinfo_1", + "spdxId": "https://github.com/pkgconf/pkgconf/Relationship/meta_package/dependsOn/test1", + "from": "https://github.com/pkgconf/pkgconf/Package/meta_package", + "to": [ + "https://github.com/pkgconf/pkgconf/Package/test1" + ], + "relationshipType": "dependsOn" + }, + { + "type": "Relationship", + "creationInfo": "_:creationinfo_1", + "spdxId": "https://github.com/pkgconf/pkgconf/Relationship/meta_package/dependsOn/test2", + "from": "https://github.com/pkgconf/pkgconf/Package/meta_package", + "to": [ + "https://github.com/pkgconf/pkgconf/Package/test2" + ], + "relationshipType": "dependsOn" + }, + { + "type": "Relationship", + "creationInfo": "_:creationinfo_1", + "spdxId": "https://github.com/pkgconf/pkgconf/Relationship/meta_package/dependsOn/test3", + "from": "https://github.com/pkgconf/pkgconf/Package/meta_package", + "to": [ + "https://github.com/pkgconf/pkgconf/Package/test3" + ], + "relationshipType": "dependsOn" + }, + { + "type": "Relationship", + "creationInfo": "_:creationinfo_1", + "spdxId": "https://github.com/pkgconf/pkgconf/Relationship/meta_package/dependsOn/test4", + "from": "https://github.com/pkgconf/pkgconf/Package/meta_package", + "to": [ + "https://github.com/pkgconf/pkgconf/Package/test4" + ], + "relationshipType": "dependsOn" + }, + { + "type": "Relationship", + "creationInfo": "_:creationinfo_1", + "spdxId": "https://github.com/pkgconf/pkgconf/Relationship/meta_package/dependsOn/test5", + "from": "https://github.com/pkgconf/pkgconf/Package/meta_package", + "to": [ + "https://github.com/pkgconf/pkgconf/Package/test5" + ], + "relationshipType": "dependsOn" + }, + { + "type": "Relationship", + "creationInfo": "_:creationinfo_1", + "spdxId": "https://github.com/pkgconf/pkgconf/Relationship/meta_package/dependsOn/test6", + "from": "https://github.com/pkgconf/pkgconf/Package/meta_package", + "to": [ + "https://github.com/pkgconf/pkgconf/Package/test6" + ], + "relationshipType": "dependsOn" + }, + { + "type": "Relationship", + "creationInfo": "_:creationinfo_1", + "spdxId": "https://github.com/pkgconf/pkgconf/Relationship/test1/hasDeclaredLicense", + "from": "https://github.com/pkgconf/pkgconf/Package/test1", + "to": [ + "https://github.com/pkgconf/pkgconf/simplelicensing_LicenseExpression/BSD-1-Clause" + ], + "relationshipType": "hasDeclaredLicense" + }, + { + "type": "Relationship", + "creationInfo": "_:creationinfo_1", + "spdxId": "https://github.com/pkgconf/pkgconf/Relationship/test1/hasConcludedLicense", + "from": "https://github.com/pkgconf/pkgconf/Package/test1", + "to": [ + "https://github.com/pkgconf/pkgconf/simplelicensing_LicenseExpression/BSD-1-Clause" + ], + "relationshipType": "hasConcludedLicense" + }, + { + "type": "Relationship", + "creationInfo": "_:creationinfo_1", + "spdxId": "https://github.com/pkgconf/pkgconf/Relationship/test2/hasDeclaredLicense", + "from": "https://github.com/pkgconf/pkgconf/Package/test2", + "to": [ + "https://github.com/pkgconf/pkgconf/simplelicensing_LicenseExpression/BSD-2-Clause" + ], + "relationshipType": "hasDeclaredLicense" + }, + { + "type": "Relationship", + "creationInfo": "_:creationinfo_1", + "spdxId": "https://github.com/pkgconf/pkgconf/Relationship/test2/hasConcludedLicense", + "from": "https://github.com/pkgconf/pkgconf/Package/test2", + "to": [ + "https://github.com/pkgconf/pkgconf/simplelicensing_LicenseExpression/BSD-2-Clause" + ], + "relationshipType": "hasConcludedLicense" + }, + { + "type": "Relationship", + "creationInfo": "_:creationinfo_1", + "spdxId": "https://github.com/pkgconf/pkgconf/Relationship/test2/dependsOn/test3", + "from": "https://github.com/pkgconf/pkgconf/Package/test2", + "to": [ + "https://github.com/pkgconf/pkgconf/Package/test3" + ], + "relationshipType": "dependsOn" + }, + { + "type": "Relationship", + "creationInfo": "_:creationinfo_1", + "spdxId": "https://github.com/pkgconf/pkgconf/Relationship/test3/hasDeclaredLicense", + "from": "https://github.com/pkgconf/pkgconf/Package/test3", + "to": [ + "https://github.com/pkgconf/pkgconf/simplelicensing_LicenseExpression/BSD-4-Clause" + ], + "relationshipType": "hasDeclaredLicense" + }, + { + "type": "Relationship", + "creationInfo": "_:creationinfo_1", + "spdxId": "https://github.com/pkgconf/pkgconf/Relationship/test3/hasConcludedLicense", + "from": "https://github.com/pkgconf/pkgconf/Package/test3", + "to": [ + "https://github.com/pkgconf/pkgconf/simplelicensing_LicenseExpression/BSD-4-Clause" + ], + "relationshipType": "hasConcludedLicense" + }, + { + "type": "Relationship", + "creationInfo": "_:creationinfo_1", + "spdxId": "https://github.com/pkgconf/pkgconf/Relationship/test4/hasDeclaredLicense", + "from": "https://github.com/pkgconf/pkgconf/Package/test4", + "to": [ + "https://github.com/pkgconf/pkgconf/simplelicensing_LicenseExpression/MIT" + ], + "relationshipType": "hasDeclaredLicense" + }, + { + "type": "Relationship", + "creationInfo": "_:creationinfo_1", + "spdxId": "https://github.com/pkgconf/pkgconf/Relationship/test4/hasConcludedLicense", + "from": "https://github.com/pkgconf/pkgconf/Package/test4", + "to": [ + "https://github.com/pkgconf/pkgconf/simplelicensing_LicenseExpression/MIT" + ], + "relationshipType": "hasConcludedLicense" + }, + { + "type": "Relationship", + "creationInfo": "_:creationinfo_1", + "spdxId": "https://github.com/pkgconf/pkgconf/Relationship/test4/dependsOn/test5", + "from": "https://github.com/pkgconf/pkgconf/Package/test4", + "to": [ + "https://github.com/pkgconf/pkgconf/Package/test5" + ], + "relationshipType": "dependsOn" + }, + { + "type": "Relationship", + "creationInfo": "_:creationinfo_1", + "spdxId": "https://github.com/pkgconf/pkgconf/Relationship/test4/dependsOn/test6", + "from": "https://github.com/pkgconf/pkgconf/Package/test4", + "to": [ + "https://github.com/pkgconf/pkgconf/Package/test6" + ], + "relationshipType": "dependsOn" + }, + { + "type": "Relationship", + "creationInfo": "_:creationinfo_1", + "spdxId": "https://github.com/pkgconf/pkgconf/Relationship/test5/hasDeclaredLicense", + "from": "https://github.com/pkgconf/pkgconf/Package/test5", + "to": [ + "https://github.com/pkgconf/pkgconf/simplelicensing_LicenseExpression/MIT" + ], + "relationshipType": "hasDeclaredLicense" + }, + { + "type": "Relationship", + "creationInfo": "_:creationinfo_1", + "spdxId": "https://github.com/pkgconf/pkgconf/Relationship/test5/hasConcludedLicense", + "from": "https://github.com/pkgconf/pkgconf/Package/test5", + "to": [ + "https://github.com/pkgconf/pkgconf/simplelicensing_LicenseExpression/MIT" + ], + "relationshipType": "hasConcludedLicense" + }, + { + "type": "Relationship", + "creationInfo": "_:creationinfo_1", + "spdxId": "https://github.com/pkgconf/pkgconf/Relationship/test6/hasDeclaredLicense", + "from": "https://github.com/pkgconf/pkgconf/Package/test6", + "to": [ + "https://github.com/pkgconf/pkgconf/simplelicensing_LicenseExpression/Apache-2.0" + ], + "relationshipType": "hasDeclaredLicense" + }, + { + "type": "Relationship", + "creationInfo": "_:creationinfo_1", + "spdxId": "https://github.com/pkgconf/pkgconf/Relationship/test6/hasConcludedLicense", + "from": "https://github.com/pkgconf/pkgconf/Package/test6", + "to": [ + "https://github.com/pkgconf/pkgconf/simplelicensing_LicenseExpression/Apache-2.0" + ], + "relationshipType": "hasConcludedLicense" + }, + { + "type": "SpdxDocument", + "creationInfo": "_:creationinfo_1", + "spdxId": "https://github.com/pkgconf/pkgconf/spdxDocument/1", + "rootElement": [ + "https://github.com/pkgconf/pkgconf/software_Sbom/meta_package", + "https://github.com/pkgconf/pkgconf/software_Sbom/test1", + "https://github.com/pkgconf/pkgconf/software_Sbom/test2", + "https://github.com/pkgconf/pkgconf/software_Sbom/test3", + "https://github.com/pkgconf/pkgconf/software_Sbom/test4", + "https://github.com/pkgconf/pkgconf/software_Sbom/test5", + "https://github.com/pkgconf/pkgconf/software_Sbom/test6" + ], + "element": [ + "https://github.com/pkgconf/pkgconf/Agent/default", + "https://github.com/pkgconf/pkgconf/simplelicensing_LicenseExpression/BSD-2-Clause", + "https://github.com/pkgconf/pkgconf/simplelicensing_LicenseExpression/BSD-1-Clause", + "https://github.com/pkgconf/pkgconf/simplelicensing_LicenseExpression/BSD-4-Clause", + "https://github.com/pkgconf/pkgconf/simplelicensing_LicenseExpression/MIT", + "https://github.com/pkgconf/pkgconf/simplelicensing_LicenseExpression/Apache-2.0", + "https://github.com/pkgconf/pkgconf/Relationship/meta_package/dependsOn/test1", + "https://github.com/pkgconf/pkgconf/Relationship/meta_package/dependsOn/test2", + "https://github.com/pkgconf/pkgconf/Relationship/meta_package/dependsOn/test3", + "https://github.com/pkgconf/pkgconf/Relationship/meta_package/dependsOn/test4", + "https://github.com/pkgconf/pkgconf/Relationship/meta_package/dependsOn/test5", + "https://github.com/pkgconf/pkgconf/Relationship/meta_package/dependsOn/test6", + "https://github.com/pkgconf/pkgconf/Relationship/meta_package/hasDeclaredLicense", + "https://github.com/pkgconf/pkgconf/Relationship/meta_package/hasConcludedLicense", + "https://github.com/pkgconf/pkgconf/Relationship/test1/hasDeclaredLicense", + "https://github.com/pkgconf/pkgconf/Relationship/test1/hasConcludedLicense", + "https://github.com/pkgconf/pkgconf/Relationship/test2/dependsOn/test3", + "https://github.com/pkgconf/pkgconf/Relationship/test2/hasDeclaredLicense", + "https://github.com/pkgconf/pkgconf/Relationship/test2/hasConcludedLicense", + "https://github.com/pkgconf/pkgconf/Relationship/test3/hasDeclaredLicense", + "https://github.com/pkgconf/pkgconf/Relationship/test3/hasConcludedLicense", + "https://github.com/pkgconf/pkgconf/Relationship/test4/dependsOn/test5", + "https://github.com/pkgconf/pkgconf/Relationship/test4/dependsOn/test6", + "https://github.com/pkgconf/pkgconf/Relationship/test4/hasDeclaredLicense", + "https://github.com/pkgconf/pkgconf/Relationship/test4/hasConcludedLicense", + "https://github.com/pkgconf/pkgconf/Relationship/test5/hasDeclaredLicense", + "https://github.com/pkgconf/pkgconf/Relationship/test5/hasConcludedLicense", + "https://github.com/pkgconf/pkgconf/Relationship/test6/hasDeclaredLicense", + "https://github.com/pkgconf/pkgconf/Relationship/test6/hasConcludedLicense", + "https://github.com/pkgconf/pkgconf/software_Sbom/meta_package", + "https://github.com/pkgconf/pkgconf/Package/meta_package", + "https://github.com/pkgconf/pkgconf/software_Sbom/test1", + "https://github.com/pkgconf/pkgconf/Package/test1", + "https://github.com/pkgconf/pkgconf/software_Sbom/test2", + "https://github.com/pkgconf/pkgconf/Package/test2", + "https://github.com/pkgconf/pkgconf/software_Sbom/test3", + "https://github.com/pkgconf/pkgconf/Package/test3", + "https://github.com/pkgconf/pkgconf/software_Sbom/test4", + "https://github.com/pkgconf/pkgconf/Package/test4", + "https://github.com/pkgconf/pkgconf/software_Sbom/test5", + "https://github.com/pkgconf/pkgconf/Package/test5", + "https://github.com/pkgconf/pkgconf/software_Sbom/test6", + "https://github.com/pkgconf/pkgconf/Package/test6" + ] + } + ] +} diff --git a/tests/lib-sbom-files/with_dependency.json b/tests/lib-sbom-files/with_dependency.json new file mode 100644 index 000000000000..d2036259550c --- /dev/null +++ b/tests/lib-sbom-files/with_dependency.json @@ -0,0 +1,162 @@ +{ + "@context": "https://spdx.org/rdf/3.0.1/spdx-context.jsonld", + "@graph": [ + { + "type": "Agent", + "creationInfo": "_:creationinfo_1", + "spdxId": "https://github.com/pkgconf/pkgconf/Agent/default", + "name": "Default" + }, + { + "type": "CreationInfo", + "@id": "_:creationinfo_1", + "created": "test", + "createdBy": [ + "https://github.com/pkgconf/pkgconf/Agent/default" + ], + "specVersion": "3.0.1" + }, + { + "type": "simplelicensing_LicenseExpression", + "creationInfo": "_:creationinfo_1", + "spdxId": "https://github.com/pkgconf/pkgconf/simplelicensing_LicenseExpression/BSD-2-Clause", + "simplelicensing_licenseExpression": "BSD-2-Clause" + }, + { + "type": "simplelicensing_LicenseExpression", + "creationInfo": "_:creationinfo_1", + "spdxId": "https://github.com/pkgconf/pkgconf/simplelicensing_LicenseExpression/BSD-4-Clause", + "simplelicensing_licenseExpression": "BSD-4-Clause" + }, + { + "type": "software_Sbom", + "creationInfo": "_:creationinfo_1", + "spdxId": "https://github.com/pkgconf/pkgconf/software_Sbom/test2", + "software_sbomType": [ + "build" + ], + "rootElement": [ + "https://github.com/pkgconf/pkgconf/Package/test2" + ], + "element": [ + "https://github.com/pkgconf/pkgconf/Relationship/test2/dependsOn/test3", + "https://github.com/pkgconf/pkgconf/Relationship/test2/hasDeclaredLicense", + "https://github.com/pkgconf/pkgconf/Relationship/test2/hasConcludedLicense" + ] + }, + { + "type": "software_Sbom", + "creationInfo": "_:creationinfo_1", + "spdxId": "https://github.com/pkgconf/pkgconf/software_Sbom/test3", + "software_sbomType": [ + "build" + ], + "rootElement": [ + "https://github.com/pkgconf/pkgconf/Package/test3" + ], + "element": [ + "https://github.com/pkgconf/pkgconf/Relationship/test3/hasDeclaredLicense", + "https://github.com/pkgconf/pkgconf/Relationship/test3/hasConcludedLicense" + ] + }, + { + "type": "software_Package", + "creationInfo": "_:creationinfo_1", + "spdxId": "https://github.com/pkgconf/pkgconf/Package/test2", + "name": "test2", + "originatedBy": [ + "https://github.com/pkgconf/pkgconf/Agent/default" + ], + "software_copyrightText": "NOASSERTION", + "software_homePage": "https://github.com/pkgconf/pkgconf/", + "software_downloadLocation": "https://github.com/pkgconf/pkgconf/archive/refs/tags/pkgconf-2.5.1.tar.gz", + "software_packageVersion": "2.0.0" + }, + { + "type": "software_Package", + "creationInfo": "_:creationinfo_1", + "spdxId": "https://github.com/pkgconf/pkgconf/Package/test3", + "name": "test3", + "originatedBy": [ + "https://github.com/pkgconf/pkgconf/Agent/default" + ], + "software_copyrightText": "Test3 copyright text", + "software_homePage": "https://github.com/pkgconf/pkgconf/", + "software_downloadLocation": "https://github.com/pkgconf/pkgconf/archive/refs/tags/pkgconf-2.5.1.tar.gz", + "software_packageVersion": "3.0.0" + }, + { + "type": "Relationship", + "creationInfo": "_:creationinfo_1", + "spdxId": "https://github.com/pkgconf/pkgconf/Relationship/test2/hasDeclaredLicense", + "from": "https://github.com/pkgconf/pkgconf/Package/test2", + "to": [ + "https://github.com/pkgconf/pkgconf/simplelicensing_LicenseExpression/BSD-2-Clause" + ], + "relationshipType": "hasDeclaredLicense" + }, + { + "type": "Relationship", + "creationInfo": "_:creationinfo_1", + "spdxId": "https://github.com/pkgconf/pkgconf/Relationship/test2/hasConcludedLicense", + "from": "https://github.com/pkgconf/pkgconf/Package/test2", + "to": [ + "https://github.com/pkgconf/pkgconf/simplelicensing_LicenseExpression/BSD-2-Clause" + ], + "relationshipType": "hasConcludedLicense" + }, + { + "type": "Relationship", + "creationInfo": "_:creationinfo_1", + "spdxId": "https://github.com/pkgconf/pkgconf/Relationship/test2/dependsOn/test3", + "from": "https://github.com/pkgconf/pkgconf/Package/test2", + "to": [ + "https://github.com/pkgconf/pkgconf/Package/test3" + ], + "relationshipType": "dependsOn" + }, + { + "type": "Relationship", + "creationInfo": "_:creationinfo_1", + "spdxId": "https://github.com/pkgconf/pkgconf/Relationship/test3/hasDeclaredLicense", + "from": "https://github.com/pkgconf/pkgconf/Package/test3", + "to": [ + "https://github.com/pkgconf/pkgconf/simplelicensing_LicenseExpression/BSD-4-Clause" + ], + "relationshipType": "hasDeclaredLicense" + }, + { + "type": "Relationship", + "creationInfo": "_:creationinfo_1", + "spdxId": "https://github.com/pkgconf/pkgconf/Relationship/test3/hasConcludedLicense", + "from": "https://github.com/pkgconf/pkgconf/Package/test3", + "to": [ + "https://github.com/pkgconf/pkgconf/simplelicensing_LicenseExpression/BSD-4-Clause" + ], + "relationshipType": "hasConcludedLicense" + }, + { + "type": "SpdxDocument", + "creationInfo": "_:creationinfo_1", + "spdxId": "https://github.com/pkgconf/pkgconf/spdxDocument/1", + "rootElement": [ + "https://github.com/pkgconf/pkgconf/software_Sbom/test2", + "https://github.com/pkgconf/pkgconf/software_Sbom/test3" + ], + "element": [ + "https://github.com/pkgconf/pkgconf/Agent/default", + "https://github.com/pkgconf/pkgconf/simplelicensing_LicenseExpression/BSD-2-Clause", + "https://github.com/pkgconf/pkgconf/simplelicensing_LicenseExpression/BSD-4-Clause", + "https://github.com/pkgconf/pkgconf/Relationship/test2/dependsOn/test3", + "https://github.com/pkgconf/pkgconf/Relationship/test2/hasDeclaredLicense", + "https://github.com/pkgconf/pkgconf/Relationship/test2/hasConcludedLicense", + "https://github.com/pkgconf/pkgconf/Relationship/test3/hasDeclaredLicense", + "https://github.com/pkgconf/pkgconf/Relationship/test3/hasConcludedLicense", + "https://github.com/pkgconf/pkgconf/software_Sbom/test2", + "https://github.com/pkgconf/pkgconf/Package/test2", + "https://github.com/pkgconf/pkgconf/software_Sbom/test3", + "https://github.com/pkgconf/pkgconf/Package/test3" + ] + } + ] +} diff --git a/tests/lib-sbom/meta_package.pc b/tests/lib-sbom/meta_package.pc new file mode 100644 index 000000000000..f3dd872ad2d5 --- /dev/null +++ b/tests/lib-sbom/meta_package.pc @@ -0,0 +1,12 @@ +Name: meta_package +Description: Meta package to test SBOM creation +URL: https://github.com/pkgconf/pkgconf +Version: 1.0.0 +Requires: test1 \ + test2 \ + test3 \ + test4 \ + test5 \ + test6 +Source: https://github.com/pkgconf/pkgconf/archive/refs/tags/pkgconf-2.5.1.tar.gz +License: BSD-2-Clause diff --git a/tests/lib-sbom/test1.pc b/tests/lib-sbom/test1.pc new file mode 100644 index 000000000000..2cde40250c3f --- /dev/null +++ b/tests/lib-sbom/test1.pc @@ -0,0 +1,6 @@ +Name: test1 +Description: Test package 1 +Version: 1.0.0 +License: BSD-1-Clause +Copyright: Test1 copyright text +Requires: test1 diff --git a/tests/lib-sbom/test2.pc b/tests/lib-sbom/test2.pc new file mode 100644 index 000000000000..d8c6f5dc9537 --- /dev/null +++ b/tests/lib-sbom/test2.pc @@ -0,0 +1,7 @@ +Name: test2 +Description: Test package 2 +URL: https://github.com/pkgconf/pkgconf/ +Version: 2.0.0 +Requires: test3 +License: BSD-2-Clause +Source: https://github.com/pkgconf/pkgconf/archive/refs/tags/pkgconf-2.5.1.tar.gz diff --git a/tests/lib-sbom/test3.pc b/tests/lib-sbom/test3.pc new file mode 100644 index 000000000000..af65789843c1 --- /dev/null +++ b/tests/lib-sbom/test3.pc @@ -0,0 +1,8 @@ +Name: test3 +Description: Test package 3 +URL: https://github.com/pkgconf/pkgconf/ +Version: 3.0.0 +License: BSD-4-Clause +Copyright: Test3 copyright text +Source: https://github.com/pkgconf/pkgconf/archive/refs/tags/pkgconf-2.5.1.tar.gz + diff --git a/tests/lib-sbom/test4.pc b/tests/lib-sbom/test4.pc new file mode 100644 index 000000000000..502a5fec8445 --- /dev/null +++ b/tests/lib-sbom/test4.pc @@ -0,0 +1,8 @@ +Name: test4 +Description: Test package 4 +URL: https://github.com/pkgconf/pkgconf/ +Version: 4.0.0 +License: MIT +Source: https://github.com/pkgconf/pkgconf/archive/refs/tags/pkgconf-2.5.1.tar.gz +Requires: test5 \ + test6 diff --git a/tests/lib-sbom/test5.pc b/tests/lib-sbom/test5.pc new file mode 100644 index 000000000000..62e77cc3e05a --- /dev/null +++ b/tests/lib-sbom/test5.pc @@ -0,0 +1,7 @@ +Name: test5 +Description: Test package 5 +URL: https://github.com/pkgconf/pkgconf/ +Version: 5.0.0 +License: MIT +Source: https://github.com/pkgconf/pkgconf/archive/refs/tags/pkgconf-2.5.1.tar.gz + diff --git a/tests/lib-sbom/test6.pc b/tests/lib-sbom/test6.pc new file mode 100644 index 000000000000..b87c3805ed25 --- /dev/null +++ b/tests/lib-sbom/test6.pc @@ -0,0 +1,7 @@ +Name: test6 +Description: Test package 6 +URL: https://github.com/pkgconf/pkgconf/releases/ +Version: 6.0.0 +License: Apache-2.0 +Source: https://github.com/pkgconf/pkgconf/archive/refs/tags/pkgconf-2.5.1.tar.gz + diff --git a/tests/lib-sbom/variable-test1.pc b/tests/lib-sbom/variable-test1.pc new file mode 100644 index 000000000000..51a1a710dc5a --- /dev/null +++ b/tests/lib-sbom/variable-test1.pc @@ -0,0 +1,7 @@ +Name: variable-test1 +Description: Variable test 1 +URL: https://github.com/pkgconf/pkgconf/releases/ +Version: ${VERSION_VARIABLE_TEST} +License: BSD-2-Clause +Source: https://github.com/pkgconf/pkgconf/archive/refs/tags/pkgconf-2.5.1.tar.gz + diff --git a/tests/lib-sbom/variable-test2.pc b/tests/lib-sbom/variable-test2.pc new file mode 100644 index 000000000000..52033aba61b9 --- /dev/null +++ b/tests/lib-sbom/variable-test2.pc @@ -0,0 +1,7 @@ +Name: variable-test2 +Description: Variable test 2 +URL: https://github.com/pkgconf/pkgconf/releases/ +Version: 2.0 +License: ${license_variable_test} +Source: https://github.com/pkgconf/pkgconf/archive/refs/tags/pkgconf-2.5.1.tar.gz +Requires: variable-test1 diff --git a/tests/lib1/c-comment.pc b/tests/lib1/c-comment.pc index ed776a1f33e4..84f358066655 100644 --- a/tests/lib1/c-comment.pc +++ b/tests/lib1/c-comment.pc @@ -15,3 +15,4 @@ Libs: -L${libdir} -lfoo Cflags: -fPIC -I${includedir}/foo Cflags.private: -DFOO_STATIC License: ISC +Source: https://foo.bar/foo diff --git a/tests/lib1/cflags-shared-test.pc b/tests/lib1/cflags-shared-test.pc new file mode 100644 index 000000000000..a802466af90e --- /dev/null +++ b/tests/lib1/cflags-shared-test.pc @@ -0,0 +1,12 @@ +prefix=/test/local +exec_prefix=${prefix} +libdir=${prefix}/lib +includedir=${prefix}/include + +Name: cflags-shared-test +Description: A testing pkg-config file for Cflags.shared +Version: 1.2.3 +Libs: -L${libdir} -lfoo +Cflags: -I${includedir}/foo +Cflags.shared: -DFOO_SHARED +Cflags.private: -DFOO_STATIC diff --git a/tests/lib1/dollar-sign-escape-2.pc b/tests/lib1/dollar-sign-escape-2.pc new file mode 100644 index 000000000000..ccbc6ac28bac --- /dev/null +++ b/tests/lib1/dollar-sign-escape-2.pc @@ -0,0 +1,7 @@ +foo = bar + +Name: dollar-sign-escape +Description: test fixture +Version: 1.0.0 + +Cflags: $$foo diff --git a/tests/lib1/dollar-sign-escape.pc b/tests/lib1/dollar-sign-escape.pc new file mode 100644 index 000000000000..a3df7c4f5964 --- /dev/null +++ b/tests/lib1/dollar-sign-escape.pc @@ -0,0 +1,7 @@ +foo = bar + +Name: dollar-sign-escape +Description: test fixture +Version: 1.0.0 + +Cflags: $${foo} diff --git a/tests/lib1/duplicate-tuple.pc b/tests/lib1/duplicate-tuple.pc new file mode 100644 index 000000000000..501aa2a2fdd5 --- /dev/null +++ b/tests/lib1/duplicate-tuple.pc @@ -0,0 +1,6 @@ +prefix=/foo +prefix=${prefix} + +Name: duplicate-tuple +Version: 1.2.3 +Description: bla bla diff --git a/tests/lib1/flag-whitespace-2.pc b/tests/lib1/flag-whitespace-2.pc new file mode 100644 index 000000000000..0b4d98b1c869 --- /dev/null +++ b/tests/lib1/flag-whitespace-2.pc @@ -0,0 +1,5 @@ +Name: flag-whitespace-2 +Version: 0 +Description: test case for whitespace between flags +URL: https://github.com/pkgconf/pkgconf +Cflags: -I/includedir diff --git a/tests/lib1/flag-whitespace.pc b/tests/lib1/flag-whitespace.pc new file mode 100644 index 000000000000..3da8f10e2641 --- /dev/null +++ b/tests/lib1/flag-whitespace.pc @@ -0,0 +1,5 @@ +Name: flag-whitespace +Version: 0 +Description: test case for whitespace between flags +URL: https://github.com/pkgconf/pkgconf +Cflags: -I /includedir diff --git a/tests/lib1/foo.pc b/tests/lib1/foo.pc index daef9f9fa956..f12ca65b99d2 100644 --- a/tests/lib1/foo.pc +++ b/tests/lib1/foo.pc @@ -10,3 +10,5 @@ Libs: -L${libdir} -lfoo Cflags: -fPIC -I${includedir}/foo Cflags.private: -DFOO_STATIC License: ISC +Source: https://foo.bar/foo +License.file: https://foo.bar/foo/COPYING diff --git a/tests/lib1/foobar.pc b/tests/lib1/foobar.pc index e9aa84337600..582a8cb66b92 100644 --- a/tests/lib1/foobar.pc +++ b/tests/lib1/foobar.pc @@ -10,3 +10,4 @@ Libs: -L${libdir} -lfoobar Cflags: -fPIC -I${includedir}/foobar Cflags.private: -DFOOBAR_STATIC License: ISC +Source: https://foo.bar/foo diff --git a/tests/lib1/fragment-group-c.pc b/tests/lib1/fragment-group-c.pc index f79965be0f1d..42688cf6829c 100644 --- a/tests/lib1/fragment-group-c.pc +++ b/tests/lib1/fragment-group-c.pc @@ -1,4 +1,4 @@ Name: fragment-group-c Version: 1.0 Description: Test fixture for fragment groups -Libs: -Wl,--start-group -la -lgcc -Wl,--end-group -Wl,--gc-sections +Libs: -Wl,--start-group -la -lb -lgcc -Wl,--end-group -Wl,--gc-sections diff --git a/tests/lib1/framework-with-libs.pc b/tests/lib1/framework-with-libs.pc new file mode 100644 index 000000000000..16e070857ec0 --- /dev/null +++ b/tests/lib1/framework-with-libs.pc @@ -0,0 +1,4 @@ +Name: framework-with-libs +Description: test fixture +Version: 1 +Libs: -framework Security -lcrypto diff --git a/tests/lib1/idirafter-ordering.pc b/tests/lib1/idirafter-ordering.pc index c42f7022736e..090da1c99790 100644 --- a/tests/lib1/idirafter-ordering.pc +++ b/tests/lib1/idirafter-ordering.pc @@ -1,4 +1,4 @@ Name: Bad Description: Demonstrates problems with -idirafter in old pkg-config; see also https://bugs.freedesktop.org/show_bug.cgi?id=23480 Version: 1 -Cflags: -I/opt/bad/include1 -idirafter -I/opt/bad/include2 -I/opt/bad/include3 +Cflags: -I/opt/bad/include1 -idirafter /opt/bad/include4 -I/opt/bad/include2 -I/opt/bad/include3 diff --git a/tests/lib1/isystem-sysroot-prefixed.pc b/tests/lib1/isystem-sysroot-prefixed.pc new file mode 100644 index 000000000000..236678af57fa --- /dev/null +++ b/tests/lib1/isystem-sysroot-prefixed.pc @@ -0,0 +1,4 @@ +Name: isystem-sysroot-prefixed +Description: -isystem path already begins with the configured sysroot; sysroot must not be injected a second time (regression test for off-by-one in should_inject_sysroot_child) +Version: 1 +Cflags: -isystem /s/usr/include diff --git a/tests/lib1/libs-shared-test.pc b/tests/lib1/libs-shared-test.pc new file mode 100644 index 000000000000..ce24d47274bc --- /dev/null +++ b/tests/lib1/libs-shared-test.pc @@ -0,0 +1,10 @@ +prefix=/test/local +exec_prefix=${prefix} +libdir=${prefix}/lib +includedir=${prefix}/include + +Name: libs-shared-test +Description: A testing pkg-config file for Cflags.shared +Version: 1.2.3 +Libs.private: libfoo-static.a +Libs.shared: libfoo-shared.so diff --git a/tests/lib1/license-malformed.pc b/tests/lib1/license-malformed.pc new file mode 100644 index 000000000000..7c3ea12152e9 --- /dev/null +++ b/tests/lib1/license-malformed.pc @@ -0,0 +1,10 @@ +prefix=/test +exec_prefix=${prefix} +libdir=${prefix}/lib +includedir=${prefix}/include + +Name: license-malformed +Description: regression fixture for a License field whose token sanitizes to empty +Version: 1.0 +Libs: -L${libdir} -llicense-malformed +License: MIT @@@ ISC diff --git a/tests/lib1/link-abi-cxx.pc b/tests/lib1/link-abi-cxx.pc new file mode 100644 index 000000000000..42b77dc231cb --- /dev/null +++ b/tests/lib1/link-abi-cxx.pc @@ -0,0 +1,5 @@ +Name: link-abi-cxx +Description: a C++ leaf library +Version: 1.0.0 +Libs: -lcxx +Link.ABI: C++ diff --git a/tests/lib1/link-abi-multi.pc b/tests/lib1/link-abi-multi.pc new file mode 100644 index 000000000000..03e1c0979135 --- /dev/null +++ b/tests/lib1/link-abi-multi.pc @@ -0,0 +1,5 @@ +Name: link-abi-multi +Description: a library declaring multiple Link.ABI tags with duplicates and mixed case +Version: 1.0.0 +Libs: -lmulti +Link.ABI: c++, Fortran, C++ diff --git a/tests/lib1/link-abi-plainc.pc b/tests/lib1/link-abi-plainc.pc new file mode 100644 index 000000000000..e72d63c7760a --- /dev/null +++ b/tests/lib1/link-abi-plainc.pc @@ -0,0 +1,4 @@ +Name: link-abi-plainc +Description: a plain C library with no Link.ABI declaration +Version: 1.0.0 +Libs: -lplainc diff --git a/tests/lib1/link-abi-private.pc b/tests/lib1/link-abi-private.pc new file mode 100644 index 000000000000..df44d8dd19f9 --- /dev/null +++ b/tests/lib1/link-abi-private.pc @@ -0,0 +1,5 @@ +Name: link-abi-private +Description: a library that privately depends on a C++ library +Version: 1.0.0 +Requires.private: link-abi-cxx +Libs: -lprivate diff --git a/tests/lib1/link-abi-public.pc b/tests/lib1/link-abi-public.pc new file mode 100644 index 000000000000..28b4f4fb6560 --- /dev/null +++ b/tests/lib1/link-abi-public.pc @@ -0,0 +1,5 @@ +Name: link-abi-public +Description: a library that publicly exposes a C++ dependency +Version: 1.0.0 +Requires: link-abi-cxx +Libs: -lpublic diff --git a/tests/lib1/multiline-folding.pc b/tests/lib1/multiline-folding.pc new file mode 100644 index 000000000000..e545f4e39e8d --- /dev/null +++ b/tests/lib1/multiline-folding.pc @@ -0,0 +1,9 @@ +Name: multiline-folding +Description: test fixture +Version: 1.0.0 + +Cflags: -foo\ +-bar + +Libs: -qux\ + -baz diff --git a/tests/lib1/requires-shared-dep.pc b/tests/lib1/requires-shared-dep.pc new file mode 100644 index 000000000000..80045bea0bd3 --- /dev/null +++ b/tests/lib1/requires-shared-dep.pc @@ -0,0 +1,10 @@ +prefix=/test/local +exec_prefix=${prefix} +libdir=${prefix}/lib +includedir=${prefix}/include + +Name: requires-shared-dep +Description: A dependency only needed for shared linking +Version: 1.0.0 +Libs: -L${libdir} -lshared-dep +Cflags: -I${includedir}/shared-dep diff --git a/tests/lib1/requires-shared.pc b/tests/lib1/requires-shared.pc new file mode 100644 index 000000000000..287a726c55b8 --- /dev/null +++ b/tests/lib1/requires-shared.pc @@ -0,0 +1,11 @@ +prefix=/test/local +exec_prefix=${prefix} +libdir=${prefix}/lib +includedir=${prefix}/include + +Name: requires-shared +Description: A testing pkg-config file for Requires.shared +Version: 1.0.0 +Libs: -L${libdir} -lrequires-shared +Cflags: -I${includedir}/requires-shared +Requires.shared: requires-shared-dep diff --git a/tests/lib1/utf8.pc b/tests/lib1/utf8.pc deleted file mode 100644 index 6507ec0f25b9..000000000000 --- a/tests/lib1/utf8.pc +++ /dev/null @@ -1,10 +0,0 @@ -prefix=/tëst -exec_prefix=${prefix} -libdir=${prefix}/lib -includedir=${prefix}/include - -Name: utf8 -Description: Library installed in a prefix with UTF-8 -Version: 0 -Libs: -L${libdir} -lutf8 -Cflags: -I${includedir} diff --git a/tests/lib1/variable-fragment-expansion.pc b/tests/lib1/variable-fragment-expansion.pc new file mode 100644 index 000000000000..68e9a5c4dd2c --- /dev/null +++ b/tests/lib1/variable-fragment-expansion.pc @@ -0,0 +1,7 @@ +baselibs = -pthread -lm + +Version: 1 +Name: foo +Description: Repro + +Libs: -lfoo ${baselibs} diff --git a/tests/meson.build b/tests/meson.build deleted file mode 100644 index 56406c3bb0c8..000000000000 --- a/tests/meson.build +++ /dev/null @@ -1,23 +0,0 @@ -configure_file(input: 'Kyuafile.in', output: 'Kyuafile', configuration: cdata) -configure_file(input: 'test_env.sh.in', output: 'test_env.sh', configuration: cdata) - - -tests = [ - 'basic', - 'builtins', - 'conflicts', - 'framework', - 'parser', - 'provides', - 'regress', - 'requires', - 'symlink', - 'sysroot', - 'version', -] - - -# yuck -foreach test : tests - test_file = configure_file(input: test + '.sh', output: test, copy: true) -endforeach diff --git a/tests/parser.sh b/tests/parser.sh deleted file mode 100755 index 9d9f9c6ff4ba..000000000000 --- a/tests/parser.sh +++ /dev/null @@ -1,372 +0,0 @@ -#!/usr/bin/env atf-sh - -. $(atf_get_srcdir)/test_env.sh - -tests_init \ - comments \ - comments_in_fields \ - dos \ - no_trailing_newline \ - argv_parse \ - bad_option \ - argv_parse_3 \ - tilde_quoting \ - paren_quoting \ - multiline_field \ - multiline_bogus_header \ - escaped_backslash \ - flag_order_1 \ - flag_order_2 \ - flag_order_3 \ - flag_order_4 \ - quoted \ - variable_whitespace \ - fragment_escaping_1 \ - fragment_escaping_2 \ - fragment_escaping_3 \ - fragment_quoting \ - fragment_quoting_2 \ - fragment_quoting_3 \ - fragment_quoting_5 \ - fragment_quoting_7 \ - fragment_comment \ - msvc_fragment_quoting \ - msvc_fragment_render_cflags \ - tuple_dequote \ - version_with_whitespace \ - version_with_whitespace_2 \ - version_with_whitespace_diagnostic \ - fragment_groups \ - fragment_groups_composite \ - fragment_tree \ - truncated \ - c_comment - -comments_body() -{ - export PKG_CONFIG_PATH="${selfdir}/lib1" - atf_check \ - -o inline:"-lfoo\n" \ - pkgconf --libs comments -} - -comments_in_fields_body() -{ - export PKG_CONFIG_PATH="${selfdir}/lib1" - atf_check \ - -o inline:"-lfoo\n" \ - pkgconf --libs comments-in-fields -} - -dos_body() -{ - export PKG_CONFIG_PATH="${selfdir}/lib1" - atf_check \ - -o inline:"-L/test/lib/dos-lineendings -ldos-lineendings\n" \ - pkgconf --libs dos-lineendings -} - -no_trailing_newline_body() -{ - export PKG_CONFIG_PATH="${selfdir}/lib1" - atf_check \ - -o inline:"-I/test/include/no-trailing-newline\n" \ - pkgconf --cflags no-trailing-newline -} - -argv_parse_body() -{ - export PKG_CONFIG_PATH="${selfdir}/lib1" - atf_check \ - -o inline:"-llib-3 -llib-1 -llib-2 -lpthread\n" \ - pkgconf --libs argv-parse -} - -bad_option_body() -{ - export PKG_CONFIG_PATH="${selfdir}/lib1" - atf_check \ - -e ignore \ - -s eq:1 \ - pkgconf --exists -foo -} - -argv_parse_3_body() -{ - export PKG_CONFIG_PATH="${selfdir}/lib1" - atf_check \ - -o inline:"-llib-1 -pthread /test/lib/lib2.so\n" \ - pkgconf --libs argv-parse-3 -} - -tilde_quoting_body() -{ - export PKG_CONFIG_PATH="${selfdir}/lib1" - atf_check \ - -o inline:"-L~ -ltilde\n" \ - pkgconf --libs tilde-quoting - atf_check \ - -o inline:"-I~\n" \ - pkgconf --cflags tilde-quoting -} - -paren_quoting_body() -{ - export PKG_CONFIG_PATH="${selfdir}/lib1" - atf_check \ - -o inline:"-L\$(libdir) -ltilde\n" \ - pkgconf --libs paren-quoting -} - -multiline_field_body() -{ - export PKG_CONFIG_PATH="${selfdir}/lib1" - atf_check \ - -e ignore \ - -o match:"multiline description" \ - pkgconf --list-all -} - -multiline_bogus_header_body() -{ - export PKG_CONFIG_PATH="${selfdir}/lib1" - atf_check \ - -s eq:0 \ - pkgconf --exists multiline-bogus -} - -escaped_backslash_body() -{ - atf_check \ - -e ignore \ - -o inline:"-IC:\\\\\\\\A\n" \ - pkgconf --with-path=${selfdir}/lib1 --cflags escaped-backslash -} - -quoted_body() -{ - export PKG_CONFIG_PATH="${selfdir}/lib1" - atf_check \ - -o inline:"-DQUOTED=\\\"bla\\\" -DA=\\\"escaped\\ string\\\'\\ literal\\\" -DB=\\\\\\1\$ -DC=bla\n" \ - pkgconf --cflags quotes -} - -flag_order_1_body() -{ - export PKG_CONFIG_PATH="${selfdir}/lib1" - atf_check \ - -o inline:"-L/test/lib -Bdynamic -lfoo -Bstatic -lbar\n" \ - pkgconf --libs flag-order-1 -} - -flag_order_2_body() -{ - export PKG_CONFIG_PATH="${selfdir}/lib1" - atf_check \ - -o inline:"-L/test/lib -Bdynamic -lfoo -Bstatic -lbar -lfoo\n" \ - pkgconf --libs flag-order-1 foo -} - -flag_order_3_body() -{ - export PKG_CONFIG_PATH="${selfdir}/lib1" - atf_check \ - -o inline:"-L/test/lib -Wl,--start-group -lfoo -lbar -Wl,--end-group\n" \ - pkgconf --libs flag-order-3 -} - -flag_order_4_body() -{ - export PKG_CONFIG_PATH="${selfdir}/lib1" - atf_check \ - -o inline:"-L/test/lib -Wl,--start-group -lfoo -lbar -Wl,--end-group -lfoo\n" \ - pkgconf --libs flag-order-3 foo -} - -variable_whitespace_body() -{ - export PKG_CONFIG_PATH="${selfdir}/lib1" - atf_check \ - -o inline:"-I/test/include\n" \ - pkgconf --cflags variable-whitespace -} - -fragment_quoting_body() -{ - export PKG_CONFIG_PATH="${selfdir}/lib1" - atf_check \ - -o inline:"-fPIC -I/test/include/foo -DQUOTED=\\\"/test/share/doc\\\"\n" \ - pkgconf --cflags fragment-quoting -} - -fragment_quoting_2_body() -{ - export PKG_CONFIG_PATH="${selfdir}/lib1" - atf_check \ - -o inline:"-fPIC -I/test/include/foo -DQUOTED=/test/share/doc\n" \ - pkgconf --cflags fragment-quoting-2 -} - -fragment_quoting_3_body() -{ - export PKG_CONFIG_PATH="${selfdir}/lib1" - atf_check \ - -o inline:"-fPIC -I/test/include/foo -DQUOTED=\\\"/test/share/doc\\\"\n" \ - pkgconf --cflags fragment-quoting-3 -} - -fragment_quoting_5_body() -{ - export PKG_CONFIG_PATH="${selfdir}/lib1" - atf_check \ - -o inline:"-fPIC -I/test/include/foo -DQUOTED=/test/share/doc\n" \ - pkgconf --cflags fragment-quoting-5 -} - -fragment_quoting_7_body() -{ - export PKG_CONFIG_PATH="${selfdir}/lib1" - atf_check \ - -o inline:"-Dhello=10 -Dworld=+32 -DDEFINED_FROM_PKG_CONFIG=hello\\ world\n" \ - pkgconf --cflags fragment-quoting-7 -} - -fragment_escaping_1_body() -{ - atf_check \ - -o inline:"-IC:\\\\\\\\D\\ E\n" \ - pkgconf --with-path="${selfdir}/lib1" --cflags fragment-escaping-1 -} - -fragment_escaping_2_body() -{ - atf_check \ - -o inline:"-IC:\\\\\\\\D\\ E\n" \ - pkgconf --with-path="${selfdir}/lib1" --cflags fragment-escaping-2 -} - -fragment_escaping_3_body() -{ - atf_check \ - -o inline:"-IC:\\\\\\\\D\\ E\n" \ - pkgconf --with-path="${selfdir}/lib1" --cflags fragment-escaping-3 -} - -fragment_quoting_7a_body() -{ - set -x - - test_cflags=$(pkgconf --with-path=${selfdir}/lib1 --cflags fragment-quoting-7) - echo $test_cflags -# test_cflags='-Dhello=10 -Dworld=+32 -DDEFINED_FROM_PKG_CONFIG=hello\\ world' - - cat > test.c <<- __TESTCASE_END__ - int main(int argc, char *argv[]) { return DEFINED_FROM_PKG_CONFIG; } - __TESTCASE_END__ - cc -o test-fragment-quoting-7 ${test_cflags} ./test.c - atf_check -e 42 ./test-fragment-quoting-7 - rm -f test.c test-fragment-quoting-7 - - set +x -} - - -fragment_comment_body() -{ - atf_check \ - -o inline:'kuku=\#ttt\n' \ - pkgconf --with-path="${selfdir}/lib1" --cflags fragment-comment -} - -msvc_fragment_quoting_body() -{ - export PKG_CONFIG_PATH="${selfdir}/lib1" - atf_check \ - -o inline:'/libpath:"C:\D E" E.lib \n' \ - pkgconf --libs --msvc-syntax fragment-escaping-1 -} - -msvc_fragment_render_cflags_body() -{ - export PKG_CONFIG_PATH="${selfdir}/lib1" - atf_check \ - -o inline:'/I/test/include/foo /DFOO_STATIC \n' \ - pkgconf --cflags --static --msvc-syntax foo -} - -tuple_dequote_body() -{ - atf_check \ - -o inline:'-L/test/lib -lfoo\n' \ - pkgconf --with-path="${selfdir}/lib1" --libs tuple-quoting -} - -version_with_whitespace_body() -{ - atf_check \ - -o inline:'3.922\n' \ - pkgconf --with-path="${selfdir}/lib1" --modversion malformed-version -} - -version_with_whitespace_2_body() -{ - atf_check \ - -o inline:'malformed-version = 3.922\n' \ - pkgconf --with-path="${selfdir}/lib1" --print-provides malformed-version -} - -version_with_whitespace_diagnostic_body() -{ - atf_check \ - -o match:warning \ - pkgconf --with-path="${selfdir}/lib1" --validate malformed-version -} - -fragment_groups_body() -{ - atf_check \ - -o inline:'-Wl,--start-group -la -lb -Wl,--end-group -nodefaultlibs -Wl,--start-group -la -lgcc -Wl,--end-group -Wl,--gc-sections\n' \ - pkgconf --with-path="${selfdir}/lib1" --libs fragment-groups -} - -fragment_groups_composite_body() -{ - atf_check \ - -o inline:'-Wl,--start-group -la -lb -Wl,--end-group -nodefaultlibs -Wl,--start-group -la -lgcc -Wl,--end-group -Wl,--gc-sections\n' \ - pkgconf --with-path="${selfdir}/lib1" --libs fragment-groups-2 -} - -truncated_body() -{ - atf_check \ - -o match:warning -s exit:1 \ - pkgconf --with-path="${selfdir}/lib1" --validate truncated -} - -c_comment_body() -{ - atf_check \ - -o match:warning \ - pkgconf --with-path="${selfdir}/lib1" --validate c-comment -} - -fragment_tree_body() -{ - atf_check \ - -o inline:"'-Wl,--start-group' [untyped] - '-la' [type l] - '-lb' [type l] - '-Wl,--end-group' [untyped] - -'-nodefaultlibs' [untyped] -'-Wl,--start-group' [untyped] - '-la' [type l] - '-lgcc' [type l] - '-Wl,--end-group' [untyped] - -'-Wl,--gc-sections' [untyped] - -" \ - pkgconf --with-path="${selfdir}/lib1" --fragment-tree fragment-groups-2 -} - diff --git a/tests/personality-data/i386-linux-gnu.personality b/tests/personality-data/i386-linux-gnu.personality new file mode 100644 index 000000000000..fbfde13da012 --- /dev/null +++ b/tests/personality-data/i386-linux-gnu.personality @@ -0,0 +1,4 @@ +Triplet: i386-linux-gnu +DefaultSearchPaths: /usr/lib/i386-linux-gnu/pkgconfig:/usr/share/pkgconfig +SystemIncludePaths: /usr/lib/i386-linux-gnu/include +SystemLibraryPaths: /usr/lib/i386-linux-gnu/lib diff --git a/tests/provides.sh b/tests/provides.sh deleted file mode 100755 index b699dbf563f1..000000000000 --- a/tests/provides.sh +++ /dev/null @@ -1,310 +0,0 @@ -#!/usr/bin/env atf-sh - -. $(atf_get_srcdir)/test_env.sh - -tests_init \ - simple \ - foo \ - bar \ - baz \ - quux \ - moo \ - meow \ - indirect_dependency_node - -simple_body() -{ - export PKG_CONFIG_PATH="${selfdir}/lib1" -OUTPUT="provides-test-foo = 1.0.0 -provides-test-bar > 1.1.0 -provides-test-baz >= 1.1.0 -provides-test-quux < 1.2.0 -provides-test-moo <= 1.2.0 -provides-test-meow != 1.3.0 -provides = 1.2.3 -" - atf_check \ - -o inline:"${OUTPUT}" \ - pkgconf --print-provides provides - atf_check \ - -o inline:"-lfoo\n" \ - pkgconf --libs provides-request-simple - atf_check \ - -e ignore \ - -s exit:1 \ - pkgconf --no-provides --libs provides-request-simple -} - -foo_body() -{ - export PKG_CONFIG_PATH="${selfdir}/lib1" - atf_check \ - -o ignore \ - pkgconf --libs provides-test-foo - atf_check \ - -o ignore \ - pkgconf --libs 'provides-test-foo = 1.0.0' - atf_check \ - -o ignore \ - pkgconf --libs 'provides-test-foo >= 1.0.0' - atf_check \ - -o ignore \ - pkgconf --libs 'provides-test-foo <= 1.0.0' - atf_check \ - -s exit:1 \ - -e ignore \ - -o ignore \ - pkgconf --libs 'provides-test-foo != 1.0.0' - atf_check \ - -s exit:1 \ - -e ignore \ - -o ignore \ - pkgconf --libs 'provides-test-foo > 1.0.0' - atf_check \ - -s exit:1 \ - -e ignore \ - -o ignore \ - pkgconf --libs 'provides-test-foo < 1.0.0' -} - -bar_body() -{ - export PKG_CONFIG_PATH="${selfdir}/lib1" - atf_check \ - -o ignore \ - pkgconf --libs provides-test-bar - atf_check \ - -o ignore \ - pkgconf --libs 'provides-test-bar = 1.1.1' - atf_check \ - -o ignore \ - pkgconf --libs 'provides-test-bar >= 1.1.1' - atf_check \ - -o ignore \ - pkgconf --libs 'provides-test-bar <= 1.1.1' - atf_check \ - -o ignore \ - pkgconf --libs 'provides-test-bar != 1.1.0' - atf_check \ - -s exit:1 \ - -e ignore \ - -o ignore \ - pkgconf --libs 'provides-test-bar != 1.1.1' - atf_check \ - -o ignore \ - pkgconf --libs 'provides-test-bar > 1.1.1' - atf_check \ - -s exit:1 \ - -e ignore \ - -o ignore \ - pkgconf --libs 'provides-test-bar <= 1.1.0' - atf_check \ - -o ignore \ - pkgconf --libs 'provides-test-bar <= 1.2.0' -} - -baz_body() -{ - export PKG_CONFIG_PATH="${selfdir}/lib1" - atf_check \ - -o ignore \ - pkgconf --libs provides-test-baz - atf_check \ - -o ignore \ - pkgconf --libs 'provides-test-baz = 1.1.0' - atf_check \ - -o ignore \ - pkgconf --libs 'provides-test-baz >= 1.1.0' - atf_check \ - -o ignore \ - pkgconf --libs 'provides-test-baz <= 1.1.0' - atf_check \ - -s exit:1 \ - -e ignore \ - -o ignore \ - pkgconf --libs 'provides-test-baz != 1.1.0' - atf_check \ - -o ignore \ - pkgconf --libs 'provides-test-baz != 1.0.0' - atf_check \ - -o ignore \ - pkgconf --libs 'provides-test-baz > 1.1.1' - atf_check \ - -o ignore \ - pkgconf --libs 'provides-test-baz > 1.1.0' - atf_check \ - -s exit:1 \ - -e ignore \ - -o ignore \ - pkgconf --libs 'provides-test-baz < 1.1.0' - atf_check \ - -o ignore \ - pkgconf --libs 'provides-test-baz < 1.2.0' -} - -quux_body() -{ - export PKG_CONFIG_PATH="${selfdir}/lib1" - atf_check \ - -o ignore \ - pkgconf --libs provides-test-quux - atf_check \ - -o ignore \ - pkgconf --libs 'provides-test-quux = 1.1.9' - atf_check \ - -o ignore \ - pkgconf --libs 'provides-test-quux >= 1.1.0' - atf_check \ - -o ignore \ - pkgconf --libs 'provides-test-quux >= 1.1.9' - atf_check \ - -s exit:1 \ - -e ignore \ - -o ignore \ - pkgconf --libs 'provides-test-quux >= 1.2.0' - atf_check \ - -s exit:1 \ - -e ignore \ - -o ignore \ - pkgconf --libs 'provides-test-quux <= 1.2.0' - atf_check \ - -o ignore \ - pkgconf --libs 'provides-test-quux <= 1.1.9' - atf_check \ - -o ignore \ - pkgconf --libs 'provides-test-quux != 1.2.0' - atf_check \ - -s exit:1 \ - -e ignore \ - -o ignore \ - pkgconf --libs 'provides-test-quux != 1.1.0' - atf_check \ - -s exit:1 \ - -e ignore \ - -o ignore \ - pkgconf --libs 'provides-test-quux != 1.0.0' - atf_check \ - -o ignore \ - pkgconf --libs 'provides-test-quux > 1.1.9' - atf_check \ - -s exit:1 \ - -e ignore \ - -o ignore \ - pkgconf --libs 'provides-test-quux > 1.2.0' - atf_check \ - -o ignore \ - pkgconf --libs 'provides-test-quux < 1.1.0' - atf_check \ - -s exit:1 \ - -e ignore \ - -o ignore \ - pkgconf --libs 'provides-test-quux > 1.2.0' -} - -moo_body() -{ - export PKG_CONFIG_PATH="${selfdir}/lib1" - atf_check \ - -o ignore \ - pkgconf --libs provides-test-moo - atf_check \ - -o ignore \ - pkgconf --libs 'provides-test-moo = 1.2.0' - atf_check \ - -o ignore \ - pkgconf --libs 'provides-test-moo >= 1.1.0' - atf_check \ - -o ignore \ - pkgconf --libs 'provides-test-moo >= 1.2.0' - atf_check \ - -s exit:1 \ - -e ignore \ - -o ignore \ - pkgconf --libs 'provides-test-moo >= 1.2.1' - atf_check \ - -o ignore \ - pkgconf --libs 'provides-test-moo <= 1.2.0' - atf_check \ - -s exit:1 \ - -e ignore \ - -o ignore \ - pkgconf --libs 'provides-test-moo != 1.1.0' - atf_check \ - -s exit:1 \ - -e ignore \ - -o ignore \ - pkgconf --libs 'provides-test-moo != 1.0.0' - atf_check \ - -o ignore \ - pkgconf --libs 'provides-test-moo > 1.1.9' - atf_check \ - -s exit:1 \ - -e ignore \ - -o ignore \ - pkgconf --libs 'provides-test-moo > 1.2.0' - atf_check \ - -o ignore \ - pkgconf --libs 'provides-test-moo < 1.1.0' - atf_check \ - -o ignore \ - pkgconf --libs 'provides-test-moo < 1.2.0' -} - -meow_body() -{ - export PKG_CONFIG_PATH="${selfdir}/lib1" - atf_check \ - -o ignore \ - pkgconf --libs provides-test-meow - atf_check \ - -s exit:1 \ - -e ignore \ - -o ignore \ - pkgconf --libs 'provides-test-meow = 1.3.0' - atf_check \ - -o ignore \ - pkgconf --libs 'provides-test-meow != 1.3.0' - atf_check \ - -s exit:1 \ - -e ignore \ - -o ignore \ - pkgconf --libs 'provides-test-meow > 1.2.9' - atf_check \ - -s exit:1 \ - -e ignore \ - -o ignore \ - pkgconf --libs 'provides-test-meow < 1.3.1' - atf_check \ - -o ignore \ - pkgconf --libs 'provides-test-meow < 1.3.0' - atf_check \ - -o ignore \ - pkgconf --libs 'provides-test-meow > 1.3.0' - atf_check \ - -s exit:1 \ - -e ignore \ - -o ignore \ - pkgconf --libs 'provides-test-meow >= 1.3.0' - atf_check \ - -o ignore \ - pkgconf --libs 'provides-test-meow >= 1.3.1' - atf_check \ - -s exit:1 \ - -e ignore \ - -o ignore \ - pkgconf --libs 'provides-test-meow <= 1.3.0' - atf_check \ - -o ignore \ - pkgconf --libs 'provides-test-meow < 1.2.9' -} - -indirect_dependency_node_body() -{ - atf_check \ - -o inline:'1.2.3\n' \ - pkgconf --with-path="${selfdir}/lib1" --modversion 'provides-test-meow' - atf_check \ - -s exit:1 \ - -e ignore \ - pkgconf --with-path="${selfdir}/lib1" --modversion 'provides-test-meow = 1.3.0' -} diff --git a/tests/regress.sh b/tests/regress.sh deleted file mode 100755 index b264f3593f90..000000000000 --- a/tests/regress.sh +++ /dev/null @@ -1,354 +0,0 @@ -#!/usr/bin/env atf-sh - -. $(atf_get_srcdir)/test_env.sh - -tests_init \ - case_sensitivity \ - depgraph_break_1 \ - depgraph_break_2 \ - depgraph_break_3 \ - define_variable \ - define_variable_override \ - variable \ - keep_system_libs \ - libs \ - libs_only \ - libs_never_mergeback \ - cflags_only \ - cflags_never_mergeback \ - incomplete_libs \ - incomplete_cflags \ - isystem_munge_order \ - isystem_munge_sysroot \ - idirafter_munge_order \ - idirafter_munge_sysroot \ - idirafter_ordering \ - modversion_common_prefix \ - modversion_fullpath \ - modversion_provides \ - modversion_uninstalled \ - modversion_one_word_expression \ - modversion_two_word_expression \ - modversion_three_word_expression \ - modversion_one_word_expression_no_space \ - modversion_one_word_expression_no_space_zero \ - pcpath \ - virtual_variable \ - fragment_collision \ - malformed_1 \ - malformed_quoting \ - explicit_sysroot \ - empty_tuple \ - solver_requires_private_debounce \ - billion_laughs \ - define_prefix_child_prefix_1 \ - define_prefix_child_prefix_1_env - -# sysroot_munge \ - -case_sensitivity_body() -{ - export PKG_CONFIG_PATH="${selfdir}/lib1" - atf_check \ - -o inline:"3\n" \ - pkgconf --variable=foo case-sensitivity - atf_check \ - -o inline:"4\n" \ - pkgconf --variable=Foo case-sensitivity -} - -depgraph_break_1_body() -{ - export PKG_CONFIG_PATH="${selfdir}/lib1" - atf_check -s exit:1 -e ignore \ - pkgconf --exists --print-errors 'foo > 0.6.0 foo < 0.8.0' -} - -depgraph_break_2_body() -{ - export PKG_CONFIG_PATH="${selfdir}/lib1" - atf_check -s exit:1 -e ignore \ - pkgconf --exists --print-errors 'nonexisting foo <= 3' -} - -depgraph_break_3_body() -{ - export PKG_CONFIG_PATH="${selfdir}/lib1" - atf_check -s exit:1 -e ignore \ - pkgconf --exists --print-errors 'depgraph-break' -} - -define_variable_body() -{ - export PKG_CONFIG_PATH="${selfdir}/lib1" - atf_check -o inline:"\\\${libdir}/typelibdir\n" \ - pkgconf --variable=typelibdir --define-variable='libdir=\${libdir}' typelibdir -} - -define_variable_override_body() -{ - export PKG_CONFIG_PATH="${selfdir}/lib1" - atf_check -o inline:"/test\n" \ - pkgconf --variable=prefix --define-variable='prefix=/test' typelibdir -} - -variable_body() -{ - export PKG_CONFIG_PATH="${selfdir}/lib1" - atf_check \ - -o inline:"/test/include\n" \ - pkgconf --variable=includedir foo -} - -keep_system_libs_body() -{ - export PKG_CONFIG_PATH="${selfdir}/lib1" - eval export "$LIBRARY_PATH_ENV"="/test/local/lib" - atf_check \ - -o inline:"\n" \ - pkgconf --libs-only-L cflags-libs-only - - atf_check \ - -o inline:"-L/test/local/lib\n" \ - pkgconf --libs-only-L --keep-system-libs cflags-libs-only -} - -libs_body() -{ - export PKG_CONFIG_PATH="${selfdir}/lib1" - atf_check \ - -o inline:"-L/test/local/lib -lfoo\n" \ - pkgconf --libs cflags-libs-only -} - -libs_only_body() -{ - export PKG_CONFIG_PATH="${selfdir}/lib1" - atf_check \ - -o inline:"-L/test/local/lib -lfoo\n" \ - pkgconf --libs-only-L --libs-only-l cflags-libs-only -} - -libs_never_mergeback_body() -{ - export PKG_CONFIG_PATH="${selfdir}/lib1" - atf_check \ - -o inline:"-L/test/bar/lib -lfoo1\n" \ - pkgconf --libs prefix-foo1 - atf_check \ - -o inline:"-L/test/bar/lib -lfoo1 -lfoo2\n" \ - pkgconf --libs prefix-foo1 prefix-foo2 -} - -cflags_only_body() -{ - export PKG_CONFIG_PATH="${selfdir}/lib1" - atf_check \ - -o inline:"-I/test/local/include/foo\n" \ - pkgconf --cflags-only-I --cflags-only-other cflags-libs-only -} - -cflags_never_mergeback_body() -{ - export PKG_CONFIG_PATH="${selfdir}/lib1" - atf_check \ - -o inline:"-I/test/bar/include/foo -DBAR -fPIC -DFOO\n" \ - pkgconf --cflags prefix-foo1 prefix-foo2 -} - -incomplete_libs_body() -{ - export PKG_CONFIG_PATH="${selfdir}/lib1" - atf_check \ - -o inline:"\n" \ - pkgconf --libs incomplete -} - -incomplete_cflags_body() -{ - export PKG_CONFIG_PATH="${selfdir}/lib1" - atf_check \ - -o inline:"\n" \ - pkgconf --cflags incomplete -} - -isystem_munge_order_body() -{ - export PKG_CONFIG_PATH="${selfdir}/lib1" - atf_check \ - -o inline:"-isystem /opt/bad/include -isystem /opt/bad2/include\n" \ - pkgconf --cflags isystem -} - -isystem_munge_sysroot_body() -{ - export PKG_CONFIG_PATH="${selfdir}/lib1" PKG_CONFIG_SYSROOT_DIR="${selfdir}" - atf_check \ - -o match:"-isystem ${selfdir}/opt/bad/include" \ - pkgconf --cflags isystem -} - -idirafter_munge_order_body() -{ - export PKG_CONFIG_PATH="${selfdir}/lib1" - atf_check \ - -o inline:"-idirafter /opt/bad/include -idirafter /opt/bad2/include\n" \ - pkgconf --cflags idirafter -} - -idirafter_munge_sysroot_body() -{ - export PKG_CONFIG_PATH="${selfdir}/lib1" PKG_CONFIG_SYSROOT_DIR="${selfdir}" - atf_check \ - -o match:"-idirafter ${selfdir}/opt/bad/include" \ - pkgconf --cflags idirafter -} - -idirafter_ordering_body() -{ - export PKG_CONFIG_PATH="${selfdir}/lib1" - atf_check \ - -o inline:"-I/opt/bad/include1 -idirafter -I/opt/bad/include2 -I/opt/bad/include3\n" \ - pkgconf --cflags idirafter-ordering -} - -pcpath_body() -{ - export PKG_CONFIG_PATH="${selfdir}/lib2" - atf_check \ - -o inline:"-fPIC -I/test/include/foo\n" \ - pkgconf --cflags ${selfdir}/lib3/bar.pc -} - -sysroot_munge_body() -{ - sed "s|/sysroot/|${selfdir}/|g" ${selfdir}/lib1/sysroot-dir.pc > ${selfdir}/lib1/sysroot-dir-selfdir.pc - export PKG_CONFIG_PATH="${selfdir}/lib1" PKG_CONFIG_SYSROOT_DIR="${selfdir}" - atf_check \ - -o inline:"-L${selfdir}/lib -lfoo\n" \ - pkgconf --libs sysroot-dir-selfdir -} - -virtual_variable_body() -{ - atf_check -s exit:0 \ - pkgconf --exists pkg-config - atf_check -s exit:0 \ - pkgconf --exists pkgconf - - atf_check -o inline:"${pcpath}\n" \ - pkgconf --variable=pc_path pkg-config - atf_check -o inline:"${pcpath}\n" \ - pkgconf --variable=pc_path pkgconf -} - -fragment_collision_body() -{ - atf_check -o inline:"-D_BAZ -D_BAR -D_FOO -D_THREAD_SAFE -pthread\n" \ - pkgconf --with-path="${selfdir}/lib1" --cflags fragment-collision -} - -malformed_1_body() -{ - atf_check -s exit:1 -o ignore \ - pkgconf --validate --with-path="${selfdir}/lib1" malformed-1 -} - -malformed_quoting_body() -{ - atf_check -s exit:0 -o ignore \ - pkgconf --validate --with-path="${selfdir}/lib1" malformed-quoting -} - -explicit_sysroot_body() -{ - export PKG_CONFIG_SYSROOT_DIR=${selfdir} - atf_check -o inline:"${selfdir}/usr/share/test\n" \ - pkgconf --with-path="${selfdir}/lib1" --variable=pkgdatadir explicit-sysroot -} - -empty_tuple_body() -{ - atf_check -o inline:"\n" \ - pkgconf --with-path="${selfdir}/lib1" --cflags empty-tuple -} - -solver_requires_private_debounce_body() -{ - atf_check -o inline:"-I/metapackage-1 -I/metapackage-2 -lmetapackage-1 -lmetapackage-2\n" \ - pkgconf --with-path="${selfdir}/lib1" --cflags --libs metapackage -} - -billion_laughs_body() -{ - atf_check -o inline:"warning: truncating very long variable to 64KB\nwarning: truncating very long variable to 64KB\nwarning: truncating very long variable to 64KB\nwarning: truncating very long variable to 64KB\nwarning: truncating very long variable to 64KB\n" \ - pkgconf --with-path="${selfdir}/lib1" --validate billion-laughs -} - -modversion_common_prefix_body() -{ - atf_check -o inline:"foo: 1.2.3\nfoobar: 3.2.1\n" \ - pkgconf --with-path="${selfdir}/lib1" --modversion --verbose foo foobar -} - -modversion_fullpath_body() -{ - atf_check -o inline:"1.2.3\n" \ - pkgconf --modversion "${selfdir}/lib1/foo.pc" -} - -modversion_provides_body() -{ - atf_check -o inline:"1.2.3\n" \ - pkgconf --with-path="${selfdir}/lib1" --modversion unavailable -} - -modversion_uninstalled_body() -{ - atf_check -o inline:"1.2.3\n" \ - pkgconf --with-path="${selfdir}/lib1" --modversion omg -} - -modversion_one_word_expression_body() -{ - atf_check -o inline:"1.2.3\n" \ - pkgconf --with-path="${selfdir}/lib1" --modversion "foo > 1.0" -} - -modversion_two_word_expression_body() -{ - atf_check -o inline:"1.2.3\n" \ - pkgconf --with-path="${selfdir}/lib1" --modversion foo "> 1.0" -} - -modversion_three_word_expression_body() -{ - atf_check -o inline:"1.2.3\n" \ - pkgconf --with-path="${selfdir}/lib1" --modversion foo ">" 1.0 -} - -modversion_one_word_expression_no_space_body() -{ - atf_check -o inline:"1.2.3\n" \ - pkgconf --with-path="${selfdir}/lib1" --modversion "foo >1.0" -} - -modversion_one_word_expression_no_space_zero_body() -{ - atf_check -o inline:"1.2.3\n" \ - pkgconf --with-path="${selfdir}/lib1" --modversion "foo >0.5" -} - -define_prefix_child_prefix_1_body() -{ - atf_check -o inline:"-I${selfdir}/lib1/include/child-prefix-1 -L${selfdir}/lib1/lib64 -lchild-prefix-1\n" \ - pkgconf --with-path="${selfdir}/lib1/child-prefix/pkgconfig" --define-prefix --cflags --libs child-prefix-1 -} - -define_prefix_child_prefix_1_env_body() -{ - export PKG_CONFIG_PATH="${selfdir}/lib1/child-prefix/pkgconfig" - export PKG_CONFIG_RELOCATE_PATHS=1 - atf_check -o inline:"-I${selfdir}/lib1/include/child-prefix-1 -L${selfdir}/lib1/lib64 -lchild-prefix-1\n" \ - pkgconf --cflags --libs child-prefix-1 -} diff --git a/tests/requires.sh b/tests/requires.sh deleted file mode 100755 index 7a95a66cd232..000000000000 --- a/tests/requires.sh +++ /dev/null @@ -1,176 +0,0 @@ -#!/usr/bin/env atf-sh - -. $(atf_get_srcdir)/test_env.sh - -tests_init \ - libs \ - libs_cflags \ - libs_static \ - libs_static_pure \ - cflags_libs_private \ - argv_parse2 \ - static_cflags \ - private_duplication \ - private_duplication_digraph \ - foo_bar \ - bar_foo \ - foo_metapackage_3 \ - libs_static2 \ - missing \ - requires_internal \ - requires_internal_missing \ - requires_internal_collision \ - orphaned_requires_private - -libs_body() -{ - export PKG_CONFIG_PATH="${selfdir}/lib1" - atf_check \ - -o inline:"-L/test/lib -lbar -lfoo\n" \ - pkgconf --libs bar -} - -libs_cflags_body() -{ - export PKG_CONFIG_PATH="${selfdir}/lib1" - atf_check \ - -o inline:"-fPIC -I/test/include/foo -L/test/lib -lbaz\n" \ - pkgconf --libs --cflags baz -} - -libs_static_body() -{ - export PKG_CONFIG_PATH="${selfdir}/lib1" - atf_check \ - -o inline:"-L/test/lib -lbaz -L/test/lib -lzee -lfoo\n" \ - pkgconf --static --libs baz -} - -libs_static_pure_body() -{ - export PKG_CONFIG_PATH="${selfdir}/lib1" - atf_check \ - -o inline:"-L/test/lib -lbaz -lfoo\n" \ - pkgconf --static --pure --libs baz -} - -argv_parse2_body() -{ - export PKG_CONFIG_PATH="${selfdir}/lib1" - atf_check \ - -o inline:"-llib-1 -pthread /test/lib/lib2.so\n" \ - pkgconf --static --libs argv-parse-2 -} - -static_cflags_body() -{ - export PKG_CONFIG_PATH="${selfdir}/lib1" - atf_check \ - -o inline:"-fPIC -I/test/include/foo -DFOO_STATIC\n" \ - pkgconf --static --cflags baz -} - -private_duplication_body() -{ - export PKG_CONFIG_PATH="${selfdir}/lib1" - atf_check \ - -o inline:"-lprivate -lbaz -lzee -lbar -lfoo\n" \ - pkgconf --static --libs-only-l private-libs-duplication -} - -private_duplication_digraph_body() -{ - export PKG_CONFIG_PATH="${selfdir}/lib1" - atf_check \ - -o 'match:"user:request" -> "private-libs-duplication"' \ - -o 'match:"private-libs-duplication" -> "bar"' \ - -o 'match:"private-libs-duplication" -> "baz"' \ - -o 'match:"bar" -> "foo"' \ - -o 'match:"baz" -> "foo"' \ - pkgconf --static --libs-only-l private-libs-duplication --digraph -} - -bar_foo_body() -{ - export PKG_CONFIG_PATH="${selfdir}/lib1" - atf_check \ - -o inline:"-lbar -lfoo\n" \ - pkgconf --static --libs-only-l bar foo -} - -foo_bar_body() -{ - export PKG_CONFIG_PATH="${selfdir}/lib1" - atf_check \ - -o inline:"-lbar -lfoo\n" \ - pkgconf --static --libs-only-l foo bar -} - -foo_metapackage_3_body() -{ - export PKG_CONFIG_PATH="${selfdir}/lib1" - atf_check \ - -o inline:"-lbar -lfoo\n" \ - pkgconf --static --libs-only-l foo metapackage-3 -} - -libs_static2_body() -{ - export PKG_CONFIG_PATH="${selfdir}/lib1" - atf_check \ - -o inline:"-lbar -lbar-private -L/test/lib -lfoo\n" \ - pkgconf --static --libs static-libs -} - -missing_body() -{ - export PKG_CONFIG_PATH="${selfdir}/lib1" - atf_check \ - -s exit:1 \ - -e ignore \ - -o ignore \ - pkgconf --cflags missing-require -} - -requires_internal_body() -{ - atf_check \ - -o inline:"-lbar -lbar-private -L/test/lib -lfoo\n" \ - pkgconf --with-path="${selfdir}/lib1" --static --libs requires-internal -} - -requires_internal_missing_body() -{ - atf_check \ - -s exit:1 \ - -e ignore \ - -o ignore \ - pkgconf --with-path="${selfdir}/lib1" --static --libs requires-internal-missing -} - -requires_internal_collision_body() -{ - atf_check \ - -o inline:"-I/test/local/include/foo\n" \ - pkgconf --with-path="${selfdir}/lib1" --cflags requires-internal-collision -} - -orphaned_requires_private_body() -{ - atf_check \ - -s exit:1 \ - -e ignore \ - -o ignore \ - pkgconf --with-path="${selfdir}/lib1" --cflags --libs orphaned-requires-private -} - -cflags_libs_private_body() -{ - atf_check \ - -o inline:"\n" \ - pkgconf --with-path="${selfdir}/lib1" --libs cflags-libs-private-a - - atf_check \ - -o inline:"-lc\n" \ - pkgconf --with-path="${selfdir}/lib1" --static --libs cflags-libs-private-a -} diff --git a/tests/symlink.sh b/tests/symlink.sh deleted file mode 100755 index 7f49655755eb..000000000000 --- a/tests/symlink.sh +++ /dev/null @@ -1,122 +0,0 @@ -#!/usr/bin/env atf-sh - -. $(atf_get_srcdir)/test_env.sh - -tests_init \ - pcfiledir_symlink_absolute \ - pcfiledir_symlink_relative - -# - We need to create a temporary subtree, since symlinks are not preserved -# in "make dist". -# - ${srcdir} is relative and since we need to compare paths, we would have -# to portably canonicalize it again, which is hard. Instead, just keep -# the whole thing nested. -pcfiledir_symlink_absolute_body() -{ - mkdir -p tmp/child - cp -f "${selfdir}/lib1/pcfiledir.pc" tmp/child/ - ln -f -s "${PWD}/tmp/child/pcfiledir.pc" tmp/pcfiledir.pc # absolute - ln -f -s tmp/pcfiledir.pc pcfiledir.pc - - atf_check \ - -o inline:"${PWD}/tmp/child\n" \ - pkgconf --variable=prefix pcfiledir.pc - atf_check \ - -o inline:"${PWD}/tmp/child\n" \ - pkgconf --variable=prefix tmp/pcfiledir.pc - atf_check \ - -o inline:"tmp/child\n" \ - pkgconf --variable=prefix tmp/child/pcfiledir.pc - - atf_check \ - -o inline:"${PWD}/tmp/child\n" \ - pkgconf --variable=prefix "${PWD}/pcfiledir.pc" - atf_check \ - -o inline:"${PWD}/tmp/child\n" \ - pkgconf --variable=prefix "${PWD}/tmp/pcfiledir.pc" - atf_check \ - -o inline:"${PWD}/tmp/child\n" \ - pkgconf --variable=prefix "${PWD}/tmp/child/pcfiledir.pc" - - export PKG_CONFIG_PATH="." - atf_check \ - -o inline:"${PWD}/tmp/child\n" \ - pkgconf --variable=prefix pcfiledir - export PKG_CONFIG_PATH="${PWD}" - atf_check \ - -o inline:"${PWD}/tmp/child\n" \ - pkgconf --variable=prefix pcfiledir - - export PKG_CONFIG_PATH="tmp" - atf_check \ - -o inline:"${PWD}/tmp/child\n" \ - pkgconf --variable=prefix pcfiledir - export PKG_CONFIG_PATH="${PWD}/tmp" - atf_check \ - -o inline:"${PWD}/tmp/child\n" \ - pkgconf --variable=prefix pcfiledir - - export PKG_CONFIG_PATH="tmp/child" - atf_check \ - -o inline:"tmp/child\n" \ - pkgconf --variable=prefix pcfiledir - export PKG_CONFIG_PATH="${PWD}/tmp/child" - atf_check \ - -o inline:"${PWD}/tmp/child\n" \ - pkgconf --variable=prefix pcfiledir -} - -pcfiledir_symlink_relative_body() -{ - mkdir -p tmp/child - cp -f "${selfdir}/lib1/pcfiledir.pc" tmp/child/ - ln -f -s child/pcfiledir.pc tmp/pcfiledir.pc # relative - ln -f -s tmp/pcfiledir.pc pcfiledir.pc - - atf_check \ - -o inline:"tmp/child\n" \ - pkgconf --variable=prefix pcfiledir.pc - atf_check \ - -o inline:"tmp/child\n" \ - pkgconf --variable=prefix tmp/pcfiledir.pc - atf_check \ - -o inline:"tmp/child\n" \ - pkgconf --variable=prefix tmp/child/pcfiledir.pc - - atf_check \ - -o inline:"${PWD}/tmp/child\n" \ - pkgconf --variable=prefix "${PWD}/pcfiledir.pc" - atf_check \ - -o inline:"${PWD}/tmp/child\n" \ - pkgconf --variable=prefix "${PWD}/tmp/pcfiledir.pc" - atf_check \ - -o inline:"${PWD}/tmp/child\n" \ - pkgconf --variable=prefix "${PWD}/tmp/child/pcfiledir.pc" - - export PKG_CONFIG_PATH="." - atf_check \ - -o inline:"tmp/child\n" \ - pkgconf --variable=prefix pcfiledir - export PKG_CONFIG_PATH="${PWD}" - atf_check \ - -o inline:"${PWD}/tmp/child\n" \ - pkgconf --variable=prefix pcfiledir - - export PKG_CONFIG_PATH="tmp" - atf_check \ - -o inline:"tmp/child\n" \ - pkgconf --variable=prefix pcfiledir - export PKG_CONFIG_PATH="${PWD}/tmp" - atf_check \ - -o inline:"${PWD}/tmp/child\n" \ - pkgconf --variable=prefix pcfiledir - - export PKG_CONFIG_PATH="tmp/child" - atf_check \ - -o inline:"tmp/child\n" \ - pkgconf --variable=prefix pcfiledir - export PKG_CONFIG_PATH="${PWD}/tmp/child" - atf_check \ - -o inline:"${PWD}/tmp/child\n" \ - pkgconf --variable=prefix pcfiledir -} diff --git a/tests/sysroot.sh b/tests/sysroot.sh deleted file mode 100755 index 9d61eaea311c..000000000000 --- a/tests/sysroot.sh +++ /dev/null @@ -1,110 +0,0 @@ -#!/usr/bin/env atf-sh - -. $(atf_get_srcdir)/test_env.sh - -tests_init \ - cflags \ - variable \ - do_not_eat_slash \ - do_not_duplicate_sysroot_dir \ - uninstalled \ - uninstalled_pkgconf1 \ - uninstalled_fdo \ - uninstalled_fdo_pc_sysrootdir - -do_not_eat_slash_body() -{ - export PKG_CONFIG_PATH="${selfdir}/lib1" - export PKG_CONFIG_SYSROOT_DIR="/" - atf_check \ - -o inline:"-fPIC -I/test/include/foo\n" \ - pkgconf --cflags baz -} - -cflags_body() -{ - export PKG_CONFIG_PATH="${selfdir}/lib1" - export PKG_CONFIG_SYSROOT_DIR="${SYSROOT_DIR}" - atf_check \ - -o inline:"-fPIC -I${SYSROOT_DIR}/test/include/foo\n" \ - pkgconf --cflags baz -} - -variable_body() -{ - export PKG_CONFIG_PATH="${selfdir}/lib1" - export PKG_CONFIG_SYSROOT_DIR="${SYSROOT_DIR}" - atf_check \ - -o inline:"${SYSROOT_DIR}/test\n" \ - pkgconf --variable=prefix foo - atf_check \ - -o inline:"${SYSROOT_DIR}/test/include\n" \ - pkgconf --variable=includedir foo -} - -do_not_duplicate_sysroot_dir_body() -{ - export PKG_CONFIG_PATH="${selfdir}/lib1" - export PKG_CONFIG_SYSROOT_DIR="/sysroot" - - atf_check \ - -o inline:"-I/sysroot/usr/include\n" \ - pkgconf --cflags sysroot-dir-2 - - atf_check \ - -o inline:"-I/sysroot/usr/include\n" \ - pkgconf --cflags sysroot-dir-3 - - atf_check \ - -o inline:"-I/sysroot/usr/include\n" \ - pkgconf --cflags sysroot-dir-5 - - export PKG_CONFIG_SYSROOT_DIR="${SYSROOT_DIR}" - - atf_check \ - -o inline:"-I${SYSROOT_DIR}/usr/include\n" \ - pkgconf --cflags sysroot-dir-4 -} - -uninstalled_body() -{ - export PKG_CONFIG_PATH="${selfdir}/lib1" - export PKG_CONFIG_SYSROOT_DIR="/sysroot" - - atf_check \ - -o inline:"-L/test/lib -lomg\n" \ - pkgconf --libs omg -} - -uninstalled_pkgconf1_body() -{ - export PKG_CONFIG_PATH="${selfdir}/lib1" - export PKG_CONFIG_SYSROOT_DIR="/sysroot" - export PKG_CONFIG_PKGCONF1_SYSROOT_RULES="1" - - atf_check \ - -o inline:"-L/sysroot/test/lib -lomg\n" \ - pkgconf --libs omg -} - -uninstalled_fdo_body() -{ - export PKG_CONFIG_PATH="${selfdir}/lib1" - export PKG_CONFIG_SYSROOT_DIR="/sysroot" - export PKG_CONFIG_FDO_SYSROOT_RULES="1" - - atf_check \ - -o inline:"-L/test/lib -lomg\n" \ - pkgconf --libs omg -} - -uninstalled_fdo_pc_sysrootdir_body() -{ - export PKG_CONFIG_PATH="${selfdir}/lib1" - export PKG_CONFIG_SYSROOT_DIR="/sysroot" - export PKG_CONFIG_FDO_SYSROOT_RULES="1" - - atf_check \ - -o inline:"-L/sysroot/test/lib -lomg\n" \ - pkgconf --libs omg-sysroot -} diff --git a/tests/test-runner.c b/tests/test-runner.c new file mode 100644 index 000000000000..5fbb426184c6 --- /dev/null +++ b/tests/test-runner.c @@ -0,0 +1,1576 @@ +/* + * test-runner.c + * test harness + * + * SPDX-License-Identifier: pkgconf + * + * Copyright (c) 2025 pkgconf authors (see AUTHORS). + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * This software is provided 'as is' and without any warranty, express or + * implied. In no event shall the authors be liable for any damages arising + * from the use of this software. + */ + +#include <libpkgconf/config.h> +#include <libpkgconf/libpkgconf.h> +#include <libpkgconf/stdinc.h> +#include <tests/win-shim.h> +#include <sys/types.h> +#include <cli/core.h> +#include <cli/getopt_long.h> +#include <limits.h> +#include <assert.h> + +#ifndef PKGCONF_LITE +# if !defined(_WIN32) && !defined(__HAIKU__) +# define PKGCONF_TEST_PLATFORM "unix" +# elif !defined(_WIN32) +# define PKGCONF_TEST_PLATFORM "haiku" +# else +# define PKGCONF_TEST_PLATFORM "windows" +# endif +#else // PKGCONF_LITE +# define PKGCONF_TEST_PLATFORM "lite" +#endif // PKGCONF_LITE + +static void test_parser_warn(void *p, const char *fmt, ...) PRINTFLIKE(2, 3); +static void handle_substs(pkgconf_buffer_t *dest, const pkgconf_buffer_t *src, const char *pwd); + +static pkgconf_buffer_t test_fixtures_dir = PKGCONF_BUFFER_INITIALIZER; +static pkgconf_buffer_t test_tool_dir = PKGCONF_BUFFER_INITIALIZER; +static bool debug = false; + +typedef enum test_match_strategy_ +{ + MATCH_EXACT = 0, + MATCH_PARTIAL, + MATCH_EMPTY, +} pkgconf_test_match_strategy_t; + +typedef struct test_case_ +{ + char *name; + char *testfile_dir; + + pkgconf_list_t search_path; + pkgconf_buffer_t query; + + pkgconf_list_t expected_stdout; + pkgconf_test_match_strategy_t match_stdout; + + pkgconf_list_t expected_stderr; + pkgconf_test_match_strategy_t match_stderr; + + pkgconf_buffer_t expected_stdout_file; + + int exitcode; + uint64_t wanted_flags; + + pkgconf_list_t env_vars; + + pkgconf_buffer_t want_env_prefix; + pkgconf_buffer_t want_variable; + pkgconf_buffer_t fragment_filter; + + pkgconf_buffer_t skip_platforms; + bool require_utf8_locale; + + pkgconf_list_t define_variables; + + int verbosity; + + pkgconf_buffer_t atleast_version; + pkgconf_buffer_t exact_version; + pkgconf_buffer_t max_version; + + pkgconf_buffer_t tool; + pkgconf_buffer_t tool_args; // TODO: tool-specific flags + + pkgconf_list_t mkdirs; +#ifndef _WIN32 + pkgconf_list_t symlinks; +#endif + pkgconf_list_t copies; + +#ifndef PKGCONF_LITE + pkgconf_buffer_t want_personality; +#endif +} pkgconf_test_case_t; + +typedef struct test_state_ +{ + pkgconf_cli_state_t cli_state; + const pkgconf_test_case_t *testcase; +} pkgconf_test_state_t; + +typedef struct test_environ_ +{ + pkgconf_node_t node; + char *key; + char *value; +} pkgconf_test_environ_t; + +typedef struct test_output_ +{ + pkgconf_output_t output; + + pkgconf_buffer_t o_stdout; + pkgconf_buffer_t o_stderr; +} pkgconf_test_output_t; + +typedef struct test_flag_pair_ +{ + const char *name; + uint64_t flag; +} pkgconf_test_flag_pair_t; + +typedef void (*test_keyword_func_t)(pkgconf_test_case_t *testcase, const char *keyword, const char *warnprefix, const ptrdiff_t offset, const char *value); + +typedef struct test_keyword_pair_ +{ + const char *keyword; + const test_keyword_func_t func; + const ptrdiff_t offset; +} pkgconf_test_keyword_pair_t; + +static void +test_environment_push(pkgconf_test_case_t *testcase, const char *key, const char *value) +{ + pkgconf_test_environ_t *env = calloc(1, sizeof(*env)); + if (env == NULL) + return; + + env->key = strdup(key); + env->value = strdup(value); + pkgconf_node_insert_tail(&env->node, env, &testcase->env_vars); +} + +static void +test_environment_free(pkgconf_list_t *env_list) +{ + pkgconf_node_t *iter, *iter_next; + + PKGCONF_FOREACH_LIST_ENTRY_SAFE(env_list->head, iter_next, iter) + { + pkgconf_test_environ_t *env = iter->data; + + pkgconf_node_delete(&env->node, env_list); + + free(env->key); + free(env->value); + free(env); + } +} + +static const char * +environ_lookup_handler(const pkgconf_client_t *client, const char *key) +{ + pkgconf_test_state_t *state = client->client_data; + pkgconf_node_t *iter; + + PKGCONF_FOREACH_LIST_ENTRY(state->testcase->env_vars.head, iter) + { + pkgconf_test_environ_t *env = iter->data; + + if (!strcmp(key, env->key)) + { + char cwd[PATH_MAX] = {0}; + const char *pwd = getcwd(cwd, sizeof(cwd)); + + pkgconf_buffer_t expanded = PKGCONF_BUFFER_INITIALIZER; + handle_substs(&expanded, PKGCONF_BUFFER_FROM_STR(env->value), pwd); + + free(env->value); + env->value = strdup(pkgconf_buffer_str_or_empty(&expanded)); + pkgconf_buffer_finalize(&expanded); + + return env->value; + } + } + + return NULL; +} + +#ifndef PKGCONF_LITE +static bool +debug_handler(const char *msg, const pkgconf_client_t *client, void *data) +{ + (void) client; + (void) data; + fprintf(stderr, "%s", msg); + return true; +} +#endif // PKGCONF_LITE + +static bool +error_handler(const char *msg, const pkgconf_client_t *client, void *data) +{ + (void) data; + pkgconf_test_state_t *state = client->client_data; + pkgconf_output_fmt(client->output, state->testcase->wanted_flags & PKG_ERRORS_ON_STDOUT ? PKGCONF_OUTPUT_STDOUT : PKGCONF_OUTPUT_STDERR, "%s", msg); + return true; +} + +static bool +write_handler(pkgconf_output_t *output, pkgconf_output_stream_t stream, const pkgconf_buffer_t *buffer) +{ + pkgconf_test_output_t *out = (pkgconf_test_output_t *) output; + pkgconf_buffer_t *dest = stream == PKGCONF_OUTPUT_STDERR ? &out->o_stderr : &out->o_stdout; + + pkgconf_buffer_append(dest, pkgconf_buffer_str(buffer)); + return true; +} + +static pkgconf_output_t * +test_output(void) +{ + static pkgconf_test_output_t output = + { + .output.write = write_handler, + }; + + return &output.output; +} + +static void +test_output_reset(pkgconf_test_output_t *out) +{ + pkgconf_buffer_reset(&out->o_stdout); + pkgconf_buffer_reset(&out->o_stderr); +} + +/* + * handle_substs: expand %TEST_FIXTURES_DIR%, %DIR_SEP%, and %PWD% + * in src into dest. pwd may be NULL, in which case %PWD% is left as-is + * (it should only appear in fields that are re-expanded after tmp_dir creation). + */ +static void +handle_substs(pkgconf_buffer_t *dest, const pkgconf_buffer_t *src, const char *pwd) +{ + struct subst_pair + { + const char *key; + const char *value; + } subst_pairs[] = + { + {"%TEST_FIXTURES_DIR%", pkgconf_buffer_str(&test_fixtures_dir)}, + {"%DIR_SEP%", PKG_CONFIG_PATH_SEP_S}, + {"%PWD%", pwd != NULL ? pwd : "%PWD%"}, + }; + + pkgconf_buffer_t workbuf_src = PKGCONF_BUFFER_INITIALIZER; + pkgconf_buffer_t workbuf_dest = PKGCONF_BUFFER_INITIALIZER; + + if (!pkgconf_buffer_len(src)) + return; + + pkgconf_buffer_append(&workbuf_dest, pkgconf_buffer_str(src)); + + for (size_t i = 0; i < PKGCONF_ARRAY_SIZE(subst_pairs); i++) + { + pkgconf_buffer_reset(&workbuf_src); + pkgconf_buffer_append(&workbuf_src, pkgconf_buffer_str(&workbuf_dest)); + + pkgconf_buffer_reset(&workbuf_dest); + pkgconf_buffer_subst(&workbuf_dest, &workbuf_src, subst_pairs[i].key, subst_pairs[i].value); + } + + pkgconf_buffer_append(dest, pkgconf_buffer_str(&workbuf_dest)); + + pkgconf_buffer_finalize(&workbuf_src); + pkgconf_buffer_finalize(&workbuf_dest); +} + +static int +test_keyword_pair_cmp(const void *key, const void *ptr) +{ + const pkgconf_test_keyword_pair_t *pair = ptr; + return strcasecmp(key, pair->keyword); +} + +static void +test_keyword_set_int(pkgconf_test_case_t *testcase, const char *keyword, const char *warnprefix, const ptrdiff_t offset, const char *value) +{ + (void) keyword; + (void) warnprefix; + + int *dest = (int *)((char *) testcase + offset); + *dest = atoi(value); +} + +static void +test_keyword_set_bool(pkgconf_test_case_t *testcase, const char *keyword, const char *warnprefix, const ptrdiff_t offset, const char *value) +{ + (void) keyword; + (void) warnprefix; + + bool *dest = (bool *)((char *) testcase + offset); + *dest = !strcasecmp(value, "true"); +} + +static void +test_keyword_set_buffer(pkgconf_test_case_t *testcase, const char *keyword, const char *warnprefix, const ptrdiff_t offset, const char *value) +{ + (void) keyword; + (void) warnprefix; + + pkgconf_buffer_t *dest = (pkgconf_buffer_t *)((char *) testcase + offset); + handle_substs(dest, PKGCONF_BUFFER_FROM_STR((char *) value), NULL); +} + +static void +test_keyword_extend_bufferset(pkgconf_test_case_t *testcase, const char *keyword, const char *warnprefix, const ptrdiff_t offset, const char *value) +{ + (void) keyword; + (void) warnprefix; + + pkgconf_list_t *dest = (pkgconf_list_t *)((char *) testcase + offset); + pkgconf_buffer_t buf = PKGCONF_BUFFER_INITIALIZER; + + handle_substs(&buf, PKGCONF_BUFFER_FROM_STR((char *) value), NULL); + pkgconf_bufferset_extend(dest, &buf); + pkgconf_buffer_finalize(&buf); +} + +static int +test_flag_pair_cmp(const void *key, const void *ptr) +{ + const pkgconf_test_flag_pair_t *pair = ptr; + return strcasecmp(key, pair->name); +} + +static const pkgconf_test_flag_pair_t test_flag_pairs[] = +{ + {"cflags", PKG_CFLAGS}, + {"cflags-only-i", PKG_CFLAGS_ONLY_I}, + {"cflags-only-other", PKG_CFLAGS_ONLY_OTHER}, + {"debug", PKG_DEBUG}, + {"define-prefix", PKG_DEFINE_PREFIX}, + {"digraph", PKG_DIGRAPH}, + {"dont-define-prefix", PKG_DONT_DEFINE_PREFIX}, + {"dont-relocate-paths", PKG_DONT_RELOCATE_PATHS}, + {"dump-license", PKG_DUMP_LICENSE}, + {"dump-license-file", PKG_DUMP_LICENSE_FILE}, + {"dump-personality", PKG_DUMP_PERSONALITY}, + {"dump-source", PKG_DUMP_SOURCE}, + {"env-only", PKG_ENV_ONLY}, + {"errors-on-stdout", PKG_ERRORS_ON_STDOUT}, + {"exists", PKG_EXISTS}, + {"exists-cflags", PKG_EXISTS_CFLAGS}, + {"fragment-tree", PKG_FRAGMENT_TREE}, + {"ignore-conflicts", PKG_IGNORE_CONFLICTS}, + {"internal-cflags", PKG_INTERNAL_CFLAGS}, + {"keep-system-cflags", PKG_KEEP_SYSTEM_CFLAGS}, + {"keep-system-libs", PKG_KEEP_SYSTEM_LIBS}, + {"libs", PKG_LIBS}, + {"libs-only-ldpath", PKG_LIBS_ONLY_LDPATH}, + {"libs-only-libname", PKG_LIBS_ONLY_LIBNAME}, + {"libs-only-other", PKG_LIBS_ONLY_OTHER}, + {"link-abi", PKG_LINK_ABI}, + {"list", PKG_LIST}, + {"list-package-names", PKG_LIST_PACKAGE_NAMES}, + {"modversion", PKG_MODVERSION}, + {"msvc-syntax", PKG_MSVC_SYNTAX}, + {"newlines", PKG_NEWLINES}, + {"no-cache", PKG_NO_CACHE}, + {"no-provides", PKG_NO_PROVIDES}, + {"no-uninstalled", PKG_NO_UNINSTALLED}, + {"path", PKG_PATH}, + {"print-digraph-query-nodes", PKG_PRINT_DIGRAPH_QUERY_NODES}, + {"print-errors", PKG_PRINT_ERRORS}, + {"print-provides", PKG_PROVIDES}, + {"print-requires", PKG_REQUIRES}, + {"print-requires-private", PKG_REQUIRES_PRIVATE}, + {"print-variables", PKG_VARIABLES}, + {"pure", PKG_PURE}, + {"shared", PKG_SHARED}, + {"short-errors", PKG_SHORT_ERRORS}, + {"silence-errors", PKG_SILENCE_ERRORS}, + {"simulate", PKG_SIMULATE}, + {"solution", PKG_SOLUTION}, + {"static", PKG_STATIC}, + {"uninstalled", PKG_UNINSTALLED}, + {"validate", PKG_VALIDATE}, +}; + +static void +test_keyword_set_wanted_flags(pkgconf_test_case_t *testcase, const char *keyword, const char *warnprefix, const ptrdiff_t offset, const char *value) +{ + int i; + int flagcount; + char **flags = NULL; + + (void) keyword; + (void) warnprefix; + (void) offset; + + pkgconf_argv_split(value, &flagcount, &flags); + + for (i = 0; i < flagcount; i++) + { + const char *flag = flags[i]; + const pkgconf_test_flag_pair_t *pair = bsearch(flag, + test_flag_pairs, PKGCONF_ARRAY_SIZE(test_flag_pairs), + sizeof(*pair), test_flag_pair_cmp); + + if (pair == NULL) + continue; + + testcase->wanted_flags |= pair->flag; + } + + pkgconf_argv_free(flags); +} + +static size_t +prefixed_path_split(const char *text, pkgconf_list_t *dirlist, const char *prefix) +{ + size_t count = 0; + char *workbuf, *p, *iter; + + if (text == NULL) + return 0; + + iter = workbuf = strdup(text); + while ((p = strtok(iter, PKG_CONFIG_PATH_SEP_S)) != NULL) + { + pkgconf_buffer_t pathbuf = PKGCONF_BUFFER_INITIALIZER; + + pkgconf_buffer_append(&pathbuf, prefix); + pkgconf_buffer_push_byte(&pathbuf, '/'); + pkgconf_buffer_append(&pathbuf, p); + pkgconf_path_add(pkgconf_buffer_str(&pathbuf), dirlist, false); + pkgconf_buffer_finalize(&pathbuf); + + count++, iter = NULL; + } + free(workbuf); + + return count; +} + +static void +test_keyword_set_path_list(pkgconf_test_case_t *testcase, const char *keyword, const char *warnprefix, const ptrdiff_t offset, const char *value) +{ + (void) keyword; + (void) warnprefix; + + pkgconf_list_t *dest = (pkgconf_list_t *)((char *) testcase + offset); + prefixed_path_split(value, dest, pkgconf_buffer_str(&test_fixtures_dir)); +} + +static void +test_keyword_set_match_strategy(pkgconf_test_case_t *testcase, const char *keyword, const char *warnprefix, const ptrdiff_t offset, const char *value) +{ + (void) keyword; + (void) warnprefix; + + pkgconf_test_match_strategy_t *dest = (pkgconf_test_match_strategy_t *)((char *) testcase + offset); + + if (!strcasecmp(value, "partial")) + *dest = MATCH_PARTIAL; + + if (!strcasecmp(value, "empty")) + *dest = MATCH_EMPTY; +} + +static void +test_keyword_set_environment(pkgconf_test_case_t *testcase, const char *keyword, const char *warnprefix, const ptrdiff_t offset, const char *value) +{ + (void) keyword; + (void) offset; + + char *eq = strchr(value, '='); + if (eq == NULL) + { + fprintf(stderr, "%s: malformed Environment entry: %s\n", warnprefix, value); + return; + } + + *eq++ = '\0'; + + // store raw, vars are expanded at run time + test_environment_push(testcase, value, eq); +} + +#ifdef _WIN32 +static void +test_keyword_disabled(pkgconf_test_case_t *testcase, const char *keyword, const char *warnprefix, const ptrdiff_t offset, const char *value) +{ + (void) testcase; + (void) keyword; + (void) warnprefix; + (void) offset; + (void) value; +} +#endif + +static const pkgconf_test_keyword_pair_t test_keyword_pairs[] = +{ + {"AtLeastVersion", test_keyword_set_buffer, offsetof(pkgconf_test_case_t, atleast_version)}, + {"DefineVariable", test_keyword_extend_bufferset, offsetof(pkgconf_test_case_t, define_variables)}, + {"Environment", test_keyword_set_environment, offsetof(pkgconf_test_case_t, env_vars)}, + {"ExactVersion", test_keyword_set_buffer, offsetof(pkgconf_test_case_t, exact_version)}, + {"ExpectedExitCode", test_keyword_set_int, offsetof(pkgconf_test_case_t, exitcode)}, + {"ExpectedStderr", test_keyword_extend_bufferset, offsetof(pkgconf_test_case_t, expected_stderr)}, + {"ExpectedStdout", test_keyword_extend_bufferset, offsetof(pkgconf_test_case_t, expected_stdout)}, + {"ExpectedStdoutFile", test_keyword_set_buffer, offsetof(pkgconf_test_case_t, expected_stdout_file)}, + {"FragmentFilter", test_keyword_set_buffer, offsetof(pkgconf_test_case_t, fragment_filter)}, + {"MatchStderr", test_keyword_set_match_strategy, offsetof(pkgconf_test_case_t, match_stderr)}, + {"MatchStdout", test_keyword_set_match_strategy, offsetof(pkgconf_test_case_t, match_stdout)}, + {"MaxVersion", test_keyword_set_buffer, offsetof(pkgconf_test_case_t, max_version)}, + {"PackageSearchPath", test_keyword_set_path_list, offsetof(pkgconf_test_case_t, search_path)}, + {"Query", test_keyword_set_buffer, offsetof(pkgconf_test_case_t, query)}, + {"RequireUtf8Locale", test_keyword_set_bool, offsetof(pkgconf_test_case_t, require_utf8_locale)}, + {"SetupCopy", test_keyword_extend_bufferset, offsetof(pkgconf_test_case_t, copies)}, + {"SetupMkdir", test_keyword_extend_bufferset, offsetof(pkgconf_test_case_t, mkdirs)}, +#ifdef _WIN32 + {"SetupSymlink", test_keyword_disabled, 0}, +#else + {"SetupSymlink", test_keyword_extend_bufferset, offsetof(pkgconf_test_case_t, symlinks)}, +#endif + {"SkipPlatforms", test_keyword_set_buffer, offsetof(pkgconf_test_case_t, skip_platforms)}, + {"Tool", test_keyword_set_buffer, offsetof(pkgconf_test_case_t, tool)}, + {"ToolArgs", test_keyword_set_buffer, offsetof(pkgconf_test_case_t, tool_args)}, + {"VerbosityLevel", test_keyword_set_int, offsetof(pkgconf_test_case_t, verbosity)}, + {"WantedFlags", test_keyword_set_wanted_flags, offsetof(pkgconf_test_case_t, wanted_flags)}, + {"WantEnvPrefix", test_keyword_set_buffer, offsetof(pkgconf_test_case_t, want_env_prefix)}, +#ifndef PKGCONF_LITE + {"WantPersonality", test_keyword_set_buffer, offsetof(pkgconf_test_case_t, want_personality)}, +#endif + {"WantVariable", test_keyword_set_buffer, offsetof(pkgconf_test_case_t, want_variable)}, +}; + +static void +test_keyword_set(void *data, const char *warnprefix, const char *keyword, const char *value) +{ + pkgconf_test_case_t *testcase = data; + const pkgconf_test_keyword_pair_t *pair = bsearch(keyword, + test_keyword_pairs, PKGCONF_ARRAY_SIZE(test_keyword_pairs), + sizeof(*pair), test_keyword_pair_cmp); + + if (pair == NULL || pair->func == NULL) + return; + + pair->func(testcase, warnprefix, keyword, pair->offset, value); +} + +static const pkgconf_parser_operand_func_t test_parser_ops[256] = +{ + [':'] = (pkgconf_parser_operand_func_t) test_keyword_set, +}; + +static void +test_parser_warn(void *p, const char *fmt, ...) +{ + va_list va; + + (void) p; + + va_start(va, fmt); + vfprintf(stderr, fmt, va); + va_end(va); +} + +static pkgconf_test_case_t * +load_test_case(char *testfile) +{ + FILE *testf = fopen(testfile, "r"); + if (testf == NULL) + return NULL; + + pkgconf_test_case_t *out = calloc(1, sizeof(*out)); + if (out == NULL) + goto cleanup; + + char *nameptr; + if ((nameptr = strrchr(testfile, '/')) != NULL) + nameptr++; + else + nameptr = testfile; + + out->name = strdup(nameptr); + + // store directory containing the test file for ExpectedStdoutFile resolution + { + char *dirend = strrchr(testfile, '/'); + if (dirend != NULL) + { + size_t dirlen = (size_t)(dirend - testfile); + out->testfile_dir = calloc(1, dirlen + 1); + if (out->testfile_dir != NULL) + memcpy(out->testfile_dir, testfile, dirlen); + } + else + out->testfile_dir = strdup("."); + } + + pkgconf_parser_parse(testf, out, test_parser_ops, test_parser_warn, testfile); + +cleanup: + fclose(testf); + return out; +} + +// we use a custom personality to ensure the tests are fully hermetic +static pkgconf_cross_personality_t * +personality_for_test(const pkgconf_test_case_t *testcase) +{ +#ifndef PKGCONF_LITE + if (pkgconf_buffer_len(&testcase->want_personality)) + return pkgconf_cross_personality_find(pkgconf_buffer_str(&testcase->want_personality)); +#endif + + pkgconf_cross_personality_t *pers = calloc(1, sizeof(*pers)); + if (pers == NULL) + return NULL; + + pers->name = strdup("test"); + pkgconf_path_copy_list(&pers->dir_list, &testcase->search_path); + pkgconf_path_add("/test/sysroot/include", &pers->filter_includedirs, false); + pkgconf_path_add("/test/sysroot/lib", &pers->filter_libdirs, false); + + return pers; +} + +static bool +report_failure(pkgconf_test_match_strategy_t match, const pkgconf_buffer_t *expected, const pkgconf_buffer_t *actual, const char *buffername) +{ + fprintf(stderr, + "================================================================================\n" + "%s did not%s match:\n" + " expected: [%s]\n" + " actual: [%s]\n" + "================================================================================\n", + buffername, match == MATCH_PARTIAL ? " partially" : "", + pkgconf_buffer_str_or_empty(expected), + pkgconf_buffer_str_or_empty(actual)); + + return false; +} + +static bool +test_match_buffer(pkgconf_test_match_strategy_t match, const pkgconf_buffer_t *expected, const pkgconf_buffer_t *actual, const char *buffername) +{ + if (!pkgconf_buffer_len(expected) && match != MATCH_EMPTY) + return true; + + if (!pkgconf_buffer_len(actual)) + { + if (match == MATCH_EMPTY) + return true; + + return report_failure(match, expected, actual, buffername); + } + + if (match == MATCH_PARTIAL) + return pkgconf_buffer_contains(actual, expected) ? true : report_failure(match, expected, actual, buffername); + + return pkgconf_buffer_match(actual, expected) ? true : report_failure(match, expected, actual, buffername); +} + +static bool +read_file_into_buffer(FILE *f, pkgconf_buffer_t *buf) +{ + char tmp[4096] = {0}; + size_t n; + while ((n = fread(tmp, 1, sizeof(tmp), f)) > 0) + pkgconf_buffer_append_slice(buf, tmp, n); + + if (ferror(f)) + return false; + + return true; +} + +static bool +open_file_into_buffer(const char *path, pkgconf_buffer_t *buf) +{ + FILE *f = fopen(path, "r"); + if (f == NULL) + return false; + + bool ok = read_file_into_buffer(f, buf); + fclose(f); + return ok; +} + +static bool +copy_file(const char *dst, const char *src) +{ + FILE *fsrc = fopen(src, "rb"); + if (!fsrc) + return false; + + FILE *fdst = fopen(dst, "wb"); + if (!fdst) + { + int errno_save = errno; + fclose(fsrc); + errno = errno_save; + return false; + } + + bool ok = true; + char buf[4096] = {0}; + size_t nr; + while ((nr = fread(buf, 1, sizeof(buf), fsrc)) > 0) + { + if (fwrite(buf, 1, nr, fdst) != nr) + { + ok = false; + break; + } + } + + if (ferror(fsrc) || ferror(fdst)) + ok = false; + + int errno_save = errno; + fclose(fsrc); + fclose(fdst); + errno = errno_save; + + return ok; +} + +/* + * Recursively remove a directory tree. + */ +static void +rmdir_recursive(const char *path) +{ + DIR *dir = opendir(path); + if (dir == NULL) + return; + + struct dirent *ent; + while ((ent = readdir(dir)) != NULL) + { + if (!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, "..")) + continue; + + pkgconf_buffer_t child = PKGCONF_BUFFER_INITIALIZER; + pkgconf_buffer_append(&child, path); + pkgconf_buffer_push_byte(&child, '/'); + pkgconf_buffer_append(&child, ent->d_name); + +#ifdef _WIN32 + if (_access(pkgconf_buffer_str(&child), 0) == 0) + { + // Get required buffer size + int size = MultiByteToWideChar(CP_ACP, 0, pkgconf_buffer_str(&child), -1, NULL, 0); + + // Allocate and convert + wchar_t* wide_path = calloc(size, sizeof(wchar_t)); + assert(wide_path != NULL); + MultiByteToWideChar(CP_ACP, 0, pkgconf_buffer_str(&child), -1, wide_path, size); + + DWORD attrs = GetFileAttributesW(wide_path); + + free(wide_path); + + if (attrs != INVALID_FILE_ATTRIBUTES && (attrs & FILE_ATTRIBUTE_DIRECTORY)) + rmdir_recursive(pkgconf_buffer_str(&child)); + else + unlink(pkgconf_buffer_str(&child)); + } +#else + struct stat st; + if (lstat(pkgconf_buffer_str(&child), &st) == 0) + { + if (S_ISDIR(st.st_mode)) + rmdir_recursive(pkgconf_buffer_str(&child)); + else + unlink(pkgconf_buffer_str(&child)); + } +#endif + + pkgconf_buffer_finalize(&child); + } + + closedir(dir); + rmdir(path); +} + +/* + * Recursively make a directory tree. + */ +static bool +mkdir_recursive(const char *path) +{ + if (!path) + return false; + + const char *tmpstr = NULL; + pkgconf_buffer_t buf = PKGCONF_BUFFER_INITIALIZER; + size_t i = 0; + + while (path[i]) + { + // Append characters up to the next separator + size_t start = i; + while (path[i] && path[i] != '/') + i++; + + pkgconf_buffer_append_slice(&buf, path + start, i - start); + + // If we hit a separator, try to create this component + if (path[i] == '/') + { + pkgconf_buffer_push_byte(&buf, '/'); + tmpstr = pkgconf_buffer_str(&buf); + if (tmpstr && mkdir(tmpstr, 0755) != 0 && errno != EEXIST) + { + pkgconf_buffer_finalize(&buf); + return false; + } + i++; // skip the separator + } + } + + // Make the final directory (handles paths without trailing separator) + tmpstr = pkgconf_buffer_str(&buf); + bool ok = true; + if (tmpstr && strlen(tmpstr) > 0) + { + if (mkdir(tmpstr, 0755) != 0 && errno != EEXIST) + ok = false; + } + + pkgconf_buffer_finalize(&buf); + return ok; +} + +// Returns true if we need tmp_dir +static bool +needs_tmp_dir(const pkgconf_test_case_t *testcase) +{ +#ifdef _WIN32 + return testcase->mkdirs.head != NULL || testcase->copies.head != NULL; +#else // _WIN32 + return testcase->mkdirs.head != NULL || testcase->copies.head != NULL || testcase->symlinks.head != NULL; +#endif // _WIN32 +} + +static int +run_tool(const pkgconf_test_case_t *testcase, pkgconf_buffer_t *o_stdout, pkgconf_buffer_t *o_stderr) +{ + (void) o_stderr; // TODO: external tool stderr goes to real stderr for now + + pkgconf_buffer_t cmdbuf = PKGCONF_BUFFER_INITIALIZER; + + // build: <tool-dir>/<tool> <tool_args> + if (pkgconf_buffer_len(&test_tool_dir)) + { + pkgconf_buffer_append(&cmdbuf, pkgconf_buffer_str(&test_tool_dir)); + pkgconf_buffer_push_byte(&cmdbuf, '/'); + } + + pkgconf_buffer_append(&cmdbuf, pkgconf_buffer_str(&testcase->tool)); + + if (pkgconf_buffer_len(&testcase->tool_args)) + { + pkgconf_buffer_append(&cmdbuf, " "); + pkgconf_buffer_append(&cmdbuf, pkgconf_buffer_str(&testcase->tool_args)); + } + + // Inject Environment vars for the child process + char tool_cwd[PATH_MAX] = {0}; + const char *pwd = getcwd(tool_cwd, sizeof(tool_cwd)); + + pkgconf_node_t *iter; + PKGCONF_FOREACH_LIST_ENTRY(testcase->env_vars.head, iter) + { + pkgconf_test_environ_t *env = iter->data; + pkgconf_buffer_t expanded = PKGCONF_BUFFER_INITIALIZER; + handle_substs(&expanded, PKGCONF_BUFFER_FROM_STR(env->value), pwd); + setenv(env->key, pkgconf_buffer_str_or_empty(&expanded), 1); + pkgconf_buffer_finalize(&expanded); + } + + FILE *pipe = popen(pkgconf_buffer_str(&cmdbuf), "r"); + pkgconf_buffer_finalize(&cmdbuf); + + if (pipe == NULL) + { + fprintf(stderr, "popen failed for tool '%s': %s\n", + pkgconf_buffer_str(&testcase->tool), strerror(errno)); + return -1; + } + + bool ok = read_file_into_buffer(pipe, o_stdout); + int saved_errno = errno; // pclose() will clobber errno, save it + int status = pclose(pipe); + if (!ok) + { + fprintf(stderr, "read failed into buffer for command '%s': %s", + pkgconf_buffer_str(&testcase->tool), strerror(saved_errno)); + return -1; + } + + if (status == -1) + { + fprintf(stderr, "pclose failed for command '%s': %s\n", + pkgconf_buffer_str(&testcase->tool), strerror(errno)); + return -1; + } + +#if defined(WIFEXITED) && defined(WEXITSTATUS) + if (WIFEXITED(status)) + return WEXITSTATUS(status); + + fprintf(stderr, "command '%s' did not exit normally\n", + pkgconf_buffer_str(&testcase->tool)); + return -1; +#else + return status; +#endif +} + +/* + * Split a bufferset entry on the first space into left and right halves. + * Caller must free *left_out and *right_out. + */ +static bool +split_pair(const char *entry, char **left_out, char **right_out) +{ + if (entry == NULL) + return false; + + const char *sp = strchr(entry, ' '); + if (sp == NULL) + return false; + + *left_out = pkgconf_strndup(entry, (size_t)(sp - entry)); + *right_out = strdup(sp + 1); + return true; +} + +/* + * run_setup: execute mkdirs, copies, and symlinks in order. + * Must be called after chdir() into the tmp_dir. + */ +static bool +run_setup(const pkgconf_test_case_t *testcase, const char *pwd) +{ + pkgconf_node_t *iter; + + // mkdirs: each entry is a single path, relative to tmp_dir + PKGCONF_FOREACH_LIST_ENTRY(testcase->mkdirs.head, iter) + { + pkgconf_bufferset_t *set = iter->data; + + pkgconf_buffer_t path = PKGCONF_BUFFER_INITIALIZER; + handle_substs(&path, &set->buffer, pwd); + + bool ok = mkdir_recursive(pkgconf_buffer_str(&path)); + pkgconf_buffer_finalize(&path); + + if (!ok && errno != EEXIST) + { + fprintf(stderr, "SetupMkdir: mkdir '%s' failed: %s\n", + pkgconf_buffer_str_or_empty(&set->buffer), strerror(errno)); + return false; + } + } + + // copies: "src dst", src relative to TEST_FIXTURES_DIR, dst relative to tmp_dir + PKGCONF_FOREACH_LIST_ENTRY(testcase->copies.head, iter) + { + pkgconf_bufferset_t *set = iter->data; + + pkgconf_buffer_t expanded = PKGCONF_BUFFER_INITIALIZER; + handle_substs(&expanded, &set->buffer, pwd); + + char *left = NULL, *right = NULL; + if (!split_pair(pkgconf_buffer_str(&expanded), &left, &right)) + { + fprintf(stderr, "SetupCopy: malformed entry (expected 'src dst'): %s\n", + pkgconf_buffer_str_or_empty(&set->buffer)); + pkgconf_buffer_finalize(&expanded); + return false; + } + pkgconf_buffer_finalize(&expanded); + + pkgconf_buffer_t srcpath = PKGCONF_BUFFER_INITIALIZER; + pkgconf_buffer_append(&srcpath, pkgconf_buffer_str(&test_fixtures_dir)); + pkgconf_buffer_push_byte(&srcpath, '/'); + pkgconf_buffer_append(&srcpath, left); + + bool ok = copy_file(right, pkgconf_buffer_str(&srcpath)); + pkgconf_buffer_finalize(&srcpath); + if (!ok) + { + fprintf(stderr, "SetupCopy: failed to copy file '%s' to '%s': %s\n", left, right, strerror(errno)); + free(left); + free(right); + return false; + } + + free(left); + free(right); + } + +#ifndef _WIN32 + // symlinks: "target linkpath" — both may be relative to tmp_dir or absolute after %PWD% expansion + PKGCONF_FOREACH_LIST_ENTRY(testcase->symlinks.head, iter) + { + pkgconf_bufferset_t *set = iter->data; + + pkgconf_buffer_t expanded = PKGCONF_BUFFER_INITIALIZER; + handle_substs(&expanded, &set->buffer, pwd); + + char *target = NULL, *linkpath = NULL; + if (!split_pair(pkgconf_buffer_str(&expanded), &target, &linkpath)) + { + fprintf(stderr, "SetupSymlink: malformed entry (expected 'target linkpath'): %s\n", + pkgconf_buffer_str_or_empty(&set->buffer)); + pkgconf_buffer_finalize(&expanded); + return false; + } + pkgconf_buffer_finalize(&expanded); + + unlink(linkpath); + + if (symlink(target, linkpath) != 0) + { + fprintf(stderr, "SetupSymlink: symlink('%s', '%s') failed: %s\n", + target, linkpath, strerror(errno)); + free(target); + free(linkpath); + return false; + } + + free(target); + free(linkpath); + } +#endif // _WIN32 + + return true; +} + +static void +annotate_result(const pkgconf_test_case_t *testcase, int ret, const pkgconf_test_output_t *out) +{ + pkgconf_buffer_t search_path_buf = PKGCONF_BUFFER_INITIALIZER; + const pkgconf_node_t *iter; + + PKGCONF_FOREACH_LIST_ENTRY(testcase->search_path.head, iter) + { + const pkgconf_path_t *path = iter->data; + + if (pkgconf_buffer_len(&search_path_buf)) + pkgconf_buffer_push_byte(&search_path_buf, ' '); + + pkgconf_buffer_append(&search_path_buf, path->path); + } + + pkgconf_buffer_t wanted_flags_buf = PKGCONF_BUFFER_INITIALIZER; + + for (size_t i = 0; i < PKGCONF_ARRAY_SIZE(test_flag_pairs); i++) + { + const pkgconf_test_flag_pair_t *pair = &test_flag_pairs[i]; + + if ((testcase->wanted_flags & pair->flag) == pair->flag) + { + if (pkgconf_buffer_len(&wanted_flags_buf)) + pkgconf_buffer_push_byte(&wanted_flags_buf, ' '); + + pkgconf_buffer_append(&wanted_flags_buf, pair->name); + } + } + + pkgconf_buffer_t env_buf = PKGCONF_BUFFER_INITIALIZER; + + PKGCONF_FOREACH_LIST_ENTRY(testcase->env_vars.head, iter) + { + const pkgconf_test_environ_t *env = iter->data; + + if (pkgconf_buffer_len(&env_buf)) + pkgconf_buffer_append(&env_buf, "\n "); + + pkgconf_buffer_append_fmt(&env_buf, "%s: %s", env->key, env->value); + } + + fprintf(stderr, + "--------------------------------------------------------------------------------\n" + "search-path: <%s>\n" + "wanted-flags: <%s>\n" + "environment:\n" + " %s\n" + "query: [%s]\n" + "exit-code: %d\n" + "verbosity: %d\n", + pkgconf_buffer_str_or_empty(&search_path_buf), + pkgconf_buffer_str_or_empty(&wanted_flags_buf), + pkgconf_buffer_str_or_empty(&env_buf), + pkgconf_buffer_str_or_empty(&testcase->query), + ret, + testcase->verbosity); + + if (pkgconf_buffer_len(&testcase->tool)) + fprintf(stderr, "tool: [%s] tool-args: [%s]\n", + pkgconf_buffer_str_or_empty(&testcase->tool), + pkgconf_buffer_str_or_empty(&testcase->tool_args)); + + fprintf(stderr, "stdout: [%s]\n", + pkgconf_buffer_str_or_empty(&out->o_stdout)); + + PKGCONF_FOREACH_LIST_ENTRY(testcase->expected_stdout.head, iter) + { + pkgconf_bufferset_t *set = iter->data; + + fprintf(stderr, + "expected-stdout: [%s] (%s)\n", + pkgconf_buffer_str_or_empty(&set->buffer), + testcase->match_stdout == MATCH_PARTIAL ? "partial" : "exact"); + } + + if (pkgconf_buffer_len(&testcase->expected_stdout_file)) + fprintf(stderr, "expected-stdout-file: [%s]\n", + pkgconf_buffer_str_or_empty(&testcase->expected_stdout_file)); + + fprintf(stderr, "stderr: [%s]\n", + pkgconf_buffer_str_or_empty(&out->o_stderr)); + + PKGCONF_FOREACH_LIST_ENTRY(testcase->expected_stderr.head, iter) + { + pkgconf_bufferset_t *set = iter->data; + + fprintf(stderr, + "expected-stderr: [%s] (%s)\n", + pkgconf_buffer_str_or_empty(&set->buffer), + testcase->match_stderr == MATCH_PARTIAL ? "partial" : "exact"); + } + + PKGCONF_FOREACH_LIST_ENTRY(testcase->define_variables.head, iter) + { + pkgconf_bufferset_t *set = iter->data; + fprintf(stderr, "define-variable: [%s]\n", pkgconf_buffer_str_or_empty(&set->buffer)); + } + + fprintf(stderr, + "want-env-prefix: [%s]\n" + "fragment-filter: [%s]\n" + "--------------------------------------------------------------------------------\n", + pkgconf_buffer_str_or_empty(&testcase->want_env_prefix), + pkgconf_buffer_str_or_empty(&testcase->fragment_filter)); + + pkgconf_buffer_finalize(&search_path_buf); + pkgconf_buffer_finalize(&wanted_flags_buf); + pkgconf_buffer_finalize(&env_buf); +} + +static bool +run_test_case(const pkgconf_test_case_t *testcase) +{ + bool passed = true; + + const pkgconf_buffer_t *our_platform = PKGCONF_BUFFER_FROM_STR(PKGCONF_TEST_PLATFORM); + if (pkgconf_buffer_contains(&testcase->skip_platforms, our_platform)) + { + printf("# test skipped on %s\nSKIP: %s\n", + pkgconf_buffer_str(our_platform), testcase->name); + return true; + } + + if (testcase->require_utf8_locale && !pkgconf_is_locale_utf8()) + { + printf("# test skipped: requires a UTF-8 locale\nSKIP: %s\n", testcase->name); + return true; + } + + // If the test has setup steps, create a new tmp_dir and chdir into it. + char original_cwd[PATH_MAX] = {0}; + char *tmp_dir = NULL; + + if (getcwd(original_cwd, sizeof(original_cwd)) == NULL) + { + fprintf(stderr, "FAIL: getcwd failed: %s\n", strerror(errno)); + return false; + } + + if (needs_tmp_dir(testcase)) + { + pkgconf_buffer_t tmp_buf = PKGCONF_BUFFER_INITIALIZER; + pkgconf_buffer_append_fmt(&tmp_buf, "%s/pkgconf-test-XXXXXX", original_cwd); + tmp_dir = pkgconf_buffer_freeze(&tmp_buf); + + if (mkdtemp(tmp_dir) == NULL) + { + fprintf(stderr, "FAIL: mkdtemp failed: %s\n", strerror(errno)); + free(tmp_dir); + return false; + } + + if (chdir(tmp_dir) != 0) + { + fprintf(stderr, "FAIL: chdir('%s') failed: %s\n", tmp_dir, strerror(errno)); + rmdir(tmp_dir); + free(tmp_dir); + return false; + } + + if (!run_setup(testcase, tmp_dir)) + { + fprintf(stderr, "FAIL: %s (setup failed)\n", testcase->name); + chdir(original_cwd); + rmdir_recursive(tmp_dir); + free(tmp_dir); + return false; + } + } + + pkgconf_test_output_t *out = (pkgconf_test_output_t *) test_output(); + int ret; + + if (pkgconf_buffer_len(&testcase->tool)) + { + ret = run_tool(testcase, &out->o_stdout, &out->o_stderr); + } + else + { + pkgconf_cross_personality_t *personality = personality_for_test(testcase); + pkgconf_test_state_t state = + { + .cli_state.want_flags = testcase->wanted_flags, + .cli_state.want_env_prefix = pkgconf_buffer_str(&testcase->want_env_prefix), + .cli_state.want_variable = pkgconf_buffer_str(&testcase->want_variable), + .cli_state.want_fragment_filter = pkgconf_buffer_str(&testcase->fragment_filter), + .cli_state.required_module_version = pkgconf_buffer_str(&testcase->atleast_version), + .cli_state.required_exact_module_version = pkgconf_buffer_str(&testcase->exact_version), + .cli_state.required_max_module_version = pkgconf_buffer_str(&testcase->max_version), + .cli_state.verbosity = testcase->verbosity, + .testcase = testcase, + }; + + pkgconf_client_init(&state.cli_state.pkg_client, error_handler, NULL, personality, &state, environ_lookup_handler); + pkgconf_client_set_output(&state.cli_state.pkg_client, &out->output); + + pkgconf_node_t *iter; + PKGCONF_FOREACH_LIST_ENTRY(testcase->define_variables.head, iter) + { + pkgconf_bufferset_t *set = iter->data; + pkgconf_tuple_define_global(&state.cli_state.pkg_client, pkgconf_buffer_str_or_empty(&set->buffer)); + } + + /* + * Re-expand Query now that %PWD% is known (if we have a tmp_dir). + * For tests without a tmp_dir this is a no-op since %PWD% won't appear. + */ + char query_cwd[PATH_MAX] = {0}; + const char *query_pwd = getcwd(query_cwd, sizeof(query_cwd)); + + pkgconf_buffer_t query_expanded = PKGCONF_BUFFER_INITIALIZER; + handle_substs(&query_expanded, &testcase->query, query_pwd); + + pkgconf_buffer_t arg_buf = PKGCONF_BUFFER_INITIALIZER; + int test_argc = 0; + char **test_argv = NULL; + + if (pkgconf_buffer_len(&query_expanded)) + pkgconf_buffer_append_fmt(&arg_buf, "pkgconf %s", pkgconf_buffer_str(&query_expanded)); + else + pkgconf_buffer_append(&arg_buf, "pkgconf"); + + pkgconf_argv_split(pkgconf_buffer_str(&arg_buf), &test_argc, &test_argv); + pkgconf_buffer_finalize(&arg_buf); + pkgconf_buffer_finalize(&query_expanded); + + pkgconf_client_set_warn_handler(&state.cli_state.pkg_client, error_handler, NULL); + +#ifndef PKGCONF_LITE + if (debug) + pkgconf_client_set_trace_handler(&state.cli_state.pkg_client, debug_handler, NULL); +#endif // PKGCONF_LITE + + ret = pkgconf_cli_run(&state.cli_state, test_argc, test_argv, 1); + pkgconf_argv_free(test_argv); + } + + if (pkgconf_buffer_len(&out->o_stdout)) + pkgconf_buffer_trim_byte(&out->o_stdout); + + if (pkgconf_buffer_len(&out->o_stderr)) + pkgconf_buffer_trim_byte(&out->o_stderr); + + pkgconf_node_t *iter; + + PKGCONF_FOREACH_LIST_ENTRY(testcase->expected_stdout.head, iter) + { + pkgconf_bufferset_t *set = iter->data; + + char expected_cwd[PATH_MAX] = {0}; + const char *expected_pwd = getcwd(expected_cwd, sizeof(expected_cwd)); + + pkgconf_buffer_t expected_expanded = PKGCONF_BUFFER_INITIALIZER; + handle_substs(&expected_expanded, &set->buffer, expected_pwd); + + if (!test_match_buffer(testcase->match_stdout, &expected_expanded, &out->o_stdout, "stdout")) + passed = false; + + pkgconf_buffer_finalize(&expected_expanded); + } + + // ExpectedStdoutFile: load file relative to the .test file's directory + if (pkgconf_buffer_len(&testcase->expected_stdout_file)) + { + pkgconf_buffer_t filepath = PKGCONF_BUFFER_INITIALIZER; + pkgconf_buffer_append(&filepath, testcase->testfile_dir); + pkgconf_buffer_push_byte(&filepath, '/'); + pkgconf_buffer_append(&filepath, pkgconf_buffer_str(&testcase->expected_stdout_file)); + + pkgconf_buffer_t file_contents = PKGCONF_BUFFER_INITIALIZER; + if (!open_file_into_buffer(pkgconf_buffer_str(&filepath), &file_contents)) + { + fprintf(stderr, "ExpectedStdoutFile: failed to open '%s': %s\n", pkgconf_buffer_str(&filepath), strerror(errno)); + passed = false; + } + else + { + if (pkgconf_buffer_len(&file_contents)) + pkgconf_buffer_trim_byte(&file_contents); + + if (!test_match_buffer(testcase->match_stdout, &file_contents, &out->o_stdout, "stdout (file)")) + passed = false; + } + + pkgconf_buffer_finalize(&file_contents); + pkgconf_buffer_finalize(&filepath); + } + + PKGCONF_FOREACH_LIST_ENTRY(testcase->expected_stderr.head, iter) + { + pkgconf_bufferset_t *set = iter->data; + + if (!test_match_buffer(testcase->match_stderr, &set->buffer, &out->o_stderr, "stderr")) + passed = false; + } + + if (ret != testcase->exitcode) + { + fprintf(stderr, "exitcode %d does not match expected %d\n", ret, testcase->exitcode); + passed = false; + } + + printf("%s: %s\n", passed ? "PASS" : "FAIL", testcase->name); + + if (!passed) + annotate_result(testcase, ret, out); + + test_output_reset(out); + + // Restore cwd and clean up tmp_dir if we created one + if (tmp_dir && strcmp(tmp_dir, original_cwd) != 0) + { + chdir(original_cwd); + rmdir_recursive(tmp_dir); + } + + free(tmp_dir); + return passed; +} + +static void +free_test_case(pkgconf_test_case_t *testcase) +{ + pkgconf_bufferset_free(&testcase->define_variables); + pkgconf_bufferset_free(&testcase->expected_stderr); + pkgconf_bufferset_free(&testcase->expected_stdout); + pkgconf_bufferset_free(&testcase->mkdirs); +#ifndef _WIN32 + pkgconf_bufferset_free(&testcase->symlinks); +#endif // _WIN32 + pkgconf_bufferset_free(&testcase->copies); + + test_environment_free(&testcase->env_vars); + pkgconf_path_free(&testcase->search_path); + + pkgconf_buffer_finalize(&testcase->query); + pkgconf_buffer_finalize(&testcase->want_env_prefix); + pkgconf_buffer_finalize(&testcase->want_variable); + pkgconf_buffer_finalize(&testcase->fragment_filter); + pkgconf_buffer_finalize(&testcase->skip_platforms); + pkgconf_buffer_finalize(&testcase->atleast_version); + pkgconf_buffer_finalize(&testcase->exact_version); + pkgconf_buffer_finalize(&testcase->max_version); + pkgconf_buffer_finalize(&testcase->expected_stdout_file); + pkgconf_buffer_finalize(&testcase->tool); + pkgconf_buffer_finalize(&testcase->tool_args); + +#ifndef PKGCONF_LITE + pkgconf_buffer_finalize(&testcase->want_personality); +#endif + + free(testcase->name); + free(testcase->testfile_dir); + free(testcase); +} + +static bool +process_test_case(char *testcase_file) +{ + pkgconf_test_case_t *testcase = load_test_case(testcase_file); + bool ret; + + if (testcase == NULL) + { + fprintf(stderr, "test %s failed to load\n", testcase_file); + return false; + } + + ret = run_test_case(testcase); + free_test_case(testcase); + + return ret; +} + +static inline bool +str_has_suffix(const char *str, const char *suffix) +{ + size_t str_len = strlen(str); + size_t suf_len = strlen(suffix); + + if (str_len < suf_len) + return false; + + return !strncasecmp(str + str_len - suf_len, suffix, suf_len); +} + +static int +path_sort_cmp(const void *a, const void *b) +{ + return strcmp(*(const char **) a, *(const char **) b); +} + +static bool +process_test_directory(char *dirpath) +{ + bool ret = true; + DIR *dir = opendir(dirpath); + if (dir == NULL) + { + fprintf(stderr, "failed to open test directory %s\n", dirpath); + return false; + } + char **paths = NULL; + size_t numpaths = 0; + + struct dirent *dirent; + for (dirent = readdir(dir); dirent != NULL; dirent = readdir(dir)) + { + pkgconf_buffer_t pathbuf = PKGCONF_BUFFER_INITIALIZER; + + pkgconf_buffer_append(&pathbuf, dirpath); + pkgconf_buffer_push_byte(&pathbuf, '/'); + pkgconf_buffer_append(&pathbuf, dirent->d_name); + + char *pathstr = pkgconf_buffer_freeze(&pathbuf); + if (pathstr == NULL) + continue; + + if (!str_has_suffix(pathstr, ".test")) + { + free(pathstr); + continue; + } + + paths = pkgconf_reallocarray(paths, ++numpaths, sizeof(void *)); + paths[numpaths - 1] = pathstr; + } + + qsort(paths, numpaths, sizeof(void *), path_sort_cmp); + + for (size_t i = 0; i < numpaths; i++) + { + char *pathstr = paths[i]; + + ret = process_test_case(pathstr); + if (!ret) + break; + } + + for (size_t i = 0; i < numpaths; i++) + free(paths[i]); + + free(paths); + closedir(dir); + return ret; +} + +static void +usage(void) +{ + fprintf(stderr, "usage: test-runner --test-fixtures <path-to-fixtures> [--tool-dir <path>] <path-to-tests>\n"); + exit(EXIT_FAILURE); +} + +int +main(int argc, char *argv[]) +{ + int ret; + char *test_fixtures_dir_arg = NULL; + char *test_tool_dir_arg = NULL; + + struct pkg_option options[] = + { + {"test-fixtures", required_argument, NULL, 1}, + {"debug", no_argument, NULL, 2}, + {"test-case", required_argument, NULL, 3}, + {"tool-dir", required_argument, NULL, 4}, + {NULL, 0, NULL, 0}, + }; + char *testcase = NULL; + + while ((ret = pkg_getopt_long_only(argc, argv, "", options, NULL)) != -1) + { + switch (ret) + { + case 1: + test_fixtures_dir_arg = pkg_optarg; + break; + case 2: + debug = true; + break; + case 3: + testcase = pkg_optarg; + break; + case 4: + test_tool_dir_arg = pkg_optarg; + break; + } + } + + if (test_fixtures_dir_arg == NULL) + usage(); + + { + char test_fixtures_dir_abs[PATH_MAX] = {0}; + if (!realpath(test_fixtures_dir_arg, test_fixtures_dir_abs)) + { + fprintf(stderr, "realpath failed: %s\n", strerror(errno)); + return EXIT_FAILURE; + } + const pkgconf_buffer_t *test_fixtures_dir_arg_buf = PKGCONF_BUFFER_FROM_STR_NONNULL(test_fixtures_dir_abs); + pkgconf_buffer_subst(&test_fixtures_dir, test_fixtures_dir_arg_buf, "\\", "/"); + } + + if (test_tool_dir_arg != NULL) + { + const pkgconf_buffer_t *test_tool_dir_arg_buf = PKGCONF_BUFFER_FROM_STR(test_tool_dir_arg); + pkgconf_buffer_subst(&test_tool_dir, test_tool_dir_arg_buf, "\\", "/"); + } + + if (testcase != NULL) + return process_test_case(testcase) ? EXIT_SUCCESS : EXIT_FAILURE; + + if (argv[pkg_optind] == NULL) + usage(); + + return process_test_directory(argv[pkg_optind]) ? EXIT_SUCCESS : EXIT_FAILURE; +} diff --git a/tests/test_env.sh.in b/tests/test_env.sh.in deleted file mode 100644 index d2b6136f18c9..000000000000 --- a/tests/test_env.sh.in +++ /dev/null @@ -1,50 +0,0 @@ -srcdir="$(atf_get_srcdir)" -export PATH="$srcdir/..:${PATH}" - -#--- begin windows kludge --- -# When building with Visual Studio, binaries are in a subdirectory named after the configration... -# and the configuration is not known unless you're in the IDE, or something. -# So just guess. This won't work well if you build more than one configuration. -the_configuration="" -for configuration in Debug Release RelWithDebInfo -do - if test -d "$srcdir/../$configuration" - then - if test "$the_configuration" != "" - then - echo "test_env.sh: FAIL: more than one configuration found" - exit 1 - fi - the_configuration=$configuration - export PATH="$srcdir/../${configuration}:${PATH}" - fi -done -#--- end kludge --- - -selfdir="@abs_top_srcdir@/tests" -LIBRARY_PATH_ENV="LIBRARY_PATH" -PATH_SEP=":" -SYSROOT_DIR="${selfdir}" -case "$(uname -s)" in -Haiku) LIBRARY_PATH_ENV="BELIBRARIES";; -esac - -prefix="@prefix@" -exec_prefix="@exec_prefix@" -datarootdir="@datarootdir@" -pcpath="@PKG_DEFAULT_PATH@" - -tests_init() -{ - TESTS="$@" - export TESTS - for t ; do - atf_test_case $t - done -} - -atf_init_test_cases() { - for t in ${TESTS}; do - atf_add_test_case $t - done -} diff --git a/tests/version.sh b/tests/version.sh deleted file mode 100755 index 0172c0437da6..000000000000 --- a/tests/version.sh +++ /dev/null @@ -1,38 +0,0 @@ -#!/usr/bin/env atf-sh - -. $(atf_get_srcdir)/test_env.sh - -tests_init \ - atleast \ - exact \ - max - -atleast_body() -{ - export PKG_CONFIG_PATH="${selfdir}/lib1" - atf_check \ - pkgconf --atleast-version 1.0 foo - atf_check \ - -s exit:1 \ - pkgconf --atleast-version 2.0 foo -} - -exact_body() -{ - export PKG_CONFIG_PATH="${selfdir}/lib1" - atf_check \ - -s exit:1 \ - pkgconf --exact-version 1.0 foo - atf_check \ - pkgconf --exact-version 1.2.3 foo -} - -max_body() -{ - export PKG_CONFIG_PATH="${selfdir}/lib1" - atf_check \ - -s exit:1 \ - pkgconf --max-version 1.0 foo - atf_check \ - pkgconf --max-version 2.0 foo -} diff --git a/tests/win-shim.h b/tests/win-shim.h new file mode 100644 index 000000000000..a58c83d794cc --- /dev/null +++ b/tests/win-shim.h @@ -0,0 +1,57 @@ +/* + * win-shim.h + * Windows function/define shims + * + * SPDX-License-Identifier: pkgconf + * + * Copyright (c) 2025 pkgconf authors (see AUTHORS). + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * This software is provided 'as is' and without any warranty, express or + * implied. In no event shall the authors be liable for any damages arising + * from the use of this software. + */ + +#ifndef WIN_SHIM_H +#define WIN_SHIM_H + +#ifdef _WIN32 + +#include <direct.h> +#include <io.h> + +// Shims shared by both MSVC and MSYS2 +#define mkdir(p, m) _mkdir(p) +#define setenv(n, v, o) _putenv_s(n, v) +#define unsetenv(n) _putenv_s(n, "") + +#ifndef PATH_MAX +# define PATH_MAX MAX_PATH +#endif // !PATH_MAX + +// MSVC-specific shims +#ifdef _MSC_VER +# define getcwd _getcwd +# define chdir _chdir +# define rmdir _rmdir +# define lstat _lstat +# define unlink _unlink +# define popen _popen +# define pclose _pclose + +static inline char * +mkdtemp(char *tmpl) +{ + if (_mktemp_s(tmpl, strlen(tmpl) + 1) != 0) + return NULL; + if (_mkdir(tmpl) != 0) + return NULL; + return tmpl; +} +#endif // _MSC_VER + +#endif // _WIN32 +#endif // WIN_SHIM_H |
