From c9bec299e66720631310c8a6532cbf3675049ca8 Mon Sep 17 00:00:00 2001 From: mtlcl410 <2368091+mtlcl410@users.noreply.github.com> Date: Sun, 1 Nov 2026 22:36:56 +0800 Subject: [PATCH] M6: test that a radio group with /PCOn items saves the clicked button's item and reopens on it Round trip through the session for the static radio fixture with /PCOn items 1 2 next to /Opt [(1) (2)] and position states /0 /1: a click on either button saves that button's own item to the datasets, reopening turns the same button on with nothing rewritten, and taking the XFA out notes no lost data. With radio_dataset_value as before dbea0793e the second button saves "1" (left: Some("1"), right: Some("2")). Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01Pq7HyCfwzyRXj4VfQAVVdv --- crates/engine/src/tests.rs | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/crates/engine/src/tests.rs b/crates/engine/src/tests.rs index cc1062fe65..6b793458d7 100644 --- a/crates/engine/src/tests.rs +++ b/crates/engine/src/tests.rs @@ -6170,6 +6170,35 @@ fn stripping_xfa_takes_a_radio_items_pcon_as_the_fields_value() { assert_eq!(lost(&s, id), Vec::::new()); } +/// A radio group whose buttons carry `/PCOn` items `1` `2` next to `/Opt [(1) (2)]` and on +/// states named by position (`/0`, `/1`): a click on either button saves that button's own item +/// to the datasets, reopening turns the same button on with nothing rewritten, and taking the XFA +/// out notes no lost data. The state `/1` used to match the first button's item `1`, so the +/// second button saved `1` and came back as the first. +#[test] +fn a_radio_group_with_pcon_items_saves_and_reopens_the_clicked_button() { + let lang = "form1[0].page1[0].lang[0]"; + let data_of = |bytes: Arc>| { + let cos = pdfcraft_cos::Document::open(bytes).unwrap(); + let data = pdfcraft_xfa::parse_datasets(&pdfcraft_xfa::read_packets(&cos).unwrap().unwrap().xdp).unwrap(); + data.text_at(&pdfcraft_xfa::som_to_path(lang)).map(str::to_owned) + }; + let value = |s: &Session, id: DocId| s.get(id).unwrap().form.iter().find(|f| f.name == lang).unwrap().value.clone(); + let form = Arc::new(pdfcraft_xfa::fixtures::static_radio_shell_with_pcon("", ["1", "2"])); + let mut s = Session::new().with_clock(|| 1_700_000_000); + for (state, item) in [("0", "1"), ("1", "2")] { + let id = s.open("blank.pdf", None, form.clone(), None).unwrap(); + s.apply(id, Edit::SetFieldValue { name: lang.into(), value: FieldValue::Radio(Some(state.into())) }).unwrap(); + let saved = s.save_bytes(id).unwrap(); + assert_eq!(data_of(saved.clone()).as_deref(), Some(item), "clicked {state}"); + let again = s.open("again.pdf", None, saved, None).unwrap(); + assert_eq!(value(&s, again), [state], "clicked {state}"); + assert!(!s.get(again).unwrap().info.warnings.iter().any(|w| w.contains("taken from this form's XFA data")), "clicked {state}"); + s.apply(again, Edit::XfaToStatic).unwrap(); + assert!(!s.get(again).unwrap().info.warnings.iter().any(|w| w.contains("held a value other than the form's XFA data")), "clicked {state}"); + } +} + /// A static XFA form whose values are only in its datasets takes every one on opening, as /// filling the fields one at a time would leave it: values, appearances and the note; a /// read-only field keeps its own value.