use indoc::indoc;
use liwe::graph::Graph;
use liwe::model::config::MarkdownOptions;
use liwe::query::{evaluate, parse_filter_expression, Filter};
use liwe::state::from_indoc;
use pretty_assertions::assert_eq;
fn matched(docs: &str, expr: &str) -> Vec<String> {
let graph = Graph::import(&from_indoc(docs), MarkdownOptions::default(), None);
let filter = parse_filter_expression(expr).expect("filter parses");
evaluate(&filter, &graph)
.into_iter()
.map(|k| k.to_string())
.collect()
}
const CORPUS: &str = indoc! {"
# alpha
Ship the editor TODO confirm date
## Status
active
_
# beta
Nothing pending here
## Notes
keep going
_
# gamma
Another TODO waits
"};
#[test]
fn content_text_membership() {
assert_eq!(
matched(CORPUS, "$content: { $text: TODO }"),
vec!["1".to_string(), "3".to_string()]
);
}
#[test]
fn content_header_membership() {
assert_eq!(
matched(CORPUS, "$content: { $header: Status }"),
vec!["1".to_string()]
);
}
#[test]
fn content_empty_predicate_matches_any_block() {
assert_eq!(
matched(CORPUS, "$content: {}"),
vec!["1".to_string(), "2".to_string(), "3".to_string()]
);
}
#[test]
fn content_absence_via_nor() {
assert_eq!(
matched(CORPUS, "$nor: [ { $content: { $header: Status } } ]"),
vec!["2".to_string(), "3".to_string()]
);
}
#[test]
fn content_composes_under_or_with_field() {
let docs = indoc! {"
---
status: draft
---
# one
plain body
_
# two
body with TODO
_
# three
clean body
"};
assert_eq!(
matched(
docs,
"$or: [ { status: draft }, { $content: { $text: TODO } } ]"
),
vec!["1".to_string(), "2".to_string()]
);
}
#[test]
fn content_scoped_membership_within_section() {
let docs = indoc! {"
# one
## Goals
Q3 target here
## Other
Q3 mention elsewhere
_
# two
## Other
Q3 only outside goals
"};
assert_eq!(
matched(docs, "$content: { $within: Goals, $text: Q3 }"),
vec!["1".to_string()]
);
}
#[test]
fn content_parses_to_content_filter() {
let filter = parse_filter_expression("$content: { $text: TODO }").expect("parses");
assert!(matches!(filter, Filter::Content(_)));
}