use buoyant::render::CharacterRender;
use buoyant::render::CharacterRenderTarget;
use std::iter::zip;
use buoyant::{
environment::DefaultEnvironment,
font::{CharacterBufferFont, FontLayout},
layout::Layout as _,
primitives::{Dimensions, Point, ProposedDimension, ProposedDimensions, Size},
render::Renderable as _,
render_target::FixedTextBuffer,
view::{
make_render_tree, HorizontalTextAlignment, LayoutExtensions as _, RenderExtensions as _,
Text,
},
};
#[derive(Debug)]
struct ArbitraryFont {
line_height: u16,
character_width: u16,
}
impl FontLayout for ArbitraryFont {
fn line_height(&self) -> u16 {
self.line_height
}
fn character_width(&self, _character: char) -> u16 {
self.character_width
}
}
#[test]
fn test_single_character() {
let font = ArbitraryFont {
line_height: 10,
character_width: 5,
};
let text = Text::new("A", &font);
let offer = Size::new(100, 100);
let env = DefaultEnvironment::non_animated();
let layout = text.layout(&offer.into(), &env);
assert_eq!(layout.resolved_size, Dimensions::new(5, 10));
}
#[test]
fn test_single_character_constrained() {
let font = ArbitraryFont {
line_height: 10,
character_width: 5,
};
let text = Text::new("A", &font);
let offer = Size::new(4, 10);
let env = DefaultEnvironment::non_animated();
let layout = text.layout(&offer.into(), &env);
assert_eq!(layout.resolved_size, Dimensions::new(5, 10));
}
#[test]
fn test_text_layout() {
let font = ArbitraryFont {
line_height: 10,
character_width: 5,
};
let text = Text::new("Hello, world!", &font);
let offer = Size::new(100, 100);
let env = DefaultEnvironment::non_animated();
let layout = text.layout(&offer.into(), &env);
assert_eq!(layout.resolved_size, Dimensions::new(5 * 13, 10));
}
#[test]
fn test_text_layout_wraps() {
let font = ArbitraryFont {
line_height: 10,
character_width: 5,
};
let text = Text::new("Hello, world!", &font);
let offer = Size::new(50, 100);
let env = DefaultEnvironment::non_animated();
let layout = text.layout(&offer.into(), &env);
assert_eq!(layout.resolved_size, Dimensions::new(6 * 5, 20));
}
#[test]
fn test_wraps_partial_words() {
let font = ArbitraryFont {
line_height: 10,
character_width: 5,
};
let text = Text::new("123412341234", &font);
let offer = Size::new(20, 100);
let env = DefaultEnvironment::non_animated();
let layout = text.layout(&offer.into(), &env);
assert_eq!(layout.resolved_size, Dimensions::new(20, 30));
}
#[test]
fn test_newline() {
let font = ArbitraryFont {
line_height: 10,
character_width: 5,
};
let text = Text::new("1234\n12\n\n123\n", &font);
let offer = Size::new(25, 100);
let env = DefaultEnvironment::non_animated();
let layout = text.layout(&offer.into(), &env);
assert_eq!(layout.resolved_size, Dimensions::new(20, 40));
}
#[test]
fn test_infinite_width() {
let font = ArbitraryFont {
line_height: 1,
character_width: 1,
};
let text = Text::new("abc defg", &font);
let offer = ProposedDimensions {
width: ProposedDimension::Infinite,
height: 100.into(),
};
let env = DefaultEnvironment::non_animated();
let layout = text.layout(&offer, &env);
assert_eq!(layout.resolved_size, Dimensions::new(8, 1));
}
#[test]
fn test_compact_width() {
let font = ArbitraryFont {
line_height: 1,
character_width: 1,
};
let text = Text::new("abc defg", &font);
let offer = ProposedDimensions {
width: ProposedDimension::Compact,
height: 100.into(),
};
let env = DefaultEnvironment::non_animated();
let layout = text.layout(&offer, &env);
assert_eq!(layout.resolved_size, Dimensions::new(8, 1));
}
#[test]
fn test_infinite_height() {
let font = ArbitraryFont {
line_height: 1,
character_width: 1,
};
let text = Text::new("abc defg h", &font);
let offer = ProposedDimensions {
width: 10.into(),
height: ProposedDimension::Infinite,
};
let env = DefaultEnvironment::non_animated();
let layout = text.layout(&offer, &env);
assert_eq!(layout.resolved_size, Dimensions::new(10, 1));
}
#[test]
fn test_compact_height() {
let font = ArbitraryFont {
line_height: 1,
character_width: 1,
};
let text = Text::new("abc defg h", &font);
let offer = ProposedDimensions {
width: 10.into(),
height: ProposedDimension::Compact,
};
let env = DefaultEnvironment::non_animated();
let layout = text.layout(&offer, &env);
assert_eq!(layout.resolved_size, Dimensions::new(10, 1));
}
#[test]
fn test_infinite_height_wrapping() {
let font = ArbitraryFont {
line_height: 1,
character_width: 1,
};
let text = Text::new("abc defg hij", &font);
let offer = ProposedDimensions {
width: 10.into(),
height: ProposedDimension::Infinite,
};
let env = DefaultEnvironment::non_animated();
let layout = text.layout(&offer, &env);
assert_eq!(layout.resolved_size, Dimensions::new(8, 2));
}
#[test]
fn test_compact_height_wrapping() {
let font = ArbitraryFont {
line_height: 1,
character_width: 1,
};
let text = Text::new("abc defg hij", &font);
let offer = ProposedDimensions {
width: 10.into(),
height: ProposedDimension::Compact,
};
let env = DefaultEnvironment::non_animated();
let layout = text.layout(&offer, &env);
assert_eq!(layout.resolved_size, Dimensions::new(8, 2));
}
#[test]
fn test_render_wrapping_leading() {
let font = CharacterBufferFont {};
let mut buffer = FixedTextBuffer::<6, 5>::default();
let text = Text::new("This is a lengthy text here", &font).foreground_color(' ');
make_render_tree(&text, buffer.size()).render(&mut buffer, &' ', Point::zero());
assert_eq!(buffer.text[0].iter().collect::<String>(), "This ");
assert_eq!(buffer.text[1].iter().collect::<String>(), "is a ");
assert_eq!(buffer.text[2].iter().collect::<String>(), "length");
assert_eq!(buffer.text[3].iter().collect::<String>(), "y text");
assert_eq!(buffer.text[4].iter().collect::<String>(), "here ");
}
#[test]
fn test_render_wrapping_center_even() {
let font = CharacterBufferFont {};
let mut buffer = FixedTextBuffer::<6, 5>::default();
let text = Text::new("This is a lengthy text here", &font)
.multiline_text_alignment(HorizontalTextAlignment::Center)
.foreground_color(' ');
make_render_tree(&text, buffer.size()).render(&mut buffer, &' ', Point::zero());
assert_eq!(buffer.text[0].iter().collect::<String>(), " This ");
assert_eq!(buffer.text[1].iter().collect::<String>(), " is a ");
assert_eq!(buffer.text[2].iter().collect::<String>(), "length");
assert_eq!(buffer.text[3].iter().collect::<String>(), "y text");
assert_eq!(buffer.text[4].iter().collect::<String>(), " here ");
}
#[test]
fn test_render_wrapping_center_odd() {
let font = CharacterBufferFont {};
let mut buffer = FixedTextBuffer::<6, 5>::default();
let text = Text::new("This is a lengthy text 12345", &font)
.multiline_text_alignment(HorizontalTextAlignment::Center)
.foreground_color(' ');
make_render_tree(&text, buffer.size()).render(&mut buffer, &' ', Point::zero());
assert_eq!(buffer.text[0].iter().collect::<String>(), " This ");
assert_eq!(buffer.text[1].iter().collect::<String>(), " is a ");
assert_eq!(buffer.text[2].iter().collect::<String>(), "length");
assert_eq!(buffer.text[3].iter().collect::<String>(), "y text");
assert_eq!(buffer.text[4].iter().collect::<String>(), "12345 ");
}
#[test]
fn test_render_wrapping_trailing() {
let font = CharacterBufferFont {};
let mut buffer = FixedTextBuffer::<6, 5>::default();
let text = Text::new("This is a lengthy text here", &font)
.multiline_text_alignment(HorizontalTextAlignment::Trailing)
.foreground_color(' ');
make_render_tree(&text, buffer.size()).render(&mut buffer, &' ', Point::zero());
assert_eq!(buffer.text[0].iter().collect::<String>(), " This");
assert_eq!(buffer.text[1].iter().collect::<String>(), " is a");
assert_eq!(buffer.text[2].iter().collect::<String>(), "length");
assert_eq!(buffer.text[3].iter().collect::<String>(), "y text");
assert_eq!(buffer.text[4].iter().collect::<String>(), " here");
}
#[test]
fn test_clipped_text_is_centered_correctly() {
let font = CharacterBufferFont {};
let view = Text::new(
"Several lines\n of text\nshould be correctly spaced when cut off",
&font,
)
.multiline_text_alignment(HorizontalTextAlignment::Center)
.foreground_color(' ');
let env = DefaultEnvironment::non_animated();
let mut buffer = FixedTextBuffer::<40, 2>::default();
let layout = view.layout(&buffer.size().into(), &env);
assert_eq!(layout.resolved_size, Dimensions::new(13, 2));
let tree = view.render_tree(&layout, Point::zero(), &env);
tree.render(&mut buffer, &' ', Point::zero());
let lines = [
"Several lines ",
" of text ",
];
zip(lines.iter(), buffer.text.iter()).for_each(|(expected, actual)| {
assert_eq!(actual.iter().collect::<String>(), *expected);
});
}
#[test]
fn test_clipped_text_trails_correctly() {
let font = CharacterBufferFont {};
let view = Text::new(
"Several lines\n of text\nshould be correctly spaced when cut off",
&font,
)
.multiline_text_alignment(HorizontalTextAlignment::Trailing)
.frame()
.with_height(2) .foreground_color(' ');
let env = DefaultEnvironment::non_animated();
let mut buffer = FixedTextBuffer::<40, 3>::default();
let layout = view.layout(&buffer.size().into(), &env);
assert_eq!(layout.resolved_size, Dimensions::new(13, 2));
let tree = view.render_tree(&layout, Point::zero(), &env);
tree.render(&mut buffer, &' ', Point::zero());
let lines = [
"Several lines ",
" of text ",
" ",
];
zip(lines.iter(), buffer.text.iter()).for_each(|(expected, actual)| {
assert_eq!(actual.iter().collect::<String>(), *expected);
});
}