use earl::expression::cli_args::{CliArgsError, parse_cli_args};
use earl::template::schema::{ParamSpec, ParamType};
fn s(v: &str) -> String {
v.to_string()
}
fn args(raw: &[&str]) -> Vec<String> {
raw.iter().map(|v| s(v)).collect()
}
fn search_params() -> Vec<ParamSpec> {
vec![
ParamSpec {
name: "query".to_string(),
r#type: ParamType::String,
required: true,
default: None,
description: None,
},
ParamSpec {
name: "per_page".to_string(),
r#type: ParamType::Integer,
required: false,
default: Some(serde_json::json!(20)),
description: None,
},
ParamSpec {
name: "verbose".to_string(),
r#type: ParamType::Boolean,
required: false,
default: Some(serde_json::json!(false)),
description: None,
},
]
}
#[test]
fn string_param_is_parsed_as_string_value() {
let params = search_params();
let expr = parse_cli_args(
"github.search_issues",
&args(&["--query", "repo:rust-lang/rust", "--per_page", "5"]),
¶ms,
)
.unwrap();
assert_eq!(
expr.named_args[0],
(
"query".to_string(),
serde_json::json!("repo:rust-lang/rust")
)
);
}
#[test]
fn integer_param_is_coerced_from_string_input() {
let params = search_params();
let expr = parse_cli_args(
"github.search_issues",
&args(&["--query", "repo:rust-lang/rust", "--per_page", "5"]),
¶ms,
)
.unwrap();
assert_eq!(
expr.named_args[1],
("per_page".to_string(), serde_json::json!(5))
);
}
#[test]
fn key_value_args_produce_no_positional_args() {
let params = search_params();
let expr = parse_cli_args(
"github.search_issues",
&args(&["--query", "repo:rust-lang/rust", "--per_page", "5"]),
¶ms,
)
.unwrap();
assert!(expr.positional_args.is_empty());
}
#[test]
fn parses_boolean_flag_without_value() {
let params = search_params();
let expr = parse_cli_args(
"github.search_issues",
&args(&["--query", "test", "--verbose"]),
¶ms,
)
.unwrap();
assert_eq!(
expr.named_args[1],
("verbose".to_string(), serde_json::json!(true))
);
}
#[test]
fn parses_boolean_flag_with_explicit_false() {
let params = search_params();
let expr = parse_cli_args(
"github.search_issues",
&args(&["--query", "test", "--verbose", "false"]),
¶ms,
)
.unwrap();
assert_eq!(
expr.named_args[1],
("verbose".to_string(), serde_json::json!(false))
);
}
#[test]
fn parses_json_object_param() {
let params = vec![ParamSpec {
name: "meta".to_string(),
r#type: ParamType::Object,
required: true,
default: None,
description: None,
}];
let expr = parse_cli_args("some.cmd", &args(&["--meta", r#"{"key":"val"}"#]), ¶ms).unwrap();
assert_eq!(expr.named_args[0].1, serde_json::json!({"key": "val"}));
}
#[test]
fn parses_json_array_param() {
let params = vec![ParamSpec {
name: "tags".to_string(),
r#type: ParamType::Array,
required: true,
default: None,
description: None,
}];
let expr = parse_cli_args("some.cmd", &args(&["--tags", "[1,2,3]"]), ¶ms).unwrap();
assert_eq!(expr.named_args[0].1, serde_json::json!([1, 2, 3]));
}
#[test]
#[allow(clippy::approx_constant)] fn parses_number_param() {
let params = vec![ParamSpec {
name: "ratio".to_string(),
r#type: ParamType::Number,
required: true,
default: None,
description: None,
}];
let expr = parse_cli_args("some.cmd", &args(&["--ratio", "3.14"]), ¶ms).unwrap();
assert_eq!(expr.named_args[0].1.as_f64().unwrap(), 3.14);
}
#[test]
fn error_on_unknown_param() {
let params = search_params();
let err = parse_cli_args(
"github.search_issues",
&args(&["--query", "test", "--unknown", "x"]),
¶ms,
)
.unwrap_err();
assert!(matches!(err, CliArgsError::UnknownParam(..)));
}
#[test]
fn error_on_invalid_integer() {
let params = search_params();
let err = parse_cli_args(
"github.search_issues",
&args(&["--query", "test", "--per_page", "abc"]),
¶ms,
)
.unwrap_err();
assert!(matches!(err, CliArgsError::InvalidValue { .. }));
}
#[test]
fn error_on_missing_value() {
let params = search_params();
let err = parse_cli_args("github.search_issues", &args(&["--query"]), ¶ms).unwrap_err();
assert!(matches!(err, CliArgsError::MissingValue(..)));
}
#[test]
fn error_on_invalid_command_format() {
let err = parse_cli_args("noperiod", &[], &[]).unwrap_err();
assert!(matches!(err, CliArgsError::InvalidCommand(..)));
}
#[test]
fn error_on_bare_argument() {
let params = search_params();
let err = parse_cli_args("github.search_issues", &args(&["test"]), ¶ms).unwrap_err();
assert!(matches!(err, CliArgsError::BareArgument(..)));
}
#[test]
fn dot_notation_splits_into_provider_and_command() {
let expr = parse_cli_args("system.disk_usage", &[], &[]).unwrap();
assert_eq!(expr.provider, "system");
assert_eq!(expr.command, "disk_usage");
}