use serde_json::Value;
use std::path::Path;
use std::process::Command;
fn memlay_bin() -> &'static str {
env!("CARGO_BIN_EXE_memlay")
}
fn git(dir: &Path, args: &[&str]) {
let out = Command::new("git")
.args(args)
.current_dir(dir)
.output()
.unwrap();
assert!(
out.status.success(),
"git {args:?}: {}",
String::from_utf8_lossy(&out.stderr)
);
}
fn fixture_repo() -> tempfile::TempDir {
let tmp = tempfile::tempdir().unwrap();
let dir = tmp.path();
git(dir, &["init", "-b", "main"]);
git(dir, &["config", "user.email", "test@example.com"]);
git(dir, &["config", "user.name", "Test"]);
git(dir, &["config", "commit.gpgsign", "false"]);
std::fs::write(
dir.join("app.ts"),
"export function startGameLoop(fps: number): void {}\n",
)
.unwrap();
git(dir, &["add", "-A"]);
git(dir, &["commit", "-m", "base"]);
tmp
}
fn run(dir: &Path, args: &[&str]) -> String {
let out = Command::new(memlay_bin())
.args(["--repo", dir.to_str().unwrap()])
.args(args)
.output()
.unwrap();
assert!(
out.status.success(),
"memlay {args:?}: {}",
String::from_utf8_lossy(&out.stderr)
);
String::from_utf8_lossy(&out.stdout).into_owned()
}
fn stats(dir: &Path) -> Value {
serde_json::from_str(&run(dir, &["--json", "index", "stats"])).unwrap()
}
#[test]
fn init_indexes_by_default() {
let tmp = fixture_repo();
let dir = tmp.path();
let out: Value = serde_json::from_str(&run(dir, &["--json", "init"])).unwrap();
assert_eq!(out["initialized"], true);
assert!(
out["indexed"]["files"].as_u64().unwrap() > 0,
"init reported no indexed files: {out}"
);
let s = stats(dir);
assert!(s["files"].as_u64().unwrap() > 0, "index is empty: {s}");
assert!(
s["symbols"].as_u64().unwrap() > 0,
"no symbols extracted: {s}"
);
}
#[test]
fn no_index_defers_the_build_and_first_query_still_works() {
let tmp = fixture_repo();
let dir = tmp.path();
let out: Value = serde_json::from_str(&run(dir, &["--json", "init", "--no-index"])).unwrap();
assert_eq!(out["initialized"], true);
assert!(
out["indexed"].is_null(),
"--no-index still built an index: {out}"
);
assert_eq!(stats(dir)["files"].as_u64().unwrap(), 0);
run(dir, &["context", "start game loop"]);
assert!(stats(dir)["files"].as_u64().unwrap() > 0);
}
#[test]
fn init_respects_an_existing_customized_config() {
let tmp = fixture_repo();
let dir = tmp.path();
std::fs::create_dir_all(dir.join("src")).unwrap();
std::fs::write(
dir.join("src").join("kept.ts"),
"export function keptSymbol(): void {}\n",
)
.unwrap();
run(dir, &["init", "--no-index"]);
let cfg_path = dir.join(".memlay").join("config.toml");
let cfg = std::fs::read_to_string(&cfg_path).unwrap();
assert!(cfg.contains("[index]"), "unexpected config shape: {cfg}");
std::fs::write(
&cfg_path,
cfg.replace("roots = [\".\"]", "roots = [\"src\"]"),
)
.unwrap();
run(dir, &["init"]);
let s = stats(dir);
assert_eq!(
s["files"].as_u64().unwrap(),
1,
"init ignored the narrowed roots and indexed the whole tree: {s}"
);
}