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