use teksilo_parse::{diag, parse_root};
fn hint_for(source: &str) -> Option<String> {
let tokens: proc_macro2::TokenStream = source.parse().expect("the fixture tokenizes");
parse_root(tokens).err().map(|e| e.to_string())
}
const CATEGORY_B: &[(&str, &str)] = &[
("Card", "content"),
("Accordion", "content"),
("TitleBar", "leading"),
("DialogContent", "body"),
("Breadcrumb", "item"),
("TabWidget", "tab"),
("PopoverWidget", "content"),
("PopoverButton", "content"),
("PopoverIconButton", "content"),
("PopoverCustom", "content"),
("Snackbar", "content"),
("Dialog", "content"),
("Wizard", "step"),
];
#[test]
fn every_category_b_widget_pre_empts_a_bare_child_with_its_own_slot() {
for (widget, slot) in CATEGORY_B {
let message =
hint_for(&format!("{widget} {{ TextWidget(\"hi\") }}")).unwrap_or_else(|| {
panic!("`{widget}` accepted a bare child instead of pre-empting it")
});
assert!(
message.contains("Category B widget with named slots"),
"`{widget}` failed for some other reason: {message}"
);
assert!(
message.contains(&format!("use `{slot}: <widget>`")),
"`{widget}` should point at its `{slot}` slot: {message}"
);
}
}
#[test]
fn the_predicate_and_the_slot_table_cover_the_same_names() {
for (widget, _) in CATEGORY_B {
assert!(
diag::is_category_b_widget(widget),
"`{widget}` is in this test's table but not in the predicate"
);
}
}
#[test]
fn a_child_taking_container_is_left_alone() {
assert!(
hint_for("VStack { TextWidget(\"hi\") }").is_none(),
"a bare child in a child-taking container must parse"
);
assert!(!diag::is_category_b_widget("VStack"));
}
#[test]
fn naming_the_slot_is_not_pre_empted() {
assert!(
hint_for("Card { content: TextWidget(\"hi\") }").is_none(),
"`content:` is the very thing the hint asks for"
);
}