use facet::Facet;
use facet_solver::{FieldCategory, FieldKey, Format, KeyResult, Schema, Solver};
use facet_testhelpers::test;
use facet_xml as xml;
#[derive(Facet, Debug)]
struct ElementWithAttrAndChild {
#[facet(xml::attribute)]
class: String,
#[facet(rename = "class")]
class_element: String,
}
#[test]
fn test_attribute_vs_element_same_name() {
let schema = Schema::build_dom(ElementWithAttrAndChild::SHAPE).unwrap();
eprintln!("Format: {:?}", schema.format());
eprintln!("Resolutions: {}", schema.resolutions().len());
assert_eq!(schema.resolutions().len(), 1);
let resolution = &schema.resolutions()[0];
for (key, info) in resolution.fields() {
eprintln!(
"Field: {} -> category={:?}, path={:?}",
key, info.category, info.path
);
}
assert!(resolution.field_by_name("class").is_some());
let attr_key = FieldKey::attribute("class");
let elem_key = FieldKey::element("class");
assert!(
resolution.field_by_key(&attr_key).is_some(),
"attribute class should exist"
);
assert!(
resolution.field_by_key(&elem_key).is_some(),
"element class should exist"
);
let mut solver = Solver::new(&schema);
let result = solver.see_attribute("class");
assert!(
matches!(result, KeyResult::Unambiguous { .. } | KeyResult::Solved(_)),
"attribute lookup failed: {:?}",
result
);
let mut solver2 = Solver::new(&schema);
let result = solver2.see_element("class");
assert!(
matches!(result, KeyResult::Unambiguous { .. } | KeyResult::Solved(_)),
"element lookup failed: {:?}",
result
);
}
#[derive(Facet, Debug)]
struct GlobalAttrs {
#[facet(xml::attribute)]
id: Option<String>,
#[facet(xml::attribute)]
class: Option<String>,
}
#[derive(Facet, Debug)]
struct DivElement {
#[facet(flatten)]
attrs: GlobalAttrs,
content: Option<String>,
}
#[test]
fn test_flattened_struct_with_attributes() {
let schema = Schema::build_dom(DivElement::SHAPE).unwrap();
assert_eq!(schema.resolutions().len(), 1);
let resolution = &schema.resolutions()[0];
let id_field = resolution.field_by_name("id");
assert!(id_field.is_some(), "id field should be present");
assert_eq!(
id_field.unwrap().category,
FieldCategory::Attribute,
"id should be an attribute"
);
let class_field = resolution.field_by_name("class");
assert!(class_field.is_some(), "class field should be present");
assert_eq!(
class_field.unwrap().category,
FieldCategory::Attribute,
"class should be an attribute"
);
let content_field = resolution.field_by_name("content");
assert!(content_field.is_some(), "content field should be present");
assert_eq!(
content_field.unwrap().category,
FieldCategory::Element,
"content should be an element"
);
let mut solver = Solver::new(&schema);
let result = solver.see_attribute("id");
assert!(
!matches!(result, KeyResult::Unknown),
"id attribute should be known"
);
let result = solver.see_attribute("class");
assert!(
!matches!(result, KeyResult::Unknown),
"class attribute should be known"
);
let result = solver.see_element("content");
assert!(
!matches!(result, KeyResult::Unknown),
"content element should be known"
);
let mut solver3 = Solver::new(&schema);
let result = solver3.see_attribute("content");
assert!(
matches!(result, KeyResult::Unknown),
"content as attribute should be unknown"
);
}
#[derive(Facet, Debug)]
struct InputText {
#[facet(xml::attribute)]
value: String,
}
#[derive(Facet, Debug)]
struct InputCheckbox {
#[facet(xml::attribute)]
checked: Option<String>,
}
#[derive(Facet, Debug)]
#[repr(u8)]
#[allow(unused)]
enum InputKind {
Text(InputText),
Checkbox(InputCheckbox),
}
#[derive(Facet, Debug)]
struct InputElement {
#[facet(xml::attribute)]
name: String,
#[facet(flatten)]
kind: InputKind,
}
#[test]
fn test_enum_disambiguation_with_attributes() {
let schema = Schema::build_dom(InputElement::SHAPE).unwrap();
eprintln!("Format: {:?}", schema.format());
eprintln!("Resolutions: {}", schema.resolutions().len());
for (i, res) in schema.resolutions().iter().enumerate() {
eprintln!("Resolution {}: {}", i, res.describe());
for (key, info) in res.fields() {
eprintln!(" Field: {} -> category={:?}", key, info.category);
}
}
assert_eq!(
schema.resolutions().len(),
2,
"should have 2 resolutions for 2 variants"
);
let mut solver = Solver::new(&schema);
solver.see_attribute("name");
let result = solver.see_element("Text");
match result {
KeyResult::Solved(handle) => {
let desc = handle.resolution().describe();
assert!(
desc.contains("Text"),
"Text element should solve to Text variant, got: {}",
desc
);
}
KeyResult::Unambiguous { .. } => {
let handle = solver.finish().expect("should finish successfully");
let desc = handle.resolution().describe();
assert!(
desc.contains("Text"),
"Text element should solve to Text variant, got: {}",
desc
);
}
other => panic!("unexpected result for Text element: {:?}", other),
}
let mut solver2 = Solver::new(&schema);
solver2.see_attribute("name"); let result = solver2.see_element("Checkbox");
match result {
KeyResult::Solved(handle) => {
let desc = handle.resolution().describe();
assert!(
desc.contains("Checkbox"),
"Checkbox element should solve to Checkbox variant, got: {}",
desc
);
}
KeyResult::Unambiguous { .. } => {
let handle = solver2.finish().expect("should finish successfully");
let desc = handle.resolution().describe();
assert!(
desc.contains("Checkbox"),
"Checkbox element should solve to Checkbox variant, got: {}",
desc
);
}
other => panic!("unexpected result for Checkbox element: {:?}", other),
}
}
#[derive(Facet, Debug)]
struct TextElement {
#[facet(xml::attribute)]
lang: Option<String>,
#[facet(xml::text)]
content: String,
}
#[test]
fn test_text_content_field() {
let schema = Schema::build_dom(TextElement::SHAPE).unwrap();
assert_eq!(schema.resolutions().len(), 1);
let resolution = &schema.resolutions()[0];
let content_field = resolution.field_by_name("content");
assert!(content_field.is_some());
assert_eq!(
content_field.unwrap().category,
FieldCategory::Text,
"content should be Text category"
);
let mut solver = Solver::new(&schema);
let result = solver.see_text();
assert!(
!matches!(result, KeyResult::Unknown),
"text content should be known"
);
}
#[test]
fn test_flat_format_ignores_categories() {
let schema = Schema::build_with_format(DivElement::SHAPE, Format::Flat).unwrap();
let mut solver = Solver::new(&schema);
let result = solver.see_key("id");
assert!(
!matches!(result, KeyResult::Unknown),
"id should be known in flat format"
);
let result = solver.see_key("class");
assert!(
!matches!(result, KeyResult::Unknown),
"class should be known in flat format"
);
let result = solver.see_key("content");
assert!(
!matches!(result, KeyResult::Unknown),
"content should be known in flat format"
);
}
#[test]
fn test_field_key_type_conversions() {
let key: FieldKey = "test".into();
assert!(matches!(key, FieldKey::Flat(_)));
assert_eq!(key.name(), "test");
let key: FieldKey = String::from("test").into();
assert!(matches!(key, FieldKey::Flat(_)));
let attr_key = FieldKey::attribute("class");
assert!(matches!(
attr_key,
FieldKey::Dom(FieldCategory::Attribute, _)
));
assert_eq!(attr_key.name(), "class");
assert_eq!(attr_key.category(), Some(FieldCategory::Attribute));
let elem_key = FieldKey::element("div");
assert!(matches!(elem_key, FieldKey::Dom(FieldCategory::Element, _)));
assert_eq!(elem_key.name(), "div");
let text_key = FieldKey::text();
assert!(matches!(text_key, FieldKey::Dom(FieldCategory::Text, _)));
assert_eq!(text_key.name(), "");
}