use super::*;
#[test]
fn exactly_n_produces_count() {
let b = lb("big(exactly 2 dog).");
let (count, body) = match root(&b) {
LogicNode::CountNode((_, n, body)) => (*n, *body),
other => panic!("root not Count: {other:?}"),
};
assert_eq!(count, 2);
assert!(has_pred_from(&b, body, "dog"));
assert!(has_pred_from(&b, body, "big"));
}
#[test]
fn no_determiner_is_count_zero() {
let b = lb("big(no dog).");
assert!(matches!(root(&b), LogicNode::CountNode((_, 0, _))));
}
#[test]
fn exactly_one_is_count_one() {
let b = lb("big(exactly 1 dog).");
assert!(matches!(root(&b), LogicNode::CountNode((_, 1, _))));
}
#[test]
fn some_still_produces_exists_not_count() {
let b = lb("big(some dog).");
assert!(matches!(root(&b), LogicNode::ExistsNode(_)));
}
#[test]
fn afterthought_and_root() {
let b = lb("goes(me) & loves(you).");
assert!(matches!(root(&b), LogicNode::AndNode(_)));
}
#[test]
fn afterthought_or_root() {
let b = lb("goes(me) | loves(you).");
assert!(matches!(root(&b), LogicNode::OrNode(_)));
}
#[test]
fn biconditional_expands_to_and_of_ors() {
let b = lb("goes(me) <-> loves(you).");
let (l, r) = match root(&b) {
LogicNode::AndNode((l, r)) => (*l, *r),
other => panic!("root not And: {other:?}"),
};
for side in [l, r] {
let arm = match node(&b, side) {
LogicNode::OrNode((a, _)) => *a,
other => panic!("And child not Or: {other:?}"),
};
assert!(
matches!(node(&b, arm), LogicNode::NotNode(_)),
"Or arm not Not"
);
}
}
#[test]
fn free_var_closes_existentially() {
let b = lb("loves($da, me).");
assert!(matches!(root(&b), LogicNode::ExistsNode((v, _)) if v == "$da"));
assert!(matches!(role_filler(&b, "loves_x1"), Some(LogicalTerm::Variable(v)) if v == "$da"));
assert!(role_is_const(&b, "loves_x2", "me"));
assert!(free_vars(&b).is_empty());
}
#[test]
fn two_free_vars_nest_two_exists() {
let b = lb("loves($da, $de).");
assert_eq!(count_exists_binding(&b, "$da"), 1);
assert_eq!(count_exists_binding(&b, "$de"), 1);
assert!(free_vars(&b).is_empty());
}
#[test]
fn repeated_free_var_binds_once() {
let b = lb("loves($da, $da).");
assert_eq!(count_exists_binding(&b, "$da"), 1);
assert!(free_vars(&b).is_empty());
}
#[test]
fn single_free_var_di() {
let b = lb("big($di).");
assert!(matches!(root(&b), LogicNode::ExistsNode((v, _)) if v == "$di"));
assert!(free_vars(&b).is_empty());
}
#[test]
fn negation_is_outside_the_existential() {
let b = lb("~loves($da, me).");
let inner = match root(&b) {
LogicNode::NotNode(i) => *i,
other => panic!("root not Not: {other:?}"),
};
assert!(matches!(node(&b, inner), LogicNode::ExistsNode(_)));
assert!(free_vars(&b).is_empty());
}
#[test]
fn witness_binds_a_fresh_existential() {
let b = lb("goes(?).");
let bound = match root(&b) {
LogicNode::ExistsNode((v, _)) => v.clone(),
other => panic!("root not Exists: {other:?}"),
};
assert!(matches!(role_filler(&b, "goes_x1"), Some(LogicalTerm::Variable(v)) if v == bound));
assert!(free_vars(&b).is_empty());
}
#[test]
fn two_witnesses_are_independent() {
let b = lb("likes(?, ?).");
let x1 = role_filler(&b, "likes_x1").unwrap();
let x2 = role_filler(&b, "likes_x2").unwrap();
assert!(matches!(x1, LogicalTerm::Variable(_)));
assert!(matches!(x2, LogicalTerm::Variable(_)));
assert_ne!(x1, x2, "the two witnesses must be distinct vars");
assert!(free_vars(&b).is_empty());
}
#[test]
fn witness_not_stolen_by_nested_rel_clause() {
let b = lb("loves(?, some dog where big).");
assert!(free_vars(&b).is_empty());
}