" }
+ ]
+ }
+ ]
+ }
+ });
+ let original = parse_original_message(&msg).unwrap();
+ // body_html must be the actual HTML, not None
+ assert!(
+ original.body_html.is_some(),
+ "HTML body with Content-ID must be preserved through parse_original_message"
+ );
+ // resolve_html_body must return the HTML, not a
-converted plain text fallback
+ let resolved = resolve_html_body(&original);
+ assert!(
+ resolved.contains("blockquote"),
+ "resolve_html_body must use the HTML body, not plain-text fallback"
+ );
+ assert!(
+ !resolved.contains("
"),
+ "resolve_html_body must not fall back to
-converted plain text"
+ );
+ // Inline signature image must still be collected as a part
+ assert_eq!(original.parts.len(), 1);
+ assert_eq!(original.parts[0].attachment_id, "SIG_IMG");
+ }
+
+ #[test]
+ fn test_extract_payload_contents_multiple_html_leaves_first_wins() {
+ // When multiple text/html parts are eligible (e.g. one with Content-ID,
+ // one without), the walker takes the first one encountered in DFS order.
+ // This documents current behavior — it is a heuristic, not a guarantee
+ // of multipart/related root-part semantics (which would require honoring
+ // the start= parameter).
+ let first_html = base64url("First HTML (with Content-ID)
");
+ let second_html = base64url("Second HTML (no Content-ID)
");
+ let payload = json!({
+ "mimeType": "multipart/related",
+ "parts": [
+ {
+ "mimeType": "multipart/alternative",
+ "parts": [
+ {
+ "mimeType": "text/html",
+ "body": { "data": first_html, "size": 34 },
+ "headers": [
+ { "name": "Content-ID", "value": "" }
+ ]
+ },
+ {
+ "mimeType": "text/html",
+ "body": { "data": second_html, "size": 37 },
+ "headers": []
+ }
+ ]
+ }
+ ]
+ });
+ let contents = extract_payload_contents(&payload);
+ assert!(
+ contents.body_html.is_some(),
+ "at least one text/html part should be recognized as body"
+ );
+ assert!(
+ contents
+ .body_html
+ .as_deref()
+ .unwrap()
+ .contains("First HTML"),
+ "First eligible text/html in DFS order should win"
+ );
+ }
+
// --- finalize_message with multiple inline images ---
#[test]