All passing
This commit is contained in:
@@ -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")?;
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user