From 85a004e263df5382780fa82d1a9b4e8c2165b50e Mon Sep 17 00:00:00 2001 From: Bossiara13 <236771060+DmitryBykov-ISPO@users.noreply.github.com> Date: Fri, 15 May 2026 00:55:01 +0300 Subject: [PATCH] test(commands): schema and Lua script validation for resources/commands/ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Three unit tests catch the kind of bug that broke weather/set_city (a phrases array instead of lang→array map silently dropped the whole pack): - every_command_toml_parses: every resources/commands/*/command.toml round- trips through toml::from_str::. Reports all failures at once instead of failing on the first. - lua_command_scripts_exist: for every type="lua" command, the named (or default script.lua) script file exists in the pack dir. - every_command_has_phrases: structural commands (terminate/stop_chaining) excluded, every other command has ≥1 phrase across all languages. Tests use env!("CARGO_MANIFEST_DIR") -> ../.. -> resources/commands so they work from any cwd. NB: cargo test does not run on this machine right now — aws-lc-sys needs cl.exe (MSVC Build Tools missing). The release binary was built earlier with MSVC available; toolchain install is a follow-up. The tests are still valid for CI / a re-armed dev box. --- crates/jarvis-core/src/commands.rs | 106 +++++++++++++++++++++++++++++ 1 file changed, 106 insertions(+) diff --git a/crates/jarvis-core/src/commands.rs b/crates/jarvis-core/src/commands.rs index c250cd0..ae1c133 100644 --- a/crates/jarvis-core/src/commands.rs +++ b/crates/jarvis-core/src/commands.rs @@ -266,6 +266,112 @@ pub fn list_paths(commands: &[JCommandsList]) -> Vec<&Path> { commands.iter().map(|x| x.path.as_path()).collect() } +#[cfg(test)] +mod tests { + use super::*; + + fn resources_commands_dir() -> PathBuf { + Path::new(env!("CARGO_MANIFEST_DIR")) + .parent().unwrap() + .parent().unwrap() + .join("resources/commands") + } + + #[test] + fn every_command_toml_parses() { + let cmds_dir = resources_commands_dir(); + assert!(cmds_dir.is_dir(), "missing {}", cmds_dir.display()); + + let mut failures = Vec::new(); + let mut packs_seen = 0; + + for entry in fs::read_dir(&cmds_dir).expect("read_dir") { + let entry = entry.expect("entry"); + let toml_file = entry.path().join("command.toml"); + if !toml_file.exists() { + continue; + } + packs_seen += 1; + let body = fs::read_to_string(&toml_file).expect("read"); + if let Err(e) = toml::from_str::(&body) { + failures.push(format!("{}: {}", toml_file.display(), e)); + } + } + + assert!(packs_seen > 0, "no command packs found in {}", cmds_dir.display()); + assert!( + failures.is_empty(), + "parse failures ({}):\n{}", + failures.len(), + failures.join("\n") + ); + } + + #[test] + fn lua_command_scripts_exist() { + let cmds_dir = resources_commands_dir(); + let mut missing = Vec::new(); + + for entry in fs::read_dir(&cmds_dir).expect("read_dir") { + let entry = entry.expect("entry"); + let pack_path = entry.path(); + let toml_file = pack_path.join("command.toml"); + if !toml_file.exists() { + continue; + } + let body = fs::read_to_string(&toml_file).expect("read"); + let pack: JCommandsList = toml::from_str(&body).expect("parse"); + for cmd in &pack.commands { + if cmd.cmd_type != "lua" { + continue; + } + let script = if cmd.script.is_empty() { + "script.lua".to_string() + } else { + cmd.script.clone() + }; + let script_path = pack_path.join(&script); + if !script_path.exists() { + missing.push(format!( + "{} -> {} (missing)", + cmd.id, + script_path.display() + )); + } + } + } + + assert!(missing.is_empty(), "missing Lua scripts:\n{}", missing.join("\n")); + } + + #[test] + fn every_command_has_phrases() { + let cmds_dir = resources_commands_dir(); + let mut empty = Vec::new(); + + for entry in fs::read_dir(&cmds_dir).expect("read_dir") { + let toml_file = entry.expect("entry").path().join("command.toml"); + if !toml_file.exists() { + continue; + } + let body = fs::read_to_string(&toml_file).expect("read"); + let pack: JCommandsList = toml::from_str(&body).expect("parse"); + for cmd in &pack.commands { + // structural commands (terminate, stop_chaining) may omit phrases + if cmd.cmd_type == "terminate" || cmd.cmd_type == "stop_chaining" { + continue; + } + let total: usize = cmd.phrases.values().map(|v| v.len()).sum(); + if total == 0 { + empty.push(cmd.id.clone()); + } + } + } + + assert!(empty.is_empty(), "commands with no phrases: {:?}", empty); + } +} + #[cfg(feature = "lua")] fn execute_lua_command( cmd_path: &PathBuf,