YAC 3.21.0
Yet Another Coupler
Loading...
Searching...
No Matches
test_utils_common.c
Go to the documentation of this file.
1// Copyright (c) 2026 The YAC Authors
2//
3// SPDX-License-Identifier: BSD-3-Clause
4
5#include <limits.h>
6#include <mpi.h>
7#include <stdio.h>
8#include <stdlib.h>
9#include <string.h>
10
11#include "tests.h"
12#include "utils_common.h"
13
19static void utest_remove_duplicates_int(void);
20static void utest_name_type_pairs(void);
21static void utest_qsort_index(void);
22static void utest_getenv_bool(MPI_Comm comm);
23static void utest_getenv_int(MPI_Comm comm);
24static void utest_getenv_str(MPI_Comm comm);
25
26int main(void) {
27
28 MPI_Init(NULL, NULL);
29
30 int comm_size;
31 MPI_Comm_size(MPI_COMM_WORLD, &comm_size);
32
33 if (comm_size != 4) {
34 PUT_ERR("ERROR: test_utils_common requires exactly 4 MPI processes");
35 MPI_Finalize();
36 return TEST_EXIT_CODE;
37 }
38
39 utest_remove_duplicates_int();
40 utest_name_type_pairs();
41 utest_qsort_index();
42 utest_getenv_bool(MPI_COMM_WORLD);
43 utest_getenv_int(MPI_COMM_WORLD);
44 utest_getenv_str(MPI_COMM_WORLD);
45
46 MPI_Finalize();
47
48 return TEST_EXIT_CODE;
49}
50
51static int utest_compare_int(void const * a, void const * b) {
52
53 int aa = *(int const *)a;
54 int bb = *(int const *)b;
55
56 return (aa > bb) - (aa < bb);
57}
58
59static void utest_unsetenv_all(MPI_Comm comm, char const * name) {
60
61 unsetenv(name);
62
63 // synchronize all ranks to ensure that the environment variable is unset
64 MPI_Barrier(comm);
65}
66
67static void utest_setenv_all(
68 MPI_Comm comm, char const * name, char const * root_value,
69 char const * other_value) {
70
71 int rank;
72 MPI_Comm_rank(comm, &rank);
73
74 char const * value = (rank == 0)?root_value:other_value;
75
76 if (value != NULL) setenv(name, value, 1);
77 else unsetenv(name);
78
79 // synchronize all ranks to ensure that the environment variable is set
80 // before proceeding
81 MPI_Barrier(comm);
82}
83
84static void utest_remove_duplicates_int(void) {
85
86 { // test that empty input is handled correctly
87 int value = 42;
88 size_t n = 0;
90 if (n != 0) PUT_ERR("yac_remove_duplicates_int failed for empty input");
91 }
92
93 { // test that duplicates are removed
94 int values[] = {1, 1, 2, 2, 2, 4, 4, 7};
95 int ref[] = {1, 2, 4, 7};
96 size_t n = sizeof(values) / sizeof(values[0]);
97
98 yac_remove_duplicates_int(values, &n);
99
100 if (n != sizeof(ref) / sizeof(ref[0]))
101 PUT_ERR("yac_remove_duplicates_int produced wrong output length");
102 for (size_t i = 0; i < n; ++i)
103 if (values[i] != ref[i])
104 PUT_ERR("yac_remove_duplicates_int produced wrong output values");
105 }
106
107 { // test that unique input is unchanged
108 int values[] = {-2, -1, 0, 3};
109 int ref[] = {-2, -1, 0, 3};
110 size_t n = sizeof(values) / sizeof(values[0]);
111
112 yac_remove_duplicates_int(values, &n);
113
114 if (n != sizeof(ref) / sizeof(ref[0]))
115 PUT_ERR("yac_remove_duplicates_int changed unique input length");
116 for (size_t i = 0; i < n; ++i)
117 if (values[i] != ref[i])
118 PUT_ERR("yac_remove_duplicates_int changed unique input values");
119 }
120}
121
122static void utest_name_type_pairs(void) {
123
124 enum { alpha = -3, beta = 2, gamma = 2, invalid = 42 };
125
127 utest_name_type_table,
128 DEF_NAME_TYPE_PAIR(alpha, alpha),
129 DEF_NAME_TYPE_PAIR(beta, beta),
130 DEF_NAME_TYPE_PAIR(BETA, beta),
131 DEF_NAME_TYPE_PAIR(gamma, gamma));
132
133 // test valid input for yac_name_type_pair_get_name
134 // (should return the first matching name for a given type)
135 char const * name =
137 utest_name_type_table, utest_name_type_table_size, beta);
138 if ((name == NULL) || strcmp(name, "beta"))
139 PUT_ERR("yac_name_type_pair_get_name returned wrong result");
140
141 // test invalid input for yac_name_type_pair_get_name
143 utest_name_type_table, utest_name_type_table_size, invalid) != NULL)
144 PUT_ERR("yac_name_type_pair_get_name should return NULL for unknown type");
145
146 // test valid input for yac_name_type_pair_get_type
148 utest_name_type_table, utest_name_type_table_size, "alpha") != alpha)
149 PUT_ERR("yac_name_type_pair_get_type returned wrong result for alpha");
150
151 // test alternate name for beta
153 utest_name_type_table, utest_name_type_table_size, "BETA") != beta)
154 PUT_ERR("yac_name_type_pair_get_type returned wrong result for BETA");
155
156 // test invalid input for yac_name_type_pair_get_type
158 utest_name_type_table, utest_name_type_table_size, "invalid") !=
159 INT_MAX)
160 PUT_ERR("yac_name_type_pair_get_type should return INT_MAX for unknown names");
161
162 // test NULL input for yac_name_type_pair_get_type
164 utest_name_type_table, utest_name_type_table_size, NULL) != INT_MAX)
165 PUT_ERR("yac_name_type_pair_get_type should return INT_MAX for NULL input");
166}
167
168static void utest_qsort_index(void) {
169
170 { // test that values are sorted and index mapping is correct
171 int values[] = {5, 1, 3, 1, 4};
172 int ref[] = {5, 1, 3, 1, 4};
173 size_t idx[] = {0, 1, 2, 3, 4};
174 int const sorted_ref[] = {1, 1, 3, 4, 5};
175
177 values, sizeof(values) / sizeof(values[0]), sizeof(values[0]),
178 utest_compare_int, idx);
179
180 for (size_t i = 0; i < sizeof(values) / sizeof(values[0]); ++i)
181 if (values[i] != sorted_ref[i])
182 PUT_ERR("yac_qsort_index failed to sort values");
183
184 int seen[] = {0, 0, 0, 0, 0};
185 for (size_t i = 0; i < sizeof(idx) / sizeof(idx[0]); ++i) {
186 if (idx[i] >= sizeof(ref) / sizeof(ref[0])) {
187 PUT_ERR("yac_qsort_index returned out-of-range index");
188 continue;
189 }
190 if (seen[idx[i]]) PUT_ERR("yac_qsort_index returned duplicate index");
191 seen[idx[i]] = 1;
192 if (ref[idx[i]] != values[i])
193 PUT_ERR("yac_qsort_index index mapping does not match sorted values");
194 }
195 }
196
197 { // test that idx == NULL is handled correctly
198 int values[] = {3, 2, 1};
199 int const sorted_ref[] = {1, 2, 3};
200
202 values, sizeof(values) / sizeof(values[0]), sizeof(values[0]),
203 utest_compare_int, NULL);
204
205 for (size_t i = 0; i < sizeof(values) / sizeof(values[0]); ++i)
206 if (values[i] != sorted_ref[i])
207 PUT_ERR("yac_qsort_index failed for idx == NULL");
208 }
209}
210
211static void utest_getenv_bool(MPI_Comm comm) {
212
213 int rank;
214 MPI_Comm_rank(comm, &rank);
215
216 char const * env_name = "YAC_UTEST_BOOL";
217
218 { // test behaviour when environment variable is not set
219 utest_unsetenv_all(comm, env_name);
220 int value = yac_getenv_bool(env_name, 1, comm);
221 if (value != 1) PUT_ERR("yac_getenv_bool returned wrong default value");
222 }
223
224 { // test behaviour when environment variable is only set on non-root ranks
225 utest_setenv_all(comm, env_name, NULL, "on");
226 int value = yac_getenv_bool(env_name, 0, comm);
227 if (value != 0)
228 PUT_ERR("yac_getenv_bool returned wrong value for unset on root");
229 }
230
231 { // test behaviour when environment variable is only set on root rank
232 utest_setenv_all(comm, env_name, "on", NULL);
233 int value = yac_getenv_bool(env_name, 0, comm);
234 if (value != 1)
235 PUT_ERR("yac_getenv_bool returned wrong value for unset on non-root");
236
237 }
238
239 { // test behaviour when environment variable is set to "on" on root and
240 // "off" on non-root ranks
241 utest_setenv_all(comm, env_name, "on", "off");
242 int value = yac_getenv_bool(env_name, 0, comm);
243 if (value != 1) PUT_ERR("yac_getenv_bool returned wrong value for 'on'");
244 }
245
246 { // test behaviour when environment variable is set to "off" on root and
247 // "on" on non-root ranks
248 utest_setenv_all(comm, env_name, "off", "on");
249 int value = yac_getenv_bool(env_name, 1, comm);
250 if (value != 0) PUT_ERR("yac_getenv_bool returned wrong value for 'off'");
251 }
252
253 // TODO: enable once support for testing of unhappy path is supported
254 // { // test behaviour when environment variable is set to an invalid value
255 // utest_setenv_all(comm, env_name, "invalid", "on");
256 // int value = yac_getenv_bool(env_name, 0, comm);
257 // if (value != 0)
258 // PUT_ERR("yac_getenv_bool returned wrong value for invalid input");
259 // }
260
261 utest_unsetenv_all(comm, env_name);
262}
263
264static void utest_getenv_int(MPI_Comm comm) {
265
266 int rank;
267 MPI_Comm_rank(comm, &rank);
268
269 char const * env_name = "YAC_UTEST_INT";
270
271 { // test behaviour when environment variable is not set
272 utest_unsetenv_all(comm, env_name);
273 int value = yac_getenv_int(env_name, 7, 0, comm);
274 if (value != 7) PUT_ERR("yac_getenv_int returned wrong default value");
275 }
276
277 { // test behaviour when environment variable is only set on non-root ranks
278 utest_setenv_all(comm, env_name, NULL, "12");
279 int value = yac_getenv_int(env_name, 7, 0, comm);
280 if (value != 7)
281 PUT_ERR("yac_getenv_int returned wrong value for unset on root");
282 }
283
284 { // test behaviour when environment variable is only set on root rank
285 utest_setenv_all(comm, env_name, "12", NULL);
286 int value = yac_getenv_int(env_name, 7, 0, comm);
287 if (value != 12)
288 PUT_ERR("yac_getenv_int returned wrong value for unset on non-root");
289 }
290
291 { // test behaviour when environment variable is set to a value below the
292 // threshold
293 utest_setenv_all(comm, env_name, "2", "2");
294 int value = yac_getenv_int(env_name, 7, 3, comm);
295 if (value != 7)
296 PUT_ERR("yac_getenv_int returned wrong value for below threshold");
297 }
298
299 { // test behavioud when environment variable is set to different values on
300 // all ranks (to local rank)
301 char str_rank[16];
302 snprintf(str_rank, sizeof(str_rank), "%d", rank);
303 utest_setenv_all(comm, env_name, str_rank, str_rank);
304 int value = yac_getenv_int(env_name, 7, 0, comm);
305 if (value != 0)
306 PUT_ERR("yac_getenv_int returned wrong value for rank-dependent input");
307 }
308
309 // TODO: enable once support for testing of unhappy path is supported
310 // { // test behaviour when environment variable is set to an invalid value
311 // utest_setenv_all(comm, env_name, "invalid", "12");
312 // int value = yac_getenv_int(env_name, 7, 0, comm);
313 // if (value != 7)
314 // PUT_ERR("yac_getenv_int returned wrong value for invalid input");
315 // }
316
317 utest_unsetenv_all(comm, env_name);
318}
319
320static void utest_getenv_str(MPI_Comm comm) {
321
322 int rank;
323 MPI_Comm_rank(comm, &rank);
324
325 char const * env_name = "YAC_UTEST_STR";
326
327 { // test behaviour when environment variable is not set
328 utest_unsetenv_all(comm, env_name);
329 char * str_value = yac_getenv_str(env_name, "fallback", comm);
330 if ((str_value == NULL) || strcmp(str_value, "fallback"))
331 PUT_ERR("yac_getenv_str returned wrong default value");
332 free(str_value);
333 }
334
335 { // test behaviour when environment variable is set to an empty string
336 utest_setenv_all(comm, env_name, "", "");
337 char * str_value = yac_getenv_str(env_name, "fallback", comm);
338 if ((str_value == NULL) || strcmp(str_value, "fallback"))
339 PUT_ERR("yac_getenv_str returned wrong value for empty string");
340 free(str_value);
341 }
342
343 { // test behaviour when environment variable is set to a non-empty string
344 utest_setenv_all(comm, env_name, "root_value", "other_value");
345 char * str_value = yac_getenv_str(env_name, "fallback", comm);
346 if ((str_value == NULL) || strcmp(str_value, "root_value"))
347 PUT_ERR("yac_getenv_str returned wrong value for non-empty string");
348 free(str_value);
349 }
350
351 { // test behaviour when environment variable is set to an empty string on
352 // root and a non-empty string on non-root ranks
353 utest_setenv_all(comm, env_name, "", "other_value");
354 char * str_value = yac_getenv_str(env_name, "fallback", comm);
355 if ((str_value == NULL) || strcmp(str_value, "fallback"))
356 PUT_ERR(
357 "yac_getenv_str returned wrong value for empty string on root");
358 free(str_value);
359 }
360
361 { // test behaviour when environment variable is set to a non-empty string on
362 // root and an empty string on non-root ranks
363 utest_setenv_all(comm, env_name, "root_value", "");
364 char * str_value = yac_getenv_str(env_name, "fallback", comm);
365 if ((str_value == NULL) || strcmp(str_value, "root_value"))
366 PUT_ERR(
367 "yac_getenv_str returned wrong value for empty string on non-root");
368 free(str_value);
369
370 }
371
372 { // test behaviour when environment variable is only set on non-root ranks
373 utest_setenv_all(comm, env_name, NULL, "other_value");
374 char * str_value = yac_getenv_str(env_name, "fallback", comm);
375 if ((str_value == NULL) || strcmp(str_value, "fallback"))
376 PUT_ERR("yac_getenv_str returned wrong value for unset on root");
377 free(str_value);
378 }
379
380 { // test behaviour when environment variable is only set on root rank
381 utest_setenv_all(comm, env_name, "root_value", NULL);
382 char * str_value = yac_getenv_str(env_name, "fallback", comm);
383 if ((str_value == NULL) || strcmp(str_value, "root_value"))
384 PUT_ERR("yac_getenv_str returned wrong value for unset on non-root");
385 free(str_value);
386
387 }
388
389 utest_unsetenv_all(comm, env_name);
390}
int yac_name_type_pair_get_type(struct yac_name_type_pair const *pairs, size_t count, char const *name)
Definition utils_core.c:23
#define DEF_NAME_TYPE_PAIR(NAME, TYPE)
char const * yac_name_type_pair_get_name(struct yac_name_type_pair const *pairs, size_t count, int type)
Definition utils_core.c:14
#define DEF_NAME_TYPE_PAIRS(NAME,...)
struct @23::@24 value
void yac_qsort_index(void *a_, size_t count, size_t size, int(*compare)(void const *, void const *), size_t *idx)
Definition quicksort.c:185
#define TEST_EXIT_CODE
Definition tests.h:15
#define PUT_ERR(string)
Definition tests.h:10
char const * name
Definition toy_scrip.c:114
int yac_getenv_int(const char *name, int default_value, int threshold, MPI_Comm comm)
Definition utils_core.c:89
static void yac_remove_duplicates_int(int *array, size_t *n)
int yac_getenv_bool(const char *name, int default_value, MPI_Comm comm)
char * yac_getenv_str(const char *name, const char *default_value, MPI_Comm comm)
Definition utils_core.c:125