test: add tests to sqlite_persist_catalog function

This commit is contained in:
2025-10-16 16:15:49 +02:00
parent 79fc4272b6
commit a5dcf7b54a

View File

@@ -89,29 +89,153 @@ pub fn run(path: &path::Path, catalog: &Catalog) -> result::Result<(), FailedTo>
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use std::{collections::HashMap, fs, path::Path};
fn setup_db(db_path: &Path) -> Connection {
let _ = fs::remove_file(db_path);
fun::sqlite_init_db::run(db_path).unwrap();
Connection::open(db_path).unwrap()
}
fn count_rows(conn: &Connection, table: &str, where_clause: &str) -> i64 {
let mut stmt = conn
.prepare(&format!(
"SELECT COUNT(*) FROM {} WHERE {}",
table, where_clause
))
.unwrap();
stmt.query_row([], |row| row.get(0)).unwrap()
}
#[test] #[test]
fn persist_should_insert_new_entities_and_attributes() { fn persist_should_insert_new_entities_and_attributes() {
// Verifies that entities marked as 'New' in the catalog are inserted into the database, along with all their attributes. // Verifies that entities marked as 'New' in the catalog are inserted into the database, along with all their attributes.
todo!(); let db_path = Path::new("test_insert.db");
let conn = setup_db(db_path);
let mut catalog = Catalog::new(db_path.to_str().unwrap());
let mut entity = Entity {
id: "e1".to_string(),
class: "c1".to_string(),
attributes: HashMap::new(),
state: EntityState::New,
ref_date: None,
};
entity.attributes.insert(
"a1".to_string(),
Attribute {
id: "a1".to_string(),
value: Value::Text("v1".to_string()),
},
);
catalog.items.insert("e1".to_string(), entity);
assert!(run(db_path, &catalog).is_ok());
assert_eq!(count_rows(&conn, "entity", "id = 'e1'"), 1);
assert_eq!(count_rows(&conn, "attribute", "entity_id = 'e1'"), 1);
fs::remove_file(db_path).unwrap();
} }
#[test] #[test]
fn persist_should_delete_entities_marked_for_deletion() { fn persist_should_delete_entities_marked_for_deletion() {
// Ensures that entities marked as 'ToDelete' are correctly removed from the database. // Ensures that entities marked as 'ToDelete' are correctly removed from the database.
todo!(); let db_path = Path::new("test_delete.db");
let conn = setup_db(db_path);
conn.execute("INSERT INTO entity (id, class) VALUES ('e1', 'c1')", [])
.unwrap();
let mut catalog = Catalog::new(db_path.to_str().unwrap());
let entity = Entity {
id: "e1".to_string(),
class: "c1".to_string(),
attributes: HashMap::new(),
state: EntityState::ToDelete,
ref_date: None,
};
catalog.items.insert("e1".to_string(), entity);
assert!(run(db_path, &catalog).is_ok());
assert_eq!(count_rows(&conn, "entity", "id = 'e1'"), 0);
fs::remove_file(db_path).unwrap();
} }
#[test] #[test]
fn persist_should_handle_a_mix_of_new_and_deleted_entities() { fn persist_should_handle_a_mix_of_new_and_deleted_entities() {
// Tests the function's ability to handle a batch operation involving both new entities to be inserted and existing ones to be deleted. // Tests the function's ability to handle a batch operation involving both new entities to be inserted and existing ones to be deleted.
todo!(); let db_path = Path::new("test_mix.db");
let conn = setup_db(db_path);
conn.execute("INSERT INTO entity (id, class) VALUES ('e1', 'c1')", [])
.unwrap();
let mut catalog = Catalog::new(db_path.to_str().unwrap());
let to_delete = Entity {
id: "e1".to_string(),
class: "c1".to_string(),
attributes: HashMap::new(),
state: EntityState::ToDelete,
ref_date: None,
};
let to_add = Entity {
id: "e2".to_string(),
class: "c2".to_string(),
attributes: HashMap::new(),
state: EntityState::New,
ref_date: None,
};
catalog.items.insert("e1".to_string(), to_delete);
catalog.items.insert("e2".to_string(), to_add);
assert!(run(db_path, &catalog).is_ok());
assert_eq!(count_rows(&conn, "entity", "id = 'e1'"), 0);
assert_eq!(count_rows(&conn, "entity", "id = 'e2'"), 1);
fs::remove_file(db_path).unwrap();
} }
#[test] #[test]
fn persist_should_not_affect_unmodified_entities() { fn persist_should_not_affect_unmodified_entities() {
// Verifies that entities in the catalog that are not marked as 'New' or 'ToDelete' remain untouched in the database. // Verifies that entities in the catalog that are not marked as 'New' or 'ToDelete' remain untouched in the database.
todo!(); let db_path = Path::new("test_unmodified.db");
let conn = setup_db(db_path);
conn.execute("INSERT INTO entity (id, class) VALUES ('e1', 'c1')", [])
.unwrap();
let mut catalog = Catalog::new(db_path.to_str().unwrap());
let unmodified = Entity {
id: "e1".to_string(),
class: "c1".to_string(),
attributes: HashMap::new(),
state: EntityState::Loaded,
ref_date: None,
};
catalog.items.insert("e1".to_string(), unmodified);
assert!(run(db_path, &catalog).is_ok());
assert_eq!(count_rows(&conn, "entity", "id = 'e1'"), 1);
fs::remove_file(db_path).unwrap();
} }
#[test] #[test]
fn persist_should_rollback_transaction_on_failure() { fn persist_should_rollback_transaction_on_failure() {
// Ensures that if any part of the persistence process fails, the entire transaction is rolled back, leaving the database state unchanged. // Ensures that if any part of the persistence process fails, the entire transaction is rolled back, leaving the database state unchanged.
todo!(); let db_path = Path::new("test_rollback.db");
let conn = setup_db(db_path);
conn.execute(
"INSERT INTO entity (id, class) VALUES ('e_existing', 'c1')",
[],
)
.unwrap();
let mut catalog = Catalog::new(db_path.to_str().unwrap());
let mut new_entity = Entity {
id: "e_new".to_string(),
class: "c1".to_string(),
attributes: HashMap::new(),
state: EntityState::New,
ref_date: None,
};
new_entity.attributes.insert(
"a1".to_string(),
Attribute {
id: "a1".to_string(),
value: Value::Text("v1".to_string()),
},
);
catalog.items.insert("e_new".to_string(), new_entity);
// Corrupt the DB to cause a failure during the transaction
conn.execute("DROP TABLE attribute", []).unwrap();
drop(conn);
let result = run(db_path, &catalog);
assert!(result.is_err());
// Re-open connection to check state
let conn = Connection::open(db_path).unwrap();
// The new entity should not have been inserted due to rollback
assert_eq!(count_rows(&conn, "entity", "id = 'e_new'"), 0);
// The existing entity should still be there
assert_eq!(count_rows(&conn, "entity", "id = 'e_existing'"), 1);
fs::remove_file(db_path).unwrap();
} }
} }