Updated tests
This commit is contained in:
@@ -3,7 +3,9 @@ use std::fs;
|
||||
use std::path::Path;
|
||||
|
||||
use anvil::templates::{TemplateManager, TemplateContext};
|
||||
use anvil::project::config::ProjectConfig;
|
||||
use anvil::project::config::{
|
||||
ProjectConfig, BoardProfile, CONFIG_FILENAME, set_default_in_file,
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// Template extraction tests
|
||||
@@ -332,6 +334,467 @@ fn test_config_skips_nonexistent_include_dirs() {
|
||||
assert_eq!(flags.len(), 0, "Should skip non-existent directories");
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Config: default board and [boards.X] structure
|
||||
// ============================================================================
|
||||
|
||||
#[test]
|
||||
fn test_config_default_points_to_boards_section() {
|
||||
let config = ProjectConfig::new("test");
|
||||
assert_eq!(config.build.default, "uno");
|
||||
assert!(
|
||||
config.boards.contains_key("uno"),
|
||||
"boards map should contain the default board"
|
||||
);
|
||||
assert_eq!(config.boards["uno"].fqbn, "arduino:avr:uno");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_config_default_fqbn_resolves() {
|
||||
let config = ProjectConfig::new("test");
|
||||
let fqbn = config.default_fqbn().unwrap();
|
||||
assert_eq!(fqbn, "arduino:avr:uno");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_config_default_board_returns_fqbn_and_baud() {
|
||||
let config = ProjectConfig::new("test");
|
||||
let (fqbn, baud) = config.default_board().unwrap();
|
||||
assert_eq!(fqbn, "arduino:avr:uno");
|
||||
assert_eq!(baud, 115200);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_config_resolve_board_named() {
|
||||
let mut config = ProjectConfig::new("test");
|
||||
config.boards.insert("mega".to_string(), BoardProfile {
|
||||
fqbn: "arduino:avr:mega:cpu=atmega2560".to_string(),
|
||||
baud: Some(57600),
|
||||
});
|
||||
let (fqbn, baud) = config.resolve_board("mega").unwrap();
|
||||
assert_eq!(fqbn, "arduino:avr:mega:cpu=atmega2560");
|
||||
assert_eq!(baud, 57600);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_config_resolve_board_inherits_baud() {
|
||||
let mut config = ProjectConfig::new("test");
|
||||
config.boards.insert("nano".to_string(), BoardProfile {
|
||||
fqbn: "arduino:avr:nano".to_string(),
|
||||
baud: None,
|
||||
});
|
||||
let (_, baud) = config.resolve_board("nano").unwrap();
|
||||
assert_eq!(
|
||||
baud, config.monitor.baud,
|
||||
"Should inherit monitor baud when board has no override"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_config_resolve_board_unknown_fails() {
|
||||
let config = ProjectConfig::new("test");
|
||||
assert!(config.resolve_board("esp32").is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_config_new_with_board_preset() {
|
||||
let config = ProjectConfig::new_with_board(
|
||||
"test", "mega", "arduino:avr:mega:cpu=atmega2560", 115200,
|
||||
);
|
||||
assert_eq!(config.build.default, "mega");
|
||||
assert!(config.boards.contains_key("mega"));
|
||||
assert_eq!(
|
||||
config.boards["mega"].fqbn,
|
||||
"arduino:avr:mega:cpu=atmega2560"
|
||||
);
|
||||
assert!(
|
||||
!config.boards.contains_key("uno"),
|
||||
"Should only contain the specified board"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_config_board_roundtrip() {
|
||||
let tmp = TempDir::new().unwrap();
|
||||
let mut config = ProjectConfig::new("multi");
|
||||
config.boards.insert("mega".to_string(), BoardProfile {
|
||||
fqbn: "arduino:avr:mega:cpu=atmega2560".to_string(),
|
||||
baud: Some(57600),
|
||||
});
|
||||
config.save(tmp.path()).unwrap();
|
||||
|
||||
let loaded = ProjectConfig::load(tmp.path()).unwrap();
|
||||
assert!(loaded.boards.contains_key("mega"));
|
||||
let mega = &loaded.boards["mega"];
|
||||
assert_eq!(mega.fqbn, "arduino:avr:mega:cpu=atmega2560");
|
||||
assert_eq!(mega.baud, Some(57600));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_toml_template_has_default_field() {
|
||||
let tmp = TempDir::new().unwrap();
|
||||
let ctx = TemplateContext {
|
||||
project_name: "default_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 content = fs::read_to_string(tmp.path().join(".anvil.toml")).unwrap();
|
||||
assert!(
|
||||
content.contains("default = \"uno\""),
|
||||
".anvil.toml should have default = \"uno\" in [build]"
|
||||
);
|
||||
assert!(
|
||||
content.contains("[boards.uno]"),
|
||||
".anvil.toml should have a [boards.uno] section"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_toml_template_no_fqbn_in_build_section() {
|
||||
// New configs should NOT have fqbn directly in [build]
|
||||
let tmp = TempDir::new().unwrap();
|
||||
let ctx = TemplateContext {
|
||||
project_name: "no_build_fqbn".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 content = fs::read_to_string(tmp.path().join(".anvil.toml")).unwrap();
|
||||
|
||||
let mut in_build = false;
|
||||
for line in content.lines() {
|
||||
let trimmed = line.trim();
|
||||
if trimmed == "[build]" {
|
||||
in_build = true;
|
||||
continue;
|
||||
}
|
||||
if trimmed.starts_with('[') {
|
||||
in_build = false;
|
||||
}
|
||||
if in_build && !trimmed.starts_with('#') {
|
||||
assert!(
|
||||
!trimmed.starts_with("fqbn"),
|
||||
"[build] section should not contain fqbn; it belongs in [boards.X]"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Config migration: old format -> new format
|
||||
// ============================================================================
|
||||
|
||||
#[test]
|
||||
fn test_migrate_old_config_adds_default_and_boards() {
|
||||
let tmp = TempDir::new().unwrap();
|
||||
let old_config = "\
|
||||
[project]\n\
|
||||
name = \"hand\"\n\
|
||||
anvil_version = \"1.0.0\"\n\
|
||||
\n\
|
||||
[build]\n\
|
||||
fqbn = \"arduino:avr:uno\"\n\
|
||||
warnings = \"more\"\n\
|
||||
include_dirs = [\"lib/hal\", \"lib/app\"]\n\
|
||||
extra_flags = [\"-Werror\"]\n\
|
||||
\n\
|
||||
[monitor]\n\
|
||||
baud = 115200\n\
|
||||
\n\
|
||||
[boards.micro]\n\
|
||||
fqbn = \"arduino:avr:micro\"\n";
|
||||
|
||||
fs::write(tmp.path().join(CONFIG_FILENAME), old_config).unwrap();
|
||||
|
||||
let config = ProjectConfig::load(tmp.path()).unwrap();
|
||||
|
||||
// In-memory state
|
||||
assert_eq!(config.build.default, "uno");
|
||||
assert!(config.boards.contains_key("uno"));
|
||||
assert_eq!(config.boards["uno"].fqbn, "arduino:avr:uno");
|
||||
assert!(config.boards.contains_key("micro"));
|
||||
|
||||
// On-disk file rewritten
|
||||
let content = fs::read_to_string(tmp.path().join(CONFIG_FILENAME)).unwrap();
|
||||
assert!(
|
||||
content.contains("default = \"uno\""),
|
||||
"Migrated file should contain default = \"uno\""
|
||||
);
|
||||
assert!(
|
||||
content.contains("[boards.uno]"),
|
||||
"Migrated file should add [boards.uno] section"
|
||||
);
|
||||
// Old fqbn kept for backward compat with pre-refresh scripts
|
||||
assert!(
|
||||
content.contains("fqbn = \"arduino:avr:uno\""),
|
||||
"Migration should keep old fqbn for backward compat"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_migrate_preserves_comments() {
|
||||
let tmp = TempDir::new().unwrap();
|
||||
let old_config = "\
|
||||
[project]\n\
|
||||
name = \"test\"\n\
|
||||
anvil_version = \"1.0.0\"\n\
|
||||
\n\
|
||||
[build]\n\
|
||||
fqbn = \"arduino:avr:uno\"\n\
|
||||
warnings = \"more\"\n\
|
||||
include_dirs = [\"lib/hal\", \"lib/app\"]\n\
|
||||
extra_flags = [\"-Werror\"]\n\
|
||||
\n\
|
||||
[monitor]\n\
|
||||
baud = 115200\n\
|
||||
# port = \"/dev/ttyUSB0\" # Uncomment to skip auto-detect\n";
|
||||
|
||||
fs::write(tmp.path().join(CONFIG_FILENAME), old_config).unwrap();
|
||||
ProjectConfig::load(tmp.path()).unwrap();
|
||||
|
||||
let content = fs::read_to_string(tmp.path().join(CONFIG_FILENAME)).unwrap();
|
||||
assert!(
|
||||
content.contains("# port = \"/dev/ttyUSB0\""),
|
||||
"Migration should preserve comments"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_migrate_matches_preset_name() {
|
||||
// A mega FQBN should get board name "mega", not "default"
|
||||
let tmp = TempDir::new().unwrap();
|
||||
let old_config = "\
|
||||
[project]\n\
|
||||
name = \"test\"\n\
|
||||
anvil_version = \"1.0.0\"\n\
|
||||
\n\
|
||||
[build]\n\
|
||||
fqbn = \"arduino:avr:mega:cpu=atmega2560\"\n\
|
||||
warnings = \"more\"\n\
|
||||
include_dirs = [\"lib/hal\", \"lib/app\"]\n\
|
||||
extra_flags = [\"-Werror\"]\n\
|
||||
\n\
|
||||
[monitor]\n\
|
||||
baud = 115200\n";
|
||||
|
||||
fs::write(tmp.path().join(CONFIG_FILENAME), old_config).unwrap();
|
||||
|
||||
let config = ProjectConfig::load(tmp.path()).unwrap();
|
||||
assert_eq!(config.build.default, "mega");
|
||||
assert!(config.boards.contains_key("mega"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_migrate_unknown_fqbn_uses_default_name() {
|
||||
let tmp = TempDir::new().unwrap();
|
||||
let old_config = "\
|
||||
[project]\n\
|
||||
name = \"test\"\n\
|
||||
anvil_version = \"1.0.0\"\n\
|
||||
\n\
|
||||
[build]\n\
|
||||
fqbn = \"some:custom:board\"\n\
|
||||
warnings = \"more\"\n\
|
||||
include_dirs = [\"lib/hal\", \"lib/app\"]\n\
|
||||
extra_flags = [\"-Werror\"]\n\
|
||||
\n\
|
||||
[monitor]\n\
|
||||
baud = 115200\n";
|
||||
|
||||
fs::write(tmp.path().join(CONFIG_FILENAME), old_config).unwrap();
|
||||
|
||||
let config = ProjectConfig::load(tmp.path()).unwrap();
|
||||
assert_eq!(config.build.default, "default");
|
||||
assert!(config.boards.contains_key("default"));
|
||||
assert_eq!(config.boards["default"].fqbn, "some:custom:board");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_migrate_skips_if_already_has_default() {
|
||||
let tmp = TempDir::new().unwrap();
|
||||
let new_config = "\
|
||||
[project]\n\
|
||||
name = \"test\"\n\
|
||||
anvil_version = \"1.0.0\"\n\
|
||||
\n\
|
||||
[build]\n\
|
||||
default = \"uno\"\n\
|
||||
warnings = \"more\"\n\
|
||||
include_dirs = [\"lib/hal\", \"lib/app\"]\n\
|
||||
extra_flags = [\"-Werror\"]\n\
|
||||
\n\
|
||||
[monitor]\n\
|
||||
baud = 115200\n\
|
||||
\n\
|
||||
[boards.uno]\n\
|
||||
fqbn = \"arduino:avr:uno\"\n";
|
||||
|
||||
fs::write(tmp.path().join(CONFIG_FILENAME), new_config).unwrap();
|
||||
|
||||
let config = ProjectConfig::load(tmp.path()).unwrap();
|
||||
assert_eq!(config.build.default, "uno");
|
||||
|
||||
// File should be unchanged
|
||||
let content = fs::read_to_string(tmp.path().join(CONFIG_FILENAME)).unwrap();
|
||||
assert_eq!(
|
||||
content, new_config,
|
||||
"New-format config should not be modified"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_migrate_does_not_duplicate_board_section() {
|
||||
// If [boards.uno] already exists, migration should not add a second one
|
||||
let tmp = TempDir::new().unwrap();
|
||||
let old_config = "\
|
||||
[project]\n\
|
||||
name = \"test\"\n\
|
||||
anvil_version = \"1.0.0\"\n\
|
||||
\n\
|
||||
[build]\n\
|
||||
fqbn = \"arduino:avr:uno\"\n\
|
||||
warnings = \"more\"\n\
|
||||
include_dirs = [\"lib/hal\", \"lib/app\"]\n\
|
||||
extra_flags = [\"-Werror\"]\n\
|
||||
\n\
|
||||
[monitor]\n\
|
||||
baud = 115200\n\
|
||||
\n\
|
||||
[boards.uno]\n\
|
||||
fqbn = \"arduino:avr:uno\"\n";
|
||||
|
||||
fs::write(tmp.path().join(CONFIG_FILENAME), old_config).unwrap();
|
||||
ProjectConfig::load(tmp.path()).unwrap();
|
||||
|
||||
let content = fs::read_to_string(tmp.path().join(CONFIG_FILENAME)).unwrap();
|
||||
let count = content.matches("[boards.uno]").count();
|
||||
assert_eq!(count, 1, "Should not duplicate [boards.uno] section");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_migrate_default_appears_before_fqbn() {
|
||||
// After migration, default = "..." should come before fqbn = "..."
|
||||
// in [build] for natural reading order.
|
||||
let tmp = TempDir::new().unwrap();
|
||||
let old_config = "\
|
||||
[project]\n\
|
||||
name = \"test\"\n\
|
||||
anvil_version = \"1.0.0\"\n\
|
||||
\n\
|
||||
[build]\n\
|
||||
fqbn = \"arduino:avr:uno\"\n\
|
||||
warnings = \"more\"\n\
|
||||
include_dirs = [\"lib/hal\", \"lib/app\"]\n\
|
||||
extra_flags = [\"-Werror\"]\n\
|
||||
\n\
|
||||
[monitor]\n\
|
||||
baud = 115200\n";
|
||||
|
||||
fs::write(tmp.path().join(CONFIG_FILENAME), old_config).unwrap();
|
||||
ProjectConfig::load(tmp.path()).unwrap();
|
||||
|
||||
let content = fs::read_to_string(tmp.path().join(CONFIG_FILENAME)).unwrap();
|
||||
let default_pos = content.find("default = ").expect("should have default");
|
||||
let fqbn_pos = content.find("fqbn = ").expect("should have fqbn");
|
||||
assert!(
|
||||
default_pos < fqbn_pos,
|
||||
"default should appear before fqbn in [build] section"
|
||||
);
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// set_default_in_file: text-based config editing
|
||||
// ============================================================================
|
||||
|
||||
#[test]
|
||||
fn test_set_default_replaces_existing() {
|
||||
let tmp = TempDir::new().unwrap();
|
||||
let config = ProjectConfig::new("test");
|
||||
config.save(tmp.path()).unwrap();
|
||||
|
||||
let config_path = tmp.path().join(CONFIG_FILENAME);
|
||||
let old = set_default_in_file(&config_path, "mega").unwrap();
|
||||
assert_eq!(old, "uno");
|
||||
|
||||
let content = fs::read_to_string(&config_path).unwrap();
|
||||
assert!(content.contains("default = \"mega\""));
|
||||
assert!(!content.contains("default = \"uno\""));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_set_default_adds_when_missing() {
|
||||
let tmp = TempDir::new().unwrap();
|
||||
let content = "\
|
||||
[project]\n\
|
||||
name = \"test\"\n\
|
||||
anvil_version = \"1.0.0\"\n\
|
||||
\n\
|
||||
[build]\n\
|
||||
warnings = \"more\"\n\
|
||||
include_dirs = [\"lib/hal\", \"lib/app\"]\n\
|
||||
extra_flags = [\"-Werror\"]\n\
|
||||
\n\
|
||||
[monitor]\n\
|
||||
baud = 115200\n\
|
||||
\n\
|
||||
[boards.uno]\n\
|
||||
fqbn = \"arduino:avr:uno\"\n";
|
||||
|
||||
let config_path = tmp.path().join(CONFIG_FILENAME);
|
||||
fs::write(&config_path, content).unwrap();
|
||||
|
||||
let old = set_default_in_file(&config_path, "uno").unwrap();
|
||||
assert_eq!(old, "", "Should return empty string when no previous default");
|
||||
|
||||
let result = fs::read_to_string(&config_path).unwrap();
|
||||
assert!(result.contains("default = \"uno\""));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_set_default_is_idempotent() {
|
||||
let tmp = TempDir::new().unwrap();
|
||||
let config = ProjectConfig::new("test");
|
||||
config.save(tmp.path()).unwrap();
|
||||
|
||||
let config_path = tmp.path().join(CONFIG_FILENAME);
|
||||
|
||||
set_default_in_file(&config_path, "mega").unwrap();
|
||||
let content_after_first = fs::read_to_string(&config_path).unwrap();
|
||||
|
||||
set_default_in_file(&config_path, "mega").unwrap();
|
||||
let content_after_second = fs::read_to_string(&config_path).unwrap();
|
||||
|
||||
assert_eq!(
|
||||
content_after_first, content_after_second,
|
||||
"Second set should not change file"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_set_default_preserves_other_fields() {
|
||||
let tmp = TempDir::new().unwrap();
|
||||
let config = ProjectConfig::new("test");
|
||||
config.save(tmp.path()).unwrap();
|
||||
|
||||
let config_path = tmp.path().join(CONFIG_FILENAME);
|
||||
set_default_in_file(&config_path, "mega").unwrap();
|
||||
|
||||
// Reload and check nothing else broke
|
||||
let loaded = ProjectConfig::load(tmp.path()).unwrap();
|
||||
assert_eq!(loaded.build.default, "mega");
|
||||
assert_eq!(loaded.build.warnings, "more");
|
||||
assert_eq!(loaded.project.name, "test");
|
||||
assert_eq!(loaded.monitor.baud, 115200);
|
||||
assert!(loaded.build.include_dirs.contains(&"lib/hal".to_string()));
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Full project creation test (end-to-end in temp dir)
|
||||
// ============================================================================
|
||||
@@ -1074,7 +1537,15 @@ fn test_board_preset_fqbn_in_config() {
|
||||
let config = ProjectConfig::load(tmp.path()).unwrap();
|
||||
assert_eq!(
|
||||
config.build.default, "mega",
|
||||
".anvil.toml should contain mega FQBN"
|
||||
".anvil.toml should have default = mega"
|
||||
);
|
||||
assert!(
|
||||
config.boards.contains_key("mega"),
|
||||
".anvil.toml should have [boards.mega]"
|
||||
);
|
||||
assert_eq!(
|
||||
config.boards["mega"].fqbn, "arduino:avr:mega:cpu=atmega2560",
|
||||
"[boards.mega] should have the correct FQBN"
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1195,3 +1666,203 @@ fn test_toml_template_has_board_profile_comments() {
|
||||
".anvil.toml should show board profile examples in comments"
|
||||
);
|
||||
}
|
||||
|
||||
// ==========================================================================
|
||||
// Scripts read default board from [build] section
|
||||
// ==========================================================================
|
||||
|
||||
#[test]
|
||||
fn test_scripts_read_default_board() {
|
||||
let tmp = TempDir::new().unwrap();
|
||||
let ctx = TemplateContext {
|
||||
project_name: "default_read".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();
|
||||
|
||||
for script in &["build.sh", "upload.sh", "monitor.sh"] {
|
||||
let content = fs::read_to_string(tmp.path().join(script)).unwrap();
|
||||
assert!(
|
||||
content.contains("DEFAULT_BOARD") && content.contains("'default'"),
|
||||
"{} should read 'default' field from .anvil.toml into DEFAULT_BOARD",
|
||||
script
|
||||
);
|
||||
assert!(
|
||||
content.contains("ACTIVE_BOARD"),
|
||||
"{} should resolve ACTIVE_BOARD from DEFAULT_BOARD or --board flag",
|
||||
script
|
||||
);
|
||||
}
|
||||
|
||||
for bat in &["build.bat", "upload.bat", "monitor.bat"] {
|
||||
let content = fs::read_to_string(tmp.path().join(bat)).unwrap();
|
||||
assert!(
|
||||
content.contains("DEFAULT_BOARD"),
|
||||
"{} should read default field into DEFAULT_BOARD",
|
||||
bat
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// ==========================================================================
|
||||
// USB_VID/USB_PID fix: compiler.cpp.extra_flags (not build.extra_flags)
|
||||
// ==========================================================================
|
||||
|
||||
#[test]
|
||||
fn test_scripts_use_compiler_extra_flags_not_build() {
|
||||
// Regression: build.extra_flags clobbers board defaults (USB_VID, USB_PID)
|
||||
// on ATmega32U4 boards (Micro, Leonardo). Scripts must use
|
||||
// compiler.cpp.extra_flags and compiler.c.extra_flags instead,
|
||||
// which are additive.
|
||||
let tmp = TempDir::new().unwrap();
|
||||
let ctx = TemplateContext {
|
||||
project_name: "usb_fix".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 compile_scripts = vec![
|
||||
"build.sh", "build.bat",
|
||||
"upload.sh", "upload.bat",
|
||||
];
|
||||
|
||||
for script in &compile_scripts {
|
||||
let content = fs::read_to_string(tmp.path().join(script)).unwrap();
|
||||
assert!(
|
||||
!content.contains("build.extra_flags"),
|
||||
"{} must NOT use build.extra_flags (clobbers USB_VID/USB_PID on ATmega32U4)",
|
||||
script
|
||||
);
|
||||
assert!(
|
||||
content.contains("compiler.cpp.extra_flags"),
|
||||
"{} should use compiler.cpp.extra_flags (additive, USB-safe)",
|
||||
script
|
||||
);
|
||||
assert!(
|
||||
content.contains("compiler.c.extra_flags"),
|
||||
"{} should use compiler.c.extra_flags (additive, USB-safe)",
|
||||
script
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_monitor_scripts_have_no_compile_flags() {
|
||||
// monitor.sh and monitor.bat should NOT contain any compile flags
|
||||
// since they don't compile anything.
|
||||
let tmp = TempDir::new().unwrap();
|
||||
let ctx = TemplateContext {
|
||||
project_name: "mon_flags".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();
|
||||
|
||||
for script in &["monitor.sh", "monitor.bat"] {
|
||||
let content = fs::read_to_string(tmp.path().join(script)).unwrap();
|
||||
assert!(
|
||||
!content.contains("compiler.cpp.extra_flags")
|
||||
&& !content.contains("compiler.c.extra_flags")
|
||||
&& !content.contains("build.extra_flags"),
|
||||
"{} should not contain any compile flags",
|
||||
script
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// ==========================================================================
|
||||
// Script error messages: helpful guidance without requiring anvil
|
||||
// ==========================================================================
|
||||
|
||||
#[test]
|
||||
fn test_script_errors_show_manual_fix() {
|
||||
// Error messages should explain how to fix .anvil.toml by hand,
|
||||
// since the project is self-contained and anvil may not be installed.
|
||||
let tmp = TempDir::new().unwrap();
|
||||
let ctx = TemplateContext {
|
||||
project_name: "err_msg".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 all_scripts = vec![
|
||||
"build.sh", "build.bat",
|
||||
"upload.sh", "upload.bat",
|
||||
"monitor.sh", "monitor.bat",
|
||||
];
|
||||
|
||||
for script in &all_scripts {
|
||||
let content = fs::read_to_string(tmp.path().join(script)).unwrap();
|
||||
assert!(
|
||||
content.contains("default = "),
|
||||
"{} error messages should show the manual fix (default = \"...\")",
|
||||
script
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_script_errors_mention_arduino_cli() {
|
||||
// Error messages should mention arduino-cli board listall as a
|
||||
// discovery option, since the project doesn't require anvil.
|
||||
let tmp = TempDir::new().unwrap();
|
||||
let ctx = TemplateContext {
|
||||
project_name: "cli_err".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 all_scripts = vec![
|
||||
"build.sh", "build.bat",
|
||||
"upload.sh", "upload.bat",
|
||||
"monitor.sh", "monitor.bat",
|
||||
];
|
||||
|
||||
for script in &all_scripts {
|
||||
let content = fs::read_to_string(tmp.path().join(script)).unwrap();
|
||||
assert!(
|
||||
content.contains("arduino-cli board listall"),
|
||||
"{} error messages should mention 'arduino-cli board listall' for board discovery",
|
||||
script
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_script_errors_mention_toml_section_syntax() {
|
||||
// The "board not found" error in build/upload scripts should show
|
||||
// the [boards.X] section syntax so users know exactly what to add.
|
||||
let tmp = TempDir::new().unwrap();
|
||||
let ctx = TemplateContext {
|
||||
project_name: "section_err".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();
|
||||
|
||||
// build and upload scripts have both no-default and board-not-found errors
|
||||
for script in &["build.sh", "build.bat", "upload.sh", "upload.bat"] {
|
||||
let content = fs::read_to_string(tmp.path().join(script)).unwrap();
|
||||
assert!(
|
||||
content.contains("[boards."),
|
||||
"{} board-not-found error should show [boards.X] section syntax",
|
||||
script
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user