]> Kevux Git Server - fll/commitdiff
Feature: Add f_network_to_ip_string() and f_network_from_ip_string() functions.
authorKevin Day <kevin@kevux.org>
Thu, 22 Jun 2023 03:26:54 +0000 (22:26 -0500)
committerKevin Day <kevin@kevux.org>
Thu, 22 Jun 2023 03:29:42 +0000 (22:29 -0500)
Provide support for inet_ntop() and inet_pton().

String are handling in FLL via f_string_static_t and f_string_dynamic_t.
The functions f_network_to_ip_string() and f_network_from_ip_string() are written to convert to these string types.

This implements a custom f_network_family_ip_t type to pass the digit IP address.
The idea here is to help reduce how much the FLL API is locked into the "libc" or POSIX API.

The structures are allocated using "{ 0 }" to take advantage of the supposed relatively new feature that treats this as an initialize all to NULL.

18 files changed:
build/level_0/settings
build/monolithic/settings
level_0/f_network/c/network.c
level_0/f_network/c/network.h
level_0/f_network/c/network/common.h [new file with mode: 0644]
level_0/f_network/data/build/dependencies
level_0/f_network/data/build/settings
level_0/f_network/data/build/settings-mocks
level_0/f_network/data/build/settings-tests
level_0/f_network/tests/unit/c/mock-network.c
level_0/f_network/tests/unit/c/mock-network.h
level_0/f_network/tests/unit/c/test-network-from_host_long.h
level_0/f_network/tests/unit/c/test-network-from_ip_string.c [new file with mode: 0644]
level_0/f_network/tests/unit/c/test-network-from_ip_string.h [new file with mode: 0644]
level_0/f_network/tests/unit/c/test-network-to_ip_string.c [new file with mode: 0644]
level_0/f_network/tests/unit/c/test-network-to_ip_string.h [new file with mode: 0644]
level_0/f_network/tests/unit/c/test-network.c
level_0/f_network/tests/unit/c/test-network.h

index 8a29bfab8f4c7cb337ea3ca8f183d5a366d23e8b..c0525d0311ccd069f88f283756d89cfb616a1f16 100644 (file)
@@ -106,7 +106,7 @@ build_sources_headers fss.h fss/comment.h fss/common.h fss/delimit.h fss/named.h
 build_sources_headers iki.h iki/common.h iki/data.h
 build_sources_headers limit.h limit/set.h limit/value.h
 build_sources_headers memory.h memory/structure.h memory/common.h
-build_sources_headers network.h
+build_sources_headers network.h network/common.h
 build_sources_headers parse.h parse/utf.h
 build_sources_headers path.h path/common.h
 build_sources_headers pipe.h
index 8a15e3de55bd58381b1a807cce11b6dc18dedf1b..a0e42b878f632cbc37e0408c266964f8d86ba05d 100644 (file)
@@ -128,7 +128,7 @@ build_sources_headers level_0/fss.h level_0/fss/comment.h level_0/fss/common.h l
 build_sources_headers level_0/iki.h level_0/iki/common.h level_0/iki/data.h
 build_sources_headers level_0/limit.h level_0/limit/set.h level_0/limit/value.h
 build_sources_headers level_0/memory.h level_0/memory/structure.h level_0/memory/common.h
-build_sources_headers level_0/network.h
+build_sources_headers level_0/network.h network/common.h
 build_sources_headers level_0/parse.h level_0/parse/utf.h
 build_sources_headers level_0/path.h level_0/path/common.h
 build_sources_headers level_0/pipe.h
index 5d0389e6df1d788b770d3ba69be530bd886b2792..d2699553fb949aa63be613196dd98ac0d47f6fa0 100644 (file)
@@ -5,7 +5,7 @@ extern "C" {
 #endif
 
 #ifndef _di_f_network_from_host_long_
-  f_status_t f_network_from_host_long(const uint32_t from, uint32_t *to) {
+  f_status_t f_network_from_host_long(const uint32_t from, uint32_t * const to) {
     #ifndef _di_level_0_parameter_checking_
       if (!to) return F_status_set_error(F_parameter);
     #endif // _di_level_0_parameter_checking_
@@ -17,7 +17,7 @@ extern "C" {
 #endif // _di_f_network_from_host_long_
 
 #ifndef _di_f_network_from_host_short_
-  f_status_t f_network_from_host_short(const uint16_t from, uint16_t *to) {
+  f_status_t f_network_from_host_short(const uint16_t from, uint16_t * const to) {
     #ifndef _di_level_0_parameter_checking_
       if (!to) return F_status_set_error(F_parameter);
     #endif // _di_level_0_parameter_checking_
@@ -28,8 +28,26 @@ extern "C" {
   }
 #endif // _di_f_network_from_host_short_
 
+#ifndef _di_f_network_from_ip_string_
+  f_status_t f_network_from_ip_string(const f_string_static_t from, f_network_family_ip_t * const to) {
+    #ifndef _di_level_0_parameter_checking_
+      if (!to) return F_status_set_error(F_parameter);
+    #endif // _di_level_0_parameter_checking_
+
+    if (!from.used || to->type == f_network_family_none_e) return F_data_not;
+
+    if (inet_pton(to->type == f_network_family_ip_4_e ? AF_INET : AF_INET6, from.string, (void *) & to->address) == -1) {
+      if (errno == EAFNOSUPPORT) return F_status_set_error(F_support_not);
+
+      return F_status_set_error(F_failure);
+    }
+
+    return F_none;
+  }
+#endif // _di_f_network_from_ip_string_
+
 #ifndef _di_f_network_to_host_long_
-  f_status_t f_network_to_host_long(const uint32_t from, uint32_t *to) {
+  f_status_t f_network_to_host_long(const uint32_t from, uint32_t * const to) {
     #ifndef _di_level_0_parameter_checking_
       if (!to) return F_status_set_error(F_parameter);
     #endif // _di_level_0_parameter_checking_
@@ -41,7 +59,7 @@ extern "C" {
 #endif // _di_f_network_to_host_long_
 
 #ifndef _di_f_network_to_host_short_
-  f_status_t f_network_to_host_short(const uint16_t from, uint16_t *to) {
+  f_status_t f_network_to_host_short(const uint16_t from, uint16_t * const to) {
     #ifndef _di_level_0_parameter_checking_
       if (!to) return F_status_set_error(F_parameter);
     #endif // _di_level_0_parameter_checking_
@@ -52,6 +70,37 @@ extern "C" {
   }
 #endif // _di_f_network_to_host_short_
 
+#ifndef _di_f_network_to_ip_string_
+  f_status_t f_network_to_ip_string(const f_network_family_ip_t from, f_string_dynamic_t * const to) {
+    #ifndef _di_level_0_parameter_checking_
+      if (!to) return F_status_set_error(F_parameter);
+    #endif // _di_level_0_parameter_checking_
+
+    if (!(from.type == f_network_family_ip_4_e || from.type == f_network_family_ip_6_e)) return F_data_not;
+
+    {
+      const f_status_t status = f_string_dynamic_increase_by((from.type == f_network_family_ip_4_e ? INET_ADDRSTRLEN : INET6_ADDRSTRLEN) + 1, to);
+      if (F_status_is_error(status)) return status;
+    }
+
+    if (!inet_ntop(from.type == f_network_family_ip_4_e ? AF_INET : AF_INET6, (void *) & from.address, to->string + to->used, from.type == f_network_family_ip_4_e ? INET_ADDRSTRLEN : INET6_ADDRSTRLEN)) {
+      if (errno == EAFNOSUPPORT) return F_status_set_error(F_support_not);
+      if (errno == ENOSPC) return F_status_set_error(F_space_not);
+
+      return F_status_set_error(F_failure);
+    }
+
+    while (to->used < to->size && to->string[to->used]) {
+      ++to->used;
+    } // while
+
+    // The string should be NULL terminated, but in case it is not, ensure one always exists.
+    to->string[to->used] = 0;
+
+    return F_none;
+  }
+#endif // _di_f_network_to_ip_string_
+
 #ifdef __cplusplus
 } // extern "C"
 #endif
index d782371b3a4eb7ab784d89c5b6c1f7245737f76b..407f1c91f0ffef27ecbcd9d6f7ac51d79d5e96dd 100644 (file)
 // FLL-0 includes.
 #include <fll/level_0/type.h>
 #include <fll/level_0/status.h>
+#include <fll/level_0/string.h>
 
 // FLL-0 network includes.
+#include <fll/level_0/network/common.h>
 
 #ifdef __cplusplus
 extern "C" {
@@ -39,7 +41,7 @@ extern "C" {
  * @see htonl()
  */
 #ifndef _di_f_network_from_host_long_
-  extern f_status_t f_network_from_host_long(const uint32_t from, uint32_t *to);
+  extern f_status_t f_network_from_host_long(const uint32_t from, uint32_t * const to);
 #endif // _di_f_network_from_host_long_
 
 /**
@@ -58,10 +60,35 @@ extern "C" {
  * @see htons()
  */
 #ifndef _di_f_network_from_host_short_
-  extern f_status_t f_network_from_host_short(const uint16_t from, uint16_t *to);
+  extern f_status_t f_network_from_host_short(const uint16_t from, uint16_t * const to);
 #endif // _di_f_network_from_host_short_
 
 /**
+ * Convert from a human-friendly string into a network IP address digit.
+ *
+ * This is for the ip address and is not for the domain name.
+ *
+ * @param from
+ *   The human-friendly ip address string.
+ * @param to
+ *   The converted IP version 4 or version 6 family integer.
+ *
+ * @return
+ *   F_none on success.
+ *   F_data_not on success but there is nothing to convert (to.type is f_network_family_none_e or from.used is 0).
+ *
+ *   F_parameter (with error bit) if a parameter is invalid.
+ *   F_space_not (with error bit) if not enough space is available in to.string.
+ *   F_support_not (with error bit) if an invalid address family type is passed to inet_pton().
+ *   F_failure (with error bit) on any other error.
+ *
+ * @see inet_pton()
+ */
+#ifndef _di_f_network_from_ip_string_
+  extern f_status_t f_network_from_ip_string(const f_string_static_t from, f_network_family_ip_t * const to);
+#endif // _di_f_network_from_ip_string_
+
+/**
  * Convert from network byte order to host byte order for an unsigned long integer.
  *
  * @param from
@@ -77,7 +104,7 @@ extern "C" {
  * @see ntohl()
  */
 #ifndef _di_f_network_to_host_long_
-  extern f_status_t f_network_to_host_long(const uint32_t from, uint32_t *to);
+  extern f_status_t f_network_to_host_long(const uint32_t from, uint32_t * const to);
 #endif // _di_f_network_to_host_long_
 
 /**
@@ -96,9 +123,38 @@ extern "C" {
  * @see ntohs()
  */
 #ifndef _di_f_network_to_host_short_
-  extern f_status_t f_network_to_host_short(const uint16_t from, uint16_t *to);
+  extern f_status_t f_network_to_host_short(const uint16_t from, uint16_t * const to);
 #endif // _di_f_network_to_host_short_
 
+/**
+ * Convert from a network IP address digit into a human-friendly string.
+ *
+ * This is for the ip address and is not for the domain name.
+ *
+ * @param from
+ *   The IP version 4 or version 6 family integer.
+ * @param to
+ *   The converted human-friendly ip address string.
+ *
+ * @return
+ *   F_none on success.
+ *   F_data_not on success but there is nothing to convert (from.type is f_network_family_none_e).
+ *
+ *   F_parameter (with error bit) if a parameter is invalid.
+ *   F_space_not (with error bit) if not enough space is available in to.string.
+ *   F_support_not (with error bit) if an invalid address family type is passed to inet_ntop().
+ *   F_failure (with error bit) on any other error.
+ *
+ *   Errors (with error bit) from: f_string_dynamic_increase_by()
+ *
+ * @see inet_ntop()
+ *
+ * @see f_string_dynamic_increase_by()
+ */
+#ifndef _di_f_network_to_ip_string_
+  extern f_status_t f_network_to_ip_string(const f_network_family_ip_t from, f_string_dynamic_t * const to);
+#endif // _di_f_network_to_ip_string_
+
 #ifdef __cplusplus
 } // extern "C"
 #endif
diff --git a/level_0/f_network/c/network/common.h b/level_0/f_network/c/network/common.h
new file mode 100644 (file)
index 0000000..b78f3a2
--- /dev/null
@@ -0,0 +1,93 @@
+/**
+ * FLL - Level 0
+ *
+ * Project: Network
+ * API Version: 0.7
+ * Licenses: lgpl-2.1-or-later
+ *
+ * Defines network common data.
+ *
+ * This is auto-included by network.h and should not need to be explicitly included.
+ */
+#ifndef _F_network_common_h
+#define _F_network_common_h
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Designate an ip address family.
+ *
+ * f_network_family_*_e:
+ *   - none: Represents address family is not set.
+ *   - ip_4: Represents IP address family version 4, similar to AF_INET.
+ *   - ip_6: Represents IP address family version 6, similar to AF_INET6.
+ */
+#ifndef _di_f_network_family_e_
+  enum {
+    f_network_family_none_e = 0,
+    f_network_family_ip_4_e,
+    f_network_family_ip_6_e,
+  }; // enum
+#endif // _di_f_network_family_e_
+
+/**
+ * A union for representing either an IP version 4 or IP version 6 structure.
+ *
+ * v4: The IP version 4.
+ * v6: The IP version 6.
+ *
+ * macro_f_network_family_ip_4_or_6_t_*:
+ *   - initialize_1: Specifically initialize the IP address version 4.
+ *   - initialize_2: Specifically initialize the IP address version 6.
+ *   - clear:        Clear the union values.
+ */
+#ifndef _di_f_network_family_ip_4_or_6_t_
+  typedef union {
+    struct in_addr v4;
+    struct in6_addr v6;
+  } f_network_family_ip_4_or_6_t;
+
+  #define f_network_family_ip_4_or_6_t_initialize { 0 }
+
+  #define macro_f_network_family_ip_4_or_6_t_initialize_1(v4) { .v4 = v4 }
+  #define macro_f_network_family_ip_4_or_6_t_initialize_2(v6) { .v6 = v6 }
+
+  #define f_network_family_ip_4_or_6_t_clear(family_ip_4_or_6) \
+    family_ip_4_or_6.v4 = 0; \
+    family_ip_4_or_6.v6 = 0;
+#endif // _di_f_network_family_ip_4_or_6_t_
+
+/**
+ * A structure for managing an IP address version 4 or 6.
+ *
+ * type:    The type, usually either one of f_network_family_ip_4_e or f_network_family_ip_6_e.
+ * address: The address data.
+ *
+ * macro_f_network_family_ip_4_or_6_t_*:
+ *   - initialize_1: Specifically initialize the IP address version 4.
+ *   - initialize_2: Specifically initialize the IP address version 6.
+ *   - clear:        Clear the union values.
+ */
+#ifndef _di_f_network_family_ip_t_
+  typedef struct {
+    uint8_t type;
+    f_network_family_ip_4_or_6_t address;
+  } f_network_family_ip_t;
+
+  #define f_network_family_ip_t_initialize { 0 }
+
+  #define macro_f_network_family_ip_t_initialize_1(v4) { f_network_family_ip_4_e, macro_f_network_family_ip_4_or_6_t_initialize_1(v4) }
+  #define macro_f_network_family_ip_t_initialize_2(v6) { f_network_family_ip_6_e, macro_f_network_family_ip_4_or_6_t_initialize_2(v6) }
+
+  #define f_network_family_ip_t_clear(family_ip) \
+    family_ip.type = f_network_family_none_e; \
+    f_network_family_ip_t_clear(family_ip.address)
+#endif // _di_f_network_family_ip_t_
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // _F_network_common_h
index d9c4b77c5eed2c34cf0396d33ba2f075e8c42ca6..d7982451c2bbeffe333ccd4738a6e98f3c11da92 100644 (file)
@@ -2,3 +2,5 @@
 
 f_type
 f_status
+f_memory
+f_string
index eb683e4775c8a01ebf152a950f4532f3a8b0b93d..cb8d96bfecb12f0f2d7599c7d00aeaf381bc00d5 100644 (file)
@@ -30,11 +30,11 @@ build_indexer_arguments rcs
 build_language c
 
 build_libraries -lc
-build_libraries-individual
+build_libraries-individual -lf_memory -lf_string
 
 build_sources_library network.c
 
-build_sources_headers network.h
+build_sources_headers network.h network/common.h
 
 build_script yes
 build_shared yes
index 6a708708ca759ba1b985d7e58c120ff145467509..e3d51f3ef93425aa74d5aa8488587a2f73cc5dd8 100644 (file)
@@ -22,7 +22,7 @@ build_libraries-individual
 
 build_sources_library network.c ../../tests/unit/c/mock-network.c
 
-build_sources_headers network.h
+build_sources_headers network.h network/common.h
 
 build_script yes
 build_shared yes
@@ -50,5 +50,7 @@ flags_library -fPIC
 # Inject mocks.
 flags -Wl,--wrap=htonl
 flags -Wl,--wrap=htons
+flags -Wl,--wrap=inet_ntop
+flags -Wl,--wrap=inet_pton
 flags -Wl,--wrap=ntohl
 flags -Wl,--wrap=ntohs
index ce8bc659be58433ed0edaa3d8a82b8922a4efe45..12156bdadf99d9f67081aa96aff70c1f70ce37b9 100644 (file)
@@ -23,9 +23,9 @@ build_indexer_arguments rcs
 build_language c
 
 build_libraries -lc -lcmocka
-build_libraries-individual -lf_network
+build_libraries-individual -lf_memory -lf_string -lf_network
 
-build_sources_program test-network-from_host_long.c test-network-from_host_short.c test-network-to_host_long.c test-network-to_host_short.c
+build_sources_program test-network-from_host_long.c test-network-from_host_short.c test-network-from_ip_string.c test-network-to_host_long.c test-network-to_host_short.c test-network-to_ip_string.c
 build_sources_program test-network.c
 
 build_script no
index e3c39861af416805e03821a9a43c217718ac1382..b8f1d0dfcb163502297cd208f588e070f7dbf1d1 100644 (file)
@@ -14,6 +14,27 @@ uint16_t __wrap_htons(uint16_t hostshort) {
   return mock_type(uint16_t);
 }
 
+const char *__wrap_inet_ntop(int af, const void *src, char *dst, socklen_t size) {
+
+  const bool failure = mock_type(bool);
+
+  if (failure) {
+    errno = mock_type(int);
+
+    return 0;
+  }
+
+  char *string = mock_type(char *);
+  size_t total = mock_type(size_t);
+
+  if (dst) {
+    memcpy(dst, string, total);
+    dst[total] = 0;
+  }
+
+  return dst;
+}
+
 uint32_t __wrap_ntohl(uint32_t netlong) {
 
   return mock_type(uint32_t);
@@ -24,6 +45,19 @@ uint16_t __wrap_ntohs(uint16_t netshort) {
   return mock_type(uint16_t);
 }
 
+int __wrap_inet_pton(int af, const char *src, void *dst) {
+
+  const bool failure = mock_type(bool);
+
+  if (failure) {
+    errno = mock_type(int);
+
+    return -1;
+  }
+
+  return 0;
+}
+
 #ifdef __cplusplus
 } // extern "C"
 #endif
index c450df3b49c805b9915a00dc8ba4db256a2dc3a0..5733e36ae0153bf57162e7a7f8777a01bfa5a2be 100644 (file)
@@ -15,6 +15,7 @@
 #include <stddef.h>
 #include <setjmp.h>
 #include <stdint.h>
+#include <string.h>
 
 // cmocka includes.
 #include <cmocka.h>
@@ -30,8 +31,10 @@ const static int mock_errno_generic = 32767;
 
 extern uint32_t __wrap_htonl(uint32_t hostlong);
 extern uint16_t __wrap_htons(uint16_t hostshort);
+const char *__wrap_inet_ntop(int af, const void *src, char *dst, socklen_t size);
 extern uint32_t __wrap_ntohl(uint32_t netlong);
 extern uint16_t __wrap_ntohs(uint16_t netshort);
+extern int __wrap_inet_pton(int af, const char *src, void *dst);
 
 #ifdef __cplusplus
 } // extern "C"
index 5c0fbf826a012502bc08cecbcc76a4edc04c4742..8110ab0d8c589d671f33f3b76fdf64f025b88523 100644 (file)
@@ -1,7 +1,7 @@
 /**
  * FLL - Level 0
  *
- * Project: Limit
+ * Project: Network
  * API Version: 0.7
  * Licenses: lgpl-2.1-or-later
  *
diff --git a/level_0/f_network/tests/unit/c/test-network-from_ip_string.c b/level_0/f_network/tests/unit/c/test-network-from_ip_string.c
new file mode 100644 (file)
index 0000000..a0bd722
--- /dev/null
@@ -0,0 +1,81 @@
+#include "test-network.h"
+#include "test-network-from_ip_string.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void test__f_network_from_ip_string__fails(void **state) {
+
+  int errnos[] = {
+    EAFNOSUPPORT,
+    mock_errno_generic,
+  };
+
+  f_status_t statuss[] = {
+    F_support_not,
+    F_failure,
+  };
+
+  for (uint8_t i = 0; i < 2; ++i) {
+
+    f_network_family_ip_t family = f_network_family_ip_t_initialize;
+
+    will_return(__wrap_inet_pton, true);
+    will_return(__wrap_inet_pton, errnos[i]);
+
+    const f_status_t status = f_network_from_ip_string(f_string_empty_s, &family);
+
+    assert_int_equal(status, F_status_set_error(statuss[i]));
+  } // for
+}
+
+void test__f_network_from_ip_string__parameter_checking(void **state) {
+
+  {
+    const f_status_t status = f_network_from_ip_string(f_string_empty_s, 0);
+
+    assert_int_equal(status, F_status_set_error(F_parameter));
+  }
+}
+
+void test__f_network_from_ip_string__returns_data_not(void **state) {
+
+  f_network_family_ip_t family = f_network_family_ip_t_initialize;
+
+  const f_string_static_t ip = macro_f_string_static_t_initialize_1("127.0.0.1", 0, 9);
+
+  {
+    const f_status_t status = f_network_from_ip_string(ip, &family);
+
+    assert_int_equal(status, F_data_not);
+  }
+
+  family.type = f_network_family_ip_4_e;
+
+  {
+    const f_status_t status = f_network_from_ip_string(f_string_empty_s, &family);
+
+    assert_int_equal(status, F_data_not);
+  }
+}
+
+void test__f_network_from_ip_string__works(void **state) {
+
+  f_network_family_ip_t family = f_network_family_ip_t_initialize;
+  family.type = f_network_family_ip_4_e;
+
+  const f_string_static_t ip = macro_f_string_static_t_initialize_1("127.0.0.1", 0, 9);
+
+  {
+    will_return(__wrap_inet_pton, false);
+
+    const f_status_t status = f_network_from_ip_string(ip, &family);
+
+    assert_int_equal(status, F_none);
+  }
+}
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
diff --git a/level_0/f_network/tests/unit/c/test-network-from_ip_string.h b/level_0/f_network/tests/unit/c/test-network-from_ip_string.h
new file mode 100644 (file)
index 0000000..cbcbf3f
--- /dev/null
@@ -0,0 +1,41 @@
+/**
+ * FLL - Level 0
+ *
+ * Project: Network
+ * API Version: 0.7
+ * Licenses: lgpl-2.1-or-later
+ *
+ * Test the network project.
+ */
+#ifndef _TEST__F_network_from_ip_string_h
+#define _TEST__F_network_from_ip_string_h
+
+/**
+ * Test that function fails.
+ *
+ * @see f_network_from_ip_string()
+ */
+extern void test__f_network_from_ip_string__fails(void **state);
+
+/**
+ * Test that parameter checking works as expected.
+ *
+ * @see f_network_from_ip_string()
+ */
+extern void test__f_network_from_ip_string__parameter_checking(void **state);
+
+/**
+ * Test that function works but the string is empty or the address.type is 0.
+ *
+ * @see f_network_from_ip_string()
+ */
+extern void test__f_network_from_ip_string__returns_data_not(void **state);
+
+/**
+ * Test that function works.
+ *
+ * @see f_network_from_ip_string()
+ */
+extern void test__f_network_from_ip_string__works(void **state);
+
+#endif // _TEST__F_network_from_ip_string_h
diff --git a/level_0/f_network/tests/unit/c/test-network-to_ip_string.c b/level_0/f_network/tests/unit/c/test-network-to_ip_string.c
new file mode 100644 (file)
index 0000000..218c7f2
--- /dev/null
@@ -0,0 +1,89 @@
+#include "test-network.h"
+#include "test-network-to_ip_string.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void test__f_network_to_ip_string__fails(void **state) {
+
+  f_network_family_ip_t family = f_network_family_ip_t_initialize;
+  f_string_dynamic_t ip = f_string_dynamic_t_initialize;
+
+  int errnos[] = {
+    EAFNOSUPPORT,
+    ENOSPC,
+    mock_errno_generic,
+  };
+
+  f_status_t statuss[] = {
+    F_support_not,
+    F_space_not,
+    F_failure,
+  };
+
+  for (uint8_t i = 0; i < 3; ++i) {
+
+    will_return(__wrap_inet_pton, true);
+    will_return(__wrap_inet_pton, errnos[i]);
+
+    const f_status_t status = f_network_to_ip_string(family, &ip);
+
+    assert_int_equal(status, F_status_set_error(statuss[i]));
+  } // for
+
+  free(ip.string);
+}
+
+void test__f_network_to_ip_string__parameter_checking(void **state) {
+
+  f_network_family_ip_t family = f_network_family_ip_t_initialize;
+
+  {
+    const f_status_t status = f_network_to_ip_string(family, 0);
+
+    assert_int_equal(status, F_status_set_error(F_parameter));
+  }
+}
+
+void test__f_network_to_ip_string__returns_data_not(void **state) {
+
+  f_network_family_ip_t family = f_network_family_ip_t_initialize;
+  f_string_dynamic_t ip = f_string_dynamic_t_initialize;
+
+  {
+    const f_status_t status = f_network_to_ip_string(family, &ip);
+
+    assert_int_equal(status, F_data_not);
+  }
+
+  free(ip.string);
+}
+
+void test__f_network_to_ip_string__works(void **state) {
+
+  f_network_family_ip_t family = f_network_family_ip_t_initialize;
+  family.type = f_network_family_ip_4_e;
+
+  f_string_dynamic_t ip = f_string_dynamic_t_initialize;
+
+  const f_string_static_t expect = macro_f_string_static_t_initialize_1("127.0.0.1", 0, 9);
+
+  {
+    will_return(__wrap_inet_ntop, false);
+    will_return(__wrap_inet_ntop, expect.string);
+    will_return(__wrap_inet_ntop, expect.used);
+
+    const f_status_t status = f_network_to_ip_string(family, &ip);
+
+    assert_int_equal(status, F_none);
+    assert_int_equal(ip.used, expect.used);
+    assert_string_equal(ip.string, expect.string);
+  }
+
+  free(ip.string);
+}
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
diff --git a/level_0/f_network/tests/unit/c/test-network-to_ip_string.h b/level_0/f_network/tests/unit/c/test-network-to_ip_string.h
new file mode 100644 (file)
index 0000000..3c42946
--- /dev/null
@@ -0,0 +1,41 @@
+/**
+ * FLL - Level 0
+ *
+ * Project: Network
+ * API Version: 0.7
+ * Licenses: lgpl-2.1-or-later
+ *
+ * Test the network project.
+ */
+#ifndef _TEST__F_network_to_ip_string_h
+#define _TEST__F_network_to_ip_string_h
+
+/**
+ * Test that function fails.
+ *
+ * @see f_network_to_ip_string()
+ */
+extern void test__f_network_to_ip_string__fails(void **state);
+
+/**
+ * Test that parameter checking works as expected.
+ *
+ * @see f_network_to_ip_string()
+ */
+extern void test__f_network_to_ip_string__parameter_checking(void **state);
+
+/**
+ * Test that function works but the address.type is 0.
+ *
+ * @see f_network_to_ip_string()
+ */
+extern void test__f_network_to_ip_string__returns_data_not(void **state);
+
+/**
+ * Test that function works.
+ *
+ * @see f_network_to_ip_string()
+ */
+extern void test__f_network_to_ip_string__works(void **state);
+
+#endif // _TEST__F_network_to_ip_string_h
index f24759f312e596b097ab47ce3dbd89f4a394236c..69b7fbe0706ff890e39ae0a5e441d0f3ab2fd998 100644 (file)
@@ -19,16 +19,23 @@ int setdown(void **state) {
 int main(void) {
 
   const struct CMUnitTest tests[] = {
+    cmocka_unit_test(test__f_network_from_ip_string__returns_data_not),
+    cmocka_unit_test(test__f_network_to_ip_string__returns_data_not),
+
     cmocka_unit_test(test__f_network_from_host_long__works),
     cmocka_unit_test(test__f_network_from_host_short__works),
+    cmocka_unit_test(test__f_network_from_ip_string__works),
     cmocka_unit_test(test__f_network_to_host_long__works),
     cmocka_unit_test(test__f_network_to_host_short__works),
+    cmocka_unit_test(test__f_network_to_ip_string__works),
 
     #ifndef _di_level_0_parameter_checking_
       cmocka_unit_test(test__f_network_from_host_long__parameter_checking),
       cmocka_unit_test(test__f_network_from_host_short__parameter_checking),
+      cmocka_unit_test(test__f_network_from_ip_string__parameter_checking),
       cmocka_unit_test(test__f_network_to_host_long__parameter_checking),
       cmocka_unit_test(test__f_network_to_host_short__parameter_checking),
+      cmocka_unit_test(test__f_network_to_ip_string__parameter_checking),
     #endif // _di_level_0_parameter_checking_
   };
 
index 74dcd067cf2cc10be94c07c0d06827bdd33f3275..36f3706b69d330ca3138761cab38928442a1bcfd 100644 (file)
@@ -21,6 +21,7 @@
 #include <cmocka.h>
 
 // FLL-0 includes.
+#include <fll/level_0/string.h>
 #include <fll/level_0/network.h>
 
 // Mock includes.
 // Test includes.
 #include "test-network-from_host_long.h"
 #include "test-network-from_host_short.h"
+#include "test-network-from_ip_string.h"
 #include "test-network-to_host_long.h"
 #include "test-network-to_host_short.h"
+#include "test-network-to_ip_string.h"
 
 #ifdef __cplusplus
 extern "C" {