xref: /freebsd/contrib/pkgconf/tests/api/test-queue.c (revision 592efe252472a3385acf36b1f49ecf710a7f3d9c)
1 /*
2  * test-queue.c
3  * Tests for the public libpkgconf queue 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 #define FIXTURE_DIR "test-queue-pcdir"
21 
22 static void
write_pc(const char * name,const char * contents)23 write_pc(const char *name, const char *contents)
24 {
25 	char path[512];
26 	FILE *f;
27 
28 	snprintf(path, sizeof path, "%s/%s", FIXTURE_DIR, name);
29 	f = fopen(path, "wb");
30 	TEST_ASSERT_NONNULL(f);
31 	fwrite(contents, 1, strlen(contents), f);
32 	fclose(f);
33 }
34 
35 static void
setup_fixtures(void)36 setup_fixtures(void)
37 {
38 	mkdir(FIXTURE_DIR, 0755);
39 	write_pc("qbar.pc", "Name: qbar\nDescription: bar\nVersion: 2.0\n");
40 	write_pc("qfoo.pc",
41 		"Name: qfoo\nDescription: foo\nVersion: 1.0\nRequires: qbar >= 1.0\n");
42 }
43 
44 static void
teardown_fixtures(void)45 teardown_fixtures(void)
46 {
47 	remove(FIXTURE_DIR "/qfoo.pc");
48 	remove(FIXTURE_DIR "/qbar.pc");
49 	rmdir(FIXTURE_DIR);
50 }
51 
52 static pkgconf_client_t *
fixture_client(void)53 fixture_client(void)
54 {
55 	pkgconf_client_t *client = test_client_new();
56 
57 	pkgconf_path_free(&client->dir_list);
58 	pkgconf_path_add(FIXTURE_DIR, &client->dir_list, false);
59 
60 	return client;
61 }
62 
63 static size_t
required_count(const pkgconf_pkg_t * world)64 required_count(const pkgconf_pkg_t *world)
65 {
66 	size_t n = 0;
67 	const pkgconf_node_t *iter;
68 
69 	PKGCONF_FOREACH_LIST_ENTRY(world->required.head, iter)
70 	{
71 		n++;
72 	}
73 
74 	return n;
75 }
76 
77 static bool
contains_dep(const pkgconf_pkg_t * world,const char * name)78 contains_dep(const pkgconf_pkg_t *world, const char *name)
79 {
80 	const pkgconf_node_t *iter;
81 
82 	PKGCONF_FOREACH_LIST_ENTRY(world->required.head, iter)
83 	{
84 		const pkgconf_dependency_t *dep = iter->data;
85 
86 		if (!strcmp(dep->package, name))
87 			return true;
88 	}
89 
90 	return false;
91 }
92 
93 static void
test_queue_validate_success(void)94 test_queue_validate_success(void)
95 {
96 	pkgconf_client_t *client = fixture_client();
97 	pkgconf_list_t queue = PKGCONF_LIST_INITIALIZER;
98 
99 	pkgconf_queue_push(&queue, "qfoo");
100 	TEST_ASSERT_TRUE(pkgconf_queue_validate(client, &queue, -1));
101 
102 	pkgconf_queue_free(&queue);
103 	pkgconf_client_free(client);
104 }
105 
106 static void
test_queue_validate_version_satisfied(void)107 test_queue_validate_version_satisfied(void)
108 {
109 	pkgconf_client_t *client = fixture_client();
110 	pkgconf_list_t queue = PKGCONF_LIST_INITIALIZER;
111 
112 	pkgconf_queue_push(&queue, "qbar >= 1.0");
113 	TEST_ASSERT_TRUE(pkgconf_queue_validate(client, &queue, -1));
114 
115 	pkgconf_queue_free(&queue);
116 	pkgconf_client_free(client);
117 }
118 
119 static void
test_queue_validate_missing_package(void)120 test_queue_validate_missing_package(void)
121 {
122 	pkgconf_client_t *client = fixture_client();
123 	pkgconf_list_t queue = PKGCONF_LIST_INITIALIZER;
124 
125 	pkgconf_queue_push(&queue, "does-not-exist");
126 	TEST_ASSERT_FALSE(pkgconf_queue_validate(client, &queue, -1));
127 
128 	pkgconf_queue_free(&queue);
129 	pkgconf_client_free(client);
130 }
131 
132 static void
test_queue_validate_unsatisfiable_version(void)133 test_queue_validate_unsatisfiable_version(void)
134 {
135 	pkgconf_client_t *client = fixture_client();
136 	pkgconf_list_t queue = PKGCONF_LIST_INITIALIZER;
137 
138 	pkgconf_queue_push(&queue, "qbar >= 99.0");
139 	TEST_ASSERT_FALSE(pkgconf_queue_validate(client, &queue, -1));
140 
141 	pkgconf_queue_free(&queue);
142 	pkgconf_client_free(client);
143 }
144 
145 static void
test_queue_validate_empty(void)146 test_queue_validate_empty(void)
147 {
148 	pkgconf_client_t *client = fixture_client();
149 	pkgconf_list_t queue = PKGCONF_LIST_INITIALIZER;
150 
151 	TEST_ASSERT_FALSE(pkgconf_queue_validate(client, &queue, -1));
152 
153 	pkgconf_queue_free(&queue);
154 	pkgconf_client_free(client);
155 }
156 
157 struct apply_state {
158 	int calls;
159 	size_t deps;
160 	bool saw_qfoo;
161 	bool saw_qbar;
162 	bool retval;
163 };
164 
165 static bool
apply_cb(pkgconf_client_t * client,pkgconf_pkg_t * world,void * data,int maxdepth)166 apply_cb(pkgconf_client_t *client, pkgconf_pkg_t *world, void *data, int maxdepth)
167 {
168 	struct apply_state *st = data;
169 
170 	(void) client;
171 	(void) maxdepth;
172 
173 	st->calls++;
174 	st->deps = required_count(world);
175 	st->saw_qfoo = contains_dep(world, "qfoo");
176 	st->saw_qbar = contains_dep(world, "qbar");
177 
178 	return st->retval;
179 }
180 
181 static void
test_queue_apply_success(void)182 test_queue_apply_success(void)
183 {
184 	pkgconf_client_t *client = fixture_client();
185 	pkgconf_list_t queue = PKGCONF_LIST_INITIALIZER;
186 	struct apply_state st = { .retval = true };
187 
188 	pkgconf_queue_push(&queue, "qfoo");
189 	TEST_ASSERT_TRUE(pkgconf_queue_apply(client, &queue, apply_cb, -1, &st));
190 
191 	TEST_ASSERT_EQ(st.calls, 1);
192 	TEST_ASSERT_GE(st.deps, 2);
193 	TEST_ASSERT_TRUE(st.saw_qfoo);
194 	TEST_ASSERT_TRUE(st.saw_qbar);
195 
196 	pkgconf_queue_free(&queue);
197 	pkgconf_client_free(client);
198 }
199 
200 static void
test_queue_apply_callback_failure(void)201 test_queue_apply_callback_failure(void)
202 {
203 	pkgconf_client_t *client = fixture_client();
204 	pkgconf_list_t queue = PKGCONF_LIST_INITIALIZER;
205 	struct apply_state st = { .retval = false };
206 
207 	pkgconf_queue_push(&queue, "qfoo");
208 	TEST_ASSERT_FALSE(pkgconf_queue_apply(client, &queue, apply_cb, -1, &st));
209 	TEST_ASSERT_EQ(st.calls, 1);
210 
211 	pkgconf_queue_free(&queue);
212 	pkgconf_client_free(client);
213 }
214 
215 static void
test_queue_apply_missing_package(void)216 test_queue_apply_missing_package(void)
217 {
218 	pkgconf_client_t *client = fixture_client();
219 	pkgconf_list_t queue = PKGCONF_LIST_INITIALIZER;
220 	struct apply_state st = { .retval = true };
221 
222 	pkgconf_queue_push(&queue, "does-not-exist");
223 	TEST_ASSERT_FALSE(pkgconf_queue_apply(client, &queue, apply_cb, -1, &st));
224 	TEST_ASSERT_EQ(st.calls, 0);
225 
226 	pkgconf_queue_free(&queue);
227 	pkgconf_client_free(client);
228 }
229 
230 int
main(int argc,char * argv[])231 main(int argc, char *argv[])
232 {
233 	(void) argc;
234 	const char *basename = pkgconf_path_find_basename(argv[0]);
235 
236 	setup_fixtures();
237 
238 	TEST_RUN(basename, test_queue_validate_success);
239 	TEST_RUN(basename, test_queue_validate_version_satisfied);
240 	TEST_RUN(basename, test_queue_validate_missing_package);
241 	TEST_RUN(basename, test_queue_validate_unsatisfiable_version);
242 	TEST_RUN(basename, test_queue_validate_empty);
243 	TEST_RUN(basename, test_queue_apply_success);
244 	TEST_RUN(basename, test_queue_apply_callback_failure);
245 	TEST_RUN(basename, test_queue_apply_missing_package);
246 
247 	teardown_fixtures();
248 
249 	return EXIT_SUCCESS;
250 }
251