use assert_cmd::Command;
use std::path::{Path, PathBuf};
use tempfile::TempDir;
const TS_FIXTURE: &str = "tests/fixtures/typescript-simple";
fn copy_dir_all(src: &Path, dest: &Path) {
std::fs::create_dir_all(dest).unwrap();
for entry in std::fs::read_dir(src).unwrap() {
let entry = entry.unwrap();
let src_path = entry.path();
let dest_path = dest.join(entry.file_name());
if src_path.is_dir() {
copy_dir_all(&src_path, &dest_path);
} else {
std::fs::copy(&src_path, &dest_path).unwrap();
}
}
}
fn setup_indexed_fixture() -> (TempDir, PathBuf) {
let dir = TempDir::new().unwrap();
let fixture = Path::new(TS_FIXTURE);
copy_dir_all(fixture, dir.path());
Command::cargo_bin("scope")
.unwrap()
.arg("init")
.current_dir(dir.path())
.assert()
.success();
Command::cargo_bin("scope")
.unwrap()
.args(["index", "--full"])
.current_dir(dir.path())
.assert()
.success();
let root = dir.path().to_path_buf();
(dir, root)
}
fn parse_json(stdout: &[u8]) -> serde_json::Value {
serde_json::from_slice(stdout).unwrap_or_else(|e| {
panic!(
"stdout is not valid JSON: {}\nraw output: {}",
e,
String::from_utf8_lossy(stdout)
)
})
}
#[test]
fn test_sketch_json_envelope() {
let (_dir, root) = setup_indexed_fixture();
let output = Command::cargo_bin("scope")
.unwrap()
.args(["sketch", "PaymentService", "--json"])
.current_dir(&root)
.assert()
.success()
.get_output()
.stdout
.clone();
let json = parse_json(&output);
assert_eq!(
json["command"], "sketch",
"JSON envelope must have command=sketch, got: {}",
json["command"]
);
assert!(
!json["data"].is_null(),
"JSON envelope must have a non-null data field"
);
}
#[test]
fn test_refs_json_envelope() {
let (_dir, root) = setup_indexed_fixture();
let output = Command::cargo_bin("scope")
.unwrap()
.args(["refs", "PaymentService", "--json"])
.current_dir(&root)
.assert()
.success()
.get_output()
.stdout
.clone();
let json = parse_json(&output);
assert_eq!(
json["command"], "refs",
"JSON envelope must have command=refs, got: {}",
json["command"]
);
assert!(
!json["data"].is_null(),
"JSON envelope must have a non-null data field"
);
}
#[test]
fn test_deps_json_envelope() {
let (_dir, root) = setup_indexed_fixture();
let output = Command::cargo_bin("scope")
.unwrap()
.args(["deps", "PaymentService", "--json"])
.current_dir(&root)
.assert()
.success()
.get_output()
.stdout
.clone();
let json = parse_json(&output);
assert_eq!(
json["command"], "deps",
"JSON envelope must have command=deps, got: {}",
json["command"]
);
assert!(
!json["data"].is_null(),
"JSON envelope must have a non-null data field"
);
}
#[test]
fn test_impact_json_envelope() {
let (_dir, root) = setup_indexed_fixture();
let output = Command::cargo_bin("scope")
.unwrap()
.args(["impact", "PaymentService", "--json"])
.current_dir(&root)
.assert()
.success()
.get_output()
.stdout
.clone();
let json = parse_json(&output);
assert_eq!(
json["command"], "impact",
"JSON envelope must have command=impact, got: {}",
json["command"]
);
assert!(
!json["data"].is_null(),
"JSON envelope must have a non-null data field"
);
}
#[test]
fn test_find_json_envelope() {
let (_dir, root) = setup_indexed_fixture();
let output = Command::cargo_bin("scope")
.unwrap()
.args(["find", "payment", "--json"])
.current_dir(&root)
.assert()
.success()
.get_output()
.stdout
.clone();
let json = parse_json(&output);
assert_eq!(
json["command"], "find",
"JSON envelope must have command=find, got: {}",
json["command"]
);
assert!(
!json["data"].is_null(),
"JSON envelope must have a non-null data field"
);
}
#[test]
fn test_status_json_envelope() {
let (_dir, root) = setup_indexed_fixture();
let output = Command::cargo_bin("scope")
.unwrap()
.args(["status", "--json"])
.current_dir(&root)
.assert()
.success()
.get_output()
.stdout
.clone();
let json = parse_json(&output);
assert_eq!(
json["command"], "status",
"JSON envelope must have command=status, got: {}",
json["command"]
);
assert!(
!json["data"].is_null(),
"JSON envelope must have a non-null data field"
);
assert_eq!(
json["data"]["index_exists"], true,
"data.index_exists must be true for an indexed project"
);
}
#[test]
fn test_sketch_json_data_has_name_and_kind() {
let (_dir, root) = setup_indexed_fixture();
let output = Command::cargo_bin("scope")
.unwrap()
.args(["sketch", "PaymentService", "--json"])
.current_dir(&root)
.assert()
.success()
.get_output()
.stdout
.clone();
let json = parse_json(&output);
let symbol = &json["data"]["symbol"];
assert!(
symbol["name"].as_str().is_some(),
"data.symbol.name must be a string, got: {}",
symbol["name"]
);
assert_eq!(
symbol["name"], "PaymentService",
"data.symbol.name must be PaymentService"
);
assert!(
symbol["kind"].as_str().is_some(),
"data.symbol.kind must be a string, got: {}",
symbol["kind"]
);
}
#[test]
fn test_refs_json_data_has_groups() {
let (_dir, root) = setup_indexed_fixture();
let output = Command::cargo_bin("scope")
.unwrap()
.args(["refs", "PaymentService", "--json"])
.current_dir(&root)
.assert()
.success()
.get_output()
.stdout
.clone();
let json = parse_json(&output);
assert!(
json["data"]["groups"].is_array(),
"refs JSON data.groups must be an array, got: {}",
json["data"]
);
}
#[test]
fn test_find_json_data_has_required_fields() {
let (_dir, root) = setup_indexed_fixture();
let output = Command::cargo_bin("scope")
.unwrap()
.args(["find", "payment", "--json"])
.current_dir(&root)
.assert()
.success()
.get_output()
.stdout
.clone();
let json = parse_json(&output);
assert!(json["data"].is_array(), "find JSON data must be an array");
let results = json["data"].as_array().unwrap();
assert!(
!results.is_empty(),
"find 'payment' should return at least one result"
);
for result in results {
assert!(
result["name"].as_str().is_some(),
"each find result must have a name string, got: {result}"
);
assert!(
result["kind"].as_str().is_some(),
"each find result must have a kind string, got: {result}"
);
assert!(
result["score"].as_f64().is_some(),
"each find result must have a numeric score, got: {result}"
);
}
}
#[test]
fn test_sketch_json_symbol_field_matches_query() {
let (_dir, root) = setup_indexed_fixture();
let output = Command::cargo_bin("scope")
.unwrap()
.args(["sketch", "PaymentService", "--json"])
.current_dir(&root)
.assert()
.success()
.get_output()
.stdout
.clone();
let json = parse_json(&output);
assert_eq!(
json["symbol"], "PaymentService",
"JSON envelope symbol field must match the queried symbol"
);
}