api_testing_core/
cli_io.rs1use std::io::{Read, Write};
2use std::path::PathBuf;
3
4use anyhow::anyhow;
5
6use crate::Result;
7
8pub fn read_response_bytes(response: &str, stdin: &mut dyn Read) -> Result<Vec<u8>> {
9 if response == "-" {
10 let mut buf = Vec::new();
11 stdin
12 .read_to_end(&mut buf)
13 .map_err(|_| anyhow!("error: failed to read response from stdin"))?;
14 return Ok(buf);
15 }
16
17 let resp_path = PathBuf::from(response);
18 if !resp_path.is_file() {
19 return Err(anyhow!("Response file not found: {}", resp_path.display()));
20 }
21
22 std::fs::read(&resp_path).map_err(|_| {
23 anyhow!(
24 "error: failed to read response file: {}",
25 resp_path.display()
26 )
27 })
28}
29
30pub fn maybe_print_failure_body_to_stderr(
31 body: &[u8],
32 max_bytes: usize,
33 stdout_is_tty: bool,
34 stderr: &mut dyn Write,
35) {
36 if stdout_is_tty || body.is_empty() {
37 return;
38 }
39
40 if serde_json::from_slice::<serde_json::Value>(body).is_ok() {
41 return;
42 }
43
44 let _ = writeln!(stderr, "Response body (non-JSON; first {max_bytes} bytes):");
45 let _ = stderr.write_all(&body[..body.len().min(max_bytes)]);
46 let _ = writeln!(stderr);
47}
48
49#[cfg(test)]
50mod tests {
51 use super::maybe_print_failure_body_to_stderr;
52
53 #[test]
54 fn maybe_print_failure_body_skips_when_stdout_is_tty() {
55 let mut stderr = Vec::new();
56 maybe_print_failure_body_to_stderr(b"not-json", 16, true, &mut stderr);
57 assert!(stderr.is_empty());
58 }
59
60 #[test]
61 fn maybe_print_failure_body_skips_when_response_is_json() {
62 let mut stderr = Vec::new();
63 maybe_print_failure_body_to_stderr(br#"{"ok":true}"#, 16, false, &mut stderr);
64 assert!(stderr.is_empty());
65 }
66
67 #[test]
68 fn maybe_print_failure_body_prints_non_json_preview() {
69 let mut stderr = Vec::new();
70 maybe_print_failure_body_to_stderr(b"abcdef", 4, false, &mut stderr);
71 let text = String::from_utf8(stderr).expect("utf8");
72 assert!(text.contains("Response body (non-JSON; first 4 bytes):"));
73 assert!(text.contains("abcd"));
74 }
75}