use roomrs::SchemaSnapshot;
fn json_v1() -> &'static str {
r#"{
"version": 1,
"tables": [{
"name": "items",
"columns": [
{ "name": "id", "sql_type": "INTEGER", "not_null": true, "pk": true }
],
"ddl": ["CREATE TABLE \"items\" (\"id\" INTEGER PRIMARY KEY)"]
}]
}"#
}
fn json_v2() -> &'static str {
r#"{
"version": 2,
"tables": [{
"name": "items",
"columns": [
{ "name": "id", "sql_type": "INTEGER", "not_null": true, "pk": true },
{ "name": "name", "sql_type": "TEXT", "not_null": false, "pk": false }
],
"ddl": [
"CREATE TABLE \"items\" (\"id\" INTEGER PRIMARY KEY, \"name\" TEXT)",
"CREATE INDEX \"idx_items_name\" ON \"items\"(\"name\")"
]
}]
}"#
}
#[test]
fn embedded_snapshot_roundtrip() {
let snap = SchemaSnapshot::from_slice(json_v1().as_bytes()).unwrap();
let json = snap.to_json().unwrap();
let comp = roomrs::compress_snapshot(json.as_bytes());
assert_eq!(
roomrs::decompress_snapshot(&comp).unwrap(),
json.as_bytes(),
"압축 왕복 무손실"
);
let embedded = roomrs::EmbeddedSchema {
version: 1,
compressed: Box::leak(comp.into_boxed_slice()),
};
let back = embedded.snapshot().unwrap();
assert_eq!(back, snap);
assert_eq!(back.hash(), snap.hash());
let bad = roomrs::EmbeddedSchema {
version: 9,
compressed: b"\xff\x00corrupt",
};
match bad.snapshot() {
Err(roomrs::Error::Migration(msg)) => assert!(msg.contains("내장 스냅샷"), "{msg}"),
other => panic!("Migration 에러 기대, 결과: {other:?}"),
}
}
#[test]
fn diff_plan_via_facade() {
let v1 = SchemaSnapshot::from_slice(json_v1().as_bytes()).unwrap();
let v2 = SchemaSnapshot::from_slice(json_v2().as_bytes()).unwrap();
let plan: roomrs::DiffPlan = roomrs::diff_plan(&v1, &v2);
assert_eq!(
plan.safe,
vec![
r#"ALTER TABLE "items" ADD COLUMN "name" TEXT"#.to_string(),
r#"CREATE INDEX "idx_items_name" ON "items"("name")"#.to_string(),
],
"안전 연산: nullable ADD COLUMN + CREATE INDEX"
);
assert!(plan.destructive.is_empty(), "{plan:?}");
let back = roomrs::diff_plan(&v2, &v1);
assert!(back.safe.is_empty(), "{back:?}");
assert_eq!(back.destructive.len(), 2, "{back:?}");
let sql = roomrs::diff_sql(&v1, &v2);
assert!(
sql.contains(r#"ALTER TABLE "items" ADD COLUMN "name" TEXT;"#),
"{sql}"
);
assert!(sql.contains("PRAGMA user_version = 2;"), "{sql}");
}
#[test]
fn snapshot_dir_scan_via_facade() {
let dir = tempfile::tempdir().unwrap();
let v1 = SchemaSnapshot::from_slice(json_v1().as_bytes()).unwrap();
let v2 = SchemaSnapshot::from_slice(json_v2().as_bytes()).unwrap();
assert_eq!(roomrs::snapshot_file_name("app_db", 2), "app_db.2.json");
v1.write_to(&roomrs::snapshot_path(dir.path(), "app_db", 1))
.unwrap();
v2.write_to(&roomrs::snapshot_path(dir.path(), "app_db", 2))
.unwrap();
v1.write_to(&roomrs::snapshot_path(dir.path(), "other_db", 1))
.unwrap();
std::fs::write(dir.path().join("app_db.x.json"), "무시").unwrap();
let files = roomrs::list_snapshot_versions(dir.path(), "app_db").unwrap();
let versions: Vec<u32> = files.iter().map(|(v, _)| *v).collect();
assert_eq!(versions, vec![1, 2], "오름차순 + 엄격 파스");
assert!(
roomrs::list_snapshot_versions(&dir.path().join("없음"), "app_db")
.unwrap()
.is_empty()
);
if std::env::var("ROOMRS_SCHEMA_DIR").is_err() {
assert_eq!(
roomrs::resolve_schema_dir("/proj"),
std::path::Path::new("/proj").join(roomrs::SCHEMA_DIR_RELATIVE)
);
}
}