From: Kevin Day Date: Sun, 9 Jul 2023 16:33:46 +0000 (-0500) Subject: Update: Network additions and improvements, minor documentation comment clean ups. X-Git-Url: https://git.kevux.org/?a=commitdiff_plain;h=73146111b3d045670dbb3fc53a4d77e88386ca9a;p=fll Update: Network additions and improvements, minor documentation comment clean ups. Add f_network_is_ip_address() along with appropriate unit tests. The unit test are not as thorough as they could be. I did not fully review the IPv6 standard, which has a rather absurd design. There are likely things that I do not yet know about that are not supported. Specifically do not support port number on any IPv6 address without brackets. (The IPv6 address notation standard is horribly written.) --- diff --git a/level_0/f_network/c/network.c b/level_0/f_network/c/network.c index e802489..d52bb0d 100644 --- a/level_0/f_network/c/network.c +++ b/level_0/f_network/c/network.c @@ -102,6 +102,326 @@ extern "C" { } #endif // _di_f_network_from_ip_string_ +#ifndef _di_f_network_is_ip_address_ + void f_network_is_ip_address(const f_string_static_t address, f_number_unsigned_t * const port, f_state_t * const state) { + + if (!state) return; + + if (!address.used) { + state->status = F_data_not; + + return; + } + + f_number_unsigned_t i = 0; + uint8_t flag = 0x0; // 0x1 == is IPv6. + uint8_t set = 0; + uint8_t count = 0; + + for (; i < address.used; ++i) { + + if (state->interrupt) { + state->interrupt((void *) state, 0); + if (F_status_set_fine(state->status) == F_interrupt) return; + } + + if (!address.string[i]) continue; + + if (isxdigit(address.string[i])) { + if (address.string[i] < f_string_ascii_0_s.string[0] || address.string[i] > f_string_ascii_9_s.string[0]) { + flag = 0x1; + } + + ++count; + + continue; + } + + if (address.string[i] == f_string_ascii_period_s.string[0]) { + + // An IPv4 looking address with a hexidecimal letter. + if (flag & 0x1) { + state->status = F_network_version_four_not; + + return; + } + + break; + } + else if (address.string[i] == f_string_ascii_colon_s.string[0]) { + flag = 0x1; + + break; + } + else if (address.string[i] == f_string_ascii_bracket_open_s.string[0]) { + if (flag) { + state->status = F_false; + + return; + } + + flag = 0x3; + + break; + } + + state->status = F_false; + + return; + } // for + + if (i >= address.used) { + state->status = F_false; + + return; + } + + f_number_unsigned_t j = 0; + + if (flag & 0x1) { + + // IPv6 flag additions: 0x2 == has bracket open, 0x4 == has forward slash, 0x8 = has double-colon, 0x10 = has no leading digit and no bracket open. + if (flag & 0x2) { + ++i; + } + + state->status = F_network_version_six_not; + + if (count > 4) return; + + if (!count) { + for (j = i; i < address.used && !address.string[j]; ++j) { + + if (state->interrupt) { + state->interrupt((void *) state, 0); + if (F_status_set_fine(state->status) == F_interrupt) return; + state->status = F_network_version_six_not; + } + } // for + + if (j == address.used) return; + if (!(flag & 0x2)) flag |= 0x10; + } + + for (; i < address.used; ++i) { + + if (state->interrupt) { + state->interrupt((void *) state, 0); + if (F_status_set_fine(state->status) == F_interrupt) return; + state->status = F_network_version_six_not; + } + + if (!address.string[i]) continue; + + if (isxdigit(address.string[i])) { + if (++count > 4) return; + + if (flag & 0x4) { + if (address.string[i] < f_string_ascii_0_s.string[0] || address.string[i] > f_string_ascii_9_s.string[0] || count > 3) return; + } + } + else if (address.string[i] == f_string_ascii_colon_s.string[0]) { + if (flag & 0x4) return; + + j = i + 1; + + if (j < address.used) { + for (; j < address.used && !address.string[j]; ++j) { + + if (state->interrupt) { + state->interrupt((void *) state, 0); + if (F_status_set_fine(state->status) == F_interrupt) return; + state->status = F_network_version_six_not; + } + } // for + + if (address.string[j] == f_string_ascii_colon_s.string[0]) { + if (flag & 0x8) return; + + i = j; + flag |= 0x8; + + for (; i < address.used && !address.string[i]; ++i) { + + if (state->interrupt) { + state->interrupt((void *) state, 0); + if (F_status_set_fine(state->status) == F_interrupt) return; + state->status = F_network_version_six_not; + } + } // for + + // Must not end on a double-colon. + if (i + 1 == address.used) return; + } + + // Colons must be followed by a hexidecimal digit. + if (!isxdigit(address.string[i + 1])) return; + } + else { + + // Must not end on a colon. + return; + } + + if (++set > 7) return; + + count = 0; + } + else if (address.string[i] == f_string_ascii_slash_forward_s.string[0]) { + if (flag & 0x4) return; + + flag |= 0x4; + } + else if (address.string[i] == f_string_ascii_bracket_close_s.string[0]) { + if (!(flag & 0x2)) return; + + for (j = i + 1; j < address.used && !address.string[j]; ++j) { + + if (state->interrupt) { + state->interrupt((void *) state, 0); + if (F_status_set_fine(state->status) == F_interrupt) return; + state->status = F_network_version_six_not; + } + } // for + + if (j < address.used) { + if (address.string[j] == f_string_ascii_colon_s.string[0]) { + while (++j < address.used && !address.string[j]) { + + if (state->interrupt) { + state->interrupt((void *) state, 0); + if (F_status_set_fine(state->status) == F_interrupt) return; + state->status = F_network_version_six_not; + } + } // while + + // The colon used to designate the port number must be followed by a (base-10) number. + for (i = j; j < address.used; ++j) { + + if (state->interrupt) { + state->interrupt((void *) state, 0); + if (F_status_set_fine(state->status) == F_interrupt) return; + state->status = F_network_version_six_not; + } + + if (!address.string[j]) continue; + if (!isdigit(address.string[j])) return; + } // for + + // The double colon either must exist when set is smaller than 7 or the double colon must not exist at all. + if (set < 7 && !(flag & 0x8) || set == 7 && (flag & 0x8)) return; + + state->status = F_network_version_six; + + if (port) *port = i; + } + else { + + // Only a colon (and port number) may follow a valid close bracket. + return; + } + } + else if (count || set) { + + // The double colon either must exist when set is smaller than 7 or the double colon must not exist at all. + if (set < 7 && !(flag & 0x8) || set == 7 && (flag & 0x8)) return; + + state->status = F_network_version_six; + + if (port) *port = 0; + } + + return; + } + else { + return; + } + } // for + + // The double colon either must exist when set is smaller than 7 or the double colon must not exist at all. + if (set < 7 && !(flag & 0x8) || set == 7 && (flag & 0x8)) return; + + // A close bracket must exist if there is an open bracket. + if (flag & 0x2) return; + + if (!(flag & 0x10) || set || count) { + state->status = F_network_version_six; + + if (port) *port = 0; + } + + return; + } + + // IPv4 flag additions: 0x2 == has port number (and all 4 proper sets), 0x4 == has forward slash, 0x8 = finished forward slash. + state->status = F_network_version_four_not; + + if (count > 3) return; + + for (; i < address.used; ++i) { + + if (state->interrupt) { + state->interrupt((void *) state, 0); + if (F_status_set_fine(state->status) == F_interrupt) return; + state->status = F_network_version_four_not; + } + + if (!address.string[i]) continue; + + if (isdigit(address.string[i])) { + if (flag & 0x4) { + if (!(flag & 0x8) && ++count > 3) return; + } + else if (!(flag & 0x2)) { + if (++count > 3) return; + } + } + else if (address.string[i] == f_string_ascii_period_s.string[0]) { + if ((flag & 0x6) || !count || ++set > 3) return; + + count = 0; + } + else if (address.string[i] == f_string_ascii_colon_s.string[0]) { + if (set != 3 || (flag & 0x2)) return; + + if (flag & 0x4) { + flag |= 0x8; + } + + for (; i < address.used && !address.string[i]; ++i) { + + if (state->interrupt) { + state->interrupt((void *) state, 0); + if (F_status_set_fine(state->status) == F_interrupt) return; + state->status = F_network_version_four_not; + } + } // for + + flag |= 0x2; + j = i + 1; // Save the position that might represent the start of the port number. + } + else if (address.string[i] == f_string_ascii_slash_forward_s.string[0]) { + if ((flag & 0x4) || set != 3) return; + + flag |= 0x4; + count = 0; + } + else { + return; + } + } // for + + if (set == 3) { + state->status = F_network_version_four; + + if (port) *port = j; + } + else { + state->status = F_network_version_four_not; + } + } +#endif // _di_f_network_is_ip_address_ + #ifndef _di_f_network_to_host_long_ f_status_t f_network_to_host_long(const uint32_t from, uint32_t * const to) { #ifndef _di_level_0_parameter_checking_ diff --git a/level_0/f_network/c/network.h b/level_0/f_network/c/network.h index 58d4034..0230957 100644 --- a/level_0/f_network/c/network.h +++ b/level_0/f_network/c/network.h @@ -12,6 +12,7 @@ // Libc includes. #include +#include #include #include #include @@ -152,6 +153,46 @@ extern "C" { #endif // _di_f_network_from_ip_string_ /** + * Identify whether or not a string is a valid IPv4 or IPv6 address, including the optional port number. + * + * This does not fully validate the numbers. + * This only checks that the address is in the proper form. + * + * For IPv6, this only accepts port numbers when the IPv6 address is wrapped in brackets ('[' (U+005B) and ']' (U+005D)). + * + * @param address + * The string to parse. + * @param port + * (optional) This gets updated with the location where the first digit of the port number begins. + * This is set to 0 if there is no port number. + * On any error, this value is not changed. + * + * Set to NULL to disable. + * @param state + * A state for providing flags and handling interrupts during long running operations. + * There is no state.handle(). + * There is no "callbacks" structure. + * There is no data structure passed to these functions. + * + * When state.interrupt() returns, only F_interrupt and F_interrupt_not are processed. + * Error bit designates an error but must be passed along with F_interrupt. + * All other statuses are ignored. + * + * This alters state.status: + * F_data_not on success but there is nothing to process (address.used is 0). + * F_false on success, but this is not an IP Address. + * F_network_version_four_not on success, but this is not an IP Address but looks close to a IPv4 address. + * F_network_version_six_not on success, but this is not an IP Address but looks close to a IPv6 address. + * F_network_version_four on success and this is an IPv4 address. + * F_network_version_six on success and this is an IPv6 address. + * + * F_interrupt (with or without error bit) if stopping due to an interrupt. + */ +#ifndef _di_f_network_is_ip_address_ + extern void f_network_is_ip_address(const f_string_static_t address, f_number_unsigned_t * const port, f_state_t * const state); +#endif // _di_f_network_is_ip_address_ + +/** * Convert from network byte order to host byte order for an unsigned long integer. * * @param from diff --git a/level_0/f_network/data/build/settings-tests b/level_0/f_network/data/build/settings-tests index 07ed04c..ed1c664 100644 --- a/level_0/f_network/data/build/settings-tests +++ b/level_0/f_network/data/build/settings-tests @@ -25,7 +25,7 @@ build_language c build_libraries -lc -lcmocka 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-from_ip_address.c test-network-from_ip_name.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-from_host_long.c test-network-from_host_short.c test-network-from_ip_address.c test-network-from_ip_name.c test-network-from_ip_string.c test-network-is_ip_address.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 diff --git a/level_0/f_network/tests/unit/c/test-network-is_ip_address.c b/level_0/f_network/tests/unit/c/test-network-is_ip_address.c new file mode 100644 index 0000000..a0dde5b --- /dev/null +++ b/level_0/f_network/tests/unit/c/test-network-is_ip_address.c @@ -0,0 +1,334 @@ +#include "test-network.h" +#include "test-network-is_ip_address.h" + +#ifdef __cplusplus +extern "C" { +#endif + +void test__f_network_is_ip_address__returns_data_not(void **state) { + + f_state_t state_data = f_state_t_initialize; + + { + f_network_is_ip_address(f_string_empty_s, 0, &state_data); + + assert_int_equal(state_data.status, F_data_not); + } +} + +void test__f_network_is_ip_address__returns_false(void **state) { + + f_state_t state_data = f_state_t_initialize; + + const f_string_static_t ips[] = { + macro_f_string_static_t_initialize_1("127", 0, 3), + macro_f_string_static_t_initialize_1("a", 0, 1), + macro_f_string_static_t_initialize_1("www.example.com", 0, 15), + macro_f_string_static_t_initialize_1("www.example.com:80", 0, 18), + macro_f_string_static_t_initialize_1("localhost", 0, 9), + macro_f_string_static_t_initialize_1("___", 0, 3), + macro_f_string_static_t_initialize_1("]", 0, 1), + }; + + for (uint8_t i = 0; i < 7; ++i) { + + state_data.status = F_none; + + f_network_is_ip_address(ips[i], 0, &state_data); + + assert_int_equal(state_data.status, F_false); + } // for +} + +void test__f_network_is_ip_address__returns_network_version_four(void **state) { + + f_state_t state_data = f_state_t_initialize; + + const f_string_static_t ips[] = { + macro_f_string_static_t_initialize_1("127.0.0.1", 0, 9), + macro_f_string_static_t_initialize_1("127.0.0.1/24", 0, 12), + macro_f_string_static_t_initialize_1("127.0.0.1:80", 0, 12), + macro_f_string_static_t_initialize_1("127.0.0.1/24:80", 0, 15), + }; + + const f_number_unsigned_t ports[] = { + 0, + 0, + 10, + 13, + }; + + f_number_unsigned_t port = 0; + + for (uint8_t i = 0; i < 4; ++i) { + + state_data.status = F_none; + port = 100000; + + f_network_is_ip_address(ips[i], &port, &state_data); + + assert_int_equal(state_data.status, F_network_version_four); + assert_int_equal(port, ports[i]); + } // for +} + +void test__f_network_is_ip_address__returns_network_version_four_not(void **state) { + + f_state_t state_data = f_state_t_initialize; + + const f_string_static_t ips[] = { + macro_f_string_static_t_initialize_1("127.", 0, 4), + macro_f_string_static_t_initialize_1("127./24", 0, 7), + macro_f_string_static_t_initialize_1("127./2a", 0, 7), + macro_f_string_static_t_initialize_1("0..", 0, 3), + macro_f_string_static_t_initialize_1("0.1111", 0, 6), + macro_f_string_static_t_initialize_1("0.1.2.3.4.", 0, 10), + macro_f_string_static_t_initialize_1("0.1.2.3.4.5.6", 0, 13), + macro_f_string_static_t_initialize_1("1274.", 0, 5), + macro_f_string_static_t_initialize_1("127.1234", 0, 8), + macro_f_string_static_t_initialize_1("127.hello", 0, 9), + macro_f_string_static_t_initialize_1("a.0.0.1", 0, 7), + macro_f_string_static_t_initialize_1("a.b", 0, 9), + macro_f_string_static_t_initialize_1("127.0.0.1/1234", 0, 14), + macro_f_string_static_t_initialize_1("127.0.0.1/2a", 0, 12), + macro_f_string_static_t_initialize_1(".", 0, 1), + macro_f_string_static_t_initialize_1("..", 0, 2), + macro_f_string_static_t_initialize_1(".127.0.0.1", 0, 10), + }; + + for (uint8_t i = 0; i < 17; ++i) { + + state_data.status = F_none; + + f_network_is_ip_address(ips[i], 0, &state_data); + + assert_int_equal(state_data.status, F_network_version_four_not); + } // for +} + +void test__f_network_is_ip_address__returns_network_version_six_not(void **state) { + + f_state_t state_data = f_state_t_initialize; + + const f_string_static_t ips[] = { + macro_f_string_static_t_initialize_1(":", 0, 1), + macro_f_string_static_t_initialize_1("::", 0, 2), + macro_f_string_static_t_initialize_1(":/24", 0, 4), + macro_f_string_static_t_initialize_1("::/24", 0, 5), + macro_f_string_static_t_initialize_1(":/2a", 0, 4), + macro_f_string_static_t_initialize_1("::/2a", 0, 5), + macro_f_string_static_t_initialize_1(":12345", 0, 6), + macro_f_string_static_t_initialize_1("::12345", 0, 7), + macro_f_string_static_t_initialize_1(":12345/24", 0, 9), + macro_f_string_static_t_initialize_1("::12345/24", 0, 10), + macro_f_string_static_t_initialize_1(":12345/2a", 0, 9), + macro_f_string_static_t_initialize_1("::12345/2a", 0, 10), + macro_f_string_static_t_initialize_1("::1/1234", 0, 8), + macro_f_string_static_t_initialize_1("::1/12a", 0, 7), + macro_f_string_static_t_initialize_1(":example", 0, 8), + macro_f_string_static_t_initialize_1("::example", 0, 9), + macro_f_string_static_t_initialize_1(":example/24", 0, 11), + macro_f_string_static_t_initialize_1("::example/24", 0, 12), + macro_f_string_static_t_initialize_1(":example/2a", 0, 11), + macro_f_string_static_t_initialize_1("::example/2a", 0, 12), + macro_f_string_static_t_initialize_1("[:", 0, 1), + macro_f_string_static_t_initialize_1("[::", 0, 2), + macro_f_string_static_t_initialize_1("[:/24", 0, 4), + macro_f_string_static_t_initialize_1("[::/24", 0, 5), + macro_f_string_static_t_initialize_1("[:/2a", 0, 4), + macro_f_string_static_t_initialize_1("[::/2a", 0, 5), + macro_f_string_static_t_initialize_1("[:1/24", 0, 5), + macro_f_string_static_t_initialize_1("[::1/24", 0, 6), + macro_f_string_static_t_initialize_1("[:12345", 0, 6), + macro_f_string_static_t_initialize_1("[::12345", 0, 7), + macro_f_string_static_t_initialize_1("[:12345/24", 0, 9), + macro_f_string_static_t_initialize_1("[::12345/24", 0, 10), + macro_f_string_static_t_initialize_1("[::1/1234", 0, 8), + macro_f_string_static_t_initialize_1("[::1", 0, 4), + macro_f_string_static_t_initialize_1("[::1/24", 0, 7), + macro_f_string_static_t_initialize_1("[:example", 0, 9), + macro_f_string_static_t_initialize_1("[::example", 0, 10), + macro_f_string_static_t_initialize_1("[:example/24", 0, 12), + macro_f_string_static_t_initialize_1("[::example/24", 0, 13), + macro_f_string_static_t_initialize_1("[:example/2a", 0, 12), + macro_f_string_static_t_initialize_1("[::example/2a", 0, 13), + macro_f_string_static_t_initialize_1("[:]", 0, 1), + macro_f_string_static_t_initialize_1("[:1/24]", 0, 7), + macro_f_string_static_t_initialize_1("[:1]/24", 0, 7), + macro_f_string_static_t_initialize_1("[:1/2a]", 0, 7), + macro_f_string_static_t_initialize_1("[:1]/2a", 0, 7), + macro_f_string_static_t_initialize_1("[::]", 0, 2), + macro_f_string_static_t_initialize_1("[::1]/24", 0, 8), + macro_f_string_static_t_initialize_1("[::1]/2a", 0, 8), + macro_f_string_static_t_initialize_1("[:/24]", 0, 4), + macro_f_string_static_t_initialize_1("[:/2a]", 0, 4), + macro_f_string_static_t_initialize_1("[::/24]", 0, 5), + macro_f_string_static_t_initialize_1("[::/2a]", 0, 5), + macro_f_string_static_t_initialize_1("[:12345]", 0, 6), + macro_f_string_static_t_initialize_1("[::12345]", 0, 7), + macro_f_string_static_t_initialize_1("[:12345/24]", 0, 9), + macro_f_string_static_t_initialize_1("[::12345/24]", 0, 10), + macro_f_string_static_t_initialize_1("[:12345/2a]", 0, 9), + macro_f_string_static_t_initialize_1("[::12345/2a]", 0, 10), + macro_f_string_static_t_initialize_1("[::1/1234]", 0, 8), + macro_f_string_static_t_initialize_1("[:example]", 0, 10), + macro_f_string_static_t_initialize_1("[::example]", 0, 11), + macro_f_string_static_t_initialize_1("[:example/24]", 0, 13), + macro_f_string_static_t_initialize_1("[::example/24]", 0, 14), + macro_f_string_static_t_initialize_1("[:example]/24", 0, 13), + macro_f_string_static_t_initialize_1("[::example]/24", 0, 14), + macro_f_string_static_t_initialize_1("[:example/2a]", 0, 13), + macro_f_string_static_t_initialize_1("[::example/2a]", 0, 14), + macro_f_string_static_t_initialize_1("[:example]/2a", 0, 13), + macro_f_string_static_t_initialize_1("[::example]/2a", 0, 14), + macro_f_string_static_t_initialize_1("1234::example", 0, 13), + macro_f_string_static_t_initialize_1("1234:example", 0, 12), + macro_f_string_static_t_initialize_1("1234:1234:1234:1234:1234:1234:1234:1234:1234", 0, 44), + macro_f_string_static_t_initialize_1("1234::1234:1234:1234:1234::1234:1234:1234", 0, 41), + macro_f_string_static_t_initialize_1("1234::1234::1234", 0, 16), + macro_f_string_static_t_initialize_1("a234:1234:1234:1234:1234:1234:1234:1234:1234", 0, 44), + macro_f_string_static_t_initialize_1("a234::1234:1234:1234:1234::1234:1234:1234", 0, 41), + macro_f_string_static_t_initialize_1("a234::1234::1234", 0, 16), + macro_f_string_static_t_initialize_1("1234:aaaa:1234:1234:1234:1234:1234:1234:1234", 0, 44), + macro_f_string_static_t_initialize_1("1234::aaaa:1234:1234:1234::1234:1234:1234", 0, 41), + macro_f_string_static_t_initialize_1("1234::aaaa::1234", 0, 16), + macro_f_string_static_t_initialize_1("1234::www.example.com", 0, 21), + macro_f_string_static_t_initialize_1("2001:0DB8:0:CD30:123:4567:89AB:CDEF/1234", 0, 40), + macro_f_string_static_t_initialize_1("2001:0DB8:0:CD30:123:4567:89AB:CDEF/2a", 0, 38), + macro_f_string_static_t_initialize_1("2001:0DB83:0:CD30:123:4567:89AB:CDEF", 0, 36), + macro_f_string_static_t_initialize_1("2001:0DB83:0:CD30:123:4567:89AB:CDEF/1234", 0, 41), + macro_f_string_static_t_initialize_1("[2001:0DB8:0:CD30:123:4567:89AB:CDEF/1234]", 0, 42), + macro_f_string_static_t_initialize_1("2001:0DB83:0:CD30:123:4567:89AB:CDEF/2a", 0, 39), + macro_f_string_static_t_initialize_1("[2001:0DB8:0:CD30:123:4567:89AB:CDEF/2a]", 0, 40), + macro_f_string_static_t_initialize_1("[2001:0DB83:0:CD30:123:4567:89AB:CDEF]", 0, 38), + macro_f_string_static_t_initialize_1("[2001:0DB83:0:CD30:123:4567:89AB:CDEF/1234]", 0, 43), + macro_f_string_static_t_initialize_1("[2001:0DB83:0:CD30:123:4567:89AB:CDEF/2a]", 0, 41), + macro_f_string_static_t_initialize_1("[2001:0DB8:0:CD30:123:4567:89AB:CDEF]a", 0, 38), + macro_f_string_static_t_initialize_1("[2001:0DB8:0:CD30:123:4567:89AB:CDEF]1", 0, 38), + macro_f_string_static_t_initialize_1("[2001:0DB8:0:CD30:123:4567:89AB:CDEF]hello", 0, 42), + macro_f_string_static_t_initialize_1("[2001:0DB8:0:CD30:123:4567:89AB:CDEF]/24", 0, 40), + macro_f_string_static_t_initialize_1("[2001:0DB8:0:CD30:123:4567:89AB:CDEF]/2a", 0, 40), + macro_f_string_static_t_initialize_1("[2001:0DB8:0:CD30:123:4567:89AB:CDEF]/1234", 0, 42), + }; + + for (uint8_t i = 0; i < 98; ++i) { + + state_data.status = F_none; + + f_network_is_ip_address(ips[i], 0, &state_data); + + assert_int_equal(state_data.status, F_network_version_six_not); + } // for +} + +void test__f_network_is_ip_address__returns_network_version_six(void **state) { + + f_state_t state_data = f_state_t_initialize; + + const f_string_static_t ips[] = { + macro_f_string_static_t_initialize_1("::1", 0, 3), + macro_f_string_static_t_initialize_1("[::1]", 0, 5), + macro_f_string_static_t_initialize_1("[::1]:80", 0, 8), + macro_f_string_static_t_initialize_1("::1/24", 0, 6), + macro_f_string_static_t_initialize_1("[::1/24]", 0, 8), + macro_f_string_static_t_initialize_1("[::1/24]:80", 0, 11), + macro_f_string_static_t_initialize_1("2001:0DB8:0:CD30:123:4567:89AB:CDEF", 0, 35), + macro_f_string_static_t_initialize_1("[2001:0DB8:0:CD30:123:4567:89AB:CDEF]", 0, 37), + macro_f_string_static_t_initialize_1("[2001:0DB8:0:CD30:123:4567:89AB:CDEF]:80", 0, 40), + macro_f_string_static_t_initialize_1("2001:0DB8:0:CD30:123:4567::CDEF", 0, 31), + macro_f_string_static_t_initialize_1("[2001:0DB8:0:CD30:123:4567::CDEF]", 0, 33), + macro_f_string_static_t_initialize_1("[2001:0DB8:0:CD30:123:4567::CDEF]:80", 0, 36), + macro_f_string_static_t_initialize_1("2001:0DB8:0:CD30:123::CDEF", 0, 26), + macro_f_string_static_t_initialize_1("[2001:0DB8:0:CD30:123::CDEF]", 0, 28), + macro_f_string_static_t_initialize_1("[2001:0DB8:0:CD30:123::CDEF]:80", 0, 31), + macro_f_string_static_t_initialize_1("2001:0DB8:0:CD30::CDEF", 0, 22), + macro_f_string_static_t_initialize_1("[2001:0DB8:0:CD30::CDEF]", 0, 24), + macro_f_string_static_t_initialize_1("[2001:0DB8:0:CD30::CDEF]:80", 0, 27), + macro_f_string_static_t_initialize_1("2001:0DB8:0::CDEF", 0, 17), + macro_f_string_static_t_initialize_1("[2001:0DB8:0::CDEF]", 0, 19), + macro_f_string_static_t_initialize_1("[2001:0DB8:0::CDEF]:80", 0, 22), + macro_f_string_static_t_initialize_1("2001:0DB8::CDEF", 0, 15), + macro_f_string_static_t_initialize_1("[2001:0DB8::CDEF]", 0, 17), + macro_f_string_static_t_initialize_1("[2001:0DB8::CDEF]:80", 0, 20), + macro_f_string_static_t_initialize_1("2001::CDEF", 0, 10), + macro_f_string_static_t_initialize_1("[2001::CDEF]", 0, 12), + macro_f_string_static_t_initialize_1("[2001::CDEF]:80", 0, 15), + macro_f_string_static_t_initialize_1("2001::0DB8:CDEF", 0, 15), + macro_f_string_static_t_initialize_1("[2001::0DB8:CDEF]", 0, 17), + macro_f_string_static_t_initialize_1("[2001::0DB8:CDEF]:80", 0, 20), + macro_f_string_static_t_initialize_1("2001:0DB8::0:CDEF", 0, 17), + macro_f_string_static_t_initialize_1("[2001:0DB8::0:CDEF]", 0, 19), + macro_f_string_static_t_initialize_1("[2001:0DB8::0:CDEF]:80", 0, 22), + macro_f_string_static_t_initialize_1("2001::0DB8:0:CD30:CDEF", 0, 22), + macro_f_string_static_t_initialize_1("[2001::0DB8:0:CD30:CDEF]", 0, 24), + macro_f_string_static_t_initialize_1("[2001::0DB8:0:CD30:CDEF]:80", 0, 27), + macro_f_string_static_t_initialize_1("2001:0DB8:0:CD30::123:CDEF", 0, 26), + macro_f_string_static_t_initialize_1("[2001:0DB8:0:CD30::123:CDEF]", 0, 28), + macro_f_string_static_t_initialize_1("[2001:0DB8:0:CD30::123:CDEF]:80", 0, 31), + macro_f_string_static_t_initialize_1("2001:0DB8:0:CD30::123:4567:CDEF", 0, 31), + macro_f_string_static_t_initialize_1("[2001:0DB8:0:CD30::123:4567:CDEF]", 0, 33), + macro_f_string_static_t_initialize_1("[2001:0DB8:0:CD30::123:4567:CDEF]:80", 0, 36), + }; + + const f_number_unsigned_t ports[] = { + 0, + 0, + 6, + 0, + 0, + 9, + 0, + 0, + 38, + 0, + 0, + 34, + 0, + 0, + 29, + 0, + 0, + 25, + 0, + 0, + 20, + 0, + 0, + 18, + 0, + 0, + 13, + 0, + 0, + 18, + 0, + 0, + 20, + 0, + 0, + 25, + 0, + 0, + 29, + 0, + 0, + 34, + }; + + f_number_unsigned_t port = 0; + + for (uint8_t i = 0; i < 42; ++i) { + + state_data.status = F_none; + port = 100000; + + f_network_is_ip_address(ips[i], &port, &state_data); + + assert_int_equal(state_data.status, F_network_version_six); + assert_int_equal(port, ports[i]); + } // for +} + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/level_0/f_network/tests/unit/c/test-network-is_ip_address.h b/level_0/f_network/tests/unit/c/test-network-is_ip_address.h new file mode 100644 index 0000000..b27b3d8 --- /dev/null +++ b/level_0/f_network/tests/unit/c/test-network-is_ip_address.h @@ -0,0 +1,55 @@ +/** + * FLL - Level 0 + * + * Project: Network + * API Version: 0.7 + * Licenses: lgpl-2.1-or-later + * + * Test the network project. + */ +#ifndef _TEST__F_network_is_ip_address_h +#define _TEST__F_network_is_ip_address_h + +/** + * Test that function works but address.used is 0. + * + * @see f_network_is_ip_address() + */ +extern void test__f_network_is_ip_address__returns_data_not(void **state); + +/** + * Test that function works and returns F_false. + * + * @see f_network_is_ip_address() + */ +extern void test__f_network_is_ip_address__returns_false(void **state); + +/** + * Test that function works and returns F_network_version_four. + * + * @see f_network_is_ip_address() + */ +extern void test__f_network_is_ip_address__returns_network_version_four(void **state); + +/** + * Test that function works and returns F_network_version_four_not. + * + * @see f_network_is_ip_address() + */ +extern void test__f_network_is_ip_address__returns_network_version_four_not(void **state); + +/** + * Test that function works and returns F_network_version_six. + * + * @see f_network_is_ip_address() + */ +extern void test__f_network_is_ip_address__returns_network_version_six(void **state); + +/** + * Test that function works and returns F_network_version_six_not. + * + * @see f_network_is_ip_address() + */ +extern void test__f_network_is_ip_address__returns_network_version_six_not(void **state); + +#endif // _TEST__F_network_is_ip_address_h diff --git a/level_0/f_network/tests/unit/c/test-network.c b/level_0/f_network/tests/unit/c/test-network.c index 797dbf5..c56d1b5 100644 --- a/level_0/f_network/tests/unit/c/test-network.c +++ b/level_0/f_network/tests/unit/c/test-network.c @@ -22,7 +22,6 @@ int main(void) { cmocka_unit_test(test__f_network_from_ip_address__returns_data_not), cmocka_unit_test(test__f_network_from_ip_name__returns_data_not), 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), @@ -35,12 +34,20 @@ int main(void) { cmocka_unit_test(test__f_network_to_host_short__works), cmocka_unit_test(test__f_network_to_ip_string__works), + cmocka_unit_test(test__f_network_is_ip_address__returns_data_not), + cmocka_unit_test(test__f_network_is_ip_address__returns_false), + cmocka_unit_test(test__f_network_is_ip_address__returns_network_version_four), + cmocka_unit_test(test__f_network_is_ip_address__returns_network_version_four_not), + cmocka_unit_test(test__f_network_is_ip_address__returns_network_version_six), + cmocka_unit_test(test__f_network_is_ip_address__returns_network_version_six_not), + #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_address__parameter_checking), cmocka_unit_test(test__f_network_from_ip_name__parameter_checking), cmocka_unit_test(test__f_network_from_ip_string__parameter_checking), + // f_network_is_ip_address() doesn't use 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), diff --git a/level_0/f_network/tests/unit/c/test-network.h b/level_0/f_network/tests/unit/c/test-network.h index ecb3d18..da66efc 100644 --- a/level_0/f_network/tests/unit/c/test-network.h +++ b/level_0/f_network/tests/unit/c/test-network.h @@ -33,6 +33,7 @@ #include "test-network-from_ip_address.h" #include "test-network-from_ip_name.h" #include "test-network-from_ip_string.h" +#include "test-network-is_ip_address.h" #include "test-network-to_host_long.h" #include "test-network-to_host_short.h" #include "test-network-to_ip_string.h"