]> Kevux Git Server - fll/commitdiff
Feature: Add additional f_time functions and types that wrap C time functions.
authorKevin Day <kevin@kevux.org>
Fri, 19 Apr 2024 03:39:18 +0000 (22:39 -0500)
committerKevin Day <kevin@kevux.org>
Fri, 19 Apr 2024 03:40:40 +0000 (22:40 -0500)
This also adds the appropriate basic unit tests.

28 files changed:
build/level_0/settings
build/monolithic/settings
level_0/f_time/c/time.c
level_0/f_time/c/time.h
level_0/f_time/c/time/common.h [new file with mode: 0644]
level_0/f_time/data/build/dependencies
level_0/f_time/data/build/settings
level_0/f_time/data/build/settings-mocks [new file with mode: 0644]
level_0/f_time/data/build/settings-tests
level_0/f_time/data/build/testfile
level_0/f_time/tests/unit/c/mock-time.c [new file with mode: 0644]
level_0/f_time/tests/unit/c/mock-time.h [new file with mode: 0644]
level_0/f_time/tests/unit/c/test-time-calendar_string.c [new file with mode: 0644]
level_0/f_time/tests/unit/c/test-time-calendar_string.h [new file with mode: 0644]
level_0/f_time/tests/unit/c/test-time-calendar_string_part.c [new file with mode: 0644]
level_0/f_time/tests/unit/c/test-time-calendar_string_part.h [new file with mode: 0644]
level_0/f_time/tests/unit/c/test-time-epoch_get.c [new file with mode: 0644]
level_0/f_time/tests/unit/c/test-time-epoch_get.h [new file with mode: 0644]
level_0/f_time/tests/unit/c/test-time-local_get.c [new file with mode: 0644]
level_0/f_time/tests/unit/c/test-time-local_get.h [new file with mode: 0644]
level_0/f_time/tests/unit/c/test-time-of_day_get.c [new file with mode: 0644]
level_0/f_time/tests/unit/c/test-time-of_day_get.h [new file with mode: 0644]
level_0/f_time/tests/unit/c/test-time-of_day_set.c [new file with mode: 0644]
level_0/f_time/tests/unit/c/test-time-of_day_set.h [new file with mode: 0644]
level_0/f_time/tests/unit/c/test-time-utc_get.c [new file with mode: 0644]
level_0/f_time/tests/unit/c/test-time-utc_get.h [new file with mode: 0644]
level_0/f_time/tests/unit/c/test-time.c
level_0/f_time/tests/unit/c/test-time.h

index 86321cd81e55c367aa751342cc489cdd07837d70..c204b55e2a3723f10e5318e0a54b69038b21f122 100644 (file)
@@ -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
index dc3fceda24fffaf69af6e108c7c6f20fc4e97d93..da446e503646b398f009226da3ebc9c7da8fac18 100644 (file)
@@ -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
index fe49c3007baed0bab582a1090353cc05cebe2201..578cd5c7e03501e53c8ac56cf2e9c0cb0aba383b 100644 (file)
@@ -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
index f367cd58c94e0d5c909226ae8ad4c025e38310bb..4a3fa34e9a29db149d40de562decfd6c79a60131 100644 (file)
 
 // 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".
@@ -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 (file)
index 0000000..ce1b80c
--- /dev/null
@@ -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
index d9c4b77c5eed2c34cf0396d33ba2f075e8c42ca6..c06dda549b9fdbc94bc26f4ce8d1be439fbd81c4 100644 (file)
@@ -2,3 +2,4 @@
 
 f_type
 f_status
+f_string
index c6c788bbdcbfd0988720813c93fb84e826371c56..5dc83609ea1aecf4cb1b3ffcd203f35f909e5a66 100644 (file)
@@ -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 (file)
index 0000000..c9281a1
--- /dev/null
@@ -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
index 922cc8aac5a20d1a029cffa44aba5220d3bd2d64..f46307c478497d1ee2fa1b0bddb2cb2f22136572 100644 (file)
@@ -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
index d86b3efaba865d7a42e37740c207204667984d81..be9259b392681b4b95f67afcf4930e2b9c75c96e 100644 (file)
@@ -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 (file)
index 0000000..49a2a66
--- /dev/null
@@ -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 (file)
index 0000000..6cd8cbb
--- /dev/null
@@ -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 <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
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 (file)
index 0000000..d8b35f9
--- /dev/null
@@ -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 (file)
index 0000000..56dcef1
--- /dev/null
@@ -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 (file)
index 0000000..2b93b0c
--- /dev/null
@@ -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 (file)
index 0000000..e04f945
--- /dev/null
@@ -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 (file)
index 0000000..1deedda
--- /dev/null
@@ -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 (file)
index 0000000..b2a1270
--- /dev/null
@@ -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 (file)
index 0000000..ea58859
--- /dev/null
@@ -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 (file)
index 0000000..68055b8
--- /dev/null
@@ -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 (file)
index 0000000..6b6a683
--- /dev/null
@@ -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 (file)
index 0000000..a265c3a
--- /dev/null
@@ -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 (file)
index 0000000..8adc47f
--- /dev/null
@@ -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 (file)
index 0000000..f10081c
--- /dev/null
@@ -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 (file)
index 0000000..cf286b0
--- /dev/null
@@ -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 (file)
index 0000000..ec981f8
--- /dev/null
@@ -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
index 7a1439d46f19a025b5eb279b71f032dd64d90447..d578958e3ab835e82bad8843ac6302b2040ac01e 100644 (file)
@@ -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_
index fede1ca56ce9c0929deea6a0319581d61e6b94e5..3c3eae6e4912e5d3b0b78e87aa6d7aa9da88a1da 100644 (file)
 #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"