use minigraf::{Minigraf, OpenOptions};
fn db() -> Minigraf {
OpenOptions::new().open_memory().unwrap()
}
#[test]
fn sum_string_attribute_error() {
let db = db();
db.execute(r#"(transact [[:a :score "high"] [:b :score "low"]])"#)
.unwrap();
let r = db.execute(r#"(query [:find (sum ?s) :where [?e :score ?s]])"#);
assert!(r.is_err(), "sum of strings must fail at runtime");
}
#[test]
fn sum_mixed_int_string_error() {
let db = db();
db.execute(r#"(transact [[:a :score 10] [:b :score "twenty"]])"#)
.unwrap();
let r = db.execute(r#"(query [:find (sum ?s) :where [?e :score ?s]])"#);
assert!(
r.is_err(),
"sum of mixed integer/string must fail at runtime"
);
}
#[test]
fn max_boolean_attribute_error() {
let db = db();
db.execute(r#"(transact [[:a :flag true] [:b :flag false]])"#)
.unwrap();
let r = db.execute(r#"(query [:find (max ?f) :where [?e :flag ?f]])"#);
assert!(r.is_err(), "max of booleans must fail at runtime");
}
#[test]
fn negative_cycle_pair_rejected() {
let db = db();
db.execute(r#"(rule [(p ?x) [?x :base true] (not (q ?x))])"#)
.unwrap();
let r = db.execute(r#"(rule [(q ?x) [?x :base true] (not (p ?x))])"#);
assert!(
r.is_err(),
"negative cycle p not-q and q not-p must be rejected"
);
let msg = r.unwrap_err().to_string();
assert!(
msg.contains("negative cycle") || msg.contains("unstratifiable"),
"error must mention the cycle"
);
}
#[test]
fn or_negative_cycle_rejected() {
let db = db();
db.execute(r#"(rule [(safe ?x) [?x :item true] (not (unsafe ?x))])"#)
.unwrap();
let r = db
.execute(r#"(rule [(unsafe ?x) [?x :item true] (or (not (safe ?x)) [?x :flagged true])])"#);
assert!(r.is_err(), "or-with-negative-cycle must be rejected");
}
#[test]
fn not_join_unbound_join_var_rejected() {
let db = db();
let r = db.execute(
r#"(query [:find ?e
:where [?e :a ?v]
(not-join [?x]
[?e :ref ?x]
[?x :blocked true])])"#,
);
assert!(
r.is_err(),
"not-join with unbound join var must fail at parse"
);
}
#[test]
fn or_mismatched_new_vars_rejected() {
let db = db();
let r = db.execute(
r#"(query [:find ?e
:where [?e :type ?_t]
(or [?e :a ?x]
[?e :b ?y])])"#,
);
assert!(r.is_err(), "or with mismatched new vars must fail at parse");
}
#[test]
fn aggregate_var_unbound_rejected() {
let db = db();
let r = db.execute(r#"(query [:find (count ?unbound) :where [?e :a ?v]])"#);
assert!(r.is_err(), "count on unbound variable must fail at parse");
}