From 70f12e5df9b89592478a548343b325931d5af4cd Mon Sep 17 00:00:00 2001 From: Chummy Date: Fri, 20 Feb 2026 16:13:20 +0800 Subject: [PATCH] test(onboard): add regression coverage for quick setup model override --- docs/commands-reference.md | 1 + src/main.rs | 53 +++++++++++++++++++++++++++++- src/onboard/wizard.rs | 67 ++++++++++++++++++++++++++++++++++++-- 3 files changed, 117 insertions(+), 4 deletions(-) diff --git a/docs/commands-reference.md b/docs/commands-reference.md index a693c81..da9d52c 100644 --- a/docs/commands-reference.md +++ b/docs/commands-reference.md @@ -34,6 +34,7 @@ Last verified: **February 19, 2026**. - `zeroclaw onboard --interactive` - `zeroclaw onboard --channels-only` - `zeroclaw onboard --api-key --provider --memory ` +- `zeroclaw onboard --api-key --provider --model --memory ` ### `agent` diff --git a/src/main.rs b/src/main.rs index 414a4f5..44df971 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1352,10 +1352,61 @@ async fn handle_auth_command(auth_command: AuthCommands, config: &Config) -> Res #[cfg(test)] mod tests { use super::*; - use clap::CommandFactory; + use clap::{CommandFactory, Parser}; #[test] fn cli_definition_has_no_flag_conflicts() { Cli::command().debug_assert(); } + + #[test] + fn onboard_help_includes_model_flag() { + let cmd = Cli::command(); + let onboard = cmd + .get_subcommands() + .find(|subcommand| subcommand.get_name() == "onboard") + .expect("onboard subcommand must exist"); + + let has_model_flag = onboard + .get_arguments() + .any(|arg| arg.get_id().as_str() == "model" && arg.get_long() == Some("model")); + + assert!( + has_model_flag, + "onboard help should include --model for quick setup overrides" + ); + } + + #[test] + fn onboard_cli_accepts_model_provider_and_api_key_in_quick_mode() { + let cli = Cli::try_parse_from([ + "zeroclaw", + "onboard", + "--provider", + "openrouter", + "--model", + "custom-model-946", + "--api-key", + "sk-issue946", + ]) + .expect("quick onboard invocation should parse"); + + match cli.command { + Commands::Onboard { + interactive, + channels_only, + api_key, + provider, + model, + .. + } => { + assert!(!interactive); + assert!(!channels_only); + assert_eq!(provider.as_deref(), Some("openrouter")); + assert_eq!(model.as_deref(), Some("custom-model-946")); + assert_eq!(api_key.as_deref(), Some("sk-issue946")); + } + other => panic!("expected onboard command, got {other:?}"), + } + } } diff --git a/src/onboard/wizard.rs b/src/onboard/wizard.rs index efbec13..7966e7d 100644 --- a/src/onboard/wizard.rs +++ b/src/onboard/wizard.rs @@ -331,6 +331,28 @@ pub async fn run_quick_setup( provider: Option<&str>, model_override: Option<&str>, memory_backend: Option<&str>, +) -> Result { + let home = directories::UserDirs::new() + .map(|u| u.home_dir().to_path_buf()) + .context("Could not find home directory")?; + + run_quick_setup_with_home( + credential_override, + provider, + model_override, + memory_backend, + &home, + ) + .await +} + +#[allow(clippy::too_many_lines)] +async fn run_quick_setup_with_home( + credential_override: Option<&str>, + provider: Option<&str>, + model_override: Option<&str>, + memory_backend: Option<&str>, + home: &Path, ) -> Result { println!("{}", style(BANNER).cyan().bold()); println!( @@ -341,9 +363,6 @@ pub async fn run_quick_setup( ); println!(); - let home = directories::UserDirs::new() - .map(|u| u.home_dir().to_path_buf()) - .context("Could not find home directory")?; let zeroclaw_dir = home.join(".zeroclaw"); let workspace_dir = zeroclaw_dir.join("workspace"); let config_path = zeroclaw_dir.join("config.toml"); @@ -4673,6 +4692,48 @@ mod tests { assert!(ctx.communication_style.is_empty()); } + #[tokio::test] + async fn quick_setup_model_override_persists_to_config_toml() { + let tmp = TempDir::new().unwrap(); + + let config = run_quick_setup_with_home( + Some("sk-issue946"), + Some("openrouter"), + Some("custom-model-946"), + Some("sqlite"), + tmp.path(), + ) + .await + .unwrap(); + + assert_eq!(config.default_provider.as_deref(), Some("openrouter")); + assert_eq!(config.default_model.as_deref(), Some("custom-model-946")); + assert_eq!(config.api_key.as_deref(), Some("sk-issue946")); + + let config_raw = tokio::fs::read_to_string(config.config_path).await.unwrap(); + assert!(config_raw.contains("default_provider = \"openrouter\"")); + assert!(config_raw.contains("default_model = \"custom-model-946\"")); + } + + #[tokio::test] + async fn quick_setup_without_model_uses_provider_default_model() { + let tmp = TempDir::new().unwrap(); + + let config = run_quick_setup_with_home( + Some("sk-issue946"), + Some("anthropic"), + None, + Some("sqlite"), + tmp.path(), + ) + .await + .unwrap(); + + let expected = default_model_for_provider("anthropic"); + assert_eq!(config.default_provider.as_deref(), Some("anthropic")); + assert_eq!(config.default_model.as_deref(), Some(expected.as_str())); + } + // ── scaffold_workspace: basic file creation ───────────────── #[test]