From 8d9d2b8610176e55327203615f015706fbf95dfe Mon Sep 17 00:00:00 2001 From: Kevin Day Date: Thu, 18 Apr 2024 22:39:18 -0500 Subject: [PATCH] Feature: Add additional f_time functions and types that wrap C time functions. This also adds the appropriate basic unit tests. --- build/level_0/settings | 8 +- build/monolithic/settings | 8 +- level_0/f_time/c/time.c | 127 +++++++++++++++ level_0/f_time/c/time.h | 173 +++++++++++++++++++++ level_0/f_time/c/time/common.h | 51 ++++++ level_0/f_time/data/build/dependencies | 1 + level_0/f_time/data/build/settings | 10 +- level_0/f_time/data/build/settings-mocks | 75 +++++++++ level_0/f_time/data/build/settings-tests | 9 +- level_0/f_time/data/build/testfile | 2 +- level_0/f_time/tests/unit/c/mock-time.c | 148 ++++++++++++++++++ level_0/f_time/tests/unit/c/mock-time.h | 52 +++++++ .../tests/unit/c/test-time-calendar_string.c | 78 ++++++++++ .../tests/unit/c/test-time-calendar_string.h | 34 ++++ .../tests/unit/c/test-time-calendar_string_part.c | 78 ++++++++++ .../tests/unit/c/test-time-calendar_string_part.h | 34 ++++ level_0/f_time/tests/unit/c/test-time-epoch_get.c | 63 ++++++++ level_0/f_time/tests/unit/c/test-time-epoch_get.h | 34 ++++ level_0/f_time/tests/unit/c/test-time-local_get.c | 69 ++++++++ level_0/f_time/tests/unit/c/test-time-local_get.h | 34 ++++ level_0/f_time/tests/unit/c/test-time-of_day_get.c | 68 ++++++++ level_0/f_time/tests/unit/c/test-time-of_day_get.h | 34 ++++ level_0/f_time/tests/unit/c/test-time-of_day_set.c | 54 +++++++ level_0/f_time/tests/unit/c/test-time-of_day_set.h | 27 ++++ level_0/f_time/tests/unit/c/test-time-utc_get.c | 69 ++++++++ level_0/f_time/tests/unit/c/test-time-utc_get.h | 34 ++++ level_0/f_time/tests/unit/c/test-time.c | 23 +++ level_0/f_time/tests/unit/c/test-time.h | 8 + 28 files changed, 1388 insertions(+), 17 deletions(-) create mode 100644 level_0/f_time/c/time/common.h create mode 100644 level_0/f_time/data/build/settings-mocks create mode 100644 level_0/f_time/tests/unit/c/mock-time.c create mode 100644 level_0/f_time/tests/unit/c/mock-time.h create mode 100644 level_0/f_time/tests/unit/c/test-time-calendar_string.c create mode 100644 level_0/f_time/tests/unit/c/test-time-calendar_string.h create mode 100644 level_0/f_time/tests/unit/c/test-time-calendar_string_part.c create mode 100644 level_0/f_time/tests/unit/c/test-time-calendar_string_part.h create mode 100644 level_0/f_time/tests/unit/c/test-time-epoch_get.c create mode 100644 level_0/f_time/tests/unit/c/test-time-epoch_get.h create mode 100644 level_0/f_time/tests/unit/c/test-time-local_get.c create mode 100644 level_0/f_time/tests/unit/c/test-time-local_get.h create mode 100644 level_0/f_time/tests/unit/c/test-time-of_day_get.c create mode 100644 level_0/f_time/tests/unit/c/test-time-of_day_get.h create mode 100644 level_0/f_time/tests/unit/c/test-time-of_day_set.c create mode 100644 level_0/f_time/tests/unit/c/test-time-of_day_set.h create mode 100644 level_0/f_time/tests/unit/c/test-time-utc_get.c create mode 100644 level_0/f_time/tests/unit/c/test-time-utc_get.h diff --git a/build/level_0/settings b/build/level_0/settings index 86321cd..c204b55 100644 --- a/build/level_0/settings +++ b/build/level_0/settings @@ -119,7 +119,7 @@ build_sources_headers string/map.h string/maps.h string/mapss.h 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 @@ -155,17 +155,17 @@ environment LANG LC_ALL LC_COLLATE LC_CTYPE LC_FASTMSG LC_MESSAGES LC_MONETARY L #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 diff --git a/build/monolithic/settings b/build/monolithic/settings index dc3fced..da446e5 100644 --- a/build/monolithic/settings +++ b/build/monolithic/settings @@ -140,7 +140,7 @@ build_sources_headers level_0/string/map.h level_0/string/maps.h level_0/string/ 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 @@ -198,17 +198,17 @@ environment LANG LC_ALL LC_COLLATE LC_CTYPE LC_FASTMSG LC_MESSAGES LC_MONETARY L #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 diff --git a/level_0/f_time/c/time.c b/level_0/f_time/c/time.c index fe49c30..578cd5c 100644 --- a/level_0/f_time/c/time.c +++ b/level_0/f_time/c/time.c @@ -4,6 +4,117 @@ 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_ @@ -81,6 +192,22 @@ extern "C" { } #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 diff --git a/level_0/f_time/c/time.h b/level_0/f_time/c/time.h index f367cd5..4a3fa34 100644 --- a/level_0/f_time/c/time.h +++ b/level_0/f_time/c/time.h @@ -12,18 +12,166 @@ // Libc includes. #include +#include // FLL-0 includes. #include #include +#include // FLL-0 time includes. +#include #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". @@ -79,6 +227,31 @@ extern "C" { 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 diff --git a/level_0/f_time/c/time/common.h b/level_0/f_time/c/time/common.h new file mode 100644 index 0000000..ce1b80c --- /dev/null +++ b/level_0/f_time/c/time/common.h @@ -0,0 +1,51 @@ +/** + * 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 diff --git a/level_0/f_time/data/build/dependencies b/level_0/f_time/data/build/dependencies index d9c4b77..c06dda5 100644 --- a/level_0/f_time/data/build/dependencies +++ b/level_0/f_time/data/build/dependencies @@ -2,3 +2,4 @@ f_type f_status +f_string diff --git a/level_0/f_time/data/build/settings b/level_0/f_time/data/build/settings index c6c788b..5dc8360 100644 --- a/level_0/f_time/data/build/settings +++ b/level_0/f_time/data/build/settings @@ -32,11 +32,11 @@ build_indexer_arguments rcs 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 @@ -63,17 +63,17 @@ 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 -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 diff --git a/level_0/f_time/data/build/settings-mocks b/level_0/f_time/data/build/settings-mocks new file mode 100644 index 0000000..c9281a1 --- /dev/null +++ b/level_0/f_time/data/build/settings-mocks @@ -0,0 +1,75 @@ +# 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 diff --git a/level_0/f_time/data/build/settings-tests b/level_0/f_time/data/build/settings-tests index 922cc8a..f46307c 100644 --- a/level_0/f_time/data/build/settings-tests +++ b/level_0/f_time/data/build/settings-tests @@ -23,8 +23,11 @@ build_indexer_arguments rcs 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 @@ -53,8 +56,8 @@ flags -O2 -g -fdiagnostics-color=always -Wno-logical-not-parentheses -Wno-parent 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 diff --git a/level_0/f_time/data/build/testfile b/level_0/f_time/data/build/testfile index d86b3ef..be9259b 100644 --- a/level_0/f_time/data/build/testfile +++ b/level_0/f_time/data/build/testfile @@ -18,7 +18,7 @@ settings: #define CMOCKA_XML_FILE ./out.xml main: - build settings individual test + build settings-mocks individual test build settings-tests individual test operate build_path diff --git a/level_0/f_time/tests/unit/c/mock-time.c b/level_0/f_time/tests/unit/c/mock-time.c new file mode 100644 index 0000000..49a2a66 --- /dev/null +++ b/level_0/f_time/tests/unit/c/mock-time.c @@ -0,0 +1,148 @@ +#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 diff --git a/level_0/f_time/tests/unit/c/mock-time.h b/level_0/f_time/tests/unit/c/mock-time.h new file mode 100644 index 0000000..6cd8cbb --- /dev/null +++ b/level_0/f_time/tests/unit/c/mock-time.h @@ -0,0 +1,52 @@ +/** + * 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 +#include +#include +#include +#include +#include + +// cmocka includes. +#include + +// FLL-0 includes. +#include + +#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 diff --git a/level_0/f_time/tests/unit/c/test-time-calendar_string.c b/level_0/f_time/tests/unit/c/test-time-calendar_string.c new file mode 100644 index 0000000..d8b35f9 --- /dev/null +++ b/level_0/f_time/tests/unit/c/test-time-calendar_string.c @@ -0,0 +1,78 @@ +#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 diff --git a/level_0/f_time/tests/unit/c/test-time-calendar_string.h b/level_0/f_time/tests/unit/c/test-time-calendar_string.h new file mode 100644 index 0000000..56dcef1 --- /dev/null +++ b/level_0/f_time/tests/unit/c/test-time-calendar_string.h @@ -0,0 +1,34 @@ +/** + * 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 diff --git a/level_0/f_time/tests/unit/c/test-time-calendar_string_part.c b/level_0/f_time/tests/unit/c/test-time-calendar_string_part.c new file mode 100644 index 0000000..2b93b0c --- /dev/null +++ b/level_0/f_time/tests/unit/c/test-time-calendar_string_part.c @@ -0,0 +1,78 @@ +#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 diff --git a/level_0/f_time/tests/unit/c/test-time-calendar_string_part.h b/level_0/f_time/tests/unit/c/test-time-calendar_string_part.h new file mode 100644 index 0000000..e04f945 --- /dev/null +++ b/level_0/f_time/tests/unit/c/test-time-calendar_string_part.h @@ -0,0 +1,34 @@ +/** + * 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 diff --git a/level_0/f_time/tests/unit/c/test-time-epoch_get.c b/level_0/f_time/tests/unit/c/test-time-epoch_get.c new file mode 100644 index 0000000..1deedda --- /dev/null +++ b/level_0/f_time/tests/unit/c/test-time-epoch_get.c @@ -0,0 +1,63 @@ +#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 diff --git a/level_0/f_time/tests/unit/c/test-time-epoch_get.h b/level_0/f_time/tests/unit/c/test-time-epoch_get.h new file mode 100644 index 0000000..b2a1270 --- /dev/null +++ b/level_0/f_time/tests/unit/c/test-time-epoch_get.h @@ -0,0 +1,34 @@ +/** + * 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 diff --git a/level_0/f_time/tests/unit/c/test-time-local_get.c b/level_0/f_time/tests/unit/c/test-time-local_get.c new file mode 100644 index 0000000..ea58859 --- /dev/null +++ b/level_0/f_time/tests/unit/c/test-time-local_get.c @@ -0,0 +1,69 @@ +#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 diff --git a/level_0/f_time/tests/unit/c/test-time-local_get.h b/level_0/f_time/tests/unit/c/test-time-local_get.h new file mode 100644 index 0000000..68055b8 --- /dev/null +++ b/level_0/f_time/tests/unit/c/test-time-local_get.h @@ -0,0 +1,34 @@ +/** + * 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 diff --git a/level_0/f_time/tests/unit/c/test-time-of_day_get.c b/level_0/f_time/tests/unit/c/test-time-of_day_get.c new file mode 100644 index 0000000..6b6a683 --- /dev/null +++ b/level_0/f_time/tests/unit/c/test-time-of_day_get.c @@ -0,0 +1,68 @@ +#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 diff --git a/level_0/f_time/tests/unit/c/test-time-of_day_get.h b/level_0/f_time/tests/unit/c/test-time-of_day_get.h new file mode 100644 index 0000000..a265c3a --- /dev/null +++ b/level_0/f_time/tests/unit/c/test-time-of_day_get.h @@ -0,0 +1,34 @@ +/** + * 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 diff --git a/level_0/f_time/tests/unit/c/test-time-of_day_set.c b/level_0/f_time/tests/unit/c/test-time-of_day_set.c new file mode 100644 index 0000000..8adc47f --- /dev/null +++ b/level_0/f_time/tests/unit/c/test-time-of_day_set.c @@ -0,0 +1,54 @@ +#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 diff --git a/level_0/f_time/tests/unit/c/test-time-of_day_set.h b/level_0/f_time/tests/unit/c/test-time-of_day_set.h new file mode 100644 index 0000000..f10081c --- /dev/null +++ b/level_0/f_time/tests/unit/c/test-time-of_day_set.h @@ -0,0 +1,27 @@ +/** + * 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 diff --git a/level_0/f_time/tests/unit/c/test-time-utc_get.c b/level_0/f_time/tests/unit/c/test-time-utc_get.c new file mode 100644 index 0000000..cf286b0 --- /dev/null +++ b/level_0/f_time/tests/unit/c/test-time-utc_get.c @@ -0,0 +1,69 @@ +#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 diff --git a/level_0/f_time/tests/unit/c/test-time-utc_get.h b/level_0/f_time/tests/unit/c/test-time-utc_get.h new file mode 100644 index 0000000..ec981f8 --- /dev/null +++ b/level_0/f_time/tests/unit/c/test-time-utc_get.h @@ -0,0 +1,34 @@ +/** + * 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 diff --git a/level_0/f_time/tests/unit/c/test-time.c b/level_0/f_time/tests/unit/c/test-time.c index 7a1439d..d578958 100644 --- a/level_0/f_time/tests/unit/c/test-time.c +++ b/level_0/f_time/tests/unit/c/test-time.c @@ -19,6 +19,22 @@ int setdown(void **state) { 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), @@ -28,6 +44,13 @@ int main(void) { 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_ diff --git a/level_0/f_time/tests/unit/c/test-time.h b/level_0/f_time/tests/unit/c/test-time.h index fede1ca..3c3eae6 100644 --- a/level_0/f_time/tests/unit/c/test-time.h +++ b/level_0/f_time/tests/unit/c/test-time.h @@ -23,8 +23,16 @@ #include // 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" -- 1.8.3.1