use std::path::{Path, PathBuf};
use rux_runtime::Document;
fn examples_dir() -> PathBuf {
Path::new(env!("CARGO_MANIFEST_DIR")).join("../../examples")
}
fn example_files() -> Vec<PathBuf> {
let mut files: Vec<PathBuf> = std::fs::read_dir(examples_dir())
.expect("examples/ is readable")
.filter_map(|entry| {
let path = entry.ok()?.path();
(path.extension()? == "rux").then_some(path)
})
.collect();
files.sort();
assert!(!files.is_empty(), "found no examples to check");
files
}
#[test]
fn the_computed_example_recomputes_when_tapped() {
fn texts(node: &rux_layout::Node) -> Vec<String> {
let mut out: Vec<String> = node.text.iter().map(|t| t.text.clone()).collect();
for child in &node.children {
out.extend(texts(child));
}
out
}
let has = |doc: &Document, needle: &str| texts(&doc.root).iter().any(|t| t == needle);
let mut doc = Document::load(examples_dir().join("computed.rux")).expect("loads");
assert!(has(&doc, "24"), "subtotal on load: {:?}", texts(&doc.root));
assert!(has(&doc, "26.4"), "total on load: {:?}", texts(&doc.root));
assert!(
texts(&doc.root).iter().any(|t| t.contains("within budget")),
"the effect ran on load, so the status is not blank: {:?}",
texts(&doc.root)
);
for _ in 0..8 {
assert!(doc.apply_handler("qty = qty + 1"), "the tap changed state");
}
assert!(has(&doc, "120"), "subtotal followed: {:?}", texts(&doc.root));
assert!(has(&doc, "132"), "and so did the computed that reads it");
assert!(
texts(&doc.root).iter().any(|t| t.contains("over budget")),
"the effect re-ran and flipped the status: {:?}",
texts(&doc.root)
);
}
#[test]
fn the_router_example_navigates() {
fn texts(node: &rux_layout::Node) -> Vec<String> {
let mut out: Vec<String> = node.text.iter().map(|t| t.text.clone()).collect();
for child in &node.children {
out.extend(texts(child));
}
out
}
fn find_link<'a>(node: &'a rux_layout::Node, label: &str) -> Option<&'a rux_layout::Node> {
let names_it = node.text.as_ref().is_some_and(|t| t.text.trim() == label);
if names_it && node.on_tap.is_some() {
return Some(node);
}
if node.on_tap.is_some() && texts(node).iter().any(|t| t.trim() == label) {
return Some(node);
}
node.children.iter().find_map(|c| find_link(c, label))
}
let has = |doc: &Document, needle: &str| {
texts(&doc.root).iter().any(|t| t.contains(needle))
};
let mut doc = Document::load(examples_dir().join("router.rux")).expect("loads");
assert!(has(&doc, "a router, at last"), "the home page: {:?}", texts(&doc.root));
let crew = find_link(&doc.root, "crew").expect("a crew link").clone();
assert_eq!(crew.access.role, rux_layout::AccessRole::Link, "announced as a link");
assert!(doc.apply_handler_in(&crew.on_tap.clone().unwrap(), crew.instance.as_deref()));
assert_eq!(doc.route(), "/crew");
assert!(has(&doc, "Grace"), "the list rendered: {:?}", texts(&doc.root));
let row = find_link(&doc.root, "Grace").expect("a crew row").clone();
assert!(doc.apply_handler_in(&row.on_tap.clone().unwrap(), row.instance.as_deref()));
assert_eq!(doc.route(), "/crew/grace");
assert!(has(&doc, "engineer"), "the detail page looked her up: {:?}", texts(&doc.root));
let back = find_link(&doc.root, "back").expect("a back button").clone();
assert!(doc.apply_handler_in(&back.on_tap.clone().unwrap(), back.instance.as_deref()));
assert_eq!(doc.route(), "/crew");
assert!(has(&doc, "Grace"), "and the list is back: {:?}", texts(&doc.root));
doc.navigate("/nowhere");
assert!(has(&doc, "nothing here"), "the fallback: {:?}", texts(&doc.root));
assert!(has(&doc, "/nowhere"), "which read the path: {:?}", texts(&doc.root));
assert!(!has(&doc, "viewing:"), "no parameters here: {:?}", texts(&doc.root));
doc.navigate("/crew/hedy");
assert!(has(&doc, "viewing: hedy"), "read outside the view: {:?}", texts(&doc.root));
let paint = |doc: &Document, label: &str| {
let button = find_link(&doc.root, label).expect("a history button");
format!("{:?}", button.style.background)
};
assert_ne!(
paint(&doc, "go back"),
paint(&doc, "go forward"),
"plenty behind us and nothing ahead, so the two should not look alike"
);
doc.back();
assert_eq!(paint(&doc, "go back"), paint(&doc, "go forward"), "both lead somewhere now");
}
#[test]
fn every_example_loads() {
let mut failures = Vec::new();
for path in example_files() {
if let Err(err) = Document::load(&path) {
failures.push(format!("{}: {err}", path.display()));
}
}
assert!(failures.is_empty(), "examples failed to load:\n{}", failures.join("\n"));
}
#[test]
fn every_example_is_warning_free() {
let mut noisy = Vec::new();
for path in example_files() {
let Ok(doc) = Document::load(&path) else { continue }; let warnings = &doc.diagnostics().warnings;
if !warnings.is_empty() {
let listed: Vec<String> = warnings.iter().map(|w| w.to_string()).collect();
noisy.push(format!("{}:\n - {}", path.display(), listed.join("\n - ")));
}
}
assert!(
noisy.is_empty(),
"examples raise warnings the dev overlay will show:\n{}",
noisy.join("\n")
);
}