use super::*;
#[test]
fn parse_observations_title_case_tags() {
let xml = r#"
<Observation>
<type>decision</type>
<title>Title case tag</title>
</Observation>
"#;
let parsed = parse_observations(xml);
assert_eq!(
parsed.len(),
1,
"Observation with title-case tags must be parsed"
);
assert_eq!(parsed[0].title.as_deref(), Some("Title case tag"));
}
#[test]
fn parse_observations_upper_case_tags() {
let xml = r#"
<OBSERVATION>
<type>decision</type>
<title>Upper case tag</title>
</OBSERVATION>
"#;
let parsed = parse_observations(xml);
assert_eq!(
parsed.len(),
1,
"OBSERVATION with all-caps tags must be parsed"
);
assert_eq!(parsed[0].title.as_deref(), Some("Upper case tag"));
}
#[test]
fn parse_observations_mixed_case_open_and_close() {
let xml = r#"<Observation><type>bugfix</type><title>Mixed close</title></observation>"#;
let parsed = parse_observations(xml);
assert_eq!(parsed.len(), 1, "Mixed-case open/close tags must be parsed");
assert_eq!(parsed[0].obs_type, "bugfix");
}
#[test]
fn parse_observations_multiple_mixed_case() {
let xml = r#"
<OBSERVATION>
<type>decision</type>
<title>First</title>
</OBSERVATION>
<observation>
<type>bugfix</type>
<title>Second</title>
</observation>
<Observation>
<type>discovery</type>
<title>Third</title>
</Observation>
"#;
let parsed = parse_observations(xml);
assert_eq!(
parsed.len(),
3,
"All three mixed-case observation blocks must be parsed"
);
assert_eq!(parsed[0].title.as_deref(), Some("First"));
assert_eq!(parsed[1].title.as_deref(), Some("Second"));
assert_eq!(parsed[2].title.as_deref(), Some("Third"));
}
#[test]
fn extract_field_scans_from_open_tag() {
let body = "</title><title>ok</title>";
assert_eq!(extract_field(body, "title").as_deref(), Some("ok"));
}
#[test]
fn xml_escape_escapes_angle_and_amp() {
assert_eq!(xml_escape_text(r#"a<&>"'"#), "a<&>"'");
}
#[test]
fn parse_observations_reads_and_clamps_confidence() {
let xml = r#"
<observation>
<type>decision</type>
<title>Valid</title>
<confidence>0.42</confidence>
</observation>
<observation>
<type>decision</type>
<title>Above range</title>
<confidence>3.5</confidence>
</observation>
<observation>
<type>decision</type>
<title>Below range</title>
<confidence>-0.2</confidence>
</observation>
<observation>
<type>decision</type>
<title>Invalid</title>
<confidence>high</confidence>
</observation>
<observation>
<type>decision</type>
<title>Missing</title>
</observation>
"#;
let parsed = parse_observations(xml);
assert_eq!(parsed.len(), 5);
assert_eq!(parsed[0].confidence, Some(0.42));
assert_eq!(parsed[1].confidence, Some(1.0));
assert_eq!(parsed[2].confidence, Some(0.0));
assert_eq!(parsed[3].confidence, None);
assert_eq!(parsed[4].confidence, None);
}
#[test]
fn parse_observations_defaults_invalid_type_and_filters_type_concept() {
let xml = r#"
<observation>
<type>unknown</type>
<title> Planning note </title>
<facts>
<fact>first</fact>
</facts>
<concepts>
<concept>discovery</concept>
<concept>rust</concept>
</concepts>
<files_read>
<file>src/lib.rs</file>
</files_read>
<files_modified>
<file>src/main.rs</file>
</files_modified>
</observation>
"#;
let parsed = parse_observations(xml);
assert_eq!(parsed.len(), 1);
assert_eq!(parsed[0].obs_type, "discovery");
assert_eq!(parsed[0].title.as_deref(), Some("Planning note"));
assert_eq!(parsed[0].facts, vec!["first"]);
assert_eq!(parsed[0].concepts, vec!["rust"]);
assert_eq!(parsed[0].files_read, vec!["src/lib.rs"]);
assert_eq!(parsed[0].files_modified, vec!["src/main.rs"]);
}