use fastxml::error::Error;
use fastxml::schema::error::SchemaError;
use fastxml::schema::xsd::parse_xsd;
mod facet_schema_errors {
use super::*;
#[test]
fn test_fraction_digits_greater_than_total_digits() {
let xsd = r#"<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:simpleType name="BadDecimal">
<xs:restriction base="xs:decimal">
<xs:totalDigits value="3"/>
<xs:fractionDigits value="5"/>
</xs:restriction>
</xs:simpleType>
</xs:schema>"#;
let result = parse_xsd(xsd.as_bytes());
assert!(
matches!(
&result,
Err(Error::Schema(
SchemaError::FractionDigitsGreaterThanTotalDigits {
fraction_digits: 5,
total_digits: 3
}
))
),
"Expected FractionDigitsGreaterThanTotalDigits error, got: {:?}",
result
);
}
#[test]
fn test_valid_total_and_fraction_digits() {
let xsd = r#"<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:simpleType name="ValidDecimal">
<xs:restriction base="xs:decimal">
<xs:totalDigits value="5"/>
<xs:fractionDigits value="2"/>
</xs:restriction>
</xs:simpleType>
</xs:schema>"#;
let result = parse_xsd(xsd.as_bytes());
assert!(
result.is_ok(),
"Valid totalDigits/fractionDigits should parse successfully, got: {:?}",
result
);
}
#[test]
fn test_equal_total_and_fraction_digits() {
let xsd = r#"<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:simpleType name="EqualDigits">
<xs:restriction base="xs:decimal">
<xs:totalDigits value="3"/>
<xs:fractionDigits value="3"/>
</xs:restriction>
</xs:simpleType>
</xs:schema>"#;
let result = parse_xsd(xsd.as_bytes());
assert!(
result.is_ok(),
"Equal totalDigits and fractionDigits should be valid, got: {:?}",
result
);
}
}
mod occurrence_errors {
use super::*;
#[test]
fn test_invalid_occurs_non_numeric() {
let xsd = r#"<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="test">
<xs:complexType>
<xs:sequence>
<xs:element name="child" minOccurs="abc"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>"#;
let result = parse_xsd(xsd.as_bytes());
assert!(
matches!(
&result,
Err(Error::Schema(SchemaError::InvalidOccurs { value })) if value.contains("abc")
),
"Expected InvalidOccurs error for non-numeric value, got: {:?}",
result
);
}
#[test]
fn test_max_occurs_unbounded() {
let xsd = r#"<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="test">
<xs:complexType>
<xs:sequence>
<xs:element name="items" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>"#;
let result = parse_xsd(xsd.as_bytes());
assert!(
result.is_ok(),
"maxOccurs='unbounded' should be valid, got: {:?}",
result
);
}
#[test]
fn test_min_occurs_zero() {
let xsd = r#"<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="test">
<xs:complexType>
<xs:sequence>
<xs:element name="optional" minOccurs="0" maxOccurs="1"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>"#;
let result = parse_xsd(xsd.as_bytes());
assert!(
result.is_ok(),
"minOccurs='0' should be valid, got: {:?}",
result
);
}
}
mod length_facet_errors {
use super::*;
#[test]
fn test_length_with_min_length() {
let xsd = r#"<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:simpleType name="Weird">
<xs:restriction base="xs:string">
<xs:length value="5"/>
<xs:minLength value="3"/>
</xs:restriction>
</xs:simpleType>
</xs:schema>"#;
let result = parse_xsd(xsd.as_bytes());
if result.is_ok() {
} else {
}
}
#[test]
fn test_zero_length() {
let xsd = r#"<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:simpleType name="Empty">
<xs:restriction base="xs:string">
<xs:length value="0"/>
</xs:restriction>
</xs:simpleType>
</xs:schema>"#;
let result = parse_xsd(xsd.as_bytes());
assert!(
result.is_ok(),
"length='0' should be valid, got: {:?}",
result
);
}
#[test]
fn test_very_large_length() {
let xsd = r#"<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:simpleType name="VeryLong">
<xs:restriction base="xs:string">
<xs:maxLength value="999999999"/>
</xs:restriction>
</xs:simpleType>
</xs:schema>"#;
let result = parse_xsd(xsd.as_bytes());
assert!(
result.is_ok(),
"Large maxLength should be valid, got: {:?}",
result
);
}
}
mod complex_type_errors {
use super::*;
#[test]
fn test_missing_base_type() {
let xsd = r#"<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:complexType name="Derived">
<xs:complexContent>
<xs:extension base="NonExistentType"/>
</xs:complexContent>
</xs:complexType>
</xs:schema>"#;
let result = parse_xsd(xsd.as_bytes());
let _ = result;
}
#[test]
fn test_self_referencing_type() {
let xsd = r#"<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:complexType name="Node">
<xs:sequence>
<xs:element name="value" type="xs:string"/>
<xs:element name="children" type="Node" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
</xs:schema>"#;
let result = parse_xsd(xsd.as_bytes());
assert!(
result.is_ok(),
"Self-referencing types should be valid (tree structures), got: {:?}",
result
);
}
#[test]
fn test_empty_sequence() {
let xsd = r#"<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:complexType name="Empty">
<xs:sequence/>
</xs:complexType>
</xs:schema>"#;
let result = parse_xsd(xsd.as_bytes());
assert!(
result.is_ok(),
"Empty sequence should be valid, got: {:?}",
result
);
}
#[test]
fn test_nested_compositors() {
let xsd = r#"<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:complexType name="Nested">
<xs:sequence>
<xs:element name="a" type="xs:string"/>
<xs:choice>
<xs:element name="b" type="xs:string"/>
<xs:element name="c" type="xs:string"/>
</xs:choice>
<xs:element name="d" type="xs:string"/>
</xs:sequence>
</xs:complexType>
</xs:schema>"#;
let result = parse_xsd(xsd.as_bytes());
assert!(
result.is_ok(),
"Nested compositors should be valid, got: {:?}",
result
);
}
}
mod attribute_errors {
use super::*;
#[test]
fn test_required_attribute() {
let xsd = r#"<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:complexType name="WithRequired">
<xs:simpleContent>
<xs:extension base="xs:string">
<xs:attribute name="id" type="xs:string" use="required"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:schema>"#;
let result = parse_xsd(xsd.as_bytes());
assert!(
result.is_ok(),
"Required attribute should be valid, got: {:?}",
result
);
}
#[test]
fn test_attribute_with_default() {
let xsd = r#"<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:complexType name="WithDefault">
<xs:simpleContent>
<xs:extension base="xs:string">
<xs:attribute name="lang" type="xs:string" default="en"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:schema>"#;
let result = parse_xsd(xsd.as_bytes());
assert!(
result.is_ok(),
"Attribute with default should be valid, got: {:?}",
result
);
}
#[test]
fn test_attribute_with_fixed() {
let xsd = r#"<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:complexType name="WithFixed">
<xs:simpleContent>
<xs:extension base="xs:string">
<xs:attribute name="version" type="xs:string" fixed="1.0"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:schema>"#;
let result = parse_xsd(xsd.as_bytes());
assert!(
result.is_ok(),
"Attribute with fixed value should be valid, got: {:?}",
result
);
}
}
mod enumeration_errors {
use super::*;
#[test]
fn test_empty_enumeration() {
let xsd = r#"<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:simpleType name="NoValues">
<xs:restriction base="xs:string">
</xs:restriction>
</xs:simpleType>
</xs:schema>"#;
let result = parse_xsd(xsd.as_bytes());
assert!(
result.is_ok(),
"Empty restriction should be valid, got: {:?}",
result
);
}
#[test]
fn test_single_enumeration_value() {
let xsd = r#"<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:simpleType name="SingleValue">
<xs:restriction base="xs:string">
<xs:enumeration value="only"/>
</xs:restriction>
</xs:simpleType>
</xs:schema>"#;
let result = parse_xsd(xsd.as_bytes());
assert!(
result.is_ok(),
"Single enumeration value should be valid, got: {:?}",
result
);
}
#[test]
fn test_duplicate_enumeration_values() {
let xsd = r#"<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:simpleType name="Duplicates">
<xs:restriction base="xs:string">
<xs:enumeration value="a"/>
<xs:enumeration value="b"/>
<xs:enumeration value="a"/>
</xs:restriction>
</xs:simpleType>
</xs:schema>"#;
let result = parse_xsd(xsd.as_bytes());
let _ = result;
}
}
mod namespace_errors {
use super::*;
#[test]
fn test_target_namespace_with_element_form() {
let xsd = r#"<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://example.com/test"
xmlns:tns="http://example.com/test"
elementFormDefault="qualified">
<xs:element name="root" type="xs:string"/>
</xs:schema>"#;
let result = parse_xsd(xsd.as_bytes());
assert!(
result.is_ok(),
"Schema with targetNamespace should be valid, got: {:?}",
result
);
if let Ok(schema) = result {
assert_eq!(
schema.target_namespace,
Some("http://example.com/test".to_string())
);
}
}
#[test]
fn test_no_target_namespace() {
let xsd = r#"<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="root" type="xs:string"/>
</xs:schema>"#;
let result = parse_xsd(xsd.as_bytes());
assert!(result.is_ok());
if let Ok(schema) = result {
assert!(
schema.target_namespace.is_none(),
"Schema without targetNamespace should have None"
);
}
}
}
mod pattern_schema_errors {
use super::*;
#[test]
fn test_valid_pattern_in_schema() {
let xsd = r#"<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:simpleType name="PhoneNumber">
<xs:restriction base="xs:string">
<xs:pattern value="\d{3}-\d{4}"/>
</xs:restriction>
</xs:simpleType>
</xs:schema>"#;
let result = parse_xsd(xsd.as_bytes());
assert!(
result.is_ok(),
"Valid pattern should be accepted, got: {:?}",
result
);
}
#[test]
fn test_multiple_patterns_in_schema() {
let xsd = r#"<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:simpleType name="Code">
<xs:restriction base="xs:string">
<xs:pattern value="[A-Z]+"/>
<xs:pattern value=".{3,5}"/>
</xs:restriction>
</xs:simpleType>
</xs:schema>"#;
let result = parse_xsd(xsd.as_bytes());
assert!(
result.is_ok(),
"Multiple patterns should be accepted, got: {:?}",
result
);
}
}
mod any_element_tests {
use super::*;
#[test]
fn test_xs_any_basic() {
let xsd = r#"<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:complexType name="Extensible">
<xs:sequence>
<xs:element name="required" type="xs:string"/>
<xs:any minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
</xs:schema>"#;
let result = parse_xsd(xsd.as_bytes());
assert!(result.is_ok(), "xs:any should be valid, got: {:?}", result);
}
#[test]
fn test_xs_any_with_target_namespace() {
let xsd = r#"<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://example.com/test">
<xs:complexType name="Extensible">
<xs:simpleContent>
<xs:extension base="xs:string">
<xs:anyAttribute/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:schema>"#;
let result = parse_xsd(xsd.as_bytes());
assert!(
result.is_ok(),
"xs:anyAttribute should be valid, got: {:?}",
result
);
}
#[test]
fn test_xs_any_with_process_contents() {
let xsd = r#"<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:complexType name="Lax">
<xs:sequence>
<xs:any processContents="lax" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
</xs:schema>"#;
let result = parse_xsd(xsd.as_bytes());
assert!(
result.is_ok(),
"xs:any with processContents should be valid, got: {:?}",
result
);
}
#[test]
fn test_xs_any_with_specific_namespace() {
let xsd = r#"<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:complexType name="WithNamespace">
<xs:sequence>
<xs:any namespace="http://example.com/ext" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
</xs:schema>"#;
let result = parse_xsd(xsd.as_bytes());
assert!(
result.is_ok(),
"xs:any with specific namespace should be valid, got: {:?}",
result
);
}
}