Add mock Arduino for x86_64 host-side testing

Complete Arduino API mock (mock_arduino.h/cpp) enabling application
code to compile and run on PC without hardware. Includes MockSerial,
String class, GPIO/analog/timing/interrupt mocks with state tracking
and test control API.

- Arduino.h, Wire.h, SPI.h shims intercept includes in test builds
- System test template (test_system.cpp) using SimHal
- CMakeLists.txt builds mock_arduino as static lib, links both suites
- Root test.sh/test.bat with --unit/--system/--clean/--verbose flags
- test.bat auto-detects MSVC via vswhere + vcvarsall.bat
- Doctor reports nuanced compiler status (on PATH vs installed)
- Refresh pulls mock infrastructure into existing projects
- 15 tests passing: 7 unit (MockHal) + 8 system (SimHal)
This commit is contained in:
Eric Ratliff
2026-02-20 08:21:11 -06:00
parent 1ae136530f
commit aa1e9d5043
13 changed files with 1831 additions and 16 deletions

158
templates/basic/test.bat Normal file
View File

@@ -0,0 +1,158 @@
@echo off
setlocal enabledelayedexpansion
:: =========================================================================
:: test.bat -- Build and run all host-side tests (no Arduino board needed)
::
:: Usage:
:: test Build and run all tests
:: test --clean Clean rebuild
:: test --verbose Verbose test output
:: test --unit Run only unit tests
:: test --system Run only system tests
::
:: This script builds your application against mock_arduino (a fake Arduino
:: environment) and runs Google Test suites. Your app code compiles and runs
:: on your PC -- no board, no wires, no USB.
::
:: Prerequisites:
:: cmake >= 3.14, a C++ compiler (g++, clang++, or MSVC), git
::
:: First run downloads Google Test automatically (~30 seconds).
:: =========================================================================
set "SCRIPT_DIR=%~dp0"
:: %~dp0 always ends with \ which breaks cmake quoting
set "SCRIPT_DIR=%SCRIPT_DIR:~0,-1%"
set "TEST_DIR=%SCRIPT_DIR%\test"
set "BUILD_DIR=%TEST_DIR%\build"
set DO_CLEAN=0
set VERBOSE=
set FILTER=
:parse_args
if "%1"=="" goto :done_args
if "%1"=="--clean" ( set DO_CLEAN=1 & shift & goto :parse_args )
if "%1"=="--verbose" ( set VERBOSE=--verbose & shift & goto :parse_args )
if "%1"=="--unit" ( set "FILTER=-R test_unit" & shift & goto :parse_args )
if "%1"=="--system" ( set "FILTER=-R test_system" & shift & goto :parse_args )
if "%1"=="--help" goto :show_help
if "%1"=="-h" goto :show_help
echo [FAIL] Unknown option: %1
echo Try: test --help
exit /b 1
:done_args
:: -- Check prerequisites ---------------------------------------------------
where cmake >nul 2>&1
if errorlevel 1 (
echo [FAIL] cmake not found.
echo Install: winget install Kitware.CMake
echo Or run: anvil doctor --fix
exit /b 1
)
set "HAS_COMPILER=0"
where g++ >nul 2>&1 && set "HAS_COMPILER=1"
where clang++ >nul 2>&1 && set "HAS_COMPILER=1"
where cl >nul 2>&1 && set "HAS_COMPILER=1"
if "%HAS_COMPILER%"=="1" goto :compiler_ok
:: cl.exe not on PATH -- try to find VS Build Tools via vswhere
set "VSWHERE=%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe"
if not exist "%VSWHERE%" goto :no_compiler
for /f "usebackq tokens=*" %%i in (`"%VSWHERE%" -latest -property installationPath`) do (
set "VS_PATH=%%i"
)
if not defined VS_PATH goto :no_compiler
set "VCVARS=!VS_PATH!\VC\Auxiliary\Build\vcvarsall.bat"
if not exist "!VCVARS!" goto :no_compiler
echo [TEST] Setting up MSVC environment...
call "!VCVARS!" x64 >nul 2>&1
where cl >nul 2>&1
if errorlevel 1 goto :no_compiler
set "HAS_COMPILER=1"
goto :compiler_ok
:no_compiler
echo [FAIL] No C++ compiler found.
echo.
echo Easiest fix -- install MinGW g++ ^(just works, lands on PATH^):
echo choco install mingw -y
echo.
echo Or if you have VS Build Tools, open "Developer Command Prompt"
echo and run test.bat from there.
echo.
echo Or run: anvil doctor --fix
exit /b 1
:compiler_ok
where git >nul 2>&1
if errorlevel 1 (
echo [FAIL] git not found ^(needed to fetch Google Test^).
echo Install: winget install Git.Git
exit /b 1
)
:: -- Build ------------------------------------------------------------------
if %DO_CLEAN%==1 (
if exist "%BUILD_DIR%" (
echo [TEST] Cleaning build directory...
rmdir /s /q "%BUILD_DIR%"
)
)
if not exist "%BUILD_DIR%\CMakeCache.txt" (
echo [TEST] Configuring test build. First run will fetch Google Test...
cmake -S "%TEST_DIR%" -B "%BUILD_DIR%" -DCMAKE_BUILD_TYPE=Debug
if errorlevel 1 (
echo [FAIL] cmake configure failed.
echo Run 'anvil doctor' to check your environment.
exit /b 1
)
echo.
)
echo [TEST] Building tests...
cmake --build "%BUILD_DIR%" --parallel
if errorlevel 1 (
echo [FAIL] Build failed.
exit /b 1
)
echo.
echo [TEST] Running tests...
echo.
:: -- Run --------------------------------------------------------------------
set "CTEST_ARGS=--test-dir "%BUILD_DIR%" --output-on-failure"
if not "%VERBOSE%"=="" set "CTEST_ARGS=%CTEST_ARGS% %VERBOSE%"
if not "%FILTER%"=="" set "CTEST_ARGS=%CTEST_ARGS% %FILTER%"
ctest %CTEST_ARGS%
if errorlevel 1 (
echo.
echo [FAIL] Some tests failed.
exit /b 1
)
echo.
echo [PASS] All tests passed.
exit /b 0
:show_help
echo Usage: test [--clean] [--verbose] [--unit^|--system]
echo.
echo --clean Delete build cache and rebuild from scratch
echo --verbose Show individual test names and output
echo --unit Run only unit tests (Google Mock)
echo --system Run only system tests (SimHal)
exit /b 0