use super::*;
#[test]
fn test_parses_provider_capabilities_audit_json() {
let cli = Cli::parse_from(["harn", "provider", "capabilities", "audit", "--json"]);
let Command::Provider(args) = cli.command.unwrap() else {
panic!("expected provider command");
};
let ProviderCommand::Capabilities(capabilities) = args.command;
let ProviderCapabilitiesCommand::Audit(audit) = capabilities.command else {
panic!("expected audit command");
};
assert!(audit.json);
}
#[test]
fn test_parses_provider_capabilities_promote_from_eval() {
let cli = Cli::parse_from([
"harn",
"provider",
"capabilities",
"promote-from-eval",
"overlay.toml",
"--catalog",
"custom-capabilities.toml",
]);
let Command::Provider(args) = cli.command.unwrap() else {
panic!("expected provider command");
};
let ProviderCommand::Capabilities(capabilities) = args.command;
let ProviderCapabilitiesCommand::PromoteFromEval(promote) = capabilities.command else {
panic!("expected promote-from-eval command");
};
assert_eq!(promote.overlay_path, PathBuf::from("overlay.toml"));
assert_eq!(promote.catalog, PathBuf::from("custom-capabilities.toml"));
}
#[test]
fn test_parses_mcp_login_flags() {
let cli = Cli::parse_from([
"harn",
"mcp",
"login",
"notion",
"--url",
"https://example.com/mcp",
"--client-id",
"abc",
]);
let Command::Mcp(args) = cli.command.unwrap() else {
panic!("expected mcp command");
};
let McpCommand::Login(login) = args.command else {
panic!("expected mcp login");
};
assert_eq!(login.target.as_deref(), Some("notion"));
assert_eq!(login.url.as_deref(), Some("https://example.com/mcp"));
assert_eq!(login.client_id.as_deref(), Some("abc"));
}
#[test]
fn test_parses_connect_oauth_flags() {
let cli = Cli::parse_from([
"harn",
"connect",
"slack",
"--client-id",
"client",
"--client-secret",
"secret",
"--scope",
"chat:write app_mentions:read",
"--no-open",
]);
let Command::Connect(args) = cli.command.unwrap() else {
panic!("expected connect command");
};
let Some(ConnectCommand::Slack(slack)) = args.command else {
panic!("expected connect slack");
};
assert_eq!(slack.client_id.as_deref(), Some("client"));
assert_eq!(slack.client_secret.as_deref(), Some("secret"));
assert_eq!(slack.scope.as_deref(), Some("chat:write app_mentions:read"));
assert!(slack.no_open);
let cli = Cli::parse_from([
"harn",
"connect",
"linear",
"--client-id",
"linear-client",
"--client-secret",
"linear-secret",
]);
let Command::Connect(args) = cli.command.unwrap() else {
panic!("expected connect command");
};
let Some(ConnectCommand::Linear(linear)) = args.command else {
panic!("expected connect linear");
};
assert!(linear.url.is_none());
assert_eq!(linear.client_id.as_deref(), Some("linear-client"));
let cli = Cli::parse_from([
"harn",
"connect",
"acme",
"--client-id",
"acme-client",
"--scope",
"tickets.read",
"--no-open",
]);
let Command::Connect(args) = cli.command.unwrap() else {
panic!("expected connect command");
};
let Some(ConnectCommand::Provider(raw)) = args.command else {
panic!("expected external provider connect command");
};
assert_eq!(
raw,
vec![
"acme".to_string(),
"--client-id".to_string(),
"acme-client".to_string(),
"--scope".to_string(),
"tickets.read".to_string(),
"--no-open".to_string()
]
);
}
#[test]
fn test_parses_connect_management_flags() {
let cli = Cli::parse_from(["harn", "connect", "--list", "--json"]);
let Command::Connect(args) = cli.command.unwrap() else {
panic!("expected connect command");
};
assert!(args.list);
assert!(args.json);
assert!(args.command.is_none());
let cli = Cli::parse_from([
"harn",
"connect",
"--generic",
"acme",
"https://mcp.example.com/mcp",
]);
let Command::Connect(args) = cli.command.unwrap() else {
panic!("expected connect command");
};
assert_eq!(args.generic, vec!["acme", "https://mcp.example.com/mcp"]);
}
#[test]
fn test_parses_mcp_serve_flags() {
let cli = Cli::parse_from([
"harn",
"mcp",
"serve",
"--config",
"workspace/harn.toml",
"--state-dir",
"state/orchestrator",
"--transport",
"http",
"--bind",
"127.0.0.1:9000",
"--path",
"/rpc",
"--sse-path",
"/events",
"--messages-path",
"/legacy/messages",
]);
let Command::Mcp(args) = cli.command.unwrap() else {
panic!("expected mcp command");
};
let McpCommand::Serve(serve) = args.command else {
panic!("expected mcp serve");
};
assert_eq!(serve.local.config, PathBuf::from("workspace/harn.toml"));
assert_eq!(serve.local.state_dir, PathBuf::from("state/orchestrator"));
assert_eq!(serve.transport, crate::cli::McpServeTransport::Http);
assert_eq!(serve.bind.to_string(), "127.0.0.1:9000");
assert_eq!(serve.path, "/rpc");
assert_eq!(serve.sse_path, "/events");
assert_eq!(serve.messages_path, "/legacy/messages");
}
#[test]
fn test_parses_mcp_mock_commands() {
let cli = Cli::parse_from([
"harn",
"mcp",
"mock",
"record",
"--cassette",
"cassette.json",
"--",
"python3",
"server.py",
]);
let Command::Mcp(args) = cli.command.unwrap() else {
panic!("expected mcp command");
};
let McpCommand::Mock(mock) = args.command else {
panic!("expected mcp mock");
};
let McpMockCommand::Record(record) = mock.command else {
panic!("expected mcp mock record");
};
assert_eq!(record.cassette, "cassette.json");
assert_eq!(record.command, vec!["python3", "server.py"]);
let cli = Cli::parse_from([
"harn",
"mcp",
"mock",
"eval",
"--spec",
"world.json",
"--state",
"run1.json",
"--state",
"run2.json",
]);
let Command::Mcp(args) = cli.command.unwrap() else {
panic!("expected mcp command");
};
let McpCommand::Mock(mock) = args.command else {
panic!("expected mcp mock");
};
let McpMockCommand::Eval(eval) = mock.command else {
panic!("expected mcp mock eval");
};
assert_eq!(eval.spec, "world.json");
assert_eq!(eval.states, vec!["run1.json", "run2.json"]);
}
#[test]
fn test_parses_connector_test_args() {
let cli = Cli::parse_from([
"harn",
"connector",
"test",
"pkg",
"--provider",
"notion",
"--run-poll-tick",
"--json",
]);
let Command::Connector(args) = cli.command.unwrap() else {
panic!("expected connector command");
};
let ConnectorCommand::Test(test) = args.command else {
panic!("expected connector test");
};
assert_eq!(test.package, "pkg");
assert_eq!(test.providers, vec!["notion"]);
assert!(test.run_poll_tick);
assert!(test.json);
}
#[test]
fn test_parses_viz_args() {
let cli = Cli::parse_from(["harn", "viz", "main.harn", "--output", "graph.mmd"]);
let Command::Viz(args) = cli.command.unwrap() else {
panic!("expected viz command");
};
assert_eq!(args.file, "main.harn");
assert_eq!(args.output.as_deref(), Some("graph.mmd"));
}
#[test]
fn test_parses_model_info_args() {
let cli = Cli::parse_from([
"harn",
"model-info",
"--verify",
"--warm",
"--keep-alive",
"forever",
"tog-gemma4-31b",
]);
let Command::ModelInfo(args) = cli.command.unwrap() else {
panic!("expected model-info command");
};
assert_eq!(args.model, "tog-gemma4-31b");
assert!(args.verify);
assert!(args.warm);
assert_eq!(args.keep_alive.as_deref(), Some("forever"));
}
#[test]
fn test_parses_models_test_args() {
let cli = Cli::parse_from([
"harn",
"models",
"test",
"qwen3:30b",
"--provider",
"ollama",
"--prompt",
"say pong",
"--json",
]);
let Command::Models(args) = cli.command.unwrap() else {
panic!("expected models command");
};
let ModelsCommand::Test(args) = args.command else {
panic!("expected models test command");
};
assert_eq!(args.model, "qwen3:30b");
assert_eq!(args.provider.as_deref(), Some("ollama"));
assert_eq!(args.prompt, "say pong");
assert!(args.json);
}
#[test]
fn test_parses_providers_refresh_args() {
let cli = Cli::parse_from([
"harn",
"providers",
"refresh",
"--live",
"--check",
"--script",
"scripts/update_provider_catalog.harn",
]);
let Command::Providers(args) = cli.command.unwrap() else {
panic!("expected providers command");
};
let ProvidersCommand::Refresh(args) = args.command else {
panic!("expected providers refresh command");
};
assert!(args.live);
assert!(args.check);
assert!(!args.update);
assert_eq!(
args.script,
std::path::PathBuf::from("scripts/update_provider_catalog.harn")
);
}
#[test]
fn test_parses_providers_validate_args() {
let cli = Cli::parse_from([
"harn",
"providers",
"validate",
"--overlay",
"providers.local.toml",
"--check-artifacts",
"--artifact-dir",
"spec/provider-catalog",
"--json",
]);
let Command::Providers(args) = cli.command.unwrap() else {
panic!("expected providers command");
};
let ProvidersCommand::Validate(args) = args.command else {
panic!("expected providers validate command");
};
assert_eq!(
args.overlay.as_deref(),
Some(std::path::Path::new("providers.local.toml"))
);
assert!(args.check_artifacts);
assert_eq!(
args.artifact_dir,
std::path::PathBuf::from("spec/provider-catalog")
);
assert!(args.json);
}
#[test]
fn test_parses_providers_export_args() {
let cli = Cli::parse_from([
"harn",
"providers",
"export",
"--output-dir",
"tmp/catalog",
"--check",
]);
let Command::Providers(args) = cli.command.unwrap() else {
panic!("expected providers command");
};
let ProvidersCommand::Export(args) = args.command else {
panic!("expected providers export command");
};
assert_eq!(args.output_dir, std::path::PathBuf::from("tmp/catalog"));
assert!(args.check);
}
#[test]
fn test_parses_providers_build_config_args() {
let cli = Cli::parse_from([
"harn",
"providers",
"build-config",
"--source-dir",
"tmp/catalog_sources",
"--output",
"tmp/providers.toml",
"--check",
]);
let Command::Providers(args) = cli.command.unwrap() else {
panic!("expected providers command");
};
let ProvidersCommand::BuildConfig(args) = args.command else {
panic!("expected providers build-config command");
};
assert_eq!(
args.source_dir,
std::path::PathBuf::from("tmp/catalog_sources")
);
assert_eq!(args.output, std::path::PathBuf::from("tmp/providers.toml"));
assert!(args.check);
}
#[test]
fn test_parses_providers_build_capabilities_args() {
let cli = Cli::parse_from([
"harn",
"providers",
"build-capabilities",
"--source-dir",
"tmp/capability_sources",
"--output",
"tmp/capabilities.toml",
"--check",
]);
let Command::Providers(args) = cli.command.unwrap() else {
panic!("expected providers command");
};
let ProvidersCommand::BuildCapabilities(args) = args.command else {
panic!("expected providers build-capabilities command");
};
assert_eq!(
args.source_dir,
std::path::PathBuf::from("tmp/capability_sources")
);
assert_eq!(
args.output,
std::path::PathBuf::from("tmp/capabilities.toml")
);
assert!(args.check);
}
#[test]
fn test_parses_providers_matrix_args() {
let cli = Cli::parse_from([
"harn",
"providers",
"matrix",
"--output",
"tmp/provider-matrix.md",
"--check",
"--stdout",
"--filter",
"native_tools",
]);
let Command::Providers(args) = cli.command.unwrap() else {
panic!("expected providers command");
};
let ProvidersCommand::Matrix(args) = args.command else {
panic!("expected providers matrix command");
};
assert_eq!(
args.output,
std::path::PathBuf::from("tmp/provider-matrix.md")
);
assert!(args.check);
assert!(args.stdout);
assert_eq!(args.filter.as_deref(), Some("native_tools"));
}
#[test]
fn test_parses_providers_support_args() {
let cli = Cli::parse_from([
"harn",
"providers",
"support",
"--output",
"tmp/provider-support.md",
"--json-output",
"tmp/provider-support.json",
"--notes",
"provider_support_notes.toml",
"--empirical",
"summary.json",
"--check",
]);
let Command::Providers(args) = cli.command.unwrap() else {
panic!("expected providers command");
};
let ProvidersCommand::Support(args) = args.command else {
panic!("expected providers support command");
};
assert_eq!(
args.output,
std::path::PathBuf::from("tmp/provider-support.md")
);
assert_eq!(
args.json_output,
std::path::PathBuf::from("tmp/provider-support.json")
);
assert_eq!(
args.notes,
std::path::PathBuf::from("provider_support_notes.toml")
);
assert_eq!(
args.empirical,
vec![std::path::PathBuf::from("summary.json")]
);
assert!(args.check);
}
#[test]
fn test_parses_provider_catalog_args() {
let cli = Cli::parse_from(["harn", "provider-catalog", "--available-only", "--refresh"]);
let Command::ProviderCatalog(args) = cli.command.unwrap() else {
panic!("expected provider-catalog command");
};
assert!(args.available_only);
assert!(args.refresh);
}
#[test]
fn test_parses_provider_ready_args() {
let cli = Cli::parse_from([
"harn",
"provider-ready",
"mlx",
"--model",
"mlx-qwen36-27b",
"--base-url",
"http://127.0.0.1:8002",
"--json",
]);
let Command::ProviderReady(args) = cli.command.unwrap() else {
panic!("expected provider-ready command");
};
assert_eq!(args.provider, "mlx");
assert_eq!(args.model.as_deref(), Some("mlx-qwen36-27b"));
assert_eq!(args.base_url.as_deref(), Some("http://127.0.0.1:8002"));
assert!(args.json);
}
#[test]
fn test_parses_provider_probe_args() {
let cli = Cli::parse_from([
"harn",
"provider-probe",
"ollama",
"--model",
"devstral-small-2",
"--base-url",
"http://127.0.0.1:11434",
]);
let Command::ProviderProbe(args) = cli.command.unwrap() else {
panic!("expected provider-probe command");
};
assert_eq!(args.provider, "ollama");
assert_eq!(args.model.as_deref(), Some("devstral-small-2"));
assert_eq!(args.base_url.as_deref(), Some("http://127.0.0.1:11434"));
assert!(args.json);
}
#[test]
fn test_parses_provider_tool_probe_args() {
let cli = Cli::parse_from([
"harn",
"provider-tool-probe",
"ollama",
"--model",
"devstral-small-2",
"--base-url",
"http://127.0.0.1:11434",
"--mode",
"non-streaming",
"--marker",
"marker",
"--response-fixture",
"fixture.json",
]);
let Command::ProviderToolProbe(args) = cli.command.unwrap() else {
panic!("expected provider-tool-probe command");
};
assert_eq!(args.provider, "ollama");
assert_eq!(args.model, "devstral-small-2");
assert_eq!(args.base_url.as_deref(), Some("http://127.0.0.1:11434"));
assert!(matches!(args.mode, ProviderToolProbeModeArg::NonStreaming));
assert_eq!(args.marker, "marker");
assert_eq!(args.response_fixture, Some(PathBuf::from("fixture.json")));
assert!(args.json);
}
#[test]
fn test_provider_model_completion_candidates_stay_permissive() {
let cli = Cli::parse_from([
"harn",
"provider-ready",
"custom-provider",
"--model",
"vendor/custom-model",
]);
let Command::ProviderReady(args) = cli.command.unwrap() else {
panic!("expected provider-ready command");
};
assert_eq!(args.provider, "custom-provider");
assert_eq!(args.model.as_deref(), Some("vendor/custom-model"));
let command = Cli::command();
let provider_ready = command
.find_subcommand("provider-ready")
.expect("provider-ready subcommand");
let provider_values: Vec<_> = provider_ready
.get_arguments()
.find(|arg| arg.get_id() == "provider")
.expect("provider argument")
.get_possible_values()
.into_iter()
.map(|value| value.get_name().to_string())
.collect();
assert!(provider_values.iter().any(|value| value == "openai"));
let model_values: Vec<_> = provider_ready
.get_arguments()
.find(|arg| arg.get_id() == "model")
.expect("model argument")
.get_possible_values()
.into_iter()
.map(|value| value.get_name().to_string())
.collect();
assert!(model_values.iter().any(|value| value == "gpt-4o-mini"));
}
#[test]
fn test_parses_models_recommend_args() {
let cli = Cli::parse_from(["harn", "models", "recommend", "--json"]);
let Command::Models(args) = cli.command.unwrap() else {
panic!("expected models command");
};
let ModelsCommand::Recommend(recommend) = args.command else {
panic!("expected models recommend command");
};
assert!(recommend.json);
}
#[test]
fn test_parses_providers_recommend_args() {
let cli = Cli::parse_from([
"harn",
"providers",
"recommend",
"--input",
"local_readiness.json",
"--provider",
"ollama",
"--json",
]);
let Command::Providers(args) = cli.command.unwrap() else {
panic!("expected providers command");
};
let ProvidersCommand::Recommend(recommend) = args.command else {
panic!("expected providers recommend command");
};
assert_eq!(recommend.input, Some(PathBuf::from("local_readiness.json")));
assert_eq!(recommend.provider.as_deref(), Some("ollama"));
assert!(recommend.json);
}