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