summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPierre Pronchery <khorben@FreeBSD.org>2026-06-25 22:11:37 +0000
committerPierre Pronchery <khorben@FreeBSD.org>2026-06-29 05:21:46 +0000
commiteaa637963bcfde283b411c14968b7903b02d6aa1 (patch)
treec8923ff21bac1e9ac4b5e7107b8a071f27f2d8a2
parentebcc78644e0cbc4141807c0887ef8d902cb91bb4 (diff)
-rw-r--r--Makefile.am98
-rw-r--r--Makefile.lite2
-rw-r--r--NEWS20
-rw-r--r--cli/bomtool/main.c35
-rw-r--r--cli/main.c21
-rw-r--r--cli/spdxtool/util.c29
-rw-r--r--cli/spdxtool/util.h3
-rw-r--r--codecov.yml12
-rw-r--r--configure.ac2
-rw-r--r--libpkgconf/client.c8
-rw-r--r--libpkgconf/libpkgconf.h6
-rw-r--r--libpkgconf/path.c13
-rw-r--r--man/bomtool.127
-rw-r--r--man/pkgconf.15
-rw-r--r--man/spdxtool.19
-rw-r--r--meson.build22
-rw-r--r--t/bomtool/about.test5
-rw-r--r--t/bomtool/bad-output.test4
-rw-r--r--t/bomtool/basic.test5
-rw-r--r--t/bomtool/default-time.test6
-rw-r--r--t/bomtool/define-variable-with-dependency.test5
-rw-r--r--t/bomtool/define-variable.test5
-rw-r--r--t/bomtool/help.test5
-rw-r--r--t/bomtool/meta-package.test5
-rw-r--r--t/bomtool/multiple-packages.test5
-rw-r--r--t/bomtool/no-license.test5
-rw-r--r--t/bomtool/output-file.test5
-rw-r--r--t/bomtool/package-whitespace.test6
-rw-r--r--t/bomtool/source-date-epoch-precedence.test6
-rw-r--r--t/bomtool/source-date-epoch.test7
-rw-r--r--t/bomtool/special-chars.test5
-rw-r--r--t/bomtool/unknown-option.test3
-rw-r--r--t/bomtool/unknown-package.test4
-rw-r--r--t/bomtool/version-operator.test6
-rw-r--r--t/bomtool/version.test5
-rw-r--r--t/bomtool/with-dependency.test5
-rw-r--r--t/cli/about.test5
-rw-r--r--t/cli/atleast-pkgconfig-version-fail.test3
-rw-r--r--t/cli/atleast-pkgconfig-version-pass.test3
-rw-r--r--t/cli/cflags-libs.test5
-rw-r--r--t/cli/dump-personality.test5
-rw-r--r--t/cli/exists-missing.test4
-rw-r--r--t/cli/exists-valid.test4
-rw-r--r--t/cli/help.test5
-rw-r--r--t/cli/missing-package-error.test6
-rw-r--r--t/cli/missing-package.test4
-rw-r--r--t/cli/modversion.test5
-rw-r--r--t/cli/no-arguments.test2
-rw-r--r--t/cli/unknown-option.test3
-rw-r--r--t/cli/version.test3
-rw-r--r--t/spdxtool/about.test5
-rw-r--r--t/spdxtool/agent-name-space.test6
-rw-r--r--t/spdxtool/agent-name.test5
-rw-r--r--t/spdxtool/bad-output.test4
-rw-r--r--t/spdxtool/creation-id.test5
-rw-r--r--t/spdxtool/default-time.test6
-rw-r--r--t/spdxtool/define-variable-with-dependency.test (renamed from t/spdxtool/define-variable-with-depencency.test)0
-rw-r--r--t/spdxtool/help.test5
-rw-r--r--t/spdxtool/multi-copyright.test5
-rw-r--r--t/spdxtool/multiple-packages.test5
-rw-r--r--t/spdxtool/no-license.test5
-rw-r--r--t/spdxtool/output-file.test5
-rw-r--r--t/spdxtool/package-whitespace.test6
-rw-r--r--t/spdxtool/source-date-epoch-precedence.test6
-rw-r--r--t/spdxtool/source-date-epoch.test7
-rw-r--r--t/spdxtool/special-chars.test5
-rw-r--r--t/spdxtool/unknown-option.test3
-rw-r--r--t/spdxtool/unknown-package.test4
-rw-r--r--t/spdxtool/version-operator.test6
-rw-r--r--t/spdxtool/version.test5
-rw-r--r--tests/api/test-fileio.c2
-rw-r--r--tests/api/test-serialize.c203
-rw-r--r--tests/lib-sbom-files/agent_name.json90
-rw-r--r--tests/lib-sbom-files/agent_name_space.json90
-rw-r--r--tests/lib-sbom-files/bomtool-basic.txt24
-rw-r--r--tests/lib-sbom-files/bomtool-define_variable.txt24
-rw-r--r--tests/lib-sbom-files/bomtool-define_variable_with_dependency.txt43
-rw-r--r--tests/lib-sbom-files/bomtool-meta_package.txt137
-rw-r--r--tests/lib-sbom-files/bomtool-multiple_packages.txt39
-rw-r--r--tests/lib-sbom-files/bomtool-nolicense.txt24
-rw-r--r--tests/lib-sbom-files/bomtool-special.txt24
-rw-r--r--tests/lib-sbom-files/bomtool-with_dependency.txt43
-rw-r--r--tests/lib-sbom-files/creation_id.json90
-rw-r--r--tests/lib-sbom-files/multi_copyright.json90
-rw-r--r--tests/lib-sbom-files/multiple_packages.json150
-rw-r--r--tests/lib-sbom-files/nolicense.json59
-rw-r--r--tests/lib-sbom-files/special.json90
-rw-r--r--tests/lib-sbom/multi-copyright.pc7
-rw-r--r--tests/lib-sbom/nolicense.pc6
-rw-r--r--tests/lib-sbom/special.pc6
-rw-r--r--tests/test-runner.c9
91 files changed, 1746 insertions, 73 deletions
diff --git a/Makefile.am b/Makefile.am
index 6d5ed6e55c66..603b49054127 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -23,6 +23,20 @@ EXTRA_DIST = pkg.m4 \
libpkgconf/meson.build \
libpkgconf/config.h.meson \
libpkgconf/win-dirent.h \
+ t/cli/about.test \
+ t/cli/atleast-pkgconfig-version-fail.test \
+ t/cli/atleast-pkgconfig-version-pass.test \
+ t/cli/cflags-libs.test \
+ t/cli/dump-personality.test \
+ t/cli/exists-missing.test \
+ t/cli/exists-valid.test \
+ t/cli/help.test \
+ t/cli/missing-package.test \
+ t/cli/missing-package-error.test \
+ t/cli/modversion.test \
+ t/cli/no-arguments.test \
+ t/cli/unknown-option.test \
+ t/cli/version.test \
t/basic/arbitrary-path.test \
t/basic/builtin-pkg-config-exists.test \
t/basic/builtin-pkg-config-pc_path-variable.test \
@@ -203,8 +217,52 @@ EXTRA_DIST = pkg.m4 \
t/solver/requires-private-debounce.test \
t/solver/requires-private-missing.test \
t/solver/requires-static-cflags.test \
+ t/bomtool/about.test \
+ t/bomtool/bad-output.test \
+ t/bomtool/basic.test \
+ t/bomtool/default-time.test \
+ t/bomtool/define-variable.test \
+ t/bomtool/define-variable-with-dependency.test \
+ t/bomtool/help.test \
+ t/bomtool/meta-package.test \
+ t/bomtool/multiple-packages.test \
+ t/bomtool/no-license.test \
+ t/bomtool/output-file.test \
+ t/bomtool/package-whitespace.test \
+ t/bomtool/source-date-epoch.test \
+ t/bomtool/source-date-epoch-precedence.test \
+ t/bomtool/special-chars.test \
+ t/bomtool/unknown-option.test \
+ t/bomtool/unknown-package.test \
+ t/bomtool/version.test \
+ t/bomtool/version-operator.test \
+ t/bomtool/with-dependency.test \
+ t/spdxtool/about.test \
+ t/spdxtool/agent-name.test \
+ t/spdxtool/agent-name-space.test \
+ t/spdxtool/bad-output.test \
t/spdxtool/basic.test \
+ t/spdxtool/basic-with-colon.test \
+ t/spdxtool/basic-with-spdx-base-id.test \
+ t/spdxtool/creation-id.test \
+ t/spdxtool/default-time.test \
+ t/spdxtool/define-variable.test \
+ t/spdxtool/define-variable-with-dependency.test \
+ t/spdxtool/help.test \
t/spdxtool/meta-package.test \
+ t/spdxtool/meta-package-with-colon-spdx-base-id.test \
+ t/spdxtool/multi-copyright.test \
+ t/spdxtool/multiple-packages.test \
+ t/spdxtool/no-license.test \
+ t/spdxtool/output-file.test \
+ t/spdxtool/package-whitespace.test \
+ t/spdxtool/source-date-epoch.test \
+ t/spdxtool/source-date-epoch-precedence.test \
+ t/spdxtool/special-chars.test \
+ t/spdxtool/unknown-option.test \
+ t/spdxtool/unknown-package.test \
+ t/spdxtool/version.test \
+ t/spdxtool/version-operator.test \
t/spdxtool/with-dependency.test \
t/sbom/license-file-bar.test \
t/sbom/license-file-foo.test \
@@ -281,6 +339,7 @@ EXTRA_DIST = pkg.m4 \
tests/api/test-fragment.c \
tests/api/test-license.c \
tests/api/test-path-utils.c \
+ tests/api/test-serialize.c \
tests/api/test-tuple.c \
tests/api/test-variable.c \
tests/lib-relocatable/lib/pkgconfig/foo.pc \
@@ -411,9 +470,34 @@ EXTRA_DIST = pkg.m4 \
tests/lib-sbom/test4.pc \
tests/lib-sbom/test5.pc \
tests/lib-sbom/test6.pc \
+ tests/lib-sbom/multi-copyright.pc \
+ tests/lib-sbom/nolicense.pc \
+ tests/lib-sbom/special.pc \
+ tests/lib-sbom/variable-test1.pc \
+ tests/lib-sbom/variable-test2.pc \
+ tests/lib-sbom-files/agent_name.json \
+ tests/lib-sbom-files/agent_name_space.json \
tests/lib-sbom-files/basic.json \
+ tests/lib-sbom-files/basic-spdx-base-id.json \
+ tests/lib-sbom-files/basic-use-uri.json \
+ tests/lib-sbom-files/creation_id.json \
+ tests/lib-sbom-files/define_variable.json \
+ tests/lib-sbom-files/define_variable_with_dependency.json \
tests/lib-sbom-files/meta_package.json \
+ tests/lib-sbom-files/meta_package-use-uri-spdx-base-id.json \
+ tests/lib-sbom-files/multi_copyright.json \
+ tests/lib-sbom-files/multiple_packages.json \
+ tests/lib-sbom-files/nolicense.json \
+ tests/lib-sbom-files/special.json \
tests/lib-sbom-files/with_dependency.json \
+ tests/lib-sbom-files/bomtool-basic.txt \
+ tests/lib-sbom-files/bomtool-define_variable.txt \
+ tests/lib-sbom-files/bomtool-define_variable_with_dependency.txt \
+ tests/lib-sbom-files/bomtool-meta_package.txt \
+ tests/lib-sbom-files/bomtool-multiple_packages.txt \
+ tests/lib-sbom-files/bomtool-nolicense.txt \
+ tests/lib-sbom-files/bomtool-special.txt \
+ tests/lib-sbom-files/bomtool-with_dependency.txt \
tests/personality-data/i386-linux-gnu.personality \
doc/conf.py \
doc/extract.py \
@@ -508,6 +592,7 @@ API_TEST_PROGS = \
test-api-fragment \
test-api-license \
test-api-path-utils \
+ test-api-serialize \
test-api-tuple \
test-api-variable
@@ -560,6 +645,16 @@ test_api_path_utils_LDADD = $(api_test_ldadd)
test_api_path_utils_SOURCES = tests/api/test-path-utils.c
test_api_path_utils_CPPFLAGS = $(api_test_cppflags)
+test_api_serialize_LDADD = $(api_test_ldadd)
+test_api_serialize_SOURCES = \
+ tests/api/test-serialize.c \
+ cli/spdxtool/core.c \
+ cli/spdxtool/software.c \
+ cli/spdxtool/serialize.c \
+ cli/spdxtool/simplelicensing.c \
+ cli/spdxtool/util.c
+test_api_serialize_CPPFLAGS = $(api_test_cppflags) -I$(top_srcdir)/cli/spdxtool
+
test_api_tuple_LDADD = $(api_test_ldadd)
test_api_tuple_SOURCES = tests/api/test-tuple.c
test_api_tuple_CPPFLAGS = $(api_test_cppflags)
@@ -585,15 +680,18 @@ check: pkgconf test-runner $(API_TEST_PROGS)
$(builddir)/test-api-fragment$(EXEEXT)
$(builddir)/test-api-license$(EXEEXT)
$(builddir)/test-api-path-utils$(EXEEXT)
+ $(builddir)/test-api-serialize$(EXEEXT)
$(builddir)/test-api-tuple$(EXEEXT)
$(builddir)/test-api-variable$(EXEEXT)
$(builddir)/test-runner$(EXEEXT) --test-fixtures=$(top_srcdir)/tests --tool-dir="$(PWD)" $(top_srcdir)/t/basic
+ $(builddir)/test-runner$(EXEEXT) --test-fixtures=$(top_srcdir)/tests --tool-dir="$(PWD)" $(top_srcdir)/t/cli
$(builddir)/test-runner$(EXEEXT) --test-fixtures=$(top_srcdir)/tests --tool-dir="$(PWD)" $(top_srcdir)/t/link-abi
$(builddir)/test-runner$(EXEEXT) --test-fixtures=$(top_srcdir)/tests --tool-dir="$(PWD)" $(top_srcdir)/t/ordering
$(builddir)/test-runner$(EXEEXT) --test-fixtures=$(top_srcdir)/tests --tool-dir="$(PWD)" $(top_srcdir)/t/parser
$(builddir)/test-runner$(EXEEXT) --test-fixtures=$(top_srcdir)/tests --tool-dir="$(PWD)" $(top_srcdir)/t/personality
$(builddir)/test-runner$(EXEEXT) --test-fixtures=$(top_srcdir)/tests --tool-dir="$(PWD)" $(top_srcdir)/t/solver
$(builddir)/test-runner$(EXEEXT) --test-fixtures=$(top_srcdir)/tests --tool-dir="$(PWD)" $(top_srcdir)/t/sbom
+ $(builddir)/test-runner$(EXEEXT) --test-fixtures=$(top_srcdir)/tests --tool-dir="$(PWD)" $(top_srcdir)/t/bomtool
$(builddir)/test-runner$(EXEEXT) --test-fixtures=$(top_srcdir)/tests --tool-dir="$(PWD)" $(top_srcdir)/t/spdxtool
$(builddir)/test-runner$(EXEEXT) --test-fixtures=$(top_srcdir)/tests --tool-dir="$(PWD)" $(top_srcdir)/t/symlink
$(builddir)/test-runner$(EXEEXT) --test-fixtures=$(top_srcdir)/tests --tool-dir="$(PWD)" $(top_srcdir)/t/sysroot
diff --git a/Makefile.lite b/Makefile.lite
index 88d66d538150..678aa18364ab 100644
--- a/Makefile.lite
+++ b/Makefile.lite
@@ -60,7 +60,7 @@ all: pkgconf-lite
libpkgconf/config.h:
@echo '#define PACKAGE_NAME "pkgconf-lite"' >> $@
@echo '#define PACKAGE_BUGREPORT "https://git.dereferenced.org/pkgconf/pkgconf/issues"' >> $@
- @echo '#define PACKAGE_VERSION "2.5.1"' >> $@
+ @echo '#define PACKAGE_VERSION "2.9.91"' >> $@
@echo '#define PACKAGE PACKAGE_NAME " " PACKAGE_VERSION' >> $@
pkgconf-lite: preflight libpkgconf/config.h ${PKGCONF_OBJS}
diff --git a/NEWS b/NEWS
index a84d0b1dd638..e9f4d61e0efd 100644
--- a/NEWS
+++ b/NEWS
@@ -11,14 +11,26 @@ Changes from 2.5.1 to 3.0.0:
Continuous integration now exercises both the muon and pkgconf-lite builds.
See https://github.com/pkgconf/pkgconf/issues/481 for rationale and discussion.
+* DEPRECATION: Support for setting `PKG_CONFIG_PATH` from the Windows registry
+ is slated for removal in 3.1. It is recommended `PKG_CONFIG_PATH` be set from
+ the environment on Windows.
+ See https://github.com/pkgconf/pkgconf/issues/546 for rationale and discussion.
+
* SPDX Software Bill of Materials (SBOM) generation:
- New spdxtool(1) utility which generates SPDX Lite 3.0.1 SBOM files. Initial
implementation by Tuukka Pasanen, sponsored by The FreeBSD Foundation, and
substantially improved since, with major contributions by Elizabeth Ashford
and additional patches by Joshua Watt and Pierre Pronchery.
- - bomtool and spdxtool now support a --output option, which writes the
- generated SBOM to a file instead of standard output, and --define-variable,
- as the pkgconf CLI does. The --define-variable support is by Tuukka Pasanen.
+ - bomtool now supports a --output option, which writes the generated SBOM to
+ a file instead of standard output, and --define-variable, as the pkgconf CLI
+ does. The --define-variable support is by Tuukka Pasanen.
+ - bomtool now supports a --creation-time option, like spdxtool, which sets the
+ SBOM creation timestamp (in ISO 8601 format) instead of using the current
+ time, and no longer embeds the pkgconf version in its output. Both changes
+ allow for reproducible SBOM generation.
+ - bomtool now honors the SOURCE_DATE_EPOCH environment variable, deriving the
+ SBOM creation timestamp from it when --creation-time is not given, for
+ reproducible builds.
- bomtool: improved SPDX conformance. Mandatory PackageCopyrightText and
PackageLicenseConcluded fields are emitted as NOASSERTION when unavailable,
a Created timestamp is included, invalid PackageVerificationCode output was
@@ -93,6 +105,8 @@ Changes from 2.5.1 to 3.0.0:
- --dump-personality output is now consistent with the
pkgconf-personality(5) format and additionally reports WantDefaultPure and
WantDefaultStatic.
+ - The vestigial --relocate=path option, which existed only for the old test
+ suite, has been removed.
* pkg.m4 changes:
- PKG_WITH_MODULES now properly quotes its action arguments (serial 16).
diff --git a/cli/bomtool/main.c b/cli/bomtool/main.c
index 136d7c1ce2ca..106820a41230 100644
--- a/cli/bomtool/main.c
+++ b/cli/bomtool/main.c
@@ -29,10 +29,12 @@
#define PKG_HELP (((uint64_t) 1) << 3)
#define PKG_OUTPUT (((uint64_t) 1) << 4)
#define PKG_DEFINE_VARIABLE (((uint64_t) 1) << 5)
+#define PKG_CREATION_TIME (((uint64_t) 1) << 6)
static const char *spdx_version = "SPDX-2.2";
static const char *bom_license = "CC0-1.0";
static const char *document_ref = "SPDXRef-DOCUMENT";
+static const char *creation_time = NULL;
static pkgconf_client_t pkg_client;
static uint64_t want_flags;
@@ -148,13 +150,26 @@ write_sbom_header(pkgconf_client_t *client, pkgconf_pkg_t *world)
free(docname);
- OUTPUT_OR_RET_FALSE(client, sbom_out, "DocumentNamespace: https://spdx.org/spdxdocs/bomtool-%s\n", PACKAGE_VERSION);
- OUTPUT_OR_RET_FALSE(client, sbom_out, "Creator: Tool: bomtool %s\n", PACKAGE_VERSION);
+ OUTPUT_OR_RET_FALSE(client, sbom_out, "DocumentNamespace: https://spdx.org/spdxdocs/bomtool\n");
+ OUTPUT_OR_RET_FALSE(client, sbom_out, "Creator: Tool: bomtool\n");
- t = time(NULL);
- tm = gmtime(&t);
- strftime(buf, sizeof(buf), "%Y-%m-%dT%H:%M:%SZ", tm);
- OUTPUT_OR_RET_FALSE(client, sbom_out, "Created: %s\n", buf);
+ if (creation_time != NULL)
+ {
+ OUTPUT_OR_RET_FALSE(client, sbom_out, "Created: %s\n", creation_time);
+ }
+ else
+ {
+ const char *source_date_epoch = getenv("SOURCE_DATE_EPOCH");
+
+ if (source_date_epoch != NULL && *source_date_epoch != '\0')
+ t = (time_t) strtoll(source_date_epoch, NULL, 10);
+ else
+ t = time(NULL);
+
+ tm = gmtime(&t);
+ strftime(buf, sizeof(buf), "%Y-%m-%dT%H:%M:%SZ", tm);
+ OUTPUT_OR_RET_FALSE(client, sbom_out, "Created: %s\n", buf);
+ }
OUTPUT_OR_RET_FALSE(client, sbom_out, "\n\n");
@@ -338,8 +353,7 @@ static int
about(void)
{
printf("bomtool (%s %s)\n", PACKAGE_NAME, PACKAGE_VERSION);
- printf("Copyright (c) 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021\n");
- printf(" pkgconf authors (see AUTHORS in documentation directory).\n\n");
+ printf("Copyright (c) 2011-2026 pkgconf authors (see AUTHORS in documentation directory)\n\n");
printf("Permission to use, copy, modify, and/or distribute this software for any\n");
printf("purpose with or without fee is hereby granted, provided that the above\n");
printf("copyright notice and this permission notice appear in all copies.\n\n");
@@ -362,6 +376,7 @@ usage(void)
printf(" --version print bomtool version to stdout\n");
printf(" --output FILE output SBOM text to FILE\n");
printf(" --define-variable=varname=value define variable 'varname' as 'value'\n");
+ printf(" --creation-time Use string as creation time (Should be in ISO8601 format) [default: current time]\n");
return EXIT_SUCCESS;
}
@@ -388,6 +403,7 @@ main(int argc, char *argv[])
{ "help", no_argument, &want_flags, PKG_HELP, },
{ "output", required_argument, NULL, PKG_OUTPUT, },
{ "define-variable", required_argument, NULL, PKG_DEFINE_VARIABLE, },
+ { "creation-time", required_argument, NULL, PKG_CREATION_TIME, },
{ NULL, 0, NULL, 0 }
};
@@ -407,6 +423,9 @@ main(int argc, char *argv[])
case PKG_DEFINE_VARIABLE:
pkgconf_tuple_define_global(&pkg_client, pkg_optarg);
break;
+ case PKG_CREATION_TIME:
+ creation_time = pkg_optarg;
+ break;
case '?':
case ':':
return EXIT_FAILURE;
diff --git a/cli/main.c b/cli/main.c
index 7959737b9913..060e54983333 100644
--- a/cli/main.c
+++ b/cli/main.c
@@ -54,19 +54,6 @@ unveil_handler(const pkgconf_client_t *client, const char *path, const char *per
}
}
-static void
-relocate_path(const char *path)
-{
- pkgconf_buffer_t pathbuf = PKGCONF_BUFFER_INITIALIZER;
-
- pkgconf_buffer_append(&pathbuf, path);
- pkgconf_path_relocate(&pathbuf);
-
- printf("%s\n", pkgconf_buffer_str(&pathbuf));
-
- pkgconf_buffer_finalize(&pathbuf);
-}
-
#ifndef PKGCONF_LITE
static pkgconf_cross_personality_t *
deduce_personality(char *argv[])
@@ -121,8 +108,7 @@ static void
about(void)
{
printf("%s %s\n", PACKAGE_NAME, PACKAGE_VERSION);
- printf("Copyright (c) 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021\n");
- printf(" pkgconf authors (see AUTHORS in documentation directory).\n\n");
+ printf("Copyright (c) 2011-2026 pkgconf authors (see AUTHORS in documentation directory)\n\n");
printf("Permission to use, copy, modify, and/or distribute this software for any\n");
printf("purpose with or without fee is hereby granted, provided that the above\n");
printf("copyright notice and this permission notice appear in all copies.\n\n");
@@ -163,7 +149,6 @@ usage(void)
printf(" --dont-define-prefix do not override the prefix variable under any circumstances\n");
printf(" --prefix-variable=varname sets the name of the variable that pkgconf considers\n");
printf(" to be the package prefix\n");
- printf(" --relocate=path relocates a path and exits (mostly for testsuite)\n");
printf(" --dont-relocate-paths disables path relocation support\n");
#ifndef PKGCONF_LITE
@@ -332,7 +317,6 @@ main(int argc, char *argv[])
{ "with-path", required_argument, NULL, 42 },
{ "prefix-variable", required_argument, NULL, 43 },
{ "define-prefix", no_argument, &state.want_flags, PKG_DEFINE_PREFIX },
- { "relocate", required_argument, NULL, 45 },
{ "dont-define-prefix", no_argument, &state.want_flags, PKG_DONT_DEFINE_PREFIX },
{ "dont-relocate-paths", no_argument, &state.want_flags, PKG_DONT_RELOCATE_PATHS },
{ "env", required_argument, NULL, 48 },
@@ -401,9 +385,6 @@ main(int argc, char *argv[])
case 43:
pkgconf_client_set_prefix_varname(&state.pkg_client, pkg_optarg);
break;
- case 45:
- relocate_path(pkg_optarg);
- return EXIT_SUCCESS;
case 48:
state.want_env_prefix = pkg_optarg;
break;
diff --git a/cli/spdxtool/util.c b/cli/spdxtool/util.c
index e47bf0a1e61f..fa717aaa6102 100644
--- a/cli/spdxtool/util.c
+++ b/cli/spdxtool/util.c
@@ -163,24 +163,6 @@ spdxtool_util_set_spdx_license(pkgconf_client_t *client, const char *spdx_licens
/*
* !doc
*
- * .. c:function:: const char *spdxtool_util_get_spdx_license(pkgconf_client_t *client)
- *
- * Get license which SBOM is release in
- *
- * :param pkgconf_client_t* client: The pkgconf client being accessed.
- * :return: SPDX license
- */
-const char *
-spdxtool_util_get_spdx_license(pkgconf_client_t *client)
-{
- return pkgconf_tuple_find_global(client, "spdx_license");
-}
-
-static size_t last_id = 0;
-
-/*
- * !doc
- *
* .. c:function:: char *spdxtool_util_get_spdx_id_int(pkgconf_client_t *client, char *part)
*
* Get spdxId with current URI.
@@ -193,6 +175,7 @@ static size_t last_id = 0;
char *
spdxtool_util_get_spdx_id_int(pkgconf_client_t *client, const char *part)
{
+ static size_t last_id = 0;
const char *global_xsd_any_uri = spdxtool_util_get_uri_root(client);
char sep = spdxtool_util_get_uri_separator(client);
pkgconf_buffer_t current_uri = PKGCONF_BUFFER_INITIALIZER;
@@ -260,7 +243,7 @@ spdxtool_util_get_iso8601_time(time_t *wanted_time)
*
* .. c:function:: char *spdxtool_util_get_current_iso8601_time(void)
*
- * Get ISO8601 current timestamp
+ * Get ISO8601 current timestamp, honouring SOURCE_DATE_EPOCH when set
*
* :return: Time string in ISO8601 format
*/
@@ -268,7 +251,13 @@ char *
spdxtool_util_get_current_iso8601_time(void)
{
time_t now;
- time(&now);
+ const char *source_date_epoch = getenv("SOURCE_DATE_EPOCH");
+
+ if (source_date_epoch != NULL && *source_date_epoch != '\0')
+ now = (time_t) strtoll(source_date_epoch, NULL, 10);
+ else
+ time(&now);
+
return spdxtool_util_get_iso8601_time(&now);
}
diff --git a/cli/spdxtool/util.h b/cli/spdxtool/util.h
index be86d6e154d7..e39c173e64c5 100644
--- a/cli/spdxtool/util.h
+++ b/cli/spdxtool/util.h
@@ -102,9 +102,6 @@ spdxtool_util_get_spdx_version(pkgconf_client_t *client);
void
spdxtool_util_set_spdx_license(pkgconf_client_t *client, const char *spdx_license);
-const char *
-spdxtool_util_get_spdx_license(pkgconf_client_t *client);
-
char *
spdxtool_util_get_spdx_id_int(pkgconf_client_t *client, const char *part);
diff --git a/codecov.yml b/codecov.yml
index bfdc9877d9ac..b152448ef21a 100644
--- a/codecov.yml
+++ b/codecov.yml
@@ -6,3 +6,15 @@ coverage:
patch:
default:
informational: true
+parsers:
+ cobertura:
+ partials_as_hits: true
+ignore:
+ # we are not going to write tests for getopt_long().
+ - "cli/getopt_long.c"
+
+ # these are portability stubs and not expected to be notable in coverage testing
+ - "libpkgconf/bsdstubs.c"
+
+ # the test runner itself should not count as part of coverage testing
+ - "tests/test-runner.c"
diff --git a/configure.ac b/configure.ac
index 7f7b813f53b5..af4081147910 100644
--- a/configure.ac
+++ b/configure.ac
@@ -12,7 +12,7 @@ dnl implied. In no event shall the authors be liable for any damages arising
dnl from the use of this software.
AC_PREREQ([2.71])
-AC_INIT([pkgconf],[2.9.90],[https://github.com/pkgconf/pkgconf/issues/new])
+AC_INIT([pkgconf],[2.9.91],[https://github.com/pkgconf/pkgconf/issues/new])
AC_CONFIG_SRCDIR([cli/main.c])
AC_CONFIG_MACRO_DIR([m4])
AX_CHECK_COMPILE_FLAG([-Wall], [CFLAGS="$CFLAGS -Wall"])
diff --git a/libpkgconf/client.c b/libpkgconf/client.c
index be64950a4a92..3e61a0fc1445 100644
--- a/libpkgconf/client.c
+++ b/libpkgconf/client.c
@@ -70,8 +70,12 @@ pkgconf_client_dir_list_build(pkgconf_client_t *client, const pkgconf_cross_pers
const pkgconf_list_t *prepend_list = &personality->dir_list;
#ifdef _WIN32
- (void) pkgconf_path_build_from_registry(HKEY_CURRENT_USER, &client->dir_list, true);
- (void) pkgconf_path_build_from_registry(HKEY_LOCAL_MACHINE, &client->dir_list, true);
+ /*
+ * NOTE: setting the pkgconf path from the registry is deprecated
+ * and will be removed in pkgconf 3.1.
+ */
+ (void) pkgconf_path_build_from_registry(client, HKEY_CURRENT_USER, &client->dir_list, true);
+ (void) pkgconf_path_build_from_registry(client, HKEY_LOCAL_MACHINE, &client->dir_list, true);
#endif
if (pkgconf_client_getenv(client, "PKG_CONFIG_LIBDIR") != NULL)
diff --git a/libpkgconf/libpkgconf.h b/libpkgconf/libpkgconf.h
index fc2c01ac8c0d..205e88e6e8b6 100644
--- a/libpkgconf/libpkgconf.h
+++ b/libpkgconf/libpkgconf.h
@@ -71,8 +71,8 @@ typedef struct pkgconf_license_ pkgconf_license_t;
#define PKGCONF_FOREACH_LIST_ENTRY_REVERSE(tail, value) \
for ((value) = (tail); (value) != NULL; (value) = (value)->prev)
-#define LIBPKGCONF_VERSION 20501
-#define LIBPKGCONF_VERSION_STR "2.5.1"
+#define LIBPKGCONF_VERSION 20991
+#define LIBPKGCONF_VERSION_STR "2.9.91"
struct pkgconf_queue_ {
pkgconf_node_t iter;
@@ -569,7 +569,7 @@ PKGCONF_API void pkgconf_path_prepend(const char *text, pkgconf_list_t *dirlist,
PKGCONF_API size_t pkgconf_path_split(const char *text, pkgconf_list_t *dirlist, bool filter);
PKGCONF_API size_t pkgconf_path_build_from_environ(const pkgconf_client_t *client, const char *envvarname, const char *fallback, pkgconf_list_t *dirlist, bool filter);
#ifdef _WIN32
-PKGCONF_API size_t pkgconf_path_build_from_registry(/* HKEY -> HANDLE -> PVOID */ void *hKey, pkgconf_list_t *dirlist, bool filter);
+PKGCONF_API size_t pkgconf_path_build_from_registry(pkgconf_client_t *client, /* HKEY -> HANDLE -> PVOID */ void *hKey, pkgconf_list_t *dirlist, bool filter);
#endif
PKGCONF_API bool pkgconf_path_match_list(const char *path, const pkgconf_list_t *dirlist);
PKGCONF_API void pkgconf_path_free(pkgconf_list_t *dirlist);
diff --git a/libpkgconf/path.c b/libpkgconf/path.c
index 56d0bb4ddb27..11891c61799f 100644
--- a/libpkgconf/path.c
+++ b/libpkgconf/path.c
@@ -528,6 +528,13 @@ pkgconf_path_find_basename(const char *path)
*
* Adds paths to a directory list discovered from a given registry key.
*
+ * .. warning::
+ * The Windows registry search path mechanism is deprecated and will be
+ * removed in pkgconf 3.1. Use ``PKG_CONFIG_PATH`` or configure search
+ * paths explicitly instead. Avoid using this function directly in new
+ * code.
+ *
+ * :param pkgconf_client_t* client: pkgconf client
* :param HKEY hKey: The registry key to enumerate.
* :param pkgconf_list_t* dir_list: The directory list to append enumerated paths to.
* :param bool filter: Whether duplicate paths should be filtered.
@@ -535,7 +542,7 @@ pkgconf_path_find_basename(const char *path)
* :rtype: size_t
*/
size_t
-pkgconf_path_build_from_registry(void *hKey, pkgconf_list_t *dir_list, bool filter)
+pkgconf_path_build_from_registry(pkgconf_client_t *client, void *hKey, pkgconf_list_t *dir_list, bool filter)
{
HKEY key;
int i = 0;
@@ -547,6 +554,10 @@ pkgconf_path_build_from_registry(void *hKey, pkgconf_list_t *dir_list, bool filt
0, KEY_READ, &key) != ERROR_SUCCESS)
return 0;
+ pkgconf_warn(client,
+ "WARNING: support for reading PKG_CONFIG_PATH from the Windows registry "
+ "is deprecated and will be removed in pkgconf 3.1\n");
+
while (RegEnumValue(key, i++, buf, &bufsize, NULL, NULL, NULL, NULL)
== ERROR_SUCCESS)
{
diff --git a/man/bomtool.1 b/man/bomtool.1
index fe73411a87c0..1585ff17cea4 100644
--- a/man/bomtool.1
+++ b/man/bomtool.1
@@ -7,7 +7,7 @@
.\" 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.
-.Dd June 4, 2025
+.Dd June 24, 2026
.Dt BOMTOOL 1
.Os
.Sh NAME
@@ -45,6 +45,20 @@ as
.Ar value .
Variables are used in query output, and some modules' results may change based
on the presence of a variable definition.
+.It Fl -creation-time Ar time
+Use
+.Ar time
+as the value of the
+.Ic Created
+field in the generated SBOM instead of the current time.
+SPDX recommends using an ISO 8601-formatted time, which is: YYYY-MM-DDThh:mm:ssZ.
+This takes precedence over the
+.Ev SOURCE_DATE_EPOCH
+environment variable.
+.It Fl -output Ar file
+Write the generated SBOM to
+.Ar file
+instead of standard output.
.El
.Sh ENVIRONMENT
.Bl -tag -width indent
@@ -89,6 +103,13 @@ files which are loaded before any other pkg-config files.
These packages are given highest priority over any other
.Xr pc 5
files that would otherwise provide a given package.
+.It Ev SOURCE_DATE_EPOCH
+If set, and the
+.Fl -creation-time
+option is not given, the
+.Ic Created
+field in the generated SBOM is derived from this UNIX timestamp instead of the
+current time, allowing for reproducible SBOM generation.
.El
.Sh EXIT STATUS
.Ex -std
@@ -99,8 +120,8 @@ Generating an SBOM for the package named foo:
.Dl DataLicense: CC0-1.0
.Dl SPDXID: SPDXRef-DOCUMENT
.Dl DocumentName: SBOM-SPDX-fooC641.2.3
-.Dl DocumentNamespace: https://spdx.org/spdxdocs/bomtool-2.4.3
-.Dl Creator: Tool: bomtool 2.4.3
+.Dl DocumentNamespace: https://spdx.org/spdxdocs/bomtool
+.Dl Creator: Tool: bomtool
.Dl [...]
.Sh SEE ALSO
.Xr pc 5 ,
diff --git a/man/pkgconf.1 b/man/pkgconf.1
index 537c5869b972..b1bdbbb5290e 100644
--- a/man/pkgconf.1
+++ b/man/pkgconf.1
@@ -73,7 +73,6 @@ These options are, ordered by descending priority:
.Bl -enum
.It
No-module options:
-.Fl -relocate ,
.Fl -dump-personality ,
.Fl -about ,
.Fl -version ,
@@ -521,10 +520,6 @@ This is mainly intended for use with the
flag and has no effect if
.Fl -shared
is also specified.
-.It Fl -relocate Ns = Ns Ar path
-Relocates a path using the pkgconf_path_relocate API.
-This is mainly used by the testsuite to provide a guaranteed interface
-to the system's path relocation backend.
.It Fl -shared
Compute a simple dependency graph that is only suitable for shared linking.
This option overrides
diff --git a/man/spdxtool.1 b/man/spdxtool.1
index bc078f2d8748..2bc7dfb165a3 100644
--- a/man/spdxtool.1
+++ b/man/spdxtool.1
@@ -48,6 +48,9 @@ in /Core/Agent-class. Default is 'Default'
Set create-property time in /Core/CreationInfo-class.
SPDX documentation recomends using ISO 8601-formated time which is: YYYY-MM-DDThh:mm:ssZ.
Default is document creation time.
+This takes precedence over the
+.Ev SOURCE_DATE_EPOCH
+environment variable.
.It Fl -creation-id
Set creation ID in /Core/CreationInfoc-class.
As ID in creation info mainly have special format and it's
@@ -103,6 +106,12 @@ files which are loaded before any other pkg-config files.
These packages are given highest priority over any other
.Xr pc 5
files that would otherwise provide a given package.
+.It Ev SOURCE_DATE_EPOCH
+If set, and the
+.Fl -creation-time
+option is not given, the creation time in /Core/CreationInfo-class is derived
+from this UNIX timestamp instead of the current time, allowing for reproducible
+SBOM generation.
.El
.Sh EXIT STATUS
.Ex -std
diff --git a/meson.build b/meson.build
index 4e89dccf9ac5..6eb7304c5d5e 100644
--- a/meson.build
+++ b/meson.build
@@ -1,5 +1,5 @@
project('pkgconf', 'c',
- version : '2.9.90',
+ version : '2.9.91',
license : 'ISC',
default_options : [
'c_std=c99',
@@ -296,11 +296,28 @@ foreach t : api_tests
test('api-' + t, exe)
endforeach
+# Unit test for spdxtool's JSON serializer. Unlike the api_tests above it must
+# also compile the spdxtool sources it exercises (everything but main.c).
+test_api_serialize_exe = executable('test-api-serialize',
+ 'tests/api/test-serialize.c',
+ 'cli/spdxtool/core.c',
+ 'cli/spdxtool/software.c',
+ 'cli/spdxtool/serialize.c',
+ 'cli/spdxtool/simplelicensing.c',
+ 'cli/spdxtool/util.c',
+ windows_manifest,
+ link_with : libpkgconf,
+ c_args : build_static,
+ include_directories : [include_directories('.'), include_directories('tests/api'), include_directories('cli/spdxtool')],
+ install : false)
+test('api-serialize', test_api_serialize_exe)
+
fixtures_dir = join_paths(meson.current_source_dir(), 'tests')
tool_dir = meson.current_build_dir()
test_suites = [
'basic',
+ 'cli',
'link-abi',
'ordering',
'parser',
@@ -309,6 +326,7 @@ test_suites = [
'sbom',
'sysroot',
'tuple',
+ 'bomtool',
'spdxtool',
'symlink'
]
@@ -316,7 +334,7 @@ test_suites = [
foreach t : test_suites
test(t, test_runner_exe,
args : ['--test-fixtures', fixtures_dir, '--tool-dir', tool_dir, join_paths(meson.current_source_dir(), 't', t)],
- depends : [spdxtool_exe])
+ depends : [pkgconf_exe, spdxtool_exe, bomtool_exe])
endforeach
install_man('man/bomtool.1')
diff --git a/t/bomtool/about.test b/t/bomtool/about.test
new file mode 100644
index 000000000000..2ff369fd397a
--- /dev/null
+++ b/t/bomtool/about.test
@@ -0,0 +1,5 @@
+Tool: bomtool
+ToolArgs: --about
+ExpectedStdout: bomtool (pkgconf
+MatchStdout: Partial
+ExpectedExitCode: 0
diff --git a/t/bomtool/bad-output.test b/t/bomtool/bad-output.test
new file mode 100644
index 000000000000..b04fee76a3c0
--- /dev/null
+++ b/t/bomtool/bad-output.test
@@ -0,0 +1,4 @@
+Tool: bomtool
+ToolArgs: --output /nonexistent-dir/out.txt test3
+Environment: PKG_CONFIG_PATH=%TEST_FIXTURES_DIR%/lib-sbom
+ExpectedExitCode: 1
diff --git a/t/bomtool/basic.test b/t/bomtool/basic.test
new file mode 100644
index 000000000000..f5e6a233974d
--- /dev/null
+++ b/t/bomtool/basic.test
@@ -0,0 +1,5 @@
+Tool: bomtool
+ToolArgs: --creation-time=test test3
+Environment: PKG_CONFIG_PATH=%TEST_FIXTURES_DIR%/lib-sbom
+ExpectedStdoutFile: ../../tests/lib-sbom-files/bomtool-basic.txt
+ExpectedExitCode: 0
diff --git a/t/bomtool/default-time.test b/t/bomtool/default-time.test
new file mode 100644
index 000000000000..8943add707ed
--- /dev/null
+++ b/t/bomtool/default-time.test
@@ -0,0 +1,6 @@
+Tool: bomtool
+ToolArgs: test3
+Environment: PKG_CONFIG_PATH=%TEST_FIXTURES_DIR%/lib-sbom
+ExpectedStdout: PackageName: test3@3.0.0
+MatchStdout: Partial
+ExpectedExitCode: 0
diff --git a/t/bomtool/define-variable-with-dependency.test b/t/bomtool/define-variable-with-dependency.test
new file mode 100644
index 000000000000..7a63ea926dc6
--- /dev/null
+++ b/t/bomtool/define-variable-with-dependency.test
@@ -0,0 +1,5 @@
+Tool: bomtool
+ToolArgs: --creation-time=test --define-variable=VERSION_VARIABLE_TEST=1.0-123 --define-variable=license_variable_test=MIT variable-test2
+Environment: PKG_CONFIG_PATH=%TEST_FIXTURES_DIR%/lib-sbom
+ExpectedStdoutFile: ../../tests/lib-sbom-files/bomtool-define_variable_with_dependency.txt
+ExpectedExitCode: 0
diff --git a/t/bomtool/define-variable.test b/t/bomtool/define-variable.test
new file mode 100644
index 000000000000..9746de4c958c
--- /dev/null
+++ b/t/bomtool/define-variable.test
@@ -0,0 +1,5 @@
+Tool: bomtool
+ToolArgs: --creation-time=test --define-variable=VERSION_VARIABLE_TEST=1.0-123 variable-test1
+Environment: PKG_CONFIG_PATH=%TEST_FIXTURES_DIR%/lib-sbom
+ExpectedStdoutFile: ../../tests/lib-sbom-files/bomtool-define_variable.txt
+ExpectedExitCode: 0
diff --git a/t/bomtool/help.test b/t/bomtool/help.test
new file mode 100644
index 000000000000..ac7416a29a37
--- /dev/null
+++ b/t/bomtool/help.test
@@ -0,0 +1,5 @@
+Tool: bomtool
+ToolArgs: --help
+ExpectedStdout: usage: bomtool
+MatchStdout: Partial
+ExpectedExitCode: 0
diff --git a/t/bomtool/meta-package.test b/t/bomtool/meta-package.test
new file mode 100644
index 000000000000..77c2b5a920f2
--- /dev/null
+++ b/t/bomtool/meta-package.test
@@ -0,0 +1,5 @@
+Tool: bomtool
+ToolArgs: --creation-time=test meta_package
+Environment: PKG_CONFIG_PATH=%TEST_FIXTURES_DIR%/lib-sbom
+ExpectedStdoutFile: ../../tests/lib-sbom-files/bomtool-meta_package.txt
+ExpectedExitCode: 0
diff --git a/t/bomtool/multiple-packages.test b/t/bomtool/multiple-packages.test
new file mode 100644
index 000000000000..a041e10d672d
--- /dev/null
+++ b/t/bomtool/multiple-packages.test
@@ -0,0 +1,5 @@
+Tool: bomtool
+ToolArgs: --creation-time=test test5 test6
+Environment: PKG_CONFIG_PATH=%TEST_FIXTURES_DIR%/lib-sbom
+ExpectedStdoutFile: ../../tests/lib-sbom-files/bomtool-multiple_packages.txt
+ExpectedExitCode: 0
diff --git a/t/bomtool/no-license.test b/t/bomtool/no-license.test
new file mode 100644
index 000000000000..1e4f95b6a9d6
--- /dev/null
+++ b/t/bomtool/no-license.test
@@ -0,0 +1,5 @@
+Tool: bomtool
+ToolArgs: --creation-time=test nolicense
+Environment: PKG_CONFIG_PATH=%TEST_FIXTURES_DIR%/lib-sbom
+ExpectedStdoutFile: ../../tests/lib-sbom-files/bomtool-nolicense.txt
+ExpectedExitCode: 0
diff --git a/t/bomtool/output-file.test b/t/bomtool/output-file.test
new file mode 100644
index 000000000000..75b92b0c09c0
--- /dev/null
+++ b/t/bomtool/output-file.test
@@ -0,0 +1,5 @@
+Tool: bomtool
+ToolArgs: --creation-time=test --output /dev/null test3
+Environment: PKG_CONFIG_PATH=%TEST_FIXTURES_DIR%/lib-sbom
+ExpectedExitCode: 0
+SkipPlatforms: windows
diff --git a/t/bomtool/package-whitespace.test b/t/bomtool/package-whitespace.test
new file mode 100644
index 000000000000..4fd3229f49bb
--- /dev/null
+++ b/t/bomtool/package-whitespace.test
@@ -0,0 +1,6 @@
+Tool: bomtool
+ToolArgs: --creation-time=test ' ' test3
+Environment: PKG_CONFIG_PATH=%TEST_FIXTURES_DIR%/lib-sbom
+ExpectedStdoutFile: ../../tests/lib-sbom-files/bomtool-basic.txt
+ExpectedExitCode: 0
+SkipPlatforms: windows
diff --git a/t/bomtool/source-date-epoch-precedence.test b/t/bomtool/source-date-epoch-precedence.test
new file mode 100644
index 000000000000..3b86fb348c83
--- /dev/null
+++ b/t/bomtool/source-date-epoch-precedence.test
@@ -0,0 +1,6 @@
+Tool: bomtool
+ToolArgs: --creation-time=test test3
+Environment: PKG_CONFIG_PATH=%TEST_FIXTURES_DIR%/lib-sbom
+Environment: SOURCE_DATE_EPOCH=1234567890
+ExpectedStdoutFile: ../../tests/lib-sbom-files/bomtool-basic.txt
+ExpectedExitCode: 0
diff --git a/t/bomtool/source-date-epoch.test b/t/bomtool/source-date-epoch.test
new file mode 100644
index 000000000000..c94394c54d91
--- /dev/null
+++ b/t/bomtool/source-date-epoch.test
@@ -0,0 +1,7 @@
+Tool: bomtool
+ToolArgs: test3
+Environment: PKG_CONFIG_PATH=%TEST_FIXTURES_DIR%/lib-sbom
+Environment: SOURCE_DATE_EPOCH=1234567890
+ExpectedStdout: Created: 2009-02-13T23:31:30Z
+MatchStdout: Partial
+ExpectedExitCode: 0
diff --git a/t/bomtool/special-chars.test b/t/bomtool/special-chars.test
new file mode 100644
index 000000000000..cb2b2024e776
--- /dev/null
+++ b/t/bomtool/special-chars.test
@@ -0,0 +1,5 @@
+Tool: bomtool
+ToolArgs: --creation-time=test special
+Environment: PKG_CONFIG_PATH=%TEST_FIXTURES_DIR%/lib-sbom
+ExpectedStdoutFile: ../../tests/lib-sbom-files/bomtool-special.txt
+ExpectedExitCode: 0
diff --git a/t/bomtool/unknown-option.test b/t/bomtool/unknown-option.test
new file mode 100644
index 000000000000..dc577f8caad1
--- /dev/null
+++ b/t/bomtool/unknown-option.test
@@ -0,0 +1,3 @@
+Tool: bomtool
+ToolArgs: --bogus-option
+ExpectedExitCode: 1
diff --git a/t/bomtool/unknown-package.test b/t/bomtool/unknown-package.test
new file mode 100644
index 000000000000..d5f14c3a1218
--- /dev/null
+++ b/t/bomtool/unknown-package.test
@@ -0,0 +1,4 @@
+Tool: bomtool
+ToolArgs: --creation-time=test no-such-pkg
+Environment: PKG_CONFIG_PATH=%TEST_FIXTURES_DIR%/lib-sbom
+ExpectedExitCode: 1
diff --git a/t/bomtool/version-operator.test b/t/bomtool/version-operator.test
new file mode 100644
index 000000000000..b788c400c1af
--- /dev/null
+++ b/t/bomtool/version-operator.test
@@ -0,0 +1,6 @@
+Tool: bomtool
+ToolArgs: --creation-time=test test3 '>=' 3.0.0
+Environment: PKG_CONFIG_PATH=%TEST_FIXTURES_DIR%/lib-sbom
+ExpectedStdoutFile: ../../tests/lib-sbom-files/bomtool-basic.txt
+ExpectedExitCode: 0
+SkipPlatforms: windows
diff --git a/t/bomtool/version.test b/t/bomtool/version.test
new file mode 100644
index 000000000000..996aa08c5bab
--- /dev/null
+++ b/t/bomtool/version.test
@@ -0,0 +1,5 @@
+Tool: bomtool
+ToolArgs: --version
+ExpectedStdout: bomtool
+MatchStdout: Partial
+ExpectedExitCode: 0
diff --git a/t/bomtool/with-dependency.test b/t/bomtool/with-dependency.test
new file mode 100644
index 000000000000..01be01845ba0
--- /dev/null
+++ b/t/bomtool/with-dependency.test
@@ -0,0 +1,5 @@
+Tool: bomtool
+ToolArgs: --creation-time=test test2
+Environment: PKG_CONFIG_PATH=%TEST_FIXTURES_DIR%/lib-sbom
+ExpectedStdoutFile: ../../tests/lib-sbom-files/bomtool-with_dependency.txt
+ExpectedExitCode: 0
diff --git a/t/cli/about.test b/t/cli/about.test
new file mode 100644
index 000000000000..20525dfceec9
--- /dev/null
+++ b/t/cli/about.test
@@ -0,0 +1,5 @@
+Tool: pkgconf
+ToolArgs: --about
+ExpectedStdout: Permission to use, copy, modify
+MatchStdout: Partial
+ExpectedExitCode: 0
diff --git a/t/cli/atleast-pkgconfig-version-fail.test b/t/cli/atleast-pkgconfig-version-fail.test
new file mode 100644
index 000000000000..a13d234eae6d
--- /dev/null
+++ b/t/cli/atleast-pkgconfig-version-fail.test
@@ -0,0 +1,3 @@
+Tool: pkgconf
+ToolArgs: --atleast-pkgconfig-version=99999
+ExpectedExitCode: 1
diff --git a/t/cli/atleast-pkgconfig-version-pass.test b/t/cli/atleast-pkgconfig-version-pass.test
new file mode 100644
index 000000000000..3ae8d391c681
--- /dev/null
+++ b/t/cli/atleast-pkgconfig-version-pass.test
@@ -0,0 +1,3 @@
+Tool: pkgconf
+ToolArgs: --atleast-pkgconfig-version=0.1
+ExpectedExitCode: 0
diff --git a/t/cli/cflags-libs.test b/t/cli/cflags-libs.test
new file mode 100644
index 000000000000..394f8b3bbe5d
--- /dev/null
+++ b/t/cli/cflags-libs.test
@@ -0,0 +1,5 @@
+Tool: pkgconf
+ToolArgs: --cflags --libs foo
+Environment: PKG_CONFIG_PATH=%TEST_FIXTURES_DIR%/lib1
+ExpectedStdout: -fPIC -I/test/include/foo -L/test/lib -lfoo
+ExpectedExitCode: 0
diff --git a/t/cli/dump-personality.test b/t/cli/dump-personality.test
new file mode 100644
index 000000000000..84a9fc40f791
--- /dev/null
+++ b/t/cli/dump-personality.test
@@ -0,0 +1,5 @@
+Tool: pkgconf
+ToolArgs: --dump-personality
+ExpectedStdout: Triplet: default
+MatchStdout: Partial
+ExpectedExitCode: 0
diff --git a/t/cli/exists-missing.test b/t/cli/exists-missing.test
new file mode 100644
index 000000000000..d5654a712481
--- /dev/null
+++ b/t/cli/exists-missing.test
@@ -0,0 +1,4 @@
+Tool: pkgconf
+ToolArgs: --exists boguspkg
+Environment: PKG_CONFIG_PATH=%TEST_FIXTURES_DIR%/lib1
+ExpectedExitCode: 1
diff --git a/t/cli/exists-valid.test b/t/cli/exists-valid.test
new file mode 100644
index 000000000000..4c9900207b89
--- /dev/null
+++ b/t/cli/exists-valid.test
@@ -0,0 +1,4 @@
+Tool: pkgconf
+ToolArgs: --exists foo
+Environment: PKG_CONFIG_PATH=%TEST_FIXTURES_DIR%/lib1
+ExpectedExitCode: 0
diff --git a/t/cli/help.test b/t/cli/help.test
new file mode 100644
index 000000000000..33d78df7bf12
--- /dev/null
+++ b/t/cli/help.test
@@ -0,0 +1,5 @@
+Tool: pkgconf
+ToolArgs: --help
+ExpectedStdout: usage: pkgconf
+MatchStdout: Partial
+ExpectedExitCode: 0
diff --git a/t/cli/missing-package-error.test b/t/cli/missing-package-error.test
new file mode 100644
index 000000000000..3edfa8a6c0f8
--- /dev/null
+++ b/t/cli/missing-package-error.test
@@ -0,0 +1,6 @@
+Tool: pkgconf
+ToolArgs: --errors-to-stdout --cflags boguspkg
+Environment: PKG_CONFIG_PATH=%TEST_FIXTURES_DIR%/lib1
+ExpectedStdout: Package boguspkg was not found in the pkg-config search path.
+MatchStdout: Partial
+ExpectedExitCode: 1
diff --git a/t/cli/missing-package.test b/t/cli/missing-package.test
new file mode 100644
index 000000000000..4e49d57dcf9c
--- /dev/null
+++ b/t/cli/missing-package.test
@@ -0,0 +1,4 @@
+Tool: pkgconf
+ToolArgs: --cflags boguspkg
+Environment: PKG_CONFIG_PATH=%TEST_FIXTURES_DIR%/lib1
+ExpectedExitCode: 1
diff --git a/t/cli/modversion.test b/t/cli/modversion.test
new file mode 100644
index 000000000000..c0343dab916a
--- /dev/null
+++ b/t/cli/modversion.test
@@ -0,0 +1,5 @@
+Tool: pkgconf
+ToolArgs: --modversion foo
+Environment: PKG_CONFIG_PATH=%TEST_FIXTURES_DIR%/lib1
+ExpectedStdout: 1.2.3
+ExpectedExitCode: 0
diff --git a/t/cli/no-arguments.test b/t/cli/no-arguments.test
new file mode 100644
index 000000000000..60395697aa0a
--- /dev/null
+++ b/t/cli/no-arguments.test
@@ -0,0 +1,2 @@
+Tool: pkgconf
+ExpectedExitCode: 1
diff --git a/t/cli/unknown-option.test b/t/cli/unknown-option.test
new file mode 100644
index 000000000000..f710eba4d53f
--- /dev/null
+++ b/t/cli/unknown-option.test
@@ -0,0 +1,3 @@
+Tool: pkgconf
+ToolArgs: --bogus-flag
+ExpectedExitCode: 1
diff --git a/t/cli/version.test b/t/cli/version.test
new file mode 100644
index 000000000000..3b96b091c5a8
--- /dev/null
+++ b/t/cli/version.test
@@ -0,0 +1,3 @@
+Tool: pkgconf
+ToolArgs: --version
+ExpectedExitCode: 0
diff --git a/t/spdxtool/about.test b/t/spdxtool/about.test
new file mode 100644
index 000000000000..cdee7adddf4d
--- /dev/null
+++ b/t/spdxtool/about.test
@@ -0,0 +1,5 @@
+Tool: spdxtool
+ToolArgs: --about
+ExpectedStdout: SPDX-License-Identifier: BSD-2-Clause
+MatchStdout: Partial
+ExpectedExitCode: 0
diff --git a/t/spdxtool/agent-name-space.test b/t/spdxtool/agent-name-space.test
new file mode 100644
index 000000000000..60e00bbee9d8
--- /dev/null
+++ b/t/spdxtool/agent-name-space.test
@@ -0,0 +1,6 @@
+Tool: spdxtool
+ToolArgs: --creation-time=test --agent-name='My Agent' test3
+Environment: PKG_CONFIG_PATH=%TEST_FIXTURES_DIR%/lib-sbom
+ExpectedStdoutFile: ../../tests/lib-sbom-files/agent_name_space.json
+ExpectedExitCode: 0
+SkipPlatforms: windows
diff --git a/t/spdxtool/agent-name.test b/t/spdxtool/agent-name.test
new file mode 100644
index 000000000000..e097bde6e9fb
--- /dev/null
+++ b/t/spdxtool/agent-name.test
@@ -0,0 +1,5 @@
+Tool: spdxtool
+ToolArgs: --creation-time=test --agent-name=MyAgent test3
+Environment: PKG_CONFIG_PATH=%TEST_FIXTURES_DIR%/lib-sbom
+ExpectedStdoutFile: ../../tests/lib-sbom-files/agent_name.json
+ExpectedExitCode: 0
diff --git a/t/spdxtool/bad-output.test b/t/spdxtool/bad-output.test
new file mode 100644
index 000000000000..276497d79458
--- /dev/null
+++ b/t/spdxtool/bad-output.test
@@ -0,0 +1,4 @@
+Tool: spdxtool
+ToolArgs: --output /nonexistent-dir/out.json test3
+Environment: PKG_CONFIG_PATH=%TEST_FIXTURES_DIR%/lib-sbom
+ExpectedExitCode: 1
diff --git a/t/spdxtool/creation-id.test b/t/spdxtool/creation-id.test
new file mode 100644
index 000000000000..a62f09dc0ebb
--- /dev/null
+++ b/t/spdxtool/creation-id.test
@@ -0,0 +1,5 @@
+Tool: spdxtool
+ToolArgs: --creation-time=test --creation-id=_:custom_1 test3
+Environment: PKG_CONFIG_PATH=%TEST_FIXTURES_DIR%/lib-sbom
+ExpectedStdoutFile: ../../tests/lib-sbom-files/creation_id.json
+ExpectedExitCode: 0
diff --git a/t/spdxtool/default-time.test b/t/spdxtool/default-time.test
new file mode 100644
index 000000000000..894f760d944b
--- /dev/null
+++ b/t/spdxtool/default-time.test
@@ -0,0 +1,6 @@
+Tool: spdxtool
+ToolArgs: test3
+Environment: PKG_CONFIG_PATH=%TEST_FIXTURES_DIR%/lib-sbom
+ExpectedStdout: "type": "software_Package"
+MatchStdout: Partial
+ExpectedExitCode: 0
diff --git a/t/spdxtool/define-variable-with-depencency.test b/t/spdxtool/define-variable-with-dependency.test
index f88a90bb8bc1..f88a90bb8bc1 100644
--- a/t/spdxtool/define-variable-with-depencency.test
+++ b/t/spdxtool/define-variable-with-dependency.test
diff --git a/t/spdxtool/help.test b/t/spdxtool/help.test
new file mode 100644
index 000000000000..2e41150dd213
--- /dev/null
+++ b/t/spdxtool/help.test
@@ -0,0 +1,5 @@
+Tool: spdxtool
+ToolArgs: --help
+ExpectedStdout: usage: spdxtool
+MatchStdout: Partial
+ExpectedExitCode: 0
diff --git a/t/spdxtool/multi-copyright.test b/t/spdxtool/multi-copyright.test
new file mode 100644
index 000000000000..80e413f8432a
--- /dev/null
+++ b/t/spdxtool/multi-copyright.test
@@ -0,0 +1,5 @@
+Tool: spdxtool
+ToolArgs: --creation-time=test multi-copyright
+Environment: PKG_CONFIG_PATH=%TEST_FIXTURES_DIR%/lib-sbom
+ExpectedStdoutFile: ../../tests/lib-sbom-files/multi_copyright.json
+ExpectedExitCode: 0
diff --git a/t/spdxtool/multiple-packages.test b/t/spdxtool/multiple-packages.test
new file mode 100644
index 000000000000..77b0a5a2840a
--- /dev/null
+++ b/t/spdxtool/multiple-packages.test
@@ -0,0 +1,5 @@
+Tool: spdxtool
+ToolArgs: --creation-time=test test5 test6
+Environment: PKG_CONFIG_PATH=%TEST_FIXTURES_DIR%/lib-sbom
+ExpectedStdoutFile: ../../tests/lib-sbom-files/multiple_packages.json
+ExpectedExitCode: 0
diff --git a/t/spdxtool/no-license.test b/t/spdxtool/no-license.test
new file mode 100644
index 000000000000..b107928a6082
--- /dev/null
+++ b/t/spdxtool/no-license.test
@@ -0,0 +1,5 @@
+Tool: spdxtool
+ToolArgs: --creation-time=test nolicense
+Environment: PKG_CONFIG_PATH=%TEST_FIXTURES_DIR%/lib-sbom
+ExpectedStdoutFile: ../../tests/lib-sbom-files/nolicense.json
+ExpectedExitCode: 0
diff --git a/t/spdxtool/output-file.test b/t/spdxtool/output-file.test
new file mode 100644
index 000000000000..26527a12662c
--- /dev/null
+++ b/t/spdxtool/output-file.test
@@ -0,0 +1,5 @@
+Tool: spdxtool
+ToolArgs: --creation-time=test --output /dev/null test3
+Environment: PKG_CONFIG_PATH=%TEST_FIXTURES_DIR%/lib-sbom
+ExpectedExitCode: 0
+SkipPlatforms: windows
diff --git a/t/spdxtool/package-whitespace.test b/t/spdxtool/package-whitespace.test
new file mode 100644
index 000000000000..23b41e35012e
--- /dev/null
+++ b/t/spdxtool/package-whitespace.test
@@ -0,0 +1,6 @@
+Tool: spdxtool
+ToolArgs: --creation-time=test ' ' test3
+Environment: PKG_CONFIG_PATH=%TEST_FIXTURES_DIR%/lib-sbom
+ExpectedStdoutFile: ../../tests/lib-sbom-files/basic.json
+ExpectedExitCode: 0
+SkipPlatforms: windows
diff --git a/t/spdxtool/source-date-epoch-precedence.test b/t/spdxtool/source-date-epoch-precedence.test
new file mode 100644
index 000000000000..d879881fca6e
--- /dev/null
+++ b/t/spdxtool/source-date-epoch-precedence.test
@@ -0,0 +1,6 @@
+Tool: spdxtool
+ToolArgs: --creation-time=test --creation-id=_:custom_1 test3
+Environment: PKG_CONFIG_PATH=%TEST_FIXTURES_DIR%/lib-sbom
+Environment: SOURCE_DATE_EPOCH=1234567890
+ExpectedStdoutFile: ../../tests/lib-sbom-files/creation_id.json
+ExpectedExitCode: 0
diff --git a/t/spdxtool/source-date-epoch.test b/t/spdxtool/source-date-epoch.test
new file mode 100644
index 000000000000..cdf5996c2c45
--- /dev/null
+++ b/t/spdxtool/source-date-epoch.test
@@ -0,0 +1,7 @@
+Tool: spdxtool
+ToolArgs: test3
+Environment: PKG_CONFIG_PATH=%TEST_FIXTURES_DIR%/lib-sbom
+Environment: SOURCE_DATE_EPOCH=1234567890
+ExpectedStdout: "created": "2009-02-13T23:31:30Z"
+MatchStdout: Partial
+ExpectedExitCode: 0
diff --git a/t/spdxtool/special-chars.test b/t/spdxtool/special-chars.test
new file mode 100644
index 000000000000..99038e4d84b0
--- /dev/null
+++ b/t/spdxtool/special-chars.test
@@ -0,0 +1,5 @@
+Tool: spdxtool
+ToolArgs: --creation-time=test special
+Environment: PKG_CONFIG_PATH=%TEST_FIXTURES_DIR%/lib-sbom
+ExpectedStdoutFile: ../../tests/lib-sbom-files/special.json
+ExpectedExitCode: 0
diff --git a/t/spdxtool/unknown-option.test b/t/spdxtool/unknown-option.test
new file mode 100644
index 000000000000..261e42cee319
--- /dev/null
+++ b/t/spdxtool/unknown-option.test
@@ -0,0 +1,3 @@
+Tool: spdxtool
+ToolArgs: --bogus-option
+ExpectedExitCode: 1
diff --git a/t/spdxtool/unknown-package.test b/t/spdxtool/unknown-package.test
new file mode 100644
index 000000000000..97e1101e7790
--- /dev/null
+++ b/t/spdxtool/unknown-package.test
@@ -0,0 +1,4 @@
+Tool: spdxtool
+ToolArgs: --creation-time=test no-such-pkg
+Environment: PKG_CONFIG_PATH=%TEST_FIXTURES_DIR%/lib-sbom
+ExpectedExitCode: 1
diff --git a/t/spdxtool/version-operator.test b/t/spdxtool/version-operator.test
new file mode 100644
index 000000000000..62b50ce6b2c8
--- /dev/null
+++ b/t/spdxtool/version-operator.test
@@ -0,0 +1,6 @@
+Tool: spdxtool
+ToolArgs: --creation-time=test test3 '>=' 3.0.0
+Environment: PKG_CONFIG_PATH=%TEST_FIXTURES_DIR%/lib-sbom
+ExpectedStdoutFile: ../../tests/lib-sbom-files/basic.json
+ExpectedExitCode: 0
+SkipPlatforms: windows
diff --git a/t/spdxtool/version.test b/t/spdxtool/version.test
new file mode 100644
index 000000000000..6437c572dfb7
--- /dev/null
+++ b/t/spdxtool/version.test
@@ -0,0 +1,5 @@
+Tool: spdxtool
+ToolArgs: --version
+ExpectedStdout: spdxtool
+MatchStdout: Partial
+ExpectedExitCode: 0
diff --git a/tests/api/test-fileio.c b/tests/api/test-fileio.c
index a4d5f81679a6..f0f48ff41fed 100644
--- a/tests/api/test-fileio.c
+++ b/tests/api/test-fileio.c
@@ -196,7 +196,7 @@ test_fgetline_crlf_split_across_fgets_buffer(void)
TEST_ASSERT_NONNULL(content);
memset(content, 'a', prefix_len);
- strcpy(content + prefix_len, "\r\nworld\n");
+ memcpy(content + prefix_len, "\r\nworld\n", strlen("\r\nworld\n") + 1);
f = fmemstream(content);
free(content);
diff --git a/tests/api/test-serialize.c b/tests/api/test-serialize.c
new file mode 100644
index 000000000000..ef7bff0fcf95
--- /dev/null
+++ b/tests/api/test-serialize.c
@@ -0,0 +1,203 @@
+/*
+ * test-serialize.c
+ * Tests for spdxtool's JSON serialization value model.
+ *
+ * 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 <libpkgconf/stdinc.h>
+#include <libpkgconf/libpkgconf.h>
+#include "test-api.h"
+#include "serialize.h"
+
+// Render a value to a freshly-allocated C string (caller frees)
+static char *
+render(spdxtool_serialize_value_t *value)
+{
+ pkgconf_buffer_t buf = PKGCONF_BUFFER_INITIALIZER;
+ TEST_ASSERT_TRUE(spdxtool_serialize_value_to_buf(&buf, value, 0));
+ char *s = strdup(pkgconf_buffer_str_or_empty(&buf));
+ pkgconf_buffer_finalize(&buf);
+ return s;
+}
+
+// Render a container without taking ownership of it
+static char *
+render_object(spdxtool_serialize_object_list_t *o)
+{
+ spdxtool_serialize_value_t wrap = { .type = SPDXTOOL_SERIALIZE_TYPE_OBJECT, .value = { .o = o } };
+ return render(&wrap);
+}
+
+static char *
+render_array(spdxtool_serialize_array_t *a)
+{
+ spdxtool_serialize_value_t wrap = { .type = SPDXTOOL_SERIALIZE_TYPE_ARRAY, .value = { .a = a } };
+ return render(&wrap);
+}
+
+// Scalar value types: string / int / bool / null
+static void
+test_serialize_value_string(void)
+{
+ spdxtool_serialize_value_t *v = spdxtool_serialize_value_string("hi");
+ TEST_ASSERT_NONNULL(v);
+ char *s = render(v);
+ TEST_ASSERT_STRCMP_EQ(s, "\"hi\"");
+ free(s);
+ spdxtool_serialize_value_free(v);
+}
+
+static void
+test_serialize_value_int(void)
+{
+ spdxtool_serialize_value_t *v = spdxtool_serialize_value_int(123);
+ TEST_ASSERT_NONNULL(v);
+ char *s = render(v);
+ TEST_ASSERT_STRCMP_EQ(s, "123");
+ free(s);
+ spdxtool_serialize_value_free(v);
+}
+
+static void
+test_serialize_value_bool(void)
+{
+ spdxtool_serialize_value_t *t = spdxtool_serialize_value_bool(true);
+ spdxtool_serialize_value_t *f = spdxtool_serialize_value_bool(false);
+ char *st = render(t);
+ char *sf = render(f);
+ TEST_ASSERT_STRCMP_EQ(st, "true");
+ TEST_ASSERT_STRCMP_EQ(sf, "false");
+ free(st);
+ free(sf);
+ spdxtool_serialize_value_free(t);
+ spdxtool_serialize_value_free(f);
+}
+
+static void
+test_serialize_value_null(void)
+{
+ spdxtool_serialize_value_t *v = spdxtool_serialize_value_null();
+ TEST_ASSERT_NONNULL(v);
+ char *s = render(v);
+ TEST_ASSERT_STRCMP_EQ(s, "null");
+ free(s);
+ spdxtool_serialize_value_free(v);
+}
+
+// All JSON string escape sequences, including control characters
+static void
+test_serialize_escape_sequences(void)
+{
+ spdxtool_serialize_value_t *v = spdxtool_serialize_value_string("\"\\\b\f\n\r\t\x01" "Z");
+ char *s = render(v);
+
+ TEST_ASSERT_STRSTR(s, "\\\""); // quote
+ TEST_ASSERT_STRSTR(s, "\\\\"); // backslash
+ TEST_ASSERT_STRSTR(s, "\\b"); // backspace
+ TEST_ASSERT_STRSTR(s, "\\f"); // form feed
+ TEST_ASSERT_STRSTR(s, "\\n"); // newline
+ TEST_ASSERT_STRSTR(s, "\\r"); // carriage return
+ TEST_ASSERT_STRSTR(s, "\\t"); // tab
+ TEST_ASSERT_STRSTR(s, "\\u0001"); // other ctrl
+ TEST_ASSERT_STRSTR(s, "Z"); // printable passthrough
+
+ free(s);
+ spdxtool_serialize_value_free(v);
+}
+
+// Mixed-type object exercises the int/bool/null add helpers
+static void
+test_serialize_object_mixed_types(void)
+{
+ spdxtool_serialize_object_list_t *o = spdxtool_serialize_object_list_new();
+ TEST_ASSERT_NONNULL(o);
+
+ TEST_ASSERT_NONNULL(spdxtool_serialize_object_add_string(o, "s", "x"));
+ TEST_ASSERT_NONNULL(spdxtool_serialize_object_add_int(o, "i", 42));
+ TEST_ASSERT_NONNULL(spdxtool_serialize_object_add_bool(o, "b", true));
+ TEST_ASSERT_NONNULL(spdxtool_serialize_object_add_null(o, "n"));
+
+ char *s = render_object(o);
+ TEST_ASSERT_STRSTR(s, "\"s\": \"x\"");
+ TEST_ASSERT_STRSTR(s, "\"i\": 42");
+ TEST_ASSERT_STRSTR(s, "\"b\": true");
+ TEST_ASSERT_STRSTR(s, "\"n\": null");
+
+ free(s);
+ spdxtool_serialize_object_list_free(o);
+}
+
+// Mixed-type array exercises the int/bool/null array helpers
+static void
+test_serialize_array_mixed_types(void)
+{
+ spdxtool_serialize_array_t *a = spdxtool_serialize_array_new();
+ TEST_ASSERT_NONNULL(a);
+
+ TEST_ASSERT_NONNULL(spdxtool_serialize_array_add_int(a, 7));
+ TEST_ASSERT_NONNULL(spdxtool_serialize_array_add_bool(a, false));
+ TEST_ASSERT_NONNULL(spdxtool_serialize_array_add_null(a));
+
+ char *s = render_array(a);
+ TEST_ASSERT_STRSTR(s, "7");
+ TEST_ASSERT_STRSTR(s, "false");
+ TEST_ASSERT_STRSTR(s, "null");
+
+ free(s);
+ spdxtool_serialize_array_free(a);
+}
+
+// Defensive NULL handling that the CLI path never reaches
+static void
+test_serialize_null_guards(void)
+{
+ pkgconf_buffer_t buf = PKGCONF_BUFFER_INITIALIZER;
+ spdxtool_serialize_value_t *v = spdxtool_serialize_value_null();
+
+ // value_to_buf rejects NULL buffer or NULL value
+ TEST_ASSERT_FALSE(spdxtool_serialize_value_to_buf(NULL, v, 0));
+ TEST_ASSERT_FALSE(spdxtool_serialize_value_to_buf(&buf, NULL, 0));
+ pkgconf_buffer_finalize(&buf);
+
+ // value_string(NULL) yields NULL
+ TEST_ASSERT_NULL(spdxtool_serialize_value_string(NULL));
+
+ // add_take with a NULL container frees the value and returns NULL
+ TEST_ASSERT_NULL(spdxtool_serialize_object_add_take(NULL, "k", v));
+ TEST_ASSERT_NULL(spdxtool_serialize_array_add_take(NULL, spdxtool_serialize_value_null()));
+
+ // free routines are NULL-safe
+ spdxtool_serialize_value_free(NULL);
+ spdxtool_serialize_object_free(NULL);
+ spdxtool_serialize_object_list_free(NULL);
+ spdxtool_serialize_array_free(NULL);
+}
+
+int
+main(int argc, const char **argv)
+{
+ (void) argc;
+ const char *basename = pkgconf_path_find_basename(argv[0]);
+
+ TEST_RUN(basename, test_serialize_value_string);
+ TEST_RUN(basename, test_serialize_value_int);
+ TEST_RUN(basename, test_serialize_value_bool);
+ TEST_RUN(basename, test_serialize_value_null);
+ TEST_RUN(basename, test_serialize_escape_sequences);
+ TEST_RUN(basename, test_serialize_object_mixed_types);
+ TEST_RUN(basename, test_serialize_array_mixed_types);
+ TEST_RUN(basename, test_serialize_null_guards);
+
+ return EXIT_SUCCESS;
+}
diff --git a/tests/lib-sbom-files/agent_name.json b/tests/lib-sbom-files/agent_name.json
new file mode 100644
index 000000000000..4441e714331f
--- /dev/null
+++ b/tests/lib-sbom-files/agent_name.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/myagent",
+ "name": "MyAgent"
+ },
+ {
+ "type": "CreationInfo",
+ "@id": "_:creationinfo_1",
+ "created": "test",
+ "createdBy": [
+ "https://github.com/pkgconf/pkgconf/Agent/myagent"
+ ],
+ "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/myagent"
+ ],
+ "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/myagent",
+ "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/agent_name_space.json b/tests/lib-sbom-files/agent_name_space.json
new file mode 100644
index 000000000000..e29416adba4e
--- /dev/null
+++ b/tests/lib-sbom-files/agent_name_space.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/my_agent",
+ "name": "My Agent"
+ },
+ {
+ "type": "CreationInfo",
+ "@id": "_:creationinfo_1",
+ "created": "test",
+ "createdBy": [
+ "https://github.com/pkgconf/pkgconf/Agent/my_agent"
+ ],
+ "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/my_agent"
+ ],
+ "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/my_agent",
+ "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/bomtool-basic.txt b/tests/lib-sbom-files/bomtool-basic.txt
new file mode 100644
index 000000000000..9adeec9ae8dc
--- /dev/null
+++ b/tests/lib-sbom-files/bomtool-basic.txt
@@ -0,0 +1,24 @@
+SPDXVersion: SPDX-2.2
+DataLicense: CC0-1.0
+SPDXID: SPDXRef-DOCUMENT
+DocumentName: SBOM-SPDX-test3C403.0.0
+DocumentNamespace: https://spdx.org/spdxdocs/bomtool
+Creator: Tool: bomtool
+Created: test
+
+
+##### Package: test3@3.0.0
+
+PackageName: test3@3.0.0
+SPDXID: SPDXRef-Package-test3C403.0.0
+PackageVersion: 3.0.0
+PackageDownloadLocation: NOASSERTION
+PackageHomePage: https://github.com/pkgconf/pkgconf/
+PackageLicenseDeclared: BSD-4-Clause
+PackageLicenseConcluded: NOASSERTION
+PackageCopyrightText: <text>Test3 copyright text</text>
+PackageSummary: <text>Test package 3</text>
+PackageDownloadLocation: https://github.com/pkgconf/pkgconf/archive/refs/tags/pkgconf-2.5.1.tar.gz
+
+
+Relationship: SPDXRef-DOCUMENT DESCRIBES SPDXRef-Package-test3C403.0.0
diff --git a/tests/lib-sbom-files/bomtool-define_variable.txt b/tests/lib-sbom-files/bomtool-define_variable.txt
new file mode 100644
index 000000000000..95478ffc6431
--- /dev/null
+++ b/tests/lib-sbom-files/bomtool-define_variable.txt
@@ -0,0 +1,24 @@
+SPDXVersion: SPDX-2.2
+DataLicense: CC0-1.0
+SPDXID: SPDXRef-DOCUMENT
+DocumentName: SBOM-SPDX-variable-test1C401.0-123
+DocumentNamespace: https://spdx.org/spdxdocs/bomtool
+Creator: Tool: bomtool
+Created: test
+
+
+##### Package: variable-test1@1.0-123
+
+PackageName: variable-test1@1.0-123
+SPDXID: SPDXRef-Package-variable-test1C401.0-123
+PackageVersion: 1.0-123
+PackageDownloadLocation: NOASSERTION
+PackageHomePage: https://github.com/pkgconf/pkgconf/releases/
+PackageLicenseDeclared: BSD-2-Clause
+PackageLicenseConcluded: NOASSERTION
+PackageCopyrightText: NOASSERTION
+PackageSummary: <text>Variable test 1</text>
+PackageDownloadLocation: https://github.com/pkgconf/pkgconf/archive/refs/tags/pkgconf-2.5.1.tar.gz
+
+
+Relationship: SPDXRef-DOCUMENT DESCRIBES SPDXRef-Package-variable-test1C401.0-123
diff --git a/tests/lib-sbom-files/bomtool-define_variable_with_dependency.txt b/tests/lib-sbom-files/bomtool-define_variable_with_dependency.txt
new file mode 100644
index 000000000000..571ec7cc58ea
--- /dev/null
+++ b/tests/lib-sbom-files/bomtool-define_variable_with_dependency.txt
@@ -0,0 +1,43 @@
+SPDXVersion: SPDX-2.2
+DataLicense: CC0-1.0
+SPDXID: SPDXRef-DOCUMENT
+DocumentName: SBOM-SPDX-variable-test2C402.0
+DocumentNamespace: https://spdx.org/spdxdocs/bomtool
+Creator: Tool: bomtool
+Created: test
+
+
+##### Package: variable-test2@2.0
+
+PackageName: variable-test2@2.0
+SPDXID: SPDXRef-Package-variable-test2C402.0
+PackageVersion: 2.0
+PackageDownloadLocation: NOASSERTION
+PackageHomePage: https://github.com/pkgconf/pkgconf/releases/
+PackageLicenseDeclared: MIT
+PackageLicenseConcluded: NOASSERTION
+PackageCopyrightText: NOASSERTION
+PackageSummary: <text>Variable test 2</text>
+PackageDownloadLocation: https://github.com/pkgconf/pkgconf/archive/refs/tags/pkgconf-2.5.1.tar.gz
+
+
+##### Package: variable-test1@1.0-123
+
+PackageName: variable-test1@1.0-123
+SPDXID: SPDXRef-Package-variable-test1C401.0-123
+PackageVersion: 1.0-123
+PackageDownloadLocation: NOASSERTION
+PackageHomePage: https://github.com/pkgconf/pkgconf/releases/
+PackageLicenseDeclared: BSD-2-Clause
+PackageLicenseConcluded: NOASSERTION
+PackageCopyrightText: NOASSERTION
+PackageSummary: <text>Variable test 1</text>
+PackageDownloadLocation: https://github.com/pkgconf/pkgconf/archive/refs/tags/pkgconf-2.5.1.tar.gz
+
+
+Relationship: SPDXRef-Package-variable-test2C402.0 DEPENDS_ON SPDXRef-Package-variable-test1C401.0-123
+Relationship: SPDXRef-Package-variable-test1C401.0-123 DEPENDENCY_OF SPDXRef-Package-variable-test2C402.0
+
+
+Relationship: SPDXRef-DOCUMENT DESCRIBES SPDXRef-Package-variable-test2C402.0
+Relationship: SPDXRef-DOCUMENT DESCRIBES SPDXRef-Package-variable-test1C401.0-123
diff --git a/tests/lib-sbom-files/bomtool-meta_package.txt b/tests/lib-sbom-files/bomtool-meta_package.txt
new file mode 100644
index 000000000000..6aa089dc5a48
--- /dev/null
+++ b/tests/lib-sbom-files/bomtool-meta_package.txt
@@ -0,0 +1,137 @@
+SPDXVersion: SPDX-2.2
+DataLicense: CC0-1.0
+SPDXID: SPDXRef-DOCUMENT
+DocumentName: SBOM-SPDX-metaC5fpackageC401.0.0
+DocumentNamespace: https://spdx.org/spdxdocs/bomtool
+Creator: Tool: bomtool
+Created: test
+
+
+##### Package: meta_package@1.0.0
+
+PackageName: meta_package@1.0.0
+SPDXID: SPDXRef-Package-metaC5fpackageC401.0.0
+PackageVersion: 1.0.0
+PackageDownloadLocation: NOASSERTION
+PackageHomePage: https://github.com/pkgconf/pkgconf
+PackageLicenseDeclared: BSD-2-Clause
+PackageLicenseConcluded: NOASSERTION
+PackageCopyrightText: NOASSERTION
+PackageSummary: <text>Meta package to test SBOM creation</text>
+PackageDownloadLocation: https://github.com/pkgconf/pkgconf/archive/refs/tags/pkgconf-2.5.1.tar.gz
+
+
+##### Package: test1@1.0.0
+
+PackageName: test1@1.0.0
+SPDXID: SPDXRef-Package-test1C401.0.0
+PackageVersion: 1.0.0
+PackageDownloadLocation: NOASSERTION
+PackageLicenseDeclared: BSD-1-Clause
+PackageLicenseConcluded: NOASSERTION
+PackageCopyrightText: <text>Test1 copyright text</text>
+PackageSummary: <text>Test package 1</text>
+PackageDownloadLocation: NOASSERTION
+
+
+##### Package: test2@2.0.0
+
+PackageName: test2@2.0.0
+SPDXID: SPDXRef-Package-test2C402.0.0
+PackageVersion: 2.0.0
+PackageDownloadLocation: NOASSERTION
+PackageHomePage: https://github.com/pkgconf/pkgconf/
+PackageLicenseDeclared: BSD-2-Clause
+PackageLicenseConcluded: NOASSERTION
+PackageCopyrightText: NOASSERTION
+PackageSummary: <text>Test package 2</text>
+PackageDownloadLocation: https://github.com/pkgconf/pkgconf/archive/refs/tags/pkgconf-2.5.1.tar.gz
+
+
+##### Package: test3@3.0.0
+
+PackageName: test3@3.0.0
+SPDXID: SPDXRef-Package-test3C403.0.0
+PackageVersion: 3.0.0
+PackageDownloadLocation: NOASSERTION
+PackageHomePage: https://github.com/pkgconf/pkgconf/
+PackageLicenseDeclared: BSD-4-Clause
+PackageLicenseConcluded: NOASSERTION
+PackageCopyrightText: <text>Test3 copyright text</text>
+PackageSummary: <text>Test package 3</text>
+PackageDownloadLocation: https://github.com/pkgconf/pkgconf/archive/refs/tags/pkgconf-2.5.1.tar.gz
+
+
+##### Package: test4@4.0.0
+
+PackageName: test4@4.0.0
+SPDXID: SPDXRef-Package-test4C404.0.0
+PackageVersion: 4.0.0
+PackageDownloadLocation: NOASSERTION
+PackageHomePage: https://github.com/pkgconf/pkgconf/
+PackageLicenseDeclared: MIT
+PackageLicenseConcluded: NOASSERTION
+PackageCopyrightText: NOASSERTION
+PackageSummary: <text>Test package 4</text>
+PackageDownloadLocation: https://github.com/pkgconf/pkgconf/archive/refs/tags/pkgconf-2.5.1.tar.gz
+
+
+##### Package: test5@5.0.0
+
+PackageName: test5@5.0.0
+SPDXID: SPDXRef-Package-test5C405.0.0
+PackageVersion: 5.0.0
+PackageDownloadLocation: NOASSERTION
+PackageHomePage: https://github.com/pkgconf/pkgconf/
+PackageLicenseDeclared: MIT
+PackageLicenseConcluded: NOASSERTION
+PackageCopyrightText: NOASSERTION
+PackageSummary: <text>Test package 5</text>
+PackageDownloadLocation: https://github.com/pkgconf/pkgconf/archive/refs/tags/pkgconf-2.5.1.tar.gz
+
+
+##### Package: test6@6.0.0
+
+PackageName: test6@6.0.0
+SPDXID: SPDXRef-Package-test6C406.0.0
+PackageVersion: 6.0.0
+PackageDownloadLocation: NOASSERTION
+PackageHomePage: https://github.com/pkgconf/pkgconf/releases/
+PackageLicenseDeclared: Apache-2.0
+PackageLicenseConcluded: NOASSERTION
+PackageCopyrightText: NOASSERTION
+PackageSummary: <text>Test package 6</text>
+PackageDownloadLocation: https://github.com/pkgconf/pkgconf/archive/refs/tags/pkgconf-2.5.1.tar.gz
+
+
+Relationship: SPDXRef-Package-metaC5fpackageC401.0.0 DEPENDS_ON SPDXRef-Package-test1C401.0.0
+Relationship: SPDXRef-Package-test1C401.0.0 DEPENDENCY_OF SPDXRef-Package-metaC5fpackageC401.0.0
+Relationship: SPDXRef-Package-metaC5fpackageC401.0.0 DEPENDS_ON SPDXRef-Package-test2C402.0.0
+Relationship: SPDXRef-Package-test2C402.0.0 DEPENDENCY_OF SPDXRef-Package-metaC5fpackageC401.0.0
+Relationship: SPDXRef-Package-metaC5fpackageC401.0.0 DEPENDS_ON SPDXRef-Package-test3C403.0.0
+Relationship: SPDXRef-Package-test3C403.0.0 DEPENDENCY_OF SPDXRef-Package-metaC5fpackageC401.0.0
+Relationship: SPDXRef-Package-metaC5fpackageC401.0.0 DEPENDS_ON SPDXRef-Package-test4C404.0.0
+Relationship: SPDXRef-Package-test4C404.0.0 DEPENDENCY_OF SPDXRef-Package-metaC5fpackageC401.0.0
+Relationship: SPDXRef-Package-metaC5fpackageC401.0.0 DEPENDS_ON SPDXRef-Package-test5C405.0.0
+Relationship: SPDXRef-Package-test5C405.0.0 DEPENDENCY_OF SPDXRef-Package-metaC5fpackageC401.0.0
+Relationship: SPDXRef-Package-metaC5fpackageC401.0.0 DEPENDS_ON SPDXRef-Package-test6C406.0.0
+Relationship: SPDXRef-Package-test6C406.0.0 DEPENDENCY_OF SPDXRef-Package-metaC5fpackageC401.0.0
+
+
+Relationship: SPDXRef-Package-test2C402.0.0 DEPENDS_ON SPDXRef-Package-test3C403.0.0
+Relationship: SPDXRef-Package-test3C403.0.0 DEPENDENCY_OF SPDXRef-Package-test2C402.0.0
+
+
+Relationship: SPDXRef-Package-test4C404.0.0 DEPENDS_ON SPDXRef-Package-test5C405.0.0
+Relationship: SPDXRef-Package-test5C405.0.0 DEPENDENCY_OF SPDXRef-Package-test4C404.0.0
+Relationship: SPDXRef-Package-test4C404.0.0 DEPENDS_ON SPDXRef-Package-test6C406.0.0
+Relationship: SPDXRef-Package-test6C406.0.0 DEPENDENCY_OF SPDXRef-Package-test4C404.0.0
+
+
+Relationship: SPDXRef-DOCUMENT DESCRIBES SPDXRef-Package-metaC5fpackageC401.0.0
+Relationship: SPDXRef-DOCUMENT DESCRIBES SPDXRef-Package-test1C401.0.0
+Relationship: SPDXRef-DOCUMENT DESCRIBES SPDXRef-Package-test2C402.0.0
+Relationship: SPDXRef-DOCUMENT DESCRIBES SPDXRef-Package-test3C403.0.0
+Relationship: SPDXRef-DOCUMENT DESCRIBES SPDXRef-Package-test4C404.0.0
+Relationship: SPDXRef-DOCUMENT DESCRIBES SPDXRef-Package-test5C405.0.0
+Relationship: SPDXRef-DOCUMENT DESCRIBES SPDXRef-Package-test6C406.0.0
diff --git a/tests/lib-sbom-files/bomtool-multiple_packages.txt b/tests/lib-sbom-files/bomtool-multiple_packages.txt
new file mode 100644
index 000000000000..58c1e2dc827d
--- /dev/null
+++ b/tests/lib-sbom-files/bomtool-multiple_packages.txt
@@ -0,0 +1,39 @@
+SPDXVersion: SPDX-2.2
+DataLicense: CC0-1.0
+SPDXID: SPDXRef-DOCUMENT
+DocumentName: SBOM-SPDX-test5C405.0.0-test6C406.0.0
+DocumentNamespace: https://spdx.org/spdxdocs/bomtool
+Creator: Tool: bomtool
+Created: test
+
+
+##### Package: test5@5.0.0
+
+PackageName: test5@5.0.0
+SPDXID: SPDXRef-Package-test5C405.0.0
+PackageVersion: 5.0.0
+PackageDownloadLocation: NOASSERTION
+PackageHomePage: https://github.com/pkgconf/pkgconf/
+PackageLicenseDeclared: MIT
+PackageLicenseConcluded: NOASSERTION
+PackageCopyrightText: NOASSERTION
+PackageSummary: <text>Test package 5</text>
+PackageDownloadLocation: https://github.com/pkgconf/pkgconf/archive/refs/tags/pkgconf-2.5.1.tar.gz
+
+
+##### Package: test6@6.0.0
+
+PackageName: test6@6.0.0
+SPDXID: SPDXRef-Package-test6C406.0.0
+PackageVersion: 6.0.0
+PackageDownloadLocation: NOASSERTION
+PackageHomePage: https://github.com/pkgconf/pkgconf/releases/
+PackageLicenseDeclared: Apache-2.0
+PackageLicenseConcluded: NOASSERTION
+PackageCopyrightText: NOASSERTION
+PackageSummary: <text>Test package 6</text>
+PackageDownloadLocation: https://github.com/pkgconf/pkgconf/archive/refs/tags/pkgconf-2.5.1.tar.gz
+
+
+Relationship: SPDXRef-DOCUMENT DESCRIBES SPDXRef-Package-test5C405.0.0
+Relationship: SPDXRef-DOCUMENT DESCRIBES SPDXRef-Package-test6C406.0.0
diff --git a/tests/lib-sbom-files/bomtool-nolicense.txt b/tests/lib-sbom-files/bomtool-nolicense.txt
new file mode 100644
index 000000000000..3fdca7694ef7
--- /dev/null
+++ b/tests/lib-sbom-files/bomtool-nolicense.txt
@@ -0,0 +1,24 @@
+SPDXVersion: SPDX-2.2
+DataLicense: CC0-1.0
+SPDXID: SPDXRef-DOCUMENT
+DocumentName: SBOM-SPDX-nolicenseC401.0.0
+DocumentNamespace: https://spdx.org/spdxdocs/bomtool
+Creator: Tool: bomtool
+Created: test
+
+
+##### Package: nolicense@1.0.0
+
+PackageName: nolicense@1.0.0
+SPDXID: SPDXRef-Package-nolicenseC401.0.0
+PackageVersion: 1.0.0
+PackageDownloadLocation: NOASSERTION
+PackageHomePage: https://example.com/nolicense
+PackageLicenseDeclared: NOASSERTION
+PackageLicenseConcluded: NOASSERTION
+PackageCopyrightText: <text>Nolicense copyright text</text>
+PackageSummary: <text>Package without a license field</text>
+PackageDownloadLocation: https://example.com/nolicense/nolicense-1.0.0.tar.gz
+
+
+Relationship: SPDXRef-DOCUMENT DESCRIBES SPDXRef-Package-nolicenseC401.0.0
diff --git a/tests/lib-sbom-files/bomtool-special.txt b/tests/lib-sbom-files/bomtool-special.txt
new file mode 100644
index 000000000000..415d0f448c25
--- /dev/null
+++ b/tests/lib-sbom-files/bomtool-special.txt
@@ -0,0 +1,24 @@
+SPDXVersion: SPDX-2.2
+DataLicense: CC0-1.0
+SPDXID: SPDXRef-DOCUMENT
+DocumentName: SBOM-SPDX-specialC401.0.0
+DocumentNamespace: https://spdx.org/spdxdocs/bomtool
+Creator: Tool: bomtool
+Created: test
+
+
+##### Package: special@1.0.0
+
+PackageName: special@1.0.0
+SPDXID: SPDXRef-Package-specialC401.0.0
+PackageVersion: 1.0.0
+PackageDownloadLocation: NOASSERTION
+PackageHomePage: https://example.com/special
+PackageLicenseDeclared: MIT
+PackageLicenseConcluded: NOASSERTION
+PackageCopyrightText: <text>Quote " backslash \ and tab</text>
+PackageSummary: <text>Package with special characters</text>
+PackageDownloadLocation: NOASSERTION
+
+
+Relationship: SPDXRef-DOCUMENT DESCRIBES SPDXRef-Package-specialC401.0.0
diff --git a/tests/lib-sbom-files/bomtool-with_dependency.txt b/tests/lib-sbom-files/bomtool-with_dependency.txt
new file mode 100644
index 000000000000..6e40e06a683b
--- /dev/null
+++ b/tests/lib-sbom-files/bomtool-with_dependency.txt
@@ -0,0 +1,43 @@
+SPDXVersion: SPDX-2.2
+DataLicense: CC0-1.0
+SPDXID: SPDXRef-DOCUMENT
+DocumentName: SBOM-SPDX-test2C402.0.0
+DocumentNamespace: https://spdx.org/spdxdocs/bomtool
+Creator: Tool: bomtool
+Created: test
+
+
+##### Package: test2@2.0.0
+
+PackageName: test2@2.0.0
+SPDXID: SPDXRef-Package-test2C402.0.0
+PackageVersion: 2.0.0
+PackageDownloadLocation: NOASSERTION
+PackageHomePage: https://github.com/pkgconf/pkgconf/
+PackageLicenseDeclared: BSD-2-Clause
+PackageLicenseConcluded: NOASSERTION
+PackageCopyrightText: NOASSERTION
+PackageSummary: <text>Test package 2</text>
+PackageDownloadLocation: https://github.com/pkgconf/pkgconf/archive/refs/tags/pkgconf-2.5.1.tar.gz
+
+
+##### Package: test3@3.0.0
+
+PackageName: test3@3.0.0
+SPDXID: SPDXRef-Package-test3C403.0.0
+PackageVersion: 3.0.0
+PackageDownloadLocation: NOASSERTION
+PackageHomePage: https://github.com/pkgconf/pkgconf/
+PackageLicenseDeclared: BSD-4-Clause
+PackageLicenseConcluded: NOASSERTION
+PackageCopyrightText: <text>Test3 copyright text</text>
+PackageSummary: <text>Test package 3</text>
+PackageDownloadLocation: https://github.com/pkgconf/pkgconf/archive/refs/tags/pkgconf-2.5.1.tar.gz
+
+
+Relationship: SPDXRef-Package-test2C402.0.0 DEPENDS_ON SPDXRef-Package-test3C403.0.0
+Relationship: SPDXRef-Package-test3C403.0.0 DEPENDENCY_OF SPDXRef-Package-test2C402.0.0
+
+
+Relationship: SPDXRef-DOCUMENT DESCRIBES SPDXRef-Package-test2C402.0.0
+Relationship: SPDXRef-DOCUMENT DESCRIBES SPDXRef-Package-test3C403.0.0
diff --git a/tests/lib-sbom-files/creation_id.json b/tests/lib-sbom-files/creation_id.json
new file mode 100644
index 000000000000..529d5b8ec296
--- /dev/null
+++ b/tests/lib-sbom-files/creation_id.json
@@ -0,0 +1,90 @@
+{
+ "@context": "https://spdx.org/rdf/3.0.1/spdx-context.jsonld",
+ "@graph": [
+ {
+ "type": "Agent",
+ "creationInfo": "_:custom_1",
+ "spdxId": "https://github.com/pkgconf/pkgconf/Agent/default",
+ "name": "Default"
+ },
+ {
+ "type": "CreationInfo",
+ "@id": "_:custom_1",
+ "created": "test",
+ "createdBy": [
+ "https://github.com/pkgconf/pkgconf/Agent/default"
+ ],
+ "specVersion": "3.0.1"
+ },
+ {
+ "type": "simplelicensing_LicenseExpression",
+ "creationInfo": "_:custom_1",
+ "spdxId": "https://github.com/pkgconf/pkgconf/simplelicensing_LicenseExpression/BSD-4-Clause",
+ "simplelicensing_licenseExpression": "BSD-4-Clause"
+ },
+ {
+ "type": "software_Sbom",
+ "creationInfo": "_:custom_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": "_:custom_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": "_:custom_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": "_:custom_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": "_:custom_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/multi_copyright.json b/tests/lib-sbom-files/multi_copyright.json
new file mode 100644
index 000000000000..cf32487cfe19
--- /dev/null
+++ b/tests/lib-sbom-files/multi_copyright.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/MIT",
+ "simplelicensing_licenseExpression": "MIT"
+ },
+ {
+ "type": "software_Sbom",
+ "creationInfo": "_:creationinfo_1",
+ "spdxId": "https://github.com/pkgconf/pkgconf/software_Sbom/multi-copyright",
+ "software_sbomType": [
+ "build"
+ ],
+ "rootElement": [
+ "https://github.com/pkgconf/pkgconf/Package/multi-copyright"
+ ],
+ "element": [
+ "https://github.com/pkgconf/pkgconf/Relationship/multi-copyright/hasDeclaredLicense",
+ "https://github.com/pkgconf/pkgconf/Relationship/multi-copyright/hasConcludedLicense"
+ ]
+ },
+ {
+ "type": "software_Package",
+ "creationInfo": "_:creationinfo_1",
+ "spdxId": "https://github.com/pkgconf/pkgconf/Package/multi-copyright",
+ "name": "multi-copyright",
+ "originatedBy": [
+ "https://github.com/pkgconf/pkgconf/Agent/default"
+ ],
+ "software_copyrightText": "First copyright holder\nSecond copyright holder",
+ "software_homePage": "https://example.com/mc",
+ "software_downloadLocation": "",
+ "software_packageVersion": "1.0.0"
+ },
+ {
+ "type": "Relationship",
+ "creationInfo": "_:creationinfo_1",
+ "spdxId": "https://github.com/pkgconf/pkgconf/Relationship/multi-copyright/hasDeclaredLicense",
+ "from": "https://github.com/pkgconf/pkgconf/Package/multi-copyright",
+ "to": [
+ "https://github.com/pkgconf/pkgconf/simplelicensing_LicenseExpression/MIT"
+ ],
+ "relationshipType": "hasDeclaredLicense"
+ },
+ {
+ "type": "Relationship",
+ "creationInfo": "_:creationinfo_1",
+ "spdxId": "https://github.com/pkgconf/pkgconf/Relationship/multi-copyright/hasConcludedLicense",
+ "from": "https://github.com/pkgconf/pkgconf/Package/multi-copyright",
+ "to": [
+ "https://github.com/pkgconf/pkgconf/simplelicensing_LicenseExpression/MIT"
+ ],
+ "relationshipType": "hasConcludedLicense"
+ },
+ {
+ "type": "SpdxDocument",
+ "creationInfo": "_:creationinfo_1",
+ "spdxId": "https://github.com/pkgconf/pkgconf/spdxDocument/1",
+ "rootElement": [
+ "https://github.com/pkgconf/pkgconf/software_Sbom/multi-copyright"
+ ],
+ "element": [
+ "https://github.com/pkgconf/pkgconf/Agent/default",
+ "https://github.com/pkgconf/pkgconf/simplelicensing_LicenseExpression/MIT",
+ "https://github.com/pkgconf/pkgconf/Relationship/multi-copyright/hasDeclaredLicense",
+ "https://github.com/pkgconf/pkgconf/Relationship/multi-copyright/hasConcludedLicense",
+ "https://github.com/pkgconf/pkgconf/software_Sbom/multi-copyright",
+ "https://github.com/pkgconf/pkgconf/Package/multi-copyright"
+ ]
+ }
+ ]
+}
diff --git a/tests/lib-sbom-files/multiple_packages.json b/tests/lib-sbom-files/multiple_packages.json
new file mode 100644
index 000000000000..3e9303c478b7
--- /dev/null
+++ b/tests/lib-sbom-files/multiple_packages.json
@@ -0,0 +1,150 @@
+{
+ "@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/Apache-2.0",
+ "simplelicensing_licenseExpression": "Apache-2.0"
+ },
+ {
+ "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/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/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/test5",
+ "https://github.com/pkgconf/pkgconf/software_Sbom/test6"
+ ],
+ "element": [
+ "https://github.com/pkgconf/pkgconf/Agent/default",
+ "https://github.com/pkgconf/pkgconf/simplelicensing_LicenseExpression/MIT",
+ "https://github.com/pkgconf/pkgconf/simplelicensing_LicenseExpression/Apache-2.0",
+ "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/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/nolicense.json b/tests/lib-sbom-files/nolicense.json
new file mode 100644
index 000000000000..d5d8ac639979
--- /dev/null
+++ b/tests/lib-sbom-files/nolicense.json
@@ -0,0 +1,59 @@
+{
+ "@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": "software_Sbom",
+ "creationInfo": "_:creationinfo_1",
+ "spdxId": "https://github.com/pkgconf/pkgconf/software_Sbom/nolicense",
+ "software_sbomType": [
+ "build"
+ ],
+ "rootElement": [
+ "https://github.com/pkgconf/pkgconf/Package/nolicense"
+ ],
+ "element": [
+ ]
+ },
+ {
+ "type": "software_Package",
+ "creationInfo": "_:creationinfo_1",
+ "spdxId": "https://github.com/pkgconf/pkgconf/Package/nolicense",
+ "name": "nolicense",
+ "originatedBy": [
+ "https://github.com/pkgconf/pkgconf/Agent/default"
+ ],
+ "software_copyrightText": "Nolicense copyright text",
+ "software_homePage": "https://example.com/nolicense",
+ "software_downloadLocation": "https://example.com/nolicense/nolicense-1.0.0.tar.gz",
+ "software_packageVersion": "1.0.0"
+ },
+ {
+ "type": "SpdxDocument",
+ "creationInfo": "_:creationinfo_1",
+ "spdxId": "https://github.com/pkgconf/pkgconf/spdxDocument/1",
+ "rootElement": [
+ "https://github.com/pkgconf/pkgconf/software_Sbom/nolicense"
+ ],
+ "element": [
+ "https://github.com/pkgconf/pkgconf/Agent/default",
+ "https://github.com/pkgconf/pkgconf/software_Sbom/nolicense",
+ "https://github.com/pkgconf/pkgconf/Package/nolicense"
+ ]
+ }
+ ]
+}
diff --git a/tests/lib-sbom-files/special.json b/tests/lib-sbom-files/special.json
new file mode 100644
index 000000000000..34d55df409ee
--- /dev/null
+++ b/tests/lib-sbom-files/special.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/MIT",
+ "simplelicensing_licenseExpression": "MIT"
+ },
+ {
+ "type": "software_Sbom",
+ "creationInfo": "_:creationinfo_1",
+ "spdxId": "https://github.com/pkgconf/pkgconf/software_Sbom/special",
+ "software_sbomType": [
+ "build"
+ ],
+ "rootElement": [
+ "https://github.com/pkgconf/pkgconf/Package/special"
+ ],
+ "element": [
+ "https://github.com/pkgconf/pkgconf/Relationship/special/hasDeclaredLicense",
+ "https://github.com/pkgconf/pkgconf/Relationship/special/hasConcludedLicense"
+ ]
+ },
+ {
+ "type": "software_Package",
+ "creationInfo": "_:creationinfo_1",
+ "spdxId": "https://github.com/pkgconf/pkgconf/Package/special",
+ "name": "special",
+ "originatedBy": [
+ "https://github.com/pkgconf/pkgconf/Agent/default"
+ ],
+ "software_copyrightText": "Quote \" backslash \\ and\ttab",
+ "software_homePage": "https://example.com/special",
+ "software_downloadLocation": "",
+ "software_packageVersion": "1.0.0"
+ },
+ {
+ "type": "Relationship",
+ "creationInfo": "_:creationinfo_1",
+ "spdxId": "https://github.com/pkgconf/pkgconf/Relationship/special/hasDeclaredLicense",
+ "from": "https://github.com/pkgconf/pkgconf/Package/special",
+ "to": [
+ "https://github.com/pkgconf/pkgconf/simplelicensing_LicenseExpression/MIT"
+ ],
+ "relationshipType": "hasDeclaredLicense"
+ },
+ {
+ "type": "Relationship",
+ "creationInfo": "_:creationinfo_1",
+ "spdxId": "https://github.com/pkgconf/pkgconf/Relationship/special/hasConcludedLicense",
+ "from": "https://github.com/pkgconf/pkgconf/Package/special",
+ "to": [
+ "https://github.com/pkgconf/pkgconf/simplelicensing_LicenseExpression/MIT"
+ ],
+ "relationshipType": "hasConcludedLicense"
+ },
+ {
+ "type": "SpdxDocument",
+ "creationInfo": "_:creationinfo_1",
+ "spdxId": "https://github.com/pkgconf/pkgconf/spdxDocument/1",
+ "rootElement": [
+ "https://github.com/pkgconf/pkgconf/software_Sbom/special"
+ ],
+ "element": [
+ "https://github.com/pkgconf/pkgconf/Agent/default",
+ "https://github.com/pkgconf/pkgconf/simplelicensing_LicenseExpression/MIT",
+ "https://github.com/pkgconf/pkgconf/Relationship/special/hasDeclaredLicense",
+ "https://github.com/pkgconf/pkgconf/Relationship/special/hasConcludedLicense",
+ "https://github.com/pkgconf/pkgconf/software_Sbom/special",
+ "https://github.com/pkgconf/pkgconf/Package/special"
+ ]
+ }
+ ]
+}
diff --git a/tests/lib-sbom/multi-copyright.pc b/tests/lib-sbom/multi-copyright.pc
new file mode 100644
index 000000000000..464a641d47db
--- /dev/null
+++ b/tests/lib-sbom/multi-copyright.pc
@@ -0,0 +1,7 @@
+Name: multi-copyright
+Description: package with multiple copyright lines
+URL: https://example.com/mc
+Version: 1.0.0
+License: MIT
+Copyright: First copyright holder
+Copyright: Second copyright holder
diff --git a/tests/lib-sbom/nolicense.pc b/tests/lib-sbom/nolicense.pc
new file mode 100644
index 000000000000..0793297f637b
--- /dev/null
+++ b/tests/lib-sbom/nolicense.pc
@@ -0,0 +1,6 @@
+Name: nolicense
+Description: Package without a license field
+URL: https://example.com/nolicense
+Version: 1.0.0
+Copyright: Nolicense copyright text
+Source: https://example.com/nolicense/nolicense-1.0.0.tar.gz
diff --git a/tests/lib-sbom/special.pc b/tests/lib-sbom/special.pc
new file mode 100644
index 000000000000..7d95d54584fa
--- /dev/null
+++ b/tests/lib-sbom/special.pc
@@ -0,0 +1,6 @@
+Name: special
+Description: Package with special characters
+URL: https://example.com/special
+Version: 1.0.0
+License: MIT
+Copyright: Quote " backslash \ and tab
diff --git a/tests/test-runner.c b/tests/test-runner.c
index 5fbb426184c6..85a63df6c810 100644
--- a/tests/test-runner.c
+++ b/tests/test-runner.c
@@ -20,6 +20,9 @@
#include <libpkgconf/stdinc.h>
#include <tests/win-shim.h>
#include <sys/types.h>
+#ifndef _WIN32
+# include <sys/wait.h>
+#endif
#include <cli/core.h>
#include <cli/getopt_long.h>
#include <limits.h>
@@ -896,6 +899,12 @@ run_tool(const pkgconf_test_case_t *testcase, pkgconf_buffer_t *o_stdout, pkgcon
FILE *pipe = popen(pkgconf_buffer_str(&cmdbuf), "r");
pkgconf_buffer_finalize(&cmdbuf);
+ PKGCONF_FOREACH_LIST_ENTRY(testcase->env_vars.head, iter)
+ {
+ pkgconf_test_environ_t *env = iter->data;
+ unsetenv(env->key);
+ }
+
if (pipe == NULL)
{
fprintf(stderr, "popen failed for tool '%s': %s\n",