Initial commit
This commit is contained in:
298
tests/integration.rs
Normal file
298
tests/integration.rs
Normal file
@@ -0,0 +1,298 @@
|
||||
use std::fs;
|
||||
use std::path::Path;
|
||||
|
||||
use assert_cmd::Command;
|
||||
use httpmock::Method::{GET, POST};
|
||||
use httpmock::MockServer;
|
||||
use predicates::str::contains;
|
||||
use tempfile::TempDir;
|
||||
|
||||
fn make_ffprobe_stub(dir: &Path) -> std::path::PathBuf {
|
||||
let bin_dir = dir.join("bin");
|
||||
fs::create_dir_all(&bin_dir).unwrap();
|
||||
let script_path = bin_dir.join("ffprobe");
|
||||
let script = r#"#!/usr/bin/env sh
|
||||
echo '{"format":{"duration":"7200"},"streams":[{"codec_type":"video","codec_name":"h264","height":1080}]}'
|
||||
"#;
|
||||
fs::write(&script_path, script).unwrap();
|
||||
let mut perms = fs::metadata(&script_path).unwrap().permissions();
|
||||
#[cfg(unix)]
|
||||
{
|
||||
use std::os::unix::fs::PermissionsExt;
|
||||
perms.set_mode(0o755);
|
||||
fs::set_permissions(&script_path, perms).unwrap();
|
||||
}
|
||||
script_path
|
||||
}
|
||||
|
||||
fn prepend_path(path: &Path) -> String {
|
||||
let current = std::env::var("PATH").unwrap_or_default();
|
||||
format!("{}:{}", path.display(), current)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn tmdb_flow_dry_run_with_mock_server() {
|
||||
let server = MockServer::start();
|
||||
|
||||
let search_mock = server.mock(|when, then| {
|
||||
when.method(GET)
|
||||
.path("/search/movie")
|
||||
.query_param("api_key", "test")
|
||||
.query_param("query", "Some Movie")
|
||||
.query_param("year", "2020");
|
||||
then.status(200)
|
||||
.header("content-type", "application/json")
|
||||
.body(r#"{"results":[{"id":123,"title":"Some Movie","release_date":"2020-01-02"}]}"#);
|
||||
});
|
||||
|
||||
let details_mock = server.mock(|when, then| {
|
||||
when.method(GET)
|
||||
.path("/movie/123")
|
||||
.query_param("api_key", "test");
|
||||
then.status(200)
|
||||
.header("content-type", "application/json")
|
||||
.body(r#"{"id":123,"title":"Some Movie","release_date":"2020-01-02","runtime":120,"imdb_id":"tt123"}"#);
|
||||
});
|
||||
|
||||
let temp = TempDir::new().unwrap();
|
||||
let input = temp.path().join("input");
|
||||
let output = temp.path().join("output");
|
||||
fs::create_dir_all(&input).unwrap();
|
||||
fs::create_dir_all(&output).unwrap();
|
||||
fs::write(input.join("Some.Movie.2020.mkv"), b"stub").unwrap();
|
||||
|
||||
let ffprobe = make_ffprobe_stub(temp.path());
|
||||
|
||||
let mut cmd = Command::new(assert_cmd::cargo_bin!("mov-renamarr"));
|
||||
cmd.arg("--input").arg(&input)
|
||||
.arg("--output").arg(&output)
|
||||
.arg("--dry-run")
|
||||
.env("MOV_RENAMARR_PROVIDER", "tmdb")
|
||||
.env("MOV_RENAMARR_TMDB_API_KEY", "test")
|
||||
.env("MOV_RENAMARR_TMDB_BASE_URL", server.url(""))
|
||||
.env("XDG_CONFIG_HOME", temp.path().join("config"))
|
||||
.env("XDG_CACHE_HOME", temp.path().join("cache"))
|
||||
.env("PATH", prepend_path(ffprobe.parent().unwrap()));
|
||||
|
||||
cmd.assert().success().stdout(contains("renamed"));
|
||||
|
||||
search_mock.assert_hits(1);
|
||||
details_mock.assert_hits(1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn omdb_flow_dry_run_with_mock_server() {
|
||||
let server = MockServer::start();
|
||||
|
||||
let search_mock = server.mock(|when, then| {
|
||||
when.method(GET)
|
||||
.path("/")
|
||||
.query_param("apikey", "test")
|
||||
.query_param("s", "Another Movie")
|
||||
.query_param("type", "movie")
|
||||
.query_param("y", "2019");
|
||||
then.status(200)
|
||||
.header("content-type", "application/json")
|
||||
.body(r#"{"Search":[{"Title":"Another Movie","Year":"2019","imdbID":"tt999"}],"Response":"True"}"#);
|
||||
});
|
||||
|
||||
let details_mock = server.mock(|when, then| {
|
||||
when.method(GET)
|
||||
.path("/")
|
||||
.query_param("apikey", "test")
|
||||
.query_param("i", "tt999")
|
||||
.query_param("plot", "short");
|
||||
then.status(200)
|
||||
.header("content-type", "application/json")
|
||||
.body(r#"{"Title":"Another Movie","Year":"2019","imdbID":"tt999","Runtime":"95 min","Response":"True"}"#);
|
||||
});
|
||||
|
||||
let temp = TempDir::new().unwrap();
|
||||
let input = temp.path().join("input");
|
||||
let output = temp.path().join("output");
|
||||
fs::create_dir_all(&input).unwrap();
|
||||
fs::create_dir_all(&output).unwrap();
|
||||
fs::write(input.join("Another.Movie.2019.mkv"), b"stub").unwrap();
|
||||
|
||||
let ffprobe = make_ffprobe_stub(temp.path());
|
||||
|
||||
let mut cmd = Command::new(assert_cmd::cargo_bin!("mov-renamarr"));
|
||||
cmd.arg("--input").arg(&input)
|
||||
.arg("--output").arg(&output)
|
||||
.arg("--dry-run")
|
||||
.env("MOV_RENAMARR_PROVIDER", "omdb")
|
||||
.env("MOV_RENAMARR_OMDB_API_KEY", "test")
|
||||
.env("MOV_RENAMARR_OMDB_BASE_URL", server.url(""))
|
||||
.env("XDG_CONFIG_HOME", temp.path().join("config"))
|
||||
.env("XDG_CACHE_HOME", temp.path().join("cache"))
|
||||
.env("PATH", prepend_path(ffprobe.parent().unwrap()));
|
||||
|
||||
cmd.assert().success().stdout(contains("renamed"));
|
||||
|
||||
search_mock.assert_hits(1);
|
||||
details_mock.assert_hits(1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn creates_default_config_on_no_args() {
|
||||
let temp = TempDir::new().unwrap();
|
||||
let config_home = temp.path().join("config");
|
||||
|
||||
let mut cmd = Command::new(assert_cmd::cargo_bin!("mov-renamarr"));
|
||||
cmd.env("XDG_CONFIG_HOME", &config_home);
|
||||
|
||||
cmd.assert().success().stderr(contains("Config file:"));
|
||||
|
||||
let config_path = config_home.join("mov-renamarr").join("config.toml");
|
||||
assert!(config_path.exists());
|
||||
let contents = fs::read_to_string(config_path).unwrap();
|
||||
assert!(contents.contains("provider = \"auto\""));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn no_lookup_uses_parsed_title_and_year() {
|
||||
let temp = TempDir::new().unwrap();
|
||||
let input = temp.path().join("input");
|
||||
let output = temp.path().join("output");
|
||||
fs::create_dir_all(&input).unwrap();
|
||||
fs::create_dir_all(&output).unwrap();
|
||||
fs::write(input.join("Test.Movie.2021.mkv"), b"stub").unwrap();
|
||||
|
||||
let ffprobe = make_ffprobe_stub(temp.path());
|
||||
|
||||
let mut cmd = Command::new(assert_cmd::cargo_bin!("mov-renamarr"));
|
||||
cmd.arg("--input").arg(&input)
|
||||
.arg("--output").arg(&output)
|
||||
.arg("--dry-run")
|
||||
.arg("--no-lookup")
|
||||
.env("XDG_CONFIG_HOME", temp.path().join("config"))
|
||||
.env("XDG_CACHE_HOME", temp.path().join("cache"))
|
||||
.env("PATH", prepend_path(ffprobe.parent().unwrap()));
|
||||
|
||||
cmd.assert().success().stdout(contains("parsed"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn no_lookup_with_llm_parse_renames_missing_year() {
|
||||
let server = MockServer::start();
|
||||
let llm_mock = server.mock(|when, then| {
|
||||
when.method(POST)
|
||||
.path("/api/generate");
|
||||
then.status(200)
|
||||
.header("content-type", "application/json")
|
||||
.body(r#"{"response":"{\"title\":\"Mystery Movie\",\"year\":\"2011\",\"alt_titles\":[]}"}"#);
|
||||
});
|
||||
|
||||
let temp = TempDir::new().unwrap();
|
||||
let input = temp.path().join("input");
|
||||
let output = temp.path().join("output");
|
||||
fs::create_dir_all(&input).unwrap();
|
||||
fs::create_dir_all(&output).unwrap();
|
||||
fs::write(input.join("Mystery.Movie.mkv"), b"stub").unwrap();
|
||||
|
||||
let ffprobe = make_ffprobe_stub(temp.path());
|
||||
|
||||
let mut cmd = Command::new(assert_cmd::cargo_bin!("mov-renamarr"));
|
||||
cmd.arg("--input").arg(&input)
|
||||
.arg("--output").arg(&output)
|
||||
.arg("--dry-run")
|
||||
.arg("--no-lookup")
|
||||
.arg("--llm-mode").arg("parse")
|
||||
.arg("--llm-endpoint").arg(server.url(""))
|
||||
.arg("--llm-model").arg("qwen")
|
||||
.env("XDG_CONFIG_HOME", temp.path().join("config"))
|
||||
.env("XDG_CACHE_HOME", temp.path().join("cache"))
|
||||
.env("PATH", prepend_path(ffprobe.parent().unwrap()));
|
||||
|
||||
cmd.assert()
|
||||
.success()
|
||||
.stdout(contains("Mystery Movie (2011)"))
|
||||
.stdout(contains("parsed"));
|
||||
|
||||
llm_mock.assert_hits(1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn collision_policy_skips_existing_destination() {
|
||||
let temp = TempDir::new().unwrap();
|
||||
let input = temp.path().join("input");
|
||||
let output = temp.path().join("output");
|
||||
fs::create_dir_all(&input).unwrap();
|
||||
fs::create_dir_all(&output).unwrap();
|
||||
fs::write(input.join("Some.Movie.2020.mkv"), b"stub").unwrap();
|
||||
|
||||
let ffprobe = make_ffprobe_stub(temp.path());
|
||||
|
||||
// Pre-create destination to trigger collision skip.
|
||||
let dest_dir = output.join("Some Movie (2020)");
|
||||
fs::create_dir_all(&dest_dir).unwrap();
|
||||
let dest_path = dest_dir.join("Some Movie (2020) [1080p].mkv");
|
||||
fs::write(&dest_path, b"existing").unwrap();
|
||||
|
||||
let mut cmd = Command::new(assert_cmd::cargo_bin!("mov-renamarr"));
|
||||
cmd.arg("--input").arg(&input)
|
||||
.arg("--output").arg(&output)
|
||||
.arg("--no-lookup")
|
||||
.env("XDG_CONFIG_HOME", temp.path().join("config"))
|
||||
.env("XDG_CACHE_HOME", temp.path().join("cache"))
|
||||
.env("PATH", prepend_path(ffprobe.parent().unwrap()));
|
||||
|
||||
cmd.assert().success().stdout(contains("destination exists"));
|
||||
|
||||
assert!(dest_path.exists());
|
||||
assert!(input.join("Some.Movie.2020.mkv").exists());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sidecars_are_copied_when_enabled() {
|
||||
let temp = TempDir::new().unwrap();
|
||||
let input = temp.path().join("input");
|
||||
let output = temp.path().join("output");
|
||||
fs::create_dir_all(&input).unwrap();
|
||||
fs::create_dir_all(&output).unwrap();
|
||||
fs::write(input.join("Film.2020.mkv"), b"stub").unwrap();
|
||||
fs::write(input.join("Film.2020.srt"), b"sub").unwrap();
|
||||
fs::write(input.join("Film.2020.nfo"), b"nfo").unwrap();
|
||||
|
||||
let ffprobe = make_ffprobe_stub(temp.path());
|
||||
|
||||
let mut cmd = Command::new(assert_cmd::cargo_bin!("mov-renamarr"));
|
||||
cmd.arg("--input").arg(&input)
|
||||
.arg("--output").arg(&output)
|
||||
.arg("--no-lookup")
|
||||
.arg("--sidecars")
|
||||
.env("XDG_CONFIG_HOME", temp.path().join("config"))
|
||||
.env("XDG_CACHE_HOME", temp.path().join("cache"))
|
||||
.env("PATH", prepend_path(ffprobe.parent().unwrap()));
|
||||
|
||||
cmd.assert().success();
|
||||
|
||||
let out_dir = output.join("Film (2020)");
|
||||
assert!(out_dir.join("Film (2020) [1080p].mkv").exists());
|
||||
assert!(out_dir.join("Film (2020) [1080p].srt").exists());
|
||||
assert!(out_dir.join("Film (2020) [1080p].nfo").exists());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rename_in_place_uses_input_as_output() {
|
||||
let temp = TempDir::new().unwrap();
|
||||
let input = temp.path().join("input");
|
||||
fs::create_dir_all(&input).unwrap();
|
||||
fs::write(input.join("Alien.1979.1080p.mkv"), b"stub").unwrap();
|
||||
|
||||
let ffprobe = make_ffprobe_stub(temp.path());
|
||||
|
||||
let mut cmd = Command::new(assert_cmd::cargo_bin!("mov-renamarr"));
|
||||
cmd.arg("--input").arg(&input)
|
||||
.arg("--rename-in-place")
|
||||
.arg("--no-lookup")
|
||||
.env("XDG_CONFIG_HOME", temp.path().join("config"))
|
||||
.env("XDG_CACHE_HOME", temp.path().join("cache"))
|
||||
.env("PATH", prepend_path(ffprobe.parent().unwrap()));
|
||||
|
||||
cmd.assert().success().stdout(contains("renamed"));
|
||||
|
||||
let renamed = input.join("Alien (1979)").join("Alien (1979) [1080p].mkv");
|
||||
assert!(renamed.exists());
|
||||
assert!(!input.join("Alien.1979.1080p.mkv").exists());
|
||||
}
|
||||
Reference in New Issue
Block a user