xref: /freebsd/contrib/pkgconf/tests/api/test-personality.c (revision 592efe252472a3385acf36b1f49ecf710a7f3d9c)
1 /*
2  * test-personality.c
3  * Tests for libpkgconf personality functions.
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 static void
test_personality_deinit_null(void)21 test_personality_deinit_null(void)
22 {
23 	// Should not crash
24 	pkgconf_cross_personality_deinit(NULL);
25 }
26 
27 static void
test_personality_default_refcount(void)28 test_personality_default_refcount(void)
29 {
30 	pkgconf_cross_personality_t *p1 = pkgconf_cross_personality_default();
31 	pkgconf_cross_personality_t *p2 = pkgconf_cross_personality_default();
32 
33 	TEST_ASSERT_NONNULL(p1);
34 	TEST_ASSERT_NONNULL(p2);
35 	// Both calls must return the same singleton pointer
36 	TEST_ASSERT_EQ((long long)(uintptr_t)p1, (long long)(uintptr_t)p2);
37 
38 	// Refcount is 2 -> first deinit drops it to 1, must not free
39 	pkgconf_cross_personality_deinit(p1);
40 	// Refcount is 1 -> second deinit drops to 0, frees internal state
41 	pkgconf_cross_personality_deinit(p2);
42 
43 	// Re-initialise from scratch
44 	pkgconf_cross_personality_t *p3 = pkgconf_cross_personality_default();
45 	TEST_ASSERT_NONNULL(p3);
46 	pkgconf_cross_personality_deinit(p3);
47 }
48 
49 #ifndef PKGCONF_LITE
50 
51 static void
test_personality_find_invalid_triplet(void)52 test_personality_find_invalid_triplet(void)
53 {
54 	/* "bad triplet!" has a space and '!' — both rejected by valid_triplet,
55 	 * and the direct-file open will also fail, so result must be NULL. */
56 	pkgconf_cross_personality_t *p = pkgconf_cross_personality_find("bad triplet!");
57 	TEST_ASSERT_NULL(p);
58 }
59 
60 static void
test_personality_find_direct_path(void)61 test_personality_find_direct_path(void)
62 {
63 	char path[] = "test-personality-XXXXXX";
64 	int fd = mkstemp(path);
65 	TEST_ASSERT_TRUE(fd >= 0);
66 
67 	FILE *f = fdopen(fd, "w");
68 	TEST_ASSERT_NONNULL(f);
69 
70 	fprintf(f,
71 		"Triplet: x86_64-linux-musl\n"
72 		"DefaultSearchPaths: /usr/lib/pkgconfig:/usr/share/pkgconfig\n"
73 		"SysrootDir: /opt/sysroot\n"
74 		"SystemIncludePaths: /opt/sysroot/usr/include\n"
75 		"SystemLibraryPaths: /opt/sysroot/usr/lib\n"
76 		"WantDefaultStatic: true\n"
77 		"WantDefaultPure: yes\n");
78 	fclose(f);
79 
80 	pkgconf_cross_personality_t *p = pkgconf_cross_personality_find(path);
81 	TEST_ASSERT_NONNULL(p);
82 	TEST_ASSERT_STRCMP_EQ(p->name, "x86_64-linux-musl");
83 	TEST_ASSERT_NONNULL(p->sysroot_dir);
84 	TEST_ASSERT_STRCMP_EQ(p->sysroot_dir, "/opt/sysroot");
85 	TEST_ASSERT_TRUE(p->want_default_static);
86 	TEST_ASSERT_TRUE(p->want_default_pure);
87 	TEST_ASSERT_NONNULL(p->dir_list.head);
88 
89 	// Exercises the non-default free path
90 	pkgconf_cross_personality_deinit(p);
91 	unlink(path);
92 }
93 
94 #if !defined(_WIN32) && !defined(__HAIKU__)
95 
96 static void
test_personality_find_via_xdg(void)97 test_personality_find_via_xdg(void)
98 {
99 	char tmpdir[] = "test-personality-xdg-XXXXXX";
100 	char *d = mkdtemp(tmpdir);
101 	TEST_ASSERT_NONNULL(d);
102 
103 	// build: <tmpdir>/pkgconfig/personality.d/
104 	char pkgconfig_dir[4096];
105 	char personality_d[4096];
106 	char file_path[4096];
107 
108 	snprintf(pkgconfig_dir, sizeof pkgconfig_dir, "%s/pkgconfig", tmpdir);
109 	snprintf(personality_d, sizeof personality_d, "%s/pkgconfig/personality.d", tmpdir);
110 	snprintf(file_path, sizeof file_path, "%s/pkgconfig/personality.d/xdg-test-triplet.personality", tmpdir);
111 
112 	TEST_ASSERT_EQ(mkdir(pkgconfig_dir, 0755), 0);
113 	TEST_ASSERT_EQ(mkdir(personality_d, 0755), 0);
114 
115 	FILE *f = fopen(file_path, "w");
116 	TEST_ASSERT_NONNULL(f);
117 	fprintf(f, "SysrootDir: /xdg/sysroot\n");
118 	fclose(f);
119 
120 	setenv("XDG_DATA_HOME", tmpdir, 1);
121 
122 	pkgconf_cross_personality_t *p = pkgconf_cross_personality_find("xdg-test-triplet");
123 	TEST_ASSERT_NONNULL(p);
124 	TEST_ASSERT_NONNULL(p->sysroot_dir);
125 	TEST_ASSERT_STRCMP_EQ(p->sysroot_dir, "/xdg/sysroot");
126 
127 	// Verify it is NOT the default singleton
128 	pkgconf_cross_personality_t *def = pkgconf_cross_personality_default();
129 	TEST_ASSERT_NE((long long)(uintptr_t)p, (long long)(uintptr_t)def);
130 	// Balance the _default() call above
131 	pkgconf_cross_personality_deinit(def);
132 
133 	// Clean up
134 	pkgconf_cross_personality_deinit(p);
135 	unsetenv("XDG_DATA_HOME");
136 
137 	unlink(file_path);
138 	rmdir(personality_d);
139 	rmdir(pkgconfig_dir);
140 	rmdir(tmpdir);
141 }
142 
143 #endif // !_WIN32 && !__HAIKU__
144 
145 static void
test_personality_find_missing_returns_default(void)146 test_personality_find_missing_returns_default(void)
147 {
148 	// clear XDG / HOME so search goes to known-empty places
149 	unsetenv("XDG_DATA_HOME");
150 	unsetenv("XDG_DATA_DIRS");
151 	unsetenv("HOME");
152 
153 	pkgconf_cross_personality_t *found = pkgconf_cross_personality_find("nonexistent-triplet-xyzzy");
154 	TEST_ASSERT_NONNULL(found);
155 
156 	// The find internally called _default(); call it ourselves to compare
157 	pkgconf_cross_personality_t *def = pkgconf_cross_personality_default();
158 	TEST_ASSERT_EQ((long long)(uintptr_t)found, (long long)(uintptr_t)def);
159 
160 	// Two deinits: one for find's internal _default(), one for ours above
161 	pkgconf_cross_personality_deinit(found);
162 	pkgconf_cross_personality_deinit(def);
163 }
164 
165 #endif /* !PKGCONF_LITE */
166 
167 int
main(int argc,char * argv[])168 main(int argc, char *argv[])
169 {
170 	(void) argc;
171 	const char *basename = pkgconf_path_find_basename(argv[0]);
172 
173 	// refcount test must run first so the singleton starts at 0
174 	TEST_RUN(basename, test_personality_deinit_null);
175 	TEST_RUN(basename, test_personality_default_refcount);
176 
177 #ifndef PKGCONF_LITE
178 	TEST_RUN(basename, test_personality_find_invalid_triplet);
179 	TEST_RUN(basename, test_personality_find_direct_path);
180 #if !defined(_WIN32) && !defined(__HAIKU__)
181 	TEST_RUN(basename, test_personality_find_via_xdg);
182 #endif
183 	TEST_RUN(basename, test_personality_find_missing_returns_default);
184 #endif
185 
186 	return EXIT_SUCCESS;
187 }
188