chore(traits): add Display and FromStr traits (#425)

Use strum for most of these, with a couple of manual implementations,
and related tests
This commit is contained in:
Josh McKinney 2023-08-22 21:21:13 -07:00 committed by GitHub
parent 1ba2246d95
commit 98155dce25
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 525 additions and 17 deletions

View file

@ -43,6 +43,7 @@ indoc = "2.0"
itertools = "0.11"
paste = "1.0.2"
serde = { version = "1", optional = true, features = ["derive"] }
strum = { version = "0.25", features = ["derive"] }
termion = { version = "2.0", optional = true }
termwiz = { version = "0.20.0", optional = true }
time = { version = "0.3.11", optional = true, features = ["local-offset"] }

View file

@ -27,6 +27,8 @@
use std::io;
use strum::{Display, EnumString};
use crate::{buffer::Cell, layout::Rect};
#[cfg(feature = "termion")]
@ -49,7 +51,7 @@ pub use self::test::TestBackend;
/// Enum representing the different types of clearing operations that can be performed
/// on the terminal screen.
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
#[derive(Debug, Display, EnumString, Clone, Copy, Eq, PartialEq, Hash)]
pub enum ClearType {
All,
AfterCursor,
@ -115,3 +117,41 @@ pub trait Backend {
/// Flush any buffered content to the terminal screen.
fn flush(&mut self) -> Result<(), io::Error>;
}
#[cfg(test)]
mod tests {
use strum::ParseError;
use super::*;
#[test]
fn clear_type_tostring() {
assert_eq!(ClearType::All.to_string(), "All");
assert_eq!(ClearType::AfterCursor.to_string(), "AfterCursor");
assert_eq!(ClearType::BeforeCursor.to_string(), "BeforeCursor");
assert_eq!(ClearType::CurrentLine.to_string(), "CurrentLine");
assert_eq!(ClearType::UntilNewLine.to_string(), "UntilNewLine");
}
#[test]
fn clear_type_from_str() {
assert_eq!("All".parse::<ClearType>(), Ok(ClearType::All));
assert_eq!(
"AfterCursor".parse::<ClearType>(),
Ok(ClearType::AfterCursor)
);
assert_eq!(
"BeforeCursor".parse::<ClearType>(),
Ok(ClearType::BeforeCursor)
);
assert_eq!(
"CurrentLine".parse::<ClearType>(),
Ok(ClearType::CurrentLine)
);
assert_eq!(
"UntilNewLine".parse::<ClearType>(),
Ok(ClearType::UntilNewLine)
);
assert_eq!("".parse::<ClearType>(), Err(ParseError::VariantNotFound));
}
}

View file

@ -2,6 +2,7 @@ use std::{
cell::RefCell,
cmp::{max, min},
collections::HashMap,
fmt,
rc::Rc,
};
@ -11,8 +12,9 @@ use cassowary::{
WeightedRelation::{EQ, GE, LE},
};
use itertools::Itertools;
use strum::{Display, EnumString};
#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash)]
#[derive(Debug, Default, Display, EnumString, Clone, Copy, Eq, PartialEq, Hash)]
pub enum Corner {
#[default]
TopLeft,
@ -21,7 +23,7 @@ pub enum Corner {
BottomLeft,
}
#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash)]
#[derive(Debug, Default, Display, EnumString, Clone, Copy, Eq, PartialEq, Hash)]
pub enum Direction {
Horizontal,
#[default]
@ -97,6 +99,18 @@ impl Default for Constraint {
}
}
impl fmt::Display for Constraint {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Constraint::Percentage(p) => write!(f, "Percentage({})", p),
Constraint::Ratio(n, d) => write!(f, "Ratio({}, {})", n, d),
Constraint::Length(l) => write!(f, "Length({})", l),
Constraint::Max(m) => write!(f, "Max({})", m),
Constraint::Min(m) => write!(f, "Min({})", m),
}
}
}
impl Constraint {
pub fn apply(&self, length: u16) -> u16 {
match *self {
@ -121,11 +135,26 @@ impl Constraint {
#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash)]
pub struct Margin {
pub vertical: u16,
pub horizontal: u16,
pub vertical: u16,
}
#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash)]
impl Margin {
pub const fn new(horizontal: u16, vertical: u16) -> Margin {
Margin {
horizontal,
vertical,
}
}
}
impl fmt::Display for Margin {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}x{}", self.horizontal, self.vertical)
}
}
#[derive(Debug, Default, Display, EnumString, Clone, Copy, Eq, PartialEq, Hash)]
pub enum Alignment {
#[default]
Left,
@ -144,6 +173,12 @@ pub struct Rect {
pub height: u16,
}
impl fmt::Display for Rect {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}x{}+{}+{}", self.width, self.height, self.x, self.y)
}
}
impl Rect {
/// Creates a new rect, with width and height limited to keep the area under max u16.
/// If clipped, aspect ratio will be preserved.
@ -234,8 +269,8 @@ impl Rect {
}
}
#[derive(Debug, Default, Clone, Eq, PartialEq, Hash)]
pub enum SegmentSize {
#[derive(Debug, Default, Display, EnumString, Clone, Eq, PartialEq, Hash)]
pub(crate) enum SegmentSize {
EvenDistribution,
#[default]
LastTakesRemainder,
@ -614,9 +649,181 @@ fn try_split(area: Rect, layout: &Layout) -> Result<Rc<[Rect]>, AddConstraintErr
#[cfg(test)]
mod tests {
use strum::ParseError;
use super::{SegmentSize::*, *};
use crate::prelude::Constraint::*;
#[test]
fn corner_to_string() {
assert_eq!(Corner::BottomLeft.to_string(), "BottomLeft");
assert_eq!(Corner::BottomRight.to_string(), "BottomRight");
assert_eq!(Corner::TopLeft.to_string(), "TopLeft");
assert_eq!(Corner::TopRight.to_string(), "TopRight");
}
#[test]
fn corner_from_str() {
assert_eq!("BottomLeft".parse::<Corner>(), Ok(Corner::BottomLeft));
assert_eq!("BottomRight".parse::<Corner>(), Ok(Corner::BottomRight));
assert_eq!("TopLeft".parse::<Corner>(), Ok(Corner::TopLeft));
assert_eq!("TopRight".parse::<Corner>(), Ok(Corner::TopRight));
assert_eq!("".parse::<Corner>(), Err(ParseError::VariantNotFound));
}
#[test]
fn direction_to_string() {
assert_eq!(Direction::Horizontal.to_string(), "Horizontal");
assert_eq!(Direction::Vertical.to_string(), "Vertical");
}
#[test]
fn direction_from_str() {
assert_eq!("Horizontal".parse::<Direction>(), Ok(Direction::Horizontal));
assert_eq!("Vertical".parse::<Direction>(), Ok(Direction::Vertical));
assert_eq!("".parse::<Direction>(), Err(ParseError::VariantNotFound));
}
#[test]
fn constraint_to_string() {
assert_eq!(Constraint::Percentage(50).to_string(), "Percentage(50)");
assert_eq!(Constraint::Ratio(1, 2).to_string(), "Ratio(1, 2)");
assert_eq!(Constraint::Length(10).to_string(), "Length(10)");
assert_eq!(Constraint::Max(10).to_string(), "Max(10)");
assert_eq!(Constraint::Min(10).to_string(), "Min(10)");
}
#[test]
fn margin_to_string() {
assert_eq!(Margin::new(1, 2).to_string(), "1x2");
}
#[test]
fn margin_new() {
assert_eq!(
Margin::new(1, 2),
Margin {
horizontal: 1,
vertical: 2
}
);
}
#[test]
fn alignment_to_string() {
assert_eq!(Alignment::Left.to_string(), "Left");
assert_eq!(Alignment::Center.to_string(), "Center");
assert_eq!(Alignment::Right.to_string(), "Right");
}
#[test]
fn alignment_from_str() {
assert_eq!("Left".parse::<Alignment>(), Ok(Alignment::Left));
assert_eq!("Center".parse::<Alignment>(), Ok(Alignment::Center));
assert_eq!("Right".parse::<Alignment>(), Ok(Alignment::Right));
assert_eq!("".parse::<Alignment>(), Err(ParseError::VariantNotFound));
}
#[test]
fn rect_to_string() {
assert_eq!(Rect::new(1, 2, 3, 4).to_string(), "3x4+1+2");
}
#[test]
fn rect_new() {
assert_eq!(
Rect::new(1, 2, 3, 4),
Rect {
x: 1,
y: 2,
width: 3,
height: 4
}
);
}
#[test]
fn rect_area() {
assert_eq!(Rect::new(1, 2, 3, 4).area(), 12);
}
#[test]
fn rect_left() {
assert_eq!(Rect::new(1, 2, 3, 4).left(), 1);
}
#[test]
fn rect_right() {
assert_eq!(Rect::new(1, 2, 3, 4).right(), 4);
}
#[test]
fn rect_top() {
assert_eq!(Rect::new(1, 2, 3, 4).top(), 2);
}
#[test]
fn rect_bottom() {
assert_eq!(Rect::new(1, 2, 3, 4).bottom(), 6);
}
#[test]
fn rect_inner() {
assert_eq!(
Rect::new(1, 2, 3, 4).inner(&Margin::new(1, 2)),
Rect::new(2, 4, 1, 0)
);
}
#[test]
fn rect_union() {
assert_eq!(
Rect::new(1, 2, 3, 4).union(Rect::new(2, 3, 4, 5)),
Rect::new(1, 2, 5, 6)
);
}
#[test]
fn rect_intersection() {
assert_eq!(
Rect::new(1, 2, 3, 4).intersection(Rect::new(2, 3, 4, 5)),
Rect::new(2, 3, 2, 3)
);
}
#[test]
fn rect_intersects() {
assert!(Rect::new(1, 2, 3, 4).intersects(Rect::new(2, 3, 4, 5)));
assert!(!Rect::new(1, 2, 3, 4).intersects(Rect::new(5, 6, 7, 8)));
}
#[test]
fn segment_size_to_string() {
assert_eq!(
SegmentSize::EvenDistribution.to_string(),
"EvenDistribution"
);
assert_eq!(
SegmentSize::LastTakesRemainder.to_string(),
"LastTakesRemainder"
);
assert_eq!(SegmentSize::None.to_string(), "None");
}
#[test]
fn segment_size_from_string() {
assert_eq!(
"EvenDistribution".parse::<SegmentSize>(),
Ok(EvenDistribution)
);
assert_eq!(
"LastTakesRemainder".parse::<SegmentSize>(),
Ok(LastTakesRemainder)
);
assert_eq!("None".parse::<SegmentSize>(), Ok(None));
assert_eq!("".parse::<SegmentSize>(), Err(ParseError::VariantNotFound));
}
fn get_x_width_with_segment_size(
segment_size: SegmentSize,
constraints: Vec<Constraint>,

View file

@ -1,3 +1,5 @@
use strum::{Display, EnumString};
pub mod block {
pub const FULL: &str = "";
pub const SEVEN_EIGHTHS: &str = "";
@ -240,7 +242,7 @@ pub mod braille {
}
/// Marker to use when plotting data points
#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash)]
#[derive(Debug, Default, Display, EnumString, Clone, Copy, Eq, PartialEq, Hash)]
pub enum Marker {
/// One point per cell in shape of dot
#[default]
@ -301,3 +303,27 @@ pub mod scrollbar {
end: "",
};
}
#[cfg(test)]
mod tests {
use strum::ParseError;
use super::*;
#[test]
fn marker_tostring() {
assert_eq!(Marker::Dot.to_string(), "Dot");
assert_eq!(Marker::Block.to_string(), "Block");
assert_eq!(Marker::Bar.to_string(), "Bar");
assert_eq!(Marker::Braille.to_string(), "Braille");
}
#[test]
fn marker_from_str() {
assert_eq!("Dot".parse::<Marker>(), Ok(Marker::Dot));
assert_eq!("Block".parse::<Marker>(), Ok(Marker::Block));
assert_eq!("Bar".parse::<Marker>(), Ok(Marker::Bar));
assert_eq!("Braille".parse::<Marker>(), Ok(Marker::Braille));
assert_eq!("".parse::<Marker>(), Err(ParseError::VariantNotFound));
}
}

View file

@ -1,4 +1,4 @@
use std::io;
use std::{fmt, io};
use crate::{
backend::{Backend, ClearType},
@ -15,6 +15,16 @@ pub enum Viewport {
Fixed(Rect),
}
impl fmt::Display for Viewport {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Viewport::Fullscreen => write!(f, "Fullscreen"),
Viewport::Inline(height) => write!(f, "Inline({})", height),
Viewport::Fixed(area) => write!(f, "Fixed({})", area),
}
}
}
/// Options to pass to [`Terminal::with_options`]
#[derive(Debug, Default, Clone, Eq, PartialEq, Hash)]
pub struct TerminalOptions {
@ -487,3 +497,18 @@ fn compute_inline_size<B: Backend>(
pos,
))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn viewport_to_string() {
assert_eq!(Viewport::Fullscreen.to_string(), "Fullscreen");
assert_eq!(Viewport::Inline(5).to_string(), "Inline(5)");
assert_eq!(
Viewport::Fixed(Rect::new(0, 0, 5, 5)).to_string(),
"Fixed(5x5+0+0)"
);
}
}

View file

@ -1,3 +1,5 @@
use strum::{Display, EnumString};
use crate::{layout::Alignment, text::Line};
#[derive(Debug, Default, Clone, Eq, PartialEq, Hash)]
@ -10,7 +12,7 @@ pub struct Title<'a> {
pub position: Option<Position>,
}
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
#[derive(Debug, Default, Display, EnumString, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Position {
#[default]
Top,
@ -45,3 +47,23 @@ where
Self::default().content(value.into())
}
}
#[cfg(test)]
mod tests {
use strum::ParseError;
use super::*;
#[test]
fn position_tostring() {
assert_eq!(Position::Top.to_string(), "Top");
assert_eq!(Position::Bottom.to_string(), "Bottom");
}
#[test]
fn position_from_str() {
assert_eq!("Top".parse::<Position>(), Ok(Position::Top));
assert_eq!("Bottom".parse::<Position>(), Ok(Position::Bottom));
assert_eq!("".parse::<Position>(), Err(ParseError::VariantNotFound));
}
}

View file

@ -1,6 +1,8 @@
#[path = "../title.rs"]
pub mod title;
use strum::{Display, EnumString};
pub use self::title::{Position, Title};
use crate::{
buffer::Buffer,
@ -10,7 +12,7 @@ use crate::{
widgets::{Borders, Widget},
};
#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash)]
#[derive(Debug, Default, Display, EnumString, Clone, Copy, Eq, PartialEq, Hash)]
pub enum BorderType {
#[default]
Plain,
@ -526,6 +528,8 @@ impl<'a> Styled for Block<'a> {
#[cfg(test)]
mod tests {
use strum::ParseError;
use super::*;
use crate::{
assert_buffer_eq,
@ -985,4 +989,19 @@ mod tests {
assert_buffer_eq!(buffer, expected_buffer);
}
}
#[test]
fn border_type_to_string() {
assert_eq!(format!("{}", BorderType::Plain), "Plain");
assert_eq!(format!("{}", BorderType::Rounded), "Rounded");
assert_eq!(format!("{}", BorderType::Double), "Double");
}
#[test]
fn border_type_from_str() {
assert_eq!("Plain".parse(), Ok(BorderType::Plain));
assert_eq!("Rounded".parse(), Ok(BorderType::Rounded));
assert_eq!("Double".parse(), Ok(BorderType::Double));
assert_eq!("".parse::<BorderType>(), Err(ParseError::VariantNotFound));
}
}

View file

@ -1,3 +1,5 @@
use strum::{Display, EnumString};
use crate::{
style::Color,
widgets::canvas::{
@ -6,7 +8,7 @@ use crate::{
},
};
#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash)]
#[derive(Debug, Default, Display, EnumString, Clone, Copy, Eq, PartialEq, Hash)]
pub enum MapResolution {
#[default]
Low,
@ -38,3 +40,26 @@ impl Shape for Map {
}
}
}
#[cfg(test)]
mod tests {
use strum::ParseError;
use super::*;
#[test]
fn map_resolution_to_string() {
assert_eq!(MapResolution::Low.to_string(), "Low");
assert_eq!(MapResolution::High.to_string(), "High");
}
#[test]
fn map_resolution_from_str() {
assert_eq!("Low".parse(), Ok(MapResolution::Low));
assert_eq!("High".parse(), Ok(MapResolution::High));
assert_eq!(
"".parse::<MapResolution>(),
Err(ParseError::VariantNotFound)
);
}
}

View file

@ -1,5 +1,6 @@
use std::{borrow::Cow, cmp::max};
use strum::{Display, EnumString};
use unicode_width::UnicodeWidthStr;
use crate::{
@ -76,7 +77,7 @@ impl<'a> Axis<'a> {
}
/// Used to determine which style of graphing to use
#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash)]
#[derive(Debug, Default, Display, EnumString, Clone, Copy, Eq, PartialEq, Hash)]
pub enum GraphType {
/// Draw each point
#[default]
@ -627,6 +628,8 @@ impl<'a> Styled for Chart<'a> {
#[cfg(test)]
mod tests {
use strum::ParseError;
use super::*;
use crate::style::{Modifier, Stylize};
@ -702,4 +705,17 @@ mod tests {
.remove_modifier(Modifier::DIM)
)
}
#[test]
fn graph_type_to_string() {
assert_eq!(GraphType::Scatter.to_string(), "Scatter");
assert_eq!(GraphType::Line.to_string(), "Line");
}
#[test]
fn graph_type_from_str() {
assert_eq!("Scatter".parse::<GraphType>(), Ok(GraphType::Scatter));
assert_eq!("Line".parse::<GraphType>(), Ok(GraphType::Line));
assert_eq!("".parse::<GraphType>(), Err(ParseError::VariantNotFound));
}
}

View file

@ -1,3 +1,5 @@
use strum::{Display, EnumString};
use super::StatefulWidget;
use crate::{
buffer::Buffer,
@ -7,7 +9,7 @@ use crate::{
};
/// An enum representing the direction of scrolling in a Scrollbar widget.
#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash)]
#[derive(Debug, Default, Display, EnumString, Clone, Copy, Eq, PartialEq, Hash)]
pub enum ScrollDirection {
/// Forward scroll direction, usually corresponds to scrolling downwards or rightwards.
#[default]
@ -101,7 +103,7 @@ impl ScrollbarState {
}
/// Scrollbar Orientation
#[derive(Debug, Default, Clone, Eq, PartialEq, Hash)]
#[derive(Debug, Default, Display, EnumString, Clone, Eq, PartialEq, Hash)]
pub enum ScrollbarOrientation {
#[default]
VerticalRight,
@ -458,12 +460,80 @@ impl<'a> StatefulWidget for Scrollbar<'a> {
#[cfg(test)]
mod tests {
use strum::ParseError;
use super::*;
use crate::{
assert_buffer_eq,
symbols::scrollbar::{HORIZONTAL, VERTICAL},
};
#[test]
fn scroll_direction_to_string() {
assert_eq!(ScrollDirection::Forward.to_string(), "Forward");
assert_eq!(ScrollDirection::Backward.to_string(), "Backward");
}
#[test]
fn scroll_direction_from_str() {
assert_eq!(
"Forward".parse::<ScrollDirection>(),
Ok(ScrollDirection::Forward)
);
assert_eq!(
"Backward".parse::<ScrollDirection>(),
Ok(ScrollDirection::Backward)
);
assert_eq!(
"".parse::<ScrollDirection>(),
Err(ParseError::VariantNotFound)
);
}
#[test]
fn scrollbar_orientation_to_string() {
assert_eq!(
ScrollbarOrientation::VerticalRight.to_string(),
"VerticalRight"
);
assert_eq!(
ScrollbarOrientation::VerticalLeft.to_string(),
"VerticalLeft"
);
assert_eq!(
ScrollbarOrientation::HorizontalBottom.to_string(),
"HorizontalBottom"
);
assert_eq!(
ScrollbarOrientation::HorizontalTop.to_string(),
"HorizontalTop"
);
}
#[test]
fn scrollbar_orientation_from_str() {
assert_eq!(
"VerticalRight".parse::<ScrollbarOrientation>(),
Ok(ScrollbarOrientation::VerticalRight)
);
assert_eq!(
"VerticalLeft".parse::<ScrollbarOrientation>(),
Ok(ScrollbarOrientation::VerticalLeft)
);
assert_eq!(
"HorizontalBottom".parse::<ScrollbarOrientation>(),
Ok(ScrollbarOrientation::HorizontalBottom)
);
assert_eq!(
"HorizontalTop".parse::<ScrollbarOrientation>(),
Ok(ScrollbarOrientation::HorizontalTop)
);
assert_eq!(
"".parse::<ScrollbarOrientation>(),
Err(ParseError::VariantNotFound)
);
}
#[test]
fn test_no_render_when_area_zero() {
let mut buffer = Buffer::empty(Rect::new(0, 0, 0, 0));

View file

@ -1,5 +1,7 @@
use std::cmp::min;
use strum::{Display, EnumString};
use crate::{
buffer::Buffer,
layout::Rect,
@ -38,7 +40,7 @@ pub struct Sparkline<'a> {
direction: RenderDirection,
}
#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash)]
#[derive(Debug, Default, Display, EnumString, Clone, Copy, Eq, PartialEq, Hash)]
pub enum RenderDirection {
#[default]
LeftToRight,
@ -167,6 +169,8 @@ impl<'a> Widget for Sparkline<'a> {
#[cfg(test)]
mod tests {
use strum::ParseError;
use super::*;
use crate::{
assert_buffer_eq,
@ -174,6 +178,28 @@ mod tests {
style::{Color, Modifier, Stylize},
};
#[test]
fn render_direction_to_string() {
assert_eq!(RenderDirection::LeftToRight.to_string(), "LeftToRight");
assert_eq!(RenderDirection::RightToLeft.to_string(), "RightToLeft");
}
#[test]
fn render_direction_from_str() {
assert_eq!(
"LeftToRight".parse::<RenderDirection>(),
Ok(RenderDirection::LeftToRight)
);
assert_eq!(
"RightToLeft".parse::<RenderDirection>(),
Ok(RenderDirection::RightToLeft)
);
assert_eq!(
"".parse::<RenderDirection>(),
Err(ParseError::VariantNotFound)
);
}
// Helper function to render a sparkline to a buffer with a given width
// filled with x symbols to make it easier to assert on the result
fn render(widget: Sparkline, width: u16) -> Buffer {

View file

@ -1,3 +1,4 @@
use strum::{Display, EnumString};
use unicode_width::UnicodeWidthStr;
use crate::{
@ -161,7 +162,7 @@ impl<'a> Styled for Row<'a> {
}
/// This option allows the user to configure the "highlight symbol" column width spacing
#[derive(Debug, PartialEq, Eq, Clone, Default, Hash)]
#[derive(Debug, Display, EnumString, PartialEq, Eq, Clone, Default, Hash)]
pub enum HighlightSpacing {
/// Always add spacing for the selection symbol column
///
@ -776,4 +777,34 @@ mod tests {
.remove_modifier(Modifier::CROSSED_OUT)
)
}
#[test]
fn highlight_spacing_to_string() {
assert_eq!(HighlightSpacing::Always.to_string(), "Always".to_string());
assert_eq!(
HighlightSpacing::WhenSelected.to_string(),
"WhenSelected".to_string()
);
assert_eq!(HighlightSpacing::Never.to_string(), "Never".to_string());
}
#[test]
fn highlight_spacing_from_str() {
assert_eq!(
"Always".parse::<HighlightSpacing>(),
Ok(HighlightSpacing::Always)
);
assert_eq!(
"WhenSelected".parse::<HighlightSpacing>(),
Ok(HighlightSpacing::WhenSelected)
);
assert_eq!(
"Never".parse::<HighlightSpacing>(),
Ok(HighlightSpacing::Never)
);
assert_eq!(
"".parse::<HighlightSpacing>(),
Err(strum::ParseError::VariantNotFound)
);
}
}