use xmlschema::{parse_schema, validate};
fn schema(body: &str) -> String {
format!(
r#"<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">{body}</xs:schema>"#
)
}
fn valid(body: &str, xml: &str) -> bool {
let s = parse_schema(&schema(body)).expect("schema parses");
let doc = oxml::parse(xml).expect("well-formed");
validate(&doc, &s).is_valid()
}
const UNIQUE: &str = r#"
<xs:element name="root">
<xs:complexType><xs:sequence>
<xs:element name="item" maxOccurs="unbounded">
<xs:complexType><xs:attribute name="k" type="xs:string"/></xs:complexType>
</xs:element>
</xs:sequence></xs:complexType>
<xs:unique name="u">
<xs:selector xpath=".//item"/>
<xs:field xpath="@k"/>
</xs:unique>
</xs:element>"#;
#[test]
fn unique_forbids_a_repeated_value() {
assert!(valid(UNIQUE, r#"<root><item k="a"/><item k="b"/></root>"#));
assert!(
!valid(UNIQUE, r#"<root><item k="a"/><item k="a"/></root>"#),
"`a` twice"
);
assert!(valid(UNIQUE, r#"<root><item k="a"/><item/></root>"#));
assert!(valid(UNIQUE, "<root><item/><item/></root>"));
}
const KEY: &str = r#"
<xs:element name="root">
<xs:complexType><xs:sequence>
<xs:element name="item" maxOccurs="unbounded">
<xs:complexType><xs:attribute name="k" type="xs:string"/></xs:complexType>
</xs:element>
</xs:sequence></xs:complexType>
<xs:key name="pk">
<xs:selector xpath=".//item"/>
<xs:field xpath="@k"/>
</xs:key>
</xs:element>"#;
#[test]
fn a_key_also_requires_the_field_to_be_present() {
assert!(valid(KEY, r#"<root><item k="a"/><item k="b"/></root>"#));
assert!(!valid(KEY, r#"<root><item k="a"/><item k="a"/></root>"#));
assert!(
!valid(KEY, r#"<root><item k="a"/><item/></root>"#),
"a key must be present on every selected node"
);
}
const KEYREF: &str = r#"
<xs:element name="root">
<xs:complexType><xs:sequence>
<xs:element name="item" maxOccurs="unbounded">
<xs:complexType><xs:attribute name="k" type="xs:string"/></xs:complexType>
</xs:element>
<xs:element name="ref" minOccurs="0" maxOccurs="unbounded">
<xs:complexType><xs:attribute name="to" type="xs:string"/></xs:complexType>
</xs:element>
</xs:sequence></xs:complexType>
<xs:key name="pk">
<xs:selector xpath=".//item"/>
<xs:field xpath="@k"/>
</xs:key>
<xs:keyref name="fk" refer="pk">
<xs:selector xpath=".//ref"/>
<xs:field xpath="@to"/>
</xs:keyref>
</xs:element>"#;
#[test]
fn a_keyref_must_find_its_target() {
assert!(valid(
KEYREF,
r#"<root><item k="a"/><item k="b"/><ref to="a"/></root>"#
));
assert!(
!valid(KEYREF, r#"<root><item k="a"/><ref to="z"/></root>"#),
"`z` is not a key"
);
assert!(valid(KEYREF, r#"<root><item k="a"/></root>"#));
}
#[test]
fn a_multi_field_constraint_compares_tuples() {
let body = r#"
<xs:element name="root">
<xs:complexType><xs:sequence>
<xs:element name="item" maxOccurs="unbounded">
<xs:complexType>
<xs:attribute name="a" type="xs:string"/>
<xs:attribute name="b" type="xs:string"/>
</xs:complexType>
</xs:element>
</xs:sequence></xs:complexType>
<xs:unique name="u">
<xs:selector xpath=".//item"/>
<xs:field xpath="@a"/>
<xs:field xpath="@b"/>
</xs:unique>
</xs:element>"#;
assert!(valid(
body,
r#"<root><item a="1" b="x"/><item a="1" b="y"/></root>"#
));
assert!(valid(
body,
r#"<root><item a="1" b="x"/><item a="2" b="x"/></root>"#
));
assert!(!valid(
body,
r#"<root><item a="1" b="x"/><item a="1" b="x"/></root>"#
));
}
#[test]
fn the_schema_id_attribute_is_an_xs_id() {
assert!(parse_schema(&schema(r#"<xs:element name="a" id="ok"/>"#)).is_ok());
assert!(parse_schema(&schema(r#"<xs:element name="a" id=""/>"#)).is_err());
assert!(
parse_schema(&schema(r#"<xs:element name="a" id="a:b"/>"#)).is_err()
);
assert!(
parse_schema(&schema(r#"<xs:element name="a" id="1x"/>"#)).is_err()
);
assert!(
parse_schema(&schema(
r#"<xs:element name="a" id="dup"/><xs:element name="b" id="dup"/>"#
))
.is_err()
);
}