From 3cbd8a356b4bcc1b41a20dba56858071150026d5 Mon Sep 17 00:00:00 2001 From: MrKevinWeiss Date: Fri, 12 Mar 2021 16:15:07 +0100 Subject: [PATCH 1/8] sys/result_output: Add initial json implementation --- sys/test_utils/result_output/json/Makefile | 3 + sys/test_utils/result_output/json/doc.txt | 13 ++ .../result_output/json/result_output_json.c | 122 ++++++++++++++++++ .../result_output/json/result_output_types.h | 37 ++++++ 4 files changed, 175 insertions(+) create mode 100644 sys/test_utils/result_output/json/Makefile create mode 100644 sys/test_utils/result_output/json/doc.txt create mode 100644 sys/test_utils/result_output/json/result_output_json.c create mode 100644 sys/test_utils/result_output/json/result_output_types.h diff --git a/sys/test_utils/result_output/json/Makefile b/sys/test_utils/result_output/json/Makefile new file mode 100644 index 000000000000..341563e492b9 --- /dev/null +++ b/sys/test_utils/result_output/json/Makefile @@ -0,0 +1,3 @@ +MODULE = test_utils_result_output_json + +include $(RIOTBASE)/Makefile.base diff --git a/sys/test_utils/result_output/json/doc.txt b/sys/test_utils/result_output/json/doc.txt new file mode 100644 index 000000000000..d3f2b1924ac6 --- /dev/null +++ b/sys/test_utils/result_output/json/doc.txt @@ -0,0 +1,13 @@ +/** + * @defgroup test_utils_result_output_json Test result output with JSON + * @brief Enable this module to have results output as json + * @ingroup test_utils_result_output + * @{ + * + * @file + * @brief Result output in json + * + * + * @author Kevin Weiss + * @} + */ diff --git a/sys/test_utils/result_output/json/result_output_json.c b/sys/test_utils/result_output/json/result_output_json.c new file mode 100644 index 000000000000..0080e54bf60b --- /dev/null +++ b/sys/test_utils/result_output/json/result_output_json.c @@ -0,0 +1,122 @@ +/* + * Copyright (C) 2020 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 + +#include "fmt.h" + +#include "test_utils/result_output.h" + +static void _print_comma(turo_t *ctx, turo_state_t state) +{ + if (ctx->state == TURO_STATE_NEED_COMMA) { + print_str(","); + } + ctx->state = state; +} + +void turo_init(turo_t *ctx) +{ + ctx->state = TURO_STATE_READY; +} + +void turo_container_open(turo_t *ctx) +{ + (void)ctx; + print_str("["); +} + +void turo_s32(turo_t *ctx, int32_t val) +{ + _print_comma(ctx, TURO_STATE_NEED_COMMA); + print_s32_dec(val); +} + +void turo_u32(turo_t *ctx, uint32_t val) +{ + _print_comma(ctx, TURO_STATE_NEED_COMMA); + print_u32_dec(val); +} + +void turo_s64(turo_t *ctx, int64_t val) +{ + _print_comma(ctx, TURO_STATE_NEED_COMMA); + print_s64_dec(val); +} + +void turo_u64(turo_t *ctx, uint64_t val) +{ + _print_comma(ctx, TURO_STATE_NEED_COMMA); + print_u64_dec(val); +} + +void turo_float(turo_t *ctx, float val) +{ + _print_comma(ctx, TURO_STATE_NEED_COMMA); + print_float(val, 8); +} + +void turo_string(turo_t *ctx, const char *str) +{ + _print_comma(ctx, TURO_STATE_NEED_COMMA); + print_str("\""); + print_str(str); + print_str("\""); +} + +void turo_bool(turo_t *ctx, bool val) +{ + _print_comma(ctx, TURO_STATE_NEED_COMMA); + if (val) { + print_str("true"); + } + else { + print_str("false"); + } +} + +void turo_dict_open(turo_t *ctx) +{ + _print_comma(ctx, TURO_STATE_READY); + print_str("{"); +} + +void turo_dict_key(turo_t *ctx, const char *key) +{ + _print_comma(ctx, TURO_STATE_READY); + print_str("\""); + print_str(key); + print_str("\": "); +} + +void turo_dict_close(turo_t *ctx) +{ + ctx->state = TURO_STATE_NEED_COMMA; + print_str("}"); +} + +void turo_array_open(turo_t *ctx) +{ + _print_comma(ctx, TURO_STATE_READY); + print_str("["); +} + +void turo_array_close(turo_t *ctx) +{ + ctx->state = TURO_STATE_NEED_COMMA; + print_str("]"); +} + +void turo_container_close(turo_t *ctx, int exit_status) +{ + _print_comma(ctx, TURO_STATE_READY); + print_str("{\"exit_status\": "); + print_s32_dec((int32_t)exit_status); + print_str("}]\n"); +} diff --git a/sys/test_utils/result_output/json/result_output_types.h b/sys/test_utils/result_output/json/result_output_types.h new file mode 100644 index 000000000000..71fa6aabac23 --- /dev/null +++ b/sys/test_utils/result_output/json/result_output_types.h @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2021 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. + */ + +#ifndef RESULT_OUTPUT_TYPES_H +#define RESULT_OUTPUT_TYPES_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief States of the TURO container + * @{ + */ +typedef enum { + TURO_STATE_READY, /**< state ready */ + TURO_STATE_NEED_COMMA, /**< next entry will need a comma */ +} turo_state_t; +/** @} */ + +/** + * @brief turo type + * @internal + */ +struct turo { + turo_state_t state; /**< current state */ +}; + +#ifdef __cplusplus +} +#endif +#endif /* RESULT_OUTPUT_TYPES_H */ From d17829311cfbf39fd5919887c27dbe6e17a9fa42 Mon Sep 17 00:00:00 2001 From: MrKevinWeiss Date: Fri, 12 Mar 2021 16:16:28 +0100 Subject: [PATCH 2/8] sys/result_output: Add initial text implementation --- sys/test_utils/result_output/txt/Makefile | 3 + sys/test_utils/result_output/txt/doc.txt | 13 ++ .../result_output/txt/result_output_txt.c | 115 ++++++++++++++++++ .../result_output/txt/result_output_types.h | 27 ++++ 4 files changed, 158 insertions(+) create mode 100644 sys/test_utils/result_output/txt/Makefile create mode 100644 sys/test_utils/result_output/txt/doc.txt create mode 100644 sys/test_utils/result_output/txt/result_output_txt.c create mode 100644 sys/test_utils/result_output/txt/result_output_types.h diff --git a/sys/test_utils/result_output/txt/Makefile b/sys/test_utils/result_output/txt/Makefile new file mode 100644 index 000000000000..754f54df5c8b --- /dev/null +++ b/sys/test_utils/result_output/txt/Makefile @@ -0,0 +1,3 @@ +MODULE = test_utils_result_output_txt + +include $(RIOTBASE)/Makefile.base diff --git a/sys/test_utils/result_output/txt/doc.txt b/sys/test_utils/result_output/txt/doc.txt new file mode 100644 index 000000000000..5286eacc5ff7 --- /dev/null +++ b/sys/test_utils/result_output/txt/doc.txt @@ -0,0 +1,13 @@ +/** + * @defgroup test_utils_result_output_txt Test result output plain text + * @brief Enable this module to have results output as text + * @ingroup test_utils_result_output + * @{ + * + * @file + * @brief Result output plain text. + * + * + * @author Kevin Weiss + * @} + */ diff --git a/sys/test_utils/result_output/txt/result_output_txt.c b/sys/test_utils/result_output/txt/result_output_txt.c new file mode 100644 index 000000000000..ea4cddbed2be --- /dev/null +++ b/sys/test_utils/result_output/txt/result_output_txt.c @@ -0,0 +1,115 @@ +/* + * Copyright (C) 2020 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 + +#include "fmt.h" + +#include "test_utils/result_output.h" + +void turo_container_open(turo_t *ctx) +{ + (void)ctx; +} + +void turo_s32(turo_t *ctx, int32_t val) +{ + (void)ctx; + print_s32_dec(val); + print_str(" "); +} + +void turo_u32(turo_t *ctx, uint32_t val) +{ + (void)ctx; + print_u32_dec(val); + print_str(" "); +} + +void turo_s64(turo_t *ctx, int64_t val) +{ + (void)ctx; + print_s64_dec(val); + print_str(" "); +} + +void turo_u64(turo_t *ctx, uint64_t val) +{ + (void)ctx; + print_u64_dec(val); + print_str(" "); +} + +void turo_float(turo_t *ctx, float val) +{ + (void)ctx; + print_float(val, 8); + print_str(" "); +} + +void turo_string(turo_t *ctx, const char *str) +{ + (void)ctx; + print_str(str); + print_str(" "); +} + +void turo_bool(turo_t *ctx, bool val) +{ + (void)ctx; + if (val) { + print_str("True"); + } + else { + print_str("False"); + } + print_str(" "); +} + +void turo_dict_open(turo_t *ctx) +{ + (void)ctx; +} + +void turo_dict_key(turo_t *ctx, const char *key) +{ + (void)ctx; + print_str(key); + print_str(": "); + +} + +void turo_dict_close(turo_t *ctx) +{ + (void)ctx; + print_str("\n"); +} + +void turo_array_open(turo_t *ctx) +{ + (void)ctx; +} + +void turo_array_close(turo_t *ctx) +{ + (void)ctx; + print_str("\n"); +} + +void turo_container_close(turo_t *ctx, int exit_status) +{ + (void)ctx; + (void)exit_status; + if (exit_status) { + print_str("\nError\n"); + } + else { + print_str("\nSuccess\n"); + } +} diff --git a/sys/test_utils/result_output/txt/result_output_types.h b/sys/test_utils/result_output/txt/result_output_types.h new file mode 100644 index 000000000000..91963572a371 --- /dev/null +++ b/sys/test_utils/result_output/txt/result_output_types.h @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2021 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. + */ + +#ifndef RESULT_OUTPUT_TYPES_H +#define RESULT_OUTPUT_TYPES_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief turo type + * @internal + */ +struct turo { + void *empty; /**< Empty type needed due to C11-ยง6.7.2.1/5 */ +}; + +#ifdef __cplusplus +} +#endif +#endif /* RESULT_OUTPUT_TYPES_H */ From 2c2be2636da79003461ebd0ac460817256e7e82b Mon Sep 17 00:00:00 2001 From: MrKevinWeiss Date: Fri, 12 Mar 2021 16:17:12 +0100 Subject: [PATCH 3/8] sys/result_output: Add initial structure check --- sys/test_utils/result_output/check/Makefile | 3 + sys/test_utils/result_output/check/doc.txt | 13 ++ .../result_output/check/result_output_check.c | 126 ++++++++++++++++++ .../result_output/check/result_output_types.h | 45 +++++++ 4 files changed, 187 insertions(+) create mode 100644 sys/test_utils/result_output/check/Makefile create mode 100644 sys/test_utils/result_output/check/doc.txt create mode 100644 sys/test_utils/result_output/check/result_output_check.c create mode 100644 sys/test_utils/result_output/check/result_output_types.h diff --git a/sys/test_utils/result_output/check/Makefile b/sys/test_utils/result_output/check/Makefile new file mode 100644 index 000000000000..1224fbb7670c --- /dev/null +++ b/sys/test_utils/result_output/check/Makefile @@ -0,0 +1,3 @@ +MODULE = test_utils_result_output_check + +include $(RIOTBASE)/Makefile.base diff --git a/sys/test_utils/result_output/check/doc.txt b/sys/test_utils/result_output/check/doc.txt new file mode 100644 index 000000000000..5666c10362b2 --- /dev/null +++ b/sys/test_utils/result_output/check/doc.txt @@ -0,0 +1,13 @@ +/** + * @defgroup test_utils_result_output_check Test result output structure + * @brief Enable this module to check the result structure + * @ingroup test_utils_result_output + * @{ + * + * @file + * @brief Result output assert check implementation + * + * + * @author Kevin Weiss + * @} + */ diff --git a/sys/test_utils/result_output/check/result_output_check.c b/sys/test_utils/result_output/check/result_output_check.c new file mode 100644 index 000000000000..b095929d8f5e --- /dev/null +++ b/sys/test_utils/result_output/check/result_output_check.c @@ -0,0 +1,126 @@ +/* + * Copyright (C) 2021 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 +#include + +#include "test_utils/result_output.h" + +void turo_init(turo_t *ctx) +{ + ctx->idx = 0; +} + +void turo_container_open(turo_t *ctx) +{ + assert(ctx->idx == 0); + assert(ctx->idx < CONFIG_TURO_MAX_NESTING_LEVELS); + ctx->states[ctx->idx++] = TURO_STATE_CONTAINER; + ctx->states[ctx->idx] = TURO_STATE_READY; +} + +static void _val_check(turo_t *ctx) +{ + assert(ctx->idx > 0); + assert(ctx->states[ctx->idx] != TURO_STATE_DICT_OPENED); + ctx->states[ctx->idx] = TURO_STATE_READY; +} + +void turo_s32(turo_t *ctx, int32_t val) +{ + (void)val; + _val_check(ctx); +} + +void turo_u32(turo_t *ctx, uint32_t val) +{ + (void)val; + _val_check(ctx); +} + +void turo_s64(turo_t *ctx, int64_t val) +{ + (void)val; + _val_check(ctx); +} + +void turo_u64(turo_t *ctx, uint64_t val) +{ + (void)val; + _val_check(ctx); +} + +void turo_float(turo_t *ctx, float val) +{ + (void)val; + _val_check(ctx); +} + +void turo_string(turo_t *ctx, const char *str) +{ + (void)str; + _val_check(ctx); +} + +void turo_bool(turo_t *ctx, bool val) +{ + (void)val; + _val_check(ctx); +} + +void turo_dict_open(turo_t *ctx) +{ + assert(ctx->idx > 0); + assert(ctx->idx < CONFIG_TURO_MAX_NESTING_LEVELS); + ctx->states[ctx->idx++] = TURO_STATE_DICT_OPENED; + ctx->states[ctx->idx] = TURO_STATE_DICT_OPENED; +} + +void turo_dict_key(turo_t *ctx, const char *key) +{ + (void)key; + assert(ctx->idx > 0); + assert(ctx->states[ctx->idx - 1] == TURO_STATE_DICT_OPENED); + assert(ctx->states[ctx->idx] == TURO_STATE_READY || + ctx->states[ctx->idx] == TURO_STATE_DICT_OPENED); + ctx->states[ctx->idx] = TURO_STATE_READY; +} + +void turo_dict_close(turo_t *ctx) +{ + assert(ctx->idx > 0); + assert(ctx->states[ctx->idx] == TURO_STATE_READY); + assert(ctx->states[--ctx->idx] == TURO_STATE_DICT_OPENED); + ctx->states[ctx->idx] = TURO_STATE_READY; +} + +void turo_array_open(turo_t *ctx) +{ + assert(ctx->idx > 0); + assert(ctx->idx < CONFIG_TURO_MAX_NESTING_LEVELS); + ctx->states[ctx->idx++] = TURO_STATE_ARRAY_OPENED; + ctx->states[ctx->idx] = TURO_STATE_READY; +} + +void turo_array_close(turo_t *ctx) +{ + assert(ctx->idx > 0); + assert(ctx->states[ctx->idx] == TURO_STATE_READY); + assert(ctx->states[--ctx->idx] == TURO_STATE_ARRAY_OPENED); + ctx->states[ctx->idx] = TURO_STATE_READY; +} + +void turo_container_close(turo_t *ctx, int exit_status) +{ + (void)exit_status; + assert(ctx->idx == 1); + assert(ctx->states[ctx->idx] == TURO_STATE_READY); + assert(ctx->states[0] == TURO_STATE_CONTAINER); + ctx->idx--; +} diff --git a/sys/test_utils/result_output/check/result_output_types.h b/sys/test_utils/result_output/check/result_output_types.h new file mode 100644 index 000000000000..601a1b52e257 --- /dev/null +++ b/sys/test_utils/result_output/check/result_output_types.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2021 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. + */ + +#ifndef RESULT_OUTPUT_TYPES_H +#define RESULT_OUTPUT_TYPES_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef CONFIG_TURO_MAX_NESTING_LEVELS +#define CONFIG_TURO_MAX_NESTING_LEVELS 32 /**< max level of state nesting */ +#endif + +/** + * @brief States of the TURO container + * @{ + */ +typedef enum { + TURO_STATE_UNKNOWN, /**< unknown state */ + TURO_STATE_READY, /**< state ready */ + TURO_STATE_CONTAINER, /**< container open or closing */ + TURO_STATE_DICT_OPENED, /**< dictionary opened */ + TURO_STATE_ARRAY_OPENED /**< array opening */ +} turo_state_t; +/** @} */ + +/** + * @brief turo type + * @internal + */ +struct turo { + size_t idx; /**< index for states */ + turo_state_t states[CONFIG_TURO_MAX_NESTING_LEVELS]; /**< state buffer */ +}; + +#ifdef __cplusplus +} +#endif +#endif /* RESULT_OUTPUT_TYPES_H */ From 6a3eb46d5e714617d08b0bf06cddc05af4e92454 Mon Sep 17 00:00:00 2001 From: MrKevinWeiss Date: Fri, 12 Mar 2021 16:18:44 +0100 Subject: [PATCH 4/8] sys/result_output: Expose result output --- sys/Makefile | 3 + sys/Makefile.dep | 4 + sys/Makefile.include | 4 + sys/include/test_utils/result_output.h | 357 ++++++++++++++++++ sys/test_utils/Makefile.dep | 3 + sys/test_utils/result_output/Makefile | 15 + sys/test_utils/result_output/Makefile.include | 9 + sys/test_utils/result_output/result_output.c | 113 ++++++ 8 files changed, 508 insertions(+) create mode 100644 sys/include/test_utils/result_output.h create mode 100644 sys/test_utils/result_output/Makefile create mode 100644 sys/test_utils/result_output/Makefile.include create mode 100644 sys/test_utils/result_output/result_output.c diff --git a/sys/Makefile b/sys/Makefile index aaa35287477d..fc5c0633c238 100644 --- a/sys/Makefile +++ b/sys/Makefile @@ -173,6 +173,9 @@ endif ifneq (,$(filter test_utils_interactive_sync,$(USEMODULE))) DIRS += test_utils/interactive_sync endif +ifneq (,$(filter test_utils_result_output,$(USEMODULE))) + DIRS += test_utils/result_output +endif ifneq (,$(filter udp,$(USEMODULE))) DIRS += net/transport_layer/udp endif diff --git a/sys/Makefile.dep b/sys/Makefile.dep index 019d117ef197..0641aafa7bf6 100644 --- a/sys/Makefile.dep +++ b/sys/Makefile.dep @@ -1084,6 +1084,10 @@ ifneq (,$(filter suit_%,$(USEMODULE))) USEMODULE += suit endif +ifneq (,$(filter test_utils_result_output_%,$(USEMODULE))) + USEMODULE += test_utils_result_output +endif + # include ztimer dependencies ifneq (,$(filter ztimer% %ztimer,$(USEMODULE))) include $(RIOTBASE)/sys/ztimer/Makefile.dep diff --git a/sys/Makefile.include b/sys/Makefile.include index 058ed847e20d..69207bfc821f 100644 --- a/sys/Makefile.include +++ b/sys/Makefile.include @@ -129,6 +129,10 @@ ifneq (,$(filter zptr,$(USEMODULE))) include $(RIOTBASE)/sys/zptr/Makefile.include endif +ifneq (,$(filter test_utils_result_output,$(USEMODULE))) + include $(RIOTBASE)/sys/test_utils/result_output/Makefile.include +endif + # Convert xtimer into a pseudo module if its API is already implemented by # ztimer's compatibility wrapper ifneq (,$(filter ztimer_xtimer_compat,$(USEMODULE))) diff --git a/sys/include/test_utils/result_output.h b/sys/include/test_utils/result_output.h new file mode 100644 index 000000000000..da59e06b1547 --- /dev/null +++ b/sys/include/test_utils/result_output.h @@ -0,0 +1,357 @@ +/* + * Copyright (C) 2021 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. + */ + +/** + * @defgroup test_utils_result_output Test result output + * @ingroup sys + * @brief Utility function for abstraction of test result output format + * + * The TURO module provides an abstraction layer allowing salient data to be + * provided for tests independent of format or medium. The intention is to have + * a test that expects some data, for example, reading some registers, + * output the results in a know way, for example json. This should help + * keeping the test results stable and not lock anyone into a perticular + * format. If JSON is too heavy all tests using this can be swapped out for + * something lighter, for example CBOR. Then the tests should not have to be + * adapted. There can also be python layers that coordinate the output results, + * ideally done with riotctrl. + * + * Only one implementation should be selected, for example, + * test_utils_result_output_json. + * + * Some of the design decisions include: + * - ability to flush immediately to prevent the need for large buffers + * - selectable output format based on `USEMODULE`: + * + `test_utils_result_output_check`: @ref test_utils_result_output_check + * + `test_utils_result_output_json`: @ref test_utils_result_output_json + * + `test_utils_result_output_txt`: @ref test_utils_result_output_txt + * - exit status similar to a linux exit status. + * - readable raw output used in the CI to assist with reproducing errors + * - structure doesn't need to be enforced in every implementation to save + * bytes, see test_utils_result_output_check for structure assertions + * + * Some limitations are: + * - Only one type of result output implementation can be used at a time + * - Errors may be caused by the specific result output implementation making + * it difficult to debug + * + * @{ + * @file + * @brief Provides abstraction and convention for output of test results + * + * @author Kevin Weiss + */ + +#ifndef TEST_UTILS_RESULT_OUTPUT_H +#define TEST_UTILS_RESULT_OUTPUT_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include + +#include "result_output_types.h" + +/** @defgroup turo_API Test Utils Result Output Implementation API + * @brief The turo API that must have an implementation. + * @{ + */ + +/** + * @brief Type for a TURO object + * + * @note API implementors: `struct turo` needs to be defined by + * implementation-specific `result_output_types.h`. + */ +typedef struct turo turo_t; + +/** + * @brief Provides initial values for the turo context. + * + * @param[out] ctx The implementation specific turo context. + */ +void turo_init(turo_t *ctx); + +/** + * @brief Outputs a container open. + * + * Must be used when starting formatted result output. + * + * @param[in] ctx The implementation specific turo context. + */ +void turo_container_open(turo_t *ctx); + +/** + * @brief Outputs a signed 32 bit integer. + * + * @pre `turo_container_open` called + * + * @param[in] ctx The implementation specific turo context. + * @param[in] val The value to output. + */ +void turo_s32(turo_t *ctx, int32_t val); + +/** + * @brief Outputs an unsigned 32 bit integer. + * + * @pre `turo_container_open` called + * + * @param[in] ctx The implementation specific turo context. + * @param[in] val The value to output. + */ +void turo_u32(turo_t *ctx, uint32_t val); + +/** + * @brief Outputs a signed 64 bit integer. + * + * @pre `turo_container_open` called + * + * @param[in] ctx The implementation specific turo context. + * @param[in] val The value to output. + */ +void turo_s64(turo_t *ctx, int64_t val); + +/** + * @brief Outputs a formatted result unsigned 64 bit integer. + * + * @pre `turo_container_open` called + * + * @param[in] ctx The implementation specific turo context. + * @param[in] val The value to output. + */ +void turo_u64(turo_t *ctx, uint64_t val); + +/** + * @brief Outputs a formatted float result of varied precision. + * + * @pre `turo_container_open` called + * + * @param[in] ctx The implementation specific turo context. + * @param[in] val The value to output. + */ +void turo_float(turo_t *ctx, float val); + +/** + * @brief Outputs a formatted string string. + * + * @pre `turo_container_open` called + * + * @param[in] ctx The implementation specific turo context. + * @param[in] str The string to output. + */ +void turo_string(turo_t *ctx, const char *str); + +/** + * @brief Outputs a formatted boolean result. + * + * @pre `turo_container_open` called + * + * @param[in] ctx The implementation specific turo context. + * @param[in] val The value to output. + */ +void turo_bool(turo_t *ctx, bool val); + +/** + * @brief Outputs a formatted open of a dictionary result. + * + * A `turo_dict_close` must match. + * + * @pre `turo_container_open` called + * + * @param[in] ctx The implementation specific turo context. + */ +void turo_dict_open(turo_t *ctx); + +/** + * @brief Outputs a formatted open of a dictionary result. + * + * A turo value must follow. + * + * @pre `turo_container_open` called + * + * @param[in] ctx The implementation specific turo context. + * @param[in] key The key of the dictionary. + */ +void turo_dict_key(turo_t *ctx, const char *key); + +/** + * @brief Outputs a formatted close of a dictionary result. + * + * @pre `turo_container_open` called + * @pre `turo_dict_open` called + * + * @param[in] ctx The implementation specific turo context. + */ +void turo_dict_close(turo_t *ctx); + +/** + * @brief Outputs a formatted open of an array result. + * + * A `turo_array_close` must match. + * + * @pre `turo_container_open` called + * + * @param[in] ctx The implementation specific turo context. + */ +void turo_array_open(turo_t *ctx); + +/** + * @brief Outputs a formatted close of an array result. + * + * @pre `turo_container_open` called + * @pre `turo_array_open` called + * + * @param[in] ctx The implementation specific turo context. + */ +void turo_array_close(turo_t *ctx); + +/** + * @brief Outputs a formatted close of a container result. + * + * @pre `turo_container_open` called + * + * @param[in] ctx The implementation specific turo context. + * @param[in] exit_status Exit status code for the result, 0 is success. + */ +void turo_container_close(turo_t *ctx, int exit_status); +/** @} */ + +/** @defgroup turo_helpers Test Utils Result Output Helpers + * @brief Common functions and helpers that all implementations can use. + * @{ + */ + +/** + * @brief Outputs a formatted uint8 array result. + * + * @pre `turo_container_open` called + * + * @param[in] ctx The implementation specific turo context. + * @param[in] vals A buffer of data to output. + * @param[in] size The amount of elements to output. + */ +void turo_array_u8(turo_t *ctx, uint8_t *vals, size_t size); + +/** + * @brief Outputs a int32 array result. + * + * @pre `turo_container_open` called + * + * @param[in] ctx The implementation specific turo context. + * @param[in] vals A buffer of data to output. + * @param[in] size The amount of elements to output. + */ +void turo_array_s32(turo_t *ctx, int32_t *vals, size_t size); + +/** + * @brief Outputs a dict with string data. + * + * @pre `turo_container_open` called + * + * @param[in] ctx The implementation specific turo context. + * @param[in] key A dictionary key. + * @param[in] val A string value of the dictionary + */ +void turo_dict_string(turo_t *ctx, const char *key, const char *val); + +/** + * @brief Outputs a dict with integer data. + * + * @pre `turo_container_open` called + * + * @param[in] ctx The implementation specific turo context. + * @param[in] key A dictionary key. + * @param[in] val The integer value of the dictionary. + */ +void turo_dict_s32(turo_t *ctx, const char *key, int32_t val); + +/** + * @brief Outputs a full successful int32 turo result. + * + * This includes all opening and closing of turo elements. + * + * @pre turo ctx initialized + * + * @param[in] ctx The implementation specific turo context. + * @param[in] val The value to output. + */ +void turo_simple_s32(turo_t *ctx, int32_t val); + +/** + * @brief Outputs a full successful uint8 array turo result. + * + * This includes all opening and closing of turo elements. + * + * @pre turo ctx initialized + * + * @param[in] ctx The implementation specific turo context. + * @param[in] vals The buffer of the integers. + * @param[in] size Number of elements in the array. + */ +void turo_simple_array_u8(turo_t *ctx, uint8_t *vals, size_t size); + +/** + * @brief Outputs a full successful int32 array turo result. + * + * This includes all opening and closing of turo elements. + * + * @pre turo ctx initialized + * + * @param[in] ctx The implementation specific turo context. + * @param[in] vals The buffer of the integers. + * @param[in] size Number of elements in the array. + */ +void turo_simple_array_s32(turo_t *ctx, int32_t *vals, size_t size); + +/** + * @brief Outputs a full successful dict with string turo result. + * + * This includes all opening and closing of turo elements. + * + * @pre turo ctx initialized + * + * @param[in] ctx The implementation specific turo context. + * @param[in] key The dictionary key. + * @param[in] val The string value. + */ +void turo_simple_dict_string(turo_t *ctx, const char *key, const char *val); + +/** + * @brief Outputs a full successful dict with an integer turo result. + * + * This includes all opening and closing of turo elements. + * + * @pre turo ctx initialized + * + * @param[in] ctx The implementation specific turo context. + * @param[in] key The dictionary key. + * @param[in] val The integer value. + */ +void turo_simple_dict_s32(turo_t *ctx, const char *key, int32_t val); + +/** + * @brief Outputs a full turo result with exit code. + * + * This includes all opening and closing of turo elements. + * + * @pre turo ctx initialized + * + * @param[in] ctx The implementation specific turo context. + * @param[in] exit_status The exit status to output. + */ +void turo_simple_exit_status(turo_t *ctx, int exit_status); +/** @} */ + +#ifdef __cplusplus +} +#endif +#endif /* TEST_UTILS_RESULT_OUTPUT_H */ +/** @} */ diff --git a/sys/test_utils/Makefile.dep b/sys/test_utils/Makefile.dep index 4bafa543b8a1..a3a16352661d 100644 --- a/sys/test_utils/Makefile.dep +++ b/sys/test_utils/Makefile.dep @@ -1,3 +1,6 @@ ifneq (,$(filter test_utils_interactive_sync,$(USEMODULE))) USEMODULE += stdin endif +ifneq (,$(filter test_utils_result_output_%,$(USEMODULE))) + USEMODULE += fmt +endif diff --git a/sys/test_utils/result_output/Makefile b/sys/test_utils/result_output/Makefile new file mode 100644 index 000000000000..d95e7fca9afe --- /dev/null +++ b/sys/test_utils/result_output/Makefile @@ -0,0 +1,15 @@ +MODULE = test_utils_result_output + +ifneq (,$(filter test_utils_result_output_json,$(USEMODULE))) + DIRS += json +endif + +ifneq (,$(filter test_utils_result_output_txt,$(USEMODULE))) + DIRS += txt +endif + +ifneq (,$(filter test_utils_result_output_check,$(USEMODULE))) + DIRS += check +endif + +include $(RIOTBASE)/Makefile.base diff --git a/sys/test_utils/result_output/Makefile.include b/sys/test_utils/result_output/Makefile.include new file mode 100644 index 000000000000..5b9ebd9a7a6e --- /dev/null +++ b/sys/test_utils/result_output/Makefile.include @@ -0,0 +1,9 @@ +ifneq (,$(filter test_utils_result_output_json,$(USEMODULE))) + INCLUDES += -I$(RIOTBASE)/sys/test_utils/result_output/json +endif +ifneq (,$(filter test_utils_result_output_txt,$(USEMODULE))) + INCLUDES += -I$(RIOTBASE)/sys/test_utils/result_output/txt +endif +ifneq (,$(filter test_utils_result_output_check,$(USEMODULE))) + INCLUDES += -I$(RIOTBASE)/sys/test_utils/result_output/check +endif diff --git a/sys/test_utils/result_output/result_output.c b/sys/test_utils/result_output/result_output.c new file mode 100644 index 000000000000..3aeb6727da76 --- /dev/null +++ b/sys/test_utils/result_output/result_output.c @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2021 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. + */ + +/** + * @ingroup sys + * @{ + * + * @file + * @brief Result output common implementation + * + * + * @author Kevin Weiss + * @} + */ + +#include +#include + +#include "test_utils/result_output.h" + +void __attribute__((weak)) turo_init(turo_t *ctx) +{ + (void)ctx; +} + +void turo_array_u8(turo_t *ctx, uint8_t *vals, size_t size) +{ + turo_array_open(ctx); + while (size > 0) { + turo_u32(ctx, (uint32_t)*vals); + vals++; + size--; + } + turo_array_close(ctx); +} + +void turo_array_s32(turo_t *ctx, int32_t *vals, size_t size) +{ + turo_array_open(ctx); + while (size-- > 0) { + turo_s32(ctx, *vals); + vals++; + } + turo_array_close(ctx); +} + +void turo_dict_string(turo_t *ctx, const char *key, const char *val) +{ + turo_dict_open(ctx); + turo_dict_key(ctx, key); + turo_string(ctx, val); + turo_dict_close(ctx); +} + +void turo_dict_s32(turo_t *ctx, const char *key, int32_t val) +{ + turo_dict_open(ctx); + turo_dict_key(ctx, key); + turo_s32(ctx, val); + turo_dict_close(ctx); +} + +void turo_simple_s32(turo_t *ctx, int32_t val) +{ + turo_container_open(ctx); + turo_s32(ctx, val); + turo_container_close(ctx, 0); +} + +void turo_simple_array_s32(turo_t *ctx, int32_t *vals, size_t size) +{ + turo_container_open(ctx); + turo_array_s32(ctx, vals, size); + turo_container_close(ctx, 0); +} + +void turo_simple_array_u8(turo_t *ctx, uint8_t *vals, size_t size) +{ + turo_container_open(ctx); + turo_array_u8(ctx, vals, size); + turo_container_close(ctx, 0); +} + +void turo_simple_dict_string(turo_t *ctx, const char *key, const char *val) +{ + turo_container_open(ctx); + turo_dict_open(ctx); + turo_dict_key(ctx, key); + turo_string(ctx, val); + turo_dict_close(ctx); + turo_container_close(ctx, 0); +} + +void turo_simple_dict_s32(turo_t *ctx, const char *key, int32_t val) +{ + turo_container_open(ctx); + turo_dict_open(ctx); + turo_dict_key(ctx, key); + turo_s32(ctx, val); + turo_dict_close(ctx); + turo_container_close(ctx, 0); +} + +void turo_simple_exit_status(turo_t *ctx, int exit_status) +{ + turo_container_open(ctx); + turo_container_close(ctx, exit_status); +} From 38884d24b2c971afcbd808b27e58a95534594925 Mon Sep 17 00:00:00 2001 From: MrKevinWeiss Date: Fri, 12 Mar 2021 16:21:22 +0100 Subject: [PATCH 5/8] sys/result_output: Add kconfig --- sys/test_utils/Kconfig | 1 + sys/test_utils/result_output/Kconfig | 44 ++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+) create mode 100644 sys/test_utils/result_output/Kconfig diff --git a/sys/test_utils/Kconfig b/sys/test_utils/Kconfig index 12f4fd6af3e3..8d37a0250c57 100644 --- a/sys/test_utils/Kconfig +++ b/sys/test_utils/Kconfig @@ -10,4 +10,5 @@ menu "Test utilities" rsource "dummy_thread/Kconfig" rsource "interactive_sync/Kconfig" +rsource "result_output/Kconfig" endmenu # Test utilities diff --git a/sys/test_utils/result_output/Kconfig b/sys/test_utils/result_output/Kconfig new file mode 100644 index 000000000000..2cfb0a0c055c --- /dev/null +++ b/sys/test_utils/result_output/Kconfig @@ -0,0 +1,44 @@ +# Copyright (c) 2021 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. +# + + +choice + bool "Test utils result output" + depends on TEST_KCONFIG + optional + default MODULE_TEST_UTILS_RESULT_OUTPUT_JSON + help + A common API that can format result output depending on the module + used. + +config MODULE_TEST_UTILS_RESULT_OUTPUT_TXT + bool "Text" + select MODULE_FMT + select MODULE_TEST_UTILS_RESULT_OUTPUT + help + Output results in plain text. Intended for developer friendly console + output. + +config MODULE_TEST_UTILS_RESULT_OUTPUT_JSON + bool "JSON" + select MODULE_FMT + select MODULE_TEST_UTILS_RESULT_OUTPUT + help + Output results json formatted results. This allows generic json parsers + to be used. Trailing commas may be present. + +config MODULE_TEST_UTILS_RESULT_OUTPUT_CHECK + bool "Check" + select MODULE_TEST_UTILS_RESULT_OUTPUT + help + Asserts that the structure of the result output are correct. No output + is given. + +endchoice + +config MODULE_TEST_UTILS_RESULT_OUTPUT + bool From e9b65306eaf29ef357fb3b2b62d68ec4502d51fc Mon Sep 17 00:00:00 2001 From: MrKevinWeiss Date: Fri, 12 Mar 2021 16:22:24 +0100 Subject: [PATCH 6/8] tests/unittests/turo: Add turo unittest --- tests/unittests/tests-turo/Makefile | 4 + tests/unittests/tests-turo/Makefile.include | 1 + tests/unittests/tests-turo/tests-turo.c | 86 +++++++++++++++++++++ 3 files changed, 91 insertions(+) create mode 100644 tests/unittests/tests-turo/Makefile create mode 100644 tests/unittests/tests-turo/Makefile.include create mode 100644 tests/unittests/tests-turo/tests-turo.c diff --git a/tests/unittests/tests-turo/Makefile b/tests/unittests/tests-turo/Makefile new file mode 100644 index 000000000000..5239a5481732 --- /dev/null +++ b/tests/unittests/tests-turo/Makefile @@ -0,0 +1,4 @@ +# Since the asserts are a part of the check we need to enable them. +DEVELHELP=1 + +include $(RIOTBASE)/Makefile.base diff --git a/tests/unittests/tests-turo/Makefile.include b/tests/unittests/tests-turo/Makefile.include new file mode 100644 index 000000000000..d4fc5b7086d6 --- /dev/null +++ b/tests/unittests/tests-turo/Makefile.include @@ -0,0 +1 @@ +USEMODULE += test_utils_result_output_check diff --git a/tests/unittests/tests-turo/tests-turo.c b/tests/unittests/tests-turo/tests-turo.c new file mode 100644 index 000000000000..3089de8b31d7 --- /dev/null +++ b/tests/unittests/tests-turo/tests-turo.c @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2021 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. + */ +/** + * @ingroup tests + * @{ + * + * @file + * @brief Unit tests for test_utils_result_output module + * + * @author Kevin Weiss + */ +#include "embUnit.h" +#include "kernel_defines.h" +#include "test_utils/result_output.h" + +void test_turo_impl(void) +{ + turo_t ctx; + turo_init(&ctx); + turo_container_open(&ctx); + turo_s32(&ctx, -1); + turo_u32(&ctx, 0xFFFFFFFF); + turo_s64(&ctx, -1); + turo_u64(&ctx, 0xFFFFFFFFFFFFFFFF); + turo_float(&ctx, 0.00001); + turo_string(&ctx, "foo"); + turo_bool(&ctx, true); + turo_dict_open(&ctx); + turo_dict_key(&ctx, "bar"); + turo_u32(&ctx, 0); + turo_dict_close(&ctx); + turo_array_open(&ctx); + turo_u32(&ctx, 0); + turo_array_close(&ctx); + turo_container_close(&ctx, 0); +} + +void test_turo_helpers(void) +{ + turo_t ctx; + turo_init(&ctx); + turo_container_open(&ctx); + uint8_t buf8[] = {1, 2, 3}; + int32_t buf32[] = {-1, 1, 0x7FFFFFFF}; + turo_array_u8(&ctx, buf8, sizeof(buf8)); + turo_array_s32(&ctx, buf32, ARRAY_SIZE(buf32)); + turo_dict_string(&ctx, "foo", "bar"); + turo_dict_s32(&ctx, "baz", 42); + turo_container_close(&ctx, 0); +} + +void test_turo_simple(void) +{ + turo_t ctx; + turo_init(&ctx); + turo_simple_s32(&ctx, 42); + uint8_t buf8[] = {1, 2, 3}; + int32_t buf32[] = {-1, 1, 0x7FFFFFFF}; + turo_simple_array_u8(&ctx, buf8, sizeof(buf8)); + turo_simple_array_s32(&ctx, buf32, ARRAY_SIZE(buf32)); + turo_simple_dict_string(&ctx, "foo", "bar"); + turo_simple_dict_s32(&ctx, "baz", 42); + turo_simple_exit_status(&ctx, -1); +} + +Test *tests_turo_all(void) +{ + EMB_UNIT_TESTFIXTURES(fixtures) { + new_TestFixture(test_turo_impl), + new_TestFixture(test_turo_helpers), + new_TestFixture(test_turo_simple), + }; + + EMB_UNIT_TESTCALLER(turo_tests, NULL, NULL, fixtures); + return (Test *)&turo_tests; +} + +void tests_turo(void) +{ + TESTS_RUN(tests_turo_all()); +} From e7cc489b14d6e5598bb5cd9920e63d2dd338d976 Mon Sep 17 00:00:00 2001 From: MrKevinWeiss Date: Fri, 12 Mar 2021 16:22:55 +0100 Subject: [PATCH 7/8] tests/turo: Add automated turo test for json --- tests/turo/Makefile | 15 ++ tests/turo/README.md | 14 ++ tests/turo/app.config.test | 3 + tests/turo/main.c | 292 +++++++++++++++++++++++++++++++++++++ tests/turo/tests/01-run.py | 151 +++++++++++++++++++ 5 files changed, 475 insertions(+) create mode 100644 tests/turo/Makefile create mode 100644 tests/turo/README.md create mode 100644 tests/turo/app.config.test create mode 100644 tests/turo/main.c create mode 100755 tests/turo/tests/01-run.py diff --git a/tests/turo/Makefile b/tests/turo/Makefile new file mode 100644 index 000000000000..fda977aa8e49 --- /dev/null +++ b/tests/turo/Makefile @@ -0,0 +1,15 @@ +include ../Makefile.tests_common + +OUTPUT_FORMAT ?= json +USEMODULE += test_utils_result_output_${OUTPUT_FORMAT} +USEMODULE += shell +USEMODULE += fmt + +# Use a terminal that does not introduce extra characters into the stream. +RIOT_TERMINAL ?= socat + +ifndef CONFIG_SHELL_NO_ECHO + CFLAGS += -DCONFIG_SHELL_NO_ECHO=1 +endif + +include $(RIOTBASE)/Makefile.include diff --git a/tests/turo/README.md b/tests/turo/README.md new file mode 100644 index 000000000000..620957881f2b --- /dev/null +++ b/tests/turo/README.md @@ -0,0 +1,14 @@ +# TURO (Test Utils Result Output) Test + +This shows a non-trival example of how to use the TURO module as a +testing abstraction layer. + +The test is written with only TURO commands allowing the underling output to +be changed as needed depending on the interpreter. This means that the test +will not need to be changed if output is changed. If the test results are +output as json and the binary is too large, the TURO can be switched to CBOR +to save space. The interpreter should also switch to a CBOR parser and the +test should not need to be changed. + +This should keep tests more stable, which is particularly useful for automated +tests. \ No newline at end of file diff --git a/tests/turo/app.config.test b/tests/turo/app.config.test new file mode 100644 index 000000000000..f6e90bee6dc2 --- /dev/null +++ b/tests/turo/app.config.test @@ -0,0 +1,3 @@ +CONFIG_MODULE_FMT=y +CONFIG_MODULE_SHELL=y +CONFIG_MODULE_TEST_UTILS_RESULT_OUTPUT_JSON=y diff --git a/tests/turo/main.c b/tests/turo/main.c new file mode 100644 index 000000000000..f0c53acd44a7 --- /dev/null +++ b/tests/turo/main.c @@ -0,0 +1,292 @@ +/* + * Copyright (C) 2021 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. + */ + +/** + * @ingroup tests + * @{ + * + * @file + * @brief Test Utils Result Output test application + * + * @author Kevin Weiss + * + * @} + */ + +#include +#include +#include +#include +#include + +#include "kernel_defines.h" +#include "test_utils/result_output.h" +#include "shell.h" + +#define _BUF_COUNT 4 + +turo_t ctx; + +static int _sc_arg2long(const char *arg, long *val) +{ + errno = 0; + char *end; + long res = strtol(arg, &end, 0); + + if ((*end != '\0') || ((res == LONG_MIN || res == LONG_MAX) && errno == ERANGE)) { + return -1; + } + *val = res; + return 0; +} + +/* We need to disable warning since long can mean different things */ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wtype-limits" +static int _sc_arg2s32(const char *arg, int32_t *val) +{ + long lval; + int res = _sc_arg2long(arg, &lval); + + if (res == 0) { + if (lval <= 2147483647 && lval >= -2147483648) { + *val = (int32_t)lval; + } + else { + res = -1; + } + + } + return res; +} +#pragma GCC diagnostic pop + +static int _sc_arg2u8(const char *arg, uint8_t *val) +{ + long lval; + int res = _sc_arg2long(arg, &lval); + if (res == 0) { + if (lval <= 255 && lval >= 0) { + *val = (uint8_t)lval; + } + else { + res = -1; + } + } + return res; +} + +static void _netif_list(turo_t *ctx, int32_t netif_num) +{ + uint8_t buf8[] = { 1, 2, 3, 4, 5, 6, 7, 8 }; + + turo_dict_open(ctx); + turo_dict_key(ctx, "netif"); + turo_dict_open(ctx); + + turo_dict_key(ctx, "num"); + turo_s32(ctx, netif_num); + + turo_dict_key(ctx, "HWaddr"); + turo_array_u8(ctx, buf8, ARRAY_SIZE(buf8)); + + turo_dict_key(ctx, "inet6 addr"); + turo_dict_open(ctx); + turo_dict_key(ctx, "addr"); + turo_string(ctx, "fe80::2445:7fff:fe5a:6fd9"); + turo_dict_key(ctx, "scope"); + turo_string(ctx, "link"); + turo_dict_key(ctx, "flags"); + turo_array_open(ctx); + turo_string(ctx, "VAL"); + turo_array_close(ctx); + turo_dict_close(ctx); + + turo_dict_key(ctx, "inet6 group"); + turo_array_open(ctx); + turo_string(ctx, "ff02::2"); + turo_string(ctx, "ff02::1"); + turo_string(ctx, "ff02::1:ff5a:6fd9"); + turo_array_close(ctx); + + turo_dict_key(ctx, "flags"); + turo_array_open(ctx); + turo_dict_s32(ctx, "L2-PDU", 1500); + turo_dict_s32(ctx, "MTU", 1500); + turo_dict_s32(ctx, "HL", 64); + turo_string(ctx, "RTR"); + turo_string(ctx, "RTR_ADV"); + turo_dict_s32(ctx, "Source address length", 6); + turo_array_close(ctx); + + turo_dict_close(ctx); + turo_dict_close(ctx); +} + + +static int cmd_turo_simple_s32(int argc, char **argv) +{ + int32_t s32 = 0; + if (argc != 2) { + turo_simple_exit_status(&ctx, -2); + return 1; + } + if (_sc_arg2s32(argv[1], &s32) != 0) { + turo_simple_exit_status(&ctx, -3); + return 1; + } + + turo_simple_s32(&ctx, s32); + return 0; +} + +static int cmd_turo_simple_array_u8(int argc, char **argv) +{ + uint8_t buf8[_BUF_COUNT]; + if (argc == 1) { + turo_simple_exit_status(&ctx, -4); + return 1; + } + if (argc > _BUF_COUNT + 1) { + turo_simple_exit_status(&ctx, -5); + return 1; + } + + for (int i = 0; i < argc - 1; i++) { + if (_sc_arg2u8(argv[i + 1], &buf8[i]) != 0) { + turo_simple_exit_status(&ctx, -6); + return 1; + } + } + + turo_simple_array_u8(&ctx, buf8, argc - 1); + return 0; +} + +static int cmd_turo_simple_array_s32(int argc, char **argv) +{ + int32_t buf32[_BUF_COUNT]; + if (argc == 1) { + turo_simple_exit_status(&ctx, -7); + return 1; + } + if (argc > _BUF_COUNT + 1) { + turo_simple_exit_status(&ctx, -8); + return 1; + } + + for (int i = 0; i < argc - 1; i++) { + if (_sc_arg2s32(argv[i + 1], &buf32[i]) != 0) { + turo_simple_exit_status(&ctx, -9); + return 1; + } + } + + turo_simple_array_s32(&ctx, buf32, argc - 1); + return 0; +} + +static int cmd_turo_simple_dict_string(int argc, char **argv) +{ + if (argc != 3) { + turo_simple_exit_status(&ctx, -10); + return 1; + } + + turo_simple_dict_string(&ctx, argv[1], argv[2]); + return 0; +} + +static int cmd_turo_simple_dict_s32(int argc, char **argv) +{ + int32_t s32 = 0; + if (argc != 3) { + turo_simple_exit_status(&ctx, -11); + return 1; + } + + if (_sc_arg2s32(argv[2], &s32) != 0) { + turo_simple_exit_status(&ctx, -12); + return 1; + } + + turo_simple_dict_s32(&ctx, argv[1], s32); + return 0; +} + +static int cmd_turo_simple_exit_status(int argc, char **argv) +{ + int32_t s32 = 0; + if (argc != 2) { + turo_simple_exit_status(&ctx, -13); + return 1; + } + + if (_sc_arg2s32(argv[1], &s32) != 0) { + turo_simple_exit_status(&ctx, -14); + return 1; + } + + turo_simple_exit_status(&ctx, (int)s32); + return 0; +} + +static int cmd_test_multi_element_dict(int argc, char **argv) +{ + if (argc != 5) { + turo_simple_exit_status(&ctx, -15); + return 1; + } + + turo_container_open(&ctx); + turo_dict_open(&ctx); + turo_dict_key(&ctx, argv[1]); + turo_string(&ctx, argv[2]); + turo_dict_key(&ctx, argv[3]); + turo_string(&ctx, argv[4]); + turo_dict_close(&ctx); + turo_container_close(&ctx, 0); + + return 0; +} + +static int cmd_test_netif(int argc, char **argv) +{ + (void) argc; + (void) argv; + + turo_container_open(&ctx); + _netif_list(&ctx, 5); + _netif_list(&ctx, 6); + turo_container_close(&ctx, 0); + + return 0; +} + +static const shell_command_t shell_commands[] = { + { "turo_simple_s32", "", cmd_turo_simple_s32 }, + { "turo_simple_array_u8", "", cmd_turo_simple_array_u8 }, + { "turo_simple_array_s32", "", cmd_turo_simple_array_s32 }, + { "turo_simple_dict_string", "", cmd_turo_simple_dict_string }, + { "turo_simple_dict_s32", "", cmd_turo_simple_dict_s32 }, + { "turo_simple_exit_status", "", cmd_turo_simple_exit_status }, + { "test_multi_element_dict", "", cmd_test_multi_element_dict }, + { "test_netif", "", cmd_test_netif }, + { NULL, NULL, NULL } +}; + +int main(void) +{ + char line_buf[SHELL_DEFAULT_BUFSIZE]; + puts("Test for the test utilities result output"); + turo_init(&ctx); + + shell_run(shell_commands, line_buf, SHELL_DEFAULT_BUFSIZE); + + return 0; +} diff --git a/tests/turo/tests/01-run.py b/tests/turo/tests/01-run.py new file mode 100755 index 000000000000..1476f58570c8 --- /dev/null +++ b/tests/turo/tests/01-run.py @@ -0,0 +1,151 @@ +#! /usr/bin/env python3 + +# Copyright (C) 2021 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. + +import logging +import sys +import unittest + +from riotctrl.ctrl import RIOTCtrl +from riotctrl.shell import ShellInteraction +from riotctrl.shell.json import RapidJSONShellInteractionParser + + +class TestTuroBase(unittest.TestCase): + DEBUG = False + + @classmethod + def setUpClass(cls): + cls.ctrl = RIOTCtrl() + cls.ctrl.start_term() + if cls.DEBUG: + cls.ctrl.term.logfile = sys.stdout + cls.ctrl.reset() + cls.shell = ShellInteraction(cls.ctrl) + cls.json_parser = RapidJSONShellInteractionParser() + cls.logger = logging.getLogger(cls.__name__) + if cls.DEBUG: + cls.logger.setLevel(logging.DEBUG) + + @classmethod + def tearDownClass(cls): + cls.ctrl.stop_term() + + def exec_turo_cmd(self, cmd, timeout=-1, async_=False): + resp = self.shell.cmd(cmd, timeout, async_) + self.logger.debug(repr(resp)) + return self._parse(resp) + + def _parse(self, resp): + resp = self.json_parser.parse(resp) + if resp[-1]['exit_status'] != 0: + raise RuntimeError("{}".format(resp[-1])) + if len(resp) == 1: + return None + elif len(resp) == 2: + return resp[0] + return resp[:-1] + + +class TestTuro(TestTuroBase): + def test_turo_simple_s32(self): + vals = [0, -1, -2147483648, 2147483647] + for val in vals: + resp = self.exec_turo_cmd('turo_simple_s32 ' + '{}'.format(val)) + assert resp == val + + def test_turo_simple_s32_fail(self): + vals = ["foo", -2147483649, 2147483648] + for val in vals: + with self.assertRaises(RuntimeError): + self.exec_turo_cmd('turo_simple_s32 ' + '{}'.format(val)) + + def test_turo_simple_array_u8(self): + vals = [255, 0, 1] + cmd = 'turo_simple_array_u8 ' + ' '.join(map(str, vals)) + resp = self.exec_turo_cmd(cmd) + self.assertCountEqual(resp, vals) + + def test_turo_simple_array_u8_fail(self): + vals = ["foo", -1, 256] + for val in vals: + with self.assertRaises(RuntimeError): + self.exec_turo_cmd('turo_simple_array_u8 ' + '{}'.format(val)) + + def test_turo_simple_array_s32(self): + vals = [0, -1, -2147483648, 2147483647] + cmd = 'turo_simple_array_s32 ' + ' '.join(map(str, vals)) + resp = self.exec_turo_cmd(cmd) + self.assertCountEqual(resp, vals) + + def test_turo_simple_array_s32_fail(self): + vals = ["foo", -2147483649, 2147483648] + for val in vals: + with self.assertRaises(RuntimeError): + self.exec_turo_cmd('turo_simple_array_s32 ' + '{}'.format(val)) + + def test_turo_simple_dict_string(self): + test_dict = {'foo': 'bar', 'strnum': '42'} + for key, val in test_dict.items(): + cmd = 'turo_simple_dict_string {} {}'.format(key, val) + resp = self.exec_turo_cmd(cmd) + assert resp[key] == val + + def test_turo_simple_dict_string_fail(self): + pass + + def test_turo_simple_dict_s32(self): + test_dict = {'foo': -1, 'bar': 2147483647} + for key, val in test_dict.items(): + cmd = 'turo_simple_dict_s32 {} {}'.format(key, val) + resp = self.exec_turo_cmd(cmd) + assert resp[key] == val + + def test_turo_simple_dict_s32_fail(self): + with self.assertRaises(RuntimeError): + self.exec_turo_cmd('turo_simple_dict_s32 foo bar') + + def test_turo_simple_exit_status(self): + self.exec_turo_cmd('turo_simple_exit_status 0') + with self.assertRaises(RuntimeError): + self.exec_turo_cmd('turo_simple_exit_status -1') + + def test_test_multi_element_dict(self): + test_dict = {'foo': 'bar', 'strnum': '42'} + cmd = 'test_multi_element_dict' + for key, val in test_dict.items(): + cmd += ' {} {}'.format(key, val) + + resp = self.exec_turo_cmd(cmd) + self.assertDictEqual(resp, test_dict) + + def test_test_netif(self): + resp = self.exec_turo_cmd("test_netif") + + assert resp[1]['netif']['num'] == 6 + assert resp[0]['netif']['num'] == 5 + addr = resp[0]['netif']['inet6 addr']['addr'] + assert addr == 'fe80::2445:7fff:fe5a:6fd9' + scope = resp[0]['netif']['inet6 addr']['scope'] + assert scope == 'link' + + flags = resp[0]['netif']['flags'] + for flag in flags: + if isinstance(flag, dict): + if "MTU" in flag.keys(): + assert flag['MTU'] == 1500 + break + else: + assert False, "MTU flag does not exist" + + +if __name__ == '__main__': + unittest.main() From 2e5ff003863fb179cef53fc0c1697db6a32dd18f Mon Sep 17 00:00:00 2001 From: MrKevinWeiss Date: Fri, 12 Mar 2021 16:23:34 +0100 Subject: [PATCH 8/8] dist/tools/uncrustify: Add turo module --- dist/tools/uncrustify/whitelist.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/dist/tools/uncrustify/whitelist.txt b/dist/tools/uncrustify/whitelist.txt index aa2d38730919..d8f8fcb32e4b 100644 --- a/dist/tools/uncrustify/whitelist.txt +++ b/dist/tools/uncrustify/whitelist.txt @@ -10,5 +10,9 @@ sys/riotboot/.*\.h sys/riotboot/.*\.c sys/congure.*\.c sys/include/congure.*\.h +sys/test_utils/result_output/.*\c +sys/test_utils/result_output/*/.*\c +sys/test_utils/result_output/*/.*\h +sys/test_utils/include/result_output.h sys/ztimer/.*\.c sys/include/ztimer.*\.h