xref: /freebsd/contrib/pkgconf/tests/api/test-audit.c (revision 592efe252472a3385acf36b1f49ecf710a7f3d9c)
1 /*
2  * test-audit.c
3  * Tests for the public libpkgconf audit API.
4  *
5  * SPDX-License-Identifier: pkgconf
6  *
7  * Copyright (c) 2026 pkgconf authors (see AUTHORS).
8  *
9  * Permission to use, copy, modify, and/or distribute this software for any
10  * purpose with or without fee is hereby granted, provided that the above
11  * copyright notice and this permission notice appear in all copies.
12  *
13  * This software is provided 'as is' and without any warranty, express or
14  * implied.  In no event shall the authors be liable for any damages arising
15  * from the use of this software.
16  */
17 
18 #include "test-api.h"
19 
20 /*
21  * Read the entire contents of f (from the start) into buf.
22  * buf must be large enough; we keep test inputs small.
23  */
24 static void
slurp(FILE * f,char * buf,size_t bufsz)25 slurp(FILE *f, char *buf, size_t bufsz)
26 {
27 	rewind(f);
28 	size_t n = fread(buf, 1, bufsz - 1, f);
29 	buf[n] = '\0';
30 }
31 
32 static void
test_audit_log_no_logfile_is_noop(void)33 test_audit_log_no_logfile_is_noop(void)
34 {
35 	pkgconf_client_t *client = test_client_new();
36 
37 	// With no audit log set, logging must be a silent no-op and must not crash.
38 	pkgconf_audit_log(client, "should go nowhere\n");
39 
40 	pkgconf_client_free(client);
41 }
42 
43 static void
test_audit_set_log_and_write(void)44 test_audit_set_log_and_write(void)
45 {
46 	pkgconf_client_t *client = test_client_new();
47 	FILE *logf = tmpfile();
48 	TEST_ASSERT_NONNULL(logf);
49 
50 	pkgconf_audit_set_log(client, logf);
51 	pkgconf_audit_log(client, "hello %s\n", "world");
52 
53 	char buf[256];
54 	slurp(logf, buf, sizeof(buf));
55 	TEST_ASSERT_STRCMP_EQ(buf, "hello world\n");
56 
57 	fclose(logf);
58 	pkgconf_client_free(client);
59 }
60 
61 static void
test_audit_log_multiple_writes(void)62 test_audit_log_multiple_writes(void)
63 {
64 	pkgconf_client_t *client = test_client_new();
65 	FILE *logf = tmpfile();
66 	TEST_ASSERT_NONNULL(logf);
67 
68 	pkgconf_audit_set_log(client, logf);
69 	pkgconf_audit_log(client, "first\n");
70 	pkgconf_audit_log(client, "second %d\n", 2);
71 
72 	char buf[256];
73 	slurp(logf, buf, sizeof(buf));
74 	TEST_ASSERT_STRCMP_EQ(buf, "first\nsecond 2\n");
75 
76 	fclose(logf);
77 	pkgconf_client_free(client);
78 }
79 
80 static void
test_audit_log_dependency_versionless(void)81 test_audit_log_dependency_versionless(void)
82 {
83 	pkgconf_client_t *client = test_client_new();
84 	FILE *logf = tmpfile();
85 	TEST_ASSERT_NONNULL(logf);
86 
87 	pkgconf_audit_set_log(client, logf);
88 
89 	// A minimal package: only the fields the logger reads
90 	pkgconf_pkg_t pkg = { 0 };
91 	pkg.id = (char *) "foo";
92 	pkg.version = (char *) "1.2.3";
93 
94 	/* A dependency with PKGCONF_CMP_ANY and no version: the logger
95 	 * should emit only "id [version]", skipping the comparator */
96 	pkgconf_dependency_t dep = { 0 };
97 	dep.compare = PKGCONF_CMP_ANY;
98 	dep.version = NULL;
99 
100 	pkgconf_audit_log_dependency(client, &pkg, &dep);
101 
102 	char buf[256];
103 	slurp(logf, buf, sizeof(buf));
104 	TEST_ASSERT_STRCMP_EQ(buf, "foo [1.2.3]\n");
105 
106 	fclose(logf);
107 	pkgconf_client_free(client);
108 }
109 
110 static void
test_audit_log_dependency_versioned(void)111 test_audit_log_dependency_versioned(void)
112 {
113 	pkgconf_client_t *client = test_client_new();
114 	FILE *logf = tmpfile();
115 	TEST_ASSERT_NONNULL(logf);
116 
117 	pkgconf_audit_set_log(client, logf);
118 
119 	pkgconf_pkg_t pkg = { 0 };
120 	pkg.id = (char *) "bar";
121 	pkg.version = (char *) "2.0";
122 
123 	/* version set AND compare != ANY: the logger emits the
124 	 * comparator and required version between id and [version] */
125 	pkgconf_dependency_t dep = { 0 };
126 	dep.compare = PKGCONF_CMP_GREATER_THAN_EQUAL;
127 	dep.version = (char *) "1.5";
128 
129 	pkgconf_audit_log_dependency(client, &pkg, &dep);
130 
131 	char buf[256];
132 	slurp(logf, buf, sizeof(buf));
133 	TEST_ASSERT_STRCMP_EQ(buf, "bar >= 1.5 [2.0]\n");
134 
135 	fclose(logf);
136 	pkgconf_client_free(client);
137 }
138 
139 static void
test_audit_log_dependency_no_logfile_is_noop(void)140 test_audit_log_dependency_no_logfile_is_noop(void)
141 {
142 	pkgconf_client_t *client = test_client_new();
143 
144 	pkgconf_pkg_t pkg = { 0 };
145 	pkg.id = (char *) "foo";
146 	pkg.version = (char *) "1.0";
147 
148 	pkgconf_dependency_t dep = { 0 };
149 	dep.compare = PKGCONF_CMP_ANY;
150 
151 	// No log set: must be a silent no-op
152 	pkgconf_audit_log_dependency(client, &pkg, &dep);
153 
154 	pkgconf_client_free(client);
155 }
156 
157 int
main(int argc,char * argv[])158 main(int argc, char *argv[])
159 {
160 	(void) argc;
161 	const char *basename = pkgconf_path_find_basename(argv[0]);
162 
163 	TEST_RUN(basename, test_audit_log_no_logfile_is_noop);
164 	TEST_RUN(basename, test_audit_set_log_and_write);
165 	TEST_RUN(basename, test_audit_log_multiple_writes);
166 	TEST_RUN(basename, test_audit_log_dependency_versionless);
167 	TEST_RUN(basename, test_audit_log_dependency_versioned);
168 	TEST_RUN(basename, test_audit_log_dependency_no_logfile_is_noop);
169 
170 	return EXIT_SUCCESS;
171 }
172