From: Ben Pfaff Date: Wed, 24 Dec 2025 21:51:52 +0000 (-0800) Subject: tests X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=158d711d558214b71cf7a39e63949975d0f26a1f;p=pspp tests --- diff --git a/rust/pspp/src/output/drivers/text.rs b/rust/pspp/src/output/drivers/text.rs index 5827fef5f8..5a11d6190c 100644 --- a/rust/pspp/src/output/drivers/text.rs +++ b/rust/pspp/src/output/drivers/text.rs @@ -385,20 +385,32 @@ impl TextDriver { } impl TextRenderer { + fn start_object(&mut self, writer: &mut W) -> FmtResult + where + W: FmtWrite, + { + if self.n_objects > 0 { + writeln!(writer)?; + } + self.n_objects += 1; + Ok(()) + } + fn render(&mut self, item: &Item, writer: &mut W) -> FmtResult where W: FmtWrite, { - for (index, item) in ItemRefIterator::without_hidden(item) - .filter(|item| !item.details.is_heading()) - .enumerate() + for item in ItemRefIterator::without_hidden(item).filter(|item| !item.details.is_heading()) { - if index > 0 { - writeln!(writer)?; - } match &item.details { - Details::Chart => writeln!(writer, "Omitting chart from text output")?, - Details::Image(_) => writeln!(writer, "Omitting image from text output")?, + Details::Chart => { + self.start_object(writer)?; + writeln!(writer, "Omitting chart from text output")? + } + Details::Image(_) => { + self.start_object(writer)?; + writeln!(writer, "Omitting image from text output")? + } Details::Heading(_) => unreachable!(), Details::Message(_diagnostic) => todo!(), Details::PageBreak => (), @@ -415,10 +427,8 @@ impl TextRenderer { where W: FmtWrite, { - for (index, layer_indexes) in table.layers(true).enumerate() { - if index > 0 { - writeln!(writer)?; - } + for layer_indexes in table.layers(true) { + self.start_object(writer)?; let mut pager = Pager::new(self, table, Some(layer_indexes.as_slice())); while pager.has_next(self).is_some() { diff --git a/rust/pspp/src/spv/read/html.rs b/rust/pspp/src/spv/read/html.rs index 19dc709766..4cc4b12caf 100644 --- a/rust/pspp/src/spv/read/html.rs +++ b/rust/pspp/src/spv/read/html.rs @@ -778,7 +778,9 @@ fn parse_nodes(nodes: &[Node]) -> Markup { } // SPSS often starts paragraphs with an initial `
` that it // ignores, but it does honor `
`. So weird. - Node::Element(br) if br.name == "br" => { + Node::Element(br) + if br.name.eq_ignore_ascii_case("br") && (br.name == "br" || i != 0) => + { add_markup(&mut retval, Markup::Text('\n'.into())); } Node::Element(element) => { @@ -970,26 +972,6 @@ mod tests { ); } - /* - #[test] - fn value() { - let value = parse_value( - r#"bold
italic
bold italic
red serif
big
"#, - ); - assert_eq!( - value, - Value::new_markup( - r##"bold -italic -bold italic -red serif -big -"## - ) - .with_font_style(FontStyle::default().with_size(10)) - ); - }*/ - /// From the corpus (also included in the documentation). #[test] fn header1() { @@ -1090,6 +1072,32 @@ mod tests { ); } + /// From the corpus, anonymized. + /// + /// This tests the unusual treatment of `
` at the start of text (`
` + /// is ignored at the start, but `
` is not). + #[test] + fn breaks() { + let text = r##"<head><style type="text/css">p{color:0;font-family:Monospaced;font-size:13pt;font-style:normal;font-weight:normal;text-decoration:none}</style></head><BR>USE ALL.<BR>COMPUTE filter_$=(group = 1).<BR>VARIABLE LABEL filter_$ 'group = 1 (FILTER)'.<BR>VALUE LABELS filter_$ 0 'Not Selected' 1 'Selected'.<BR>FORMAT filter_$ (f1.0).<BR>FILTER BY filter_$.<BR>EXECUTE.<BR>NPAR TEST<BR>  /WILCOXON=x WITH y<BR>   z w (PAIRED)<BR>  /MISSING ANALYSIS."##; + let content = quick_xml::de::from_str::(text).unwrap(); + let html = Document::from_html(&content); + let s = html.into_value().display(()).to_string(); + assert_eq!( + s, + r##"USE ALL. +COMPUTE filter_$=(group = 1). +VARIABLE LABEL filter_$ 'group = 1 (FILTER)'. +VALUE LABELS filter_$ 0 'Not Selected' 1 'Selected'. +FORMAT filter_$ (f1.0). +FILTER BY filter_$. +EXECUTE. +NPAR TEST +  /WILCOXON=x WITH y +   z w (PAIRED) +  /MISSING ANALYSIS."## + ); + } + /// Checks that the `escape-html` feature is enabled in [quick_xml], since /// we need that to resolve ` ` and other HTML entities. #[test] diff --git a/rust/pspp/src/spv/read/legacy_xml.rs b/rust/pspp/src/spv/read/legacy_xml.rs index 5998f8bb3f..5b4a5473f7 100644 --- a/rust/pspp/src/spv/read/legacy_xml.rs +++ b/rust/pspp/src/spv/read/legacy_xml.rs @@ -17,6 +17,7 @@ use std::{ cell::{Cell, RefCell}, collections::{BTreeMap, HashMap}, + fmt::Debug, marker::PhantomData, mem::take, num::NonZeroUsize, @@ -670,16 +671,10 @@ impl Visualization { let cell = series.get("cell").unwrap()/*XXX*/; let mut coords = Vec::with_capacity(dims.len()); let (cell_formats, format_map) = graph.interval.labeling.decode_format_map(&series); - let cell_footnotes = - graph - .interval - .labeling - .children - .iter() - .find_map(|child| match child { - LabelingChild::Footnotes(footnotes) => series.get(footnotes.variable.as_str()), - _ => None, - }); + let cell_footnotes = graph + .interval + .footnotes() + .and_then(|footnotes| series.get(footnotes.variable.as_str())); let mut data = HashMap::new(); for (i, cell) in cell.values.iter().enumerate() { coords.clear(); @@ -718,9 +713,9 @@ impl Visualization { for part in s.split(',') { if let Ok(index) = part.parse::() && let Some(index) = index.checked_sub(1) - && let Some(footnote) = footnotes.get(index) + && let Some(footnote) = dbg!(footnotes.get(index)) { - value = value.with_footnote(footnote); + value.add_footnote(footnote); } } } @@ -1021,7 +1016,7 @@ impl Visualization { .collect::>(); let mut pivot_table = PivotTable::new(dimensions) .with_look(Arc::new(look)) - .with_footnotes(footnotes) + .with_footnotes(dbg!(footnotes)) .with_data(data) .with_layer(¤t_layer); let decimal = Decimal::for_lang(&self.lang); @@ -1050,6 +1045,14 @@ struct Series { dimension_index: Cell>, } +impl Debug for Series { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("Series") + .field("name", &self.name) + .finish_non_exhaustive() + } +} + impl Series { fn new(name: String, values: Vec, map: Map) -> Self { Self { @@ -1888,10 +1891,6 @@ impl Style { base_style: &AreaStyle, ) { if let Some(sf) = sf { - if sf.reset == Some(true) { - value.styling_mut().footnotes.clear(); - } - let format = match &sf.child { Some(SetFormatChild::Format(format)) => Some(format.decode()), Some(SetFormatChild::NumberFormat(format)) => { @@ -2414,6 +2413,19 @@ struct Interval { footnotes: Option, } +impl Interval { + fn footnotes(&self) -> Option<&Footnotes> { + if let Some(footnotes) = &self.footnotes { + Some(footnotes) + } else { + self.labeling + .children + .iter() + .find_map(|child| child.as_footnotes()) + } + } +} + #[derive(Deserialize, Debug)] #[serde(rename_all = "camelCase")] struct Labeling { @@ -2459,6 +2471,15 @@ enum LabelingChild { Footnotes(Footnotes), } +impl LabelingChild { + fn as_footnotes(&self) -> Option<&Footnotes> { + match self { + Self::Footnotes(footnotes) => Some(footnotes), + _ => None, + } + } +} + #[derive(Deserialize, Debug)] #[serde(rename_all = "camelCase")] struct Formatting { diff --git a/rust/pspp/src/spv/read/tests.rs b/rust/pspp/src/spv/read/tests.rs index ee61dbc782..bf12298010 100644 --- a/rust/pspp/src/spv/read/tests.rs +++ b/rust/pspp/src/spv/read/tests.rs @@ -43,6 +43,12 @@ fn legacy6() { test_raw_spvfile("legacy6"); } +/// Regression test for ``. +#[test] +fn legacy7() { + test_raw_spvfile("legacy7"); +} + fn test_raw_spvfile(name: &str) { let input_filename = Path::new("src/spv/testdata") .join(name) diff --git a/rust/pspp/src/spv/testdata/legacy7.expected b/rust/pspp/src/spv/testdata/legacy7.expected new file mode 100644 index 0000000000..18283a8a4e --- /dev/null +++ b/rust/pspp/src/spv/testdata/legacy7.expected @@ -0,0 +1,44 @@ + Ranks +╭───────────────────────────────────────────────────────┬─────┬─────────┬────────────╮ +│ │ N │Mean Rank│Sum of Ranks│ +├───────────────────────────────────────────────────────┼─────┼─────────┼────────────┤ +│xxxxxxxxxx - yyyyyyyyyyyyy Negative Ranks│25[a]│ 13,00│ 325,00│ +│ Positive Ranks│ 0[b]│ ,00│ ,00│ +│ Ties │ 0[c]│ │ │ +│ Total │ 25│ │ │ +├───────────────────────────────────────────────────────┼─────┼─────────┼────────────┤ +│xxxxxxxxxxxxx - yyyyyyyyyyyyyy Negative Ranks│25[d]│ 13,00│ 325,00│ +│ Positive Ranks│ 0[e]│ ,00│ ,00│ +│ Ties │ 0[f]│ │ │ +│ Total │ 25│ │ │ +├───────────────────────────────────────────────────────┼─────┼─────────┼────────────┤ +│xxxxxxxxxxxxxx - yyyyyyyyyyyyyyy Negative Ranks│25[g]│ 13,00│ 325,00│ +│ Positive Ranks│ 0[h]│ ,00│ ,00│ +│ Ties │ 0[i]│ │ │ +│ Total │ 25│ │ │ +├───────────────────────────────────────────────────────┼─────┼─────────┼────────────┤ +│xxxxxxxxxxxxxxxx - yyyyyyyyyyyyyyyyy Negative Ranks│ 5[j]│ 3,00│ 15,00│ +│ Positive Ranks│ 0[k]│ ,00│ ,00│ +│ Ties │20[l]│ │ │ +│ Total │ 25│ │ │ +├───────────────────────────────────────────────────────┼─────┼─────────┼────────────┤ +│xxxxxxxxxxxxxxxxxxx - yyyyyyyyyyyyyyyyyy Negative Ranks│ 0[m]│ ,00│ ,00│ +│ Positive Ranks│ 5[n]│ 3,00│ 15,00│ +│ Ties │20[o]│ │ │ +│ Total │ 25│ │ │ +╰───────────────────────────────────────────────────────┴─────┴─────────┴────────────╯ +a. Footnote A +b. Footnote B +c. Footnote C +d. Footnote D +e. Footnote E +f. Footnote F +g. Footnote G +h. Footnote H +i. Footnote I +j. Footnote J +k. Footnote K +l. Footnote L +m. Footnote M +n. Footnote N +o. Footnote O diff --git a/rust/pspp/src/spv/testdata/legacy7.spv b/rust/pspp/src/spv/testdata/legacy7.spv new file mode 100644 index 0000000000..77caf75627 Binary files /dev/null and b/rust/pspp/src/spv/testdata/legacy7.spv differ