use quarb_text::TextModel;
const DOC: &str = r##"<!doctype html>
<html lang="en">
<head><title>Site</title><style>p { color: red }</style></head>
<body>
<nav>Menu Home About</nav>
<header>Site chrome</header>
<main>
<h1>Guide</h1>
<p>Intro paragraph with <a href="/x">a link</a>.</p>
<div class="wrap">
<h2>Usage</h2>
<p>Use it.</p>
</div>
<blockquote><p>Quoted wisdom.</p><footer>— Sage</footer></blockquote>
<ul>
<li>alpha</li>
<li>beta <ul><li>beta-child</li></ul></li>
</ul>
<ol start="3">
<li>third</li>
<li>fourth</li>
</ol>
<pre><code class="language-rust">fn main() {}</code></pre>
<table>
<caption>Crew</caption>
<thead><tr><th>Name</th><th>Role</th></tr></thead>
<tbody>
<tr><td>Alice</td><td>captain</td></tr>
<tr><td>Bob</td><td></td></tr>
</tbody>
</table>
<script>alert("soup")</script>
</main>
<footer>copyright</footer>
</body>
</html>"##;
fn model() -> TextModel {
quarb_text_html::parse(DOC)
}
fn values(query: &str) -> Vec<String> {
let model = model();
match quarb::run(query, &model).unwrap() {
quarb::QueryResult::Values(vs) => vs.iter().map(|v| v.to_string()).collect(),
quarb::QueryResult::Nodes(_) => panic!("expected values"),
}
}
fn nodes(query: &str) -> Vec<String> {
let model = model();
let mut got: Vec<String> = match quarb::run(query, &model).unwrap() {
quarb::QueryResult::Nodes(ns) => ns.into_iter().map(|n| model.locator(n)).collect(),
quarb::QueryResult::Values(_) => panic!("expected nodes"),
};
got.sort();
got
}
#[test]
fn soup_is_dropped() {
let prose = values("::").remove(0);
for soup in ["Menu", "Site chrome", "alert", "copyright", "color"] {
assert!(!prose.contains(soup), "soup {soup:?} leaked into {prose:?}");
}
}
#[test]
fn sections_nest_through_wrappers() {
assert_eq!(values("/section::lemma"), vec!["Guide"]);
assert_eq!(values("/section/section::lemma"), vec!["Usage"]);
assert_eq!(values("/section/section::::level"), vec!["2"]);
}
#[test]
fn inline_flattens() {
assert_eq!(
values("/section/paragraph::"),
vec!["Intro paragraph with a link."]
);
}
#[test]
fn blockquote_attribution() {
assert_eq!(values("//blockquote::hypograph"), vec!["— Sage"]);
assert_eq!(values("//blockquote/paragraph::"), vec!["Quoted wisdom."]);
}
#[test]
fn lists() {
assert_eq!(
values("/section/section/unordered-list/unordered-item::"),
vec!["alpha", "beta\nbeta-child"]
);
assert_eq!(values("//ordered-item::taxis"), vec!["3", "4", "1", "2"]);
}
#[test]
fn verbatim() {
assert_eq!(values("//verbatim::::lang"), vec!["rust"]);
assert_eq!(values("//verbatim::"), vec!["fn main() {}"]);
}
#[test]
fn table_denormalizes() {
assert_eq!(values("//*<table>::lemma"), vec!["Crew"]);
assert_eq!(
values("//*<table>//unordered-item::"),
vec!["Name: Alice", "Role: captain", "Name: Bob"]
);
assert_eq!(nodes("//*<table>").len(), 1);
}
#[test]
fn html_round_trips() {
use quarb::AstAdapter as _;
let m = model();
let html = quarb_text::render_node(&m, m.root(), quarb_text::Render::Html);
let m2 = quarb_text_html::parse(&html);
for q in [
"//section::lemma",
"//blockquote::hypograph",
"//ordered-item::taxis",
"//verbatim::::lang",
"::",
] {
let a = quarb::run(q, &m).unwrap();
let b = quarb::run(q, &m2).unwrap();
let show = |r: quarb::QueryResult| match r {
quarb::QueryResult::Values(vs) => {
vs.iter().map(|v| v.to_string()).collect::<Vec<_>>()
}
quarb::QueryResult::Nodes(_) => panic!("expected values"),
};
assert_eq!(show(a), show(b), "round trip diverged on {q}");
}
}
#[test]
fn infobox_row_labels() {
let m = quarb_text_html::parse(
r#"<table class="infobox">
<tbody>
<tr><th colspan="2">Emu War</th></tr>
<tr><td colspan="2">A man holding an emu</td></tr>
<tr><th>Date</th><td>2 November 1932</td></tr>
<tr><th colspan="2">Belligerents</th></tr>
<tr><th>Result</th><td>Emu victory</td></tr>
</tbody></table>"#,
);
let vals = |q: &str| match quarb::run(q, &m).unwrap() {
quarb::QueryResult::Values(vs) => {
vs.iter().map(|v| v.to_string()).collect::<Vec<_>>()
}
_ => panic!("expected values"),
};
assert_eq!(vals("//*<table>::lemma"), vec!["Emu War"]);
assert_eq!(
vals("//*<table>//unordered-item::"),
vec![
"A man holding an emu",
"Date: 2 November 1932",
"Belligerents",
"Result: Emu victory",
]
);
}