Add tests for table rendering

This commit is contained in:
Matias Fontanini 2023-10-07 07:25:57 -07:00
parent 3163d310be
commit 0500d51f8c
6 changed files with 54 additions and 18 deletions

View File

@ -329,7 +329,7 @@ impl<'a> PresentationBuilder<'a> {
}
if !texts.is_empty() {
self.slide_operations.push(RenderOperation::RenderTextLine {
texts: WeightedLine::from(texts),
line: WeightedLine::from(texts),
alignment: alignment.clone(),
});
}
@ -408,12 +408,15 @@ impl<'a> PresentationBuilder<'a> {
let mut separator = Text { chunks: Vec::new() };
for (index, width) in widths.iter().enumerate() {
let mut contents = String::new();
let mut extra_lines = 1;
let mut margin = 1;
if index > 0 {
contents.push('┼');
extra_lines += 1;
// Append an extra dash to have 1 column margin on both sides
if index < widths.len() - 1 {
margin += 1;
}
contents.extend(iter::repeat("").take(*width + extra_lines));
}
contents.extend(iter::repeat("").take(*width + margin));
separator.chunks.push(StyledText::from(contents));
}
@ -480,7 +483,7 @@ impl AsRenderOperations for FooterGenerator {
operations.extend([
RenderOperation::JumpToWindowBottom,
RenderOperation::RenderTextLine {
texts: vec![Self::render_template(left, &current_slide, &context, colors.clone())].into(),
line: vec![Self::render_template(left, &current_slide, &context, colors.clone())].into(),
alignment: Alignment::Left { margin: 1 },
},
]);
@ -489,7 +492,7 @@ impl AsRenderOperations for FooterGenerator {
operations.extend([
RenderOperation::JumpToWindowBottom,
RenderOperation::RenderTextLine {
texts: vec![Self::render_template(right, &current_slide, &context, colors.clone())].into(),
line: vec![Self::render_template(right, &current_slide, &context, colors.clone())].into(),
alignment: Alignment::Right { margin: 1 },
},
]);
@ -505,7 +508,7 @@ impl AsRenderOperations for FooterGenerator {
let bar = vec![WeightedText::from(StyledText::new(bar, TextStyle::default().colors(colors.clone())))];
vec![
RenderOperation::JumpToWindowBottom,
RenderOperation::RenderTextLine { texts: bar.into(), alignment: Alignment::Left { margin: 0 } },
RenderOperation::RenderTextLine { line: bar.into(), alignment: Alignment::Left { margin: 0 } },
]
}
FooterStyle::Empty => vec![],
@ -564,6 +567,20 @@ mod test {
}
}
fn extract_text_lines(operations: &[RenderOperation]) -> Vec<String> {
let mut output = Vec::new();
for operation in operations {
match operation {
RenderOperation::RenderTextLine { line, .. } => {
let texts: Vec<_> = line.iter_texts().map(|text| text.text.text.clone()).collect();
output.push(texts.join(""));
}
_ => (),
};
}
output
}
#[test]
fn prelude_appears_once() {
let elements = vec![
@ -629,4 +646,18 @@ mod test {
assert_eq!(lengths[0], (width, width));
assert_eq!(lengths[1], (width, width));
}
#[test]
fn table() {
let elements = vec![MarkdownElement::Table(Table {
header: TableRow(vec![Text::from("key"), Text::from("value"), Text::from("other")]),
rows: vec![TableRow(vec![Text::from("potato"), Text::from("bar"), Text::from("yes")])],
})];
let slides = build_presentation(elements).into_slides();
let operations: Vec<_> =
slides.into_iter().next().unwrap().render_operations.into_iter().filter(|op| is_visible(op)).collect();
let lines = extract_text_lines(&operations);
let expected_lines = &["key │ value │ other", "───────┼───────┼──────", "potato │ bar │ yes "];
assert_eq!(lines, expected_lines);
}
}

View File

@ -50,7 +50,7 @@ impl ContentDiff for RenderOperation {
match (self, other) {
(SetColors(original), SetColors(updated)) if original != updated => false,
(RenderTextLine { texts: original, .. }, RenderTextLine { texts: updated, .. }) if original != updated => {
(RenderTextLine { line: original, .. }, RenderTextLine { line: updated, .. }) if original != updated => {
true
}
(RenderTextLine { alignment: original, .. }, RenderTextLine { alignment: updated, .. })
@ -114,7 +114,7 @@ mod test {
#[case(RenderOperation::RenderSeparator)]
#[case(RenderOperation::RenderLineBreak)]
#[case(RenderOperation::SetColors(Colors{background: None, foreground: None}))]
#[case(RenderOperation::RenderTextLine{texts: String::from("asd").into(), alignment: Default::default()})]
#[case(RenderOperation::RenderTextLine{line: String::from("asd").into(), alignment: Default::default()})]
#[case(RenderOperation::RenderPreformattedLine(
PreformattedLine{
text: "asd".into(),
@ -131,19 +131,19 @@ mod test {
#[test]
fn different_text() {
let lhs = RenderOperation::RenderTextLine { texts: String::from("foo").into(), alignment: Default::default() };
let rhs = RenderOperation::RenderTextLine { texts: String::from("bar").into(), alignment: Default::default() };
let lhs = RenderOperation::RenderTextLine { line: String::from("foo").into(), alignment: Default::default() };
let rhs = RenderOperation::RenderTextLine { line: String::from("bar").into(), alignment: Default::default() };
assert!(lhs.is_content_different(&rhs));
}
#[test]
fn different_text_alignment() {
let lhs = RenderOperation::RenderTextLine {
texts: String::from("foo").into(),
line: String::from("foo").into(),
alignment: Alignment::Left { margin: 42 },
};
let rhs = RenderOperation::RenderTextLine {
texts: String::from("foo").into(),
line: String::from("foo").into(),
alignment: Alignment::Left { margin: 1337 },
};
assert!(!lhs.is_content_different(&rhs));

View File

@ -18,6 +18,11 @@ impl WeightedLine {
pub fn width(&self) -> usize {
self.0.iter().map(|text| text.width()).sum()
}
/// Get an iterator to the underlying text chunks.
pub fn iter_texts(&self) -> impl Iterator<Item = &WeightedText> {
self.0.iter()
}
}
impl From<Vec<WeightedText>> for WeightedLine {
@ -42,7 +47,7 @@ struct CharAccumulator {
/// A piece of weighted text.
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct WeightedText {
text: StyledText,
pub text: StyledText,
accumulators: Vec<CharAccumulator>,
}

View File

@ -168,7 +168,7 @@ pub enum RenderOperation {
JumpToSlideBottom,
/// Render a line of text.
RenderTextLine { texts: WeightedLine, alignment: Alignment },
RenderTextLine { line: WeightedLine, alignment: Alignment },
/// Render a horizontal separator line.
RenderSeparator,

View File

@ -64,10 +64,10 @@ where
RenderOperation::ClearScreen,
RenderOperation::SetColors(Colors { foreground: Some(Color::Red), background: Some(Color::Black) }),
RenderOperation::JumpToVerticalCenter,
RenderOperation::RenderTextLine { texts: WeightedLine::from(heading), alignment: alignment.clone() },
RenderOperation::RenderTextLine { line: WeightedLine::from(heading), alignment: alignment.clone() },
RenderOperation::RenderLineBreak,
RenderOperation::RenderLineBreak,
RenderOperation::RenderTextLine { texts: WeightedLine::from(error), alignment: alignment.clone() },
RenderOperation::RenderTextLine { line: WeightedLine::from(error), alignment: alignment.clone() },
];
let mut operator = RenderOperator::new(&mut self.handle, dimensions.clone(), dimensions, Default::default());
for operation in operations {

View File

@ -44,7 +44,7 @@ where
RenderOperation::JumpToVerticalCenter => self.jump_to_vertical_center(),
RenderOperation::JumpToSlideBottom => self.jump_to_slide_bottom(),
RenderOperation::JumpToWindowBottom => self.jump_to_window_bottom(),
RenderOperation::RenderTextLine { texts, alignment } => self.render_text(texts, alignment),
RenderOperation::RenderTextLine { line: texts, alignment } => self.render_text(texts, alignment),
RenderOperation::RenderSeparator => self.render_separator(),
RenderOperation::RenderLineBreak => self.render_line_break(),
RenderOperation::RenderImage(image) => self.render_image(image),