use assert_cmd::Command;
use predicates::str::contains;
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 setup_empty_ts_project() -> (TempDir, PathBuf) {
let dir = TempDir::new().unwrap();
std::fs::write(
dir.path().join("tsconfig.json"),
r#"{"compilerOptions":{"target":"ES2020"},"include":["src/**/*"]}"#,
)
.unwrap();
Command::cargo_bin("scope")
.unwrap()
.arg("init")
.current_dir(dir.path())
.assert()
.success();
let root = dir.path().to_path_buf();
(dir, root)
}
#[test]
fn test_index_file_with_syntax_errors() {
let (dir, root) = setup_empty_ts_project();
std::fs::create_dir_all(dir.path().join("src")).unwrap();
std::fs::write(
dir.path().join("src/valid.ts"),
"export class ValidClass { greet(): string { return 'hello'; } }",
)
.unwrap();
std::fs::write(
dir.path().join("src/broken.ts"),
"export class {{{{ this is not valid TypeScript )))))",
)
.unwrap();
Command::cargo_bin("scope")
.unwrap()
.args(["index", "--full"])
.current_dir(&root)
.assert()
.success();
Command::cargo_bin("scope")
.unwrap()
.args(["sketch", "ValidClass"])
.current_dir(&root)
.assert()
.success()
.stdout(contains("ValidClass"));
}
#[test]
fn test_index_empty_file() {
let (dir, root) = setup_empty_ts_project();
std::fs::create_dir_all(dir.path().join("src")).unwrap();
std::fs::write(dir.path().join("src/empty.ts"), "").unwrap();
Command::cargo_bin("scope")
.unwrap()
.args(["index", "--full"])
.current_dir(&root)
.assert()
.success();
}
#[test]
fn test_index_file_with_no_symbols() {
let (dir, root) = setup_empty_ts_project();
std::fs::create_dir_all(dir.path().join("src")).unwrap();
std::fs::write(
dir.path().join("src/comments_only.ts"),
"// This file intentionally left blank.\n// No symbols here.\n",
)
.unwrap();
Command::cargo_bin("scope")
.unwrap()
.args(["index", "--full"])
.current_dir(&root)
.assert()
.success();
}
#[test]
fn test_sketch_after_file_deleted() {
let (dir, root) = setup_empty_ts_project();
std::fs::create_dir_all(dir.path().join("src")).unwrap();
std::fs::write(
dir.path().join("src/temporary.ts"),
"export class TemporaryClass { doWork(): void {} }",
)
.unwrap();
Command::cargo_bin("scope")
.unwrap()
.args(["index", "--full"])
.current_dir(&root)
.assert()
.success();
Command::cargo_bin("scope")
.unwrap()
.args(["sketch", "TemporaryClass"])
.current_dir(&root)
.assert()
.success()
.stdout(contains("TemporaryClass"));
std::fs::remove_file(dir.path().join("src/temporary.ts")).unwrap();
Command::cargo_bin("scope")
.unwrap()
.args(["index", "--full"])
.current_dir(&root)
.assert()
.success();
Command::cargo_bin("scope")
.unwrap()
.args(["sketch", "TemporaryClass"])
.current_dir(&root)
.assert()
.failure()
.stderr(contains("not found"));
}
#[test]
fn test_impact_depth_limit() {
let (_dir, root) = setup_indexed_fixture();
Command::cargo_bin("scope")
.unwrap()
.args(["impact", "PaymentService", "--depth", "10"])
.current_dir(&root)
.assert()
.success()
.stdout(contains("Impact analysis"));
}
#[test]
fn test_find_empty_query() {
let (_dir, root) = setup_indexed_fixture();
Command::cargo_bin("scope")
.unwrap()
.args(["find", ""])
.current_dir(&root)
.assert()
.success();
}
#[test]
fn test_find_no_results() {
let (_dir, root) = setup_indexed_fixture();
Command::cargo_bin("scope")
.unwrap()
.args(["find", "xyzzynonexistent"])
.current_dir(&root)
.assert()
.success()
.stdout(contains("no results found"));
}
#[test]
fn test_refs_with_limit_zero() {
let (_dir, root) = setup_indexed_fixture();
Command::cargo_bin("scope")
.unwrap()
.args(["refs", "PaymentService", "--limit", "0"])
.current_dir(&root)
.assert()
.success();
}