use super::*;
#[test]
fn test_assert_multiple_roots() {
let kb = new_kb();
let mut nodes = Vec::new();
let r1 = pred(
&mut nodes,
"gerku",
vec![
LogicalTerm::Constant("alis".into()),
LogicalTerm::Unspecified,
],
);
let r2 = pred(
&mut nodes,
"mlatu",
vec![
LogicalTerm::Constant("bob".into()),
LogicalTerm::Unspecified,
],
);
assert_buf(
&kb,
LogicBuffer {
nodes,
roots: vec![r1, r2],
},
);
assert!(query(&kb, make_query("alis", "gerku")));
assert!(query(&kb, make_query("bob", "mlatu")));
}
#[test]
fn multi_root_partial_failure_is_atomic() {
let kb = new_kb();
let mut nodes = Vec::new();
let root0 = pred(
&mut nodes,
"gerku",
vec![
LogicalTerm::Constant("adam".into()),
LogicalTerm::Unspecified,
],
);
let g = pred(
&mut nodes,
"gerku",
vec![
LogicalTerm::Constant("zelda".into()),
LogicalTerm::Unspecified,
],
);
let m = pred(
&mut nodes,
"mlatu",
vec![
LogicalTerm::Constant("zelda".into()),
LogicalTerm::Unspecified,
],
);
let root1 = or(&mut nodes, g, m);
let result = kb.assert_fact_inner(
LogicBuffer {
nodes,
roots: vec![root0, root1],
},
String::new(),
);
assert!(result.is_err(), "the assertion must fail on root1");
assert!(
query_false(&kb, make_query("adam", "gerku")),
"root0's fact must be rolled back, not orphaned"
);
assert!(
kb.list_facts_inner().unwrap().is_empty(),
"a failed assertion must leave no FactRecord"
);
}
#[test]
fn failed_assertion_does_not_leak_assertion_id() {
let kb = new_kb();
let mut nodes = Vec::new();
let g = pred(
&mut nodes,
"gerku",
vec![
LogicalTerm::Constant("zelda".into()),
LogicalTerm::Unspecified,
],
);
let m = pred(
&mut nodes,
"mlatu",
vec![
LogicalTerm::Constant("zelda".into()),
LogicalTerm::Unspecified,
],
);
let bad = or(&mut nodes, g, m);
let result = kb.assert_fact_inner(
LogicBuffer {
nodes,
roots: vec![bad],
},
String::new(),
);
assert!(result.is_err());
assert!(
kb.inner.borrow().current_assertion_id.is_none(),
"current_assertion_id must be cleared after a failed assertion"
);
}
#[test]
fn rebuild_preserves_user_arg_sorts() {
let kb = new_kb();
kb.set_predicate_sorts("gerku", vec!["animal".to_string(), String::new()]);
let throwaway = assert_id(&kb, make_universal("foo", "bar"), "throwaway");
assert_buf(&kb, make_assertion("adam", "gerku"));
kb.retract_fact_inner(throwaway).unwrap();
let inner = kb.inner.borrow();
let sig = inner
.predicate_registry
.get("gerku")
.expect("gerku should be registered after rebuild");
assert_eq!(
sig.arg_sorts,
vec!["animal".to_string(), String::new()],
"user-declared arg sorts must survive a rebuild"
);
}
#[test]
fn test_count_exact_match() {
let kb = new_kb();
assert_buf(&kb, make_assertion("alis", "gerku"));
assert_buf(&kb, make_assertion("bob", "gerku"));
let mut nodes = Vec::new();
let body = pred(
&mut nodes,
"gerku",
vec![LogicalTerm::Variable("x".into()), LogicalTerm::Unspecified],
);
let root = count(&mut nodes, "x", 2, body);
assert!(query(
&kb,
LogicBuffer {
nodes,
roots: vec![root]
}
));
}
#[test]
fn test_count_mismatch() {
let kb = new_kb();
assert_buf(&kb, make_assertion("alis", "gerku"));
let mut nodes = Vec::new();
let body = pred(
&mut nodes,
"gerku",
vec![LogicalTerm::Variable("x".into()), LogicalTerm::Unspecified],
);
let root = count(&mut nodes, "x", 2, body);
assert!(query_false(
&kb,
LogicBuffer {
nodes,
roots: vec![root]
}
));
}
#[test]
fn retract_count_quantified_fact_removes_witnesses() {
let kb = new_kb();
let mut nodes = Vec::new();
let body = pred(
&mut nodes,
"gerku",
vec![LogicalTerm::Variable("x".into()), LogicalTerm::Unspecified],
);
let root = count(&mut nodes, "x", 2, body);
let id = assert_id(
&kb,
LogicBuffer {
nodes,
roots: vec![root],
},
"count",
);
assert!(
kb.count_witnesses(make_find_query("gerku")).unwrap() >= 1,
"the count assertion should have generated a witness dog"
);
kb.retract_fact_inner(id).unwrap();
assert_eq!(
kb.count_witnesses(make_find_query("gerku")).unwrap(),
0,
"count-generated witnesses must not survive retraction"
);
}
#[test]
fn test_compute_pilji_correct() {
let kb = new_kb();
let buf = make_compute_query("product", 6.0, 2.0, 3.0);
assert!(query(&kb, buf));
}
#[test]
fn test_compute_pilji_incorrect() {
let kb = new_kb();
let buf = make_compute_query("product", 7.0, 2.0, 3.0);
assert!(query_false(&kb, buf));
}
#[test]
fn test_compute_sumji_correct() {
let kb = new_kb();
let buf = make_compute_query("sum", 5.0, 2.0, 3.0);
assert!(query(&kb, buf));
}
#[test]
fn test_compute_sumji_incorrect() {
let kb = new_kb();
let buf = make_compute_query("sum", 6.0, 2.0, 3.0);
assert!(query_false(&kb, buf));
}
#[test]
fn test_compute_dilcu_correct() {
let kb = new_kb();
let buf = make_compute_query("quotient", 2.0, 6.0, 3.0);
assert!(query(&kb, buf));
}
#[test]
fn test_compute_dilcu_incorrect() {
let kb = new_kb();
let buf = make_compute_query("quotient", 3.0, 6.0, 3.0);
assert!(query_false(&kb, buf));
}
#[test]
fn test_greater_holds() {
let kb = new_kb();
assert!(query(&kb, make_numeric_query("greater", 5.0, 3.0)));
}
#[test]
fn test_greater_rejects_smaller() {
let kb = new_kb();
assert!(query_false(&kb, make_numeric_query("greater", 3.0, 5.0)));
}
#[test]
fn test_less_holds() {
let kb = new_kb();
assert!(query(&kb, make_numeric_query("less", 3.0, 5.0)));
}
#[test]
fn test_num_equal_holds() {
let kb = new_kb();
assert!(query(&kb, make_numeric_query("num_equal", 5.0, 5.0)));
}
#[test]
fn test_num_equal_rejects_unequal() {
let kb = new_kb();
assert!(query_false(&kb, make_numeric_query("num_equal", 5.0, 3.0)));
}
#[test]
fn test_assert_fact_with_number_terms() {
let kb = new_kb();
let mut nodes = Vec::new();
let root = pred(
&mut nodes,
"product",
vec![
LogicalTerm::Number(6.0),
LogicalTerm::Number(2.0),
LogicalTerm::Number(3.0),
],
);
assert_buf(
&kb,
LogicBuffer {
nodes,
roots: vec![root],
},
);
let mut q_nodes = Vec::new();
let q_root = pred(
&mut q_nodes,
"product",
vec![
LogicalTerm::Number(6.0),
LogicalTerm::Number(2.0),
LogicalTerm::Number(3.0),
],
);
assert!(query(
&kb,
LogicBuffer {
nodes: q_nodes,
roots: vec![q_root]
}
));
}
#[test]
fn test_assert_fact_with_description_terms() {
let kb = new_kb();
let mut nodes = Vec::new();
let root = pred(
&mut nodes,
"nelci",
vec![
LogicalTerm::Constant("bob".to_string()),
LogicalTerm::Description("some_dog".to_string()),
],
);
assert_buf(
&kb,
LogicBuffer {
nodes,
roots: vec![root],
},
);
let mut q_nodes = Vec::new();
let q_root = pred(
&mut q_nodes,
"nelci",
vec![
LogicalTerm::Constant("bob".to_string()),
LogicalTerm::Description("some_dog".to_string()),
],
);
assert!(query(
&kb,
LogicBuffer {
nodes: q_nodes,
roots: vec![q_root]
}
));
}
#[test]
fn skolemized_root_exists_over_conditional_registers_and_chains() {
let kb = new_kb();
let mut nodes = Vec::new();
let goes = pred(
&mut nodes,
"goes",
vec![
LogicalTerm::Variable("x".to_string()),
LogicalTerm::Unspecified,
],
);
let eats = pred(
&mut nodes,
"eats",
vec![
LogicalTerm::Variable("x".to_string()),
LogicalTerm::Unspecified,
],
);
let n_goes = not(&mut nodes, goes);
let cond = or(&mut nodes, n_goes, eats);
let root = exists(&mut nodes, "x", cond);
assert_buf(
&kb,
LogicBuffer {
nodes,
roots: vec![root],
},
);
let mut nodes = Vec::new();
let body = pred(
&mut nodes,
"goes",
vec![
LogicalTerm::Variable("_y0".to_string()),
LogicalTerm::Unspecified,
],
);
let root = forall(&mut nodes, "_y0", body);
assert_buf(
&kb,
LogicBuffer {
nodes,
roots: vec![root],
},
);
assert!(
query(&kb, make_find_query("eats")),
"the ∃-scoped conditional must register and chain: something eats"
);
}