From: Kevin Day Date: Sat, 3 Aug 2024 05:14:05 +0000 (-0500) Subject: Feature: Add clock get, set, and precision functions to f_time. X-Git-Url: https://git.kevux.org/?a=commitdiff_plain;h=e29c5e68fc6e6683451fdcaebbbf94e5c88847d4;p=fll Feature: Add clock get, set, and precision functions to f_time. --- diff --git a/build/stand_alone/example.config.h b/build/stand_alone/example.config.h index 0b7f135..bb6dc39 100644 --- a/build/stand_alone/example.config.h +++ b/build/stand_alone/example.config.h @@ -8,7 +8,7 @@ // // Example: // echo > /tmp/all.txt -// for i in f_type f_status f_memory f_type_array f_string f_utf f_color f_console f_conversion f_file f_pipe f_print f_rip f_signal f_time f_thread ; do grep -horP '\b_di_f_\w*\b' level_0/$i/c >> /tmp/all.txt ; grep -horP '\b_di_macro_\w*\b' level_0/$i/c >> /tmp/all.txt ; done +// for i in f_type f_status f_memory f_type_array f_string f_utf f_color f_console f_conversion f_file f_pipe f_print f_rip f_signal f_thread f_time ; do grep -horP '\b_di_f_\w*\b' level_0/$i/c >> /tmp/all.txt ; grep -horP '\b_di_macro_\w*\b' level_0/$i/c >> /tmp/all.txt ; done // for i in fl_print ; do grep -horP '\b_di_fl_\w*\b' level_1/$i/c >> /tmp/all.txt ; grep -horP '\b_di_macro_\w*\b' level_1/$i/c >> /tmp/all.txt ; done // for i in fll_error fll_print fll_program ; do grep -horP '\b_di_fll_\w*\b' level_2/$i/c >> /tmp/all.txt ; grep -horP '\b_di_macro_\w*\b' level_2/$i/c >> /tmp/all.txt ; done // sort /tmp/all.txt | uniq | sed -e 's|^_|#define &|g' > /tmp/sorted.txt @@ -1360,6 +1360,9 @@ #define _di_f_thread_unlock_ #define _di_f_time_calendar_string_ #define _di_f_time_calendar_string_part_ +#define _di_f_time_clock_get_ +#define _di_f_time_clock_precision_ +#define _di_f_time_clock_set_ #define _di_f_time_d_ #define _di_f_time_epoch_get_ #define _di_f_time_local_get_ diff --git a/build/stand_alone/firewall.config.h b/build/stand_alone/firewall.config.h index c16c4c3..f4427d3 100644 --- a/build/stand_alone/firewall.config.h +++ b/build/stand_alone/firewall.config.h @@ -1992,6 +1992,9 @@ #define _di_f_thread_unlock_ #define _di_f_time_calendar_string_ #define _di_f_time_calendar_string_part_ +#define _di_f_time_clock_get_ +#define _di_f_time_clock_precision_ +#define _di_f_time_clock_set_ #define _di_f_time_d_ #define _di_f_time_epoch_get_ #define _di_f_time_local_get_ diff --git a/level_0/f_time/c/time.c b/level_0/f_time/c/time.c index be6be87..c061d9f 100644 --- a/level_0/f_time/c/time.c +++ b/level_0/f_time/c/time.c @@ -46,6 +46,69 @@ extern "C" { } #endif // _di_f_time_calendar_string_part_ +#ifndef _di_f_time_clock_get_ + f_status_t f_time_clock_get(const clockid_t code, f_time_spec_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 (clock_gettime(code, time)) { + if (errno == EACCES) return F_status_set_error(F_access_denied); + if (errno == EFAULT) return F_status_set_error(F_buffer); + if (errno == ENODEV) return F_status_set_error(F_device_not); + if (errno == ENOTSUP) return F_status_set_error(F_support_not); + if (errno == EINVAL) return F_status_set_error(F_parameter); + if (errno == EOVERFLOW) return F_status_set_error(F_buffer_overflow); + if (errno == EPERM) return F_status_set_error(F_prohibited); + + return F_status_set_error(F_failure); + } + + return F_okay; + } +#endif // _di_f_time_clock_get_ + +#ifndef _di_f_time_clock_precision_ + f_status_t f_time_clock_precision(const clockid_t code, f_time_spec_t * const precision) { + #ifndef _di_level_0_parameter_checking_ + if (!precision) return F_status_set_error(F_parameter); + #endif // _di_level_0_parameter_checking_ + + if (clock_getres(code, precision)) { + if (errno == EACCES) return F_status_set_error(F_access_denied); + if (errno == EFAULT) return F_status_set_error(F_buffer); + if (errno == ENODEV) return F_status_set_error(F_device_not); + if (errno == ENOTSUP) return F_status_set_error(F_support_not); + if (errno == EINVAL) return F_status_set_error(F_parameter); + if (errno == EOVERFLOW) return F_status_set_error(F_buffer_overflow); + if (errno == EPERM) return F_status_set_error(F_prohibited); + + return F_status_set_error(F_failure); + } + + return F_okay; + } +#endif // _di_f_time_clock_precision_ + +#ifndef _di_f_time_clock_set_ + f_status_t f_time_clock_set(const clockid_t code, const f_time_spec_t time) { + + if (clock_settime(code, &time)) { + if (errno == EACCES) return F_status_set_error(F_access_denied); + if (errno == EFAULT) return F_status_set_error(F_buffer); + if (errno == ENODEV) return F_status_set_error(F_device_not); + if (errno == ENOTSUP) return F_status_set_error(F_support_not); + if (errno == EINVAL) return F_status_set_error(F_parameter); + if (errno == EOVERFLOW) return F_status_set_error(F_buffer_overflow); + if (errno == EPERM) return F_status_set_error(F_prohibited); + + return F_status_set_error(F_failure); + } + + return F_okay; + } +#endif // _di_f_time_clock_set_ + #ifndef _di_f_time_epoch_get_ f_status_t f_time_epoch_get(time_t * const time_value) { #ifndef _di_level_0_parameter_checking_ diff --git a/level_0/f_time/c/time.h b/level_0/f_time/c/time.h index 6bc0d2c..a912956 100644 --- a/level_0/f_time/c/time.h +++ b/level_0/f_time/c/time.h @@ -82,6 +82,91 @@ extern "C" { #endif // _di_f_time_calendar_string_part_ /** + * Get the current seconds and nanoseconds from the system clock. + * + * @param code + * Designates how to get the time from the system clock. + * @param time + * The time retrieved. + * + * Must not be NULL. + * + * @return + * F_okay on success. + * + * F_access_denied (with error bit) on access denied. + * F_buffer (with error bit) if the buffer is invalid. + * F_buffer_overflow (with error bit) if the time stamp does not fit in the time range. + * F_device_not (with error bit) if the system clock is no onger available (such as when a hot-pluggable clock disappears). + * F_parameter (with error bit) if a parameter is invalid. + * F_prohibited (with error bit) if not permitted to perform this operation. + * F_support_not (with error bit) if the operation specified by the code is not supported by the clock. + * + * F_failure (with error bit) on any other error. + * + * @see clock_gettime() + */ +#ifndef _di_f_time_clock_get_ + extern f_status_t f_time_clock_get(const clockid_t code, f_time_spec_t * const time); +#endif // _di_f_time_clock_get_ + +/** + * Get the precision from the system clock. + * + * @param code + * Designates how to get the time from the system clock. + * @param precision + * The clock precision (clock resolution). + * + * Must not be NULL. + * + * @return + * F_okay on success. + * + * F_access_denied (with error bit) on access denied. + * F_buffer (with error bit) if the buffer is invalid. + * F_buffer_overflow (with error bit) if the time stamp does not fit in the time range. + * F_device_not (with error bit) if the system clock is no onger available (such as when a hot-pluggable clock disappears). + * F_parameter (with error bit) if a parameter is invalid. + * F_prohibited (with error bit) if not permitted to perform this operation. + * F_support_not (with error bit) if the operation specified by the code is not supported by the clock. + * + * F_failure (with error bit) on any other error. + * + * @see clock_getres() + */ +#ifndef _di_f_time_clock_precision_ + extern f_status_t f_time_clock_precision(const clockid_t code, f_time_spec_t * const precision); +#endif // _di_f_time_clock_precision_ + +/** + * Set the current seconds and nanoseconds from the system clock. + * + * @param code + * Designates how to set the time of the system clock. + * @param time + * The time to set. + * + * @return + * F_okay on success. + * + * F_access_denied (with error bit) on access denied. + * F_buffer (with error bit) if the buffer is invalid. + * F_buffer_overflow (with error bit) if the time stamp does not fit in the time range. + * F_device_not (with error bit) if the system clock is no onger available (such as when a hot-pluggable clock disappears). + * F_parameter (with error bit) if a parameter is invalid. + * F_prohibited (with error bit) if not permitted to perform this operation. + * F_support_not (with error bit) if the operation specified by the code is not supported by the clock. + * + * F_failure (with error bit) on any other error. + * + * @see clock_settime() + */ +#ifndef _di_f_time_clock_set_ + extern f_status_t f_time_clock_set(const clockid_t code, const f_time_spec_t time); +#endif // _di_f_time_clock_set_ + +/** * Get the current time in seconds since epoch. * * @param time diff --git a/level_0/f_time/data/build/settings-mocks b/level_0/f_time/data/build/settings-mocks index afe10eb..f2503bb 100644 --- a/level_0/f_time/data/build/settings-mocks +++ b/level_0/f_time/data/build/settings-mocks @@ -66,6 +66,9 @@ flags_library -fPIC # Inject mocks. flags -Wl,--wrap=asctime_r +flags -Wl,--wrap=clock_getres +flags -Wl,--wrap=clock_gettime +flags -Wl,--wrap=clock_settime flags -Wl,--wrap=ctime_r flags -Wl,--wrap=f_string_append flags -Wl,--wrap=gettimeofday diff --git a/level_0/f_time/data/build/settings-tests b/level_0/f_time/data/build/settings-tests index 7613e3e..951d644 100644 --- a/level_0/f_time/data/build/settings-tests +++ b/level_0/f_time/data/build/settings-tests @@ -26,6 +26,7 @@ build_libraries -lc -lcmocka 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-clock_get.c test-time-clock_precision.c test-time-clock_set.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-sleep_spec.c test-time-spec_millisecond.c test-time-spec_nanosecond.c diff --git a/level_0/f_time/tests/unit/c/mock-time.c b/level_0/f_time/tests/unit/c/mock-time.c index 72cf1ea..c497bd2 100644 --- a/level_0/f_time/tests/unit/c/mock-time.c +++ b/level_0/f_time/tests/unit/c/mock-time.c @@ -160,6 +160,53 @@ time_t __wrap_time(time_t *tloc) { return mock_type(time_t); } +int __wrap_clock_getres(clockid_t clockid, struct timespec *tp) { + + const bool failure = mock_type(bool); + + if (failure) { + errno = mock_type(int); + + return -1; + } + + if (tp) { + *tp = *mock_type(struct timespec *); + } + + return 0; +} + +int __wrap_clock_gettime(clockid_t clockid, struct timespec *tp) { + + const bool failure = mock_type(bool); + + if (failure) { + errno = mock_type(int); + + return -1; + } + + if (tp) { + *tp = *mock_type(struct timespec *); + } + + return 0; +} + +int __wrap_clock_settime(clockid_t clockid, const struct timespec *tp) { + + const bool failure = mock_type(bool); + + if (failure) { + errno = mock_type(int); + + return -1; + } + + return 0; +} + #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 index 3681a3b..6d72284 100644 --- a/level_0/f_time/tests/unit/c/mock-time.h +++ b/level_0/f_time/tests/unit/c/mock-time.h @@ -39,6 +39,9 @@ extern f_status_t __real_f_string_append(const f_string_t source, const f_number 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 int __wrap_clock_getres(clockid_t clockid, struct timespec *tp); +extern int __wrap_clock_gettime(clockid_t clockid, struct timespec *tp); +extern int __wrap_clock_settime(clockid_t clockid, const struct timespec *tp); 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); diff --git a/level_0/f_time/tests/unit/c/test-time-clock_get.c b/level_0/f_time/tests/unit/c/test-time-clock_get.c new file mode 100644 index 0000000..e80bdf8 --- /dev/null +++ b/level_0/f_time/tests/unit/c/test-time-clock_get.c @@ -0,0 +1,76 @@ +#include "test-time.h" +#include "test-time-clock_get.h" + +#ifdef __cplusplus +extern "C" { +#endif + +void test__f_time_clock_get__fails(void **state) { + + { + int errnos[] = { + EACCES, + EFAULT, + ENODEV, + ENOTSUP, + EINVAL, + EOVERFLOW, + EPERM, + mock_errno_generic, + }; + + f_status_t statuss[] = { + F_status_set_error(F_access_denied), + F_status_set_error(F_buffer), + F_status_set_error(F_device_not), + F_status_set_error(F_support_not), + F_status_set_error(F_parameter), + F_status_set_error(F_buffer_overflow), + F_status_set_error(F_prohibited), + F_status_set_error(F_failure), + }; + + for (int i = 0; i < 8; ++i) { + + f_time_spec_t time = f_time_spec_t_initialize; + + will_return(__wrap_clock_gettime, true); + will_return(__wrap_clock_gettime, errnos[i]); + + const f_status_t status = f_time_clock_get(0, &time); + + assert_int_equal(status, statuss[i]); + } // for + } +} + +void test__f_time_clock_get__parameter_checking(void **state) { + + { + const f_status_t status = f_time_clock_get(0, 0); + + assert_int_equal(status, F_status_set_error(F_parameter)); + } +} + +void test__f_time_clock_get__works(void **state) { + + const f_time_spec_t expect = { .tv_sec = 1, .tv_nsec = 2 }; + + { + f_time_spec_t time = f_time_spec_t_initialize; + + will_return(__wrap_clock_gettime, false); + will_return(__wrap_clock_gettime, &expect); + + const f_status_t status = f_time_clock_get(0, &time); + + assert_int_equal(status, F_okay); + assert_int_equal(time.tv_sec, expect.tv_sec); + assert_int_equal(time.tv_nsec, expect.tv_nsec); + } +} + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/level_0/f_time/tests/unit/c/test-time-clock_get.h b/level_0/f_time/tests/unit/c/test-time-clock_get.h new file mode 100644 index 0000000..19c9282 --- /dev/null +++ b/level_0/f_time/tests/unit/c/test-time-clock_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_clock_get_h +#define _TEST__F_time_clock_get_h + +/** + * Test that function fails. + * + * @see f_time_clock_get() + */ +extern void test__f_time_clock_get__fails(void **state); + +/** + * Test that parameter checking works as expected. + * + * @see f_time_clock_get() + */ +extern void test__f_time_clock_get__parameter_checking(void **state); + +/** + * Test that function works. + * + * @see f_time_clock_get() + */ +extern void test__f_time_clock_get__works(void **state); + +#endif // _TEST__F_time_clock_get_h diff --git a/level_0/f_time/tests/unit/c/test-time-clock_precision.c b/level_0/f_time/tests/unit/c/test-time-clock_precision.c new file mode 100644 index 0000000..8758340 --- /dev/null +++ b/level_0/f_time/tests/unit/c/test-time-clock_precision.c @@ -0,0 +1,76 @@ +#include "test-time.h" +#include "test-time-clock_precision.h" + +#ifdef __cplusplus +extern "C" { +#endif + +void test__f_time_clock_precision__fails(void **state) { + + { + int errnos[] = { + EACCES, + EFAULT, + ENODEV, + ENOTSUP, + EINVAL, + EOVERFLOW, + EPERM, + mock_errno_generic, + }; + + f_status_t statuss[] = { + F_status_set_error(F_access_denied), + F_status_set_error(F_buffer), + F_status_set_error(F_device_not), + F_status_set_error(F_support_not), + F_status_set_error(F_parameter), + F_status_set_error(F_buffer_overflow), + F_status_set_error(F_prohibited), + F_status_set_error(F_failure), + }; + + for (int i = 0; i < 8; ++i) { + + f_time_spec_t time = f_time_spec_t_initialize; + + will_return(__wrap_clock_getres, true); + will_return(__wrap_clock_getres, errnos[i]); + + const f_status_t status = f_time_clock_precision(0, &time); + + assert_int_equal(status, statuss[i]); + } // for + } +} + +void test__f_time_clock_precision__parameter_checking(void **state) { + + { + const f_status_t status = f_time_clock_precision(0, 0); + + assert_int_equal(status, F_status_set_error(F_parameter)); + } +} + +void test__f_time_clock_precision__works(void **state) { + + const f_time_spec_t expect = { .tv_sec = 1, .tv_nsec = 2 }; + + { + f_time_spec_t time = f_time_spec_t_initialize; + + will_return(__wrap_clock_getres, false); + will_return(__wrap_clock_getres, &expect); + + const f_status_t status = f_time_clock_precision(0, &time); + + assert_int_equal(status, F_okay); + assert_int_equal(time.tv_sec, expect.tv_sec); + assert_int_equal(time.tv_nsec, expect.tv_nsec); + } +} + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/level_0/f_time/tests/unit/c/test-time-clock_precision.h b/level_0/f_time/tests/unit/c/test-time-clock_precision.h new file mode 100644 index 0000000..ba74c70 --- /dev/null +++ b/level_0/f_time/tests/unit/c/test-time-clock_precision.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_clock_precision_h +#define _TEST__F_time_clock_precision_h + +/** + * Test that function fails. + * + * @see f_time_clock_precision() + */ +extern void test__f_time_clock_precision__fails(void **state); + +/** + * Test that parameter checking works as expected. + * + * @see f_time_clock_precision() + */ +extern void test__f_time_clock_precision__parameter_checking(void **state); + +/** + * Test that function works. + * + * @see f_time_clock_precision() + */ +extern void test__f_time_clock_precision__works(void **state); + +#endif // _TEST__F_time_clock_precision_h diff --git a/level_0/f_time/tests/unit/c/test-time-clock_set.c b/level_0/f_time/tests/unit/c/test-time-clock_set.c new file mode 100644 index 0000000..00df1cb --- /dev/null +++ b/level_0/f_time/tests/unit/c/test-time-clock_set.c @@ -0,0 +1,62 @@ +#include "test-time.h" +#include "test-time-clock_set.h" + +#ifdef __cplusplus +extern "C" { +#endif + +void test__f_time_clock_set__fails(void **state) { + + const f_time_spec_t time = f_time_spec_t_initialize; + + { + int errnos[] = { + EACCES, + EFAULT, + ENODEV, + ENOTSUP, + EINVAL, + EOVERFLOW, + EPERM, + mock_errno_generic, + }; + + f_status_t statuss[] = { + F_status_set_error(F_access_denied), + F_status_set_error(F_buffer), + F_status_set_error(F_device_not), + F_status_set_error(F_support_not), + F_status_set_error(F_parameter), + F_status_set_error(F_buffer_overflow), + F_status_set_error(F_prohibited), + F_status_set_error(F_failure), + }; + + for (int i = 0; i < 8; ++i) { + + will_return(__wrap_clock_settime, true); + will_return(__wrap_clock_settime, errnos[i]); + + const f_status_t status = f_time_clock_set(0, time); + + assert_int_equal(status, statuss[i]); + } // for + } +} + +void test__f_time_clock_set__works(void **state) { + + { + const f_time_spec_t time = f_time_spec_t_initialize; + + will_return(__wrap_clock_settime, false); + + const f_status_t status = f_time_clock_set(0, time); + + assert_int_equal(status, F_okay); + } +} + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/level_0/f_time/tests/unit/c/test-time-clock_set.h b/level_0/f_time/tests/unit/c/test-time-clock_set.h new file mode 100644 index 0000000..fef1ba6 --- /dev/null +++ b/level_0/f_time/tests/unit/c/test-time-clock_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_clock_set_h +#define _TEST__F_time_clock_set_h + +/** + * Test that function fails. + * + * @see f_time_clock_set() + */ +extern void test__f_time_clock_set__fails(void **state); + +/** + * Test that function works. + * + * @see f_time_clock_set() + */ +extern void test__f_time_clock_set__works(void **state); + +#endif // _TEST__F_time_clock_set_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 e2fe635..8cb17aa 100644 --- a/level_0/f_time/tests/unit/c/test-time.c +++ b/level_0/f_time/tests/unit/c/test-time.c @@ -21,6 +21,9 @@ 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_clock_get__fails), + cmocka_unit_test(test__f_time_clock_precision__fails), + cmocka_unit_test(test__f_time_clock_set__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), @@ -30,6 +33,9 @@ int main(void) { 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_clock_get__works), + cmocka_unit_test(test__f_time_clock_precision__works), + cmocka_unit_test(test__f_time_clock_set__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), @@ -48,6 +54,9 @@ int main(void) { #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_clock_get__parameter_checking), + cmocka_unit_test(test__f_time_clock_precision__parameter_checking), + // f_time_clock_set() doesn't use 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), 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 787929f..def4e7c 100644 --- a/level_0/f_time/tests/unit/c/test-time.h +++ b/level_0/f_time/tests/unit/c/test-time.h @@ -28,6 +28,9 @@ // Test includes. #include "test-time-calendar_string.h" #include "test-time-calendar_string_part.h" +#include "test-time-clock_get.h" +#include "test-time-clock_precision.h" +#include "test-time-clock_set.h" #include "test-time-epoch_get.h" #include "test-time-local_get.h" #include "test-time-of_day_get.h"