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