#![allow(
clippy::unwrap_used,
clippy::expect_used,
clippy::panic,
clippy::needless_raw_string_hashes,
clippy::duration_suboptimal_units,
clippy::branches_sharing_code,
clippy::used_underscore_binding,
clippy::single_char_pattern,
clippy::ignore_without_reason,
clippy::cloned_ref_to_slice_refs,
clippy::doc_overindented_list_items,
clippy::match_wildcard_for_single_variants,
clippy::ignored_unit_patterns,
clippy::needless_collect,
clippy::unnecessary_map_or,
clippy::manual_flatten,
clippy::manual_strip,
clippy::future_not_send,
clippy::unnested_or_patterns,
clippy::no_effect_underscore_binding,
clippy::literal_string_with_formatting_args
)]
use ggen_graph::graph::quad::parse_nquad;
use ggen_graph::ocel::{OcelEvent, OcelLog, OcelObject};
use ggen_graph::{AdapterLayer, GenesisCore, OuterMembrane, ProjectionLayer};
use serde_json::json;
#[test]
fn test_genesis_core_and_transaction() -> Result<(), Box<dyn std::error::Error>> {
let core = GenesisCore::new()?;
let q1 = parse_nquad("<http://example.org/alice> <http://example.org/name> \"Alice\" <http://example.org/graph> .")?;
let q2 = parse_nquad(
"<http://example.org/bob> <http://example.org/name> \"Bob\" <http://example.org/graph> .",
)?;
let hash_init = core.graph().state_hash()?;
let delta = ggen_graph::RdfDelta::new(vec![q1.to_string()], vec![]);
let receipt = core.execute_transaction(&delta)?;
assert_eq!(receipt.pre_state_hash, hash_init);
assert_ne!(receipt.post_state_hash, hash_init);
assert!(core.graph().contains_quad(&q1)?);
assert!(!core.graph().contains_quad(&q2)?);
receipt.verify()?;
Ok(())
}
#[test]
fn test_outer_membrane_sanitization_and_injection_blocks() -> Result<(), Box<dyn std::error::Error>>
{
let membrane = OuterMembrane::new();
let res_empty = membrane.admit_input(" ");
assert!(res_empty.is_err());
assert_eq!(
res_empty.unwrap_err().to_string(),
"Other error: Empty input rejected by outer membrane"
);
let res_drop = membrane.admit_input("DROP GRAPH <http://example.org/g>");
assert!(res_drop.is_err());
assert!(res_drop
.unwrap_err()
.to_string()
.contains("Security violation"));
let res_delete = membrane.admit_input("DELETE WHERE { ?s ?p ?o }");
assert!(res_delete.is_err());
assert!(res_delete
.unwrap_err()
.to_string()
.contains("Security violation"));
let res_valid = membrane.admit_input("SELECT ?s ?p ?o WHERE { ?s ?p ?o }");
assert!(res_valid.is_ok());
let valid_quad = parse_nquad(
"<http://example.org/s> <http://example.org/p> \"o\" <http://example.org/g> .",
)?;
assert!(membrane.validate_quads(&[valid_quad]).is_ok());
Ok(())
}
#[test]
fn test_adapter_layer_json_rpc() -> Result<(), Box<dyn std::error::Error>> {
let req = json!({
"jsonrpc": "2.0",
"method": "apply_delta",
"params": {
"additions": [
"<http://example.org/a> <http://example.org/b> \"c\" <http://example.org/g> ."
],
"deletions": []
},
"id": 1
});
let delta = AdapterLayer::adapt_json_rpc(&req)?;
assert_eq!(delta.additions.len(), 1);
assert_eq!(delta.deletions.len(), 0);
assert_eq!(
delta.additions[0],
"<http://example.org/a> <http://example.org/b> \"c\" <http://example.org/g> ."
);
let malformed_req = json!({
"jsonrpc": "2.0",
"method": "apply_delta",
"id": 1
});
assert!(AdapterLayer::adapt_json_rpc(&malformed_req).is_err());
let bad_method_req = json!({
"jsonrpc": "2.0",
"method": "delete_all",
"params": {
"additions": [],
"deletions": []
},
"id": 1
});
assert!(AdapterLayer::adapt_json_rpc(&bad_method_req).is_err());
Ok(())
}
#[test]
fn test_projection_layer_ocel() -> Result<(), Box<dyn std::error::Error>> {
let core = GenesisCore::new()?;
let log = OcelLog {
objects: vec![OcelObject {
id: "obj-1".to_string(),
r#type: "CustomType".to_string(),
attributes: std::collections::HashMap::new(),
}],
events: vec![OcelEvent {
id: "ev-1".to_string(),
activity: "PerformAction".to_string(),
timestamp: chrono::DateTime::parse_from_rfc3339("2026-05-27T06:00:00Z")
.unwrap()
.into(),
objects: vec![],
attributes: std::collections::HashMap::new(),
}],
};
ProjectionLayer::project_ocel_to_state(&core, &log)?;
let extracted = ProjectionLayer::project_state_to_ocel(&core)?;
assert_eq!(extracted.objects.len(), 1);
assert_eq!(extracted.objects[0].id, "obj-1");
assert_eq!(extracted.objects[0].r#type, "CustomType");
assert_eq!(extracted.events.len(), 1);
assert_eq!(extracted.events[0].id, "ev-1");
assert_eq!(extracted.events[0].activity, "PerformAction");
Ok(())
}