use anyhow::Result;
use assert_cmd::Command;
use predicates::prelude::*;
use tempfile::TempDir;
#[tokio::test]
async fn test_model_list_command() -> Result<()> {
let mut cmd = Command::cargo_bin("tp")?;
cmd.arg("model").arg("list");
cmd.assert()
.success()
.stdout(predicate::str::contains("Available Embedding Models"))
.stdout(predicate::str::contains(
"sentence-transformers/all-MiniLM-L6-v2",
))
.stdout(predicate::str::contains("nomic-embed-code.Q5_K_S.gguf"))
.stdout(predicate::str::contains("Qwen/Qwen3-Embedding-0.6B"))
.stdout(predicate::str::contains("Dimensions:"))
.stdout(predicate::str::contains("Size:"))
.stdout(predicate::str::contains("Backend:"));
Ok(())
}
#[tokio::test]
async fn test_model_list_cache_status() -> Result<()> {
let mut cmd = Command::cargo_bin("tp")?;
cmd.arg("model").arg("list");
let output = cmd.assert().success();
output.stdout(
predicate::str::contains("cached").or(predicate::str::contains("download required")),
);
Ok(())
}
#[tokio::test]
async fn test_model_info_sentence_transformer() -> Result<()> {
let mut cmd = Command::cargo_bin("tp")?;
cmd.arg("model")
.arg("info")
.arg("sentence-transformers/all-MiniLM-L6-v2");
cmd.assert()
.success()
.stdout(predicate::str::contains("Model Information"))
.stdout(predicate::str::contains(
"sentence-transformers/all-MiniLM-L6-v2",
))
.stdout(predicate::str::contains("Dimensions: 384"))
.stdout(predicate::str::contains("FastEmbed"))
.stdout(predicate::str::contains("SentenceTransformer"))
.stdout(predicate::str::contains("Cache Status:"));
Ok(())
}
#[tokio::test]
async fn test_model_info_gguf() -> Result<()> {
let mut cmd = Command::cargo_bin("tp")?;
cmd.arg("model")
.arg("info")
.arg("nomic-embed-code.Q5_K_S.gguf");
cmd.assert()
.success()
.stdout(predicate::str::contains("Model Information"))
.stdout(predicate::str::contains("nomic-embed-code.Q5_K_S.gguf"))
.stdout(predicate::str::contains("Dimensions: 768"))
.stdout(predicate::str::contains("Candle"))
.stdout(predicate::str::contains("GGUF"))
.stdout(predicate::str::contains("Download URL:"))
.stdout(predicate::str::contains("Nomic Embed Code Features:"))
.stdout(predicate::str::contains("code search"));
Ok(())
}
#[tokio::test]
async fn test_model_info_qwen3() -> Result<()> {
let mut cmd = Command::cargo_bin("tp")?;
cmd.arg("model")
.arg("info")
.arg("Qwen/Qwen3-Embedding-0.6B");
cmd.assert()
.success()
.stdout(predicate::str::contains("Model Information"))
.stdout(predicate::str::contains("Qwen/Qwen3-Embedding-0.6B"))
.stdout(predicate::str::contains("Dimensions: 1024"))
.stdout(predicate::str::contains("Custom"))
.stdout(predicate::str::contains("HuggingFace"))
.stdout(predicate::str::contains("Qwen3 Model Features:"))
.stdout(predicate::str::contains("instruction-based embeddings"))
.stdout(predicate::str::contains("Multilingual support"));
Ok(())
}
#[tokio::test]
async fn test_model_info_nonexistent() -> Result<()> {
let mut cmd = Command::cargo_bin("tp")?;
cmd.arg("model").arg("info").arg("nonexistent/model");
cmd.assert()
.failure()
.stderr(predicate::str::contains("not found"));
Ok(())
}
#[tokio::test]
async fn test_model_download_fastembed() -> Result<()> {
let mut cmd = Command::cargo_bin("tp")?;
cmd.arg("model")
.arg("download")
.arg("sentence-transformers/all-MiniLM-L6-v2");
cmd.assert()
.success()
.stdout(predicate::str::contains("FastEmbed model"))
.stdout(predicate::str::contains("downloaded automatically"));
Ok(())
}
#[tokio::test]
async fn test_model_download_nonexistent() -> Result<()> {
let mut cmd = Command::cargo_bin("tp")?;
cmd.arg("model").arg("download").arg("nonexistent/model");
cmd.assert()
.failure()
.stderr(predicate::str::contains("not found"));
Ok(())
}
#[tokio::test]
async fn test_model_clear_all() -> Result<()> {
let mut cmd = Command::cargo_bin("tp")?;
cmd.arg("model").arg("clear");
cmd.assert()
.success()
.stdout(predicate::str::contains("Clearing all model caches"))
.stdout(predicate::str::contains("Successfully cleared"));
Ok(())
}
#[tokio::test]
async fn test_model_clear_specific() -> Result<()> {
let mut cmd = Command::cargo_bin("tp")?;
cmd.arg("model")
.arg("clear")
.arg("sentence-transformers/all-MiniLM-L6-v2");
cmd.assert()
.success()
.stdout(predicate::str::contains("Clearing cache for model"))
.stdout(predicate::str::contains(
"sentence-transformers/all-MiniLM-L6-v2",
))
.stdout(predicate::str::contains("Successfully cleared"));
Ok(())
}
fn is_offline_mode() -> bool {
std::env::var("TURBOPROP_TEST_ONLINE").unwrap_or_default() != "1"
}
#[tokio::test]
async fn test_index_with_custom_model() -> Result<()> {
let temp_dir = TempDir::new()?;
std::fs::write(
temp_dir.path().join("test.js"),
"function hello() { console.log('world'); }",
)?;
let mut git_init = Command::new("git");
git_init
.args(["init", "--quiet"])
.current_dir(temp_dir.path());
git_init.assert().success();
let mut git_add = Command::new("git");
git_add
.args(["add", "test.js"])
.current_dir(temp_dir.path());
git_add.assert().success();
let offline_mode = is_offline_mode();
let model = if offline_mode {
"mock://test-model"
} else {
"sentence-transformers/all-MiniLM-L6-v2"
};
let mut cmd = Command::cargo_bin("tp")?;
cmd.arg("index")
.arg("--repo")
.arg(temp_dir.path())
.arg("--model")
.arg(model);
if offline_mode {
let result = cmd.assert();
if result.try_success().is_err() {
return Ok(());
}
} else {
cmd.assert().success();
}
Ok(())
}
#[tokio::test]
async fn test_search_with_custom_model() -> Result<()> {
let temp_dir = TempDir::new()?;
std::fs::write(
temp_dir.path().join("test.py"),
"def authenticate_user(username, password):\n return username == 'admin' and password == 'secret'"
)?;
let mut git_init = Command::new("git");
git_init
.args(["init", "--quiet"])
.current_dir(temp_dir.path());
git_init.assert().success();
let mut git_add = Command::new("git");
git_add
.args(["add", "test.py"])
.current_dir(temp_dir.path());
git_add.assert().success();
let offline_mode = is_offline_mode();
let model = if offline_mode {
"mock://test-model"
} else {
"sentence-transformers/all-MiniLM-L6-v2"
};
let mut index_cmd = Command::cargo_bin("tp")?;
index_cmd
.arg("index")
.arg("--repo")
.arg(temp_dir.path())
.arg("--model")
.arg(model);
if offline_mode {
let result = index_cmd.assert();
if result.try_success().is_err() {
return Ok(());
}
} else {
index_cmd.assert().success();
}
let mut search_cmd = Command::cargo_bin("tp")?;
search_cmd
.arg("search")
.arg("authentication")
.arg("--repo")
.arg(temp_dir.path())
.arg("--model")
.arg(model);
if offline_mode {
let result = search_cmd.assert();
if result.try_success().is_err() {
return Ok(());
}
} else {
search_cmd
.assert()
.success()
.stdout(predicate::str::contains("authenticate_user"));
}
Ok(())
}
#[tokio::test]
async fn test_model_help() -> Result<()> {
let mut cmd = Command::cargo_bin("tp")?;
cmd.arg("model").arg("--help");
cmd.assert()
.success()
.stdout(predicate::str::contains("model management commands"))
.stdout(predicate::str::contains("list"))
.stdout(predicate::str::contains("info"))
.stdout(predicate::str::contains("download"))
.stdout(predicate::str::contains("clear"));
Ok(())
}
#[tokio::test]
async fn test_model_list_help() -> Result<()> {
let mut cmd = Command::cargo_bin("tp")?;
cmd.arg("model").arg("list").arg("--help");
cmd.assert().success().stdout(predicate::str::contains(
"List all available embedding models",
));
Ok(())
}
#[tokio::test]
async fn test_model_info_help() -> Result<()> {
let mut cmd = Command::cargo_bin("tp")?;
cmd.arg("model").arg("info").arg("--help");
cmd.assert().success().stdout(predicate::str::contains(
"Show detailed information about a specific model",
));
Ok(())
}
#[tokio::test]
async fn test_model_download_help() -> Result<()> {
let mut cmd = Command::cargo_bin("tp")?;
cmd.arg("model").arg("download").arg("--help");
cmd.assert()
.success()
.stdout(predicate::str::contains("Download a specific model"));
Ok(())
}
#[tokio::test]
async fn test_model_clear_help() -> Result<()> {
let mut cmd = Command::cargo_bin("tp")?;
cmd.arg("model").arg("clear").arg("--help");
cmd.assert()
.success()
.stdout(predicate::str::contains("Clear model cache"));
Ok(())
}
#[tokio::test]
async fn test_model_info_missing_argument() -> Result<()> {
let mut cmd = Command::cargo_bin("tp")?;
cmd.arg("model").arg("info");
cmd.assert()
.failure()
.stderr(predicate::str::contains("required"));
Ok(())
}
#[tokio::test]
async fn test_model_download_missing_argument() -> Result<()> {
let mut cmd = Command::cargo_bin("tp")?;
cmd.arg("model").arg("download");
cmd.assert()
.failure()
.stderr(predicate::str::contains("required"));
Ok(())
}
#[tokio::test]
async fn test_model_list_output_format() -> Result<()> {
let mut cmd_default = Command::cargo_bin("tp")?;
cmd_default.arg("model").arg("list");
let output = cmd_default.assert().success();
output
.stdout(predicate::str::contains("Available Embedding Models"))
.stdout(predicate::str::contains("Description:"))
.stdout(predicate::str::contains("Type:"))
.stdout(predicate::str::contains("Backend:"))
.stdout(predicate::str::contains("Dimensions:"))
.stdout(predicate::str::contains("Size:"));
Ok(())
}
#[tokio::test]
async fn test_model_list_verbose() -> Result<()> {
let mut cmd = Command::cargo_bin("tp")?;
cmd.arg("model").arg("list").arg("--verbose");
let result = cmd.assert();
match result.try_success() {
Ok(output) => {
output.stdout(predicate::str::contains("Available Embedding Models"));
}
Err(_) => {
}
}
Ok(())
}
#[tokio::test]
async fn test_model_command_with_log_level() -> Result<()> {
let mut cmd = Command::cargo_bin("tp")?;
cmd.env("RUST_LOG", "debug").arg("model").arg("list");
cmd.assert().success();
Ok(())
}
#[tokio::test]
async fn test_model_caching_through_cli() -> Result<()> {
let temp_dir = TempDir::new()?;
let cache_dir = temp_dir.path().join("custom_cache");
std::fs::create_dir_all(&cache_dir)?;
let mut cmd = Command::cargo_bin("tp")?;
cmd.env("TURBOPROP_CACHE_DIR", cache_dir.to_str().unwrap())
.arg("model")
.arg("list");
cmd.assert().success();
Ok(())
}
#[tokio::test]
#[ignore] async fn test_qwen3_instruction_cli() -> Result<()> {
let temp_dir = TempDir::new()?;
std::fs::write(
temp_dir.path().join("code.rs"),
"fn main() { println!(\"Hello, world!\"); }",
)?;
let mut git_init = Command::new("git");
git_init
.args(["init", "--quiet"])
.current_dir(temp_dir.path());
git_init.assert().success();
let mut git_add = Command::new("git");
git_add
.args(["add", "code.rs"])
.current_dir(temp_dir.path());
git_add.assert().success();
let mut cmd = Command::cargo_bin("tp")?;
cmd.arg("index")
.arg("--repo")
.arg(temp_dir.path())
.arg("--model")
.arg("Qwen/Qwen3-Embedding-0.6B")
.arg("--instruction")
.arg("Represent this code for search");
cmd.assert().success();
Ok(())
}
#[tokio::test]
#[ignore] async fn test_model_download_with_progress() -> Result<()> {
let mut cmd = Command::cargo_bin("tp")?;
cmd.arg("model")
.arg("download")
.arg("nomic-embed-code.Q5_K_S.gguf");
cmd.assert()
.success()
.stdout(predicate::str::contains("Downloading"))
.stdout(predicate::str::contains("Successfully downloaded"));
Ok(())
}
#[tokio::test]
async fn test_model_download_huggingface_placeholder() -> Result<()> {
let offline_mode = is_offline_mode();
if offline_mode {
return Ok(());
}
let mut cmd = Command::cargo_bin("tp")?;
cmd.arg("model")
.arg("download")
.arg("Qwen/Qwen3-Embedding-0.6B");
cmd.assert()
.success()
.stdout(predicate::str::contains("Downloading Hugging Face model"))
.stdout(predicate::str::contains("placeholder"));
Ok(())
}