From eaa2e370eb8fa12438d8445b2ded3f12ac9d36e8 Mon Sep 17 00:00:00 2001 From: Maxim Prokhorov Date: Thu, 13 Jan 2022 03:59:39 +0300 Subject: [PATCH] ci: use esp8266 mock framework Resolve the issue with the UnixHostDuino not really being compatible with the esp8266 Core String (...and the rest of the Core, as well) Port the CMakeLists.txt from the rpnlib and update it use FetchContent instead of either manually fetching dependencies or using PIO artifacts Caching is *expected* to work, but might need slight adjustments --- .github/workflows/push.yml | 11 +- ci_install.sh | 3 +- ci_script.sh | 11 +- code/espurna/tuya_dataframe.h | 10 +- code/test/lib/StreamString/StreamString.cpp | 60 ---- code/test/lib/StreamString/StreamString.h | 39 --- code/test/lib/test_arduino_compat.h | 5 - code/test/platformio.ini | 40 --- code/test/unit/CMakeLists.txt | 179 ++++++++++ code/test/unit/cache/README.txt | 1 + code/test/unit/src/ArduinoMainOverride.cpp | 325 ++++++++++++++++++ code/test/unit/{ => src}/basic/basic.cpp | 4 +- .../main.cpp => src/settings/settings.cpp} | 2 +- .../test/unit/{ => src}/terminal/terminal.cpp | 8 +- code/test/unit/{ => src}/tuya/tuya.cpp | 2 +- code/test/unit/src/unity_fixtures.c | 14 + code/test/unit/{ => src}/url/url.cpp | 8 +- 17 files changed, 545 insertions(+), 177 deletions(-) delete mode 100644 code/test/lib/StreamString/StreamString.cpp delete mode 100644 code/test/lib/StreamString/StreamString.h delete mode 100644 code/test/lib/test_arduino_compat.h delete mode 100644 code/test/platformio.ini create mode 100644 code/test/unit/CMakeLists.txt create mode 100644 code/test/unit/cache/README.txt create mode 100644 code/test/unit/src/ArduinoMainOverride.cpp rename code/test/unit/{ => src}/basic/basic.cpp (82%) rename code/test/unit/{settings/main.cpp => src/settings/settings.cpp} (99%) rename code/test/unit/{ => src}/terminal/terminal.cpp (98%) rename code/test/unit/{ => src}/tuya/tuya.cpp (99%) create mode 100644 code/test/unit/src/unity_fixtures.c rename code/test/unit/{ => src}/url/url.cpp (86%) diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml index e917ca55..e64d6750 100644 --- a/.github/workflows/push.yml +++ b/.github/workflows/push.yml @@ -17,16 +17,11 @@ jobs: - uses: actions/setup-python@v2 with: python-version: '3.x' - - name: Cache pip + - name: Cache CMake uses: actions/cache@v2 with: - path: ~/.cache/pip - key: ${{ runner.os }}-pip-${{ hashFiles('ci_install.sh') }} - - name: Cache PlatformIO - uses: actions/cache@v2 - with: - path: ~/.platformio - key: ${{ runner.os }}-${{ hashFiles('code/platformio.ini') }} + path: code/test/unit/cache + key: ${{ runner.os }}-${{ hashFiles('code/test/unit/CMakeLists.txt') }} - name: Host tests run: | ./ci_install.sh host diff --git a/ci_install.sh b/ci_install.sh index 9b781730..10ee028f 100755 --- a/ci_install.sh +++ b/ci_install.sh @@ -14,14 +14,13 @@ pio_install() { } host_install() { - pio platform install native + sudo apt install cmake } cd code case "$1" in ("host") - pio_install host_install ;; ("webui") diff --git a/ci_script.sh b/ci_script.sh index 54b77401..91846cd3 100755 --- a/ci_script.sh +++ b/ci_script.sh @@ -6,10 +6,13 @@ cd code case "$1" in ("host") - # runs PIO unit tests, using the host compiler - # (see https://github.com/ThrowTheSwitch/Unity) - pushd test - pio test + # runs unit tests, using the host compiler and the esp8266 mock framework + # - https://github.com/esp8266/Arduino/blob/master/tests/host/Makefile + # - https://github.com/ThrowTheSwitch/Unity + pushd test/unit + cmake -B build + cmake --build build + cmake --build build --target test popd ;; ("webui") diff --git a/code/espurna/tuya_dataframe.h b/code/espurna/tuya_dataframe.h index cba2b5c9..d2ba21a1 100644 --- a/code/espurna/tuya_dataframe.h +++ b/code/espurna/tuya_dataframe.h @@ -129,8 +129,8 @@ public: {} explicit DataFrame(const Transport& input) : - _version(input[2]), - _command(input[3]) + _command(input[3]), + _version(input[2]) { auto length = (input[4] << 8) + input[5]; _data.reserve(length); @@ -141,8 +141,8 @@ public: explicit DataFrame(const DataFrameView& view) : _data(view.cbegin(), view.cend()), - _version(view.version()), - _command(view.command()) + _command(view.command()), + _version(view.version()) {} const container& data() const { @@ -180,8 +180,8 @@ public: private: container _data; - uint8_t _version { 0u }; uint8_t _command { 0u }; + uint8_t _version { 0u }; }; } // namespace diff --git a/code/test/lib/StreamString/StreamString.cpp b/code/test/lib/StreamString/StreamString.cpp deleted file mode 100644 index 4ea857fe..00000000 --- a/code/test/lib/StreamString/StreamString.cpp +++ /dev/null @@ -1,60 +0,0 @@ -/** - StreamString.cpp - - Copyright (c) 2015 Markus Sattler. All rights reserved. - This file is part of the esp8266 core for Arduino environment. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - - */ - -#include -#include "StreamString.h" - -size_t StreamString::write(const uint8_t *data, size_t size) { - if (!size || !data) return 0; - copy((const char*)data, size + 1); - return size; -} - -size_t StreamString::write(uint8_t data) { - return concat((char) data); -} - -int StreamString::available() { - return length(); -} - -int StreamString::read() { - if(length()) { - char c = charAt(0); - remove(0, 1); - return c; - - } - return -1; -} - -int StreamString::peek() { - if(length()) { - char c = charAt(0); - return c; - } - return -1; -} - -void StreamString::flush() { -} - diff --git a/code/test/lib/StreamString/StreamString.h b/code/test/lib/StreamString/StreamString.h deleted file mode 100644 index 2e81fa14..00000000 --- a/code/test/lib/StreamString/StreamString.h +++ /dev/null @@ -1,39 +0,0 @@ -/** - StreamString.h - - Copyright (c) 2015 Markus Sattler. All rights reserved. - This file is part of the esp8266 core for Arduino environment. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -*/ - -#ifndef STREAMSTRING_H_ -#define STREAMSTRING_H_ - - -class StreamString: public Stream, public String { -public: - size_t write(const uint8_t *buffer, size_t size) override; - size_t write(uint8_t data) override; - - int available() override; - int read() override; - int peek() override; - void flush() override; -}; - - -#endif /* STREAMSTRING_H_ */ diff --git a/code/test/lib/test_arduino_compat.h b/code/test/lib/test_arduino_compat.h deleted file mode 100644 index bc9feb2c..00000000 --- a/code/test/lib/test_arduino_compat.h +++ /dev/null @@ -1,5 +0,0 @@ -// some overrides we need when using UnixHostDuino - -#pragma once - -#define strncasecmp_P strncasecmp diff --git a/code/test/platformio.ini b/code/test/platformio.ini deleted file mode 100644 index 13e05d18..00000000 --- a/code/test/platformio.ini +++ /dev/null @@ -1,40 +0,0 @@ -# This file is used compile and run tests located in the `unit` directory. -# For more info, see: -# https://docs.platformio.org/en/latest/plus/unit-testing.html -# https://github.com/ThrowTheSwitch/Unity -# https://github.com/ThrowTheSwitch/Unity/blob/master/docs/UnityAssertionsReference.md - -[platformio] -test_dir = unit -src_dir = ../espurna - -# TODO: add `-t coverage` via python scripting? -# TODO: do we need `-O0`? - -# To prepare coverage data for lcov, add ${coverage.build_flags} to env:test build flags -# To actually generate coverage report: -# $ `pio test` / run the test `program` manually -# $ lcov --include (readlink -f ../espurna)'/*' --capture --directory .pio/build/test/ --output-file test.info -# $ genhtml --ignore-errors source test.info --output-directory out - -[coverage] -build_flags = -lgcov -fprofile-arcs -ftest-coverage - -[env:test] -platform = native -lib_compat_mode = off -test_build_project_src = true -src_filter = - +<../espurna/terminal_commands.cpp> - +<../espurna/terminal_parsing.cpp> -lib_deps = - StreamString - https://github.com/bxparks/UnixHostDuino#d740398e -build_flags = - -DMANUFACTURER="PLATFORMIO" - -DDEVICE="TEST" - -std=gnu++11 - -g - -Os - -include lib/test_arduino_compat.h - -I../espurna/ diff --git a/code/test/unit/CMakeLists.txt b/code/test/unit/CMakeLists.txt new file mode 100644 index 00000000..97af1bed --- /dev/null +++ b/code/test/unit/CMakeLists.txt @@ -0,0 +1,179 @@ +# crude test builder based on +# - https://github.com/esp8266/Arduino/blob/3.0.2/tests/host/Makefile +# - https://github.com/mcspr/rpnlib/blob/0.24.1/examples/host/CMakeLists.txt +# +# we do require certain pre-requisites +# - https://github.com/esp8266/Arduino/ git tree for both Core's and Mock files +# - https://github.com/ThrowTheSwitch/Unity git tree (or tool-unity from platformio) +# +# after everything is installed +# $ cmake -B build +# $ cmake --build build --target test + +cmake_minimum_required(VERSION 3.5) +project(host-test VERSION 1 LANGUAGES C CXX) + +set(CMAKE_C_STANDARD 11 CACHE STRING "Global C standard version (...does not yet work with 17 though)") +set(CMAKE_CXX_STANDARD 17 "Global C++ standard version") + +# required for esp8266 host mocking +set(COMMON_FLAGS + -Os + -g + -fno-common + -funsigned-char + -DCORE_MOCK + -DHOST_MOCK=1 + -DLWIP_IPV6=0 + -Dstrncasecmp_P=strncasecmp +) + +set(ESPURNA_PATH ${CMAKE_SOURCE_DIR}/../../../ CACHE PATH "ESPurna source code repo root") + +# PIO does not really make it easy to install packages outside of the 'platform' context, +# so sharing these between a normal builder might not be an option. (...big TODO though) +# for right now, just fetch these as raw repos. plus, there's no need for any extra params + +set(unity_version v2.5.2) + +include(FetchContent) +FetchContent_Declare( + unitygit + GIT_REPOSITORY https://github.com/ThrowTheSwitch/Unity + GIT_TAG ${unity_version} + GIT_CONFIG core.autocrlf=false core.eol=lf + SOURCE_DIR ${CMAKE_SOURCE_DIR}/cache/unitygit-${unity_version}-src + SUBBUILD_DIR ${CMAKE_SOURCE_DIR}/cache/unitygit-${unity_version}-subbuild +) + +FetchContent_MakeAvailable(unitygit) +FetchContent_GetProperties(unitygit SOURCE_DIR) + +target_compile_options(unity BEFORE PRIVATE + -DUNITY_OUTPUT_COLOR +) + +set(esp8266_version 9fcf14f81fa9be589530e9596b7c5a264dc81ee8) + +FetchContent_Declare( + esp8266git + GIT_REPOSITORY https://github.com/esp8266/Arduino/ + GIT_TAG 9fcf14f81fa9be589530e9596b7c5a264dc81ee8 + GIT_CONFIG core.autocrlf=false core.eol=lf + SOURCE_DIR ${CMAKE_SOURCE_DIR}/cache/esp8266git-${esp8266_version}-src + SUBBUILD_DIR ${CMAKE_SOURCE_DIR}/cache/esp8266git-${esp8266_version}-subbuild +) + +FetchContent_MakeAvailable(esp8266git) +FetchContent_GetProperties(esp8266git SOURCE_DIR) + +# mock'ed Arduino Core headers sometimes expect to be included with some pre-requisites, which we obviously don't have +add_library(common INTERFACE) +target_compile_options(common INTERFACE + "SHELL:-include ${esp8266git_SOURCE_DIR}/tests/host/common/mock.h" + "SHELL:-include ${esp8266git_SOURCE_DIR}/tests/host/common/c_types.h" +) + +# try to hack esp8266 host test layer +# - we need to specify bunch of things that the original Makefile does +# - there are a lot of cross-dependencies, we need to include a lot of .cpp files here +add_library(esp8266 STATIC + src/unity_fixtures.c + src/ArduinoMainOverride.cpp + ${esp8266git_SOURCE_DIR}/tests/host/common/Arduino.cpp + ${esp8266git_SOURCE_DIR}/tests/host/common/ArduinoMainUdp.cpp + ${esp8266git_SOURCE_DIR}/tests/host/common/WMath.cpp + ${esp8266git_SOURCE_DIR}/tests/host/common/MockUART.cpp + ${esp8266git_SOURCE_DIR}/tests/host/common/MockTools.cpp + ${esp8266git_SOURCE_DIR}/tests/host/common/MocklwIP.cpp + ${esp8266git_SOURCE_DIR}/tests/host/common/MockDigital.cpp + ${esp8266git_SOURCE_DIR}/tests/host/common/MockEsp.cpp + ${esp8266git_SOURCE_DIR}/tests/host/common/UdpContextSocket.cpp + ${esp8266git_SOURCE_DIR}/tests/host/common/user_interface.cpp + ${esp8266git_SOURCE_DIR}/tests/host/common/md5.c + ${esp8266git_SOURCE_DIR}/tests/host/common/noniso.c + ${esp8266git_SOURCE_DIR}/tests/host/common/flash_hal_mock.cpp + ${esp8266git_SOURCE_DIR}/tests/host/common/spiffs_mock.cpp + ${esp8266git_SOURCE_DIR}/tests/host/common/littlefs_mock.cpp + ${esp8266git_SOURCE_DIR}/tests/host/common/sdfs_mock.cpp + ${esp8266git_SOURCE_DIR}/tests/host/common/ArduinoMainUdp.cpp + ${esp8266git_SOURCE_DIR}/tests/host/common/ArduinoMainSpiffs.cpp + ${esp8266git_SOURCE_DIR}/tests/host/common/ArduinoMainLittlefs.cpp + ${esp8266git_SOURCE_DIR}/tests/host/common/user_interface.cpp + ${esp8266git_SOURCE_DIR}/cores/esp8266/debug.cpp + ${esp8266git_SOURCE_DIR}/cores/esp8266/core_esp8266_noniso.cpp + ${esp8266git_SOURCE_DIR}/cores/esp8266/stdlib_noniso.cpp + ${esp8266git_SOURCE_DIR}/cores/esp8266/WString.cpp + ${esp8266git_SOURCE_DIR}/cores/esp8266/HardwareSerial.cpp + ${esp8266git_SOURCE_DIR}/cores/esp8266/Print.cpp + ${esp8266git_SOURCE_DIR}/cores/esp8266/Schedule.cpp + ${esp8266git_SOURCE_DIR}/cores/esp8266/time.cpp + ${esp8266git_SOURCE_DIR}/cores/esp8266/Stream.cpp + ${esp8266git_SOURCE_DIR}/cores/esp8266/StreamSend.cpp + ${esp8266git_SOURCE_DIR}/cores/esp8266/FS.cpp + ${esp8266git_SOURCE_DIR}/cores/esp8266/spiffs_api.cpp + ${esp8266git_SOURCE_DIR}/cores/esp8266/spiffs/spiffs_cache.cpp + ${esp8266git_SOURCE_DIR}/cores/esp8266/spiffs/spiffs_check.cpp + ${esp8266git_SOURCE_DIR}/cores/esp8266/spiffs/spiffs_gc.cpp + ${esp8266git_SOURCE_DIR}/cores/esp8266/spiffs/spiffs_hydrogen.cpp + ${esp8266git_SOURCE_DIR}/cores/esp8266/spiffs/spiffs_nucleus.cpp + ${esp8266git_SOURCE_DIR}/libraries/LittleFS/src/LittleFS.cpp + ${esp8266git_SOURCE_DIR}/libraries/LittleFS/src/lfs.c + ${esp8266git_SOURCE_DIR}/libraries/LittleFS/src/lfs_util.c +) +target_include_directories(esp8266 PUBLIC + ${esp8266git_SOURCE_DIR}/tests/host/common/ + ${esp8266git_SOURCE_DIR}/tests/host + ${esp8266git_SOURCE_DIR}/tools/sdk/lwip2/include + ${esp8266git_SOURCE_DIR}/tools/sdk/include + ${esp8266git_SOURCE_DIR}/cores/esp8266/ + ${esp8266git_SOURCE_DIR}/libraries/LittleFS/src/ + ${esp8266git_SOURCE_DIR}/libraries/SPI/ + ${esp8266git_SOURCE_DIR}/libraries/ESP8266SdFat/src +) +target_compile_options(esp8266 PUBLIC + ${COMMON_FLAGS} + -DF_CPU=80000000 + -Wl,--defsym,_FS_start=0x40300000 + -Wl,--defsym,_FS_end=0x411FA000 + -Wl,--defsym,_FS_page=0x100 + -Wl,--defsym,_FS_block=0x2000 + -Wl,--defsym,_EEPROM_start=0x411fb000 +) +target_link_libraries(esp8266 PUBLIC common) + +# our library source (maybe some day this will be a simple glob) +add_library(terminal STATIC + ${ESPURNA_PATH}/code/espurna/terminal_commands.cpp + ${ESPURNA_PATH}/code/espurna/terminal_parsing.cpp +) +target_link_libraries(terminal PUBLIC esp8266) +target_include_directories(terminal PUBLIC + ${ESPURNA_PATH}/code/espurna/ +) +target_compile_options(terminal PUBLIC + ${COMMON_FLAGS} +) +target_compile_options(terminal PRIVATE + -Wall + -Wextra +) + +# each case is built separately, we expect these to work like a normal executable +include(CTest) + +function(build_tests) + foreach(ARG IN LISTS ARGN) + add_executable(test-${ARG} src/${ARG}/${ARG}.cpp) + target_link_libraries(test-${ARG} terminal unity) + target_compile_options(test-${ARG} PRIVATE + ${COMMON_FLAGS} + -Wall + -Wextra + ) + set_target_properties(test-${ARG} PROPERTIES COMPILE_FLAGS -g) + add_test(NAME ${ARG} COMMAND test-${ARG}) + endforeach() +endfunction() + +build_tests(basic settings terminal tuya url) diff --git a/code/test/unit/cache/README.txt b/code/test/unit/cache/README.txt new file mode 100644 index 00000000..a5eee3d9 --- /dev/null +++ b/code/test/unit/cache/README.txt @@ -0,0 +1 @@ +ref. ../CMakeLists.txt diff --git a/code/test/unit/src/ArduinoMainOverride.cpp b/code/test/unit/src/ArduinoMainOverride.cpp new file mode 100644 index 00000000..b2cba983 --- /dev/null +++ b/code/test/unit/src/ArduinoMainOverride.cpp @@ -0,0 +1,325 @@ +// direct c/p from the esp8266/Arduino, just removing the main() since we already call it +// and don't need the rest of the bootstraping done + +/* + Arduino emulator main loop + Copyright (c) 2018 david gauchard. All rights reserved. + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal with the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + - Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimers. + + - Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimers in the + documentation and/or other materials provided with the distribution. + + - The names of its contributors may not be used to endorse or promote + products derived from this Software without specific prior written + permission. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS WITH THE SOFTWARE. +*/ + +#include +#include // wifi_get_ip_info() + +#include +#include +#include +#include +#include +#include + +#define MOCK_PORT_SHIFTER 9000 + +bool user_exit = false; +bool run_once = false; +const char* host_interface = nullptr; +size_t spiffs_kb = 1024; +size_t littlefs_kb = 1024; +bool ignore_sigint = false; +bool restore_tty = false; +bool mockdebug = false; +int mock_port_shifter = MOCK_PORT_SHIFTER; +const char* fspath = nullptr; + +#define STDIN STDIN_FILENO + +static struct termios initial_settings; + +int mockverbose (const char* fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + if (mockdebug) + return fprintf(stderr, MOCK) + vfprintf(stderr, fmt, ap); + return 0; +} + +static int mock_start_uart(void) +{ + struct termios settings; + + if (!isatty(STDIN)) + { + perror("setting tty in raw mode: isatty(STDIN)"); + return -1; + } + if (tcgetattr(STDIN, &initial_settings) < 0) + { + perror("setting tty in raw mode: tcgetattr(STDIN)"); + return -1; + } + settings = initial_settings; + settings.c_lflag &= ~(ignore_sigint ? ISIG : 0); + settings.c_lflag &= ~(ECHO | ICANON); + settings.c_iflag &= ~(ICRNL | INLCR | ISTRIP | IXON); + settings.c_oflag |= (ONLCR); + settings.c_cc[VMIN] = 0; + settings.c_cc[VTIME] = 0; + if (tcsetattr(STDIN, TCSANOW, &settings) < 0) + { + perror("setting tty in raw mode: tcsetattr(STDIN)"); + return -1; + } + restore_tty = true; + return 0; +} + +static int mock_stop_uart(void) +{ + if (!restore_tty) return 0; + if (!isatty(STDIN)) { + perror("restoring tty: isatty(STDIN)"); + return -1; + } + if (tcsetattr(STDIN, TCSANOW, &initial_settings) < 0) + { + perror("restoring tty: tcsetattr(STDIN)"); + return -1; + } + printf("\e[?25h"); // show cursor + return (0); +} + +static uint8_t mock_read_uart(void) +{ + uint8_t ch = 0; + return (read(STDIN, &ch, 1) == 1) ? ch : 0; +} + +void help (const char* argv0, int exitcode) +{ + printf( + "%s - compiled with esp8266/arduino emulator\n" + "options:\n" + "\t-h\n" + "\tnetwork:\n" + "\t-i - use this interface for IP address\n" + "\t-l - bind tcp/udp servers to interface only (not 0.0.0.0)\n" + "\t-s - port shifter (default: %d, when root: 0)\n" + "\tterminal:\n" + "\t-b - blocking tty/mocked-uart (default: not blocking tty)\n" + "\t-T - show timestamp on output\n" + "\tFS:\n" + "\t-P - path for fs-persistent files (default: %s-)\n" + "\t-S - spiffs size in KBytes (default: %zd)\n" + "\t-L - littlefs size in KBytes (default: %zd)\n" + "\t (spiffs, littlefs: negative value will force mismatched size)\n" + "\tgeneral:\n" + "\t-c - ignore CTRL-C (send it via Serial)\n" + "\t-f - no throttle (possibly 100%%CPU)\n" + "\t-1 - run loop once then exit (for host testing)\n" + "\t-v - verbose\n" + , argv0, MOCK_PORT_SHIFTER, argv0, spiffs_kb, littlefs_kb); + exit(exitcode); +} + +static struct option options[] = +{ + { "help", no_argument, NULL, 'h' }, + { "fast", no_argument, NULL, 'f' }, + { "local", no_argument, NULL, 'l' }, + { "sigint", no_argument, NULL, 'c' }, + { "blockinguart", no_argument, NULL, 'b' }, + { "verbose", no_argument, NULL, 'v' }, + { "timestamp", no_argument, NULL, 'T' }, + { "interface", required_argument, NULL, 'i' }, + { "fspath", required_argument, NULL, 'P' }, + { "spiffskb", required_argument, NULL, 'S' }, + { "littlefskb", required_argument, NULL, 'L' }, + { "portshifter", required_argument, NULL, 's' }, + { "once", no_argument, NULL, '1' }, +}; + +void cleanup () +{ + mock_stop_spiffs(); + mock_stop_littlefs(); + mock_stop_uart(); +} + +void make_fs_filename (String& name, const char* fspath, const char* argv0) +{ + name.clear(); + if (fspath) + { + int lastSlash = -1; + for (int i = 0; argv0[i]; i++) + if (argv0[i] == '/') + lastSlash = i; + name = fspath; + name += '/'; + name += &argv0[lastSlash + 1]; + } + else + name = argv0; +} + +void control_c (int sig) +{ + (void)sig; + + if (user_exit) + { + fprintf(stderr, MOCK "stuck, killing\n"); + cleanup(); + exit(1); + } + user_exit = true; +} + +#if 0 +int main (int argc, char* const argv []) +{ + bool fast = false; + blocking_uart = false; // global + + signal(SIGINT, control_c); + signal(SIGTERM, control_c); + if (geteuid() == 0) + mock_port_shifter = 0; + else + mock_port_shifter = MOCK_PORT_SHIFTER; + + for (;;) + { + int n = getopt_long(argc, argv, "hlcfbvTi:S:s:L:P:1", options, NULL); + if (n < 0) + break; + switch (n) + { + case 'h': + help(argv[0], EXIT_SUCCESS); + break; + case 'i': + host_interface = optarg; + break; + case 'l': + global_ipv4_netfmt = NO_GLOBAL_BINDING; + break; + case 's': + mock_port_shifter = atoi(optarg); + break; + case 'c': + ignore_sigint = true; + break; + case 'f': + fast = true; + break; + case 'S': + spiffs_kb = atoi(optarg); + break; + case 'L': + littlefs_kb = atoi(optarg); + break; + case 'P': + fspath = optarg; + break; + case 'b': + blocking_uart = true; + break; + case 'v': + mockdebug = true; + break; + case 'T': + serial_timestamp = true; + break; + case '1': + run_once = true; + break; + default: + help(argv[0], EXIT_FAILURE); + } + } + + mockverbose("server port shifter: %d\n", mock_port_shifter); + + if (spiffs_kb) + { + String name; + make_fs_filename(name, fspath, argv[0]); + name += "-spiffs"; + name += String(spiffs_kb > 0? spiffs_kb: -spiffs_kb, DEC); + name += "KB"; + mock_start_spiffs(name, spiffs_kb); + } + + if (littlefs_kb) + { + String name; + make_fs_filename(name, fspath, argv[0]); + name += "-littlefs"; + name += String(littlefs_kb > 0? littlefs_kb: -littlefs_kb, DEC); + name += "KB"; + mock_start_littlefs(name, littlefs_kb); + } + + // setup global global_ipv4_netfmt + wifi_get_ip_info(0, nullptr); + + if (!blocking_uart) + { + // set stdin to non blocking mode + mock_start_uart(); + } + + // install exit handler in case Esp.restart() is called + atexit(cleanup); + + // first call to millis(): now is millis() and micros() beginning + millis(); + + setup(); + while (!user_exit) + { + uint8_t data = mock_read_uart(); + + if (data) + uart_new_data(UART0, data); + if (!fast) + usleep(1000); // not 100% cpu, ~1000 loops per second + loop(); + loop_end(); + check_incoming_udp(); + + if (run_once) + user_exit = true; + } + cleanup(); + + return 0; +} +#endif diff --git a/code/test/unit/basic/basic.cpp b/code/test/unit/src/basic/basic.cpp similarity index 82% rename from code/test/unit/basic/basic.cpp rename to code/test/unit/src/basic/basic.cpp index 7ecf5eef..c8112344 100644 --- a/code/test/unit/basic/basic.cpp +++ b/code/test/unit/src/basic/basic.cpp @@ -9,8 +9,8 @@ void test_linkage() { pinMode(0, OUTPUT); } -int main(int argc, char** argv) { +int main(int, char**) { UNITY_BEGIN(); RUN_TEST(test_linkage); - UNITY_END(); + return UNITY_END(); } diff --git a/code/test/unit/settings/main.cpp b/code/test/unit/src/settings/settings.cpp similarity index 99% rename from code/test/unit/settings/main.cpp rename to code/test/unit/src/settings/settings.cpp index 1f6dc8b4..a301cda2 100644 --- a/code/test/unit/settings/main.cpp +++ b/code/test/unit/src/settings/settings.cpp @@ -477,7 +477,7 @@ void test_keys_iterator() { } -int main(int argc, char** argv) { +int main(int, char**) { UNITY_BEGIN(); RUN_TEST(test_storage); RUN_TEST(test_keys_iterator); diff --git a/code/test/unit/terminal/terminal.cpp b/code/test/unit/src/terminal/terminal.cpp similarity index 98% rename from code/test/unit/terminal/terminal.cpp rename to code/test/unit/src/terminal/terminal.cpp index 94995f0a..1742dffa 100644 --- a/code/test/unit/terminal/terminal.cpp +++ b/code/test/unit/src/terminal/terminal.cpp @@ -216,10 +216,10 @@ void test_quotes() { void test_case_insensitive() { - terminal::Terminal::addCommand(F("test.lowercase1"), [](::terminal::CommandContext&& ctx) { + terminal::Terminal::addCommand(F("test.lowercase1"), [](::terminal::CommandContext&&) { TEST_FAIL_MESSAGE("`test.lowercase1` was registered first, but there's another function by the same name. This should not be called"); }); - terminal::Terminal::addCommand(F("TEST.LOWERCASE1"), [](::terminal::CommandContext&& ctx) { + terminal::Terminal::addCommand(F("TEST.LOWERCASE1"), [](::terminal::CommandContext&&) { __asm__ volatile ("nop"); }); @@ -252,7 +252,7 @@ void test_output() { // When adding test functions, don't forget to add RUN_TEST(...) in the main() -int main(int argc, char** argv) { +int main(int, char**) { UNITY_BEGIN(); RUN_TEST(test_command); RUN_TEST(test_command_args); @@ -262,5 +262,5 @@ int main(int argc, char** argv) { RUN_TEST(test_quotes); RUN_TEST(test_case_insensitive); RUN_TEST(test_output); - UNITY_END(); + return UNITY_END(); } diff --git a/code/test/unit/tuya/tuya.cpp b/code/test/unit/src/tuya/tuya.cpp similarity index 99% rename from code/test/unit/tuya/tuya.cpp rename to code/test/unit/src/tuya/tuya.cpp index 869eb7c7..5248cf41 100644 --- a/code/test/unit/tuya/tuya.cpp +++ b/code/test/unit/src/tuya/tuya.cpp @@ -298,7 +298,7 @@ void test_dataframe_echo() { } } -int main(int argc, char** argv) { +int main(int, char**) { UNITY_BEGIN(); diff --git a/code/test/unit/src/unity_fixtures.c b/code/test/unit/src/unity_fixtures.c new file mode 100644 index 00000000..edca66d0 --- /dev/null +++ b/code/test/unit/src/unity_fixtures.c @@ -0,0 +1,14 @@ +// minimal set of functions that are supposed to be linked with the unity.c + +void setUp(void) { +} + +void tearDown(void) { +} + +void suiteSetUp(void) { +} + +int suiteTearDown(int failures) { + return failures; +} diff --git a/code/test/unit/url/url.cpp b/code/test/unit/src/url/url.cpp similarity index 86% rename from code/test/unit/url/url.cpp rename to code/test/unit/src/url/url.cpp index a0c4fe9b..43fa6511 100644 --- a/code/test/unit/url/url.cpp +++ b/code/test/unit/src/url/url.cpp @@ -10,12 +10,8 @@ void test_parse() { TEST_ASSERT_EQUAL(80, url.port); } -int main(int argc, char** argv) { - +int main(int, char**) { UNITY_BEGIN(); - RUN_TEST(test_parse); - - UNITY_END(); - + return UNITY_END(); }