mirror of
https://github.com/Start9Labs/patch-db.git
synced 2026-03-26 10:21:53 +00:00
audit fixes, repo restructure, and documentation
Soundness and performance audit (17 fixes): - See AUDIT.md for full details and @claude comments in code Repo restructure: - Inline json-ptr and json-patch submodules as regular directories - Remove cbor submodule, replace serde_cbor with ciborium - Rename patch-db/ -> core/, patch-db-macro/ -> macro/, patch-db-macro-internals/ -> macro-internals/, patch-db-util/ -> util/ - Purge upstream CI/CD, bench, and release cruft from json-patch - Remove .gitmodules Test fixes: - Fix proptest doesnt_crash (unique file paths, proper close/cleanup) - Add PatchDb::close() for clean teardown Documentation: - Add README.md, ARCHITECTURE.md, CONTRIBUTING.md, CLAUDE.md, AUDIT.md - Add TSDocs to TypeScript client exports Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
105
core/src/test.rs
Normal file
105
core/src/test.rs
Normal file
@@ -0,0 +1,105 @@
|
||||
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.unwrap();
|
||||
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.unwrap();
|
||||
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>>);
|
||||
Reference in New Issue
Block a user