Supporting a button library.
This commit is contained in:
@@ -615,4 +615,214 @@ fn test_add_remove_pin_assignment_survives() {
|
||||
board_pins.assignments.contains_key("tmp36_data"),
|
||||
"Pin assignment should survive library removal"
|
||||
);
|
||||
}
|
||||
|
||||
// ==========================================================================
|
||||
// Button Library: registry, extraction, content, coexistence
|
||||
// ==========================================================================
|
||||
|
||||
#[test]
|
||||
fn test_library_registry_lists_button() {
|
||||
let libs = library::list_available();
|
||||
let btn = libs.iter().find(|l| l.name == "button");
|
||||
assert!(btn.is_some(), "Button should be in the registry");
|
||||
|
||||
let meta = btn.unwrap();
|
||||
assert_eq!(meta.bus, "digital");
|
||||
assert_eq!(meta.pins, vec!["signal"]);
|
||||
assert_eq!(meta.interface, "button.h");
|
||||
assert_eq!(meta.mock, "button_mock.h");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_button_extract_creates_driver_directory() {
|
||||
let tmp = TempDir::new().unwrap();
|
||||
|
||||
let written = library::extract_library("button", tmp.path()).unwrap();
|
||||
assert!(!written.is_empty(), "Should write files");
|
||||
|
||||
let driver_dir = tmp.path().join("lib/drivers/button");
|
||||
assert!(driver_dir.exists(), "Driver directory should be created");
|
||||
|
||||
assert!(driver_dir.join("button.h").exists(), "Interface header");
|
||||
assert!(driver_dir.join("button_digital.h").exists(), "Implementation");
|
||||
assert!(driver_dir.join("button_mock.h").exists(), "Mock");
|
||||
assert!(driver_dir.join("button_sim.h").exists(), "Simulation");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_button_extract_files_content_is_valid() {
|
||||
let tmp = TempDir::new().unwrap();
|
||||
library::extract_library("button", tmp.path()).unwrap();
|
||||
|
||||
let driver_dir = tmp.path().join("lib/drivers/button");
|
||||
|
||||
// Interface should define Button class
|
||||
let interface = fs::read_to_string(driver_dir.join("button.h")).unwrap();
|
||||
assert!(interface.contains("class Button"), "Should define Button");
|
||||
assert!(interface.contains("isPressed"), "Should declare isPressed");
|
||||
assert!(interface.contains("readState"), "Should declare readState");
|
||||
|
||||
// Implementation should include hal.h
|
||||
let impl_h = fs::read_to_string(driver_dir.join("button_digital.h")).unwrap();
|
||||
assert!(impl_h.contains("hal.h"), "Implementation should use HAL");
|
||||
assert!(impl_h.contains("class ButtonDigital"), "Should define ButtonDigital");
|
||||
assert!(impl_h.contains("digitalRead"), "Should use digitalRead");
|
||||
|
||||
// Mock should have setPressed
|
||||
let mock_h = fs::read_to_string(driver_dir.join("button_mock.h")).unwrap();
|
||||
assert!(mock_h.contains("class ButtonMock"), "Should define ButtonMock");
|
||||
assert!(mock_h.contains("setPressed"), "Mock should have setPressed");
|
||||
|
||||
// Sim should have press/release and bounce
|
||||
let sim_h = fs::read_to_string(driver_dir.join("button_sim.h")).unwrap();
|
||||
assert!(sim_h.contains("class ButtonSim"), "Should define ButtonSim");
|
||||
assert!(sim_h.contains("setBounceReads"), "Sim should have setBounceReads");
|
||||
assert!(sim_h.contains("press()"), "Sim should have press()");
|
||||
assert!(sim_h.contains("release()"), "Sim should have release()");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_button_files_are_ascii_only() {
|
||||
let tmp = TempDir::new().unwrap();
|
||||
library::extract_library("button", tmp.path()).unwrap();
|
||||
|
||||
let driver_dir = tmp.path().join("lib/drivers/button");
|
||||
for entry in fs::read_dir(&driver_dir).unwrap() {
|
||||
let entry = entry.unwrap();
|
||||
let content = fs::read_to_string(entry.path()).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}",
|
||||
entry.file_name().to_string_lossy(),
|
||||
line_num + 1, col + 1, ch as u32
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_button_remove_cleans_up() {
|
||||
let tmp = TempDir::new().unwrap();
|
||||
library::extract_library("button", tmp.path()).unwrap();
|
||||
|
||||
assert!(library::is_installed_on_disk("button", tmp.path()));
|
||||
assert!(tmp.path().join("test/test_button.cpp").exists());
|
||||
|
||||
library::remove_library_files("button", tmp.path()).unwrap();
|
||||
|
||||
assert!(!library::is_installed_on_disk("button", tmp.path()));
|
||||
assert!(!tmp.path().join("test/test_button.cpp").exists());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_button_meta_wiring_summary() {
|
||||
let meta = library::find_library("button").unwrap();
|
||||
let summary = meta.wiring_summary();
|
||||
assert!(summary.contains("digital"), "Should mention digital bus: {}", summary);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_button_meta_pin_roles() {
|
||||
let meta = library::find_library("button").unwrap();
|
||||
let roles = meta.pin_roles();
|
||||
assert_eq!(roles.len(), 1);
|
||||
assert_eq!(roles[0].0, "signal");
|
||||
assert_eq!(roles[0].1, "button_signal");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_button_meta_default_mode() {
|
||||
let meta = library::find_library("button").unwrap();
|
||||
assert_eq!(meta.default_mode(), "input");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_button_interface_uses_polymorphism() {
|
||||
let tmp = TempDir::new().unwrap();
|
||||
library::extract_library("button", tmp.path()).unwrap();
|
||||
|
||||
let driver_dir = tmp.path().join("lib/drivers/button");
|
||||
|
||||
// All implementations should inherit from Button
|
||||
let impl_h = fs::read_to_string(driver_dir.join("button_digital.h")).unwrap();
|
||||
assert!(impl_h.contains(": public Button"), "ButtonDigital should inherit Button");
|
||||
|
||||
let mock_h = fs::read_to_string(driver_dir.join("button_mock.h")).unwrap();
|
||||
assert!(mock_h.contains(": public Button"), "ButtonMock should inherit Button");
|
||||
|
||||
let sim_h = fs::read_to_string(driver_dir.join("button_sim.h")).unwrap();
|
||||
assert!(sim_h.contains(": public Button"), "ButtonSim should inherit Button");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_add_button_full_flow() {
|
||||
let tmp = TempDir::new().unwrap();
|
||||
let ctx = TemplateContext {
|
||||
project_name: "btn_flow".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 meta = library::find_library("button").unwrap();
|
||||
library::extract_library("button", tmp.path()).unwrap();
|
||||
|
||||
let mut config = ProjectConfig::load(tmp.path()).unwrap();
|
||||
let driver_include = format!("lib/drivers/{}", meta.name);
|
||||
config.build.include_dirs.push(driver_include);
|
||||
config.libraries.insert(meta.name.clone(), meta.version.clone());
|
||||
config.save(tmp.path()).unwrap();
|
||||
|
||||
// Assign a digital pin
|
||||
let dir_str = tmp.path().to_string_lossy().to_string();
|
||||
commands::pin::assign_pin(
|
||||
"button_signal", "2",
|
||||
Some("input"),
|
||||
None,
|
||||
Some(&dir_str),
|
||||
).unwrap();
|
||||
|
||||
let config_after = ProjectConfig::load(tmp.path()).unwrap();
|
||||
assert!(config_after.libraries.contains_key("button"));
|
||||
let board_pins = config_after.pins.get("uno").unwrap();
|
||||
assert!(board_pins.assignments.contains_key("button_signal"));
|
||||
let assignment = &board_pins.assignments["button_signal"];
|
||||
assert_eq!(assignment.mode, "input");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_both_libraries_install_together() {
|
||||
let tmp = TempDir::new().unwrap();
|
||||
let ctx = TemplateContext {
|
||||
project_name: "both_libs".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();
|
||||
|
||||
library::extract_library("tmp36", tmp.path()).unwrap();
|
||||
library::extract_library("button", tmp.path()).unwrap();
|
||||
|
||||
// Both driver directories exist
|
||||
assert!(tmp.path().join("lib/drivers/tmp36").is_dir());
|
||||
assert!(tmp.path().join("lib/drivers/button").is_dir());
|
||||
|
||||
// Both test files exist
|
||||
assert!(tmp.path().join("test/test_tmp36.cpp").exists());
|
||||
assert!(tmp.path().join("test/test_button.cpp").exists());
|
||||
|
||||
// Remove button, tmp36 survives
|
||||
library::remove_library_files("button", tmp.path()).unwrap();
|
||||
assert!(!library::is_installed_on_disk("button", tmp.path()));
|
||||
assert!(library::is_installed_on_disk("tmp36", tmp.path()));
|
||||
assert!(tmp.path().join("test/test_tmp36.cpp").exists());
|
||||
assert!(!tmp.path().join("test/test_button.cpp").exists());
|
||||
}
|
||||
Reference in New Issue
Block a user