This also adds the appropriate basic unit tests.
build_sources_headers string/map_multi.h string/map_multis.h string/map_multiss.h
build_sources_headers string/static.h string/statics.h string/staticss.h
build_sources_headers string/triple.h string/triples.h string/tripless.h
-build_sources_headers time.h
+build_sources_headers time.h time/common.h
build_sources_headers type.h type/cell.h type/file.h type/fll.h type/mode.h type/number.h type/quantity.h type/range.h type/range_double.h type/state.h type/status.h type/time.h
build_sources_headers type_array.h type_array_file.h type_array/common.h type_array/cell.h type_array/file.h type_array/fll_id.h type_array/int8.h type_array/int16.h type_array/int32.h type_array/int64.h type_array/int128.h type_array/number_signed.h type_array/number_unsigned.h type_array/poll.h type_array/quantity.h type_array/quantitys.h type_array/quantityss.h type_array/range.h type_array/ranges.h type_array/rangess.h type_array/range_double.h type_array/range_doubles.h type_array/range_doubless.h type_array/state.h type_array/status.h type_array/uint8.h type_array/uint16.h type_array/uint32.h type_array/uint64.h type_array/uint128.h
build_sources_headers utf.h utf/common.h utf/convert.h utf/dynamic.h utf/dynamics.h utf/dynamicss.h utf/is.h utf/is_character.h utf/map.h utf/maps.h utf/mapss.h utf/map_multi.h utf/map_multis.h utf/map_multiss.h utf/static.h utf/statics.h utf/staticss.h utf/string.h utf/triple.h utf/triples.h utf/tripless.h
#defines -D_f_file_rename_use_renameat2_
defines -D_libcap_legacy_only_
defines-clang -D_clang_not_a_compile_time_constant_workaround_
-defines-threadless -D_di_thread_support_
defines-thread -D_pthread_attr_unsupported_ -D_pthread_sigqueue_unsupported_
+defines-threadless -D_di_thread_support_
flags -O2 -g -fdiagnostics-color=always -Wno-logical-not-parentheses -Wno-parentheses -Wno-missing-braces
flags -fstack-clash-protection -fno-delete-null-pointer-checks
flags -Wl,-z,nodlopen -Wl,-z,noexecstack -Wl,-z,relro -Wl,-z,now
-flags-thread -pthread
flags-clang -Wno-logical-op-parentheses
+flags-fanalyzer -fanalyzer
flags-gcc_13 -fstrict-flex-arrays=3
flags-test -fstack-protector-strong -Wall
-flags-fanalyzer -fanalyzer
+flags-thread -pthread
flags_library -fPIC
flags_object -fPIC
build_sources_headers level_0/string/map_multi.h level_0/string/map_multis.h level_0/string/map_multiss.h
build_sources_headers level_0/string/static.h level_0/string/statics.h level_0/string/staticss.h
build_sources_headers level_0/string/triple.h level_0/string/triples.h level_0/string/tripless.h
-build_sources_headers level_0/time.h
+build_sources_headers level_0/time.h level_0/time/common.h
build_sources_headers level_0/type.h level_0/type/cell.h level_0/type/file.h level_0/type/fll.h level_0/type/mode.h level_0/type/number.h level_0/type/quantity.h level_0/type/range.h level_0/type/range_double.h level_0/type/state.h level_0/type/status.h level_0/type/time.h
build_sources_headers level_0/type_array.h level_0/type_array_file.h level_0/type_array/common.h level_0/type_array/cell.h level_0/type_array/file.h level_0/type_array/fll_id.h level_0/type_array/int8.h level_0/type_array/int16.h level_0/type_array/int32.h level_0/type_array/int64.h level_0/type_array/int128.h level_0/type_array/number_signed.h level_0/type_array/number_unsigned.h level_0/type_array/poll.h level_0/type_array/quantity.h level_0/type_array/quantitys.h level_0/type_array/quantityss.h level_0/type_array/range.h level_0/type_array/ranges.h level_0/type_array/rangess.h level_0/type_array/range_double.h level_0/type_array/range_doubles.h level_0/type_array/range_doubless.h level_0/type_array/state.h level_0/type_array/status.h level_0/type_array/uint8.h level_0/type_array/uint16.h level_0/type_array/uint32.h level_0/type_array/uint64.h level_0/type_array/uint128.h
build_sources_headers level_0/utf.h level_0/utf/common.h level_0/utf/convert.h level_0/utf/dynamic.h level_0/utf/dynamics.h level_0/utf/dynamicss.h level_0/utf/is.h level_0/utf/is_character.h level_0/utf/map.h level_0/utf/maps.h level_0/utf/mapss.h level_0/utf/map_multi.h level_0/utf/map_multis.h level_0/utf/map_multiss.h level_0/utf/static.h level_0/utf/statics.h level_0/utf/staticss.h level_0/utf/string.h level_0/utf/triple.h level_0/utf/triples.h level_0/utf/tripless.h
#defines -D_f_file_rename_use_renameat2_
defines -D_libcap_legacy_only_
defines-clang -D_clang_not_a_compile_time_constant_workaround_
-defines-threadless -D_di_thread_support_
defines-thread -D_pthread_attr_unsupported_ -D_pthread_sigqueue_unsupported_
+defines-threadless -D_di_thread_support_
flags -O2 -g -fdiagnostics-color=always -Wno-logical-not-parentheses -Wno-parentheses -Wno-missing-braces
flags -fstack-clash-protection -fno-delete-null-pointer-checks
flags -Wl,-z,nodlopen -Wl,-z,noexecstack -Wl,-z,relro -Wl,-z,now
-flags-thread -pthread
flags-clang -Wno-logical-op-parentheses
+flags-fanalyzer -fanalyzer
flags-gcc_13 -fstrict-flex-arrays=3
flags-test -fstack-protector-strong -Wall
-flags-fanalyzer -fanalyzer
+flags-thread -pthread
flags_library -fPIC
flags_object -fPIC
extern "C" {
#endif
+#ifndef _di_f_time_calendar_string_
+ f_status_t f_time_calendar_string(const time_t time, f_string_dynamic_t * const destination) {
+ #ifndef _di_level_0_parameter_checking_
+ if (!destination) return F_status_set_error(F_parameter);
+ #endif // _di_level_0_parameter_checking_
+
+ f_char_t string[F_time_calendar_string_length_d] = { 0 };
+
+ if (!ctime_r(&time, string)) {
+ if (errno == EOVERFLOW) return F_status_set_error(F_buffer_overflow);
+
+ return F_status_set_error(F_failure);
+ }
+
+ const f_status_t status = f_string_append(string, strnlen(string, F_time_calendar_string_length_d), destination);
+ if (F_status_is_error(status)) return status;
+
+ return F_okay;
+ }
+#endif // _di_f_time_calendar_string_
+
+#ifndef _di_f_time_calendar_string_part_
+ f_status_t f_time_calendar_string_part(const f_time_part_t part, f_string_dynamic_t * const destination) {
+ #ifndef _di_level_0_parameter_checking_
+ if (!destination) return F_status_set_error(F_parameter);
+ #endif // _di_level_0_parameter_checking_
+
+ f_char_t string[F_time_calendar_string_length_d] = { 0 };
+
+ if (!asctime_r(&part, string)) {
+ if (errno == EOVERFLOW) return F_status_set_error(F_buffer_overflow);
+
+ return F_status_set_error(F_failure);
+ }
+
+ const f_status_t status = f_string_append(string, strnlen(string, F_time_calendar_string_length_d), destination);
+ if (F_status_is_error(status)) return status;
+
+ return F_okay;
+ }
+#endif // _di_f_time_calendar_string_part_
+
+#ifndef _di_f_time_epoch_get_
+ f_status_t f_time_epoch_get(time_t * const time_value) {
+ #ifndef _di_level_0_parameter_checking_
+ if (!time_value) return F_status_set_error(F_parameter);
+ #endif // _di_level_0_parameter_checking_
+
+ const time_t result = time(0);
+
+ if (result == ((time_t) -1)) {
+ if (errno == EFAULT) return F_status_set_error(F_buffer);
+
+ return F_status_set_error(F_failure);
+ }
+
+ *time_value = result;
+
+ return F_okay;
+ }
+#endif // _di_f_time_epoch_get_
+
+#ifndef _di_f_time_local_get_
+ f_status_t f_time_local_get(const time_t time, f_time_part_t * const destination) {
+ #ifndef _di_level_0_parameter_checking_
+ if (!destination) return F_status_set_error(F_parameter);
+ #endif // _di_level_0_parameter_checking_
+
+ if (!localtime_r(&time, destination)) {
+ if (errno == EOVERFLOW) return F_status_set_error(F_buffer_overflow);
+
+ return F_status_set_error(F_failure);
+ }
+
+ return F_okay;
+ }
+#endif // _di_f_time_local_get_
+
+#ifndef _di_f_time_of_day_get_
+ f_status_t f_time_of_day_get(f_time_value_t * const time) {
+ #ifndef _di_level_0_parameter_checking_
+ if (!time) return F_status_set_error(F_parameter);
+ #endif // _di_level_0_parameter_checking_
+
+ if (gettimeofday(time, 0) == -1) {
+ if (errno == EFAULT) return F_status_set_error(F_buffer);
+ if (errno == EINVAL) return F_status_set_error(F_parameter);
+ if (errno == EPERM) return F_status_set_error(F_prohibited);
+
+ return F_status_set_error(F_failure);
+ }
+
+ return F_okay;
+ }
+#endif // _di_f_time_of_day_get_
+
+#ifndef _di_f_time_of_day_set_
+ f_status_t f_time_of_day_set(const f_time_value_t time) {
+
+ if (settimeofday(&time, 0) == -1) {
+ if (errno == EFAULT) return F_status_set_error(F_buffer);
+ if (errno == EINVAL) return F_status_set_error(F_parameter);
+ if (errno == EPERM) return F_status_set_error(F_prohibited);
+
+ return F_status_set_error(F_failure);
+ }
+
+ return F_okay;
+ }
+#endif // _di_f_time_of_day_set_
+
#ifndef _di_f_time_spec_millisecond_
extern f_status_t f_time_spec_millisecond(const f_number_unsigned_t second, const f_number_unsigned_t millisecond, struct timespec * const time) {
#ifndef _di_level_0_parameter_checking_
}
#endif // _di_f_time_spec_nanosecond_
+#ifndef _di_f_time_utc_get_
+ f_status_t f_time_utc_get(const time_t time, f_time_part_t * const destination) {
+ #ifndef _di_level_0_parameter_checking_
+ if (!destination) return F_status_set_error(F_parameter);
+ #endif // _di_level_0_parameter_checking_
+
+ if (!gmtime_r(&time, destination)) {
+ if (errno == EOVERFLOW) return F_status_set_error(F_buffer_overflow);
+
+ return F_status_set_error(F_failure);
+ }
+
+ return F_okay;
+ }
+#endif // _di_f_time_utc_get_
+
#ifdef __cplusplus
} // extern "C"
#endif
// Libc includes.
#include <time.h>
+#include <sys/time.h>
// FLL-0 includes.
#include <fll/level_0/type.h>
#include <fll/level_0/status.h>
+#include <fll/level_0/string.h>
// FLL-0 time includes.
+#include <fll/level_0/time/common.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
+ * Convert the given time into a calendar-time string.
+ *
+ * @param time
+ * The time to convert.
+ * @param destination
+ * The calendar string representation of the given time.
+ *
+ * Must not be NULL.
+ *
+ * @return
+ * F_okay on success.
+ *
+ * F_buffer_overflow (with error bit) on buffer overflow.
+ *
+ * Errors (with error bit) from: f_string_append().
+ *
+ * F_failure (with error bit) on any other error.
+ *
+ * @see ctime_r()
+ *
+ * @see f_string_append()
+ */
+#ifndef _di_f_time_calendar_string_
+ extern f_status_t f_time_calendar_string(const time_t time, f_string_dynamic_t * const destination);
+#endif // _di_f_time_calendar_string_
+
+/**
+ * Convert the given time into a calendar-time string from a broken up (part) date and time.
+ *
+ * @param part
+ * The time parts to convert.
+ * @param destination
+ * The calendar string representation of the given time.
+ *
+ * Must not be NULL.
+ *
+ * @return
+ * F_okay on success.
+ *
+ * F_buffer_overflow (with error bit) on buffer overflow.
+ *
+ * Errors (with error bit) from: f_string_append().
+ *
+ * F_failure (with error bit) on any other error.
+ *
+ * @see asctime_r()
+ *
+ * @see f_string_append()
+ */
+#ifndef _di_f_time_calendar_string_part_
+ extern f_status_t f_time_calendar_string_part(const f_time_part_t part, f_string_dynamic_t * const destination);
+#endif // _di_f_time_calendar_string_part_
+
+/**
+ * Get the current time in seconds since epoch.
+ *
+ * @param time
+ * The time retrieved.
+ *
+ * Must not be NULL.
+ *
+ * @return
+ * F_okay on success.
+ *
+ * F_buffer (with error bit) if the buffer is invalid.
+ * F_parameter (with error bit) if a parameter is invalid.
+ *
+ * F_failure (with error bit) on any other error.
+ *
+ * @see time()
+ */
+#ifndef _di_f_time_epoch_get_
+ extern f_status_t f_time_epoch_get(time_t * const time);
+#endif // _di_f_time_epoch_get_
+
+/**
+ * Convert the given time into local time parts.
+ *
+ * @param time
+ * The time to convert.
+ * @param destination
+ * The time parts.
+ *
+ * Must not be NULL.
+ *
+ * @return
+ * F_okay on success.
+ *
+ * F_buffer_overflow (with error bit) on buffer overflow.
+ *
+ * F_parameter (with error bit) if a parameter is invalid.
+ *
+ * F_failure (with error bit) on any other error.
+ *
+ * @see localtime_r()
+ */
+#ifndef _di_f_time_local_get_
+ extern f_status_t f_time_local_get(const time_t time, f_time_part_t * const destination);
+#endif // _di_f_time_local_get_
+
+/**
+ * Get the current time of day.
+ *
+ * @param time
+ * The time retrieved.
+ *
+ * Must not be NULL.
+ *
+ * @return
+ * F_okay on success.
+ *
+ * F_buffer (with error bit) if the buffer is invalid.
+ * F_parameter (with error bit) if a parameter is invalid.
+ * F_prohibited (with error bit) if the file system does not permit this operation.
+ *
+ * F_failure (with error bit) on any other error.
+ *
+ * @see gettimeofday()
+ */
+#ifndef _di_f_time_of_day_get_
+ extern f_status_t f_time_of_day_get(f_time_value_t * const time);
+#endif // _di_f_time_of_day_get_
+
+/**
+ * Set the current time of day.
+ *
+ * @param time
+ * The time to set.
+ *
+ * @return
+ * F_okay on success.
+ *
+ * F_number_overflow (with error bit) if the summation of seconds and nanoseconds results in an overflow when cast to appropriate integer type.
+ * F_number_underflow (with error bit) if the second or nanoseconds is less than 0 when cast to appropriate integer type.
+ * F_parameter (with error bit) if a parameter is invalid.
+ *
+ * F_failure (with error bit) on any other error.
+ *
+ * @see settimeofday()
+ */
+#ifndef _di_f_time_of_day_set_
+ extern f_status_t f_time_of_day_set(const f_time_value_t time);
+#endif // _di_f_time_of_day_set_
+
+/**
* Create a timespec representing the given seconds and milliseconds.
*
* This is intended to work with "struct timespec" and is not intended to work with "f_time_spec_t".
extern f_status_t f_time_spec_nanosecond(const f_number_unsigned_t second, const f_number_unsigned_t nanosecond, struct timespec * const time);
#endif // _di_f_time_spec_nanosecond_
+/**
+ * Convert the given time into UTC time parts.
+ *
+ * @param time
+ * The time to convert.
+ * @param destination
+ * The time parts.
+ *
+ * Must not be NULL.
+ *
+ * @return
+ * F_okay on success.
+ *
+ * F_buffer_overflow (with error bit) on buffer overflow.
+ *
+ * F_parameter (with error bit) if a parameter is invalid.
+ *
+ * F_failure (with error bit) on any other error.
+ *
+ * @see gmtime_r()
+ */
+#ifndef _di_f_time_utc_get_
+ extern f_status_t f_time_utc_get(const time_t time, f_time_part_t * const destination);
+#endif // _di_f_time_utc_get_
+
#ifdef __cplusplus
} // extern "C"
#endif
--- /dev/null
+/**
+ * FLL - Level 0
+ *
+ * Project: Time
+ * API Version: 0.7
+ * Licenses: lgpl-2.1-or-later
+ *
+ * Defines common data to be used for/by project time.
+ *
+ * This is auto-included by time.h and should not need to be explicitly included.
+ */
+#ifndef _F_time_common_h
+#define _F_time_common_h
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Custom defines for f_time.
+ *
+ * F_time_*_d:
+ * - calendar_string_length: The length to increase the time string for functions that use ctime_r() and similar (the minimum value is 26).
+ */
+#ifndef _di_f_time_d_
+ #define F_time_calendar_string_length_d 27
+#endif // _di_f_time_d_
+
+/**
+ * A typedef representing struct timeval.
+ */
+#ifndef _di_f_time_value_t_
+ typedef struct timeval f_time_value_t;
+
+ #define f_time_value_t_initialize { 0 }
+#endif // _di_f_time_value_t_
+
+/**
+ * A typedef representing struct tm.
+ */
+#ifndef _di_f_time_part_t_
+ typedef struct tm f_time_part_t;
+
+ #define f_time_part_t_initialize { 0 }
+#endif // _di_f_time_part_t_
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // _F_time_common_h
f_type
f_status
+f_string
build_language c
build_libraries -lc
-build_libraries-individual
+build_libraries-individual -lf_memory -lf_string
build_sources_library time.c
-build_sources_headers time.h
+build_sources_headers time.h time/common.h
build_script yes
build_shared yes
environment PATH LD_LIBRARY_PATH
environment LANG LC_ALL LC_COLLATE LC_CTYPE LC_FASTMSG LC_MESSAGES LC_MONETARY LC_NUMERIC LC_TIME LOCPATH NLSPATH
-defines-threadless -D_di_thread_support_
defines-thread -D_pthread_attr_unsupported_ -D_pthread_sigqueue_unsupported_
+defines-threadless -D_di_thread_support_
flags -O2 -g -fdiagnostics-color=always -Wno-logical-not-parentheses -Wno-parentheses -Wno-missing-braces
flags -fstack-clash-protection -fno-delete-null-pointer-checks
flags -Wl,-z,nodlopen -Wl,-z,noexecstack -Wl,-z,relro -Wl,-z,now
-flags-thread -pthread
flags-clang -Wno-logical-op-parentheses
+flags-coverage -O0 --coverage -fprofile-abs-path -fprofile-dir=build/coverage/
flags-gcc_13 -fstrict-flex-arrays=3
flags-test -O0 -fstack-protector-strong -Wall
-flags-coverage -O0 --coverage -fprofile-abs-path -fprofile-dir=build/coverage/
+flags-thread -pthread
flags_library -fPIC
flags_object -fPIC
--- /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_time
+
+version_major 0
+version_minor 7
+version_micro 0
+version_file micro
+version_target minor
+
+modes individual clang gcc test coverage
+modes_default individual test gcc
+
+build_compiler gcc
+build_compiler-clang clang
+build_indexer ar
+build_indexer_arguments rcs
+build_language c
+
+build_libraries -lc
+build_libraries-individual -lf_memory -lf_string
+
+build_sources_library time.c
+build_sources_library ../../tests/unit/c/mock-time.c
+
+build_sources_headers time.h time/common.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
+
+environment PATH LD_LIBRARY_PATH
+environment LANG LC_ALL LC_COLLATE LC_CTYPE LC_FASTMSG LC_MESSAGES LC_MONETARY LC_NUMERIC LC_TIME LOCPATH NLSPATH
+
+flags -O0 -g -fdiagnostics-color=always -Wno-logical-not-parentheses -Wno-parentheses -Wno-missing-braces
+flags -fstack-clash-protection -fno-delete-null-pointer-checks
+flags -Wl,-z,nodlopen -Wl,-z,noexecstack -Wl,-z,relro -Wl,-z,now
+flags-clang -Wno-logical-op-parentheses
+flags-coverage -O0 --coverage -fprofile-abs-path -fprofile-dir=build/coverage/
+flags-gcc_13 -fstrict-flex-arrays=3
+flags-test -O0 -fstack-protector-strong -Wall
+
+flags_library -fPIC
+
+# Inject mocks.
+flags -Wl,--wrap=asctime_r
+flags -Wl,--wrap=ctime_r
+flags -Wl,--wrap=f_string_append
+flags -Wl,--wrap=gettimeofday
+flags -Wl,--wrap=gmtime_r
+flags -Wl,--wrap=localtime_r
+flags -Wl,--wrap=settimeofday
+flags -Wl,--wrap=time
build_language c
build_libraries -lc -lcmocka
-build_libraries-individual -lf_time
+build_libraries-individual -lf_memory -lf_string -lf_time
+build_sources_program test-time-calendar_string.c test-time-calendar_string_part.c test-time-epoch_get.c
+build_sources_program test-time-of_day_get.c test-time-of_day_set.c
+build_sources_program test-time-local_get.c test-time-utc_get.c
build_sources_program test-time-spec_millisecond.c test-time-spec_nanosecond.c
build_sources_program test-time.c
flags -fstack-clash-protection -fno-delete-null-pointer-checks
flags -Wl,-z,nodlopen -Wl,-z,noexecstack -Wl,-z,relro -Wl,-z,now
flags-clang -Wno-logical-op-parentheses
-flags-gcc_13 -fstrict-flex-arrays=3
-flags-test -fstack-protector-strong -Wall
flags-coverage -O0 --coverage -fprofile-abs-path -fprofile-dir=build/coverage/
+flags-gcc_13 -fstrict-flex-arrays=3
+flags-test -O0 -fstack-protector-strong -Wall
flags_program -fPIE
#define CMOCKA_XML_FILE ./out.xml
main:
- build settings individual test
+ build settings-mocks individual test
build settings-tests individual test
operate build_path
--- /dev/null
+#include "mock-time.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int mock_unwrap = 0;
+int mock_unwrap_f_string = 1;
+
+f_status_t __wrap_f_string_append(const f_string_t source, const f_number_unsigned_t length, f_string_dynamic_t * const destination) {
+
+ if (mock_unwrap_f_string) {
+ return __real_f_string_append(source, length, destination);
+ }
+
+ if (!destination) return F_status_set_error(F_parameter_not);
+
+ const bool failure = mock_type(bool);
+
+ if (failure) return mock_type(f_status_t);
+
+ destination->string = mock_type(f_string_t);
+ destination->used = mock_type(f_number_unsigned_t);
+ destination->size = 0;
+
+ return mock_type(f_status_t);
+}
+
+char *__wrap_asctime_r(const struct tm *tm, char *buf) {
+
+ const bool failure = mock_type(bool);
+
+ if (failure) {
+ errno = mock_type(int);
+
+ return 0;
+ }
+
+ char *str = mock_type(char *);
+
+ strcpy(buf, str);
+
+ return str;
+}
+
+char *__wrap_ctime_r(const time_t *timep, char *buf) {
+
+ const bool failure = mock_type(bool);
+
+ if (failure) {
+ errno = mock_type(int);
+
+ return 0;
+ }
+
+ char *str = mock_type(char *);
+
+ strcpy(buf, str);
+
+ return str;
+}
+
+int __wrap_gettimeofday(struct timeval *tv, struct timezone *tz) {
+
+ const bool failure = mock_type(bool);
+
+ if (failure) {
+ errno = mock_type(int);
+
+ return -1;
+ }
+
+ struct timeval *result = mock_type(struct timeval *);
+
+ if (tv) {
+ *tv = *result;
+ }
+
+ return 0;
+}
+
+struct tm *__wrap_gmtime_r(const time_t *timep, struct tm *result) {
+
+ const bool failure = mock_type(bool);
+
+ if (failure) {
+ errno = mock_type(int);
+
+ return 0;
+ }
+
+ struct tm *res = mock_type(struct tm *);
+
+ if (result) {
+ *result = *res;
+ }
+
+ return res;
+}
+
+struct tm *__wrap_localtime_r(const time_t *timep, struct tm *result) {
+
+ const bool failure = mock_type(bool);
+
+ if (failure) {
+ errno = mock_type(int);
+
+ return 0;
+ }
+
+ struct tm *res = mock_type(struct tm *);
+
+ if (result) {
+ *result = *res;
+ }
+
+ return res;
+}
+
+int __wrap_settimeofday(const struct timeval *tv, const struct timezone *tz) {
+
+ const bool failure = mock_type(bool);
+
+ if (failure) {
+ errno = mock_type(int);
+
+ return -1;
+ }
+
+ return 0;
+}
+
+time_t __wrap_time(time_t *tloc) {
+
+ const bool failure = mock_type(bool);
+
+ if (failure) {
+ errno = mock_type(int);
+
+ return ((time_t) -1);
+ }
+
+ return mock_type(time_t);
+}
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
--- /dev/null
+/**
+ * FLL - Level 0
+ *
+ * Project: Time
+ * API Version: 0.7
+ * Licenses: lgpl-2.1-or-later
+ *
+ * Test the time project.
+ */
+#ifndef _MOCK__time_h
+#define _MOCK__time_h
+
+// Libc includes.
+#include <semaphore.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <setjmp.h>
+#include <stdint.h>
+#include <string.h>
+
+// cmocka includes.
+#include <cmocka.h>
+
+// FLL-0 includes.
+#include <fll/level_0/time.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+const static int mock_errno_generic = 32767;
+
+extern int mock_unwrap;
+extern int mock_unwrap_f_string;
+
+extern f_status_t __real_f_string_append(const f_string_t source, const f_number_unsigned_t length, f_string_dynamic_t * const destination);
+
+extern f_status_t __wrap_f_string_append(const f_string_t source, const f_number_unsigned_t length, f_string_dynamic_t * const destination);
+
+extern char *__wrap_asctime_r(const struct tm *tm, char *buf);
+extern char *__wrap_ctime_r(const time_t *timep, char *buf);
+extern int __wrap_gettimeofday(struct timeval *tv, struct timezone *tz);
+extern struct tm *__wrap_gmtime_r(const time_t *timep, struct tm *result);
+extern struct tm *__wrap_localtime_r(const time_t *timep, struct tm *result);
+extern int __wrap_settimeofday(const struct timeval *tv, const struct timezone *tz);
+extern time_t __wrap_time(time_t *tloc);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // _MOCK__time_h
--- /dev/null
+#include "test-time.h"
+#include "test-time-calendar_string.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void test__f_time_calendar_string__fails(void **state) {
+
+ const time_t time = { 0 };
+ f_string_dynamic_t destination = f_string_dynamic_t_initialize;
+
+ {
+ int errnos[] = {
+ EOVERFLOW,
+ mock_errno_generic,
+ };
+
+ f_status_t statuss[] = {
+ F_status_set_error(F_buffer_overflow),
+ F_status_set_error(F_failure),
+ };
+
+ for (int i = 0; i < 2; ++i) {
+
+ will_return(__wrap_ctime_r, true);
+ will_return(__wrap_ctime_r, errnos[i]);
+
+ const f_status_t status = f_time_calendar_string(time, &destination);
+
+ assert_int_equal(status, statuss[i]);
+ } // for
+ }
+}
+
+void test__f_time_calendar_string__parameter_checking(void **state) {
+
+ const time_t time = { 0 };
+
+ {
+ const f_status_t status = f_time_calendar_string(time, 0);
+
+ assert_int_equal(status, F_status_set_error(F_parameter));
+ }
+}
+
+void test__f_time_calendar_string__works(void **state) {
+
+ mock_unwrap_f_string = 0;
+
+ const time_t time = { 0 };
+ const f_string_static_t example = macro_f_string_static_t_initialize_1("example", 0, 7);
+
+ {
+ f_string_dynamic_t destination = f_string_dynamic_t_initialize;
+
+ f_char_t example_string[255];
+ memset((void *) example_string, 0, 255);
+ memcpy((void *) example_string, example.string, example.used);
+
+ will_return(__wrap_ctime_r, false);
+ will_return(__wrap_ctime_r, example_string);
+ will_return(__wrap_f_string_append, false);
+ will_return(__wrap_f_string_append, example.string);
+ will_return(__wrap_f_string_append, example.used);
+ will_return(__wrap_f_string_append, F_okay);
+
+ const f_status_t status = f_time_calendar_string(time, &destination);
+
+ assert_int_equal(status, F_okay);
+ assert_int_equal(destination.used, example.used);
+ assert_string_equal(destination.string, example.string);
+ }
+}
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
--- /dev/null
+/**
+ * FLL - Level 0
+ *
+ * Project: Time
+ * API Version: 0.7
+ * Licenses: lgpl-2.1-or-later
+ *
+ * Test the time project.
+ */
+#ifndef _TEST__F_time_calendar_string_h
+#define _TEST__F_time_calendar_string_h
+
+/**
+ * Test that function fails.
+ *
+ * @see f_time_calendar_string()
+ */
+extern void test__f_time_calendar_string__fails(void **state);
+
+/**
+ * Test that parameter checking works as expected.
+ *
+ * @see f_time_calendar_string()
+ */
+extern void test__f_time_calendar_string__parameter_checking(void **state);
+
+/**
+ * Test that function works.
+ *
+ * @see f_time_calendar_string()
+ */
+extern void test__f_time_calendar_string__works(void **state);
+
+#endif // _TEST__F_time_calendar_string_h
--- /dev/null
+#include "test-time.h"
+#include "test-time-calendar_string_part.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void test__f_time_calendar_string_part__fails(void **state) {
+
+ const f_time_part_t time = f_time_part_t_initialize;
+ f_string_dynamic_t destination = f_string_dynamic_t_initialize;
+
+ {
+ int errnos[] = {
+ EOVERFLOW,
+ mock_errno_generic,
+ };
+
+ f_status_t statuss[] = {
+ F_status_set_error(F_buffer_overflow),
+ F_status_set_error(F_failure),
+ };
+
+ for (int i = 0; i < 2; ++i) {
+
+ will_return(__wrap_asctime_r, true);
+ will_return(__wrap_asctime_r, errnos[i]);
+
+ const f_status_t status = f_time_calendar_string_part(time, &destination);
+
+ assert_int_equal(status, statuss[i]);
+ } // for
+ }
+}
+
+void test__f_time_calendar_string_part__parameter_checking(void **state) {
+
+ const f_time_part_t time = f_time_part_t_initialize;
+
+ {
+ const f_status_t status = f_time_calendar_string_part(time, 0);
+
+ assert_int_equal(status, F_status_set_error(F_parameter));
+ }
+}
+
+void test__f_time_calendar_string_part__works(void **state) {
+
+ mock_unwrap_f_string = 0;
+
+ const f_time_part_t time = f_time_part_t_initialize;
+ const f_string_static_t example = macro_f_string_static_t_initialize_1("example", 0, 7);
+
+ {
+ f_string_dynamic_t destination = f_string_dynamic_t_initialize;
+
+ f_char_t example_string[255];
+ memset((void *) example_string, 0, 255);
+ memcpy((void *) example_string, example.string, example.used);
+
+ will_return(__wrap_asctime_r, false);
+ will_return(__wrap_asctime_r, example_string);
+ will_return(__wrap_f_string_append, false);
+ will_return(__wrap_f_string_append, example.string);
+ will_return(__wrap_f_string_append, example.used);
+ will_return(__wrap_f_string_append, F_okay);
+
+ const f_status_t status = f_time_calendar_string_part(time, &destination);
+
+ assert_int_equal(status, F_okay);
+ assert_int_equal(destination.used, example.used);
+ assert_string_equal(destination.string, example.string);
+ }
+}
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
--- /dev/null
+/**
+ * FLL - Level 0
+ *
+ * Project: Time
+ * API Version: 0.7
+ * Licenses: lgpl-2.1-or-later
+ *
+ * Test the time project.
+ */
+#ifndef _TEST__F_time_calendar_string_part_h
+#define _TEST__F_time_calendar_string_part_h
+
+/**
+ * Test that function fails.
+ *
+ * @see f_time_calendar_string_part()
+ */
+extern void test__f_time_calendar_string_part__fails(void **state);
+
+/**
+ * Test that parameter checking works as expected.
+ *
+ * @see f_time_calendar_string_part()
+ */
+extern void test__f_time_calendar_string_part__parameter_checking(void **state);
+
+/**
+ * Test that function works.
+ *
+ * @see f_time_calendar_string_part()
+ */
+extern void test__f_time_calendar_string_part__works(void **state);
+
+#endif // _TEST__F_time_calendar_string_part_h
--- /dev/null
+#include "test-time.h"
+#include "test-time-epoch_get.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void test__f_time_epoch_get__fails(void **state) {
+
+ {
+ int errnos[] = {
+ EFAULT,
+ mock_errno_generic,
+ };
+
+ f_status_t statuss[] = {
+ F_status_set_error(F_buffer),
+ F_status_set_error(F_failure),
+ };
+
+ for (int i = 0; i < 2; ++i) {
+
+ time_t time = { 0 };
+
+ will_return(__wrap_time, true);
+ will_return(__wrap_time, errnos[i]);
+
+ const f_status_t status = f_time_epoch_get(&time);
+
+ assert_int_equal(status, statuss[i]);
+ } // for
+ }
+}
+
+void test__f_time_epoch_get__parameter_checking(void **state) {
+
+ {
+ const f_status_t status = f_time_epoch_get(0);
+
+ assert_int_equal(status, F_status_set_error(F_parameter));
+ }
+}
+
+void test__f_time_epoch_get__works(void **state) {
+
+ const time_t expect = 1;
+
+ {
+ time_t time = 0;
+
+ will_return(__wrap_time, false);
+ will_return(__wrap_time, expect);
+
+ const f_status_t status = f_time_epoch_get(&time);
+
+ assert_int_equal(status, F_okay);
+ assert_int_equal(time, expect);
+ }
+}
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
--- /dev/null
+/**
+ * FLL - Level 0
+ *
+ * Project: Time
+ * API Version: 0.7
+ * Licenses: lgpl-2.1-or-later
+ *
+ * Test the time project.
+ */
+#ifndef _TEST__F_time_epoch_get_h
+#define _TEST__F_time_epoch_get_h
+
+/**
+ * Test that function fails.
+ *
+ * @see f_time_epoch_get()
+ */
+extern void test__f_time_epoch_get__fails(void **state);
+
+/**
+ * Test that parameter checking works as expected.
+ *
+ * @see f_time_epoch_get()
+ */
+extern void test__f_time_epoch_get__parameter_checking(void **state);
+
+/**
+ * Test that function works.
+ *
+ * @see f_time_epoch_get()
+ */
+extern void test__f_time_epoch_get__works(void **state);
+
+#endif // _TEST__F_time_epoch_get_h
--- /dev/null
+#include "test-time.h"
+#include "test-time-local_get.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void test__f_time_local_get__fails(void **state) {
+
+ const time_t time = { 0 };
+ f_time_part_t part = f_time_part_t_initialize;
+
+ {
+ int errnos[] = {
+ EOVERFLOW,
+ mock_errno_generic,
+ };
+
+ f_status_t statuss[] = {
+ F_status_set_error(F_buffer_overflow),
+ F_status_set_error(F_failure),
+ };
+
+ for (int i = 0; i < 2; ++i) {
+
+ will_return(__wrap_localtime_r, true);
+ will_return(__wrap_localtime_r, errnos[i]);
+
+ const f_status_t status = f_time_local_get(time, &part);
+
+ assert_int_equal(status, statuss[i]);
+ } // for
+ }
+}
+
+void test__f_time_local_get__parameter_checking(void **state) {
+
+ const time_t time = { 0 };
+
+ {
+ const f_status_t status = f_time_local_get(time, 0);
+
+ assert_int_equal(status, F_status_set_error(F_parameter));
+ }
+}
+
+void test__f_time_local_get__works(void **state) {
+
+ const time_t time = { 0 };
+ const f_time_part_t expect = { .tm_sec = 1, .tm_min = 2, .tm_hour = 3 };
+
+ {
+ f_time_part_t part = f_time_part_t_initialize;
+
+ will_return(__wrap_localtime_r, false);
+ will_return(__wrap_localtime_r, &expect);
+
+ const f_status_t status = f_time_local_get(time, &part);
+
+ assert_int_equal(status, F_okay);
+ assert_int_equal(part.tm_sec, expect.tm_sec);
+ assert_int_equal(part.tm_min, expect.tm_min);
+ assert_int_equal(part.tm_hour, expect.tm_hour);
+ }
+}
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
--- /dev/null
+/**
+ * FLL - Level 0
+ *
+ * Project: Time
+ * API Version: 0.7
+ * Licenses: lgpl-2.1-or-later
+ *
+ * Test the time project.
+ */
+#ifndef _TEST__F_time_local_get_h
+#define _TEST__F_time_local_get_h
+
+/**
+ * Test that function fails.
+ *
+ * @see f_time_local_get()
+ */
+extern void test__f_time_local_get__fails(void **state);
+
+/**
+ * Test that parameter checking works as expected.
+ *
+ * @see f_time_local_get()
+ */
+extern void test__f_time_local_get__parameter_checking(void **state);
+
+/**
+ * Test that function works.
+ *
+ * @see f_time_local_get()
+ */
+extern void test__f_time_local_get__works(void **state);
+
+#endif // _TEST__F_time_local_get_h
--- /dev/null
+#include "test-time.h"
+#include "test-time-of_day_get.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void test__f_time_of_day_get__fails(void **state) {
+
+ {
+ int errnos[] = {
+ EFAULT,
+ EINVAL,
+ EPERM,
+ mock_errno_generic,
+ };
+
+ f_status_t statuss[] = {
+ F_status_set_error(F_buffer),
+ F_status_set_error(F_parameter),
+ F_status_set_error(F_prohibited),
+ F_status_set_error(F_failure),
+ };
+
+ for (int i = 0; i < 4; ++i) {
+
+ f_time_value_t time = f_time_value_t_initialize;
+
+ will_return(__wrap_gettimeofday, true);
+ will_return(__wrap_gettimeofday, errnos[i]);
+
+ const f_status_t status = f_time_of_day_get(&time);
+
+ assert_int_equal(status, statuss[i]);
+ } // for
+ }
+}
+
+void test__f_time_of_day_get__parameter_checking(void **state) {
+
+ {
+ const f_status_t status = f_time_of_day_get(0);
+
+ assert_int_equal(status, F_status_set_error(F_parameter));
+ }
+}
+
+void test__f_time_of_day_get__works(void **state) {
+
+ const f_time_value_t expect = { .tv_sec = 1, .tv_usec = 2 };
+
+ {
+ f_time_value_t time = f_time_value_t_initialize;
+
+ will_return(__wrap_gettimeofday, false);
+ will_return(__wrap_gettimeofday, &expect);
+
+ const f_status_t status = f_time_of_day_get(&time);
+
+ assert_int_equal(status, F_okay);
+ assert_int_equal(time.tv_sec, expect.tv_sec);
+ assert_int_equal(time.tv_usec, expect.tv_usec);
+ }
+}
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
--- /dev/null
+/**
+ * FLL - Level 0
+ *
+ * Project: Time
+ * API Version: 0.7
+ * Licenses: lgpl-2.1-or-later
+ *
+ * Test the time project.
+ */
+#ifndef _TEST__F_time_of_day_get_h
+#define _TEST__F_time_of_day_get_h
+
+/**
+ * Test that function fails.
+ *
+ * @see f_time_of_day_get()
+ */
+extern void test__f_time_of_day_get__fails(void **state);
+
+/**
+ * Test that parameter checking works as expected.
+ *
+ * @see f_time_of_day_get()
+ */
+extern void test__f_time_of_day_get__parameter_checking(void **state);
+
+/**
+ * Test that function works.
+ *
+ * @see f_time_of_day_get()
+ */
+extern void test__f_time_of_day_get__works(void **state);
+
+#endif // _TEST__F_time_of_day_get_h
--- /dev/null
+#include "test-time.h"
+#include "test-time-of_day_set.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void test__f_time_of_day_set__fails(void **state) {
+
+ const f_time_value_t time = f_time_value_t_initialize;
+
+ {
+ int errnos[] = {
+ EFAULT,
+ EINVAL,
+ EPERM,
+ mock_errno_generic,
+ };
+
+ f_status_t statuss[] = {
+ F_status_set_error(F_buffer),
+ F_status_set_error(F_parameter),
+ F_status_set_error(F_prohibited),
+ F_status_set_error(F_failure),
+ };
+
+ for (int i = 0; i < 4; ++i) {
+
+ will_return(__wrap_settimeofday, true);
+ will_return(__wrap_settimeofday, errnos[i]);
+
+ const f_status_t status = f_time_of_day_set(time);
+
+ assert_int_equal(status, statuss[i]);
+ } // for
+ }
+}
+
+void test__f_time_of_day_set__works(void **state) {
+
+ {
+ const f_time_value_t time = f_time_value_t_initialize;
+
+ will_return(__wrap_settimeofday, false);
+
+ const f_status_t status = f_time_of_day_set(time);
+
+ assert_int_equal(status, F_okay);
+ }
+}
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
--- /dev/null
+/**
+ * FLL - Level 0
+ *
+ * Project: Time
+ * API Version: 0.7
+ * Licenses: lgpl-2.1-or-later
+ *
+ * Test the time project.
+ */
+#ifndef _TEST__F_time_of_day_set_h
+#define _TEST__F_time_of_day_set_h
+
+/**
+ * Test that function fails.
+ *
+ * @see f_time_of_day_set()
+ */
+extern void test__f_time_of_day_set__fails(void **state);
+
+/**
+ * Test that function works.
+ *
+ * @see f_time_of_day_set()
+ */
+extern void test__f_time_of_day_set__works(void **state);
+
+#endif // _TEST__F_time_of_day_set_h
--- /dev/null
+#include "test-time.h"
+#include "test-time-utc_get.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void test__f_time_utc_get__fails(void **state) {
+
+ const time_t time = { 0 };
+ f_time_part_t part = f_time_part_t_initialize;
+
+ {
+ int errnos[] = {
+ EOVERFLOW,
+ mock_errno_generic,
+ };
+
+ f_status_t statuss[] = {
+ F_status_set_error(F_buffer_overflow),
+ F_status_set_error(F_failure),
+ };
+
+ for (int i = 0; i < 2; ++i) {
+
+ will_return(__wrap_gmtime_r, true);
+ will_return(__wrap_gmtime_r, errnos[i]);
+
+ const f_status_t status = f_time_utc_get(time, &part);
+
+ assert_int_equal(status, statuss[i]);
+ } // for
+ }
+}
+
+void test__f_time_utc_get__parameter_checking(void **state) {
+
+ const time_t time = { 0 };
+
+ {
+ const f_status_t status = f_time_utc_get(time, 0);
+
+ assert_int_equal(status, F_status_set_error(F_parameter));
+ }
+}
+
+void test__f_time_utc_get__works(void **state) {
+
+ const time_t time = { 0 };
+ const f_time_part_t expect = { .tm_sec = 1, .tm_min = 2, .tm_hour = 3 };
+
+ {
+ f_time_part_t part = f_time_part_t_initialize;
+
+ will_return(__wrap_gmtime_r, false);
+ will_return(__wrap_gmtime_r, &expect);
+
+ const f_status_t status = f_time_utc_get(time, &part);
+
+ assert_int_equal(status, F_okay);
+ assert_int_equal(part.tm_sec, expect.tm_sec);
+ assert_int_equal(part.tm_min, expect.tm_min);
+ assert_int_equal(part.tm_hour, expect.tm_hour);
+ }
+}
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
--- /dev/null
+/**
+ * FLL - Level 0
+ *
+ * Project: Time
+ * API Version: 0.7
+ * Licenses: lgpl-2.1-or-later
+ *
+ * Test the time project.
+ */
+#ifndef _TEST__F_time_utc_get_h
+#define _TEST__F_time_utc_get_h
+
+/**
+ * Test that function fails.
+ *
+ * @see f_time_utc_get()
+ */
+extern void test__f_time_utc_get__fails(void **state);
+
+/**
+ * Test that parameter checking works as expected.
+ *
+ * @see f_time_utc_get()
+ */
+extern void test__f_time_utc_get__parameter_checking(void **state);
+
+/**
+ * Test that function works.
+ *
+ * @see f_time_utc_get()
+ */
+extern void test__f_time_utc_get__works(void **state);
+
+#endif // _TEST__F_time_utc_get_h
int main(void) {
const struct CMUnitTest tests[] = {
+ cmocka_unit_test(test__f_time_calendar_string__fails),
+ cmocka_unit_test(test__f_time_calendar_string_part__fails),
+ cmocka_unit_test(test__f_time_epoch_get__fails),
+ cmocka_unit_test(test__f_time_local_get__fails),
+ cmocka_unit_test(test__f_time_of_day_get__fails),
+ cmocka_unit_test(test__f_time_of_day_set__fails),
+ cmocka_unit_test(test__f_time_utc_get__fails),
+
+ cmocka_unit_test(test__f_time_calendar_string__works),
+ cmocka_unit_test(test__f_time_calendar_string_part__works),
+ cmocka_unit_test(test__f_time_epoch_get__works),
+ cmocka_unit_test(test__f_time_local_get__works),
+ cmocka_unit_test(test__f_time_of_day_get__works),
+ cmocka_unit_test(test__f_time_of_day_set__works),
+ cmocka_unit_test(test__f_time_utc_get__works),
+
cmocka_unit_test(test__f_time_spec_millisecond__number_overflow),
cmocka_unit_test(test__f_time_spec_millisecond__number_underflow),
cmocka_unit_test(test__f_time_spec_millisecond__works),
cmocka_unit_test(test__f_time_spec_nanosecond__works),
#ifndef _di_level_0_parameter_checking_
+ cmocka_unit_test(test__f_time_calendar_string__parameter_checking),
+ cmocka_unit_test(test__f_time_calendar_string_part__parameter_checking),
+ cmocka_unit_test(test__f_time_epoch_get__parameter_checking),
+ cmocka_unit_test(test__f_time_local_get__parameter_checking),
+ cmocka_unit_test(test__f_time_of_day_get__parameter_checking),
+ // f_time_of_day_set() doesn't use parameter checking.
+ cmocka_unit_test(test__f_time_utc_get__parameter_checking),
cmocka_unit_test(test__f_time_spec_millisecond__parameter_checking),
cmocka_unit_test(test__f_time_spec_nanosecond__parameter_checking),
#endif // _di_level_0_parameter_checking_
#include <fll/level_0/time.h>
// Mock includes.
+#include "mock-time.h"
// Test includes.
+#include "test-time-calendar_string.h"
+#include "test-time-calendar_string_part.h"
+#include "test-time-epoch_get.h"
+#include "test-time-local_get.h"
+#include "test-time-of_day_get.h"
+#include "test-time-of_day_set.h"
+#include "test-time-utc_get.h"
#include "test-time-spec_millisecond.h"
#include "test-time-spec_nanosecond.h"