Add the unit tests for f_environment.
The new function f_environment_secure_is() brings in libcap dependency requirements to f_environment.
This is added to add support for something similar to secure_getenv() rather than wrapping a non-standard method.
I am still not very experience with capabilities and do not guarantee an accurate replacement for secure_getenv().
Replace F_valid_not error returns with F_parameter error returns.
}
#endif // _di_f_environment_get_
+#ifndef _di_f_environment_secure_is_
+ f_status_t f_environment_secure_is(void) {
+
+ if (geteuid() == getuid() && getegid() == getgid()) {
+ return F_true;
+ }
+
+ #ifndef _di_libcap_
+ cap_t capability = cap_get_proc();
+
+ if (!capability) {
+ if (errno == EINVAL) return F_status_set_error(F_parameter);
+ if (errno == EPERM) return F_status_set_error(F_prohibited);
+ if (errno == ENOMEM) return F_status_set_error(F_memory_not);
+
+ return F_status_set_error(F_failure);
+ }
+
+ cap_flag_value_t value;
+
+ memset(&value, 0, sizeof(cap_flag_value_t));
+
+ if (cap_get_flag(capability, CAP_SETUID, CAP_EFFECTIVE, &value) == -1) {
+ cap_free(capability);
+
+ if (errno == EINVAL) return F_status_set_error(F_parameter);
+
+ return F_status_set_error(F_failure);
+ }
+
+ cap_free(capability);
+
+ if (value == CAP_SET) {
+ return F_true;
+ }
+ #endif // _di_libcap_
+
+ return F_false;
+ }
+#endif // _di_f_environment_secure_is_
+
#ifndef _di_f_environment_set_
f_status_t f_environment_set(const f_string_static_t name, const f_string_static_t value, const bool replace) {
}
if (setenv(name.string, value.string, replace) < 0) {
- if (errno == EINVAL) return F_status_set_error(F_valid_not);
+ if (errno == EINVAL) return F_status_set_error(F_parameter);
if (errno == ENOMEM) return F_status_set_error(F_memory_not);
return F_status_set_error(F_failure);
}
if (unsetenv(name.string) < 0) {
- if (errno == EINVAL) return F_status_set_error(F_valid_not);
+ if (errno == EINVAL) return F_status_set_error(F_parameter);
if (errno == ENOMEM) return F_status_set_error(F_memory_not);
return F_status_set_error(F_failure);
// Libc includes.
#include <stdio.h>
+#include <unistd.h>
#include <sys/stat.h>
+#include <sys/types.h>
+
+#ifndef _di_libcap_
+ #include <sys/capability.h>
+#endif // _di_libcap_
// FLL-0 includes.
#include <fll/level_0/type.h>
#endif // _di_f_environment_get_
/**
+ * Check to see if the environment is secure for calling getenv() safely for "secure execution".
+ *
+ * This is intended to closely mimic the checks secure_getenv().
+ *
+ * Any of these conditions must be true for secure environment:
+ * - The process' effective UID matches the real UID and the effective GID matches the real GID.
+ * - The process has the effective CAP_SETUID set.
+ *
+ * The documentation for secure_getenv() is unclear on which capabilities are expected to be set.
+ * This takes a conservative approach and only returns true for the above mentioned capabilities.
+ *
+ * @return
+ * F_true if the environment is secure according to the described rules.
+ * F_false if the environment is not secure according to the described rules.
+ *
+ * F_memory_not (with error bit) on out of memory.
+ * F_parameter (with error bit) if name is an invalid string.
+ * F_prohibited (with error bit) if the file system does not permit this operation (usually due to the cap_get_proc() call).
+ *
+ * F_failure (with error bit) on any other error.
+ *
+ * @see cap_get_flag()
+ * @see cap_get_proc()
+ * @see getegid()
+ * @see geteuid()
+ * @see getgid()
+ * @see getuid()
+ */
+#ifndef _di_f_environment_secure_is_
+ extern f_status_t f_environment_secure_is(void);
+#endif // _di_f_environment_secure_is_
+
+/**
* Assign the given value to the named environment variable.
*
* If the name does not exist, then it is created.
* F_data_not if name.used is 0.
*
* F_memory_not (with error bit) on out of memory.
- * F_valid_not (with error bit) if name is an invalid string.
+ * F_parameter (with error bit) if name is an invalid string.
+ *
* F_failure (with error bit) on any other error.
*
* @see setenv()
* F_data_not if name.used is 0.
*
* F_memory_not (with error bit) on out of memory.
- * F_valid_not (with error bit) if name is an invalid string.
+ * F_parameter (with error bit) if name is an invalid string.
+ *
* F_failure (with error bit) on any other error.
*
* @see unsetenv()
# fss-0000
+_di_libcap_ Disable libcap support, allow for compiling and linking without libcap (-lcap).
--- /dev/null
+# fss-0001
+
+cmocka 1.*
build_indexer_arguments rcs
build_language c
-build_libraries -lc
+build_libraries -lc -lcap
build_libraries-individual -lf_memory -lf_string
build_sources_library environment.c
search_shared yes
search_static yes
+#defines -D_di_libcap_
+
flags -O2 -z now -g -fdiagnostics-color=always -Wno-logical-not-parentheses -Wno-parentheses
flags-clang -Wno-logical-op-parentheses
flags-test -fstack-protector
--- /dev/null
+# fss-0001
+#
+# Build the project with appropriate mocks linked in via the dynamic linker's "--wrap" functionality.
+#
+# The -Wl,--wrap does not work across shared files.
+# Therefore, this file is a work-around to inject the mocks into the library for testing purposes.
+# This should exactly match the "settings" file, except for the additional "-Wl,--wrap" parts and the additional mock source file.
+#
+# The flags -o0 must be passed to prevent the compiler from optimizing away any functions being mocked (which results in the mock not happening and a real function being called).
+# Alternatively, figure out which optimization that is disabled by -o0 and have that specific optimization disabled.
+#
+
+build_name f_environment
+
+version_major 0
+version_minor 5
+version_micro 9
+version_file micro
+version_target minor
+
+modes individual clang test
+modes_default individual
+
+build_compiler gcc
+build_compiler-clang clang
+build_indexer ar
+build_indexer_arguments rcs
+build_language c
+
+build_libraries -lc -lcap
+build_libraries-individual -lf_memory -lf_string
+
+build_sources_library environment.c ../../tests/unit/c/mock-environment.c
+
+build_sources_headers environment.h environment/common.h environment/type.h
+
+build_script yes
+build_shared yes
+build_static no
+
+path_headers fll/level_0
+path_library_script script
+path_library_shared shared
+path_library_static static
+
+has_path_standard yes
+preserve_path_headers yes
+
+search_exclusive yes
+search_shared yes
+search_static yes
+
+#defines -D_di_libcap_
+
+flags -O0 -z now -g -fdiagnostics-color=always -Wno-logical-not-parentheses -Wno-parentheses
+flags-clang -Wno-logical-op-parentheses
+flags-test -fstack-protector
+
+flags_library -fPIC
+
+# Inject mocks.
+flags -Wl,--wrap=clearenv
+flags -Wl,--wrap=getegid
+flags -Wl,--wrap=getenv
+flags -Wl,--wrap=geteuid
+flags -Wl,--wrap=getgid
+flags -Wl,--wrap=getuid
+flags -Wl,--wrap=setenv
+flags -Wl,--wrap=unsetenv
+
+# Disable these mock injections when using "-D_di_libcap_".
+flags -Wl,--wrap=cap_free
+flags -Wl,--wrap=cap_get_flag
+flags -Wl,--wrap=cap_get_proc
+flags -Wl,--wrap=cap_set_proc
--- /dev/null
+# fss-0001
+#
+# Builds a program that is links to the generated library and is executed to perform tests.
+#
+# Memory leaks in the test program can be checked for by running valgrind with this executable.
+#
+
+build_name test-f_environment
+
+version_major 0
+version_minor 5
+version_micro 9
+version_file major
+version_target major
+
+modes individual clang test
+modes_default individual
+
+build_compiler gcc
+build_compiler-clang clang
+build_indexer ar
+build_indexer_arguments rcs
+build_language c
+
+build_libraries -lc -lcmocka
+build_libraries-individual -lf_memory -lf_string -lf_environment
+
+build_sources_program test-environment-clear.c test-environment-exists.c test-environment-get.c test-environment-secure_is.c test-environment-set.c test-environment-unset.c
+build_sources_program test-environment.c
+
+build_script no
+build_shared yes
+build_static no
+
+path_headers tests/unit/c
+path_sources tests/unit/c
+
+has_path_standard no
+preserve_path_headers yes
+
+search_exclusive yes
+search_shared yes
+search_static yes
+
+#defines -D_di_libcap_
+defines -Ibuild/includes
+defines_static -Lbuild/libraries/static
+defines_shared -Lbuild/libraries/shared
+
+flags -O2 -z now -g -fdiagnostics-color=always -Wno-logical-not-parentheses -Wno-parentheses
+flags-clang -Wno-logical-op-parentheses
+flags-test -fstack-protector
+
+flags_program -fPIE
--- /dev/null
+# fss-0005 iki-0002
+
+settings:
+ load_build yes
+ fail exit
+
+ environment LD_LIBRARY_PATH
+
+main:
+ build settings-mocks
+ build settings-tests
+
+ operate ld_library_path
+
+ if exists build/programs/shared/test-f_environment
+ shell build/programs/shared/test-f_environment
+
+ if exists build/programs/static/test-f_environment
+ shell build/programs/static/test-f_environment
+
+ if not exists build/programs/shared/test-f_environment
+ and not exists build/programs/static/test-f_environment
+ operate not_created
+
+not_created:
+ print
+ print 'context:"error"Failed to test due to being unable to find either a shared or static test binary to perform tests. context:"reset"'
+
+ exit failure
+
+ld_library_path:
+ if defined environment LD_LIBRARY_PATH
+ and defined parameter work
+ define LD_LIBRARY_PATH 'build/libraries/shared:parameter:"work:value"libraries/shared:define:"LD_LIBRARY_PATH"'
+
+ else
+ if defined environment LD_LIBRARY_PATH
+ define LD_LIBRARY_PATH 'build/libraries/shared:parameter:define:"LD_LIBRARY_PATH"'
+
+ else
+ if defined parameter work
+ define LD_LIBRARY_PATH 'build/libraries/shared:parameter:"work:value"libraries/shared'
+
+ else
+ define LD_LIBRARY_PATH build/libraries/shared
--- /dev/null
+#include "mock-environment.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef _di_libcap_
+ int __wrap_cap_free(void *obj_d) {
+
+ return mock_type(int);
+ }
+
+ int __wrap_cap_get_flag(cap_t cap_p, cap_value_t cap, cap_flag_t flag, cap_flag_value_t *value_p) {
+
+ const bool failure = mock_type(bool);
+
+ if (failure) {
+ errno = mock_type(int);
+
+ return -1;
+ }
+
+ *value_p = mock_type(cap_flag_value_t);
+
+ return mock_type(int);
+ }
+
+ cap_t __wrap_cap_get_proc(void) {
+
+ const bool failure = mock_type(bool);
+
+ if (failure) {
+ errno = mock_type(int);
+
+ return 0;
+ }
+
+ return mock_type(cap_t);
+ }
+
+ int __wrap_cap_set_proc(cap_t cap_p) {
+
+ const bool failure = mock_type(bool);
+
+ if (failure) {
+ errno = mock_type(int);
+
+ return -1;
+ }
+
+ return mock_type(int);
+ }
+#endif // _di_libcap_
+
+int __wrap_clearenv(void) {
+
+ return mock_type(int);
+}
+
+int __wrap_getegid(void) {
+
+ return mock_type(int);
+}
+
+char *__wrap_getenv(const char *name) {
+
+ return mock_type(char *);
+}
+
+int __wrap_geteuid(void) {
+
+ return mock_type(int);
+}
+
+int __wrap_getgid(void) {
+
+ return mock_type(int);
+}
+
+int __wrap_getuid(void) {
+
+ return mock_type(int);
+}
+
+int __wrap_setenv(const char *name, const char *value, int overwrite) {
+
+ const bool failure = mock_type(bool);
+
+ if (failure) {
+ errno = mock_type(int);
+
+ return -1;
+ }
+
+ return mock_type(int);
+}
+
+int __wrap_unsetenv(const char *name) {
+
+ const bool failure = mock_type(bool);
+
+ if (failure) {
+ errno = mock_type(int);
+
+ return -1;
+ }
+
+ return mock_type(int);
+}
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
--- /dev/null
+/**
+ * FLL - Level 0
+ *
+ * Project: Environment
+ * API Version: 0.5
+ * Licenses: lgpl-2.1-or-later
+ *
+ * Test the environment project.
+ */
+#ifndef _MOCK__environment_h
+#define _MOCK__environment_h
+
+// Libc includes.
+#include <stdarg.h>
+#include <stddef.h>
+#include <setjmp.h>
+#include <stdint.h>
+
+#ifndef _di_libcap_
+ #include <sys/capability.h>
+#endif // _di_libcap_
+
+// cmocka includes.
+#include <cmocka.h>
+
+// FLL-0 includes.
+#include <fll/level_0/environment.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+const static int mock_errno_generic = 32767;
+
+#ifndef _di_libcap_
+ extern int __wrap_cap_free(void *obj_d);
+ extern int __wrap_cap_get_flag(cap_t cap_p, cap_value_t cap, cap_flag_t flag, cap_flag_value_t *value_p);
+ extern cap_t __wrap_cap_get_proc(void);
+ extern int __wrap_cap_set_proc(cap_t cap_p);
+#endif // _di_libcap_
+
+extern int __wrap_clearenv(void);
+extern int __wrap_getegid(void);
+extern char *__wrap_getenv(const char *name);
+extern int __wrap_geteuid(void);
+extern int __wrap_getgid(void);
+extern int __wrap_getuid(void);
+extern int __wrap_setenv(const char *name, const char *value, int overwrite);
+extern int __wrap_unsetenv(const char *name);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // _MOCK__environment_h
--- /dev/null
+#include "test-environment.h"
+#include "test-environment-clear.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void test__f_environment_clear__fails(void **state) {
+
+ {
+ will_return(__wrap_clearenv, -1);
+
+ const f_status_t status = f_environment_clear();
+
+ assert_int_equal(F_status_set_fine(status), F_failure);
+ }
+}
+
+void test__f_environment_clear__works(void **state) {
+
+ {
+ will_return(__wrap_clearenv, 0);
+
+ const f_status_t status = f_environment_clear();
+
+ assert_int_equal(status, F_none);
+ }
+}
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
--- /dev/null
+/**
+ * FLL - Level 0
+ *
+ * Project: Environment
+ * API Version: 0.5
+ * Licenses: lgpl-2.1-or-later
+ *
+ * Test the environment project.
+ */
+#ifndef _TEST__F_environment_clear_h
+#define _TEST__F_environment_clear_h
+
+/**
+ * Test that function fails.
+ *
+ * @see f_environment_clear()
+ */
+extern void test__f_environment_clear__fails(void **state);
+
+/**
+ * Test that function works.
+ *
+ * @see f_environment_clear()
+ */
+extern void test__f_environment_clear__works(void **state);
+
+#endif // _TEST__F_environment_clear_h
--- /dev/null
+#include "test-environment.h"
+#include "test-environment-exists.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void test__f_environment_exists__fails(void **state) {
+
+ const f_string_static_t path = macro_f_string_static_t_initialize("test", 0, 4);
+
+ {
+ will_return(__wrap_getenv, 0);
+
+ const f_status_t status = f_environment_exists(path);
+
+ assert_int_equal(status, F_false);
+ }
+}
+
+void test__f_environment_exists__returns_data_not(void **state) {
+
+ {
+ const f_status_t status = f_environment_exists(f_string_empty_s);
+
+ assert_int_equal(status, F_data_not);
+ }
+}
+
+void test__f_environment_exists__works(void **state) {
+
+ const f_string_static_t path = macro_f_string_static_t_initialize("test", 0, 4);
+
+ {
+ will_return(__wrap_getenv, path.string);
+
+ const f_status_t status = f_environment_exists(path);
+
+ assert_int_equal(status, F_true);
+ }
+}
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
--- /dev/null
+/**
+ * FLL - Level 0
+ *
+ * Project: Environment
+ * API Version: 0.5
+ * Licenses: lgpl-2.1-or-later
+ *
+ * Test the environment project.
+ */
+#ifndef _TEST__F_environment_exists_h
+#define _TEST__F_environment_exists_h
+
+/**
+ * Test that function fails.
+ *
+ * @see f_environment_exists()
+ */
+extern void test__f_environment_exists__fails(void **state);
+
+/**
+ * Test that function works but the path is empty.
+ *
+ * @see f_environment_exists()
+ */
+extern void test__f_environment_exists__returns_data_not(void **state);
+
+/**
+ * Test that function works.
+ *
+ * @see f_environment_exists()
+ */
+extern void test__f_environment_exists__works(void **state);
+
+#endif // _TEST__F_environment_exists_h
--- /dev/null
+#include "test-environment.h"
+#include "test-environment-get.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void test__f_environment_get__fails(void **state) {
+
+ const f_string_static_t path = macro_f_string_static_t_initialize("test", 0, 4);
+
+ f_string_dynamic_t buffer = f_string_dynamic_t_initialize;
+
+ {
+ will_return(__wrap_getenv, 0);
+
+ const f_status_t status = f_environment_get(path, &buffer);
+
+ assert_int_equal(status, F_exist_not);
+ }
+
+ f_string_dynamic_resize(0, &buffer);
+}
+
+#ifndef _di_level_0_parameter_checking_
+ void test__f_environment_get__parameter_checking(void **state) {
+
+ const f_string_static_t path = macro_f_string_static_t_initialize("test", 0, 4);
+
+ {
+ const f_status_t status = f_environment_get(path, 0);
+
+ assert_int_equal(F_status_set_fine(status), F_parameter);
+ }
+ }
+#endif // _di_level_0_parameter_checking_
+
+void test__f_environment_get__returns_data_not(void **state) {
+
+ f_string_dynamic_t buffer = f_string_dynamic_t_initialize;
+
+ {
+ const f_status_t status = f_environment_get(f_string_empty_s, &buffer);
+
+ assert_int_equal(status, F_data_not);
+ }
+
+ f_string_dynamic_resize(0, &buffer);
+}
+
+void test__f_environment_get__works(void **state) {
+
+ const f_string_static_t path = macro_f_string_static_t_initialize("test", 0, 4);
+
+ f_string_dynamic_t buffer = f_string_dynamic_t_initialize;
+
+ {
+ will_return(__wrap_getenv, path.string);
+
+ const f_status_t status = f_environment_get(path, &buffer);
+
+ assert_int_equal(status, F_none);
+ assert_int_equal(buffer.used, path.used);
+ assert_string_equal(buffer.string, path.string);
+ }
+
+ buffer.used = 0;
+
+ {
+ will_return(__wrap_getenv, f_string_empty_s.string);
+
+ const f_status_t status = f_environment_get(path, &buffer);
+
+ assert_int_equal(status, F_none);
+ assert_int_equal(buffer.used, f_string_empty_s.used);
+ assert_string_equal(buffer.string, f_string_empty_s.string);
+ }
+
+ f_string_dynamic_resize(0, &buffer);
+}
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
--- /dev/null
+/**
+ * FLL - Level 0
+ *
+ * Project: Environment
+ * API Version: 0.5
+ * Licenses: lgpl-2.1-or-later
+ *
+ * Test the environment project.
+ */
+#ifndef _TEST__F_environment_get_h
+#define _TEST__F_environment_get_h
+
+/**
+ * Test that function fails.
+ *
+ * @see f_environment_get()
+ */
+extern void test__f_environment_get__fails(void **state);
+
+/**
+ * Test that parameter checking works as expected.
+ *
+ * @see f_environment_get()
+ */
+#ifndef _di_level_0_parameter_checking_
+ extern void test__f_environment_get__parameter_checking(void **state);
+#endif // _di_level_0_parameter_checking_
+
+/**
+ * Test that function works but the path is empty.
+ *
+ * @see f_environment_get()
+ */
+extern void test__f_environment_get__returns_data_not(void **state);
+
+/**
+ * Test that function works.
+ *
+ * @see f_environment_get()
+ */
+extern void test__f_environment_get__works(void **state);
+
+#endif // _TEST__F_environment_get_h
--- /dev/null
+#include "test-environment.h"
+#include "test-environment-secure_is.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void test__f_environment_secure_is__fails(void **state) {
+
+ #ifndef _di_libcap_
+ {
+ int errnos[] = {
+ EINVAL,
+ EPERM,
+ ENOMEM,
+ mock_errno_generic,
+ };
+
+ f_status_t statuss[] = {
+ F_parameter,
+ F_prohibited,
+ F_memory_not,
+ F_failure,
+ };
+
+ for (int i = 0; i < 4; ++i) {
+
+ will_return(__wrap_geteuid, 1);
+ will_return(__wrap_getuid, 2);
+
+ will_return(__wrap_cap_get_proc, true);
+ will_return(__wrap_cap_get_proc, errnos[i]);
+
+ const f_status_t status = f_environment_secure_is();
+
+ assert_int_equal(F_status_set_fine(status), statuss[i]);
+ } // for
+ }
+
+ {
+ int errnos[] = {
+ EINVAL,
+ mock_errno_generic,
+ };
+
+ f_status_t statuss[] = {
+ F_parameter,
+ F_failure,
+ };
+
+ for (int i = 0; i < 2; ++i) {
+
+ long stub = 0;
+ cap_t capability = (cap_t) &stub;
+
+ will_return(__wrap_geteuid, 1);
+ will_return(__wrap_getuid, 1);
+
+ will_return(__wrap_getegid, 3);
+ will_return(__wrap_getgid, 4);
+
+ will_return(__wrap_cap_get_proc, false);
+ will_return(__wrap_cap_get_proc, capability);
+
+ will_return(__wrap_cap_get_flag, true);
+ will_return(__wrap_cap_get_flag, errnos[i]);
+
+ will_return(__wrap_cap_free, 0);
+
+ const f_status_t status = f_environment_secure_is();
+
+ assert_int_equal(F_status_set_fine(status), statuss[i]);
+ } // for
+ }
+ #endif // _di_libcap_
+}
+
+void test__f_environment_secure_is__works(void **state) {
+
+ {
+ will_return(__wrap_geteuid, 1);
+ will_return(__wrap_getuid, 1);
+
+ will_return(__wrap_getegid, 1);
+ will_return(__wrap_getgid, 1);
+
+ const f_status_t status = f_environment_secure_is();
+
+ assert_int_equal(status, F_true);
+ }
+
+ {
+ #ifndef _di_libcap_
+ long stub = 0;
+ cap_t capability = (cap_t) &stub;
+ #endif // _di_libcap_
+
+ will_return(__wrap_geteuid, 1);
+ will_return(__wrap_getuid, 0);
+
+ #ifndef _di_libcap_
+ will_return(__wrap_cap_get_proc, false);
+ will_return(__wrap_cap_get_proc, capability);
+
+ will_return(__wrap_cap_get_flag, false);
+ will_return(__wrap_cap_get_flag, CAP_CLEAR);
+ will_return(__wrap_cap_get_flag, 0);
+
+ will_return(__wrap_cap_free, 0);
+ #endif // _di_libcap_
+
+ const f_status_t status = f_environment_secure_is();
+
+ assert_int_equal(status, F_false);
+ }
+
+ #ifndef _di_libcap_
+ {
+ long stub = 0;
+ cap_t capability = (cap_t) &stub;
+
+ will_return(__wrap_geteuid, 1);
+ will_return(__wrap_getuid, 1);
+
+ will_return(__wrap_getegid, 1);
+ will_return(__wrap_getgid, 2);
+
+ will_return(__wrap_cap_get_proc, false);
+ will_return(__wrap_cap_get_proc, capability);
+
+ will_return(__wrap_cap_get_flag, false);
+ will_return(__wrap_cap_get_flag, CAP_CLEAR);
+ will_return(__wrap_cap_get_flag, 0);
+
+ will_return(__wrap_cap_free, 0);
+
+ const f_status_t status = f_environment_secure_is();
+
+ assert_int_equal(status, F_false);
+ }
+ #endif // _di_libcap_
+
+ #ifndef _di_libcap_
+ {
+ long stub = 0;
+ cap_t capability = (cap_t) &stub;;
+
+ will_return(__wrap_geteuid, 1);
+ will_return(__wrap_getuid, 2);
+
+ will_return(__wrap_cap_get_proc, false);
+ will_return(__wrap_cap_get_proc, capability);
+
+ will_return(__wrap_cap_get_flag, false);
+ will_return(__wrap_cap_get_flag, CAP_SET);
+ will_return(__wrap_cap_get_flag, 0);
+
+ will_return(__wrap_cap_free, 0);
+
+ const f_status_t status = f_environment_secure_is();
+
+ assert_int_equal(status, F_true);
+ }
+ #endif // _di_libcap_
+}
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
--- /dev/null
+/**
+ * FLL - Level 0
+ *
+ * Project: Environment
+ * API Version: 0.5
+ * Licenses: lgpl-2.1-or-later
+ *
+ * Test the environment project.
+ */
+#ifndef _TEST__F_environment_secure_is_h
+#define _TEST__F_environment_secure_is_h
+
+/**
+ * Test that function fails.
+ *
+ * @see f_environment_secure_is()
+ */
+extern void test__f_environment_secure_is__fails(void **state);
+
+/**
+ * Test that function works.
+ *
+ * @see f_environment_secure_is()
+ */
+extern void test__f_environment_secure_is__works(void **state);
+
+#endif // _TEST__F_environment_secure_is_h
--- /dev/null
+#include "test-environment.h"
+#include "test-environment-set.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void test__f_environment_set__fails(void **state) {
+
+ const f_string_static_t path = macro_f_string_static_t_initialize("test", 0, 4);
+
+ {
+ int errnos[] = {
+ EINVAL,
+ ENOMEM,
+ mock_errno_generic,
+ };
+
+ f_status_t statuss[] = {
+ F_parameter,
+ F_memory_not,
+ F_failure,
+ };
+
+ for (int i = 0; i < 3; ++i) {
+
+ will_return(__wrap_setenv, true);
+ will_return(__wrap_setenv, errnos[i]);
+
+ const f_status_t status = f_environment_set(path, path, F_false);
+
+ assert_int_equal(F_status_set_fine(status), statuss[i]);
+ } // for
+ }
+}
+
+void test__f_environment_set__returns_data_not(void **state) {
+
+ const f_string_static_t path = macro_f_string_static_t_initialize("test", 0, 4);
+
+ {
+ const f_status_t status = f_environment_set(f_string_empty_s, f_string_empty_s, F_false);
+
+ assert_int_equal(status, F_data_not);
+ }
+
+ {
+ const f_status_t status = f_environment_set(f_string_empty_s, path, F_false);
+
+ assert_int_equal(status, F_data_not);
+ }
+}
+
+void test__f_environment_set__works(void **state) {
+
+ const f_string_static_t path = macro_f_string_static_t_initialize("test", 0, 4);
+
+ {
+ will_return(__wrap_setenv, false);
+ will_return(__wrap_setenv, 0);
+
+ const f_status_t status = f_environment_set(path, path, F_false);
+
+ assert_int_equal(status, F_none);
+ }
+}
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
--- /dev/null
+/**
+ * FLL - Level 0
+ *
+ * Project: Environment
+ * API Version: 0.5
+ * Licenses: lgpl-2.1-or-later
+ *
+ * Test the environment project.
+ */
+#ifndef _TEST__F_environment_set_h
+#define _TEST__F_environment_set_h
+
+/**
+ * Test that function fails.
+ *
+ * @see f_environment_set()
+ */
+extern void test__f_environment_set__fails(void **state);
+
+/**
+ * Test that function works but the path is empty.
+ *
+ * @see f_environment_set()
+ */
+extern void test__f_environment_set__returns_data_not(void **state);
+
+/**
+ * Test that function works.
+ *
+ * @see f_environment_set()
+ */
+extern void test__f_environment_set__works(void **state);
+
+#endif // _TEST__F_environment_set_h
--- /dev/null
+#include "test-environment.h"
+#include "test-environment-unset.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void test__f_environment_unset__fails(void **state) {
+
+ const f_string_static_t path = macro_f_string_static_t_initialize("test", 0, 4);
+
+ {
+ int errnos[] = {
+ EINVAL,
+ ENOMEM,
+ mock_errno_generic,
+ };
+
+ f_status_t statuss[] = {
+ F_parameter,
+ F_memory_not,
+ F_failure,
+ };
+
+ for (int i = 0; i < 3; ++i) {
+
+ will_return(__wrap_unsetenv, true);
+ will_return(__wrap_unsetenv, errnos[i]);
+
+ const f_status_t status = f_environment_unset(path);
+
+ assert_int_equal(F_status_set_fine(status), statuss[i]);
+ } // for
+ }
+}
+
+void test__f_environment_unset__returns_data_not(void **state) {
+
+ {
+ const f_status_t status = f_environment_unset(f_string_empty_s);
+
+ assert_int_equal(status, F_data_not);
+ }
+}
+
+void test__f_environment_unset__works(void **state) {
+
+ const f_string_static_t path = macro_f_string_static_t_initialize("test", 0, 4);
+
+ {
+ will_return(__wrap_unsetenv, false);
+ will_return(__wrap_unsetenv, 0);
+
+ const f_status_t status = f_environment_unset(path);
+
+ assert_int_equal(status, F_none);
+ }
+}
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
--- /dev/null
+/**
+ * FLL - Level 0
+ *
+ * Project: Environment
+ * API Version: 0.5
+ * Licenses: lgpl-2.1-or-later
+ *
+ * Test the environment project.
+ */
+#ifndef _TEST__F_environment_unset_h
+#define _TEST__F_environment_unset_h
+
+/**
+ * Test that function fails.
+ *
+ * @see f_environment_unset()
+ */
+extern void test__f_environment_unset__fails(void **state);
+
+/**
+ * Test that function works but the path is empty.
+ *
+ * @see f_environment_unset()
+ */
+extern void test__f_environment_unset__returns_data_not(void **state);
+
+/**
+ * Test that function works.
+ *
+ * @see f_environment_unset()
+ */
+extern void test__f_environment_unset__works(void **state);
+
+#endif // _TEST__F_environment_unset_h
--- /dev/null
+#include "test-environment.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int setup(void **state) {
+
+ return 0;
+}
+
+int setdown(void **state) {
+
+ errno = 0;
+
+ return 0;
+}
+
+int main(void) {
+
+ const struct CMUnitTest tests[] = {
+ cmocka_unit_test(test__f_environment_clear__fails),
+ cmocka_unit_test(test__f_environment_clear__works),
+
+ cmocka_unit_test(test__f_environment_exists__fails),
+ cmocka_unit_test(test__f_environment_exists__returns_data_not),
+ cmocka_unit_test(test__f_environment_exists__works),
+
+ cmocka_unit_test(test__f_environment_get__fails),
+ cmocka_unit_test(test__f_environment_get__returns_data_not),
+ cmocka_unit_test(test__f_environment_get__works),
+
+ cmocka_unit_test(test__f_environment_secure_is__fails),
+ cmocka_unit_test(test__f_environment_secure_is__works),
+
+ cmocka_unit_test(test__f_environment_set__fails),
+ cmocka_unit_test(test__f_environment_set__returns_data_not),
+ cmocka_unit_test(test__f_environment_set__works),
+
+ cmocka_unit_test(test__f_environment_unset__fails),
+ cmocka_unit_test(test__f_environment_unset__returns_data_not),
+ cmocka_unit_test(test__f_environment_unset__works),
+
+ #ifndef _di_level_0_parameter_checking_
+ // f_environment_clear() doesn't use parameter checking.
+ // f_environment_exists() doesn't use parameter checking.
+ cmocka_unit_test(test__f_environment_get__parameter_checking),
+ // f_environment_secure_is() doesn't use parameter checking.
+ // f_environment_set() doesn't use parameter checking.
+ // f_environment_unset() doesn't use parameter checking.
+ #endif // _di_level_0_parameter_checking_
+ };
+
+ return cmocka_run_group_tests(tests, setup, setdown);
+}
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
--- /dev/null
+/**
+ * FLL - Level 0
+ *
+ * Project: Environment
+ * API Version: 0.5
+ * Licenses: lgpl-2.1-or-later
+ *
+ * Test the environment project.
+ */
+#ifndef _TEST__F_environment_h
+#define _TEST__F_environment_h
+
+// Libc includes.
+#include <stdarg.h>
+#include <stddef.h>
+#include <setjmp.h>
+#include <stdint.h>
+
+// cmocka includes.
+#include <cmocka.h>
+
+// FLL-0 includes.
+#include <fll/level_0/environment.h>
+
+// Mock includes.
+#include "mock-environment.h"
+
+// Test includes.
+#include "test-environment-clear.h"
+#include "test-environment-exists.h"
+#include "test-environment-get.h"
+#include "test-environment-secure_is.h"
+#include "test-environment-set.h"
+#include "test-environment-unset.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Perform any setup operations.
+ *
+ * @param state
+ * The test state.
+ *
+ * @return
+ * The status of this function, where 0 means success.
+ */
+extern int setup(void **state);
+
+/**
+ * Peform any setdown operations.
+ *
+ * @param state
+ * The test state.
+ *
+ * @return
+ * The status of this function, where 0 means success.
+ */
+extern int setdown(void **state);
+
+/**
+ * Run all tests.
+ *
+ * @return
+ * The final result of the tests.
+ *
+ * @see cmocka_run_group_tests()
+ * @see cmocka_unit_test()
+ */
+extern int main(void);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // _TEST__F_environment_h