use edn::parse;
use edn::query::{PatternNonValuePlace, WhereClause};
#[test]
fn in_sources_and_bindings() {
let q = parse::parse_query("[:find ?x :in $ [?a ...] :where [?x :foo/bar ?a]]").unwrap();
assert_eq!((q.in_bindings.len(), q.in_sources.len()), (1, 1));
}
#[test]
fn in_scalar_derives_in_vars() {
let q = parse::parse_query("[:find ?x :in ?y :where [?x :foo/bar ?y]]").unwrap();
assert_eq!(q.in_vars.len(), 1);
assert_eq!(q.in_bindings.len(), 1);
}
#[test]
fn five_place_pattern_parses_with_added() {
let q = parse::parse_query("[:find ?e :where [?e ?a ?v ?tx ?added]]").unwrap();
match &q.where_clauses[0] {
WhereClause::Pattern(p) => assert!(matches!(p.added, PatternNonValuePlace::Variable(_))),
_ => panic!("expected a pattern"),
}
}
#[test]
fn four_place_pattern_has_placeholder_added() {
let q = parse::parse_query("[:find ?e :where [?e :foo/bar ?v]]").unwrap();
match &q.where_clauses[0] {
WhereClause::Pattern(p) => assert_eq!(p.added, PatternNonValuePlace::Placeholder),
_ => panic!("expected a pattern"),
}
}
#[test]
fn rules_under_both_rules_and_with() {
for q in [
"[:find ?p :rules [[(adult ?p) [?p :person/age ?a]]] :where (adult ?p)]",
"[:find ?p :with [[(adult ?p) [?p :person/age ?a]]] :where (adult ?p)]",
] {
assert_eq!(parse::parse_query(q).unwrap().rules.len(), 1, "{q}");
}
}
#[test]
fn with_vars_still_means_with_vars() {
let q = parse::parse_query("[:find (count ?x) :with ?y :where [?x :a/b ?y]]").unwrap();
assert_eq!(q.with.len(), 1);
assert_eq!(q.rules.len(), 0);
}
#[test]
fn plain_keyword_value_parses() {
assert!(parse::parse_query("[:find ?e :where [?e :task/status :done]]").is_ok());
}
#[test]
fn reverse_pull_parses() {
assert!(
parse::parse_query("[:find (pull ?e [:person/_friends]) :where [?e :person/name _]]")
.is_ok()
);
}
#[test]
fn builtin_tx_fn_exists() {
let _ = edn::entities::BuiltinTxFn::Cas;
let _ = edn::entities::BuiltinTxFn::RetractEntity;
}
#[test]
fn arithmetic_where_fns_parse_including_plus_minus_div() {
for op in ["+", "-", "*", "/"] {
let q = parse::parse_query(&format!(
"[:find ?s :where [?e :a/n ?n] [({op} ?n 10) ?s] [(> ?s 1)]]"
))
.unwrap_or_else(|e| panic!("{op}: {e:?}"));
match &q.where_clauses[1] {
WhereClause::WhereFn(f) => assert_eq!(f.operator.0.as_str(), op),
other => panic!("{op}: expected a where-fn, got {other:?}"),
}
}
let q = parse::parse_query("[:find ?s :where [?e :a/n ?n] [(+ ?n -5) ?s]]").unwrap();
match &q.where_clauses[1] {
WhereClause::WhereFn(f) => assert_eq!(format!("{:?}", f.args[1]), "EntidOrInteger(-5)"),
other => panic!("expected a where-fn, got {other:?}"),
}
}
#[test]
fn sign_and_slash_symbols_follow_the_edn_spec() {
use edn::types::Value;
let v = |s: &str| parse::value(s).unwrap().without_spans();
let sym = |s: &str| Value::PlainSymbol(edn::symbols::PlainSymbol::plain(s));
for s in ["+", "-", "/", "-foo", "+bar"] {
assert_eq!(v(s), sym(s), "{s}");
}
assert_eq!(v("-5"), Value::Integer(-5));
assert_eq!(v("+5"), Value::Integer(5));
assert_eq!(format!("{:?}", v("-1.5")), "Float(-1.5)");
assert_eq!(
v("(- -5 3)"),
Value::List(
vec![sym("-"), Value::Integer(-5), Value::Integer(3)]
.into_iter()
.collect()
)
);
}