mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
Merge pull request #15950 from MrKevinWeiss/pr/turo/initial
sys/test_utils/result_output: Initial implementations and API of turo
This commit is contained in:
commit
fd36c626a3
4
dist/tools/uncrustify/whitelist.txt
vendored
4
dist/tools/uncrustify/whitelist.txt
vendored
@ -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
|
||||
|
@ -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
|
||||
|
@ -1083,6 +1083,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
|
||||
|
@ -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)))
|
||||
|
357
sys/include/test_utils/result_output.h
Normal file
357
sys/include/test_utils/result_output.h
Normal file
@ -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 <kevin.weiss@haw-hamburg.de>
|
||||
*/
|
||||
|
||||
#ifndef TEST_UTILS_RESULT_OUTPUT_H
|
||||
#define TEST_UTILS_RESULT_OUTPUT_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#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 */
|
||||
/** @} */
|
@ -10,4 +10,5 @@ menu "Test utilities"
|
||||
|
||||
rsource "dummy_thread/Kconfig"
|
||||
rsource "interactive_sync/Kconfig"
|
||||
rsource "result_output/Kconfig"
|
||||
endmenu # Test utilities
|
||||
|
@ -1,3 +1,6 @@
|
||||
ifneq (,$(filter test_utils_interactive_sync,$(USEMODULE)))
|
||||
USEMODULE += stdin
|
||||
endif
|
||||
ifneq (,$(filter test_utils_result_output_%,$(USEMODULE)))
|
||||
USEMODULE += fmt
|
||||
endif
|
||||
|
44
sys/test_utils/result_output/Kconfig
Normal file
44
sys/test_utils/result_output/Kconfig
Normal file
@ -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
|
15
sys/test_utils/result_output/Makefile
Normal file
15
sys/test_utils/result_output/Makefile
Normal file
@ -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
|
9
sys/test_utils/result_output/Makefile.include
Normal file
9
sys/test_utils/result_output/Makefile.include
Normal file
@ -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
|
3
sys/test_utils/result_output/check/Makefile
Normal file
3
sys/test_utils/result_output/check/Makefile
Normal file
@ -0,0 +1,3 @@
|
||||
MODULE = test_utils_result_output_check
|
||||
|
||||
include $(RIOTBASE)/Makefile.base
|
13
sys/test_utils/result_output/check/doc.txt
Normal file
13
sys/test_utils/result_output/check/doc.txt
Normal file
@ -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 <kevin.weiss@haw-hamburg.de>
|
||||
* @}
|
||||
*/
|
126
sys/test_utils/result_output/check/result_output_check.c
Normal file
126
sys/test_utils/result_output/check/result_output_check.c
Normal file
@ -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 <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <assert.h>
|
||||
|
||||
#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--;
|
||||
}
|
45
sys/test_utils/result_output/check/result_output_types.h
Normal file
45
sys/test_utils/result_output/check/result_output_types.h
Normal file
@ -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 */
|
3
sys/test_utils/result_output/json/Makefile
Normal file
3
sys/test_utils/result_output/json/Makefile
Normal file
@ -0,0 +1,3 @@
|
||||
MODULE = test_utils_result_output_json
|
||||
|
||||
include $(RIOTBASE)/Makefile.base
|
13
sys/test_utils/result_output/json/doc.txt
Normal file
13
sys/test_utils/result_output/json/doc.txt
Normal file
@ -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 <kevin.weiss@haw-hamburg.de>
|
||||
* @}
|
||||
*/
|
122
sys/test_utils/result_output/json/result_output_json.c
Normal file
122
sys/test_utils/result_output/json/result_output_json.c
Normal file
@ -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 <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#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");
|
||||
}
|
37
sys/test_utils/result_output/json/result_output_types.h
Normal file
37
sys/test_utils/result_output/json/result_output_types.h
Normal file
@ -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 */
|
113
sys/test_utils/result_output/result_output.c
Normal file
113
sys/test_utils/result_output/result_output.c
Normal file
@ -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 <kevin.weiss@haw-hamburg.de>
|
||||
* @}
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#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);
|
||||
}
|
3
sys/test_utils/result_output/txt/Makefile
Normal file
3
sys/test_utils/result_output/txt/Makefile
Normal file
@ -0,0 +1,3 @@
|
||||
MODULE = test_utils_result_output_txt
|
||||
|
||||
include $(RIOTBASE)/Makefile.base
|
13
sys/test_utils/result_output/txt/doc.txt
Normal file
13
sys/test_utils/result_output/txt/doc.txt
Normal file
@ -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 <kevin.weiss@haw-hamburg.de>
|
||||
* @}
|
||||
*/
|
115
sys/test_utils/result_output/txt/result_output_txt.c
Normal file
115
sys/test_utils/result_output/txt/result_output_txt.c
Normal file
@ -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 <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#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");
|
||||
}
|
||||
}
|
27
sys/test_utils/result_output/txt/result_output_types.h
Normal file
27
sys/test_utils/result_output/txt/result_output_types.h
Normal file
@ -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 */
|
15
tests/turo/Makefile
Normal file
15
tests/turo/Makefile
Normal file
@ -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
|
14
tests/turo/README.md
Normal file
14
tests/turo/README.md
Normal file
@ -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.
|
3
tests/turo/app.config.test
Normal file
3
tests/turo/app.config.test
Normal file
@ -0,0 +1,3 @@
|
||||
CONFIG_MODULE_FMT=y
|
||||
CONFIG_MODULE_SHELL=y
|
||||
CONFIG_MODULE_TEST_UTILS_RESULT_OUTPUT_JSON=y
|
292
tests/turo/main.c
Normal file
292
tests/turo/main.c
Normal file
@ -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 <kevin.weiss@haw-hamburg.de>
|
||||
*
|
||||
* @}
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <limits.h>
|
||||
#include <errno.h>
|
||||
|
||||
#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;
|
||||
}
|
151
tests/turo/tests/01-run.py
Executable file
151
tests/turo/tests/01-run.py
Executable file
@ -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()
|
4
tests/unittests/tests-turo/Makefile
Normal file
4
tests/unittests/tests-turo/Makefile
Normal file
@ -0,0 +1,4 @@
|
||||
# Since the asserts are a part of the check we need to enable them.
|
||||
DEVELHELP=1
|
||||
|
||||
include $(RIOTBASE)/Makefile.base
|
1
tests/unittests/tests-turo/Makefile.include
Normal file
1
tests/unittests/tests-turo/Makefile.include
Normal file
@ -0,0 +1 @@
|
||||
USEMODULE += test_utils_result_output_check
|
86
tests/unittests/tests-turo/tests-turo.c
Normal file
86
tests/unittests/tests-turo/tests-turo.c
Normal file
@ -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 <kevin.weiss@haw-hamburg.de>
|
||||
*/
|
||||
#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());
|
||||
}
|
Loading…
Reference in New Issue
Block a user