pub n_orphan_lines: usize,
}
+impl Look {
+ pub fn with_omit_empty(mut self, omit_empty: bool) -> Self {
+ self.omit_empty = omit_empty;
+ self
+ }
+ pub fn with_row_label_position(mut self, row_label_position: LabelPosition) -> Self {
+ self.row_label_position = row_label_position;
+ self
+ }
+}
+
impl Default for Look {
fn default() -> Self {
Self {
pub cells: HashMap<usize, Value>,
}
+impl PivotTable {
+ fn with_title(mut self, title: Value) -> Self {
+ self.title = Some(Box::new(title));
+ self.show_title = true;
+ self
+ }
+
+ fn with_caption(mut self, caption: Value) -> Self {
+ self.caption = Some(Box::new(caption));
+ self.show_caption = true;
+ self
+ }
+
+ fn with_show_title(mut self, show_title: bool) -> Self {
+ self.show_title = show_title;
+ self
+ }
+
+ fn with_show_caption(mut self, show_caption: bool) -> Self {
+ self.show_caption = show_caption;
+ self
+ }
+
+ fn with_layer(mut self, layer: &[usize]) -> Self {
+ debug_assert_eq!(layer.len(), self.current_layer.len());
+ if self.look.print_all_layers {
+ Arc::make_mut(&mut self.look).print_all_layers = false;
+ }
+ self.current_layer.clear();
+ self.current_layer.extend_from_slice(layer);
+ self
+ }
+
+ fn with_all_layers(mut self) -> Self {
+ if !self.look.print_all_layers {
+ Arc::make_mut(&mut self.look).print_all_layers = true;
+ }
+ self
+ }
+}
+
impl Default for PivotTable {
fn default() -> Self {
Self {
///
/// - Otherwise, the iterator will just visit `self.current_layer`.
pub fn layers(&self, print: bool) -> Box<dyn Iterator<Item = SmallVec<[usize; 4]>> + '_> {
+ dbg!(self.look.print_all_layers);
if print && self.look.print_all_layers {
+ dbg!();
Box::new(self.axis_values(Axis3::Z))
} else {
Box::new(once(SmallVec::from_slice(&self.current_layer)))
use std::sync::Arc;
-use crate::output::pivot::{Area, Color, Look, PivotTable};
+use crate::output::pivot::{Area, Color, LabelPosition, Look, PivotTable};
use super::{Axis3, DimensionBuilder, GroupBuilder, PivotTableBuilder, Value};
for i in 0..3 {
pt.insert(&[i], Value::new_integer(Some(i as f64)));
}
- pt.with_look(test_look()).build()
+ pt.with_look(Arc::new(test_look())).build()
}
#[test]
);
}
-fn test_look() -> Arc<Look> {
+fn test_look() -> Look {
let mut look = Look::default();
look.areas[Area::Title].cell_style.horz_align = Some(super::HorzAlign::Left);
look.areas[Area::Title].font_style.bold = false;
- Arc::new(look)
+ look
}
-fn d2(title: &str, axes: [Axis3; 2], dimension_labels: bool) -> PivotTable {
- let mut a = GroupBuilder::new(Value::new_text("a")).with_show_label(dimension_labels);
+fn d2(title: &str, axes: [Axis3; 2], dimension_labels: Option<LabelPosition>) -> PivotTable {
+ let mut a = GroupBuilder::new(Value::new_text("a")).with_show_label(dimension_labels.is_some());
for name in ["a1", "a2", "a3"] {
a.push(Value::new_text(name));
}
let d1 = DimensionBuilder::new(axes[0], a);
- let mut b = GroupBuilder::new(Value::new_text("b")).with_show_label(dimension_labels);
+ let mut b = GroupBuilder::new(Value::new_text("b")).with_show_label(dimension_labels.is_some());
for name in ["b1", "b2", "b3"] {
b.push(Value::new_text(name));
}
i += 1;
}
}
- pt.with_look(test_look()).build()
+ let look = match dimension_labels {
+ Some(position) => test_look().with_row_label_position(position),
+ None => test_look(),
+ };
+ pt.with_look(Arc::new(look)).build()
}
#[track_caller]
-fn assert_rendering(pivot_table: PivotTable, expected: &str) {
+fn assert_rendering(pivot_table: &PivotTable, expected: &str) {
let actual = pivot_table.to_string();
if actual != expected {
- panic!("Unexpected pivot table rendering.\nActual:\n{actual}\nExpected:\n{expected}");
+ eprintln!("Unexpected pivot table rendering:\n--- expected\n+++ actual");
+ for result in diff::lines(expected, &actual) {
+ match result {
+ diff::Result::Left(line) => eprintln!("-{line:?}"),
+ diff::Result::Both(line, _) => eprintln!(" {line:?}"),
+ diff::Result::Right(line) => eprintln!("+{line:?}"),
+ }
+ }
+ panic!();
}
}
#[test]
fn d2_cc() {
assert_rendering(
- d2("Columns", [Axis3::X, Axis3::X], false),
+ &d2("Columns", [Axis3::X, Axis3::X], None),
"\
Columns
╭────────┬────────┬────────╮
#[test]
fn d2_cc_with_dim_labels() {
assert_rendering(
- d2("Columns", [Axis3::X, Axis3::X], true),
+ &d2("Columns", [Axis3::X, Axis3::X], Some(LabelPosition::Corner)),
"\
Columns
╭──────────────────────────╮
#[test]
fn d2_rr() {
assert_rendering(
- d2("Rows", [Axis3::Y, Axis3::Y], false),
+ &d2("Rows", [Axis3::Y, Axis3::Y], None),
"\
Rows
╭─────┬─╮
}
#[test]
-fn d2_rr_with_dim_labels() {
+fn d2_rr_with_corner_dim_labels() {
assert_rendering(
- d2("Rows - Corner", [Axis3::Y, Axis3::Y], true),
+ &d2(
+ "Rows - Corner",
+ [Axis3::Y, Axis3::Y],
+ Some(LabelPosition::Corner),
+ ),
"\
Rows - Corner
╭─────┬─╮
);
}
+#[test]
+fn d2_rr_with_nested_dim_labels() {
+ assert_rendering(
+ &d2(
+ "Rows - Nested",
+ [Axis3::Y, Axis3::Y],
+ Some(LabelPosition::Nested),
+ ),
+ "\
+Rows - Nested
+╭─────────┬─╮
+│b b1 a a1│0│
+│ a2│1│
+│ a3│2│
+│ ╶───────┼─┤
+│ b2 a a1│3│
+│ a2│4│
+│ a3│5│
+│ ╶───────┼─┤
+│ b3 a a1│6│
+│ a2│7│
+│ a3│8│
+╰─────────┴─╯
+",
+ );
+}
+
#[test]
fn d2_cr() {
assert_rendering(
- d2("Column x Row", [Axis3::X, Axis3::Y], false),
+ &d2("Column x Row", [Axis3::X, Axis3::Y], None),
"\
Column x Row
╭──┬──┬──┬──╮
);
}
+#[test]
+fn d2_cr_with_corner_dim_labels() {
+ assert_rendering(
+ &d2(
+ "Column x Row - Corner",
+ [Axis3::X, Axis3::Y],
+ Some(LabelPosition::Corner),
+ ),
+ "\
+Column x Row - Corner
+╭──┬────────╮
+│ │ a │
+│ ├──┬──┬──┤
+│b │a1│a2│a3│
+├──┼──┼──┼──┤
+│b1│ 0│ 1│ 2│
+│b2│ 3│ 4│ 5│
+│b3│ 6│ 7│ 8│
+╰──┴──┴──┴──╯
+",
+ );
+}
+
+#[test]
+fn d2_cr_with_nested_dim_labels() {
+ assert_rendering(
+ &d2(
+ "Column x Row - Nested",
+ [Axis3::X, Axis3::Y],
+ Some(LabelPosition::Nested),
+ ),
+ "\
+Column x Row - Nested
+╭────┬────────╮
+│ │ a │
+│ ├──┬──┬──┤
+│ │a1│a2│a3│
+├────┼──┼──┼──┤
+│b b1│ 0│ 1│ 2│
+│ b2│ 3│ 4│ 5│
+│ b3│ 6│ 7│ 8│
+╰────┴──┴──┴──╯
+",
+ );
+}
+
#[test]
fn d2_rc() {
assert_rendering(
- d2("Row x Column", [Axis3::Y, Axis3::X], false),
+ &d2("Row x Column", [Axis3::Y, Axis3::X], None),
"\
Row x Column
╭──┬──┬──┬──╮
",
);
}
+
+#[test]
+fn d2_rc_with_corner_dim_labels() {
+ assert_rendering(
+ &d2(
+ "Row x Column - Corner",
+ [Axis3::Y, Axis3::X],
+ Some(LabelPosition::Corner),
+ ),
+ "\
+Row x Column - Corner
+╭──┬────────╮
+│ │ b │
+│ ├──┬──┬──┤
+│a │b1│b2│b3│
+├──┼──┼──┼──┤
+│a1│ 0│ 3│ 6│
+│a2│ 1│ 4│ 7│
+│a3│ 2│ 5│ 8│
+╰──┴──┴──┴──╯
+",
+ );
+}
+
+#[test]
+fn d2_rc_with_nested_dim_labels() {
+ assert_rendering(
+ &d2(
+ "Row x Column - Nested",
+ [Axis3::Y, Axis3::X],
+ Some(LabelPosition::Nested),
+ ),
+ "\
+Row x Column - Nested
+╭────┬────────╮
+│ │ b │
+│ ├──┬──┬──┤
+│ │b1│b2│b3│
+├────┼──┼──┼──┤
+│a a1│ 0│ 3│ 6│
+│ a2│ 1│ 4│ 7│
+│ a3│ 2│ 5│ 8│
+╰────┴──┴──┴──╯
+",
+ );
+}
+
+#[test]
+fn d2_cl() {
+ let pivot_table = d2("Column x b1", [Axis3::X, Axis3::Z], None);
+ assert_rendering(
+ &pivot_table,
+ "\
+Column x b1
+b1
+╭──┬──┬──╮
+│a1│a2│a3│
+├──┼──┼──┤
+│ 0│ 1│ 2│
+╰──┴──┴──╯
+",
+ );
+
+ let pivot_table = pivot_table
+ .with_layer(&[1])
+ .with_title(Value::new_text("Column x b2"));
+ assert_rendering(
+ &pivot_table,
+ "\
+Column x b2
+b2
+╭──┬──┬──╮
+│a1│a2│a3│
+├──┼──┼──┤
+│ 3│ 4│ 5│
+╰──┴──┴──╯
+",
+ );
+
+ let pivot_table = pivot_table
+ .with_all_layers()
+ .with_title(Value::new_text("Column (All Layers)"));
+ assert_rendering(
+ &pivot_table,
+ "\
+Column (All Layers)
+b1
+╭──┬──┬──╮
+│a1│a2│a3│
+├──┼──┼──┤
+│ 0│ 1│ 2│
+╰──┴──┴──╯
+
+Column (All Layers)
+b2
+╭──┬──┬──╮
+│a1│a2│a3│
+├──┼──┼──┤
+│ 3│ 4│ 5│
+╰──┴──┴──╯
+
+Column (All Layers)
+b3
+╭──┬──┬──╮
+│a1│a2│a3│
+├──┼──┼──┤
+│ 6│ 7│ 8│
+╰──┴──┴──╯
+",
+ );
+}
+
+#[test]
+fn d2_rl() {
+ let pivot_table = d2("Row x b1", [Axis3::Y, Axis3::Z], None);
+ assert_rendering(
+ &pivot_table,
+ "\
+Row x b1
+b1
+╭──┬─╮
+│a1│0│
+│a2│1│
+│a3│2│
+╰──┴─╯
+",
+ );
+
+ let pivot_table = pivot_table
+ .with_layer(&[1])
+ .with_title(Value::new_text("Row x b2"));
+ assert_rendering(
+ &pivot_table,
+ "\
+Row x b2
+b2
+╭──┬─╮
+│a1│3│
+│a2│4│
+│a3│5│
+╰──┴─╯
+",
+ );
+
+ let pivot_table = pivot_table
+ .with_all_layers()
+ .with_title(Value::new_text("Row (All Layers)"));
+ assert_rendering(
+ &pivot_table,
+ "\
+Row (All Layers)
+b1
+╭──┬─╮
+│a1│0│
+│a2│1│
+│a3│2│
+╰──┴─╯
+
+Row (All Layers)
+b2
+╭──┬─╮
+│a1│3│
+│a2│4│
+│a3│5│
+╰──┴─╯
+
+Row (All Layers)
+b3
+╭──┬─╮
+│a1│6│
+│a2│7│
+│a3│8│
+╰──┴─╯
+",
+ );
+}
+
+#[test]
+fn title_and_caption() {
+ let pivot_table =
+ d2("Title", [Axis3::X, Axis3::Y], None).with_caption(Value::new_text("Caption"));
+ assert_rendering(
+ &pivot_table,
+ "\
+Title
+╭──┬──┬──┬──╮
+│ │a1│a2│a3│
+├──┼──┼──┼──┤
+│b1│ 0│ 1│ 2│
+│b2│ 3│ 4│ 5│
+│b3│ 6│ 7│ 8│
+╰──┴──┴──┴──╯
+Caption
+",
+ );
+
+ let pivot_table = pivot_table.with_show_title(false);
+ assert_rendering(
+ &pivot_table,
+ "\
+╭──┬──┬──┬──╮
+│ │a1│a2│a3│
+├──┼──┼──┼──┤
+│b1│ 0│ 1│ 2│
+│b2│ 3│ 4│ 5│
+│b3│ 6│ 7│ 8│
+╰──┴──┴──┴──╯
+Caption
+",
+ );
+
+ let pivot_table = pivot_table.with_show_caption(false);
+ assert_rendering(
+ &pivot_table,
+ "\
+╭──┬──┬──┬──╮
+│ │a1│a2│a3│
+├──┼──┼──┼──┤
+│b1│ 0│ 1│ 2│
+│b2│ 3│ 4│ 5│
+│b3│ 6│ 7│ 8│
+╰──┴──┴──┴──╯
+",
+ );
+}
+
+#[test]
+fn no_dimension() {
+ let pivot_table = PivotTableBuilder::new(Value::new_text("No Dimensions"), &[])
+ .with_look(Arc::new(test_look()))
+ .build();
+ assert_rendering(
+ &pivot_table,
+ "No Dimensions
+╭╮
+╰╯
+",
+ );
+}
+
+#[test]
+fn empty_dimensions() {
+ let look = Arc::new(test_look().with_omit_empty(false));
+
+ let d1 = DimensionBuilder::new(Axis3::X, GroupBuilder::new(Value::new_text("a")));
+ let pivot_table = PivotTableBuilder::new(Value::new_text("One Empty Dimension"), &[d1])
+ .with_look(look.clone())
+ .build();
+ assert_rendering(&pivot_table, "One Empty Dimension\n");
+
+ let d1 = DimensionBuilder::new(Axis3::X, GroupBuilder::new(Value::new_text("a")));
+ let d2 = DimensionBuilder::new(
+ Axis3::X,
+ GroupBuilder::new(Value::new_text("b")).with_label_shown(),
+ );
+ let pivot_table = PivotTableBuilder::new(Value::new_text("Two Empty Dimensions"), &[d1, d2])
+ .with_look(look.clone())
+ .build();
+ assert_rendering(&pivot_table, "Two Empty Dimensions\n");
+
+ let d1 = DimensionBuilder::new(Axis3::X, GroupBuilder::new(Value::new_text("a")));
+ let d2 = DimensionBuilder::new(
+ Axis3::X,
+ GroupBuilder::new(Value::new_text("b")).with_label_shown(),
+ );
+ let d3 = DimensionBuilder::new(
+ Axis3::X,
+ GroupBuilder::new(Value::new_text("c"))
+ .with(Value::new_text("c1"))
+ .with(Value::new_text("c2")),
+ );
+ let pivot_table =
+ PivotTableBuilder::new(Value::new_text("Three Dimensions, Two Empty"), &[d1, d2, d3])
+ .with_look(look.clone())
+ .build();
+ assert_rendering(&pivot_table, "Three Dimensions, Two Empty\n");
+}