#![cfg(feature = "inference-local-models")]
use std::path::Path;
use std::process::{Command, Stdio};
const BIN: &str = env!("CARGO_BIN_EXE_roteiro");
fn roteiro(home: &Path, args: &[&str]) -> std::process::Output {
Command::new(BIN)
.args(args)
.env("ROTEIRO_HOME", home)
.stdin(Stdio::piped())
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.spawn()
.and_then(std::process::Child::wait_with_output)
.expect("run roteiro")
}
fn fresh_home(name: &str) -> std::path::PathBuf {
let dir = std::env::temp_dir().join(format!("roteiro-model-{}-{name}", std::process::id()));
std::fs::remove_dir_all(&dir).ok();
std::fs::create_dir_all(&dir).expect("mkdir");
dir
}
#[test]
fn model_list_shows_registry() {
let home = fresh_home("list");
let out = roteiro(&home, &["model", "list"]);
assert!(out.status.success(), "model list failed: {out:?}");
let text = String::from_utf8_lossy(&out.stdout);
assert!(
text.contains("all-minilm-l6-v2"),
"registry model listed: {text}"
);
assert!(
text.contains("hashing embedder"),
"notes the always-available default"
);
assert!(
text.contains("available"),
"uninstalled model marked available"
);
std::fs::remove_dir_all(&home).ok();
}
#[test]
fn pull_is_declined_non_interactively_and_downloads_nothing() {
let home = fresh_home("pull");
let out = roteiro(&home, &["model", "pull", "all-minilm-l6-v2"]);
assert!(!out.status.success(), "pull must decline non-interactively");
let err = String::from_utf8_lossy(&out.stderr);
assert!(err.contains("non-interactive"), "explains why: {err}");
assert!(err.contains("--yes"), "points at the override: {err}");
let model_dir = home.join("models/all-minilm-l6-v2");
assert!(
!model_dir.join("model.safetensors").exists(),
"no weights should be downloaded",
);
std::fs::remove_dir_all(&home).ok();
}
#[test]
fn pull_rejects_unknown_model() {
let home = fresh_home("unknown");
let out = roteiro(&home, &["model", "pull", "no-such-model", "--yes"]);
assert!(!out.status.success(), "unknown model must fail");
let err = String::from_utf8_lossy(&out.stderr);
assert!(err.contains("unknown model"), "clear error: {err}");
std::fs::remove_dir_all(&home).ok();
}
#[test]
fn infer_with_uninstalled_model_errors() {
let dir = fresh_home("infer");
std::fs::write(dir.join("a.rs"), "fn a() {}\n").expect("write");
for args in [
&["-c", "user.name=t", "-c", "user.email=t@e", "init", "-q"][..],
&["-c", "user.name=t", "-c", "user.email=t@e", "add", "."][..],
&[
"-c",
"user.name=t",
"-c",
"user.email=t@e",
"-c",
"commit.gpgsign=false",
"commit",
"-qm",
"x",
][..],
] {
assert!(
Command::new("git")
.args(args)
.current_dir(&dir)
.status()
.expect("git")
.success()
);
}
let out = Command::new(BIN)
.args(["infer", "--model", "all-minilm-l6-v2"])
.current_dir(&dir)
.env("ROTEIRO_HOME", &dir)
.output()
.expect("run");
assert!(!out.status.success(), "uninstalled model must error");
let err = String::from_utf8_lossy(&out.stderr);
assert!(err.contains("not installed"), "points at model pull: {err}");
std::fs::remove_dir_all(&dir).ok();
}