Files
anvil/tests/test_mock_arduino.rs
2026-02-21 13:27:40 -06:00

205 lines
8.6 KiB
Rust

use anvil::templates::{TemplateManager, TemplateContext};
use std::fs;
use tempfile::TempDir;
// ==========================================================================
// Mock Arduino: template file content verification
// ==========================================================================
#[test]
fn test_mock_arduino_header_has_core_api() {
let tmp = TempDir::new().unwrap();
let ctx = TemplateContext {
project_name: "mock_test".to_string(),
anvil_version: "1.0.0".to_string(),
board_name: "uno".to_string(),
fqbn: "arduino:avr:uno".to_string(),
baud: 115200,
};
TemplateManager::extract("basic", tmp.path(), &ctx).unwrap();
let header = fs::read_to_string(tmp.path().join("test/mocks/mock_arduino.h")).unwrap();
// Core Arduino constants
assert!(header.contains("#define INPUT"), "Should define INPUT");
assert!(header.contains("#define OUTPUT"), "Should define OUTPUT");
assert!(header.contains("#define HIGH"), "Should define HIGH");
assert!(header.contains("#define LOW"), "Should define LOW");
assert!(header.contains("#define LED_BUILTIN"), "Should define LED_BUILTIN");
assert!(header.contains("#define A0"), "Should define A0");
// Core Arduino functions (declarations use aligned whitespace)
assert!(header.contains("pinMode("), "Should declare pinMode");
assert!(header.contains("digitalWrite("), "Should declare digitalWrite");
assert!(header.contains("digitalRead("), "Should declare digitalRead");
assert!(header.contains("analogRead("), "Should declare analogRead");
assert!(header.contains("analogWrite("), "Should declare analogWrite");
assert!(header.contains("millis()"), "Should declare millis");
assert!(header.contains("delay("), "Should declare delay");
// Serial class
assert!(header.contains("class MockSerial"), "Should declare MockSerial");
assert!(header.contains("extern MockSerial Serial"), "Should declare global Serial");
// Test control API
assert!(header.contains("mock_arduino_reset()"), "Should have reset");
assert!(header.contains("mock_arduino_advance_millis("), "Should have advance_millis");
assert!(header.contains("mock_arduino_set_digital("), "Should have set_digital");
assert!(header.contains("mock_arduino_set_analog("), "Should have set_analog");
// String class
assert!(header.contains("class String"), "Should declare String class");
}
#[test]
fn test_mock_arduino_shims_exist() {
let tmp = TempDir::new().unwrap();
let ctx = TemplateContext {
project_name: "shim_test".to_string(),
anvil_version: "1.0.0".to_string(),
board_name: "uno".to_string(),
fqbn: "arduino:avr:uno".to_string(),
baud: 115200,
};
TemplateManager::extract("basic", tmp.path(), &ctx).unwrap();
// Arduino.h shim should include mock_arduino.h
let arduino_h = fs::read_to_string(tmp.path().join("test/mocks/Arduino.h")).unwrap();
assert!(
arduino_h.contains("mock_arduino.h"),
"Arduino.h shim should redirect to mock_arduino.h"
);
// Wire.h shim should provide MockWire
let wire_h = fs::read_to_string(tmp.path().join("test/mocks/Wire.h")).unwrap();
assert!(wire_h.contains("class MockWire"), "Wire.h should declare MockWire");
assert!(wire_h.contains("extern MockWire Wire"), "Wire.h should declare global Wire");
// SPI.h shim should provide MockSPI
let spi_h = fs::read_to_string(tmp.path().join("test/mocks/SPI.h")).unwrap();
assert!(spi_h.contains("class MockSPI"), "SPI.h should declare MockSPI");
assert!(spi_h.contains("extern MockSPI SPI"), "SPI.h should declare global SPI");
assert!(spi_h.contains("SPI_MODE0"), "SPI.h should define SPI modes");
assert!(spi_h.contains("struct SPISettings"), "SPI.h should define SPISettings");
}
#[test]
fn test_mock_arduino_all_files_ascii() {
let tmp = TempDir::new().unwrap();
let ctx = TemplateContext {
project_name: "ascii_mock".to_string(),
anvil_version: "1.0.0".to_string(),
board_name: "uno".to_string(),
fqbn: "arduino:avr:uno".to_string(),
baud: 115200,
};
TemplateManager::extract("basic", tmp.path(), &ctx).unwrap();
let mock_files = vec![
"test/mocks/mock_arduino.h",
"test/mocks/mock_arduino.cpp",
"test/mocks/Arduino.h",
"test/mocks/Wire.h",
"test/mocks/SPI.h",
];
for filename in &mock_files {
let content = fs::read_to_string(tmp.path().join(filename)).unwrap();
for (line_num, line) in content.lines().enumerate() {
for (col, ch) in line.chars().enumerate() {
assert!(
ch.is_ascii(),
"Non-ASCII in {} at {}:{}: '{}' (U+{:04X})",
filename, line_num + 1, col + 1, ch, ch as u32
);
}
}
}
}
#[test]
fn test_cmake_links_mock_arduino() {
let tmp = TempDir::new().unwrap();
let ctx = TemplateContext {
project_name: "cmake_test".to_string(),
anvil_version: "1.0.0".to_string(),
board_name: "uno".to_string(),
fqbn: "arduino:avr:uno".to_string(),
baud: 115200,
};
TemplateManager::extract("basic", tmp.path(), &ctx).unwrap();
let cmake = fs::read_to_string(tmp.path().join("test/CMakeLists.txt")).unwrap();
// Should define mock_arduino library
assert!(cmake.contains("add_library(mock_arduino"), "Should define mock_arduino library");
assert!(cmake.contains("mock_arduino.cpp"), "Should compile mock_arduino.cpp");
// Both test targets should link mock_arduino
assert!(cmake.contains("target_link_libraries(test_unit"), "Should have test_unit target");
assert!(cmake.contains("target_link_libraries(test_system"), "Should have test_system target");
// System test target
assert!(cmake.contains("add_executable(test_system"), "Should build test_system");
assert!(cmake.contains("test_system.cpp"), "Should compile test_system.cpp");
// gtest discovery for both
assert!(cmake.contains("gtest_discover_tests(test_unit)"), "Should discover unit tests");
assert!(cmake.contains("gtest_discover_tests(test_system)"), "Should discover system tests");
}
#[test]
fn test_system_test_template_uses_simhal() {
let tmp = TempDir::new().unwrap();
let ctx = TemplateContext {
project_name: "sys_test".to_string(),
anvil_version: "1.0.0".to_string(),
board_name: "uno".to_string(),
fqbn: "arduino:avr:uno".to_string(),
baud: 115200,
};
TemplateManager::extract("basic", tmp.path(), &ctx).unwrap();
let system_test = fs::read_to_string(tmp.path().join("test/test_system.cpp")).unwrap();
// Should include mock_arduino and sim_hal
assert!(system_test.contains("mock_arduino.h"), "Should include mock_arduino.h");
assert!(system_test.contains("sim_hal.h"), "Should include sim_hal.h");
assert!(system_test.contains("sys_test_app.h"), "Should reference project app header");
// Should use SimHal, not MockHal
assert!(system_test.contains("SimHal"), "Should use SimHal for system tests");
// Should call mock_arduino_reset
assert!(system_test.contains("mock_arduino_reset()"), "Should reset mock state in SetUp");
}
#[test]
fn test_root_test_scripts_exist_and_reference_test_dir() {
let tmp = TempDir::new().unwrap();
let ctx = TemplateContext {
project_name: "script_test".to_string(),
anvil_version: "1.0.0".to_string(),
board_name: "uno".to_string(),
fqbn: "arduino:avr:uno".to_string(),
baud: 115200,
};
TemplateManager::extract("basic", tmp.path(), &ctx).unwrap();
// test.sh
let test_sh = fs::read_to_string(tmp.path().join("test.sh")).unwrap();
assert!(test_sh.contains("TEST_DIR="), "test.sh should set TEST_DIR");
assert!(test_sh.contains("cmake"), "test.sh should invoke cmake");
assert!(test_sh.contains("ctest"), "test.sh should invoke ctest");
assert!(test_sh.contains("--unit"), "test.sh should support --unit flag");
assert!(test_sh.contains("--system"), "test.sh should support --system flag");
assert!(test_sh.contains("--clean"), "test.sh should support --clean flag");
// test.bat
let test_bat = fs::read_to_string(tmp.path().join("test.bat")).unwrap();
assert!(test_bat.contains("TEST_DIR"), "test.bat should set TEST_DIR");
assert!(test_bat.contains("cmake"), "test.bat should invoke cmake");
assert!(test_bat.contains("ctest"), "test.bat should invoke ctest");
assert!(test_bat.contains("--unit"), "test.bat should support --unit flag");
assert!(test_bat.contains("--system"), "test.bat should support --system flag");
}