use super::*;
use crate::runtime::control_plane::receipts::{Blake3Hash, CryptographicReceipt};
use ed25519_dalek::Signer;
use oxigraph::model::{GraphName, Literal, NamedNode, NamedOrBlankNode, Quad, Term};
use oxigraph::sparql::{QueryResults, SparqlEvaluator};
use oxigraph::store::Store;
use rand_core::RngCore;
#[test]
fn test_xorshift_rng_determinism() {
let mut rng1 = XorshiftRng::new(42);
let mut rng2 = XorshiftRng::new(42);
assert_eq!(rng1.next_u64(), rng2.next_u64());
assert_eq!(rng1.next_u32(), rng2.next_u32());
}
#[test]
fn test_replay_clock_formatting() {
let clock = ReplayClock::new(1772886586000);
let iso = clock.now_iso();
assert_eq!(iso, "2026-03-07T12:29:46Z");
}
#[test]
fn test_preprocess_query_now_rand() {
let clock = ReplayClock::new(1772886586000);
let mut entropy = ReplayEntropy::new(42);
let query = "SELECT (now() AS ?time) (rand() AS ?r) WHERE { ?s ?p ?o }";
let preprocessed = preprocess_query(query, &clock, &mut entropy);
assert!(preprocessed
.contains("\"2026-03-07T12:29:46Z\"^^<http://www.w3.org/2001/XMLSchema#dateTime>"));
assert!(!preprocessed.contains("rand()"));
let query2 = "SELECT ?brand WHERE { ?s brand:now() ?o }";
let preprocessed2 = preprocess_query(query2, &clock, &mut entropy);
assert!(preprocessed2.contains("brand:now()"));
}
#[test]
fn test_hash_query_results_boolean() {
let res_t = QueryResults::Boolean(true);
let hash_t = hash_query_results(res_t).unwrap();
let res_f = QueryResults::Boolean(false);
let hash_f = hash_query_results(res_f).unwrap();
assert_ne!(hash_t, hash_f);
}
#[test]
fn test_verifier_end_to_end() {
let store = Store::new().unwrap();
let snap_graph = GraphName::NamedNode(NamedNode::new("urn:project:local:snapshot:g1").unwrap());
store
.insert(&Quad::new(
NamedOrBlankNode::NamedNode(NamedNode::new("urn:project:s1").unwrap()),
NamedNode::new("urn:project:p1").unwrap(),
Term::Literal(Literal::new_simple_literal("hello")),
snap_graph.clone(),
))
.unwrap();
let query_str = "SELECT ?val WHERE { ?s <urn:project:p1> ?val }";
let query_hash = crate::runtime::sha256(query_str.as_bytes());
let isolated = Store::new().unwrap();
isolated
.insert(&Quad::new(
NamedOrBlankNode::NamedNode(NamedNode::new("urn:project:s1").unwrap()),
NamedNode::new("urn:project:p1").unwrap(),
Term::Literal(Literal::new_simple_literal("hello")),
GraphName::DefaultGraph,
))
.unwrap();
let parsed = SparqlEvaluator::new().parse_query(query_str).unwrap();
let results = parsed.on_store(&isolated).execute().unwrap();
let expected_hash = hash_query_results(results).unwrap();
let rcpt_node = NamedOrBlankNode::NamedNode(NamedNode::new("urn:receipt:1").unwrap());
store
.insert(&Quad::new(
rcpt_node.clone(),
NamedNode::new("http://www.w3.org/1999/02/22-rdf-syntax-ns#type").unwrap(),
Term::NamedNode(NamedNode::new("urn:lsp-max:core:Receipt").unwrap()),
GraphName::DefaultGraph,
))
.unwrap();
store
.insert(&Quad::new(
rcpt_node.clone(),
NamedNode::new("urn:lsp-max:core:resultHash").unwrap(),
Term::Literal(Literal::new_simple_literal(expected_hash.clone())),
GraphName::DefaultGraph,
))
.unwrap();
store
.insert(&Quad::new(
rcpt_node.clone(),
NamedNode::new("urn:lsp-max:core:queryHash").unwrap(),
Term::Literal(Literal::new_simple_literal(query_hash.clone())),
GraphName::DefaultGraph,
))
.unwrap();
store
.insert(&Quad::new(
rcpt_node.clone(),
NamedNode::new("urn:lsp-max:core:graphHash").unwrap(),
Term::Literal(Literal::new_simple_literal("g1")),
GraphName::DefaultGraph,
))
.unwrap();
let mut verifier = QueryConsequenceReplayVerifier::new(1772886586000, 42);
verifier.register_query(query_hash.clone(), query_str.to_string());
let summary = verifier.verify_all(&store).unwrap();
assert_eq!(summary.total_replayed, 1);
assert_eq!(summary.total_success, 1);
assert_eq!(summary.total_mismatch, 0);
let check_replay_q = "
PREFIX max: <urn:lsp-max:core:>
ASK {
?r a max:Replay ;
max:queryHash ?qHash ;
max:graphHash ?gHash ;
max:resultHash ?resHash .
}
";
let parsed_check = SparqlEvaluator::new().parse_query(check_replay_q).unwrap();
let check_res = parsed_check.on_store(&store).execute().unwrap();
if let QueryResults::Boolean(val) = check_res {
assert!(val);
} else {
panic!("Expected boolean result");
}
}
#[test]
fn test_verify_replay_engine() {
use ed25519_dalek::SigningKey;
use uuid::Uuid;
let seed = [0u8; 32];
let signing_key = SigningKey::from_bytes(&seed);
let verifying_key = signing_key.verifying_key();
let genesis_hash = Blake3Hash([0u8; 32]);
let disc_id = Uuid::nil();
let law_id = Uuid::nil();
let mut r0 = CryptographicReceipt {
prev_hash: genesis_hash,
discipline_id: disc_id,
law_id,
consequence_hash: Blake3Hash([0u8; 32]),
sequence: 0,
signature: [0u8; 64],
};
let payload_hash_0 = r0.compute_payload_hash();
r0.signature = signing_key.sign(&payload_hash_0.0).to_bytes();
let mut r1 = CryptographicReceipt {
prev_hash: payload_hash_0,
discipline_id: disc_id,
law_id,
consequence_hash: Blake3Hash([42u8; 32]),
sequence: 1,
signature: [0u8; 64],
};
let payload_hash_1 = r1.compute_payload_hash();
r1.signature = signing_key.sign(&payload_hash_1.0).to_bytes();
let chain = vec![r0, r1];
let res = verify_replay(&chain, &verifying_key, &genesis_hash);
assert!(res.is_ok(), "Replay verification failed: {:?}", res);
let mut invalid_chain = chain.clone();
invalid_chain[1].prev_hash = Blake3Hash([99u8; 32]);
let res_invalid = verify_replay(&invalid_chain, &verifying_key, &genesis_hash);
assert!(res_invalid.is_err());
}