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 21 test_personality_deinit_null(void) 22 { 23 // Should not crash 24 pkgconf_cross_personality_deinit(NULL); 25 } 26 27 static 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 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 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 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 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 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