All passing

This commit is contained in:
Eric Ratliff
2026-02-21 21:36:49 -06:00
parent a9f729c7de
commit 344c59ca13
2 changed files with 30 additions and 59 deletions

View File

@@ -152,12 +152,18 @@ pub fn generate_default(project_dir: &Path, _template_name: &str) -> Result<()>
// Sketch is protected // Sketch is protected
content.push_str("# Your Arduino sketch.\n"); content.push_str("# Your Arduino sketch.\n");
content.push_str(&format!("{}/*.ino\n", "*/")); // Pattern: any-directory/*.ino (do NOT use format! here)
content.push_str("*/*.ino\n");
content.push_str("\n"); content.push_str("\n");
// Config is protected // Config and project files are protected
content.push_str("# Project configuration.\n"); content.push_str("# Project configuration and docs.\n");
content.push_str(".anvil.toml\n"); content.push_str(".anvil.toml\n");
content.push_str(".gitignore\n");
content.push_str(".editorconfig\n");
content.push_str(".clang-format\n");
content.push_str(".vscode/*\n");
content.push_str("README.md\n");
fs::write(&path, content) fs::write(&path, content)
.context("Failed to create .anvilignore")?; .context("Failed to create .anvilignore")?;

View File

@@ -597,7 +597,9 @@ fn count_constructor_params(header: &str, class_name: &str) -> (usize, usize) {
} }
#[test] #[test]
fn test_template_system_tests_use_valid_sim_api() { fn test_template_weather_tests_use_valid_sensor_api() {
// test_weather.cpp includes BOTH unit tests (Tmp36Mock) and system tests
// (Tmp36Sim). Each sensor method call must exist in at least one header.
let tmp = extract_weather("wx"); let tmp = extract_weather("wx");
commands::lib::install_library("tmp36", tmp.path()).unwrap(); commands::lib::install_library("tmp36", tmp.path()).unwrap();
@@ -610,54 +612,6 @@ fn test_template_system_tests_use_valid_sim_api() {
) )
.unwrap(); .unwrap();
let test_source = fs::read_to_string(
tmp.path().join("test").join("test_weather.cpp"),
)
.unwrap();
let methods = extract_public_methods(&sim_header);
// Verify test code only calls methods that exist in the header
// Check for common method-call patterns: "sensor.methodName("
// or "exact_sensor.methodName(" etc.
for line in test_source.lines() {
let trimmed = line.trim();
if trimmed.starts_with("//") || trimmed.is_empty() {
continue;
}
// Find "identifier.methodName(" patterns
if let Some(dot_pos) = trimmed.find('.') {
let after_dot = &trimmed[dot_pos + 1..];
if let Some(paren_pos) = after_dot.find('(') {
let method_name = after_dot[..paren_pos].trim();
// Only check methods on sensor/sim-like objects
let before_dot = trimmed[..dot_pos].trim();
let before_dot = before_dot
.split_whitespace()
.last()
.unwrap_or(before_dot);
if before_dot.contains("sensor") || before_dot.contains("sim") {
assert!(
methods.contains(&method_name.to_string()),
"test_weather.cpp calls '{}.{}()' but '{}' \
is not in tmp36_sim.h.\n \
Available methods: {:?}",
before_dot,
method_name,
method_name,
methods
);
}
}
}
}
}
#[test]
fn test_template_unit_tests_use_valid_mock_api() {
let tmp = extract_weather("wx");
commands::lib::install_library("tmp36", tmp.path()).unwrap();
let mock_header = fs::read_to_string( let mock_header = fs::read_to_string(
tmp.path() tmp.path()
.join("lib") .join("lib")
@@ -672,7 +626,16 @@ fn test_template_unit_tests_use_valid_mock_api() {
) )
.unwrap(); .unwrap();
let methods = extract_public_methods(&mock_header); let sim_methods = extract_public_methods(&sim_header);
let mock_methods = extract_public_methods(&mock_header);
// Union of all valid methods across both sensor types
let mut all_methods: Vec<String> = sim_methods.clone();
for m in &mock_methods {
if !all_methods.contains(m) {
all_methods.push(m.clone());
}
}
for line in test_source.lines() { for line in test_source.lines() {
let trimmed = line.trim(); let trimmed = line.trim();
@@ -690,14 +653,16 @@ fn test_template_unit_tests_use_valid_mock_api() {
.unwrap_or(before_dot); .unwrap_or(before_dot);
if before_dot.contains("sensor") { if before_dot.contains("sensor") {
assert!( assert!(
methods.contains(&method_name.to_string()), all_methods.contains(&method_name.to_string()),
"test_weather.cpp calls '{}.{}()' but '{}' \ "test_weather.cpp calls '{}.{}()' but '{}' \
is not in tmp36_mock.h.\n \ is not in tmp36_sim.h or tmp36_mock.h.\n \
Available methods: {:?}", Sim methods: {:?}\n \
Mock methods: {:?}",
before_dot, before_dot,
method_name, method_name,
method_name, method_name,
methods sim_methods,
mock_methods
); );
} }
} }
@@ -1033,7 +998,7 @@ fn test_refresh_updates_managed_template_test() {
// Tamper with managed test_weather.cpp // Tamper with managed test_weather.cpp
let test_weather = tmp.path().join("test").join("test_weather.cpp"); let test_weather = tmp.path().join("test").join("test_weather.cpp");
let original = fs::read_to_string(&test_weather).unwrap(); let _original = fs::read_to_string(&test_weather).unwrap();
fs::write(&test_weather, "// tampered\n").unwrap(); fs::write(&test_weather, "// tampered\n").unwrap();
// Run refresh --force // Run refresh --force
@@ -1056,7 +1021,7 @@ fn test_refresh_force_file_overrides_ignore() {
// Modify ignored test_unit.cpp // Modify ignored test_unit.cpp
let test_unit = tmp.path().join("test").join("test_unit.cpp"); let test_unit = tmp.path().join("test").join("test_unit.cpp");
let original = fs::read_to_string(&test_unit).unwrap(); let _original = fs::read_to_string(&test_unit).unwrap();
fs::write(&test_unit, "// i want this overwritten\n").unwrap(); fs::write(&test_unit, "// i want this overwritten\n").unwrap();
// Run refresh --force --file test/test_unit.cpp // Run refresh --force --file test/test_unit.cpp