coreutils / tests /env /tests_for_unset_envvars.c
AryaWu's picture
Upload folder using huggingface_hub
78d2150 verified
#include "../../unity/unity.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
#include <errno.h>
/* Note:
- This test file is included at the end of env.c, so it shares the same
translation unit and can access the static symbols:
- usvars, usvars_used, usvars_alloc
- unset_envvars()
- We only manipulate usvars/usvars_used/usvars_alloc; we do not redefine any
symbol from the program.
*/
static char const **allocated_usvars = NULL; /* Track array we allocate for cleanup */
/* Helper: set the list of variables to unset. Copies the pointer list, not the strings. */
static void prepare_usvars_list(char const *const *list, size_t count)
{
/* Free any prior allocation from a previous test run */
if (allocated_usvars)
{
free((void *)allocated_usvars);
allocated_usvars = NULL;
}
if (count == 0 || list == NULL)
{
usvars = NULL;
usvars_used = 0;
usvars_alloc = 0;
return;
}
char const **arr = (char const **)malloc(sizeof(char const *) * count);
TEST_ASSERT_NOT_NULL(arr);
for (size_t i = 0; i < count; i++)
arr[i] = list[i];
usvars = arr;
usvars_used = (typeof(usvars_used))count;
usvars_alloc = (typeof(usvars_alloc))count;
allocated_usvars = arr;
}
/* Helper: make a unique environment variable name. Caller frees the returned string. */
static char *make_unique_name(const char *prefix)
{
char buf[128];
static unsigned counter = 0;
snprintf(buf, sizeof buf, "%s_%ld_%u", prefix, (long)getpid(), ++counter);
return strdup(buf);
}
void setUp(void)
{
/* Reset our managed allocation; program globals will be set per-test */
if (allocated_usvars)
{
free((void *)allocated_usvars);
allocated_usvars = NULL;
}
usvars = NULL;
usvars_used = 0;
usvars_alloc = 0;
}
void tearDown(void)
{
if (allocated_usvars)
{
free((void *)allocated_usvars);
allocated_usvars = NULL;
}
/* Leave environment as modified by the test; each test sets/clears variables it needs */
}
/* Test: unsetting a single existing variable removes it from the environment. */
static void test_unset_envvars_single_existing(void)
{
char *name = make_unique_name("ENV_TEST_ONE");
TEST_ASSERT_NOT_NULL(name);
/* Ensure the variable exists */
TEST_ASSERT_EQUAL_INT(0, setenv(name, "value", 1));
TEST_ASSERT_NOT_NULL(getenv(name));
char const *list[] = { name };
prepare_usvars_list(list, 1);
unset_envvars();
TEST_ASSERT_NULL(getenv(name));
free(name);
}
/* Test: unsetting multiple variables including one that does not exist. */
static void test_unset_envvars_multiple_existing_and_nonexistent(void)
{
char *n1 = make_unique_name("ENV_TEST_MULTI1");
char *n2 = make_unique_name("ENV_TEST_MULTI2");
char *n3 = make_unique_name("ENV_TEST_MULTI3_NOEXIST");
TEST_ASSERT_NOT_NULL(n1);
TEST_ASSERT_NOT_NULL(n2);
TEST_ASSERT_NOT_NULL(n3);
/* Create two variables, leave third non-existent */
TEST_ASSERT_EQUAL_INT(0, setenv(n1, "v1", 1));
TEST_ASSERT_EQUAL_INT(0, setenv(n2, "v2", 1));
TEST_ASSERT_NOT_NULL(getenv(n1));
TEST_ASSERT_NOT_NULL(getenv(n2));
TEST_ASSERT_NULL(getenv(n3));
char const *list[] = { n1, n2, n3 };
prepare_usvars_list(list, 3);
unset_envvars();
TEST_ASSERT_NULL(getenv(n1));
TEST_ASSERT_NULL(getenv(n2));
TEST_ASSERT_NULL(getenv(n3));
free(n1);
free(n2);
free(n3);
}
/* Test: unsetting a non-existent variable should not error and should remain non-existent. */
static void test_unset_envvars_nonexistent_only(void)
{
char *name = make_unique_name("ENV_TEST_NOEXIST");
TEST_ASSERT_NOT_NULL(name);
/* Ensure it does not exist */
unsetenv(name);
TEST_ASSERT_NULL(getenv(name));
char const *list[] = { name };
prepare_usvars_list(list, 1);
unset_envvars();
TEST_ASSERT_NULL(getenv(name));
free(name);
}
/* Test: empty unset list should be a no-op (does not unset other variables). */
static void test_unset_envvars_empty_list_noop(void)
{
char *persist = make_unique_name("ENV_TEST_PERSIST");
TEST_ASSERT_NOT_NULL(persist);
TEST_ASSERT_EQUAL_INT(0, setenv(persist, "keep", 1));
TEST_ASSERT_NOT_NULL(getenv(persist));
prepare_usvars_list(NULL, 0); /* No variables to unset */
unset_envvars();
TEST_ASSERT_NOT_NULL(getenv(persist));
/* Cleanup: remove the variable we created */
TEST_ASSERT_EQUAL_INT(0, unsetenv(persist));
TEST_ASSERT_NULL(getenv(persist));
free(persist);
}
/* Test: invalid variable name (contains '=') should cause error() to exit with EXIT_CANCELED.
Run in a child process to avoid terminating the whole test runner. */
static void test_unset_envvars_invalid_name_triggers_error(void)
{
fflush(stdout);
fflush(stderr);
pid_t pid = fork();
TEST_ASSERT_MESSAGE(pid >= 0, "fork() failed");
if (pid == 0)
{
/* Child: set invalid name and call function; should exit via error(). */
char const *list[] = { "BAD=NAME" };
prepare_usvars_list(list, 1);
/* Calling unset_envvars should invoke error(EXIT_CANCELED, ...) and exit. */
unset_envvars();
/* If we get here, it did not exit as expected. Use a distinct exit code. */
_exit(0xEE);
}
int status = 0;
pid_t w = waitpid(pid, &status, 0);
TEST_ASSERT_EQUAL_INT(pid, w);
TEST_ASSERT_TRUE(WIFEXITED(status));
int es = WEXITSTATUS(status);
/* EXIT_CANCELED is available from the program's headers included earlier. */
TEST_ASSERT_EQUAL_INT(EXIT_CANCELED, es);
}
int main(void)
{
UNITY_BEGIN();
RUN_TEST(test_unset_envvars_single_existing);
RUN_TEST(test_unset_envvars_multiple_existing_and_nonexistent);
RUN_TEST(test_unset_envvars_nonexistent_only);
RUN_TEST(test_unset_envvars_empty_list_noop);
RUN_TEST(test_unset_envvars_invalid_name_triggers_error);
return UNITY_END();
}