| //===----------------------------------------------------------------------===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| /// |
| /// \file |
| /// Integration tests for putenv. |
| /// |
| //===----------------------------------------------------------------------===// |
| |
| #include "src/stdlib/getenv.h" |
| #include "src/stdlib/putenv.h" |
| #include "src/unistd/environ.h" |
| |
| #include "test/IntegrationTest/test.h" |
| |
| #include <errno.h> |
| |
| static char set_var[] = "PUTENV_TEST=hello"; |
| static char replace_var[] = "PUTENV_TEST=world"; |
| static char empty_value[] = "PUTENV_EMPTY="; |
| static char special_chars[] = "PUTENV_SPECIAL=!@#$%^&*()"; |
| |
| TEST_MAIN() { |
| // Test: Basic set |
| { |
| ASSERT_EQ(LIBC_NAMESPACE::putenv(set_var), 0); |
| char *value = LIBC_NAMESPACE::getenv("PUTENV_TEST"); |
| ASSERT_TRUE(value != nullptr); |
| ASSERT_STREQ(value, "hello"); |
| } |
| |
| // Test: Overwrite existing variable |
| { |
| ASSERT_EQ(LIBC_NAMESPACE::putenv(replace_var), 0); |
| char *value = LIBC_NAMESPACE::getenv("PUTENV_TEST"); |
| ASSERT_TRUE(value != nullptr); |
| ASSERT_STREQ(value, "world"); |
| } |
| |
| // Test: The pointer itself is used (not a copy) |
| { |
| // After putenv, getenv should return a pointer into the original string. |
| char *value = LIBC_NAMESPACE::getenv("PUTENV_TEST"); |
| ASSERT_TRUE(value == replace_var + 12); // "PUTENV_TEST=" is 12 chars |
| } |
| |
| // Test: Empty value |
| { |
| ASSERT_EQ(LIBC_NAMESPACE::putenv(empty_value), 0); |
| char *value = LIBC_NAMESPACE::getenv("PUTENV_EMPTY"); |
| ASSERT_TRUE(value != nullptr); |
| ASSERT_STREQ(value, ""); |
| } |
| |
| // Test: Special characters in value |
| { |
| ASSERT_EQ(LIBC_NAMESPACE::putenv(special_chars), 0); |
| char *value = LIBC_NAMESPACE::getenv("PUTENV_SPECIAL"); |
| ASSERT_TRUE(value != nullptr); |
| ASSERT_STREQ(value, "!@#$%^&*()"); |
| } |
| |
| // Test: No '=' removes the variable (POSIX behavior) |
| { |
| // First set a variable via putenv |
| static char var_to_remove[] = "REMOVE_ME=present"; |
| ASSERT_EQ(LIBC_NAMESPACE::putenv(var_to_remove), 0); |
| ASSERT_TRUE(LIBC_NAMESPACE::getenv("REMOVE_ME") != nullptr); |
| |
| // Now call putenv without '=' to remove it |
| static char remove_cmd[] = "REMOVE_ME"; |
| ASSERT_EQ(LIBC_NAMESPACE::putenv(remove_cmd), 0); |
| ASSERT_TRUE(LIBC_NAMESPACE::getenv("REMOVE_ME") == nullptr); |
| } |
| |
| // Test: environ is updated and contains the exact pointer |
| { |
| bool found = false; |
| for (char **env = LIBC_NAMESPACE::environ; *env != nullptr; ++env) { |
| if (*env == replace_var) { |
| found = true; |
| break; |
| } |
| } |
| ASSERT_TRUE(found); |
| } |
| |
| // Test: Pathological inputs (empty names, empty string) are allowed to match |
| // glibc. |
| { |
| // Empty name with value (=value) should succeed and be found in environ. |
| static char empty_name[] = "=value"; |
| ASSERT_EQ(LIBC_NAMESPACE::putenv(empty_name), 0); |
| bool found = false; |
| for (char **env = LIBC_NAMESPACE::environ; *env != nullptr; ++env) { |
| if (*env == empty_name) { |
| found = true; |
| break; |
| } |
| } |
| ASSERT_TRUE(found); |
| |
| // Just "=" should succeed and be found in environ. |
| static char just_equals[] = "="; |
| ASSERT_EQ(LIBC_NAMESPACE::putenv(just_equals), 0); |
| found = false; |
| for (char **env = LIBC_NAMESPACE::environ; *env != nullptr; ++env) { |
| if (*env == just_equals) { |
| found = true; |
| break; |
| } |
| } |
| ASSERT_TRUE(found); |
| |
| // Empty string unsets the empty name. |
| static char empty_string[] = ""; |
| ASSERT_EQ(LIBC_NAMESPACE::putenv(empty_string), 0); |
| // Verify "=value" is no longer in environ (it should have been unset). |
| found = false; |
| for (char **env = LIBC_NAMESPACE::environ; *env != nullptr; ++env) { |
| if (*env == empty_name) { |
| found = true; |
| break; |
| } |
| } |
| ASSERT_FALSE(found); |
| } |
| |
| return 0; |
| } |