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:
148
templates/basic/test/test_system.cpp.tmpl
Normal file
148
templates/basic/test/test_system.cpp.tmpl
Normal file
@@ -0,0 +1,148 @@
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "mock_arduino.h"
|
||||
#include "hal.h"
|
||||
#include "sim_hal.h"
|
||||
#include "{{PROJECT_NAME}}_app.h"
|
||||
|
||||
// ============================================================================
|
||||
// System Tests -- exercise full application logic against simulated hardware
|
||||
//
|
||||
// Unlike unit tests (which verify exact call sequences), system tests
|
||||
// run the real application code against SimHal and inspect observable
|
||||
// outputs: pin states, serial messages, timing behavior.
|
||||
// ============================================================================
|
||||
|
||||
class BlinkAppSystemTest : public ::testing::Test {
|
||||
protected:
|
||||
void SetUp() override {
|
||||
mock_arduino_reset();
|
||||
sim_.setMillis(0);
|
||||
}
|
||||
|
||||
SimHal sim_;
|
||||
};
|
||||
|
||||
TEST_F(BlinkAppSystemTest, SetupConfiguresPins) {
|
||||
BlinkApp app(&sim_);
|
||||
app.begin();
|
||||
|
||||
EXPECT_EQ(sim_.getPinMode(13), OUTPUT);
|
||||
EXPECT_EQ(sim_.getPinMode(2), INPUT_PULLUP);
|
||||
}
|
||||
|
||||
TEST_F(BlinkAppSystemTest, LedTogglesAtCorrectInterval) {
|
||||
BlinkApp app(&sim_);
|
||||
app.begin();
|
||||
|
||||
// LED should be off initially
|
||||
EXPECT_EQ(sim_.getPin(13), LOW);
|
||||
|
||||
// Advance past one slow interval (500ms)
|
||||
sim_.advanceMillis(500);
|
||||
app.update();
|
||||
EXPECT_EQ(sim_.getPin(13), HIGH);
|
||||
|
||||
// Advance another interval
|
||||
sim_.advanceMillis(500);
|
||||
app.update();
|
||||
EXPECT_EQ(sim_.getPin(13), LOW);
|
||||
}
|
||||
|
||||
TEST_F(BlinkAppSystemTest, LedDoesNotToggleTooEarly) {
|
||||
BlinkApp app(&sim_);
|
||||
app.begin();
|
||||
|
||||
sim_.advanceMillis(499);
|
||||
app.update();
|
||||
EXPECT_EQ(sim_.getPin(13), LOW);
|
||||
}
|
||||
|
||||
TEST_F(BlinkAppSystemTest, ButtonTogglesFastMode) {
|
||||
BlinkApp app(&sim_, 13, 2);
|
||||
sim_.setPin(2, HIGH); // Button not pressed (INPUT_PULLUP)
|
||||
app.begin();
|
||||
|
||||
EXPECT_FALSE(app.fastMode());
|
||||
|
||||
// Press button
|
||||
sim_.setPin(2, LOW);
|
||||
app.update();
|
||||
EXPECT_TRUE(app.fastMode());
|
||||
EXPECT_EQ(app.interval(), BlinkApp::FAST_INTERVAL_MS);
|
||||
|
||||
// Release and press again -> back to slow
|
||||
sim_.setPin(2, HIGH);
|
||||
app.update();
|
||||
sim_.setPin(2, LOW);
|
||||
app.update();
|
||||
EXPECT_FALSE(app.fastMode());
|
||||
EXPECT_EQ(app.interval(), BlinkApp::SLOW_INTERVAL_MS);
|
||||
}
|
||||
|
||||
TEST_F(BlinkAppSystemTest, FastModeBlinksFaster) {
|
||||
BlinkApp app(&sim_, 13, 2);
|
||||
sim_.setPin(2, HIGH);
|
||||
app.begin();
|
||||
|
||||
// Switch to fast mode
|
||||
sim_.setPin(2, LOW);
|
||||
app.update();
|
||||
sim_.setPin(2, HIGH);
|
||||
app.update();
|
||||
EXPECT_TRUE(app.fastMode());
|
||||
|
||||
// Clear log, then count toggles over 1 second
|
||||
sim_.clearGpioLog();
|
||||
for (int i = 0; i < 8; ++i) {
|
||||
sim_.advanceMillis(125);
|
||||
app.update();
|
||||
}
|
||||
|
||||
// In 1 second at 125ms intervals, we expect 8 toggles
|
||||
int high_count = sim_.countWrites(13, HIGH);
|
||||
int low_count = sim_.countWrites(13, LOW);
|
||||
EXPECT_EQ(high_count + low_count, 8);
|
||||
}
|
||||
|
||||
TEST_F(BlinkAppSystemTest, SerialOutputOnStartup) {
|
||||
BlinkApp app(&sim_);
|
||||
app.begin();
|
||||
|
||||
std::string output = sim_.serialOutput();
|
||||
EXPECT_NE(output.find("BlinkApp started"), std::string::npos);
|
||||
}
|
||||
|
||||
TEST_F(BlinkAppSystemTest, SerialOutputOnModeChange) {
|
||||
BlinkApp app(&sim_, 13, 2);
|
||||
sim_.setPin(2, HIGH);
|
||||
app.begin();
|
||||
sim_.clearSerialOutput();
|
||||
|
||||
// Press button
|
||||
sim_.setPin(2, LOW);
|
||||
app.update();
|
||||
|
||||
std::string output = sim_.serialOutput();
|
||||
EXPECT_NE(output.find("FAST"), std::string::npos);
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Timing accuracy test -- verifies blink over a longer duration
|
||||
// ============================================================================
|
||||
|
||||
TEST_F(BlinkAppSystemTest, TenSecondBlinkCount) {
|
||||
BlinkApp app(&sim_);
|
||||
app.begin();
|
||||
sim_.clearGpioLog();
|
||||
|
||||
// Run for 10 seconds at 10ms resolution
|
||||
for (int i = 0; i < 1000; ++i) {
|
||||
sim_.advanceMillis(10);
|
||||
app.update();
|
||||
}
|
||||
|
||||
// At 500ms intervals over 10s, expect 20 toggles
|
||||
int toggles = sim_.countWrites(13, HIGH) + sim_.countWrites(13, LOW);
|
||||
EXPECT_EQ(toggles, 20);
|
||||
}
|
||||
Reference in New Issue
Block a user