use super::*;
use crate::error::SchemaError;
use crate::ids::TypeKey;
#[test]
fn test_load_and_process_minimal_schema() {
let mut schema_set = SchemaSet::new();
let xsd = r#"<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
</xs:schema>"#;
let result = load_and_process_schema(xsd.as_bytes(), "test.xsd", &mut schema_set, None);
assert!(result.is_ok(), "Should parse minimal schema: {:?}", result);
let stats = result.unwrap();
assert_eq!(stats.doc_id, 0);
assert!(stats.inline_stats.is_some());
assert!(stats.resolution_stats.is_some());
}
#[test]
fn test_load_and_process_element_with_type() {
let mut schema_set = SchemaSet::new();
let xsd = r#"<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="root" type="xs:string"/>
</xs:schema>"#;
let result = load_and_process_schema(xsd.as_bytes(), "test.xsd", &mut schema_set, None);
assert!(result.is_ok());
let stats = result.unwrap();
let resolution_stats = stats.resolution_stats.unwrap();
assert!(
resolution_stats.types_resolved > 0,
"Should resolve type reference"
);
let root_name = schema_set.name_table.get("root").unwrap();
let elem_key = schema_set.lookup_element(None, root_name).unwrap();
let elem = schema_set.arenas.elements.get(elem_key).unwrap();
assert!(
elem.resolved_type.is_some(),
"Element type should be resolved"
);
}
#[test]
fn test_load_and_process_inline_complex_type() {
let mut schema_set = SchemaSet::new();
let xsd = r#"<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="person">
<xs:complexType>
<xs:sequence>
<xs:element name="name" type="xs:string"/>
<xs:element name="age" type="xs:int"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>"#;
let result = load_and_process_schema(xsd.as_bytes(), "test.xsd", &mut schema_set, None);
assert!(
result.is_ok(),
"Should parse schema with inline type: {:?}",
result
);
let stats = result.unwrap();
let inline_stats = stats.inline_stats.unwrap();
assert!(
inline_stats.element_inline_types > 0,
"Should assemble inline complex type"
);
let person_name = schema_set.name_table.get("person").unwrap();
let elem_key = schema_set.lookup_element(None, person_name).unwrap();
let elem = schema_set.arenas.elements.get(elem_key).unwrap();
assert!(
elem.resolved_type.is_some(),
"Inline type should be resolved"
);
assert!(matches!(elem.resolved_type, Some(TypeKey::Complex(_))));
}
#[test]
fn test_load_and_process_inline_simple_type() {
let mut schema_set = SchemaSet::new();
let xsd = r#"<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="status">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:enumeration value="active"/>
<xs:enumeration value="inactive"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
</xs:schema>"#;
let result = load_and_process_schema(xsd.as_bytes(), "test.xsd", &mut schema_set, None);
assert!(
result.is_ok(),
"Should parse schema with inline simple type: {:?}",
result
);
let stats = result.unwrap();
let inline_stats = stats.inline_stats.unwrap();
assert!(
inline_stats.element_inline_types > 0,
"Should assemble inline simple type"
);
let status_name = schema_set.name_table.get("status").unwrap();
let elem_key = schema_set.lookup_element(None, status_name).unwrap();
let elem = schema_set.arenas.elements.get(elem_key).unwrap();
assert!(
elem.resolved_type.is_some(),
"Inline type should be resolved"
);
assert!(matches!(elem.resolved_type, Some(TypeKey::Simple(_))));
}
#[test]
fn test_load_and_process_rejects_invalid_particle_wildcard_restriction() {
let mut schema_set = SchemaSet::new();
let xsd = r###"<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="urn:test"
xmlns:t="urn:test">
<xs:complexType name="Base">
<xs:choice>
<xs:any namespace="##any"/>
</xs:choice>
</xs:complexType>
<xs:complexType name="Restricted">
<xs:complexContent>
<xs:restriction base="t:Base">
<xs:choice>
<xs:any processContents="lax"/>
</xs:choice>
</xs:restriction>
</xs:complexContent>
</xs:complexType>
</xs:schema>"###;
let result = load_and_process_schema(xsd.as_bytes(), "test.xsd", &mut schema_set, None);
assert!(result.is_err());
match result.unwrap_err() {
crate::error::SchemaError::StructuralError { constraint, .. } => {
assert_eq!(constraint, "derivation-ok-restriction");
}
other => panic!("Expected derivation-ok-restriction, got {:?}", other),
}
}
#[test]
fn test_load_and_process_rejects_upa_conflict() {
let mut schema_set = SchemaSet::new();
let xsd = r#"<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:complexType name="Ambiguous">
<xs:choice>
<xs:element name="a"/>
<xs:element name="a"/>
</xs:choice>
</xs:complexType>
</xs:schema>"#;
let result = load_and_process_schema(xsd.as_bytes(), "test.xsd", &mut schema_set, None);
assert!(result.is_err());
match result.unwrap_err() {
crate::error::SchemaError::StructuralError { constraint, .. } => {
assert_eq!(constraint, "cos-nonambig");
}
other => panic!("Expected cos-nonambig, got {:?}", other),
}
}
#[test]
fn test_load_and_process_accepts_sequence_restriction_of_all_group() {
let mut schema_set = SchemaSet::new();
let xsd = r#"<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:complexType name="Base">
<xs:all>
<xs:element name="a" type="xs:string"/>
<xs:element name="b" type="xs:string" minOccurs="0"/>
</xs:all>
</xs:complexType>
<xs:complexType name="Restricted">
<xs:complexContent>
<xs:restriction base="Base">
<xs:sequence>
<xs:element name="a" type="xs:string"/>
</xs:sequence>
</xs:restriction>
</xs:complexContent>
</xs:complexType>
</xs:schema>"#;
let result = load_and_process_schema(xsd.as_bytes(), "test.xsd", &mut schema_set, None);
assert!(
result.is_ok(),
"all-group restriction should be valid: {:?}",
result
);
}
#[test]
fn test_load_and_process_xsd10_rejects_optional_element_restricting_optional_choice() {
let mut schema_set = SchemaSet::new();
let xsd = r#"<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:complexType name="Base">
<xs:sequence>
<xs:choice minOccurs="0">
<xs:element name="a" type="xs:string"/>
<xs:element name="b" type="xs:string"/>
</xs:choice>
</xs:sequence>
</xs:complexType>
<xs:complexType name="Restricted">
<xs:complexContent>
<xs:restriction base="Base">
<xs:sequence>
<xs:element name="a" type="xs:string" minOccurs="0"/>
</xs:sequence>
</xs:restriction>
</xs:complexContent>
</xs:complexType>
</xs:schema>"#;
let result = load_and_process_schema(xsd.as_bytes(), "test.xsd", &mut schema_set, None);
assert!(result.is_err());
match result.unwrap_err() {
crate::error::SchemaError::StructuralError { constraint, .. } => {
assert_eq!(constraint, "derivation-ok-restriction");
}
other => panic!("Expected derivation-ok-restriction, got {:?}", other),
}
}
#[test]
fn test_load_and_process_xsd11_allows_optional_element_restricting_optional_choice() {
let mut schema_set = SchemaSet::xsd11();
let xsd = r#"<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:complexType name="Base">
<xs:sequence>
<xs:choice minOccurs="0">
<xs:element name="a" type="xs:string"/>
<xs:element name="b" type="xs:string"/>
</xs:choice>
</xs:sequence>
</xs:complexType>
<xs:complexType name="Restricted">
<xs:complexContent>
<xs:restriction base="Base">
<xs:sequence>
<xs:element name="a" type="xs:string" minOccurs="0"/>
</xs:sequence>
</xs:restriction>
</xs:complexContent>
</xs:complexType>
</xs:schema>"#;
let result = load_and_process_schema(xsd.as_bytes(), "test.xsd", &mut schema_set, None);
assert!(
result.is_ok(),
"XSD 1.1 optional-choice restriction should be valid: {:?}",
result
);
}
#[test]
fn test_reject_repeated_sequence_occurs_mismatch() {
let mut schema_set = SchemaSet::new();
let xsd = r#"<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:complexType name="base">
<xs:choice>
<xs:sequence minOccurs="1" maxOccurs="2">
<xs:element name="b" minOccurs="2" maxOccurs="2"/>
</xs:sequence>
</xs:choice>
</xs:complexType>
<xs:complexType name="derived">
<xs:complexContent>
<xs:restriction base="base">
<xs:choice>
<xs:element name="b" minOccurs="3" maxOccurs="3"/>
</xs:choice>
</xs:restriction>
</xs:complexContent>
</xs:complexType>
</xs:schema>"#;
let result = load_and_process_schema(xsd.as_bytes(), "test.xsd", &mut schema_set, None);
assert!(
result.is_err(),
"b{{3,3}} cannot restrict sequence{{1,2}}(b{{2,2}})"
);
match result.unwrap_err() {
crate::error::SchemaError::StructuralError { constraint, .. } => {
assert_eq!(constraint, "derivation-ok-restriction");
}
other => panic!("Expected derivation-ok-restriction, got {:?}", other),
}
}
#[test]
fn test_reject_choice_branch_occurs_mismatch() {
let mut schema_set = SchemaSet::new();
let xsd = r#"<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:complexType name="B">
<xs:sequence>
<xs:choice>
<xs:element name="c1" minOccurs="2" maxOccurs="2"/>
<xs:element name="c2"/>
</xs:choice>
<xs:choice minOccurs="1" maxOccurs="3">
<xs:element name="d1"/>
<xs:element name="d2"/>
</xs:choice>
</xs:sequence>
</xs:complexType>
<xs:complexType name="R">
<xs:complexContent>
<xs:restriction base="B">
<xs:sequence>
<xs:element name="c1" minOccurs="3" maxOccurs="3"/>
<xs:element name="d1"/>
</xs:sequence>
</xs:restriction>
</xs:complexContent>
</xs:complexType>
</xs:schema>"#;
let result = load_and_process_schema(xsd.as_bytes(), "test.xsd", &mut schema_set, None);
assert!(
result.is_err(),
"c1{{3,3}} cannot restrict choice branch c1{{2,2}}"
);
}
#[test]
fn test_accept_group_ref_restriction_with_flatten() {
let mut schema_set = SchemaSet::new();
let xsd = r#"<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:group name="g1">
<xs:sequence>
<xs:element name="r1"/>
<xs:element name="r2"/>
</xs:sequence>
</xs:group>
<xs:group name="g2">
<xs:sequence>
<xs:element name="r3"/>
<xs:element name="r4"/>
</xs:sequence>
</xs:group>
<xs:complexType name="A">
<xs:sequence>
<xs:group ref="g1"/>
<xs:group ref="g2" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
<xs:element name="elem">
<xs:complexType>
<xs:complexContent>
<xs:restriction base="A">
<xs:sequence>
<xs:group ref="g1"/>
</xs:sequence>
</xs:restriction>
</xs:complexContent>
</xs:complexType>
</xs:element>
</xs:schema>"#;
let result = load_and_process_schema(xsd.as_bytes(), "test.xsd", &mut schema_set, None);
assert!(
result.is_ok(),
"group ref restriction should be valid after flattening: {:?}",
result
);
}
#[test]
fn test_accept_restriction_with_zero_max_occurs_branch() {
let mut schema_set = SchemaSet::new();
let xsd = r#"<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:complexType name="bar">
<xs:choice>
<xs:element name="e1"/>
<xs:element name="e2"/>
</xs:choice>
</xs:complexType>
<xs:complexType name="foo">
<xs:complexContent>
<xs:restriction base="bar">
<xs:choice>
<xs:element name="e1" minOccurs="0" maxOccurs="0"/>
<xs:element name="e2"/>
</xs:choice>
</xs:restriction>
</xs:complexContent>
</xs:complexType>
</xs:schema>"#;
let result = load_and_process_schema(xsd.as_bytes(), "test.xsd", &mut schema_set, None);
assert!(
result.is_ok(),
"restriction with maxOccurs=0 branch should be valid: {:?}",
result
);
}
#[test]
fn test_accept_all_zero_restriction_of_optional_wildcard() {
let mut schema_set = SchemaSet::new();
let xsd = r###"<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://xsdtesting" xmlns:x="http://xsdtesting">
<xs:complexType name="B">
<xs:sequence>
<xs:any namespace="##targetNamespace" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="R">
<xs:complexContent>
<xs:restriction base="x:B">
<xs:sequence>
<xs:element name="e1" minOccurs="0" maxOccurs="0"/>
</xs:sequence>
</xs:restriction>
</xs:complexContent>
</xs:complexType>
</xs:schema>"###;
let result = load_and_process_schema(xsd.as_bytes(), "test.xsd", &mut schema_set, None);
assert!(
result.is_ok(),
"all-zero restriction of optional wildcard should be valid: {:?}",
result
);
}
#[test]
fn test_accept_restriction_of_empty_extension() {
let mut schema_set = SchemaSet::new();
let xsd = r#"<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:complexType name="B">
<xs:sequence>
<xs:element name="foo" type="xs:string"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="De">
<xs:complexContent>
<xs:extension base="B"/>
</xs:complexContent>
</xs:complexType>
<xs:complexType name="Der">
<xs:complexContent>
<xs:restriction base="De">
<xs:sequence>
<xs:element name="foo" type="xs:string"/>
</xs:sequence>
</xs:restriction>
</xs:complexContent>
</xs:complexType>
</xs:schema>"#;
let result = load_and_process_schema(xsd.as_bytes(), "test.xsd", &mut schema_set, None);
assert!(
result.is_ok(),
"restriction of empty extension should see inherited content: {:?}",
result
);
}
#[test]
fn test_accept_sequence_restricting_repeated_choice() {
let mut schema_set = SchemaSet::new();
let xsd = r#"<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:complexType name="B">
<xs:choice minOccurs="0" maxOccurs="2">
<xs:element name="e1" maxOccurs="3"/>
<xs:element name="e2" maxOccurs="3"/>
</xs:choice>
</xs:complexType>
<xs:complexType name="R">
<xs:complexContent>
<xs:restriction base="B">
<xs:sequence maxOccurs="1">
<xs:element name="e1" maxOccurs="3"/>
<xs:element name="e2" maxOccurs="3"/>
</xs:sequence>
</xs:restriction>
</xs:complexContent>
</xs:complexType>
</xs:schema>"#;
let result = load_and_process_schema(xsd.as_bytes(), "test.xsd", &mut schema_set, None);
assert!(
result.is_ok(),
"cross-compositor restriction should be provisionally accepted: {:?}",
result
);
}
#[test]
fn test_accept_repeated_sequence_restriction_w011() {
let mut schema_set = SchemaSet::new();
let xsd = r#"<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://xsdtesting" xmlns:x="http://xsdtesting">
<xs:complexType name="B">
<xs:sequence minOccurs="1" maxOccurs="9">
<xs:element name="e1"/>
<xs:element name="e2"/>
<xs:element name="e3"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="R">
<xs:complexContent>
<xs:restriction base="x:B">
<xs:sequence>
<xs:element name="e1"/>
<xs:element name="e2"/>
<xs:element name="e3"/>
</xs:sequence>
</xs:restriction>
</xs:complexContent>
</xs:complexType>
</xs:schema>"#;
let result = load_and_process_schema(xsd.as_bytes(), "test.xsd", &mut schema_set, None);
assert!(
result.is_ok(),
"sequence{{1,1}} validly restricts sequence{{1,9}}: {:?}",
result
);
}
#[test]
fn test_accept_repeated_sequence_restriction_type_narrowing_w016() {
let mut schema_set = SchemaSet::new();
let xsd = r#"<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://xsdtesting" xmlns:x="http://xsdtesting">
<xs:complexType name="ct1">
<xs:sequence>
<xs:element name="foo" minOccurs="2" maxOccurs="5"/>
<xs:element name="bar" form="qualified"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="ct3">
<xs:complexContent>
<xs:restriction base="x:ct1">
<xs:sequence>
<xs:element name="foo" minOccurs="3" maxOccurs="3"/>
<xs:element name="bar" form="qualified"/>
</xs:sequence>
</xs:restriction>
</xs:complexContent>
</xs:complexType>
<xs:complexType name="B">
<xs:sequence minOccurs="1" maxOccurs="9">
<xs:element name="e1" type="x:ct1"/>
<xs:element name="e2"/>
<xs:element name="e3"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="R">
<xs:complexContent>
<xs:restriction base="x:B">
<xs:sequence>
<xs:element name="e1" type="x:ct3"/>
<xs:element name="e2"/>
<xs:element name="e3"/>
</xs:sequence>
</xs:restriction>
</xs:complexContent>
</xs:complexType>
</xs:schema>"#;
let result = load_and_process_schema(xsd.as_bytes(), "test.xsd", &mut schema_set, None);
assert!(
result.is_ok(),
"type-narrowed sequence restriction should be valid: {:?}",
result
);
}
#[test]
fn test_reject_sequence_vs_choice_min_violation_v002() {
let mut schema_set = SchemaSet::new();
let xsd = r#"<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://xsdtesting" xmlns:x="http://xsdtesting">
<xs:complexType name="B">
<xs:choice minOccurs="1" maxOccurs="99">
<xs:element name="e1" minOccurs="1" maxOccurs="10"/>
<xs:element name="e2" minOccurs="2" maxOccurs="10"/>
<xs:element name="e3" minOccurs="3" maxOccurs="10"/>
</xs:choice>
</xs:complexType>
<xs:complexType name="R">
<xs:complexContent>
<xs:restriction base="x:B">
<xs:sequence minOccurs="1" maxOccurs="99">
<xs:element name="e1" minOccurs="1" maxOccurs="10"/>
<xs:element name="e2" minOccurs="2" maxOccurs="10"/>
<xs:element name="e3" minOccurs="2" maxOccurs="10"/>
</xs:sequence>
</xs:restriction>
</xs:complexContent>
</xs:complexType>
</xs:schema>"#;
let result = load_and_process_schema(xsd.as_bytes(), "test.xsd", &mut schema_set, None);
assert!(
result.is_err(),
"sequence-vs-choice: e3 min=2 violates base choice branch min=3"
);
}
#[test]
fn test_reject_sequence_vs_choice_not_expressible_v005() {
let mut schema_set = SchemaSet::new();
let xsd = r#"<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://xsdtesting" xmlns:x="http://xsdtesting">
<xs:complexType name="B">
<xs:choice minOccurs="0" maxOccurs="2">
<xs:element name="e1" maxOccurs="3"/>
<xs:element name="e2" maxOccurs="3"/>
</xs:choice>
</xs:complexType>
<xs:complexType name="R">
<xs:complexContent>
<xs:restriction base="x:B">
<xs:sequence maxOccurs="2">
<xs:element name="e1" maxOccurs="2"/>
<xs:element name="e2" maxOccurs="2"/>
</xs:sequence>
</xs:restriction>
</xs:complexContent>
</xs:complexType>
</xs:schema>"#;
let result = load_and_process_schema(xsd.as_bytes(), "test.xsd", &mut schema_set, None);
assert!(
result.is_err(),
"sequence-vs-choice with both elements required per repetition is invalid"
);
}
#[test]
fn test_reject_sequence_vs_choice_extra_element_v016() {
let mut schema_set = SchemaSet::new();
let xsd = r#"<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://xsdtesting" xmlns:x="http://xsdtesting">
<xs:complexType name="B">
<xs:choice maxOccurs="unbounded">
<xs:element name="e1" maxOccurs="3"/>
<xs:element name="e2" minOccurs="0" maxOccurs="3"/>
<xs:element name="e3" minOccurs="0" maxOccurs="3"/>
</xs:choice>
</xs:complexType>
<xs:complexType name="R">
<xs:complexContent>
<xs:restriction base="x:B">
<xs:sequence>
<xs:element name="e1"/>
<xs:element name="e2" minOccurs="0"/>
<xs:element name="e3" minOccurs="0"/>
<xs:element name="e4" minOccurs="0"/>
</xs:sequence>
</xs:restriction>
</xs:complexContent>
</xs:complexType>
</xs:schema>"#;
let result = load_and_process_schema(xsd.as_bytes(), "test.xsd", &mut schema_set, None);
assert!(
result.is_err(),
"sequence-vs-choice: e4 has no base counterpart"
);
}
#[test]
fn test_reject_sequence_vs_choice_type_mismatch_v018() {
let mut schema_set = SchemaSet::new();
let xsd = r#"<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://xsdtesting" xmlns:x="http://xsdtesting">
<xs:complexType name="ct1">
<xs:sequence>
<xs:element name="foo" minOccurs="2" maxOccurs="5"/>
<xs:element name="bar" form="qualified"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="ct2">
<xs:sequence>
<xs:element name="foo"/>
<xs:element name="bar"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="B">
<xs:choice maxOccurs="4">
<xs:element name="e1" type="x:ct1"/>
<xs:element name="e2"/>
</xs:choice>
</xs:complexType>
<xs:complexType name="R">
<xs:complexContent>
<xs:restriction base="x:B">
<xs:sequence>
<xs:element name="e1" type="x:ct2"/>
<xs:element name="e2"/>
</xs:sequence>
</xs:restriction>
</xs:complexContent>
</xs:complexType>
</xs:schema>"#;
let result = load_and_process_schema(xsd.as_bytes(), "test.xsd", &mut schema_set, None);
assert!(
result.is_err(),
"sequence-vs-choice: ct2 is not derived from ct1"
);
}
#[test]
fn test_reject_all_restricting_choice_hb006() {
let mut schema_set = SchemaSet::new();
let xsd = r#"<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://xsdtesting" xmlns:x="http://xsdtesting"
elementFormDefault="qualified">
<xs:complexType name="B">
<xs:choice minOccurs="1" maxOccurs="99">
<xs:element name="e1"/>
<xs:element name="e2"/>
</xs:choice>
</xs:complexType>
<xs:complexType name="base">
<xs:complexContent>
<xs:restriction base="x:B">
<xs:choice minOccurs="3" maxOccurs="9">
<xs:element name="e1"/>
<xs:element name="e2"/>
</xs:choice>
</xs:restriction>
</xs:complexContent>
</xs:complexType>
<xs:complexType name="R">
<xs:complexContent>
<xs:restriction base="x:base">
<xs:all>
<xs:element name="e1"/>
<xs:element name="e2"/>
</xs:all>
</xs:restriction>
</xs:complexContent>
</xs:complexType>
</xs:schema>"#;
let result = load_and_process_schema(xsd.as_bytes(), "test.xsd", &mut schema_set, None);
assert!(result.is_err(), "all-from-choice restriction is forbidden");
}
#[test]
fn test_reject_all_restricting_sequence_hb007() {
let mut schema_set = SchemaSet::new();
let xsd = r#"<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://xsdtesting" xmlns:x="http://xsdtesting"
elementFormDefault="qualified">
<xs:group name="Gb">
<xs:sequence>
<xs:element name="e1"/>
<xs:element name="e2"/>
</xs:sequence>
</xs:group>
<xs:group name="Gr">
<xs:all>
<xs:element name="e1"/>
<xs:element name="e2"/>
</xs:all>
</xs:group>
<xs:complexType name="base">
<xs:group ref="x:Gb"/>
</xs:complexType>
<xs:complexType name="R">
<xs:complexContent>
<xs:restriction base="x:base">
<xs:group ref="x:Gr"/>
</xs:restriction>
</xs:complexContent>
</xs:complexType>
</xs:schema>"#;
let result = load_and_process_schema(xsd.as_bytes(), "test.xsd", &mut schema_set, None);
assert!(
result.is_err(),
"all-from-sequence restriction via group refs is forbidden"
);
}
#[test]
fn test_reject_choice_restricting_all_hb009() {
let mut schema_set = SchemaSet::new();
let xsd = r#"<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://xsdtesting" xmlns:x="http://xsdtesting"
elementFormDefault="qualified">
<xs:complexType name="base">
<xs:all>
<xs:element name="e1"/>
<xs:element name="e2"/>
</xs:all>
</xs:complexType>
<xs:complexType name="R">
<xs:complexContent>
<xs:restriction base="x:base">
<xs:choice>
<xs:element name="e1"/>
<xs:element name="e2"/>
</xs:choice>
</xs:restriction>
</xs:complexContent>
</xs:complexType>
</xs:schema>"#;
let result = load_and_process_schema(xsd.as_bytes(), "test.xsd", &mut schema_set, None);
assert!(result.is_err(), "choice-from-all restriction is forbidden");
}
#[test]
fn test_reject_choice_branch_element_vs_sequence_m033() {
let mut schema_set = SchemaSet::new();
let xsd = r#"<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://xsdtesting" xmlns:x="http://xsdtesting">
<xs:complexType name="B">
<xs:choice>
<xs:element name="c1" minOccurs="2" maxOccurs="2"/>
<xs:sequence minOccurs="1" maxOccurs="unbounded">
<xs:element name="d1" minOccurs="1" maxOccurs="1"/>
<xs:element name="d2" minOccurs="1" maxOccurs="1"/>
</xs:sequence>
</xs:choice>
</xs:complexType>
<xs:complexType name="R">
<xs:complexContent>
<xs:restriction base="x:B">
<xs:choice>
<xs:element name="c1" minOccurs="2" maxOccurs="2"/>
<xs:element name="d2" minOccurs="1" maxOccurs="unbounded"/>
</xs:choice>
</xs:restriction>
</xs:complexContent>
</xs:complexType>
</xs:schema>"#;
let result = load_and_process_schema(xsd.as_bytes(), "test.xsd", &mut schema_set, None);
assert!(
result.is_err(),
"choice branch d2 cannot restrict base sequence(d1,d2)"
);
}
#[test]
fn test_reject_choice_branch_vs_multi_child_sequences_m034() {
let mut schema_set = SchemaSet::new();
let xsd = r#"<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://xsdtesting" xmlns:x="http://xsdtesting">
<xs:complexType name="B">
<xs:choice>
<xs:sequence minOccurs="0" maxOccurs="unbounded">
<xs:element name="c1" minOccurs="2" maxOccurs="2"/>
<xs:element name="c2" minOccurs="0" maxOccurs="1"/>
</xs:sequence>
<xs:sequence minOccurs="1" maxOccurs="unbounded">
<xs:element name="d1" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="d2" minOccurs="1" maxOccurs="unbounded"/>
</xs:sequence>
</xs:choice>
</xs:complexType>
<xs:complexType name="R">
<xs:complexContent>
<xs:restriction base="x:B">
<xs:choice>
<xs:element name="d1" minOccurs="1" maxOccurs="unbounded"/>
</xs:choice>
</xs:restriction>
</xs:complexContent>
</xs:complexType>
</xs:schema>"#;
let result = load_and_process_schema(xsd.as_bytes(), "test.xsd", &mut schema_set, None);
assert!(
result.is_err(),
"choice branch d1 cannot restrict either base sequence branch"
);
}
#[test]
fn test_accept_choice_restriction_all_branches_zero() {
let mut schema_set = SchemaSet::new();
let xsd = r#"<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://xsdtesting" xmlns:x="http://xsdtesting"
elementFormDefault="qualified">
<xs:complexType name="base">
<xs:choice minOccurs="0">
<xs:element name="e1" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="e2" minOccurs="0" maxOccurs="unbounded"/>
</xs:choice>
</xs:complexType>
<xs:complexType name="testing">
<xs:complexContent>
<xs:restriction base="x:base">
<xs:choice minOccurs="0">
<xs:element name="e1" minOccurs="0" maxOccurs="0"/>
<xs:element name="e2" minOccurs="0" maxOccurs="0"/>
</xs:choice>
</xs:restriction>
</xs:complexContent>
</xs:complexType>
</xs:schema>"#;
let result = load_and_process_schema(xsd.as_bytes(), "test.xsd", &mut schema_set, None);
assert!(
result.is_ok(),
"choice restriction with all-zero branches should be valid: {:?}",
result
);
}
#[test]
fn test_reject_element_restricting_group_with_required_repetition() {
let mut schema_set = SchemaSet::new();
let xsd = r#"<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:complexType name="base">
<xs:sequence minOccurs="2" maxOccurs="2">
<xs:element name="a"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="derived">
<xs:complexContent>
<xs:restriction base="base">
<xs:sequence>
<xs:element name="a"/>
</xs:sequence>
</xs:restriction>
</xs:complexContent>
</xs:complexType>
</xs:schema>"#;
let result = load_and_process_schema(xsd.as_bytes(), "test.xsd", &mut schema_set, None);
assert!(
result.is_err(),
"derived sequence{{1,1}} cannot restrict base sequence{{2,2}}"
);
}
#[test]
fn test_accept_sequence_restriction_dropping_optional() {
let mut schema_set = SchemaSet::new();
let xsd = r#"<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:complexType name="base">
<xs:sequence>
<xs:element name="a" type="xs:string"/>
<xs:element name="b" type="xs:string" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="derived">
<xs:complexContent>
<xs:restriction base="base">
<xs:sequence>
<xs:element name="a" type="xs:string"/>
</xs:sequence>
</xs:restriction>
</xs:complexContent>
</xs:complexType>
</xs:schema>"#;
let result = load_and_process_schema(xsd.as_bytes(), "test.xsd", &mut schema_set, None);
assert!(
result.is_ok(),
"dropping optional tail should be valid: {:?}",
result
);
}
#[test]
fn test_load_and_process_attribute_with_inline_type() {
let mut schema_set = SchemaSet::new();
let xsd = r#"<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:complexType name="ProductType">
<xs:attribute name="code">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:pattern value="[A-Z]{3}-[0-9]{4}"/>
</xs:restriction>
</xs:simpleType>
</xs:attribute>
</xs:complexType>
</xs:schema>"#;
let result = load_and_process_schema(xsd.as_bytes(), "test.xsd", &mut schema_set, None);
assert!(
result.is_ok(),
"Should parse schema with attribute inline type: {:?}",
result
);
let stats = result.unwrap();
let inline_stats = stats.inline_stats.unwrap();
assert!(
inline_stats.total_inline_types > 0,
"Should assemble attribute inline type"
);
}
#[test]
fn test_parse_only_mode() {
let mut schema_set = SchemaSet::new();
let xsd = r#"<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="root" type="xs:string"/>
</xs:schema>"#;
let result = load_and_process_schema(
xsd.as_bytes(),
"test.xsd",
&mut schema_set,
Some(PipelineConfig::parse_only()),
);
assert!(result.is_ok());
let stats = result.unwrap();
assert!(stats.inline_stats.is_none());
assert!(stats.resolution_stats.is_none());
let root_name = schema_set.name_table.get("root").unwrap();
let elem_key = schema_set.lookup_element(None, root_name).unwrap();
let elem = schema_set.arenas.elements.get(elem_key).unwrap();
assert!(
elem.resolved_type.is_none(),
"Type should not be resolved in parse-only mode"
);
}
#[test]
fn test_process_loaded_schemas() {
let mut schema_set = SchemaSet::new();
let xsd = r#"<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="item">
<xs:complexType>
<xs:sequence>
<xs:element name="value" type="xs:decimal"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>"#;
let doc_id = parse_schema_only(xsd.as_bytes(), "test.xsd", &mut schema_set).unwrap();
assert_eq!(doc_id, 0);
let item_name = schema_set.name_table.get("item").unwrap();
let elem_key = schema_set.lookup_element(None, item_name).unwrap();
let elem = schema_set.arenas.elements.get(elem_key).unwrap();
assert!(elem.resolved_type.is_none());
let (inline_stats, resolution_stats) = process_loaded_schemas(&mut schema_set).unwrap();
assert!(inline_stats.total_inline_types > 0);
let elem = schema_set.arenas.elements.get(elem_key).unwrap();
assert!(
elem.resolved_type.is_some(),
"Type should be resolved after processing"
);
let _ = resolution_stats; }
#[test]
fn test_pipeline_config_default() {
let config = PipelineConfig::default();
assert!(config.resolve_directives);
assert!(config.assemble_inline_types);
assert!(config.resolve_references);
}
#[test]
fn test_pipeline_config_parse_only() {
let config = PipelineConfig::parse_only();
assert!(!config.resolve_directives);
assert!(!config.assemble_inline_types);
assert!(!config.resolve_references);
}
#[test]
fn test_load_schema_convenience() {
let mut schema_set = SchemaSet::new();
let xsd = r#"<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="data" type="xs:string"/>
</xs:schema>"#;
let result = load_schema(xsd.as_bytes(), "test.xsd", &mut schema_set);
assert!(result.is_ok());
}
#[test]
fn test_nested_inline_types() {
let mut schema_set = SchemaSet::new();
let xsd = r#"<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="order">
<xs:complexType>
<xs:sequence>
<xs:element name="item">
<xs:complexType>
<xs:sequence>
<xs:element name="name" type="xs:string"/>
<xs:element name="price">
<xs:simpleType>
<xs:restriction base="xs:decimal">
<xs:minInclusive value="0"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>"#;
let result = load_and_process_schema(xsd.as_bytes(), "test.xsd", &mut schema_set, None);
assert!(
result.is_ok(),
"Should handle nested inline types: {:?}",
result
);
let stats = result.unwrap();
let inline_stats = stats.inline_stats.unwrap();
assert!(
inline_stats.total_inline_types >= 1,
"Should assemble multiple inline types"
);
}
#[test]
fn test_reject_element_name_and_ref() {
let mut schema_set = SchemaSet::new();
let xsd = r#"<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="foo" ref="bar"/>
</xs:schema>"#;
let mut config = PipelineConfig::default();
config.parser.error_recovery = false;
let result = load_and_process_schema(xsd.as_bytes(), "test.xsd", &mut schema_set, Some(config));
assert!(
result.is_err(),
"Should reject element with both name and ref"
);
let err = result.unwrap_err();
assert!(
err.to_string().contains("name") || err.to_string().contains("ref"),
"Error should mention name/ref conflict: {}",
err
);
}
#[test]
fn test_list_itemtype_xor_inline() {
let mut schema_set = SchemaSet::new();
let xsd = r#"<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:simpleType name="badList">
<xs:list itemType="xs:string">
<xs:simpleType>
<xs:restriction base="xs:integer"/>
</xs:simpleType>
</xs:list>
</xs:simpleType>
</xs:schema>"#;
let mut config = PipelineConfig::default();
config.parser.error_recovery = false;
let result = load_and_process_schema(xsd.as_bytes(), "test.xsd", &mut schema_set, Some(config));
assert!(
result.is_err(),
"Should reject list with both itemType and inline type"
);
}
#[test]
fn test_union_requires_membertypes_or_inline() {
let mut schema_set = SchemaSet::new();
let xsd = r#"<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:simpleType name="badUnion">
<xs:union/>
</xs:simpleType>
</xs:schema>"#;
let mut config = PipelineConfig::default();
config.parser.error_recovery = false;
let result = load_and_process_schema(xsd.as_bytes(), "test.xsd", &mut schema_set, Some(config));
assert!(
result.is_err() || !schema_set.arenas.simple_types.is_empty(),
"Should either reject empty union or parse it for later validation"
);
}
#[cfg(feature = "xsd11")]
#[test]
fn test_xsd11_assert_rejected_in_10_mode() {
let mut schema_set = SchemaSet::new(); let xsd = r#"<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:complexType name="ValidatedType">
<xs:sequence>
<xs:element name="value" type="xs:integer"/>
</xs:sequence>
<xs:assert test="value gt 0"/>
</xs:complexType>
</xs:schema>"#;
let config = PipelineConfig {
parser: ParserConfig {
error_recovery: false,
..Default::default()
},
..Default::default()
};
let result = load_and_process_schema(xsd.as_bytes(), "test.xsd", &mut schema_set, Some(config));
assert!(
result.is_err(),
"xs:assert should be rejected in XSD 1.0 mode"
);
}
#[cfg(feature = "xsd11")]
#[test]
fn test_xsd11_assert_allowed_in_11_mode() {
let mut schema_set = SchemaSet::xsd11();
let xsd = r#"<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:complexType name="ValidatedType">
<xs:sequence>
<xs:element name="value" type="xs:integer"/>
</xs:sequence>
<xs:assert test="value gt 0"/>
</xs:complexType>
</xs:schema>"#;
let result = load_and_process_schema(xsd.as_bytes(), "test.xsd", &mut schema_set, None);
assert!(
result.is_ok(),
"xs:assert should be allowed in XSD 1.1 mode: {:?}",
result
);
}
#[cfg(feature = "xsd11")]
#[test]
fn test_xsd11_alternative_rejected_in_10_mode() {
let mut schema_set = SchemaSet::new(); let xsd = r#"<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="item">
<xs:alternative test="@type='special'" type="xs:string"/>
</xs:element>
</xs:schema>"#;
let config = PipelineConfig {
parser: ParserConfig {
error_recovery: false,
..Default::default()
},
..Default::default()
};
let result = load_and_process_schema(xsd.as_bytes(), "test.xsd", &mut schema_set, Some(config));
assert!(
result.is_err(),
"xs:alternative should be rejected in XSD 1.0 mode"
);
}
#[test]
fn test_skip_unknown_subtree() {
let mut schema_set = SchemaSet::new();
let xsd = r#"<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<unknownElement>
<nested>content</nested>
</unknownElement>
<xs:element name="valid" type="xs:string"/>
</xs:schema>"#;
let result = load_and_process_schema(xsd.as_bytes(), "test.xsd", &mut schema_set, None);
let err = result.expect_err("Foreign element at schema level must be rejected");
let msg = err.to_string();
assert!(
msg.contains("Foreign-namespace element") || msg.contains("sch-props-correct"),
"Expected sch-props-correct foreign-element error, got: {}",
msg
);
let valid_name = schema_set.name_table.get("valid").unwrap();
let elem_key = schema_set.lookup_element(None, valid_name);
assert!(
elem_key.is_some(),
"Valid element should still be parsed after the unknown subtree is skipped"
);
}
#[test]
fn test_element_foreign_attribute_creates_implicit_annotation() {
let mut schema_set = SchemaSet::new();
let xsd = r#"<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:custom="http://example.com/custom">
<xs:element name="test" custom:attr="value"/>
</xs:schema>"#;
let result = load_and_process_schema(xsd.as_bytes(), "test.xsd", &mut schema_set, None);
assert!(
result.is_ok(),
"Should parse schema with foreign attribute: {:?}",
result
);
let test_name = schema_set.name_table.get("test").unwrap();
let elem_key = schema_set.lookup_element(None, test_name).unwrap();
let elem = schema_set.arenas.elements.get(elem_key).unwrap();
assert!(
elem.annotation.is_some(),
"Element with foreign attribute should have annotation"
);
let ann = elem.annotation.as_ref().unwrap();
assert!(
!ann.attributes.is_empty(),
"Annotation should have foreign attributes"
);
assert_eq!(ann.attributes[0].value, "value");
}
#[test]
fn test_foreign_attribute_merged_with_explicit_annotation() {
let mut schema_set = SchemaSet::new();
let xsd = r#"<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:custom="http://example.com/custom">
<xs:element name="test" custom:attr="value">
<xs:annotation>
<xs:documentation>Test documentation</xs:documentation>
</xs:annotation>
</xs:element>
</xs:schema>"#;
let result = load_and_process_schema(xsd.as_bytes(), "test.xsd", &mut schema_set, None);
assert!(result.is_ok(), "Should parse schema: {:?}", result);
let test_name = schema_set.name_table.get("test").unwrap();
let elem_key = schema_set.lookup_element(None, test_name).unwrap();
let elem = schema_set.arenas.elements.get(elem_key).unwrap();
assert!(elem.annotation.is_some(), "Element should have annotation");
let ann = elem.annotation.as_ref().unwrap();
assert!(
!ann.items.is_empty(),
"Annotation should have documentation item"
);
assert!(
!ann.attributes.is_empty(),
"Annotation should have merged foreign attributes"
);
}
#[test]
fn test_complex_type_foreign_attribute() {
let mut schema_set = SchemaSet::new();
let xsd = r#"<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:jaxb="http://java.sun.com/xml/ns/jaxb">
<xs:complexType name="PersonType" jaxb:class="Person">
<xs:sequence>
<xs:element name="name" type="xs:string"/>
</xs:sequence>
</xs:complexType>
</xs:schema>"#;
let result = load_and_process_schema(xsd.as_bytes(), "test.xsd", &mut schema_set, None);
assert!(result.is_ok(), "Should parse schema: {:?}", result);
let type_name = schema_set.name_table.get("PersonType").unwrap();
let type_key = schema_set.lookup_type(None, type_name).unwrap();
if let TypeKey::Complex(ct_key) = type_key {
let ct = schema_set.arenas.complex_types.get(ct_key).unwrap();
assert!(
ct.annotation.is_some(),
"ComplexType with foreign attribute should have annotation"
);
let ann = ct.annotation.as_ref().unwrap();
assert!(
!ann.attributes.is_empty(),
"Annotation should have foreign attributes"
);
} else {
panic!("Expected complex type");
}
}
#[test]
fn test_redefine_via_pipeline() {
let tmp = std::env::temp_dir().join("xsd_test_redefine");
std::fs::create_dir_all(&tmp).unwrap();
let base_xsd = r#"<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:simpleType name="MyString">
<xs:restriction base="xs:string"/>
</xs:simpleType>
</xs:schema>"#;
let base_path = tmp.join("base.xsd");
std::fs::write(&base_path, base_xsd).unwrap();
let redefine_xsd = format!(
r#"<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:redefine schemaLocation="{}">
<xs:simpleType name="MyString">
<xs:restriction base="MyString">
<xs:maxLength value="100"/>
</xs:restriction>
</xs:simpleType>
</xs:redefine>
<xs:element name="root" type="MyString"/>
</xs:schema>"#,
base_path.to_string_lossy()
);
let mut schema_set = SchemaSet::new();
let result = load_and_process_schema(
redefine_xsd.as_bytes(),
&tmp.join("redefine.xsd").to_string_lossy(),
&mut schema_set,
None,
);
assert!(
result.is_ok(),
"Redefine via pipeline should succeed: {:?}",
result
);
let name = schema_set.name_table.get("MyString").unwrap();
let type_key = schema_set.lookup_type(None, name);
assert!(type_key.is_some(), "Redefined type should be registered");
assert!(matches!(type_key.unwrap(), TypeKey::Simple(_)));
let root_name = schema_set.name_table.get("root").unwrap();
let elem_key = schema_set.lookup_element(None, root_name).unwrap();
let elem = schema_set.arenas.elements.get(elem_key).unwrap();
assert!(
elem.resolved_type.is_some(),
"Element type should resolve to redefined type"
);
let _ = std::fs::remove_dir_all(&tmp);
}
#[cfg(feature = "xsd11")]
#[test]
fn test_override_via_pipeline() {
use crate::schema::model::XsdVersion;
let tmp = std::env::temp_dir().join("xsd_test_override");
std::fs::create_dir_all(&tmp).unwrap();
let base_xsd = r#"<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:simpleType name="CodeType">
<xs:restriction base="xs:string"/>
</xs:simpleType>
</xs:schema>"#;
let base_path = tmp.join("base.xsd");
std::fs::write(&base_path, base_xsd).unwrap();
let override_xsd = format!(
r#"<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:override schemaLocation="{}">
<xs:simpleType name="CodeType">
<xs:restriction base="xs:token">
<xs:pattern value="[A-Z]{{3}}"/>
</xs:restriction>
</xs:simpleType>
</xs:override>
<xs:element name="code" type="CodeType"/>
</xs:schema>"#,
base_path.to_string_lossy()
);
let mut schema_set = SchemaSet::with_version(XsdVersion::V1_1);
let result = load_and_process_schema(
override_xsd.as_bytes(),
&tmp.join("override.xsd").to_string_lossy(),
&mut schema_set,
None,
);
assert!(
result.is_ok(),
"Override via pipeline should succeed: {:?}",
result
);
let name = schema_set.name_table.get("CodeType").unwrap();
let type_key = schema_set.lookup_type(None, name);
assert!(type_key.is_some(), "Overridden type should be registered");
let code_name = schema_set.name_table.get("code").unwrap();
let elem_key = schema_set.lookup_element(None, code_name).unwrap();
let elem = schema_set.arenas.elements.get(elem_key).unwrap();
assert!(
elem.resolved_type.is_some(),
"Element type should resolve to overridden type"
);
let _ = std::fs::remove_dir_all(&tmp);
}
#[test]
fn test_process_loaded_schemas_with_redefine() {
let base_xsd = r#"<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:complexType name="BaseType">
<xs:sequence>
<xs:element name="name" type="xs:string"/>
</xs:sequence>
</xs:complexType>
</xs:schema>"#;
let redefine_xsd = r#"<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:redefine schemaLocation="base.xsd">
<xs:complexType name="BaseType">
<xs:complexContent>
<xs:extension base="BaseType">
<xs:sequence>
<xs:element name="extra" type="xs:int"/>
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType>
</xs:redefine>
<xs:element name="item" type="BaseType"/>
</xs:schema>"#;
let mut schema_set = SchemaSet::new();
let _base_id = parse_schema_only(base_xsd.as_bytes(), "base.xsd", &mut schema_set).unwrap();
let _redefine_id =
parse_schema_only(redefine_xsd.as_bytes(), "redefine.xsd", &mut schema_set).unwrap();
let result = process_loaded_schemas(&mut schema_set);
assert!(
result.is_ok(),
"process_loaded_schemas with redefine should succeed: {:?}",
result
);
let name = schema_set.name_table.get("BaseType").unwrap();
let type_key = schema_set.lookup_type(None, name);
assert!(type_key.is_some(), "Redefined type should be registered");
assert!(matches!(type_key.unwrap(), TypeKey::Complex(_)));
}
#[test]
fn test_redefine_simple_type_base_resolves_to_original() {
let tmp = std::env::temp_dir().join("xsd_test_redefine_simple_base");
std::fs::create_dir_all(&tmp).unwrap();
let base_xsd = r#"<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:simpleType name="MyString">
<xs:restriction base="xs:string"/>
</xs:simpleType>
</xs:schema>"#;
let base_path = tmp.join("base.xsd");
std::fs::write(&base_path, base_xsd).unwrap();
let redefine_xsd = format!(
r#"<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:redefine schemaLocation="{}">
<xs:simpleType name="MyString">
<xs:restriction base="MyString">
<xs:maxLength value="100"/>
</xs:restriction>
</xs:simpleType>
</xs:redefine>
</xs:schema>"#,
base_path.to_string_lossy()
);
let mut schema_set = SchemaSet::new();
let result = load_and_process_schema(
redefine_xsd.as_bytes(),
&tmp.join("redefine.xsd").to_string_lossy(),
&mut schema_set,
None,
);
assert!(result.is_ok(), "Redefine should succeed: {:?}", result);
let name = schema_set.name_table.get("MyString").unwrap();
let type_key = schema_set.lookup_type(None, name).unwrap();
let TypeKey::Simple(simple_key) = type_key else {
panic!("Expected simple type");
};
let type_def = schema_set.arenas.simple_types.get(simple_key).unwrap();
assert!(
type_def.redefine_original.is_some(),
"redefine_original should be set"
);
assert!(
type_def.resolved_base_type.is_some(),
"resolved_base_type should be set"
);
assert_ne!(
type_def.resolved_base_type.unwrap(),
type_key,
"resolved_base_type must point to the original, not self"
);
assert_eq!(
type_def.resolved_base_type.unwrap(),
TypeKey::Simple(type_def.redefine_original.unwrap()),
"resolved_base_type must equal TypeKey::Simple(redefine_original)"
);
let _ = std::fs::remove_dir_all(&tmp);
}
#[test]
fn test_redefine_complex_type_base_resolves_to_original() {
let tmp = std::env::temp_dir().join("xsd_test_redefine_complex_base");
std::fs::create_dir_all(&tmp).unwrap();
let base_xsd = r#"<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:complexType name="PersonType">
<xs:sequence>
<xs:element name="name" type="xs:string"/>
</xs:sequence>
</xs:complexType>
</xs:schema>"#;
let base_path = tmp.join("base.xsd");
std::fs::write(&base_path, base_xsd).unwrap();
let redefine_xsd = format!(
r#"<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:redefine schemaLocation="{}">
<xs:complexType name="PersonType">
<xs:complexContent>
<xs:extension base="PersonType">
<xs:sequence>
<xs:element name="age" type="xs:int"/>
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType>
</xs:redefine>
<xs:element name="person" type="PersonType"/>
</xs:schema>"#,
base_path.to_string_lossy()
);
let mut schema_set = SchemaSet::new();
let result = load_and_process_schema(
redefine_xsd.as_bytes(),
&tmp.join("redefine.xsd").to_string_lossy(),
&mut schema_set,
None,
);
assert!(result.is_ok(), "Redefine should succeed: {:?}", result);
let name = schema_set.name_table.get("PersonType").unwrap();
let type_key = schema_set.lookup_type(None, name).unwrap();
let TypeKey::Complex(complex_key) = type_key else {
panic!("Expected complex type");
};
let type_def = schema_set.arenas.complex_types.get(complex_key).unwrap();
assert!(
type_def.redefine_original.is_some(),
"redefine_original should be set"
);
assert!(
type_def.resolved_base_type.is_some(),
"resolved_base_type should be set"
);
assert_ne!(
type_def.resolved_base_type.unwrap(),
type_key,
"resolved_base_type must point to the original, not self"
);
assert_eq!(
type_def.resolved_base_type.unwrap(),
TypeKey::Complex(type_def.redefine_original.unwrap()),
"resolved_base_type must equal TypeKey::Complex(redefine_original)"
);
let _ = std::fs::remove_dir_all(&tmp);
}
#[test]
fn test_redefine_complex_type_extension_via_batch_path() {
let base_xsd = r#"<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:complexType name="BaseType">
<xs:sequence>
<xs:element name="name" type="xs:string"/>
</xs:sequence>
</xs:complexType>
</xs:schema>"#;
let redefine_xsd = r#"<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:redefine schemaLocation="base.xsd">
<xs:complexType name="BaseType">
<xs:complexContent>
<xs:extension base="BaseType">
<xs:sequence>
<xs:element name="extra" type="xs:int"/>
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType>
</xs:redefine>
<xs:element name="item" type="BaseType"/>
</xs:schema>"#;
let mut schema_set = SchemaSet::new();
let _base_id = parse_schema_only(base_xsd.as_bytes(), "base.xsd", &mut schema_set).unwrap();
let _redefine_id =
parse_schema_only(redefine_xsd.as_bytes(), "redefine.xsd", &mut schema_set).unwrap();
let result = process_loaded_schemas(&mut schema_set);
assert!(
result.is_ok(),
"process_loaded_schemas should succeed: {:?}",
result
);
let name = schema_set.name_table.get("BaseType").unwrap();
let type_key = schema_set.lookup_type(None, name).unwrap();
let TypeKey::Complex(complex_key) = type_key else {
panic!("Expected complex type");
};
let type_def = schema_set.arenas.complex_types.get(complex_key).unwrap();
assert!(
type_def.resolved_base_type.is_some(),
"resolved_base_type should be set"
);
assert_ne!(
type_def.resolved_base_type.unwrap(),
type_key,
"resolved_base_type must not be self in batch path"
);
}
#[test]
fn test_process_loaded_schemas_propagates_dependency_error() {
let schema_xsd = r#"<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:complexType name="SelfRef">
<xs:complexContent>
<xs:extension base="SelfRef">
<xs:sequence>
<xs:element name="x" type="xs:string"/>
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType>
</xs:schema>"#;
let mut schema_set = SchemaSet::new();
let _doc_id = parse_schema_only(schema_xsd.as_bytes(), "selfref.xsd", &mut schema_set).unwrap();
let result = process_loaded_schemas(&mut schema_set);
assert!(
result.is_err(),
"Self-referencing type dependency should be detected as error"
);
}
#[test]
fn test_cross_reference_cycle_with_namespace_prefix() {
let schema_xsd = r#"<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="urn:test" xmlns:t="urn:test">
<xs:complexType name="TypeA">
<xs:complexContent>
<xs:extension base="t:TypeB">
<xs:sequence>
<xs:element name="a" type="xs:string"/>
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType>
<xs:complexType name="TypeB">
<xs:complexContent>
<xs:extension base="t:TypeA">
<xs:sequence>
<xs:element name="b" type="xs:string"/>
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType>
</xs:schema>"#;
let mut schema_set = SchemaSet::new();
let _doc_id =
parse_schema_only(schema_xsd.as_bytes(), "circular.xsd", &mut schema_set).unwrap();
let urn_test = schema_set.name_table.get("urn:test");
let type_a_name = schema_set.name_table.get("TypeA");
let type_b_name = schema_set.name_table.get("TypeB");
assert!(urn_test.is_some(), "urn:test should be interned");
assert!(type_a_name.is_some(), "TypeA should be interned");
assert!(type_b_name.is_some(), "TypeB should be interned");
let urn_test = urn_test.unwrap();
let type_a_name = type_a_name.unwrap();
let type_b_name = type_b_name.unwrap();
let a_key = schema_set.lookup_type(Some(urn_test), type_a_name);
let b_key = schema_set.lookup_type(Some(urn_test), type_b_name);
assert!(
a_key.is_some(),
"TypeA should be registered in urn:test namespace"
);
assert!(
b_key.is_some(),
"TypeB should be registered in urn:test namespace"
);
let TypeKey::Complex(ak) = a_key.unwrap() else {
panic!("TypeA not complex")
};
let TypeKey::Complex(bk) = b_key.unwrap() else {
panic!("TypeB not complex")
};
let a_def = schema_set.arenas.complex_types.get(ak).unwrap();
let b_def = schema_set.arenas.complex_types.get(bk).unwrap();
assert!(
a_def.base_type.is_some(),
"TypeA base_type QName should be set after parsing"
);
assert!(
b_def.base_type.is_some(),
"TypeB base_type QName should be set after parsing"
);
let result = process_loaded_schemas(&mut schema_set);
assert!(
result.is_err(),
"Circular dependency (TypeA ↔ TypeB) should be detected as error"
);
let a_def = schema_set.arenas.complex_types.get(ak).unwrap();
let b_def = schema_set.arenas.complex_types.get(bk).unwrap();
assert!(
a_def.resolved_base_type.is_some(),
"TypeA resolved_base_type should be set — pointing to TypeB"
);
assert!(
b_def.resolved_base_type.is_some(),
"TypeB resolved_base_type should be set — pointing to TypeA"
);
}
#[test]
fn test_redefine_rejects_cross_namespace_base_reference() {
let tmp = std::env::temp_dir().join("xsd_test_redefine_cross_ns");
std::fs::create_dir_all(&tmp).unwrap();
let base_xsd = r#"<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="urn:base">
<xs:simpleType name="Code">
<xs:restriction base="xs:string"/>
</xs:simpleType>
</xs:schema>"#;
let base_path = tmp.join("base.xsd");
std::fs::write(&base_path, base_xsd).unwrap();
let redefine_xsd = format!(
r#"<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="urn:base" xmlns:other="urn:other">
<xs:redefine schemaLocation="{}">
<xs:simpleType name="Code">
<xs:restriction base="other:Code">
<xs:maxLength value="10"/>
</xs:restriction>
</xs:simpleType>
</xs:redefine>
</xs:schema>"#,
base_path.to_string_lossy()
);
let mut schema_set = SchemaSet::new();
let result = load_and_process_schema(
redefine_xsd.as_bytes(),
&tmp.join("redefine.xsd").to_string_lossy(),
&mut schema_set,
None,
);
assert!(
result.is_err(),
"Cross-namespace base reference in redefine should be rejected: {:?}",
result,
);
let _ = std::fs::remove_dir_all(&tmp);
}
#[test]
fn test_malformed_qname_rejected() {
let xsd = r#"<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:simpleType name="Bad">
<xs:restriction base="xs:"/>
</xs:simpleType>
</xs:schema>"#;
let mut schema_set = SchemaSet::new();
let _ = load_and_process_schema(xsd.as_bytes(), "bad.xsd", &mut schema_set, None);
let name = schema_set.name_table.get("Bad");
if let Some(name_id) = name {
if let Some(TypeKey::Simple(sk)) = schema_set.lookup_type(None, name_id) {
let td = schema_set.arenas.simple_types.get(sk).unwrap();
assert!(
td.base_type.is_none()
|| matches!(&td.base_type, Some(crate::parser::frames::TypeRefResult::QName(q)) if schema_set.name_table.resolve(q.local_name).is_empty()),
"Malformed QName 'xs:' should not produce a valid base_type"
);
}
}
}
#[cfg(feature = "xsd11")]
#[test]
fn test_default_open_content_interleave_valid() {
let mut schema_set = SchemaSet::xsd11();
let xsd = r###"<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:defaultOpenContent mode="interleave">
<xs:any namespace="##other" processContents="lax"/>
</xs:defaultOpenContent>
<xs:element name="root" type="xs:string"/>
</xs:schema>"###;
let result = load_and_process_schema(xsd.as_bytes(), "test.xsd", &mut schema_set, None);
assert!(
result.is_ok(),
"Valid defaultOpenContent (interleave) should pass: {:?}",
result
);
}
#[cfg(feature = "xsd11")]
#[test]
fn test_default_open_content_suffix_valid() {
let mut schema_set = SchemaSet::xsd11();
let xsd = r###"<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:defaultOpenContent mode="suffix">
<xs:any namespace="##other" processContents="skip"/>
</xs:defaultOpenContent>
<xs:element name="root" type="xs:string"/>
</xs:schema>"###;
let result = load_and_process_schema(xsd.as_bytes(), "test.xsd", &mut schema_set, None);
assert!(
result.is_ok(),
"Valid defaultOpenContent (suffix) should pass: {:?}",
result
);
}
#[cfg(feature = "xsd11")]
#[test]
fn test_default_open_content_missing_wildcard() {
use crate::error::SchemaError;
let mut schema_set = SchemaSet::xsd11();
let xsd = r#"<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:defaultOpenContent mode="interleave"/>
<xs:element name="root" type="xs:string"/>
</xs:schema>"#;
let result = load_and_process_schema(xsd.as_bytes(), "test.xsd", &mut schema_set, None);
assert!(
result.is_err(),
"defaultOpenContent without wildcard should fail"
);
if let Err(SchemaError::StructuralError { constraint, .. }) = result {
assert_eq!(constraint, "cos-valid-default-oc");
} else {
panic!(
"Expected structural error with cos-valid-default-oc constraint, got: {:?}",
result
);
}
}
#[cfg(feature = "xsd11")]
#[test]
fn test_default_open_content_applies_to_empty_valid() {
let mut schema_set = SchemaSet::xsd11();
let xsd = r###"<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:defaultOpenContent mode="suffix" appliesToEmpty="true">
<xs:any namespace="##other" processContents="lax"/>
</xs:defaultOpenContent>
<xs:element name="root" type="xs:string"/>
</xs:schema>"###;
let result = load_and_process_schema(xsd.as_bytes(), "test.xsd", &mut schema_set, None);
assert!(
result.is_ok(),
"Valid defaultOpenContent with appliesToEmpty should pass: {:?}",
result
);
}
#[test]
fn test_substitution_group_final_restriction_blocks_member() {
let mut schema_set = SchemaSet::new();
let xsd = r###"<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://test" xmlns:t="http://test"
elementFormDefault="qualified">
<xsd:complexType name="foo">
<xsd:choice>
<xsd:element name="c1" minOccurs="0" maxOccurs="2"/>
<xsd:element name="c2"/>
</xsd:choice>
</xsd:complexType>
<xsd:complexType name="bar">
<xsd:complexContent>
<xsd:restriction base="t:foo">
<xsd:choice>
<xsd:element name="c1"/>
<xsd:element name="c2"/>
</xsd:choice>
</xsd:restriction>
</xsd:complexContent>
</xsd:complexType>
<xsd:element name="e1" type="t:foo" final="restriction"/>
<xsd:element name="e2" type="t:bar" substitutionGroup="t:e1"/>
</xsd:schema>"###;
let result = load_and_process_schema(xsd.as_bytes(), "test.xsd", &mut schema_set, None);
assert!(
result.is_err(),
"Schema should be invalid: final='restriction' blocks member"
);
match result.unwrap_err() {
SchemaError::StructuralError { constraint, .. } => {
assert_eq!(constraint, "e-props-correct.4");
}
other => panic!("Expected e-props-correct.4, got {:?}", other),
}
}
#[test]
fn test_substitution_group_final_extension_allows_restriction_member() {
let mut schema_set = SchemaSet::new();
let xsd = r###"<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://test" xmlns:t="http://test"
elementFormDefault="qualified">
<xsd:complexType name="foo">
<xsd:choice>
<xsd:element name="c1" minOccurs="0" maxOccurs="2"/>
<xsd:element name="c2"/>
</xsd:choice>
</xsd:complexType>
<xsd:complexType name="bar">
<xsd:complexContent>
<xsd:restriction base="t:foo">
<xsd:choice>
<xsd:element name="c1"/>
<xsd:element name="c2"/>
</xsd:choice>
</xsd:restriction>
</xsd:complexContent>
</xsd:complexType>
<xsd:element name="e1" type="t:foo" final="extension"/>
<xsd:element name="e2" type="t:bar" substitutionGroup="t:e1"/>
</xsd:schema>"###;
let result = load_and_process_schema(xsd.as_bytes(), "test.xsd", &mut schema_set, None);
assert!(
result.is_ok(),
"final='extension' should not block restriction-derived member: {:?}",
result
);
}
#[test]
fn test_element_restriction_shorthand_type_restricts_anytype() {
let mut schema_set = SchemaSet::new();
let xsd = r###"<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://test" xmlns:t="http://test"
elementFormDefault="qualified">
<xsd:complexType name="foo">
<xsd:choice>
<xsd:element name="f1" maxOccurs="5"/>
<xsd:element name="f2"/>
</xsd:choice>
</xsd:complexType>
<xsd:complexType name="B">
<xsd:choice>
<xsd:element name="c1" type="xsd:anyType"/>
<xsd:element name="c2"/>
</xsd:choice>
</xsd:complexType>
<xsd:complexType name="R">
<xsd:complexContent>
<xsd:restriction base="t:B">
<xsd:choice>
<xsd:element name="c1" type="t:foo"/>
<xsd:element name="c2"/>
</xsd:choice>
</xsd:restriction>
</xsd:complexContent>
</xsd:complexType>
</xsd:schema>"###;
let result = load_and_process_schema(xsd.as_bytes(), "test.xsd", &mut schema_set, None);
assert!(
result.is_ok(),
"Schema should be valid: foo (shorthand complex type) restricts anyType: {:?}",
result
);
}
#[test]
fn test_all_all_reorder_invalid_xsd10() {
let mut schema_set = SchemaSet::new();
let xsd = r###"<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://test" xmlns:t="http://test">
<xsd:complexType name="B">
<xsd:all>
<xsd:element name="e1"/>
<xsd:element name="e2"/>
<xsd:element name="e3"/>
</xsd:all>
</xsd:complexType>
<xsd:complexType name="R">
<xsd:complexContent>
<xsd:restriction base="t:B">
<xsd:all>
<xsd:element name="e2"/>
<xsd:element name="e1"/>
<xsd:element name="e3"/>
</xsd:all>
</xsd:restriction>
</xsd:complexContent>
</xsd:complexType>
</xsd:schema>"###;
let result = load_and_process_schema(xsd.as_bytes(), "test.xsd", &mut schema_set, None);
assert!(
result.is_err(),
"All:All reordering should be invalid in XSD 1.0"
);
}
#[cfg(feature = "xsd11")]
#[test]
fn test_all_all_reorder_valid_xsd11() {
let mut schema_set = SchemaSet::xsd11();
let xsd = r###"<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://test" xmlns:t="http://test">
<xsd:complexType name="B">
<xsd:all>
<xsd:element name="e1"/>
<xsd:element name="e2"/>
<xsd:element name="e3"/>
</xsd:all>
</xsd:complexType>
<xsd:complexType name="R">
<xsd:complexContent>
<xsd:restriction base="t:B">
<xsd:all>
<xsd:element name="e2"/>
<xsd:element name="e1"/>
<xsd:element name="e3"/>
</xsd:all>
</xsd:restriction>
</xsd:complexContent>
</xsd:complexType>
</xsd:schema>"###;
let result = load_and_process_schema(xsd.as_bytes(), "test.xsd", &mut schema_set, None);
assert!(
result.is_ok(),
"All:All reordering should be valid in XSD 1.1: {:?}",
result
);
}
#[test]
fn test_all_all_same_order_valid_xsd10() {
let mut schema_set = SchemaSet::new();
let xsd = r###"<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://test" xmlns:t="http://test">
<xsd:complexType name="B">
<xsd:all>
<xsd:element name="e1"/>
<xsd:element name="e2"/>
</xsd:all>
</xsd:complexType>
<xsd:complexType name="R">
<xsd:complexContent>
<xsd:restriction base="t:B">
<xsd:all>
<xsd:element name="e1"/>
<xsd:element name="e2"/>
</xsd:all>
</xsd:restriction>
</xsd:complexContent>
</xsd:complexType>
</xsd:schema>"###;
let result = load_and_process_schema(xsd.as_bytes(), "test.xsd", &mut schema_set, None);
assert!(
result.is_ok(),
"All:All same order should be valid in XSD 1.0: {:?}",
result
);
}
#[test]
fn test_accept_sequence_restricts_all_reordered_u003() {
let mut schema_set = SchemaSet::new();
let xsd = r###"<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://test" xmlns:t="http://test">
<xsd:complexType name="B">
<xsd:all>
<xsd:element name="e1"/>
<xsd:element name="e2"/>
</xsd:all>
</xsd:complexType>
<xsd:complexType name="R">
<xsd:complexContent>
<xsd:restriction base="t:B">
<xsd:sequence>
<xsd:element name="e2"/>
<xsd:element name="e1"/>
</xsd:sequence>
</xsd:restriction>
</xsd:complexContent>
</xsd:complexType>
</xsd:schema>"###;
let result = load_and_process_schema(xsd.as_bytes(), "test.xsd", &mut schema_set, None);
assert!(
result.is_ok(),
"Sequence:All reordering should be valid (RecurseUnordered): {:?}",
result
);
}
#[test]
fn test_accept_sequence_restricts_all_omit_optional_u004() {
let mut schema_set = SchemaSet::new();
let xsd = r###"<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://test" xmlns:t="http://test">
<xsd:complexType name="B">
<xsd:all>
<xsd:element name="e1"/>
<xsd:element name="e2"/>
<xsd:element name="e3" minOccurs="0"/>
</xsd:all>
</xsd:complexType>
<xsd:complexType name="R">
<xsd:complexContent>
<xsd:restriction base="t:B">
<xsd:sequence>
<xsd:element name="e2"/>
<xsd:element name="e1"/>
</xsd:sequence>
</xsd:restriction>
</xsd:complexContent>
</xsd:complexType>
</xsd:schema>"###;
let result = load_and_process_schema(xsd.as_bytes(), "test.xsd", &mut schema_set, None);
assert!(
result.is_ok(),
"Sequence:All reorder + omit optional should be valid: {:?}",
result
);
}
#[test]
fn test_accept_sequence_restricts_all_full_reorder_u007() {
let mut schema_set = SchemaSet::new();
let xsd = r###"<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://test" xmlns:t="http://test">
<xsd:complexType name="B">
<xsd:all>
<xsd:element name="e1"/>
<xsd:element name="e2" minOccurs="0"/>
<xsd:element name="e3"/>
<xsd:element name="e4" minOccurs="0"/>
</xsd:all>
</xsd:complexType>
<xsd:complexType name="R">
<xsd:complexContent>
<xsd:restriction base="t:B">
<xsd:sequence>
<xsd:element name="e4"/>
<xsd:element name="e2" minOccurs="0"/>
<xsd:element name="e3"/>
<xsd:element name="e1"/>
</xsd:sequence>
</xsd:restriction>
</xsd:complexContent>
</xsd:complexType>
</xsd:schema>"###;
let result = load_and_process_schema(xsd.as_bytes(), "test.xsd", &mut schema_set, None);
assert!(
result.is_ok(),
"Sequence:All full reorder with promoted optional should be valid: {:?}",
result
);
}
#[test]
fn test_accept_repeated_sequence_restricts_choice_v001() {
let mut schema_set = SchemaSet::new();
let xsd = r###"<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://test" xmlns:t="http://test">
<xsd:complexType name="B">
<xsd:choice minOccurs="1" maxOccurs="10">
<xsd:element name="e1" minOccurs="1" maxOccurs="10"/>
<xsd:element name="e2" minOccurs="2" maxOccurs="10"/>
<xsd:element name="e3" minOccurs="3" maxOccurs="10"/>
</xsd:choice>
</xsd:complexType>
<xsd:complexType name="R">
<xsd:complexContent>
<xsd:restriction base="t:B">
<xsd:sequence minOccurs="1" maxOccurs="3">
<xsd:element name="e1" minOccurs="1" maxOccurs="10"/>
<xsd:element name="e2" minOccurs="2" maxOccurs="10"/>
<xsd:element name="e3" minOccurs="3" maxOccurs="10"/>
</xsd:sequence>
</xsd:restriction>
</xsd:complexContent>
</xsd:complexType>
</xsd:schema>"###;
let result = load_and_process_schema(xsd.as_bytes(), "test.xsd", &mut schema_set, None);
assert!(
result.is_ok(),
"Repeated sequence should validly restrict repeated choice (MapAndSum): {:?}",
result
);
}
#[test]
fn test_accept_repeated_sequence_restricts_choice_v003() {
let mut schema_set = SchemaSet::new();
let xsd = r###"<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://test" xmlns:t="http://test">
<xsd:complexType name="B">
<xsd:choice minOccurs="3" maxOccurs="9">
<xsd:element name="e1"/>
<xsd:element name="e2"/>
</xsd:choice>
</xsd:complexType>
<xsd:complexType name="R">
<xsd:complexContent>
<xsd:restriction base="t:B">
<xsd:sequence minOccurs="2" maxOccurs="4">
<xsd:element name="e1"/>
<xsd:element name="e2"/>
</xsd:sequence>
</xsd:restriction>
</xsd:complexContent>
</xsd:complexType>
</xsd:schema>"###;
let result = load_and_process_schema(xsd.as_bytes(), "test.xsd", &mut schema_set, None);
assert!(
result.is_ok(),
"Repeated sequence{{2,4}} should validly restrict choice{{3,9}}: {:?}",
result
);
}
#[test]
fn test_choice_choice_reorder_invalid_xsd10() {
let mut schema_set = SchemaSet::new();
let xsd = r###"<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://test" xmlns:t="http://test">
<xsd:complexType name="B">
<xsd:sequence>
<xsd:choice>
<xsd:element name="c1"/>
<xsd:element name="c2"/>
</xsd:choice>
<xsd:element name="foo"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="R">
<xsd:complexContent>
<xsd:restriction base="t:B">
<xsd:sequence>
<xsd:choice>
<xsd:element name="c2"/>
<xsd:element name="c1"/>
</xsd:choice>
<xsd:element name="foo"/>
</xsd:sequence>
</xsd:restriction>
</xsd:complexContent>
</xsd:complexType>
</xsd:schema>"###;
let result = load_and_process_schema(xsd.as_bytes(), "test.xsd", &mut schema_set, None);
assert!(
result.is_err(),
"Choice:Choice reordering should be invalid in XSD 1.0"
);
}
#[cfg(feature = "xsd11")]
#[test]
fn test_choice_choice_reorder_valid_xsd11() {
let mut schema_set = SchemaSet::xsd11();
let xsd = r###"<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://test" xmlns:t="http://test">
<xsd:complexType name="B">
<xsd:sequence>
<xsd:choice>
<xsd:element name="c1"/>
<xsd:element name="c2"/>
</xsd:choice>
<xsd:element name="foo"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="R">
<xsd:complexContent>
<xsd:restriction base="t:B">
<xsd:sequence>
<xsd:choice>
<xsd:element name="c2"/>
<xsd:element name="c1"/>
</xsd:choice>
<xsd:element name="foo"/>
</xsd:sequence>
</xsd:restriction>
</xsd:complexContent>
</xsd:complexType>
</xsd:schema>"###;
let result = load_and_process_schema(xsd.as_bytes(), "test.xsd", &mut schema_set, None);
assert!(
result.is_ok(),
"Choice:Choice reordering should be valid in XSD 1.1: {:?}",
result
);
}
#[test]
fn test_choice_choice_same_order_valid_xsd10() {
let mut schema_set = SchemaSet::new();
let xsd = r###"<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://test" xmlns:t="http://test">
<xsd:complexType name="B">
<xsd:sequence>
<xsd:choice>
<xsd:element name="c1"/>
<xsd:element name="c2"/>
</xsd:choice>
<xsd:element name="foo"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="R">
<xsd:complexContent>
<xsd:restriction base="t:B">
<xsd:sequence>
<xsd:choice>
<xsd:element name="c1"/>
<xsd:element name="c2"/>
</xsd:choice>
<xsd:element name="foo"/>
</xsd:sequence>
</xsd:restriction>
</xsd:complexContent>
</xsd:complexType>
</xsd:schema>"###;
let result = load_and_process_schema(xsd.as_bytes(), "test.xsd", &mut schema_set, None);
assert!(
result.is_ok(),
"Choice:Choice same order should be valid in XSD 1.0: {:?}",
result
);
}
#[test]
fn test_accept_dead_wildcard_restriction_jd005() {
let mut schema_set = SchemaSet::new();
let xsd = r###"<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://xsdtesting" xmlns:a="http://xsdtesting">
<xs:complexType name="B">
<xs:sequence>
<xs:any namespace="##any" minOccurs="0" maxOccurs="0"/>
<xs:element name="e2"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="R">
<xs:complexContent>
<xs:restriction base="a:B">
<xs:sequence>
<xs:element name="e1" minOccurs="0" maxOccurs="0"/>
<xs:element name="e2"/>
</xs:sequence>
</xs:restriction>
</xs:complexContent>
</xs:complexType>
</xs:schema>"###;
let result = load_and_process_schema(xsd.as_bytes(), "test.xsd", &mut schema_set, None);
assert!(
result.is_ok(),
"dead wildcard restriction (Jd005 shape) should be valid: {:?}",
result
);
}
#[test]
fn test_accept_dead_imported_element_restriction_jf005() {
let mut schema_set = SchemaSet::new();
let xsd = r###"<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://xsdtesting" xmlns:x="http://xsdtesting">
<xs:complexType name="B">
<xs:sequence>
<xs:any namespace="##any" minOccurs="0" maxOccurs="0"/>
<xs:element name="e1"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="R">
<xs:complexContent>
<xs:restriction base="x:B">
<xs:sequence>
<xs:element name="e1" minOccurs="0" maxOccurs="0"/>
<xs:element name="e1"/>
</xs:sequence>
</xs:restriction>
</xs:complexContent>
</xs:complexType>
</xs:schema>"###;
let result = load_and_process_schema(xsd.as_bytes(), "test.xsd", &mut schema_set, None);
assert!(
result.is_ok(),
"dead imported-element restriction (Jf005 shape) should be valid: {:?}",
result
);
}
#[test]
fn test_reject_all_group_with_wildcard_xsd10() {
let mut schema_set = SchemaSet::new();
let xsd = r###"<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns="particles" targetNamespace="particles">
<xsd:group name="G1">
<xsd:all>
<xsd:any/>
</xsd:all>
</xsd:group>
<xsd:element name="a" type="xsd:string"/>
</xsd:schema>"###;
let result = load_and_process_schema(xsd.as_bytes(), "test.xsd", &mut schema_set, None);
assert!(
result.is_err(),
"xs:any in xs:all must be rejected in XSD 1.0"
);
match result.unwrap_err() {
crate::error::SchemaError::StructuralError { constraint, .. } => {
assert_eq!(constraint, "cos-all-limited");
}
other => panic!("Expected cos-all-limited, got {:?}", other),
}
}
#[cfg(feature = "xsd11")]
#[test]
fn test_accept_all_group_with_wildcard_xsd11() {
let mut schema_set = SchemaSet::xsd11();
let xsd = r###"<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns="particles" targetNamespace="particles">
<xsd:group name="G1">
<xsd:all>
<xsd:any/>
</xsd:all>
</xsd:group>
<xsd:element name="a" type="xsd:string"/>
</xsd:schema>"###;
let result = load_and_process_schema(xsd.as_bytes(), "test.xsd", &mut schema_set, None);
assert!(
result.is_ok(),
"xs:any in xs:all should be accepted in XSD 1.1: {:?}",
result
);
}
#[test]
fn test_reject_extension_with_all_over_choice() {
let mut schema_set = SchemaSet::new();
let xsd = r###"<?xml version="1.0"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://xsdtesting" xmlns:x="http://xsdtesting"
elementFormDefault="qualified">
<xsd:complexType name="base">
<xsd:choice>
<xsd:element name="c1"/>
<xsd:element name="c2"/>
</xsd:choice>
</xsd:complexType>
<xsd:element name="doc">
<xsd:complexType>
<xsd:complexContent>
<xsd:extension base="x:base">
<xsd:all>
<xsd:element name="a1"/>
<xsd:element name="a2"/>
</xsd:all>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
</xsd:element>
</xsd:schema>"###;
let result = load_and_process_schema(xsd.as_bytes(), "test.xsd", &mut schema_set, None);
assert!(
result.is_err(),
"extending choice with all must be rejected"
);
match result.unwrap_err() {
crate::error::SchemaError::StructuralError { constraint, .. } => {
assert_eq!(constraint, "cos-ct-extends");
}
other => panic!("Expected cos-ct-extends, got {:?}", other),
}
}
#[test]
fn test_accept_extension_with_choice_over_sequence() {
let mut schema_set = SchemaSet::new();
let xsd = r###"<?xml version="1.0"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://xsdtesting" xmlns:x="http://xsdtesting"
elementFormDefault="qualified">
<xsd:complexType name="base">
<xsd:sequence>
<xsd:element name="s1" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
<xsd:element name="doc">
<xsd:complexType>
<xsd:complexContent>
<xsd:extension base="x:base">
<xsd:choice>
<xsd:element name="c1" type="xsd:string"/>
<xsd:element name="c2" type="xsd:string"/>
</xsd:choice>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
</xsd:element>
</xsd:schema>"###;
let result = load_and_process_schema(xsd.as_bytes(), "test.xsd", &mut schema_set, None);
assert!(
result.is_ok(),
"extending sequence with choice is valid per spec: {:?}",
result.err()
);
}
#[cfg(feature = "xsd11")]
#[test]
fn test_accept_xsd11_all_over_all_extension() {
let mut schema_set = SchemaSet::xsd11();
let xsd = r###"<?xml version="1.0"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://xsdtesting" xmlns:x="http://xsdtesting"
elementFormDefault="qualified">
<xsd:complexType name="base">
<xsd:all>
<xsd:element name="a1" type="xsd:string"/>
</xsd:all>
</xsd:complexType>
<xsd:element name="doc">
<xsd:complexType>
<xsd:complexContent>
<xsd:extension base="x:base">
<xsd:all>
<xsd:element name="a2" type="xsd:string"/>
</xsd:all>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
</xsd:element>
</xsd:schema>"###;
let result = load_and_process_schema(xsd.as_bytes(), "test.xsd", &mut schema_set, None);
assert!(
result.is_ok(),
"XSD 1.1 all-over-all extension should be accepted: {:?}",
result
);
}
#[test]
fn test_reject_attribute_type_not_derived_in_restriction() {
let mut schema_set = SchemaSet::new();
let xsd = r###"<?xml version="1.0"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://xsdtesting" xmlns:t="http://xsdtesting"
attributeFormDefault="qualified" elementFormDefault="qualified">
<xsd:simpleType name="myType10">
<xsd:union memberTypes="xsd:float xsd:integer">
<xsd:simpleType>
<xsd:restriction base="xsd:boolean"/>
</xsd:simpleType>
<xsd:simpleType>
<xsd:restriction base="xsd:string">
<xsd:enumeration value="x"/>
<xsd:enumeration value="y"/>
</xsd:restriction>
</xsd:simpleType>
</xsd:union>
</xsd:simpleType>
<xsd:complexType name="CT1">
<xsd:attribute name="att1" type="xsd:integer"/>
</xsd:complexType>
<xsd:complexType name="CT2">
<xsd:complexContent>
<xsd:restriction base="t:CT1">
<xsd:attribute name="att1" type="t:myType10"/>
</xsd:restriction>
</xsd:complexContent>
</xsd:complexType>
</xsd:schema>"###;
let result = load_and_process_schema(xsd.as_bytes(), "test.xsd", &mut schema_set, None);
assert!(
result.is_err(),
"attribute type not derived from base must be rejected"
);
match result.unwrap_err() {
crate::error::SchemaError::StructuralError { constraint, .. } => {
assert_eq!(constraint, "derivation-ok-restriction");
}
other => panic!("Expected derivation-ok-restriction, got {:?}", other),
}
}
#[test]
fn test_reject_required_attribute_becomes_optional() {
let mut schema_set = SchemaSet::new();
let xsd = r###"<?xml version="1.0"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:complexType name="XML-Deviant">
<xs:sequence>
<xs:element name="e1" type="xs:integer" minOccurs="0"/>
<xs:element name="e2" type="xs:string" nillable="true"/>
</xs:sequence>
<xs:attribute name="a1" type="xs:date" use="required"/>
<xs:attribute name="a2" type="xs:string"/>
</xs:complexType>
<xs:complexType name="DareObasanjo">
<xs:complexContent>
<xs:restriction base="XML-Deviant">
<xs:sequence>
<xs:element name="e1" type="xs:integer" minOccurs="1"/>
<xs:element name="e2" type="xs:string" nillable="false"/>
</xs:sequence>
<xs:attribute name="a1" type="xs:date" use="optional"/>
<xs:attribute name="a2" type="xs:string" fixed="Microsoft Outlook"/>
</xs:restriction>
</xs:complexContent>
</xs:complexType>
</xs:schema>"###;
let result = load_and_process_schema(xsd.as_bytes(), "test.xsd", &mut schema_set, None);
assert!(
result.is_err(),
"required->optional attribute must be rejected"
);
match result.unwrap_err() {
crate::error::SchemaError::StructuralError { constraint, .. } => {
assert_eq!(constraint, "derivation-ok-restriction");
}
other => panic!("Expected derivation-ok-restriction, got {:?}", other),
}
}
#[test]
fn test_accept_restriction_inherits_namespaced_required_attribute() {
let mut schema_set = SchemaSet::new();
let xsd = r###"<?xml version="1.0"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://ns1" xmlns:ns1="http://ns1">
<xs:attribute name="id" type="xs:string"/>
<xs:complexType name="Base">
<xs:sequence>
<xs:element name="e" type="xs:string"/>
</xs:sequence>
<xs:attribute ref="ns1:id" use="required"/>
</xs:complexType>
<xs:complexType name="Derived">
<xs:complexContent>
<xs:restriction base="ns1:Base">
<xs:sequence>
<xs:element name="e" type="xs:string"/>
</xs:sequence>
</xs:restriction>
</xs:complexContent>
</xs:complexType>
</xs:schema>"###;
let result = load_and_process_schema(xsd.as_bytes(), "test.xsd", &mut schema_set, None);
assert!(
result.is_ok(),
"omitting a base required attribute inherits it unchanged, \
which is a valid restriction (spec §3.4.2.3 mapping + \
derivation-ok-restriction clause 3): {:?}",
result.err(),
);
}
#[test]
fn test_reject_simple_content_restriction_with_list_over_atomic() {
let mut schema_set = SchemaSet::new();
let xsd = r###"<?xml version="1.0"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:complexType name="B1">
<xs:simpleContent>
<xs:extension base="xs:decimal">
<xs:attribute name="foo"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
<xs:complexType name="C2">
<xs:simpleContent>
<xs:restriction base="B1">
<xs:simpleType>
<xs:list itemType="xs:int"/>
</xs:simpleType>
</xs:restriction>
</xs:simpleContent>
</xs:complexType>
</xs:schema>"###;
let result = load_and_process_schema(xsd.as_bytes(), "test.xsd", &mut schema_set, None);
assert!(
result.is_err(),
"list type restricting atomic simple content must be rejected"
);
match result.unwrap_err() {
crate::error::SchemaError::StructuralError { constraint, .. } => {
assert_eq!(constraint, "derivation-ok-restriction");
}
other => panic!("Expected derivation-ok-restriction, got {:?}", other),
}
}
#[test]
fn test_accept_simple_content_list_over_any_simple_type() {
let mut schema_set = SchemaSet::new();
let xsd = r###"<?xml version="1.0"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:complexType name="B1">
<xs:simpleContent>
<xs:extension base="xs:anySimpleType">
<xs:attribute name="foo"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
<xs:complexType name="C2">
<xs:simpleContent>
<xs:restriction base="B1">
<xs:simpleType>
<xs:list itemType="xs:int"/>
</xs:simpleType>
</xs:restriction>
</xs:simpleContent>
</xs:complexType>
</xs:schema>"###;
let result = load_and_process_schema(xsd.as_bytes(), "test.xsd", &mut schema_set, None);
assert!(
result.is_ok(),
"list restricting anySimpleType should be accepted: {:?}",
result
);
}
#[test]
fn test_accept_simple_content_union_over_any_simple_type() {
let mut schema_set = SchemaSet::new();
let xsd = r###"<?xml version="1.0"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:complexType name="B1">
<xs:simpleContent>
<xs:extension base="xs:anySimpleType">
<xs:attribute name="foo"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
<xs:complexType name="C2">
<xs:simpleContent>
<xs:restriction base="B1">
<xs:simpleType>
<xs:union memberTypes="xs:int xs:string"/>
</xs:simpleType>
</xs:restriction>
</xs:simpleContent>
</xs:complexType>
</xs:schema>"###;
let result = load_and_process_schema(xsd.as_bytes(), "test.xsd", &mut schema_set, None);
assert!(
result.is_ok(),
"union restricting anySimpleType should be accepted: {:?}",
result
);
}
#[cfg(feature = "xsd11")]
#[test]
fn test_accept_xsd11_choice_extension() {
let mut schema_set = SchemaSet::xsd11();
let xsd = r###"<?xml version="1.0"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://xsdtesting" xmlns:x="http://xsdtesting"
elementFormDefault="qualified">
<xsd:complexType name="base">
<xsd:choice>
<xsd:any namespace="##local ##targetNamespace foo" maxOccurs="3"/>
</xsd:choice>
</xsd:complexType>
<xsd:element name="doc">
<xsd:complexType>
<xsd:complexContent>
<xsd:extension base="x:base">
<xsd:choice>
<xsd:element name="c1"/>
<xsd:element name="c2"/>
</xsd:choice>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
</xsd:element>
</xsd:schema>"###;
let result = load_and_process_schema(xsd.as_bytes(), "test.xsd", &mut schema_set, None);
assert!(
result.is_ok(),
"XSD 1.1: choice extension over non-empty base should be accepted: {:?}",
result
);
}
#[cfg(feature = "xsd11")]
#[test]
fn test_reject_xsd11_complexcontent_over_simplecontent() {
let mut schema_set = SchemaSet::xsd11();
let xsd = r###"<?xml version="1.0"?>
<xs:schema xmlns="http://schema1" xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://schema1">
<xs:complexType name="Type1">
<xs:simpleContent>
<xs:extension base="xs:string">
<xs:attribute name="Field1" type="xs:string"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
<xs:complexType name="Type2">
<xs:complexContent>
<xs:extension base="Type1">
<xs:attribute name="Field2" type="xs:string"/>
</xs:extension>
</xs:complexContent>
</xs:complexType>
</xs:schema>"###;
let result = load_and_process_schema(xsd.as_bytes(), "test.xsd", &mut schema_set, None);
assert!(
result.is_err(),
"XSD 1.1: complexContent extension over simpleContent must be rejected"
);
match result.unwrap_err() {
crate::error::SchemaError::StructuralError { constraint, .. } => {
assert_eq!(constraint, "cos-ct-extends");
}
other => panic!("Expected cos-ct-extends, got {:?}", other),
}
}
#[test]
fn test_accept_xsd10_complexcontent_over_simplecontent() {
let mut schema_set = SchemaSet::new();
let xsd = r###"<?xml version="1.0"?>
<xs:schema xmlns="http://schema1" xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://schema1">
<xs:complexType name="Type1">
<xs:simpleContent>
<xs:extension base="xs:string">
<xs:attribute name="Field1" type="xs:string"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
<xs:complexType name="Type2">
<xs:complexContent>
<xs:extension base="Type1">
<xs:attribute name="Field2" type="xs:string"/>
</xs:extension>
</xs:complexContent>
</xs:complexType>
</xs:schema>"###;
let result = load_and_process_schema(xsd.as_bytes(), "test.xsd", &mut schema_set, None);
assert!(
result.is_ok(),
"XSD 1.0: attribute-only complexContent extension over simpleContent should be accepted: {:?}",
result
);
}
#[cfg(feature = "xsd11")]
#[test]
fn test_accept_xsd11_intensional_restriction_hb008() {
let mut schema_set = SchemaSet::xsd11();
let xsd = r###"<?xml version="1.0"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://xsdtesting" xmlns:x="http://xsdtesting"
elementFormDefault="qualified">
<xsd:complexType name="base">
<xsd:choice>
<xsd:element name="e1" minOccurs="1" maxOccurs="3"/>
<xsd:sequence maxOccurs="2">
<xsd:element name="e2" minOccurs="1" maxOccurs="3"/>
<xsd:element name="e3" minOccurs="0" maxOccurs="3"/>
<xsd:element name="e4" minOccurs="0" maxOccurs="3"/>
</xsd:sequence>
</xsd:choice>
</xsd:complexType>
<xsd:element name="doc">
<xsd:complexType>
<xsd:complexContent>
<xsd:restriction base="x:base">
<xsd:choice>
<xsd:element name="e1" minOccurs="1" maxOccurs="2"/>
<xsd:sequence maxOccurs="2">
<xsd:element name="e2"/>
<xsd:choice>
<xsd:element name="e3" minOccurs="2" maxOccurs="3"/>
<xsd:element name="e4" minOccurs="1" maxOccurs="3"/>
</xsd:choice>
</xsd:sequence>
</xsd:choice>
</xsd:restriction>
</xsd:complexContent>
</xsd:complexType>
</xsd:element>
</xsd:schema>"###;
let result = load_and_process_schema(xsd.as_bytes(), "test.xsd", &mut schema_set, None);
assert!(
result.is_ok(),
"XSD 1.1: choice-in-derived-sequence restriction (Hb008) should be accepted: {:?}",
result
);
}
#[cfg(feature = "xsd11")]
#[test]
fn test_accept_xsd11_intensional_restriction_hb011() {
let mut schema_set = SchemaSet::xsd11();
let xsd = r###"<?xml version="1.0"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://xsdtesting" xmlns:x="http://xsdtesting"
elementFormDefault="qualified">
<xsd:complexType name="base">
<xsd:choice minOccurs="2" maxOccurs="unbounded">
<xsd:element name="e1" minOccurs="0" maxOccurs="10"/>
<xsd:element name="e2" minOccurs="0"/>
<xsd:element name="e3" minOccurs="0"/>
</xsd:choice>
</xsd:complexType>
<xsd:element name="doc">
<xsd:complexType>
<xsd:complexContent>
<xsd:restriction base="x:base">
<xsd:choice minOccurs="2" maxOccurs="unbounded">
<xsd:sequence maxOccurs="2">
<xsd:element name="e1" maxOccurs="2"/>
</xsd:sequence>
<xsd:element name="e2"/>
<xsd:element name="e3" minOccurs="1"/>
</xsd:choice>
</xsd:restriction>
</xsd:complexContent>
</xsd:complexType>
</xsd:element>
</xsd:schema>"###;
let result = load_and_process_schema(xsd.as_bytes(), "test.xsd", &mut schema_set, None);
assert!(
result.is_ok(),
"XSD 1.1: single-child sequence folding (Hb011) should be accepted: {:?}",
result
);
}
#[cfg(feature = "xsd11")]
#[test]
fn test_accept_xsd11_intensional_restriction_z023() {
let mut schema_set = SchemaSet::xsd11();
let xsd = r###"<?xml version="1.0"?>
<xsd:schema targetNamespace="http://myuri" xmlns="http://myuri"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:element name="A" type="xsd:string"/>
<xsd:element name="B" type="xsd:string"/>
<xsd:complexType name="eleType">
<xsd:sequence>
<xsd:element ref="A"/>
<xsd:element ref="B"/>
<xsd:choice>
<xsd:sequence>
<xsd:element name="AAA" minOccurs="0" maxOccurs="unbounded"/>
<xsd:element name="BBB" minOccurs="0" maxOccurs="unbounded"/>
<xsd:element name="CCC" minOccurs="0" maxOccurs="unbounded"/>
</xsd:sequence>
<xsd:sequence>
<xsd:element name="AAAA" minOccurs="0" maxOccurs="unbounded"/>
<xsd:element name="BBBB" minOccurs="0" maxOccurs="unbounded"/>
<xsd:element name="CCCC" minOccurs="0" maxOccurs="unbounded"/>
</xsd:sequence>
</xsd:choice>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="eleType2">
<xsd:complexContent>
<xsd:restriction base="eleType">
<xsd:sequence>
<xsd:element ref="A"/>
<xsd:element ref="B"/>
<xsd:choice>
<xsd:sequence>
<xsd:element name="AAA" minOccurs="0" maxOccurs="unbounded"/>
<xsd:element name="BBB" minOccurs="0" maxOccurs="unbounded"/>
<xsd:element name="CCC" minOccurs="0" maxOccurs="unbounded"/>
</xsd:sequence>
</xsd:choice>
</xsd:sequence>
</xsd:restriction>
</xsd:complexContent>
</xsd:complexType>
</xsd:schema>"###;
let result = load_and_process_schema(xsd.as_bytes(), "test.xsd", &mut schema_set, None);
assert!(
result.is_ok(),
"XSD 1.1: single-branch choice restriction (Z023) should be accepted: {:?}",
result
);
}
#[cfg(feature = "xsd11")]
#[test]
fn test_accept_xsd11_intensional_restriction_z024() {
let mut schema_set = SchemaSet::xsd11();
let xsd = r###"<?xml version="1.0"?>
<xsd:schema targetNamespace="http://myuri" xmlns="http://myuri"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:element name="A" type="xsd:string"/>
<xsd:element name="B" type="xsd:string"/>
<xsd:group name="G1">
<xsd:sequence>
<xsd:element name="AA" minOccurs="0" maxOccurs="unbounded"/>
<xsd:element name="BB" minOccurs="0" maxOccurs="unbounded"/>
</xsd:sequence>
</xsd:group>
<xsd:group name="G2">
<xsd:sequence>
<xsd:element name="AAA" minOccurs="0" maxOccurs="unbounded"/>
<xsd:element name="BBB" minOccurs="0" maxOccurs="unbounded"/>
</xsd:sequence>
</xsd:group>
<xsd:complexType name="eleType">
<xsd:sequence>
<xsd:element ref="A"/>
<xsd:element ref="B"/>
<xsd:choice>
<xsd:group ref="G1" minOccurs="0" maxOccurs="unbounded"/>
<xsd:group ref="G2" minOccurs="0" maxOccurs="unbounded"/>
</xsd:choice>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="eleType2">
<xsd:complexContent>
<xsd:restriction base="eleType">
<xsd:sequence>
<xsd:element ref="A"/>
<xsd:element ref="B"/>
<xsd:choice>
<xsd:group ref="G1" minOccurs="0"/>
</xsd:choice>
</xsd:sequence>
</xsd:restriction>
</xsd:complexContent>
</xsd:complexType>
</xsd:schema>"###;
let result = load_and_process_schema(xsd.as_bytes(), "test.xsd", &mut schema_set, None);
assert!(
result.is_ok(),
"XSD 1.1: single group-ref choice restriction (Z024) should be accepted: {:?}",
result
);
}
#[cfg(feature = "xsd11")]
#[test]
fn test_accept_xsd11_intensional_restriction_z028() {
let mut schema_set = SchemaSet::xsd11();
let xsd = r###"<?xml version="1.0"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element abstract="true" name="aba" type="xs:string"/>
<xs:element name="a" substitutionGroup="aba" type="xs:string"/>
<xs:element name="d" type="xs:anyURI"/>
<xs:group name="abs">
<xs:choice>
<xs:element ref="aba"/>
</xs:choice>
</xs:group>
<xs:complexType name="test">
<xs:sequence>
<xs:group maxOccurs="unbounded" minOccurs="0" ref="abs"/>
<xs:element minOccurs="0" ref="d"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="test4">
<xs:complexContent>
<xs:restriction base="test">
<xs:sequence>
<xs:sequence minOccurs="1" maxOccurs="1">
<xs:element ref="a"/>
</xs:sequence>
<xs:element ref="d"/>
</xs:sequence>
</xs:restriction>
</xs:complexContent>
</xs:complexType>
</xs:schema>"###;
let result = load_and_process_schema(xsd.as_bytes(), "test.xsd", &mut schema_set, None);
assert!(
result.is_ok(),
"XSD 1.1: substitution group sequence restriction (Z028) should be accepted: {:?}",
result
);
}