added unit tests

This commit is contained in:
2026-03-12 17:47:56 +01:00
parent c8fdf0bc23
commit 2b81393fc9
5 changed files with 333 additions and 24 deletions

View File

@@ -85,3 +85,135 @@ impl<'a> ConflictSolver<'a> {
self.files.iter().map(|e| e.1.to_owned()).collect()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn no_conflict() {
let mut solver = ConflictSolver::new();
let mod1 = InstalledMod::new("mod1", 0);
let m1f1 = ModFile::new("Data/Plugin1.esp", "Data/Plugin1.esp", 0);
let mod2 = InstalledMod::new("mod2", 0);
let m2f1 = ModFile::new("Data/Plugin2.esp", "Data/Plugin2.esp", 0);
assert!(solver.add_file(&m1f1, &mod1).is_none());
assert!(solver.add_file(&m2f1, &mod2).is_none());
let export = solver.export_files();
assert_eq!(export.len(), 2);
assert!(
export
.iter()
.find(|e| e.1 == &mod1 && e.0 == &m1f1)
.is_some(),
"Missing mod1 file1"
);
assert!(
export
.iter()
.find(|e| e.1 == &mod2 && e.0 == &m2f1)
.is_some(),
"Missing mod2 file1"
);
}
#[test]
fn conflict_same_mod_solved() {
let mut solver = ConflictSolver::new();
let mod1 = InstalledMod::new("mod1", 0);
let m1f1 = ModFile::new("Data/Plugin1.esp", "Data/Plugin.esp", 0);
let m1f2 = ModFile::new("Data/Plugin_alt.esp", "Data/Plugin.esp", 1);
assert!(solver.add_file(&m1f1, &mod1).is_none());
assert!(solver.add_file(&m1f2, &mod1).is_none());
let export = solver.export_files();
assert_eq!(export.len(), 1);
assert!(
export
.iter()
.find(|e| e.1 == &mod1 && e.0 == &m1f2)
.is_some(),
"Missing mod1 file2"
);
}
#[test]
fn conflict_diff_mod_solved() {
let mut solver = ConflictSolver::new();
let mod1 = InstalledMod::new("mod1", 0);
let m1f1 = ModFile::new("Data/Plugin1.esp", "Data/Plugin.esp", 0);
let mod2 = InstalledMod::new("mod2", 1);
let m2f1 = ModFile::new("Data/Plugin.esp", "Data/Plugin.esp", 0);
assert!(solver.add_file(&m1f1, &mod1).is_none());
assert!(solver.add_file(&m2f1, &mod2).is_none());
let export = solver.export_files();
assert_eq!(export.len(), 1);
assert!(
export
.iter()
.find(|e| e.1 == &mod2 && e.0 == &m2f1)
.is_some(),
"Missing mod2 file1"
);
}
#[test]
fn conflict_same_mod() {
let mut solver = ConflictSolver::new();
let mod1 = InstalledMod::new("mod1", 0);
let m1f1 = ModFile::new("Data/Plugin1.esp", "Data/Plugin.esp", 0);
let m1f2 = ModFile::new("Data/Plugin_alt.esp", "Data/Plugin.esp", 0);
assert!(solver.add_file(&m1f1, &mod1).is_none());
let conflict = solver.add_file(&m1f2, &mod1);
assert!(conflict.is_some());
let unwraped = conflict.expect("Aserted before");
assert!(
unwraped.rhs_mod == unwraped.lhs_mod,
"Not same mod in conflict"
);
assert!(unwraped.rhs_file != unwraped.lhs_file, "Files are the same");
assert!(
unwraped.rhs_file == &m1f1 || unwraped.rhs_file == &m1f2,
"One file not found in conflict "
);
}
#[test]
fn conflict_diff_mod() {
let mut solver = ConflictSolver::new();
let mod1 = InstalledMod::new("mod1", 0);
let m1f1 = ModFile::new("Data/Plugin1.esp", "Data/Plugin.esp", 0);
let mod2 = InstalledMod::new("mod2", 0);
let m2f1 = ModFile::new("Data/Plugin.esp", "Data/Plugin.esp", 0);
assert!(solver.add_file(&m1f1, &mod1).is_none());
let conflict = solver.add_file(&m2f1, &mod2);
assert!(conflict.is_some());
let unwraped = conflict.expect("Aserted before");
assert!(unwraped.rhs_mod != unwraped.lhs_mod, "Same mod in conflict");
assert!(unwraped.rhs_file != unwraped.lhs_file, "Files are the same");
assert!(
unwraped.rhs_file == &m1f1 || unwraped.lhs_file == &m1f1,
"One file not found in conflict "
);
assert_eq!(unwraped.rhs_file.dst(), "Data/Plugin.esp");
}
}

View File

@@ -14,6 +14,12 @@ pub struct Game {
}
impl Game {
pub fn new(path: impl AsRef<Path>) -> Self {
Self {
path: path.as_ref().to_owned(),
}
}
pub fn export_links(&self) -> Result<Vec<Link>, io::Error> {
let links: Vec<Link> = walk_all_files(&self.path)?
.map(|entry| {

View File

@@ -7,7 +7,7 @@ use crate::{
utils::walk_all_files,
};
#[derive(Debug, Clone, Deserialize)]
#[derive(Debug, Clone, Deserialize, PartialEq, Eq)]
pub struct ModFile {
/// Relative path in the mod
src: PathBuf,

View File

@@ -29,6 +29,22 @@ pub struct ModdedInstance {
}
impl ModdedInstance {
pub fn new(
game: &str,
mods: &[InstalledMod],
load_order: &[String],
overrides: &[Link],
self_path: impl AsRef<Path>,
) -> Self {
Self {
game: game.to_owned(),
mods: mods.to_owned(),
load_order: load_order.to_owned(),
game_file_overrides: overrides.to_owned(),
self_path: self_path.as_ref().to_owned(),
}
}
pub fn load_from_file(path: impl AsRef<Path>) -> Result<Self, ConfigReadWriteError> {
debug!(
"Loading ModdedInstance from file: {}",
@@ -94,3 +110,52 @@ impl ModdedInstance {
self.mods.iter().flat_map(|e| e.active_plugins())
}
}
#[cfg(test)]
mod tests {
use super::*;
fn create_config() -> ModdedInstance {
ModdedInstance::new(
"sse",
&[InstalledMod::new("mod1", 0), InstalledMod::new("mod1", 0)],
&["Plugin1.esp".to_owned(), "Plugin2.esp".to_owned()],
&[Link::new("file1.txt", "file2.txt")],
"/config/instance.toml",
)
}
#[test]
fn basic_members() {
let cfg = create_config();
assert_eq!(cfg.game_file_overrides().len(), 1);
assert_eq!(cfg.mods().len(), 2);
assert_eq!(cfg.load_order().len(), 2);
}
#[test]
fn add_mod() {
let mut cfg = create_config();
let new_mod = InstalledMod::new("mod3", 1);
cfg.update_or_create_mod(&new_mod);
let mods = cfg.mods();
assert_eq!(mods.len(), 3);
let found_mod = mods.iter().find(|e| e.mod_id() == "mod3");
assert!(found_mod.is_some());
}
#[test]
fn update_mod() {
let mut cfg = create_config();
let new_mod = InstalledMod::new("mod1", 1);
cfg.update_or_create_mod(&new_mod);
}
}

View File

@@ -52,25 +52,6 @@ impl RootConfig {
.to_owned();
config.self_path = absolute;
if config.mod_location.is_relative() {
config.mod_location = config.self_parent.join(config.mod_location).to_owned();
debug!(
"Resolved mod_location to absolue path: {}",
config.mod_location.to_string_lossy()
);
}
if let Some(dl_location) = &config.download_location
&& dl_location.is_relative()
{
let dl_abs_path = config.self_parent.join(dl_location).to_owned();
debug!(
"Resolve download_location to absolute path {}",
dl_abs_path.to_string_lossy()
);
config.download_location = Some(dl_abs_path);
}
Ok(config)
}
@@ -106,16 +87,26 @@ impl RootConfig {
}
}
pub fn mod_location(&self) -> &Path {
&self.mod_location
pub fn mod_location(&self) -> PathBuf {
if self.mod_location.is_relative() {
self.self_parent.join(&self.mod_location)
} else {
self.mod_location.clone()
}
}
pub fn nexus_api_key(&self) -> Option<&str> {
self.nexus_api_key.as_deref()
}
pub fn download_location(&self) -> Option<&Path> {
self.download_location.as_deref()
pub fn download_location(&self) -> Option<PathBuf> {
self.download_location.as_ref().map(|e| {
if e.is_relative() {
self.self_parent.join(e)
} else {
e.clone()
}
})
}
}
@@ -123,3 +114,118 @@ impl RootConfig {
struct InstancePointer {
path: PathBuf,
}
#[cfg(test)]
mod tests {
use super::*;
fn create_config() -> RootConfig {
RootConfig {
games: HashMap::from([("sse".to_owned(), Game::new("/games/sse"))]),
mod_location: PathBuf::from("mods"),
download_location: Some(PathBuf::from("download")),
nexus_api_key: Some("1234".to_owned()),
instances: HashMap::from([(
"instance1".to_owned(),
InstancePointer {
path: PathBuf::from("instances/instance1.toml"),
},
)]),
mods: HashMap::from([(
"mod1".to_owned(),
ModConfig::new("mod1", PathBuf::from("mod1")),
)]),
self_path: PathBuf::from("/config/root.toml"),
self_parent: PathBuf::from("/config"),
}
}
#[test]
fn get_game() {
let cfg = create_config();
let game = cfg.game_by_id("sse");
assert!(game.is_some());
let unwraped = game.expect("Asserted before");
assert_eq!(unwraped.install_location(), "/games/sse");
}
#[test]
fn get_missing_game() {
let cfg = create_config();
let game = cfg.game_by_id("starfield");
assert!(game.is_none());
}
#[test]
fn get_mod() {
let cfg = create_config();
let found_mod = cfg.mod_by_id("mod1");
assert!(found_mod.is_some());
let unwraped = found_mod.expect("Asserted before");
assert_eq!(unwraped.path(), "mod1");
}
#[test]
fn get_missing_mod() {
let cfg = create_config();
let found_mod = cfg.mod_by_id("mod200");
assert!(found_mod.is_none());
}
#[test]
fn get_api_key() {
let cfg = create_config();
assert_eq!(cfg.nexus_api_key(), Some("1234"));
}
#[test]
fn get_download_location() {
let cfg = create_config();
let dl = cfg.download_location();
assert!(dl.is_some());
let unwraped = dl.expect("Asserted before");
assert!(unwraped.is_absolute(), "Path not absolute");
assert_eq!(unwraped, PathBuf::from("/config/download"));
}
#[test]
fn get_mod_location() {
let cfg = create_config();
let mod_dir = cfg.mod_location();
assert!(mod_dir.is_absolute(), "Path not absolute");
assert_eq!(mod_dir, PathBuf::from("/config/mods"));
}
#[test]
fn add_mod() {
let mut cfg = create_config();
let new_mod = ModConfig::new("new_mod", "new_mod_path");
cfg.add_mod(&new_mod);
let found_mod = cfg.mod_by_id("new_mod");
assert!(found_mod.is_some());
let unwraped = found_mod.expect("Asserted before");
assert_eq!(unwraped.path(), new_mod.path());
}
}