mirror of
https://github.com/instructkr/claude-code.git
synced 2026-06-05 12:06:43 +00:00
fix: type output format selection
This commit is contained in:
@@ -2345,6 +2345,11 @@ fn assert_non_empty_action(parsed: &Value, args: &[&str]) {
|
||||
fn run_claw(current_dir: &Path, args: &[&str], envs: &[(&str, &str)]) -> Output {
|
||||
let mut command = Command::new(env!("CARGO_BIN_EXE_claw"));
|
||||
command.current_dir(current_dir).args(args);
|
||||
for key in ["CLAW_OUTPUT_FORMAT", "CLAW_LOG", "RUST_LOG"] {
|
||||
if !envs.iter().any(|(env_key, _)| *env_key == key) {
|
||||
command.env_remove(key);
|
||||
}
|
||||
}
|
||||
for (key, value) in envs {
|
||||
command.env(key, value);
|
||||
}
|
||||
@@ -2722,6 +2727,140 @@ fn flag_value_errors_have_error_kind_and_hint_756() {
|
||||
"missing --model hint must be non-empty (#756): {parsed2}"
|
||||
);
|
||||
}
|
||||
#[test]
|
||||
fn output_format_flags_and_env_have_typed_contract_433() {
|
||||
let root = unique_temp_dir("output-format-433");
|
||||
fs::create_dir_all(&root).expect("temp dir");
|
||||
|
||||
let repeated = run_claw(
|
||||
&root,
|
||||
&[
|
||||
"--output-format",
|
||||
"text",
|
||||
"--output-format",
|
||||
"JSON",
|
||||
"status",
|
||||
],
|
||||
&[],
|
||||
);
|
||||
assert!(repeated.status.success());
|
||||
let repeated_stderr = String::from_utf8_lossy(&repeated.stderr);
|
||||
assert!(
|
||||
repeated_stderr.contains("warning: --output-format specified multiple times"),
|
||||
"repeated output-format should warn on stderr: {repeated_stderr}"
|
||||
);
|
||||
let repeated_json = parse_json_stdout(&repeated, "repeated output-format status");
|
||||
assert_eq!(repeated_json["kind"], "status");
|
||||
assert_eq!(repeated_json["format_source"], "flag");
|
||||
assert_eq!(repeated_json["format_raw"], "JSON");
|
||||
assert_eq!(repeated_json["format_overridden"][0], "text");
|
||||
|
||||
let repeated_text = run_claw(
|
||||
&root,
|
||||
&[
|
||||
"--output-format",
|
||||
"json",
|
||||
"--output-format",
|
||||
"text",
|
||||
"status",
|
||||
],
|
||||
&[],
|
||||
);
|
||||
assert!(repeated_text.status.success());
|
||||
let repeated_text_stderr = String::from_utf8_lossy(&repeated_text.stderr);
|
||||
assert!(
|
||||
repeated_text_stderr.contains("using last value 'text'"),
|
||||
"json-to-text repeated output-format should warn: {repeated_text_stderr}"
|
||||
);
|
||||
let repeated_text_stdout = String::from_utf8_lossy(&repeated_text.stdout);
|
||||
assert!(
|
||||
repeated_text_stdout.contains("Status"),
|
||||
"last text output-format should produce text status: {repeated_text_stdout}"
|
||||
);
|
||||
|
||||
for value in ["json", "JSON", "Json"] {
|
||||
let parsed = assert_json_command(&root, &["--output-format", value, "status"]);
|
||||
assert_eq!(
|
||||
parsed["kind"], "status",
|
||||
"case {value} should parse as JSON"
|
||||
);
|
||||
assert_eq!(parsed["format_source"], "flag");
|
||||
assert_eq!(parsed["format_raw"], value);
|
||||
}
|
||||
|
||||
let from_env =
|
||||
assert_json_command_with_env(&root, &["status"], &[("CLAW_OUTPUT_FORMAT", "json")]);
|
||||
assert_eq!(from_env["kind"], "status");
|
||||
assert_eq!(from_env["format_source"], "env");
|
||||
assert_eq!(from_env["format_raw"], "json");
|
||||
|
||||
let flag_overrides_env = run_claw(
|
||||
&root,
|
||||
&["--output-format", "json", "status"],
|
||||
&[("CLAW_OUTPUT_FORMAT", "text")],
|
||||
);
|
||||
assert!(flag_overrides_env.status.success());
|
||||
let override_json = parse_json_stdout(&flag_overrides_env, "flag overrides env output-format");
|
||||
assert_eq!(override_json["kind"], "status");
|
||||
assert_eq!(override_json["format_source"], "flag");
|
||||
assert_eq!(override_json["format_raw"], "json");
|
||||
assert_eq!(
|
||||
override_json["format_overridden"].as_array().map(Vec::len),
|
||||
Some(0)
|
||||
);
|
||||
|
||||
let invalid = run_claw(&root, &["--output-format", "YAML", "status"], &[]);
|
||||
assert_eq!(invalid.status.code(), Some(1));
|
||||
assert!(
|
||||
invalid.stderr.is_empty(),
|
||||
"invalid output-format in JSON mode must keep stderr empty: {}",
|
||||
String::from_utf8_lossy(&invalid.stderr)
|
||||
);
|
||||
let invalid_json = parse_json_stdout(&invalid, "invalid output-format JSON error");
|
||||
assert_eq!(invalid_json["error_kind"], "invalid_output_format");
|
||||
assert_eq!(invalid_json["value"], "YAML");
|
||||
assert_eq!(
|
||||
invalid_json["expected"],
|
||||
serde_json::json!(["text", "json"])
|
||||
);
|
||||
assert!(invalid_json["hint"]
|
||||
.as_str()
|
||||
.is_some_and(|hint| hint.contains("--output-format json")));
|
||||
|
||||
let help = assert_json_command(&root, &["--output-format", "json", "help"]);
|
||||
let help_text = help["message"].as_str().expect("help message");
|
||||
assert!(
|
||||
help_text.contains("CLAW_OUTPUT_FORMAT"),
|
||||
"help should document CLAW_OUTPUT_FORMAT: {help_text}"
|
||||
);
|
||||
assert!(
|
||||
help_text.contains("CLAW_LOG"),
|
||||
"help should document CLAW_LOG: {help_text}"
|
||||
);
|
||||
assert!(
|
||||
help_text.contains("RUST_LOG"),
|
||||
"help should document RUST_LOG: {help_text}"
|
||||
);
|
||||
|
||||
let doctor = assert_json_command_with_env(
|
||||
&root,
|
||||
&["doctor"],
|
||||
&[
|
||||
("CLAW_OUTPUT_FORMAT", "json"),
|
||||
("CLAW_LOG", "debug"),
|
||||
("RUST_LOG", "claw=debug"),
|
||||
],
|
||||
);
|
||||
let system_check = doctor["checks"]
|
||||
.as_array()
|
||||
.expect("doctor checks")
|
||||
.iter()
|
||||
.find(|check| check["name"] == "system")
|
||||
.expect("system check");
|
||||
assert_eq!(system_check["claw_output_format"], "json");
|
||||
assert_eq!(system_check["claw_log"], "debug");
|
||||
assert_eq!(system_check["rust_log"], "claw=debug");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn allowed_tools_errors_have_typed_json_and_alias_map_432() {
|
||||
|
||||
Reference in New Issue
Block a user