use quarb::{Defs, expand};
fn exp(q: &str) -> String {
expand(q, &Defs::default()).unwrap()
}
fn err(q: &str) -> String {
expand(q, &Defs::default()).unwrap_err().to_string()
}
#[test]
fn a_constructor_builds_a_node_by_vocabulary() {
assert_eq!(
exp("macro &hop: ^ | syntax:step(\"//\"; \"row\"); /a&hop | count"),
"/a//row | count"
);
assert_eq!(
exp(
"macro &old: ^ | syntax:predicate(syntax:compare(\">\"; q(::age); q(30))); /row&old::name"
),
"/row[::age > 30]::name"
);
assert_eq!(
exp("macro &key($k): /k/literal | syntax:projection(::value); /row | &key(\"name\")"),
"/row | ::name"
);
assert_eq!(
exp(
"macro &deep: ^ | syntax:node(\"step\"; %(axis = \"//\"; matcher = \"*\")); /a&deep | count"
),
"/a//* | count"
);
assert_eq!(
exp(
"macro &swap($p; $q): /p//step | syntax:node($_; ^/q//predicate); &swap(/row[::a = 1]; /x[::b = 2]) | count"
),
"/row[::b = 2] | count"
);
}
#[test]
fn a_constructor_is_checked_against_the_vocabulary() {
let e = err("macro &bad: ^ | syntax:node(\"step\"; %(colour = 1)); /a&bad | count");
assert!(e.contains("step node has no property 'colour'"), "{e}");
let e = err("macro &bad: ^ | syntax:compare(\">\"; q(::age)); /a&bad | count");
assert!(
e.contains("compare node holds two operands; 1 given"),
"{e}"
);
let e = err("macro &bad: ^ | syntax:projection(\"x\"; \"y\"; q(::age)); /a&bad | count");
assert!(
e.contains("no projection kind") || e.contains("holds no children"),
"{e}"
);
let e = err("macro &bad: ^ | syntax:node(\"quarq\"); /a&bad | count");
assert!(e.contains("not built by a constructor"), "{e}");
}
#[test]
fn a_tree_is_rebuilt_bottom_up_one_node_per_thread() {
let later = "macro &later($p): \
/p//* \
| .:b(([!/*[!:.b]] \
| syntax:node(([:name = \"literal\"] | $_ ++! %(value = ::value + 10)) ?? $_; \
/*:.b)) ?? null){1;} \
| ^/p/*:.b @| first;";
assert_eq!(
exp(&format!("{later} &later(/row[::year > 1810]::title)")),
"/row[::year > 1820]::title"
);
assert_eq!(
exp("macro &same($p): /p/* | $_; &same(/row[::x]::y) | count"),
"/row[::x]::y | count"
);
}
#[test]
fn a_quarq_child_takes_parameters_and_expansions() {
assert_eq!(
exp(
"macro &over($col; $n): ^ | syntax:predicate(syntax:compare(\">\"; q($col); q(${$n}))); \
/row&over(::Age; 60) @| count"
),
"/row[::Age > 60] @| count"
);
assert_eq!(
exp(
"macro &over($col; $n): ^ | syntax:predicate(syntax:compare(\">\"; q($col); q(${$n * 2}))); \
/row&over(::Age; 30) @| count"
),
"/row[::Age > 60] @| count"
);
}
#[test]
fn a_trait_is_a_form_and_has_a_constructor() {
assert_eq!(
exp("macro &lk: ^ | syntax:step(\"/\"; \"*\"; syntax:trait(\"link\")); /a&lk | count"),
"/a/*<link> | count"
);
assert_eq!(
exp(
"macro &lk: ^ | syntax:step(\"/\"; \"*\"; syntax:trait(@(\"block\"; \"inline\"))); /a&lk | count"
),
"/a/*<block || inline> | count"
);
assert_eq!(
exp("macro &m($q): /q//step | syntax:node($_; /*); &m(/a<link>[::x]) | count"),
"/a<link>[::x] | count"
);
let same = "macro &same($p): \
/p//* \
| .:b(([!/*[!:.b]] | syntax:node($_; /*:.b)) ?? null){1;} \
| ^/p/*:.b @| first;";
assert_eq!(
exp(&format!("{same} &same(/row<link>[::year > 1810]::title)")),
"/row<link>[::year > 1810]::title"
);
assert_eq!(
exp("macro &t: ^ | syntax:step(\"/\"; \"*\"; syntax:predicate(q(::x))); /a&t | count"),
"/a/*[::x] | count"
);
let e = err("macro &bad(@r): /r | syntax:node($_); &bad(1) | count");
assert!(e.contains("nothing given to build like"), "{e}");
}