test: cover resolve_library_param and per-library ExifDao filter

Adds 9 unit tests around the library plumbing:
- resolve_library_param branches (absent, empty/whitespace, numeric id,
  name, unknown id, unknown name)
- Library::resolve symmetry with strip_root
- ExifDao::get_all_with_date_taken in union and scoped modes

Introduces SqliteExifDao::from_connection test constructor mirroring the
existing preview_dao pattern so DAO tests can drive an in-memory SQLite.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Cameron
2026-04-18 18:25:47 -04:00
committed by cameron
parent b04dd8b601
commit 4a775b5e9b
2 changed files with 177 additions and 0 deletions

View File

@@ -403,6 +403,13 @@ impl SqliteExifDao {
connection: Arc::new(Mutex::new(connect())),
}
}
#[cfg(test)]
pub fn from_connection(conn: SqliteConnection) -> Self {
SqliteExifDao {
connection: Arc::new(Mutex::new(conn)),
}
}
}
impl ExifDao for SqliteExifDao {
@@ -927,3 +934,92 @@ impl ExifDao for SqliteExifDao {
.map_err(|_| DbError::new(DbErrorKind::QueryError))
}
}
#[cfg(test)]
mod exif_dao_tests {
use super::*;
use crate::database::models::InsertLibrary;
use crate::database::test::in_memory_db_connection;
fn ctx() -> opentelemetry::Context {
opentelemetry::Context::new()
}
fn insert_row(dao: &mut SqliteExifDao, lib_id: i32, rel: &str, date: Option<i64>) {
dao.store_exif(
&ctx(),
InsertImageExif {
library_id: lib_id,
file_path: rel.to_string(),
camera_make: None,
camera_model: None,
lens_model: None,
width: None,
height: None,
orientation: None,
gps_latitude: None,
gps_longitude: None,
gps_altitude: None,
focal_length: None,
aperture: None,
shutter_speed: None,
iso: None,
date_taken: date,
created_time: 0,
last_modified: 0,
content_hash: None,
size_bytes: None,
},
)
.expect("insert exif row");
}
fn setup_two_libraries() -> SqliteExifDao {
let mut conn = in_memory_db_connection();
// Migration seeds library id=1 with a placeholder root; add id=2.
diesel::insert_into(schema::libraries::table)
.values(InsertLibrary {
name: "archive",
root_path: "/tmp/archive",
created_at: 0,
})
.execute(&mut conn)
.expect("seed second library");
SqliteExifDao::from_connection(conn)
}
#[test]
fn get_all_with_date_taken_union_returns_all_libraries() {
let mut dao = setup_two_libraries();
insert_row(&mut dao, 1, "main/a.jpg", Some(100));
insert_row(&mut dao, 2, "archive/b.jpg", Some(200));
// Row without a date must be excluded even in union mode.
insert_row(&mut dao, 2, "archive/c.jpg", None);
let mut rows = dao.get_all_with_date_taken(&ctx(), None).unwrap();
rows.sort_by_key(|(_, ts)| *ts);
assert_eq!(
rows,
vec![
("main/a.jpg".to_string(), 100),
("archive/b.jpg".to_string(), 200),
]
);
}
#[test]
fn get_all_with_date_taken_scopes_by_library_id() {
let mut dao = setup_two_libraries();
insert_row(&mut dao, 1, "main/a.jpg", Some(100));
insert_row(&mut dao, 2, "archive/b.jpg", Some(200));
insert_row(&mut dao, 2, "archive/c.jpg", Some(300));
let lib2 = dao.get_all_with_date_taken(&ctx(), Some(2)).unwrap();
let mut paths: Vec<String> = lib2.into_iter().map(|(p, _)| p).collect();
paths.sort();
assert_eq!(paths, vec!["archive/b.jpg", "archive/c.jpg"]);
let lib1 = dao.get_all_with_date_taken(&ctx(), Some(1)).unwrap();
assert_eq!(lib1, vec![("main/a.jpg".to_string(), 100)]);
}
}