diff --git a/tests/unittests/tests-clif/Makefile b/tests/unittests/tests-clif/Makefile new file mode 100644 index 0000000000000..48422e909a47d --- /dev/null +++ b/tests/unittests/tests-clif/Makefile @@ -0,0 +1 @@ +include $(RIOTBASE)/Makefile.base diff --git a/tests/unittests/tests-clif/Makefile.include b/tests/unittests/tests-clif/Makefile.include new file mode 100644 index 0000000000000..fdeca4902bc22 --- /dev/null +++ b/tests/unittests/tests-clif/Makefile.include @@ -0,0 +1 @@ +USEMODULE += clif diff --git a/tests/unittests/tests-clif/tests-clif.c b/tests/unittests/tests-clif/tests-clif.c new file mode 100644 index 0000000000000..2552581cc1390 --- /dev/null +++ b/tests/unittests/tests-clif/tests-clif.c @@ -0,0 +1,292 @@ +/* +* Copyright (C) 2019 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 +* directory for more details. +*/ + +#include +#include "embUnit.h" +#include "tests-clif.h" + +#include "clif.h" + +#ifdef TESTS_CLIF_PRINT +#include +static void _print_attr(clif_attr_t *attr) +{ + if (attr->key) { + printf("-- Attr: "); + printf("%.*s", attr->key_len, attr->key); + if (attr->value) { + printf(" = %.*s\n", attr->value_len, attr->value); + } + else { + puts(""); + } + } +} +#endif /* TESTS_CLIF_PRINT */ + +#define _STR_LEN(s) (sizeof(s)-1) +#define _NEW_ATTR(k, v) { .key = k, .key_len = _STR_LEN(k), .value = v, \ + .value_len = _STR_LEN(v) } +#define _NEW_ATTR_NO_VAL(k) { .key = k, .key_len = _STR_LEN(k), .value_len = 0 } + +/** + * @brief Compares two link format attributes + * + * @param[in] p1 first attribute to compare + * @param[in] p2 second attribute to compare + * + * @return 0 if attributes are equal + * @return 1 otherwise + */ +static unsigned _compare_attrs(clif_attr_t *p1, clif_attr_t *p2) +{ + unsigned result = 1; + int res; + + if (p1->key_len != p2->key_len) { + goto out; + } + + if (strncmp(p1->key, p2->key, p1->key_len)) { + goto out; + } + + if (!p1->value && !p2->value) { + goto success_out; + } + + if (!p1->value || !p2->value || (p1->value_len != p2->value_len)) { + goto out; + } + + res = strncmp(p1->value, p2->value, p1->value_len); + if (res != 0) { + goto out; + } +success_out: + result = 0; +out: + return result; +} + +/* This also tests the functions `clif_add_target` and + * `clif_add_attr`. */ +static void test_clif_encode_links(void) +{ + const char exp_string[] = ";rt=\"temperature\";if=\"sensor\"," + ",;ct=\"40\""; + clif_attr_t attrs[] = { + { .key = "rt", .value = "temperature" }, + { .key = "if", .value = "sensor" }, + { .key = "ct", .value = "40" } + }; + + clif_t links[] = { + { .target = "/sensor/temp", .attrs = attrs, .attrs_len = 2 }, + { .target = "/node/info", .attrs_len = 0 }, + { .target = "/node/ep", .attrs = &attrs[2], .attrs_len = 1 } + }; + + const size_t exp_size = sizeof(exp_string) - 1; + char output[exp_size + 1]; + size_t pos = 0; + ssize_t res = 0; + + /* first test with NULL output to check the needed bytes */ + res = clif_encode_link(&links[0], NULL, 0); + pos += res; + + for (unsigned i = 1; i < sizeof(links) / sizeof(links[0]); i++) { + res = clif_add_link_separator(NULL, 0); + if (res <= 0) { + break; + } + pos += res; + + res = clif_encode_link(&links[i],NULL, 0); + if (res <= 0) { + break; + } + pos += res; + } + + TEST_ASSERT_EQUAL_INT(exp_size, pos); + + /* now actually encode the links */ + pos = 0; + res = clif_encode_link(&links[0], output, sizeof(output)); + pos += res; + + for (unsigned i = 1; i < sizeof(links) / sizeof(links[0]); i++) { + res = clif_add_link_separator(&output[pos], sizeof(output) - pos); + if (res <= 0) { + break; + } + pos += res; + + res = clif_encode_link(&links[i], &output[pos], sizeof(output) - pos); + if (res <= 0) { + break; + } + pos += res; + } + output[pos++] = '\0'; + +#ifdef TESTS_CLIF_PRINT + puts("\n========================================"); + puts("[Test: encode_links]"); + puts("---------------------"); + printf("Encoded links: %s\n", output); +#endif + + TEST_ASSERT_EQUAL_STRING(exp_string, output); + TEST_ASSERT_EQUAL_INT(exp_size, pos - 1); /* do not count '\0' */ +} + +/* This also tests the functions `clif_get_target` and `clif_get_attr` */ +static void test_clif_decode_links(void) +{ + /* string to decode */ + char input_string[] = ";ct=40;title=\"\\\"Sensor\\\" Index, collection\"," + ";rt=\"temperature-c\";if=\"sensor\"," + ";rt=\"light-lux\";if=sensor," + ";" + "anchor=\"/sensors/temp\";rel=\"describedby\";sz=1234," + ";anchor=\"/sensors/temp\";rel=\"alternate\";a;s=\"This is \\\"escaped and has , \\\"\"," + ",;obs"; + + /* ordered expected types to be decoded */ + clif_attr_type_t exp_types[] = { + CLIF_ATTR_CT, CLIF_ATTR_TITLE, CLIF_ATTR_RT, CLIF_ATTR_IF, + CLIF_ATTR_RT, CLIF_ATTR_IF, CLIF_ATTR_ANCHOR, CLIF_ATTR_REL, + CLIF_ATTR_SZ, CLIF_ATTR_ANCHOR, CLIF_ATTR_REL, CLIF_ATTR_EXT, + CLIF_ATTR_EXT, CLIF_ATTR_OBS + }; + + /* ordered amount of expected attributes per link to be decoded */ + unsigned exp_attr_numof[] = { 2, 2, 2, 3, 4, 0, 1 }; + + /* ordered expected attributes to be decoded */ + clif_attr_t exp_attrs[] = { + _NEW_ATTR("ct", "40"), + _NEW_ATTR("title", "\\\"Sensor\\\" Index, collection"), + _NEW_ATTR("rt", "temperature-c"), + _NEW_ATTR("if", "sensor"), + _NEW_ATTR("rt", "light-lux"), + _NEW_ATTR("if", "sensor"), + _NEW_ATTR("anchor", "/sensors/temp"), + _NEW_ATTR("rel", "describedby"), + _NEW_ATTR("sz", "1234"), + _NEW_ATTR("anchor", "/sensors/temp"), + _NEW_ATTR("rel", "alternate"), + _NEW_ATTR_NO_VAL("a"), + _NEW_ATTR("s", "This is \\\"escaped and has , \\\""), + _NEW_ATTR_NO_VAL("obs"), + }; + + /* ordered expected targets to be decoded */ + const char *exp_targets[] = { + "/sensors", "/sensors/temp", "/sensors/light", + "http://www.example.com/sensors/t123", "/t", "/riot/board", "/riot/info" + }; + + const unsigned exp_links_numof = sizeof(exp_targets) / sizeof(exp_targets[0]); + const unsigned exp_attrs_numof = sizeof(exp_attrs) / sizeof(exp_attrs[0]); + const size_t input_len = sizeof(input_string) - 1; + + clif_t out_link; + char *pos = input_string; + unsigned links_numof = 0; + + /* first test without attributes array, to test the expected attributes + * functionality */ + do { + ssize_t res = clif_decode_link(&out_link, NULL, 0, pos, + input_len - (pos - input_string)); + if (res < 0) { + break; + } + pos += res; + + /* check expected target */ + TEST_ASSERT(!strncmp(exp_targets[links_numof], out_link.target, out_link.target_len)); + + /* check expected amount of attributes */ + TEST_ASSERT_EQUAL_INT(exp_attr_numof[links_numof], out_link.attrs_len); + links_numof++; + } while (pos < input_string + sizeof(input_string)); + +#ifdef TESTS_CLIF_PRINT + puts("\n========================================"); + puts("[Test: decode_links]"); + printf("- Amount of decoded links: %u\n", links_numof); +#endif + TEST_ASSERT(exp_links_numof == links_numof); + + /* now decode again but saving the attributes */ + clif_attr_t out_attrs[exp_attrs_numof]; + pos = input_string; + unsigned attrs_numof = 0; + do { + ssize_t res = clif_decode_link(&out_link, &out_attrs[attrs_numof], + exp_attrs_numof - attrs_numof, pos, + input_len - (pos - input_string)); + + if (res < 0) { + break; + } + pos += res; +#ifdef TESTS_CLIF_PRINT + puts("---------------------"); + puts("New link:"); + printf("- Target: %.*s\n", out_link.target_len, out_link.target); + printf("- Number of attributes: %d\n", out_link.attrs_len); +#endif + + for (unsigned i = 0; i < out_link.attrs_len; i++) { +#ifdef TESTS_CLIF_PRINT + _print_attr(&out_link.attrs[i]); +#endif + /* compare the attribute structure with the expected one */ + TEST_ASSERT(!_compare_attrs(&out_link.attrs[i], + &exp_attrs[attrs_numof])); + clif_attr_type_t type = clif_get_attr_type(out_link.attrs[i].key, + out_link.attrs[i].key_len); + + /* check that the returned type is the expected one */ + TEST_ASSERT_EQUAL_INT(exp_types[attrs_numof], type); + + /* test type to string conversion */ + const char *t; + if (clif_attr_type_to_str(type, &t) < 0) { + t = NULL; + } + TEST_ASSERT_EQUAL_STRING(type == CLIF_ATTR_EXT ? + NULL : exp_attrs[attrs_numof].key, t); + attrs_numof++; + } + } while (pos < input_string + sizeof(input_string)); + TEST_ASSERT_EQUAL_INT(exp_attrs_numof, attrs_numof); +} + +Test *tests_clif_tests(void) +{ + EMB_UNIT_TESTFIXTURES(fixtures) { + new_TestFixture(test_clif_encode_links), + new_TestFixture(test_clif_decode_links) + }; + + EMB_UNIT_TESTCALLER(clif_tests, NULL, NULL, fixtures); + + return (Test *)&clif_tests; +} + +void tests_clif(void) +{ + TESTS_RUN(tests_clif_tests()); +} diff --git a/tests/unittests/tests-clif/tests-clif.h b/tests/unittests/tests-clif/tests-clif.h new file mode 100644 index 0000000000000..55dc45ee794af --- /dev/null +++ b/tests/unittests/tests-clif/tests-clif.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2019 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 + * directory for more details. + */ + +/** + * @addtogroup unittests + * @{ + * + * @file + * @brief Unittests for the ``clif`` module + * + * @author Leandro Lanzieri + */ +#ifndef TESTS_CLIF_H +#define TESTS_CLIF_H +#include "embUnit/embUnit.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** +* @brief The entry point of this test suite. +*/ +void tests_clif(void); + +/** + * @brief Generates tests for link format + * + * @return embUnit tests if successful, NULL if not. + */ +Test *tests_clif_tests(void); + +#ifdef __cplusplus +} +#endif + +#endif /* TESTS_CLIF_H */ +/** @} */