From 49efb727da742a7d867740efde4dba4d6ec09b5b Mon Sep 17 00:00:00 2001 From: Teufelchen1 Date: Tue, 4 Oct 2022 18:01:38 +0200 Subject: [PATCH] unittests/uri_parser: Rework tests to be more verbose --- .../tests-uri_parser/tests-uri_parser.c | 1085 ++++++++--------- 1 file changed, 514 insertions(+), 571 deletions(-) diff --git a/tests/unittests/tests-uri_parser/tests-uri_parser.c b/tests/unittests/tests-uri_parser/tests-uri_parser.c index 77e58e7a7b..c1b6ea89eb 100644 --- a/tests/unittests/tests-uri_parser/tests-uri_parser.c +++ b/tests/unittests/tests-uri_parser/tests-uri_parser.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020 HAW Hamburg + * Copyright (C) 2022 Bennet Blischke / HAW Hamburg * * This file is subject to the terms and conditions of the GNU Lesser * General Public License v2.1. See the file LICENSE in the top level @@ -21,599 +21,542 @@ #include "unittests-constants.h" #include "tests-uri_parser.h" -#define VEC(u, f, s, us, h, v6a, z, po_str, po, pa, q, e) \ - { .uri = u, .full_uri = f, .scheme = s, .userinfo = us, .host = h, \ - .ipv6addr = v6a, .zoneid = z, .port_str = po_str, .port = po, \ - .path = pa, .query = q, .expected = e } - -#define VEC_CHECK_INT(comp, i, vec_msg) \ - do { \ - vec_msg[0] = '\0'; \ - stdimpl_strcat(vec_msg, "Unexpected " # comp " member "); \ - stdimpl_lltoa(validate_uris[i].comp, &vec_msg[strlen(vec_msg)], 10);\ - stdimpl_strcat(vec_msg, " for \""); \ - stdimpl_strcat(vec_msg, validate_uris[i].uri); \ - stdimpl_strcat(vec_msg, "\""); \ - TEST_ASSERT_MESSAGE(validate_uris[i].comp == ures.comp, vec_msg); \ - } while (0) - -#define VEC_CHECK_STR(comp, i, vec_msg) \ - do { \ - if (ures.comp == NULL) { \ - TEST_ASSERT(validate_uris[i].comp[0] == '\0'); \ - } \ - else { \ - TEST_ASSERT_EQUAL_INT(strlen(validate_uris[i].comp), \ - ures.comp##_len); \ - vec_msg[0] = '\0'; \ - stdimpl_strcat(vec_msg, "Unexpected " # comp " member \""); \ - stdimpl_strcat(vec_msg, validate_uris[i].comp); \ - stdimpl_strcat(vec_msg, "\" for \""); \ - stdimpl_strcat(vec_msg, validate_uris[i].uri); \ - stdimpl_strcat(vec_msg, "\""); \ - TEST_ASSERT_MESSAGE(0 == \ - strncmp(ures.comp, \ - validate_uris[i].comp, \ - strlen(validate_uris[i].comp)), \ - vec_msg); \ - } \ - } while (0) - -#define VEC_MSG_LEN (256) - typedef struct { - char uri[64]; - bool full_uri; - char scheme[8]; - char userinfo[16]; - char host[24]; - char ipv6addr[16]; - char zoneid[8]; - char port_str[32]; + char *input_uri; + char *scheme; + char *userinfo; + char *host; + char *ipv6addr; + char *zoneid; + char *port_str; uint16_t port; - char path[48]; - char query[32]; - int expected; -} validate_t; + char *path; + char *query; +} expected_uri_result_t; + +static void _print_return_expectation(const char *uri, int expected, int observed) +{ + printf("\nURI-Input: %s\n", uri); + printf("Expected return: %d\n", expected); + printf("Observed return: %d", observed); +} /* - VEC(uri_to_parse, - scheme, userinfo, host, port_str, port, - path, query, expected return value) -*/ -static const validate_t validate_uris[] = { - /* uri to parse */ - VEC("coap://RIOT:test@[fe80:db8::1%tap0]:5683/.well-known/core?v=1", - /* is URI */ - true, - /* parsed scheme */ - "coap", - /* parsed userinfo */ - "RIOT:test", - /* parsed host */ - "[fe80:db8::1%tap0]", - /* parsed host without zoneid */ - "fe80:db8::1", - /* parsed zoneid */ - "tap0", - /* parsed port_str */ - "5683", - /* parsed port */ - 5683, - /* parsed path */ - "/.well-known/core", - /* parsed query */ - "v=1", - /* expected return value */ - 0), - VEC("coap://RIOT:test@[fe80:db8::1%]:5683/.well-known/core?v=1", - true, - "coap", - "RIOT:test", - "[fe80:db8::1%]", - "fe80:db8::1", - "", - "5683", - 5683, - "/.well-known/core", - "v=1", - -1), - VEC("coap://[fe80::1]/foo%20bar", - true, - "coap", - "", - "[fe80::1]", - "fe80::1", - "", - "", - 0, - "/foo%20bar", - "", - 0), - VEC("/.well-known/core?v=1", - false, - "", - "", - "", - "", - "", - "", - 0, - "/.well-known/core", - "v=1", - 0), - VEC("coap://R@[2001:db8::1]:5/v=1", - true, - "coap", - "R", - "[2001:db8::1]", - "2001:db8::1", - "", - "5", - 5, - "/v=1", - "", - 0), - VEC("coap://R@[2001:db8::1]:5/:v=1", - true, - "coap", - "R", - "[2001:db8::1]", - "2001:db8::1", - "", - "5", - 5, - "/:v=1", - "", - 0), - VEC("cap://R@[2001:db8::1]:5/?v=1", - true, - "cap", - "R", - "[2001:db8::1]", - "2001:db8::1", - "", - "5", - 5, - "/", - "v=1", - 0), - VEC("oap://Y2001:db8::1]:5/av=1", - true, - "oap", - "", - "Y2001:db8::1]", - "", - "", - "5", - 5, - "/av=1", - "", - 0), - VEC("coap://R@[2001:db8::1]:5own/v=1", - true, - "coap", - "R", - "[2001:db8::1]", - "2001:db8::1", - "", - "5own", - 5, - "/v=1", - "", - -1), - VEC("coap://R@[2001:db8::1]:5own/:v=1", - true, - "coap", - "R", - "[2001:db8::1]", - "2001:db8::1", - "", - "5own", - 5, - "/:v=1", - "", - -1), - VEC("cap://R@[2001:db8::1]:5own/?v=1", - true, - "cap", - "R", - "[2001:db8::1]", - "2001:db8::1", - "", - "5own", - 5, - "/", - "v=1", - -1), - VEC("oap://Y2001:db8::1]:5own/av=1", - true, - "oap", - "", - "Y2001:db8::1]", - "", - "", - "5own", - 5, - "/av=1", - "", - -1), - VEC("//Rb[ʰ00J:d/5v=0", - false, - "", - "", - "", - "", - "", - "", - 0, - "//Rb[ʰ00J:d/5v=0", - "", - 0), - VEC("coap://oap://P@[2001:b", - true, - "", - "", - "", - "", - "", - "", - 0, - "", - "", - -1), - VEC("coap:///R@[2008::1]:5own//R@[2008::1]:5own/?v=1", - true, - "coap", - "", - "", - "", - "", - "", - 0, - "/R@[2008::1]:5own//R@[2008::1]:5own/", - "v=1", - 0), - VEC("coaP://R/RZ[2001[8:01[8::1]:5o:1]:5oTMv=1", - true, - "coaP", - "", - "R", - "", - "", - "", - 0, - "/RZ[2001[8:01[8::1]:5o:1]:5oTMv=1", - "", - 0), - VEC("coap://R@////////////////7///v=1", - true, - "coap", - "R", - "", - "", - "", - "", - 0, - "////////////////7///v=1", - "", - 0), - VEC("coa[:////[2001:db5ow:5own/Ov=1", - false, - "", - "", - "", - "", - "", - "", - 0, - "coa[:////[2001:db5ow:5own/Ov=1", - "", - 0), - VEC("tel:+1-816-555-1212", - true, - "tel", - "", - "", - "", - "", - "", - 0, - "+1-816-555-1212", - "", - 0), - VEC("sms:+15105550101,+15105550102?body=hello%20there", - true, - "sms", - "", - "", - "", - "", - "", - 0, - "+15105550101,+15105550102", - "body=hello%20there", - 0), - VEC("a", - false, - "", - "", - "", - "", - "", - "", - 0, - "a", - "", - 0), - VEC("mailto:test@example.com", - true, - "mailto", - "", - "", - "", - "", - "", - 0, - "test@example.com", - "", - 0), - VEC("ftp://ftp.is.co.za/rfc/rfc1808.txt", - true, - "ftp", - "", - "ftp.is.co.za", - "", - "", - "", - 0, - "/rfc/rfc1808.txt", - "", - 0), - VEC("http://www.ietf.org/rfc/rfc2396.txt", - true, - "http", - "", - "www.ietf.org", - "", - "", - "", - 0, - "/rfc/rfc2396.txt", - "", - 0), - VEC("ldap://[2001:db8::7]/c=GB?objectClass?one", - true, - "ldap", - "", - "[2001:db8::7]", - "2001:db8::7", - "", - "", - 0, - "/c=GB", - "objectClass?one", - 0), - VEC("mailto:John.Doe@example.com", - true, - "mailto", - "", - "", - "", - "", - "", - 0, - "John.Doe@example.com", - "", - 0), - VEC("news:comp.infosystems.www.servers.unix", - true, - "news", - "", - "", - "", - "", - "", - 0, - "comp.infosystems.www.servers.unix", - "", - 0), - VEC("tel:+1-816-555-1212", - true, - "tel", - "", - "", - "", - "", - "", - 0, - "+1-816-555-1212", - "", - 0), - VEC("telnet://192.0.2.16:80/", - true, - "telnet", - "", - "192.0.2.16", - "", - "", - "80", - 80, - "/", - "", - 0), - VEC("urn:oasis:names:specification:docbook:dtd:xml:4.1.2", - true, - "urn", - "", - "", - "", - "", - "", - 0, - "oasis:names:specification:docbook:dtd:xml:4.1.2", - "", - 0), - VEC("", - false, - "", - "", - "", - "", - "", - "", - 0, - "", - "", - -1), - VEC("/", - false, - "", - "", - "", - "", - "", - "", - 0, - "/", - "", - 0), - VEC("./this:that", - false, - "", - "", - "", - "", - "", - "", - 0, - "./this:that", - "", - 0), - VEC("pP://", - true, - "pP", - "", - "", - "", - "", - "", - 0, - "", - "", - 0), - VEC("A://@", - true, - "A", - "", - "", - "", - "", - "", - 0, - "", - "", - 0), - VEC("coap://example.com:1234568910", - /* is URI */ - true, - /* parsed scheme */ - "coap", - /* parsed userinfo */ - "", - /* parsed host */ - "example.com", - /* parsed host without zoneid */ - "", - /* parsed zoneid */ - "", - /* parsed port_str */ - "", - /* parsed port */ - 0, - /* parsed path */ - "", - /* parsed query */ - "", - /* expected return value */ - -1), - VEC("coap://example.com: 12/foo", - true, - "", - "", - "example.com", - "", - "", - "", - 0, - "", - "", - -1), - VEC("coap://example.com:0x12/foo", - true, - "", - "", - "example.com", - "", - "", - "", - 0, - "", - "", - -1), -}; - -static char _failure_msg[VEC_MSG_LEN]; - -static void test_uri_parser__validate(void) + * The uri_parser returns a string-buffer (non zero terminated). + * This function compares a given string with a given uri_parser buffer + length. + * Additionally, it takes the original uri (from the test vector) and a name + * in order to print a precise and helpful error message if the buffer and string + * aren't identical. + */ +static int _compare_string_buffer(const char *name, const char *input_uri, const char *expected_str, + const char *actual_str, size_t actual_len) { - uri_parser_result_t ures; - for (unsigned i = 0; i < ARRAY_SIZE(validate_uris); i++) { - int res = uri_parser_process_string(&ures, validate_uris[i].uri); - TEST_ASSERT_EQUAL_INT(validate_uris[i].full_uri, - uri_parser_is_absolute_string(validate_uris[i].uri)); - TEST_ASSERT_EQUAL_INT(validate_uris[i].expected, res); - if (res == 0) { - VEC_CHECK_STR(scheme, i, _failure_msg); - VEC_CHECK_STR(userinfo, i, _failure_msg); - VEC_CHECK_STR(host, i, _failure_msg); - VEC_CHECK_STR(ipv6addr, i, _failure_msg); - VEC_CHECK_STR(zoneid, i, _failure_msg); - VEC_CHECK_STR(port_str, i, _failure_msg); - VEC_CHECK_INT(port, i, _failure_msg); - VEC_CHECK_STR(path, i, _failure_msg); - VEC_CHECK_STR(query, i, _failure_msg); + if ((actual_len == strlen(expected_str)) && + (strncmp(actual_str, expected_str, actual_len) == 0)) { + return 0; + } + printf( + "\nWith given input uri '%s', expected %s '%s' with length '%d' but got '%.*s' with length '%d'\n", + input_uri, name, expected_str, strlen(expected_str), actual_len, actual_str, actual_len); + return -1; +} + +/* + * Given a simple valid uri, this test checks that the parsing returns success + */ +static void _successful_parsing_of_valid_uri(void) +{ + char *failure_msg = "Failure: The uri_parser failed to parse a correct and valid uri."; + int expected_ret = 0; /* Indicates a successful parsing */ + + char *simple_uri_1 = "coap://example.org/foo/bar"; + char *simple_uri_2 = "ftp://riot-os.org/bar/foo"; + char *simple_uri_3 = "ftp://riot-os.org:99/bar/foo"; + char *simple_uri_4 = "http://riot-os.org:99/bar/foo"; + char *simple_uri_5 = "https://riot-os.org/"; + + char *legacy_test_case_01 = "coap://RIOT:test@[fe80:db8::1%tap0]:5683/.well-known/core?v=1"; + char *legacy_test_case_02 = "coap://[fe80::1]/foo%20bar"; + char *legacy_test_case_03 = "/.well-known/core?v=1"; + char *legacy_test_case_04 = "coap://R@[2001:db8::1]:5/v=1"; + char *legacy_test_case_05 = "coap://R@[2001:db8::1]:5/:v=1"; + char *legacy_test_case_06 = "cap://R@[2001:db8::1]:5/?v=1"; + char *legacy_test_case_07 = "oap://Y2001:db8::1]:5/av=1"; + char *legacy_test_case_08 = "//Rb[ʰ00J:d/5v=0"; + char *legacy_test_case_09 = "coap:///R@[2008::1]:5own//R@[2008::1]:5own/?v=1"; + char *legacy_test_case_10 = "coaP://R/RZ[2001[8:01[8::1]:5o:1]:5oTMv=1"; + char *legacy_test_case_11 = "coap://R@////////////////7///v=1"; + char *legacy_test_case_12 = "coa[:////[2001:db5ow:5own/Ov=1"; + char *legacy_test_case_13 = "tel:+1-816-555-1212"; + char *legacy_test_case_14 = "sms:+15105550101,+15105550102?body=hello%20there"; + char *legacy_test_case_15 = "a"; + char *legacy_test_case_16 = "mailto:test@example.com"; + char *legacy_test_case_17 = "ftp://ftp.is.co.za/rfc/rfc1808.txt"; + char *legacy_test_case_18 = "http://www.ietf.org/rfc/rfc2396.txt"; + char *legacy_test_case_19 = "ldap://[2001:db8::7]/c=GB?objectClass?one"; + char *legacy_test_case_20 = "mailto:John.Doe@example.com"; + char *legacy_test_case_21 = "news:comp.infosystems.www.servers.unix"; + char *legacy_test_case_22 = "tel:+1-816-555-1212"; + char *legacy_test_case_23 = "telnet://192.0.2.16:80/"; + char *legacy_test_case_24 = "urn:oasis:names:specification:docbook:dtd:xml:4.1.2"; + char *legacy_test_case_25 = "/"; + char *legacy_test_case_26 = "./this:that"; + char *legacy_test_case_27 = "pP://"; + char *legacy_test_case_28 = "A://@"; + + char *test_vec[] = { + simple_uri_1, + simple_uri_2, + simple_uri_3, + simple_uri_4, + simple_uri_5, + legacy_test_case_01, + legacy_test_case_02, + legacy_test_case_03, + legacy_test_case_04, + legacy_test_case_05, + legacy_test_case_06, + legacy_test_case_07, + legacy_test_case_08, + legacy_test_case_09, + legacy_test_case_10, + legacy_test_case_11, + legacy_test_case_12, + legacy_test_case_13, + legacy_test_case_14, + legacy_test_case_15, + legacy_test_case_16, + legacy_test_case_17, + legacy_test_case_18, + legacy_test_case_19, + legacy_test_case_20, + legacy_test_case_21, + legacy_test_case_22, + legacy_test_case_23, + legacy_test_case_24, + legacy_test_case_25, + legacy_test_case_26, + legacy_test_case_27, + legacy_test_case_28, + }; + + uri_parser_result_t uri_res; + int ret = 0; + + for (unsigned int i = 0; i < ARRAY_SIZE(test_vec); ++i) { + ret = uri_parser_process_string(&uri_res, test_vec[i]); + if (ret != expected_ret) { + _print_return_expectation(test_vec[i], expected_ret, ret); + TEST_FAIL(failure_msg); } } } +/* + * Given a simple invalid uri, this test checks that the parsing returns an error + */ +static void _successful_rejecting_of_invalid_uri(void) +{ + char *failure_msg = "Failure: The uri_parser failed to reject an invalid uri."; + int expected_ret = -1; /* Indicates an invalid uri */ + + char *trailing_percent = "coap://RIOT:test@[fe80:db8::1%]:5683/.well-known/core?v=1"; + char *invalid_port = "coap://R@[2001:db8::1]:5own/v=1"; + char *invalid_port_colon = "coap://R@[2001:db8::1]:5own/:v=1"; + char *invalid_port_short_scheme = "cap://R@[2001:db8::1]:5own/?v=1"; + char *invalid_host = "oap://Y2001:db8::1]:5own/av=1"; + char *double_scheme = "coap://oap://P@[2001:b"; + char *empty_input = ""; + char *port_too_long = "coap://example.com:1234568910"; + char *white_space_in_port = "coap://example.com: 12/foo"; + char *hex_port = "coap://example.com:0x12/foo"; + + char *test_vec[] = { + trailing_percent, + invalid_port, + invalid_port_colon, + invalid_port_short_scheme, + invalid_host, + double_scheme, + empty_input, + port_too_long, + white_space_in_port, + hex_port, + }; + + uri_parser_result_t uri_res; + int ret = 0; + + for (unsigned int i = 0; i < ARRAY_SIZE(test_vec); ++i) { + ret = uri_parser_process_string(&uri_res, test_vec[i]); + if (ret != expected_ret) { + _print_return_expectation(test_vec[i], expected_ret, ret); + TEST_FAIL(failure_msg); + } + } +} + +/* + * This test checks if the uri_parser returns an error if the port length + * (as a string) is invalid, that is, longer than 5 characters. + * This differs from the RFC, where the port in an uri can be zero to infinite + * number of characters long; ABNF: *DIGIT + */ +static void _error_if_port_str_is_too_long(void) +{ + char *failure_msg = "Failure: The uri_parser did not detect an invalid port-length as invalid."; + int expected_ret = -1; /* Indicates an invalid uri */ + + char *leading_zeroes_arent_ignored = "https://example.org:000456/foo/bar"; + char *too_many_digits = "https://example.org:123456/foo/bar"; + char *too_much_whitespace = "https://example.org: 23456/foo/bar"; + + char *test_vec[] = { + too_many_digits, + leading_zeroes_arent_ignored, + too_much_whitespace, + }; + + uri_parser_result_t uri_res; + int ret = 0; + + for (unsigned int i = 0; i < ARRAY_SIZE(test_vec); ++i) { + ret = uri_parser_process_string(&uri_res, test_vec[i]); + if (ret != expected_ret) { + _print_return_expectation(test_vec[i], expected_ret, ret); + TEST_FAIL(failure_msg); + } + } +} + +/* + * This test checks if the uri_parser returns an error if the port + * (as a string) is invalid, that is, containing illegal characters + */ +static void _error_if_port_str_contains_illegal_characters(void) +{ + char *failure_msg = "Failure: The uri_parser did not detect an invalid port-string as invalid."; + int expected_ret = -1; /* Indicates an invalid uri */ + + char *letters_within_a_number = "https://example.org:12ff34/foo/bar"; + char *hex_number_as_port = "https://example.org:0x1234/foo/bar"; + char *bin_number_as_port = "https://example.org:0b1010/foo/bar"; + char *negativ_port = "https://example.org:-12/foo/bar"; + char *whitespace_within_port = "https://example.org:12 34/foo/bar"; + char *bigger_than_max_port = "https://example.org:65536/foo/bar"; + + char *test_vec[] = { + letters_within_a_number, + hex_number_as_port, + bin_number_as_port, + negativ_port, + whitespace_within_port, + bigger_than_max_port + }; + + uri_parser_result_t uri_res; + int ret = 0; + + for (unsigned int i = 0; i < ARRAY_SIZE(test_vec); ++i) { + ret = uri_parser_process_string(&uri_res, test_vec[i]); + if (ret != expected_ret) { + _print_return_expectation(test_vec[i], expected_ret, ret); + TEST_FAIL(failure_msg); + } + } +} + +/* + * Given a uri which contains a scheme, this test checks that the + * uri_parser can isolate that scheme successful. + */ +static void _result_component_scheme_matches_input_scheme(void) +{ + char *failure_msg = "Failure: The uri_parser did not parse the scheme correctly."; + int expected_ret = 0; + + expected_uri_result_t very_long_scheme = { + .input_uri = "wowlongcoap://example.org/foo/bar", + .scheme = "wowlongcoap", + }; + expected_uri_result_t normal_scheme = { + .input_uri = "coap://example.org/foo/bar", + .scheme = "coap", + }; + expected_uri_result_t short_scheme = { + .input_uri = "a://example.org/foo/bar", + .scheme = "a", + }; + expected_uri_result_t digit_scheme = { + .input_uri = "a1b2://example.org/foo/bar", + .scheme = "a1b2", + }; + + expected_uri_result_t *test_vec[] = { + &very_long_scheme, + &normal_scheme, + &short_scheme, + &digit_scheme, + }; + + uri_parser_result_t uri_res; + int ret = 0; + + for (unsigned int i = 0; i < ARRAY_SIZE(test_vec); ++i) { + ret = uri_parser_process_string(&uri_res, test_vec[i]->input_uri); + if (ret != expected_ret) { + /* if the uri_parser return indicates an error, this test fails */ + _print_return_expectation(test_vec[i]->input_uri, expected_ret, ret); + TEST_FAIL(failure_msg); + } + else { + /* if the uri_parser return indicates success + * the length of the schemes must match. + * we can't use strlen on the result scheme as it is not null terminated, + * but the uri_parser provides the length separately*/ + if (uri_res.scheme_len != strlen(test_vec[i]->scheme)) { + printf( + "With given input uri '%s', expected a scheme with the length '%d' but got '%d'\n", + test_vec[i]->input_uri, strlen(test_vec[i]->scheme), uri_res.scheme_len); + TEST_FAIL(failure_msg); + } + else { + /* If the schemes have the same length, they also should look identical */ + if (strncmp(uri_res.scheme, test_vec[i]->scheme, uri_res.scheme_len) != 0) { + printf("With given input uri '%s', expected scheme '%s' but got '%.*s'\n", + test_vec[i]->input_uri, test_vec[i]->scheme, uri_res.scheme_len, + uri_res.scheme); + TEST_FAIL(failure_msg); + } + } + } + } +} + +/* + * Given a valid uri, this test checks that the + * uri_parser can isolate all parts of it successfully. + */ +static void _result_components_matches_input(void) +{ + char *failure_msg = "Failure: The uri_parser did not parse the uri correctly."; + int expected_ret = 0; + + expected_uri_result_t uri_0 = { + .input_uri = "coap://example.org/foo/bar", + .scheme = "coap", + .userinfo = "", /* This is an empty string because no userinfo has been set in this uri */ + .host = "example.org", + .ipv6addr = "", /* This is an empty string because a hostname was used instead in this uri */ + .zoneid = "", /* Not applicable without ipv6 */ + .port_str = "", /* This is an empty string because no port has been set in this uri */ + .port = 0, /* Remains zero when no port is given */ + .path = "/foo/bar", + .query = "" /* This is an empty string because no query is present in this uri */ + }; + expected_uri_result_t uri_trailing_slash = { + .input_uri = "coap://example.org/", + .scheme = "coap", + .userinfo = "", + .host = "example.org", + .ipv6addr = "", + .zoneid = "", + .port_str = "", + .port = 0, + .path = "/", + .query = "" + }; + expected_uri_result_t uri_without_trailing_slash = { + .input_uri = "coap://example.org", + .scheme = "coap", + .userinfo = "", + .host = "example.org", + .ipv6addr = "", + .zoneid = "", + .port_str = "", + .port = 0, + .path = "", + .query = "" + }; + expected_uri_result_t uri_with_userinfo = { + .input_uri = "coap://user@example.org", + .scheme = "coap", + .userinfo = "user", + .host = "example.org", + .ipv6addr = "", + .zoneid = "", + .port_str = "", + .port = 0, + .path = "", + .query = "" + }; + expected_uri_result_t uri_with_ipv6 = { + .input_uri = "coap://user@[2001:db8::1]", + .scheme = "coap", + .userinfo = "user", + .host = "[2001:db8::1]", + .ipv6addr = "2001:db8::1", + .zoneid = "", + .port_str = "", + .port = 0, + .path = "", + .query = "" + }; + expected_uri_result_t uri_with_ipv6_and_port = { + .input_uri = "coap://user@[2001:db8::1]:12345", + .scheme = "coap", + .userinfo = "user", + .host = "[2001:db8::1]", + .ipv6addr = "2001:db8::1", + .zoneid = "", + .port_str = "12345", + .port = 12345, + .path = "", + .query = "" + }; + expected_uri_result_t uri_with_ipv6_and_port_and_zoneid = { + .input_uri = "coap://user@[2001:db8::1%eth0]:12345", + .scheme = "coap", + .userinfo = "user", + .host = "[2001:db8::1%eth0]", + .ipv6addr = "2001:db8::1", + .zoneid = "eth0", + .port_str = "12345", + .port = 12345, + .path = "", + .query = "" + }; + + expected_uri_result_t *test_vec[] = { + &uri_0, + &uri_trailing_slash, + &uri_without_trailing_slash, + &uri_with_userinfo, + &uri_with_ipv6, + &uri_with_ipv6_and_port, + &uri_with_ipv6_and_port_and_zoneid, + }; + + uri_parser_result_t uri_res; + int ret = 0; + + for (unsigned int i = 0; i < ARRAY_SIZE(test_vec); ++i) { + expected_uri_result_t *this_vec = test_vec[i]; + + ret = uri_parser_process_string(&uri_res, this_vec->input_uri); + if (ret != expected_ret) { + /* if the uri_parser return indicates an error, this test fails */ + _print_return_expectation(this_vec->input_uri, expected_ret, ret); + TEST_FAIL(failure_msg); + } + else { + /* if the uri_parser return indicates success */ + if (_compare_string_buffer("scheme", this_vec->input_uri, this_vec->scheme, + uri_res.scheme, uri_res.scheme_len) != 0) { + TEST_FAIL(failure_msg); + } + if (_compare_string_buffer("userinfo", this_vec->input_uri, this_vec->userinfo, + uri_res.userinfo, uri_res.userinfo_len) != 0) { + TEST_FAIL(failure_msg); + } + if (_compare_string_buffer("host", this_vec->input_uri, this_vec->host, uri_res.host, + uri_res.host_len) != 0) { + TEST_FAIL(failure_msg); + } + if (_compare_string_buffer("ipv6addr", this_vec->input_uri, this_vec->ipv6addr, + uri_res.ipv6addr, uri_res.ipv6addr_len) != 0) { + TEST_FAIL(failure_msg); + } + if (_compare_string_buffer("zoneid", this_vec->input_uri, this_vec->zoneid, + uri_res.zoneid, uri_res.zoneid_len) != 0) { + TEST_FAIL(failure_msg); + } + if (_compare_string_buffer("port_str", this_vec->input_uri, this_vec->port_str, + uri_res.port_str, uri_res.port_str_len) != 0) { + TEST_FAIL(failure_msg); + } + if (_compare_string_buffer("path", this_vec->input_uri, this_vec->path, uri_res.path, + uri_res.path_len) != 0) { + TEST_FAIL(failure_msg); + } + if (_compare_string_buffer("query", this_vec->input_uri, this_vec->query, uri_res.query, + uri_res.query_len) != 0) { + TEST_FAIL(failure_msg); + } + } + } +} + + static void test_uri_parser__unterminated_string(void) { + char *failure_msg = + "Failure: The uri_parser did not parse an unterminated uri string correctly."; + expected_uri_result_t this_vec = { + .input_uri = "coap://RIOT:test@[fe80:db8::1%eth2]:5683/.well-known/core?v=1", + .scheme = "coap", + .userinfo = "RIOT:test", + .host = "[fe80:db8::1%eth2]", + .ipv6addr = "fe80:db8::1", + .zoneid = "eth2", + .port_str = "5683", + .port = 5683, + .path = "/.well-known/core", + .query = "v=1" + }; + uri_parser_result_t ures; char uri[64]; - /* initialize with a non-null character */ + + /* initialize with a non-null character */ memset(uri, 'Z', sizeof(uri)); - memcpy(uri, validate_uris[0].uri, strlen(validate_uris[0].uri)); + memcpy(uri, this_vec.input_uri, strlen(this_vec.input_uri)); - int res = uri_parser_process(&ures, uri, strlen(validate_uris[0].uri)); + int res = uri_parser_process(&ures, uri, strlen(this_vec.input_uri)); TEST_ASSERT_EQUAL_INT(0, res); - VEC_CHECK_STR(scheme, 0, _failure_msg); - VEC_CHECK_STR(userinfo, 0, _failure_msg); - VEC_CHECK_STR(host, 0, _failure_msg); - VEC_CHECK_STR(ipv6addr, 0, _failure_msg); - VEC_CHECK_STR(zoneid, 0, _failure_msg); - VEC_CHECK_STR(port_str, 0, _failure_msg); - VEC_CHECK_INT(port, 0, _failure_msg); - VEC_CHECK_STR(path, 0, _failure_msg); - VEC_CHECK_STR(query, 0, _failure_msg); + + if (_compare_string_buffer("userinfo", this_vec.input_uri, this_vec.userinfo, ures.userinfo, + ures.userinfo_len) != 0) { + TEST_FAIL(failure_msg); + } + if (_compare_string_buffer("host", this_vec.input_uri, this_vec.host, ures.host, + ures.host_len) != 0) { + TEST_FAIL(failure_msg); + } + if (_compare_string_buffer("ipv6addr", this_vec.input_uri, this_vec.ipv6addr, ures.ipv6addr, + ures.ipv6addr_len) != 0) { + TEST_FAIL(failure_msg); + } + if (_compare_string_buffer("zoneid", this_vec.input_uri, this_vec.zoneid, ures.zoneid, + ures.zoneid_len) != 0) { + TEST_FAIL(failure_msg); + } + if (_compare_string_buffer("port_str", this_vec.input_uri, this_vec.port_str, ures.port_str, + ures.port_str_len) != 0) { + TEST_FAIL(failure_msg); + } + if (_compare_string_buffer("path", this_vec.input_uri, this_vec.path, ures.path, + ures.path_len) != 0) { + TEST_FAIL(failure_msg); + } + if (_compare_string_buffer("query", this_vec.input_uri, this_vec.query, ures.query, + ures.query_len) != 0) { + TEST_FAIL(failure_msg); + } } + Test *tests_uri_parser_tests(void) { EMB_UNIT_TESTFIXTURES(fixtures) { - new_TestFixture(test_uri_parser__validate), + new_TestFixture(_successful_parsing_of_valid_uri), + new_TestFixture(_successful_rejecting_of_invalid_uri), + new_TestFixture(_error_if_port_str_is_too_long), + new_TestFixture(_error_if_port_str_contains_illegal_characters), + new_TestFixture(_result_component_scheme_matches_input_scheme), + new_TestFixture(_result_components_matches_input), new_TestFixture(test_uri_parser__unterminated_string), };