#![allow(
clippy::expect_used,
clippy::panic,
clippy::tests_outside_test_module,
clippy::unwrap_used
)]
use assert_cmd::Command;
use predicates::prelude::*;
#[test]
fn bare_invocation_requires_subcommand() {
Command::cargo_bin("docspec")
.unwrap()
.assert()
.failure()
.stderr(predicate::str::contains("Usage").or(predicate::str::contains("subcommand")));
}
#[test]
fn convert_subcommand_routes() {
Command::cargo_bin("docspec")
.unwrap()
.args(["convert", "--from", "markdown", "--to", "html"])
.write_stdin("Hello world\n")
.assert()
.success()
.stdout(predicate::str::contains("Hello"));
}
#[cfg(feature = "http")]
#[test]
fn http_subcommand_routes() {
Command::cargo_bin("docspec")
.unwrap()
.args(["http", "--help"])
.assert()
.success()
.stdout(predicate::str::contains("--host"))
.stdout(predicate::str::contains("--port"));
}
#[cfg(feature = "http")]
#[test]
fn http_subcommand_binds_and_serves_health() {
use core::time::Duration;
use std::process::Stdio;
use std::time::Instant;
let listener = std::net::TcpListener::bind("127.0.0.1:0").unwrap();
let port = listener.local_addr().unwrap().port();
drop(listener);
let mut child = std::process::Command::new(env!("CARGO_BIN_EXE_docspec"))
.args(["http", "--port", &port.to_string()])
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.spawn()
.unwrap();
let url = format!("http://127.0.0.1:{port}/health");
let deadline = Instant::now() + Duration::from_secs(5);
let client = reqwest::blocking::Client::builder()
.timeout(Duration::from_millis(500))
.build()
.unwrap();
let body = loop {
if let Ok(resp) = client.get(&url).send() {
if resp.status().is_success() {
break resp.text().unwrap_or_default();
}
}
if Instant::now() >= deadline {
drop(child.kill());
drop(child.wait());
panic!("docspec http /health did not respond within 5s");
}
std::thread::sleep(Duration::from_millis(50));
};
child.kill().unwrap();
let wait_result = child.wait();
assert!(
wait_result.is_ok(),
"child process should exit after kill: {:?}",
wait_result.err()
);
assert!(
body.contains("Healthy"),
"expected 'Healthy' in body, got: {body}"
);
}