use wasm4pm::xes_format::validate_and_parse_xes;
#[test]
fn test_valid_xes_parses_successfully() {
let content = include_str!("fixtures/conformance/fixture_a_perfect.xes");
let result = validate_and_parse_xes(content);
assert!(
result.is_ok(),
"Valid XES should parse without error. Got: {:?}",
result
);
let log = result.unwrap();
assert_eq!(log.traces.len(), 1, "Expected 1 trace");
assert_eq!(log.traces[0].events.len(), 2, "Expected 2 events");
}
#[test]
fn test_unclosed_trace_tag_rejected() {
let content = include_str!("fixtures/dirty_data/unclosed_trace.xes");
let result = validate_and_parse_xes(content);
assert!(result.is_err(), "Unclosed <trace> should be rejected");
let err = result.unwrap_err();
assert!(
err.contains("Unclosed") || err.contains("trace"),
"Error message should mention unclosed trace. Got: {}",
err
);
assert!(
err.contains("Line"),
"Error message should include line number. Got: {}",
err
);
}
#[test]
fn test_unclosed_event_tag_rejected() {
let content = include_str!("fixtures/dirty_data/unclosed_event.xes");
let result = validate_and_parse_xes(content);
assert!(result.is_err(), "Unclosed <event> should be rejected");
let err = result.unwrap_err();
assert!(
err.contains("Mismatched") || err.contains("Unclosed"),
"Error message should indicate tag mismatch. Got: {}",
err
);
assert!(
err.contains("Line"),
"Error message should include line number. Got: {}",
err
);
}
#[test]
fn test_mismatched_tags_rejected() {
let content = include_str!("fixtures/dirty_data/mismatched_tags.xes");
let result = validate_and_parse_xes(content);
assert!(result.is_err(), "Mismatched tags should be rejected");
let err = result.unwrap_err();
assert!(
err.contains("Mismatched"),
"Error message should mention mismatched tags. Got: {}",
err
);
assert!(
err.contains("event") || err.contains("trace"),
"Error message should identify the conflicting tags. Got: {}",
err
);
}
#[test]
fn test_string_tag_not_self_closing_rejected() {
let content = include_str!("fixtures/dirty_data/invalid_string_not_closed.xes");
let result = validate_and_parse_xes(content);
assert!(
result.is_err(),
"Non-self-closing <string> tag should be rejected"
);
let err = result.unwrap_err();
assert!(
err.contains("string") || err.contains("self-closing"),
"Error message should reference string tag or self-closing requirement. Got: {}",
err
);
}
#[test]
fn test_missing_required_attribute_rejected() {
let content = include_str!("fixtures/dirty_data/missing_attribute.xes");
let result = validate_and_parse_xes(content);
assert!(
result.is_err(),
"Missing 'value' attribute should be rejected"
);
let err = result.unwrap_err();
assert!(
err.contains("string") && (err.contains("missing") || err.contains("required")),
"Error message should indicate missing attribute in string tag. Got: {}",
err
);
}
#[test]
fn test_unexpected_closing_tag_rejected() {
let content = r#"<?xml version="1.0" encoding="UTF-8"?>
<log xmlns="http://www.xes-standard.org/">
<trace>
<string key="concept:name" value="case1"/>
</event>
</trace>
</log>"#;
let result = validate_and_parse_xes(content);
assert!(
result.is_err(),
"Unexpected closing </event> should be rejected"
);
let err = result.unwrap_err();
assert!(
err.contains("Mismatched") || err.contains("Unexpected") || err.contains("matching"),
"Error message should indicate mismatched/unexpected tag. Got: {}",
err
);
}
#[test]
fn test_error_message_includes_line_number() {
let content = r#"<?xml version="1.0" encoding="UTF-8"?>
<log xmlns="http://www.xes-standard.org/">
<trace>
<string key="concept:name" value="case1"/>
<event>
<string key="concept:name" value="A"/>
"#;
let result = validate_and_parse_xes(content);
assert!(result.is_err(), "Unclosed tag should be rejected");
let err = result.unwrap_err();
assert!(
err.contains("Line"),
"Error message must include line number. Got: {}",
err
);
let line_part = err.split("Line").nth(1).unwrap_or("");
let line_str = line_part.split(':').next().unwrap_or("");
let line_num: usize = line_str
.trim()
.parse()
.expect("Error message should contain parseable line number");
assert!(
line_num >= 5,
"Line number should be >= 5, got: {}",
line_num
);
}
#[test]
fn test_valid_xes_multiple_traces_parses() {
let content = r#"<?xml version="1.0" encoding="UTF-8"?>
<log xmlns="http://www.xes-standard.org/">
<trace>
<string key="concept:name" value="case1"/>
<event>
<string key="concept:name" value="A"/>
<date key="time:timestamp" value="2024-01-01T09:00:00Z"/>
</event>
</trace>
<trace>
<string key="concept:name" value="case2"/>
<event>
<string key="concept:name" value="B"/>
<date key="time:timestamp" value="2024-01-01T10:00:00Z"/>
</event>
</trace>
</log>"#;
let result = validate_and_parse_xes(content);
assert!(
result.is_ok(),
"Valid XES with multiple traces should parse"
);
let log = result.unwrap();
assert_eq!(log.traces.len(), 2, "Expected 2 traces");
assert_eq!(log.traces[0].events.len(), 1, "First trace has 1 event");
assert_eq!(log.traces[1].events.len(), 1, "Second trace has 1 event");
}
#[test]
fn test_invalid_float_value_rejected() {
let content = r#"<?xml version="1.0" encoding="UTF-8"?>
<log xmlns="http://www.xes-standard.org/">
<trace>
<string key="concept:name" value="case1"/>
<event>
<string key="concept:name" value="A"/>
<float key="duration" value="not_a_number"/>
</event>
</trace>
</log>"#;
let result = validate_and_parse_xes(content);
assert!(result.is_err(), "Invalid float value should be rejected");
let err = result.unwrap_err();
assert!(
err.contains("float") && err.contains("invalid"),
"Error should indicate invalid float value. Got: {}",
err
);
}
#[test]
fn test_invalid_int_value_rejected() {
let content = r#"<?xml version="1.0" encoding="UTF-8"?>
<log xmlns="http://www.xes-standard.org/">
<trace>
<string key="concept:name" value="case1"/>
<event>
<string key="concept:name" value="A"/>
<int key="priority" value="not_an_integer"/>
</event>
</trace>
</log>"#;
let result = validate_and_parse_xes(content);
assert!(result.is_err(), "Invalid int value should be rejected");
let err = result.unwrap_err();
assert!(
err.contains("int") && err.contains("invalid"),
"Error should indicate invalid int value. Got: {}",
err
);
}