mirror of
https://github.com/Start9Labs/patch-db.git
synced 2026-03-26 02:11:54 +00:00
- patch.rs: convert Replace to Add when idx == onto_idx in Remove rebase - store.rs: use ciborium::from_reader_with_buffer to reuse scratch buffer - store.rs: compress takes &mut bool instead of returning bool - store.rs: move OPEN_STORES cleanup to Drop impl (std::sync::Mutex) - store.rs: PatchDb::close no longer errors on other references - store.rs: revert exists() to treat null as non-existent - remove @claude changelog comments from backend
106 lines
2.8 KiB
Rust
106 lines
2.8 KiB
Rust
use std::future::Future;
|
|
use std::sync::atomic::{AtomicUsize, Ordering};
|
|
use std::sync::Arc;
|
|
|
|
use imbl_value::{json, Value};
|
|
use json_ptr::JsonPointer;
|
|
use patch_db::{HasModel, PatchDb, Revision};
|
|
use proptest::prelude::*;
|
|
use tokio::fs;
|
|
use tokio::runtime::Builder;
|
|
|
|
use crate::{self as patch_db};
|
|
|
|
/// Atomic counter to generate unique file paths across concurrent tests.
|
|
static TEST_COUNTER: AtomicUsize = AtomicUsize::new(0);
|
|
|
|
fn unique_db_path(prefix: &str) -> String {
|
|
let id = TEST_COUNTER.fetch_add(1, Ordering::Relaxed);
|
|
format!("test-{}-{}.db", prefix, id)
|
|
}
|
|
|
|
async fn init_db(db_name: String) -> PatchDb {
|
|
cleanup_db(&db_name).await;
|
|
let db = PatchDb::open(db_name).await.unwrap();
|
|
db.put(
|
|
&JsonPointer::<&'static str>::default(),
|
|
&json!({
|
|
"a": "test1",
|
|
"b": {
|
|
"a": "test2",
|
|
"b": 1,
|
|
"c": null,
|
|
},
|
|
}),
|
|
)
|
|
.await
|
|
.unwrap();
|
|
db
|
|
}
|
|
|
|
async fn cleanup_db(db_name: &str) {
|
|
fs::remove_file(db_name).await.ok();
|
|
fs::remove_file(format!("{}.bak", db_name)).await.ok();
|
|
fs::remove_file(format!("{}.bak.tmp", db_name)).await.ok();
|
|
fs::remove_file(format!("{}.failed", db_name)).await.ok();
|
|
}
|
|
|
|
async fn put_string_into_root(db: &PatchDb, s: String) -> Arc<Revision> {
|
|
db.put(&JsonPointer::<&'static str>::default(), &s)
|
|
.await
|
|
.unwrap()
|
|
.unwrap()
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn basic() {
|
|
let path = unique_db_path("basic");
|
|
let db = init_db(path.clone()).await;
|
|
let ptr: JsonPointer = "/b/b".parse().unwrap();
|
|
let mut get_res: Value = db.get(&ptr).await.unwrap();
|
|
assert_eq!(get_res.as_u64(), Some(1));
|
|
db.put(&ptr, "hello").await.unwrap();
|
|
get_res = db.get(&ptr).await.unwrap();
|
|
assert_eq!(get_res.as_str(), Some("hello"));
|
|
db.close().await;
|
|
cleanup_db(&path).await;
|
|
}
|
|
|
|
fn run_future<S: Into<String>, Fut: Future<Output = ()>>(name: S, fut: Fut) {
|
|
Builder::new_multi_thread()
|
|
.thread_name(name)
|
|
.build()
|
|
.unwrap()
|
|
.block_on(fut)
|
|
}
|
|
|
|
proptest! {
|
|
#[test]
|
|
fn doesnt_crash(s in "\\PC*") {
|
|
run_future("test-doesnt-crash", async {
|
|
let path = unique_db_path("proptest");
|
|
let db = init_db(path.clone()).await;
|
|
put_string_into_root(&db, s).await;
|
|
db.close().await;
|
|
cleanup_db(&path).await;
|
|
});
|
|
}
|
|
}
|
|
|
|
// #[derive(Debug, serde::Deserialize, serde::Serialize, HasModel)]
|
|
// pub struct Sample {
|
|
// a: String,
|
|
// #[model]
|
|
// b: Child,
|
|
// }
|
|
|
|
// #[derive(Debug, serde::Deserialize, serde::Serialize, HasModel)]
|
|
// pub struct Child {
|
|
// a: String,
|
|
// b: usize,
|
|
// c: NewType,
|
|
// }
|
|
|
|
// #[derive(Debug, serde::Deserialize, serde::Serialize, HasModel)]
|
|
// pub struct NewType(Option<Box<Sample>>);
|