1 /* 2 * test-license.c 3 * Tests for the public libpkgconf license 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 static size_t 21 license_count(const pkgconf_list_t *list) 22 { 23 size_t n = 0; 24 const pkgconf_node_t *iter; 25 26 PKGCONF_FOREACH_LIST_ENTRY(list->head, iter) 27 { 28 n++; 29 } 30 31 return n; 32 } 33 34 static char * 35 render_to_string(pkgconf_client_t *client, const pkgconf_list_t *list) 36 { 37 pkgconf_buffer_t buf = PKGCONF_BUFFER_INITIALIZER; 38 pkgconf_license_render(client, list, &buf); 39 40 char *out = strdup(pkgconf_buffer_str_or_empty(&buf)); 41 pkgconf_buffer_finalize(&buf); 42 return out; 43 } 44 45 static void 46 test_license_insert_and_free(void) 47 { 48 pkgconf_client_t *client = test_client_new(); 49 pkgconf_list_t licenses = PKGCONF_LIST_INITIALIZER; 50 51 pkgconf_license_insert(client, &licenses, PKGCONF_LICENSE_EXPRESSION, "BSD-3-Clause"); 52 TEST_ASSERT_EQ(license_count(&licenses), 1); 53 54 const pkgconf_license_t *l = licenses.head->data; 55 TEST_ASSERT_NONNULL(l); 56 TEST_ASSERT_EQ(l->type, PKGCONF_LICENSE_EXPRESSION); 57 TEST_ASSERT_STRCMP_EQ(l->data, "BSD-3-Clause"); 58 59 pkgconf_license_free(&licenses); 60 pkgconf_client_free(client); 61 } 62 63 static void 64 test_license_free_empty(void) 65 { 66 pkgconf_list_t licenses = PKGCONF_LIST_INITIALIZER; 67 68 // Freeing an empty list is a no-op. Smoke test. 69 pkgconf_license_free(&licenses); 70 71 // Smoke test 72 pkgconf_license_free(NULL); 73 } 74 75 static void 76 test_license_evaluate_single(void) 77 { 78 pkgconf_client_t *client = test_client_new(); 79 pkgconf_list_t licenses = PKGCONF_LIST_INITIALIZER; 80 81 pkgconf_license_evaluate_str(client, &licenses, "BSD-3-Clause", 0); 82 83 TEST_ASSERT_EQ(license_count(&licenses), 1); 84 const pkgconf_license_t *l = licenses.head->data; 85 TEST_ASSERT_EQ(l->type, PKGCONF_LICENSE_EXPRESSION); 86 TEST_ASSERT_STRCMP_EQ(l->data, "BSD-3-Clause"); 87 88 pkgconf_license_free(&licenses); 89 pkgconf_client_free(client); 90 } 91 92 static void 93 test_license_evaluate_or(void) 94 { 95 pkgconf_client_t *client = test_client_new(); 96 pkgconf_list_t licenses = PKGCONF_LIST_INITIALIZER; 97 98 pkgconf_license_evaluate_str(client, &licenses, "MIT OR ISC", 0); 99 100 TEST_ASSERT_EQ(license_count(&licenses), 3); 101 102 char *rendered = render_to_string(client, &licenses); 103 TEST_ASSERT_STRCMP_EQ(rendered, "MIT OR ISC"); 104 free(rendered); 105 106 pkgconf_license_free(&licenses); 107 pkgconf_client_free(client); 108 } 109 110 static void 111 test_license_evaluate_and(void) 112 { 113 pkgconf_client_t *client = test_client_new(); 114 pkgconf_list_t licenses = PKGCONF_LIST_INITIALIZER; 115 116 pkgconf_license_evaluate_str(client, &licenses, "LGPL-2.1-only AND MIT", 0); 117 118 char *rendered = render_to_string(client, &licenses); 119 TEST_ASSERT_STRCMP_EQ(rendered, "LGPL-2.1-only AND MIT"); 120 free(rendered); 121 122 pkgconf_license_free(&licenses); 123 pkgconf_client_free(client); 124 } 125 126 static void 127 test_license_evaluate_multiple_keys_implicit_and(void) 128 { 129 pkgconf_client_t *client = test_client_new(); 130 pkgconf_list_t licenses = PKGCONF_LIST_INITIALIZER; 131 132 pkgconf_license_evaluate_str(client, &licenses, "BSD-3-Clause", 0); 133 pkgconf_license_evaluate_str(client, &licenses, "BSD-2-Clause", 0); 134 135 char *rendered = render_to_string(client, &licenses); 136 TEST_ASSERT_STRCMP_EQ(rendered, "BSD-3-Clause AND BSD-2-Clause"); 137 free(rendered); 138 139 pkgconf_license_free(&licenses); 140 pkgconf_client_free(client); 141 } 142 143 static void 144 test_license_evaluate_brackets(void) 145 { 146 pkgconf_client_t *client = test_client_new(); 147 pkgconf_list_t licenses = PKGCONF_LIST_INITIALIZER; 148 149 pkgconf_license_evaluate_str(client, &licenses, "ISC AND (BSD-3-Clause AND BSD-2-Clause)", 0); 150 151 char *rendered = render_to_string(client, &licenses); 152 TEST_ASSERT_STRCMP_EQ(rendered, "ISC AND (BSD-3-Clause AND BSD-2-Clause)"); 153 free(rendered); 154 155 pkgconf_license_free(&licenses); 156 pkgconf_client_free(client); 157 } 158 159 static void 160 test_license_evaluate_empty(void) 161 { 162 pkgconf_client_t *client = test_client_new(); 163 pkgconf_list_t licenses = PKGCONF_LIST_INITIALIZER; 164 165 pkgconf_license_evaluate_str(client, &licenses, "", 0); 166 TEST_ASSERT_EQ(license_count(&licenses), 0); 167 168 pkgconf_license_free(&licenses); 169 pkgconf_client_free(client); 170 } 171 172 static void 173 test_license_evaluate_sanitizes(void) 174 { 175 pkgconf_client_t *client = test_client_new(); 176 pkgconf_list_t licenses = PKGCONF_LIST_INITIALIZER; 177 178 /* The sanitiser strips characters outside the allowed set 179 * (alnum, '-', '+', '(', ')', '.', ':'). A token of pure 180 * junk should sanitise to empty and be skipped. */ 181 pkgconf_license_evaluate_str(client, &licenses, "BSD-3-Clause", 0); 182 183 const pkgconf_license_t *l = licenses.head->data; 184 TEST_ASSERT_STRCMP_EQ(l->data, "BSD-3-Clause"); 185 186 pkgconf_license_free(&licenses); 187 pkgconf_client_free(client); 188 } 189 190 static void 191 test_license_render_empty(void) 192 { 193 pkgconf_client_t *client = test_client_new(); 194 pkgconf_list_t licenses = PKGCONF_LIST_INITIALIZER; 195 196 char *rendered = render_to_string(client, &licenses); 197 TEST_ASSERT_EMPTY_STRING(rendered); 198 free(rendered); 199 200 pkgconf_license_free(&licenses); 201 pkgconf_client_free(client); 202 } 203 204 static void 205 test_license_render_single(void) 206 { 207 pkgconf_client_t *client = test_client_new(); 208 pkgconf_list_t licenses = PKGCONF_LIST_INITIALIZER; 209 210 pkgconf_license_insert(client, &licenses, PKGCONF_LICENSE_EXPRESSION, "MIT"); 211 212 char *rendered = render_to_string(client, &licenses); 213 TEST_ASSERT_STRCMP_EQ(rendered, "MIT"); 214 free(rendered); 215 216 pkgconf_license_free(&licenses); 217 pkgconf_client_free(client); 218 } 219 220 static void 221 test_license_copy_list(void) 222 { 223 pkgconf_client_t *client = test_client_new(); 224 pkgconf_list_t src = PKGCONF_LIST_INITIALIZER; 225 pkgconf_list_t dst = PKGCONF_LIST_INITIALIZER; 226 227 pkgconf_license_evaluate_str(client, &src, "MIT OR ISC", 0); 228 size_t src_count = license_count(&src); 229 230 pkgconf_license_copy_list(client, &dst, &src); 231 TEST_ASSERT_EQ(license_count(&dst), src_count); 232 233 /* The copy is independent: freeing the source must not affect 234 * the destination's rendered output. */ 235 pkgconf_license_free(&src); 236 237 char *rendered = render_to_string(client, &dst); 238 TEST_ASSERT_STRCMP_EQ(rendered, "MIT OR ISC"); 239 free(rendered); 240 241 pkgconf_license_free(&dst); 242 pkgconf_client_free(client); 243 } 244 245 static void 246 test_license_evaluate_long_sanitized_token(void) 247 { 248 pkgconf_client_t *client = test_client_new(); 249 pkgconf_list_t licenses = PKGCONF_LIST_INITIALIZER; 250 251 char token[512]; 252 token[0] = 'A'; 253 memset(token + 1, '_', 400); 254 token[401] = '\0'; 255 256 pkgconf_license_evaluate_str(client, &licenses, token, 0); 257 258 TEST_ASSERT_EQ(license_count(&licenses), 1); 259 const pkgconf_license_t *l = licenses.head->data; 260 TEST_ASSERT_EQ(l->type, PKGCONF_LICENSE_EXPRESSION); 261 TEST_ASSERT_STRCMP_EQ(l->data, "A"); 262 263 pkgconf_license_free(&licenses); 264 pkgconf_client_free(client); 265 } 266 267 static void 268 test_license_evaluate_unterminated_quote(void) 269 { 270 pkgconf_client_t *client = test_client_new(); 271 pkgconf_list_t licenses = PKGCONF_LIST_INITIALIZER; 272 273 pkgconf_license_evaluate_str(client, &licenses, "\"", 0); 274 TEST_ASSERT_EQ(license_count(&licenses), 0); 275 276 pkgconf_license_evaluate_str(client, &licenses, "MIT \"unterminated", 0); 277 TEST_ASSERT_EQ(license_count(&licenses), 0); 278 279 pkgconf_license_evaluate_str(client, &licenses, "\\", 0); 280 TEST_ASSERT_EQ(license_count(&licenses), 0); 281 282 pkgconf_license_free(&licenses); 283 pkgconf_client_free(client); 284 } 285 286 int 287 main(int argc, char *argv[]) 288 { 289 (void) argc; 290 const char *basename = pkgconf_path_find_basename(argv[0]); 291 292 TEST_RUN(basename, test_license_insert_and_free); 293 TEST_RUN(basename, test_license_free_empty); 294 295 TEST_RUN(basename, test_license_evaluate_single); 296 TEST_RUN(basename, test_license_evaluate_or); 297 TEST_RUN(basename, test_license_evaluate_and); 298 TEST_RUN(basename, test_license_evaluate_multiple_keys_implicit_and); 299 TEST_RUN(basename, test_license_evaluate_brackets); 300 TEST_RUN(basename, test_license_evaluate_empty); 301 TEST_RUN(basename, test_license_evaluate_sanitizes); 302 TEST_RUN(basename, test_license_evaluate_long_sanitized_token); 303 TEST_RUN(basename, test_license_evaluate_unterminated_quote); 304 305 TEST_RUN(basename, test_license_render_empty); 306 TEST_RUN(basename, test_license_render_single); 307 308 TEST_RUN(basename, test_license_copy_list); 309 310 return EXIT_SUCCESS; 311 } 312