Wave 5: Schemas command, sync command, network policy, test fixtures (bd-x15, bd-3f4, bd-1cv, bd-lx6)

- Implement schemas command with list/show modes, regex filtering, ref expansion
- Implement sync command with conditional fetch, content hash diffing, dry-run
- Add NetworkPolicy enum (Auto/Offline/OnlineOnly) with env var + CLI flag resolution
- Integrate network policy into AsyncHttpClient and fetch command
- Create test fixtures (petstore.json/yaml, minimal.json) and integration test helpers
- Fix clippy lints: derivable_impls, len_zero, borrow-after-move, deprecated API
- 192 tests passing (179 unit + 13 integration), all quality gates green
This commit is contained in:
teernisse
2026-02-12 14:36:22 -05:00
parent faa6281790
commit 346fef9135
11 changed files with 2051 additions and 31 deletions

134
tests/helpers/mod.rs Normal file
View File

@@ -0,0 +1,134 @@
use std::path::{Path, PathBuf};
use assert_cmd::Command;
use tempfile::TempDir;
/// An isolated test environment with its own home, cache, and config directories.
///
/// Setting `SWAGGER_CLI_HOME` on each command invocation ensures tests never
/// touch the real user cache or config.
pub struct TestEnv {
// Kept alive for RAII cleanup; not read directly.
_temp_dir: TempDir,
pub home_dir: PathBuf,
pub cache_dir: PathBuf,
pub config_dir: PathBuf,
}
impl TestEnv {
/// Creates a fresh isolated test environment backed by a temporary directory.
pub fn new() -> Self {
let temp_dir = TempDir::new().expect("failed to create temp dir");
let home_dir = temp_dir.path().join("swagger-cli-home");
let cache_dir = home_dir.join("cache");
let config_dir = home_dir.join("config");
std::fs::create_dir_all(&cache_dir).expect("failed to create cache dir");
std::fs::create_dir_all(&config_dir).expect("failed to create config dir");
Self {
_temp_dir: temp_dir,
home_dir,
cache_dir,
config_dir,
}
}
}
/// Run `swagger-cli` with the given arguments inside the provided test environment.
///
/// `SWAGGER_CLI_HOME` is set so all reads/writes go to the temp directory.
#[allow(deprecated)]
pub fn run_cmd(env: &TestEnv, args: &[&str]) -> assert_cmd::assert::Assert {
Command::cargo_bin("swagger-cli")
.expect("binary not found -- run `cargo build` first")
.env("SWAGGER_CLI_HOME", &env.home_dir)
.args(args)
.assert()
}
/// Fetch a fixture file into the test environment's cache under the given alias.
///
/// Runs: `swagger-cli fetch <fixture_path> --alias <alias>`
pub fn fetch_fixture(env: &TestEnv, fixture_name: &str, alias: &str) {
let path = fixture_path(fixture_name);
assert!(
path.exists(),
"fixture file does not exist: {}",
path.display()
);
let path_str = path.to_str().expect("fixture path is not valid UTF-8");
run_cmd(env, &["fetch", path_str, "--alias", alias]).success();
}
/// Parse robot-mode JSON output from command stdout bytes.
///
/// The robot envelope has the shape: `{"ok": true, "data": {...}, "meta": {...}}`
pub fn parse_robot_json(output: &[u8]) -> serde_json::Value {
let text = std::str::from_utf8(output).expect("stdout is not valid UTF-8");
serde_json::from_str(text.trim()).expect("stdout is not valid JSON")
}
/// Return the absolute path to a test fixture file by name.
///
/// Fixtures live in `tests/fixtures/` relative to the project root.
pub fn fixture_path(name: &str) -> PathBuf {
let manifest_dir =
std::env::var("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR not set -- run via cargo");
Path::new(&manifest_dir)
.join("tests")
.join("fixtures")
.join(name)
}
// ---------------------------------------------------------------------------
// Self-tests for the helpers
// ---------------------------------------------------------------------------
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_env_creates_directories() {
let env = TestEnv::new();
assert!(env.home_dir.exists());
assert!(env.cache_dir.exists());
assert!(env.config_dir.exists());
}
#[test]
fn test_fixture_path_exists() {
let path = fixture_path("petstore.json");
assert!(path.exists(), "petstore.json fixture missing");
assert!(path.is_absolute());
}
#[test]
fn test_fixture_path_yaml() {
let path = fixture_path("petstore.yaml");
assert!(path.exists(), "petstore.yaml fixture missing");
}
#[test]
fn test_fixture_path_minimal() {
let path = fixture_path("minimal.json");
assert!(path.exists(), "minimal.json fixture missing");
}
#[test]
fn test_parse_robot_json_valid() {
let input = br#"{"ok":true,"data":{"x":1},"meta":{}}"#;
let val = parse_robot_json(input);
assert_eq!(val["ok"], true);
assert_eq!(val["data"]["x"], 1);
}
#[test]
#[should_panic(expected = "not valid JSON")]
fn test_parse_robot_json_invalid() {
parse_robot_json(b"not json");
}
}