1
0
mirror of https://github.com/esp8266/Arduino.git synced 2025-07-29 05:21:37 +03:00

add support for environment variables in device tests

Previously device tests included information such as access point SSID/password at compile time. This made it difficult to compile test binaries once and then send them to multiple test runners for execution.

This change adds a command to the test library to set environment variable on the target device: “setenv key value”. C library setenv/getenv facility is used to store variables.

Test runner, tests, and makefile are updated to use this functionality.
This commit is contained in:
Ivan Grokhotkov
2018-04-10 16:27:19 +08:00
committed by Ivan Grokhotkov
parent 2315ac20bc
commit 8bd26f2ded
21 changed files with 306 additions and 78 deletions

View File

@ -35,11 +35,27 @@ public:
return len;
}
bool read_int(int& result)
size_t read_line(char* dest, size_t dest_size)
{
// TODO: fix this for 0 value
result = m_stream.parseInt();
return result != 0;
size_t len = 0;
// Can't use Stream::readBytesUntil here because it can't tell the
// difference between timing out and receiving the terminator.
while (len < dest_size - 1) {
int c = m_stream.read();
if (c < 0) {
delay(1);
continue;
}
if (c == '\r') {
continue;
}
if (c == '\n') {
dest[len] = 0;
break;
}
dest[len++] = c;
}
return len;
}
protected:

View File

@ -0,0 +1,151 @@
/* Splitting string into tokens, taking quotes and escape sequences into account.
* From https://github.com/espressif/esp-idf/blob/master/components/console/split_argv.c
* Copyright 2016-2017 Espressif Systems (Shanghai) PTE LTD
* Licensed under the Apache License 2.0.
*/
#ifndef BS_ARGS_H
#define BS_ARGS_H
#include <stdio.h>
#include <ctype.h>
#include <string.h>
namespace bs
{
namespace protocol
{
#define SS_FLAG_ESCAPE 0x8
typedef enum {
/* parsing the space between arguments */
SS_SPACE = 0x0,
/* parsing an argument which isn't quoted */
SS_ARG = 0x1,
/* parsing a quoted argument */
SS_QUOTED_ARG = 0x2,
/* parsing an escape sequence within unquoted argument */
SS_ARG_ESCAPED = SS_ARG | SS_FLAG_ESCAPE,
/* parsing an escape sequence within a quoted argument */
SS_QUOTED_ARG_ESCAPED = SS_QUOTED_ARG | SS_FLAG_ESCAPE,
} split_state_t;
/* helper macro, called when done with an argument */
#define END_ARG() do { \
char_out = 0; \
argv[argc++] = next_arg_start; \
state = SS_SPACE; \
} while(0);
/**
* @brief Split command line into arguments in place
*
* - This function finds whitespace-separated arguments in the given input line.
*
* 'abc def 1 20 .3' -> [ 'abc', 'def', '1', '20', '.3' ]
*
* - Argument which include spaces may be surrounded with quotes. In this case
* spaces are preserved and quotes are stripped.
*
* 'abc "123 456" def' -> [ 'abc', '123 456', 'def' ]
*
* - Escape sequences may be used to produce backslash, double quote, and space:
*
* 'a\ b\\c\"' -> [ 'a b\c"' ]
*
* Pointers to at most argv_size - 1 arguments are returned in argv array.
* The pointer after the last one (i.e. argv[argc]) is set to NULL.
*
* @param line pointer to buffer to parse; it is modified in place
* @param argv array where the pointers to arguments are written
* @param argv_size number of elements in argv_array (max. number of arguments will be argv_size - 1)
* @return number of arguments found (argc)
*/
inline size_t split_args(char *line, char **argv, size_t argv_size)
{
const int QUOTE = '"';
const int ESCAPE = '\\';
const int SPACE = ' ';
split_state_t state = SS_SPACE;
int argc = 0;
char *next_arg_start = line;
char *out_ptr = line;
for (char *in_ptr = line; argc < argv_size - 1; ++in_ptr) {
int char_in = (unsigned char) *in_ptr;
if (char_in == 0) {
break;
}
int char_out = -1;
switch (state) {
case SS_SPACE:
if (char_in == SPACE) {
/* skip space */
} else if (char_in == QUOTE) {
next_arg_start = out_ptr;
state = SS_QUOTED_ARG;
} else if (char_in == ESCAPE) {
next_arg_start = out_ptr;
state = SS_ARG_ESCAPED;
} else {
next_arg_start = out_ptr;
state = SS_ARG;
char_out = char_in;
}
break;
case SS_QUOTED_ARG:
if (char_in == QUOTE) {
END_ARG();
} else if (char_in == ESCAPE) {
state = SS_QUOTED_ARG_ESCAPED;
} else {
char_out = char_in;
}
break;
case SS_ARG_ESCAPED:
case SS_QUOTED_ARG_ESCAPED:
if (char_in == ESCAPE || char_in == QUOTE || char_in == SPACE) {
char_out = char_in;
} else {
/* unrecognized escape character, skip */
}
state = (split_state_t) (state & (~SS_FLAG_ESCAPE));
break;
case SS_ARG:
if (char_in == SPACE) {
END_ARG();
} else if (char_in == ESCAPE) {
state = SS_ARG_ESCAPED;
} else {
char_out = char_in;
}
break;
}
/* need to output anything? */
if (char_out >= 0) {
*out_ptr = char_out;
++out_ptr;
}
}
/* make sure the final argument is terminated */
*out_ptr = 0;
/* finalize the last argument */
if (state != SS_SPACE && argc < argv_size - 1) {
argv[argc++] = next_arg_start;
}
/* add a NULL at the end of argv */
argv[argc] = NULL;
return argc;
}
} // namespace bs
} // namespace protocol
#endif //BS_ARGS_H

View File

@ -1,6 +1,8 @@
#ifndef BS_PROTOCOL_H
#define BS_PROTOCOL_H
#include "BSArgs.h"
#define BS_LINE_PREFIX ">>>>>bs_test_"
namespace bs
@ -44,9 +46,38 @@ void output_menu_end(IO& io)
}
template<typename IO>
bool input_menu_choice(IO& io, int& result)
void output_setenv_result(IO& io, const char* key, const char* value)
{
return io.read_int(result);
io.printf(BS_LINE_PREFIX "setenv ok key='%s' value='%s'\n", key, value);
}
template<typename IO>
bool input_handle(IO& io, char* line_buf, size_t line_buf_size, int& test_num)
{
int cb_read = io.read_line(line_buf, line_buf_size);
if (cb_read == 0 || line_buf[0] == '\n') {
return false;
}
char* argv[4];
size_t argc = split_args(line_buf, argv, sizeof(argv)/sizeof(argv[0]));
if (argc == 0) {
return false;
}
if (strcmp(argv[0], "setenv") == 0) {
if (argc != 3) {
return false;
}
setenv(argv[1], argv[2], 1);
output_setenv_result(io, argv[1], argv[2]);
test_num = -1;
return false; /* we didn't get the test number yet, so return false */
}
char* endptr;
test_num = (int) strtol(argv[0], &endptr, 10);
if (endptr != argv[0] + strlen(argv[0])) {
return false;
}
return true;
}
} // ::protocol

View File

@ -22,9 +22,18 @@ public:
return result;
}
bool read_int(int& result)
size_t read_line(char* dest, size_t dest_size)
{
return scanf("%d", &result) == 1;
char* res = fgets(dest, dest_size, stdin);
if (res == NULL) {
return 0;
}
size_t len = strlen(dest);
if (dest[len - 1] == '\n') {
dest[len - 1] = 0;
len--;
}
return len;
}
};

View File

@ -14,6 +14,10 @@
#include "BSStdio.h"
#endif
#ifndef BS_LINE_BUF_SIZE
#define BS_LINE_BUF_SIZE 80
#endif
namespace bs
{
typedef void(*test_case_func_t)();
@ -143,7 +147,8 @@ protected:
protocol::output_menu_end(m_io);
while(true) {
int id;
if (!protocol::input_menu_choice(m_io, id)) {
char line_buf[BS_LINE_BUF_SIZE];
if (!protocol::input_handle(m_io, line_buf, sizeof(line_buf), id)) {
continue;
}
if (id < 0) {
@ -214,4 +219,5 @@ inline void require(bool condition, size_t line)
#define BS_ENV_DECLARE() namespace bs { Env g_env; }
#define BS_RUN(...) do { bs::IOHelper helper = bs::IOHelper(__VA_ARGS__); bs::Runner<bs::IOHelper> runner(helper); runner.run(); } while(0);
#endif //BSTEST_H