use fundu_core::config::{Config, Delimiter};
use fundu_core::parse::Parser;
use fundu_core::time::TimeUnit;
use super::time_units::TimeUnits;
use crate::DurationParser;
#[derive(Debug, PartialEq, Eq)]
enum TimeUnitsChoice<'a> {
Default,
All,
None,
Custom(&'a [TimeUnit]),
}
#[derive(Debug, PartialEq, Eq)]
pub struct DurationParserBuilder<'a> {
time_units_choice: TimeUnitsChoice<'a>,
config: Config<'a>,
}
impl<'a> Default for DurationParserBuilder<'a> {
fn default() -> Self {
Self::new()
}
}
impl<'a> DurationParserBuilder<'a> {
#[cfg_attr(miri, doc = "```rust,ignore")]
#[cfg_attr(not(miri), doc = "```rust")]
pub const fn new() -> Self {
Self {
time_units_choice: TimeUnitsChoice::None,
config: Config::new(),
}
}
pub const fn default_time_units(mut self) -> Self {
self.time_units_choice = TimeUnitsChoice::Default;
self
}
pub const fn all_time_units(mut self) -> Self {
self.time_units_choice = TimeUnitsChoice::All;
self
}
pub const fn time_units(mut self, time_units: &'a [TimeUnit]) -> Self {
self.time_units_choice = TimeUnitsChoice::Custom(time_units);
self
}
pub const fn default_unit(mut self, time_unit: TimeUnit) -> Self {
self.config.default_unit = time_unit;
self
}
pub const fn allow_time_unit_delimiter(mut self) -> Self {
self.config.allow_time_unit_delimiter = true;
self
}
pub const fn allow_sign_delimiter(mut self) -> Self {
self.config.allow_sign_delimiter = true;
self
}
pub const fn allow_negative(mut self) -> Self {
self.config.allow_negative = true;
self
}
pub const fn allow_ago(mut self) -> Self {
self.config.allow_ago = true;
self.config.allow_negative = true;
self
}
pub const fn disable_exponent(mut self) -> Self {
self.config.disable_exponent = true;
self
}
pub const fn disable_fraction(mut self) -> Self {
self.config.disable_fraction = true;
self
}
pub const fn disable_infinity(mut self) -> Self {
self.config.disable_infinity = true;
self
}
pub const fn number_is_optional(mut self) -> Self {
self.config.number_is_optional = true;
self
}
pub const fn parse_multiple(mut self, conjunctions: Option<&'a [&'a str]>) -> Self {
self.config.allow_multiple = true;
self.config.conjunctions = conjunctions;
self
}
pub const fn inner_delimiter(mut self, delimiter: Delimiter) -> Self {
self.config.inner_delimiter = delimiter;
self
}
pub const fn outer_delimiter(mut self, delimiter: Delimiter) -> Self {
self.config.outer_delimiter = delimiter;
self
}
pub const fn build(self) -> DurationParser<'a> {
let parser = Parser::with_config(self.config);
match self.time_units_choice {
TimeUnitsChoice::Default => DurationParser {
time_units: TimeUnits::with_default_time_units(),
inner: parser,
},
TimeUnitsChoice::All => DurationParser {
time_units: TimeUnits::with_all_time_units(),
inner: parser,
},
TimeUnitsChoice::None => DurationParser {
time_units: TimeUnits::new(),
inner: parser,
},
TimeUnitsChoice::Custom(time_units) => DurationParser {
time_units: TimeUnits::with_time_units(time_units),
inner: parser,
},
}
}
}
#[cfg(test)]
mod tests {
use fundu_core::config::Config;
use rstest::rstest;
use super::*;
use crate::TimeUnit::*;
#[test]
#[cfg_attr(miri, ignore)]
fn test_duration_parser_builder_when_new() {
let builder = DurationParserBuilder::new();
assert_eq!(builder.config, Config::new());
assert_eq!(builder.time_units_choice, TimeUnitsChoice::None);
}
#[test]
fn test_duration_parser_builder_when_default_time_units() {
let builder = DurationParserBuilder::new().default_time_units();
assert_eq!(builder.time_units_choice, TimeUnitsChoice::Default);
}
#[test]
fn test_duration_parser_builder_when_all_time_units() {
let builder = DurationParserBuilder::new().all_time_units();
assert_eq!(builder.time_units_choice, TimeUnitsChoice::All);
}
#[test]
fn test_duration_parser_builder_when_custom_time_units() {
let builder = DurationParserBuilder::new().time_units(&[MicroSecond, Hour, Week, Year]);
assert_eq!(
builder.time_units_choice,
TimeUnitsChoice::Custom(&[MicroSecond, Hour, Week, Year])
);
}
#[test]
#[cfg_attr(miri, ignore)]
fn test_duration_parser_builder_when_default_unit() {
let mut expected = Config::new();
expected.default_unit = MicroSecond;
let builder = DurationParserBuilder::new().default_unit(MicroSecond);
assert_eq!(builder.config, expected);
}
#[test]
fn test_duration_parser_builder_when_allow_delimiter() {
let builder = DurationParserBuilder::new().allow_time_unit_delimiter();
assert!(builder.config.allow_time_unit_delimiter);
}
#[test]
fn test_duration_parser_builder_when_allow_ago() {
let builder = DurationParserBuilder::new().allow_ago();
assert!(builder.config.allow_ago);
assert!(builder.config.allow_negative);
}
#[test]
fn test_duration_parser_builder_when_allow_sign_delimiter() {
let builder = DurationParserBuilder::new().allow_sign_delimiter();
assert!(builder.config.allow_sign_delimiter);
}
#[test]
#[cfg_attr(miri, ignore)]
fn test_duration_parser_builder_when_disable_fraction() {
let mut expected = Config::new();
expected.disable_fraction = true;
let builder = DurationParserBuilder::new().disable_fraction();
assert_eq!(builder.config, expected);
}
#[test]
#[cfg_attr(miri, ignore)]
fn test_duration_parser_builder_when_disable_exponent() {
let mut expected = Config::new();
expected.disable_exponent = true;
let builder = DurationParserBuilder::new().disable_exponent();
assert_eq!(builder.config, expected);
}
#[test]
#[cfg_attr(miri, ignore)]
fn test_duration_parser_builder_when_disable_infinity() {
let mut expected = Config::new();
expected.disable_infinity = true;
let builder = DurationParserBuilder::new().disable_infinity();
assert_eq!(builder.config, expected);
}
#[test]
#[cfg_attr(miri, ignore)]
fn test_duration_parser_builder_when_number_is_optional() {
let mut expected = Config::new();
expected.number_is_optional = true;
let builder = DurationParserBuilder::new().number_is_optional();
assert_eq!(builder.config, expected);
}
#[test]
fn test_duration_parser_builder_when_parse_multiple() {
let builder = DurationParserBuilder::new().parse_multiple(None);
assert!(builder.config.allow_multiple);
}
#[rstest]
#[case::default_time_units(TimeUnitsChoice::Default, DurationParser::new())]
#[case::all_time_units(TimeUnitsChoice::All, DurationParser::with_all_time_units())]
#[case::no_time_units(TimeUnitsChoice::None, DurationParser::without_time_units())]
#[case::custom_time_units(
TimeUnitsChoice::Custom(&[NanoSecond, Minute]),
DurationParser::with_time_units(&[NanoSecond, Minute])
)]
#[cfg_attr(miri, ignore)]
fn test_duration_parser_builder_build(
#[case] choice: TimeUnitsChoice,
#[case] expected: DurationParser,
) {
let mut builder = DurationParserBuilder::new();
builder.time_units_choice = choice;
assert_eq!(builder.build(), expected);
}
#[test]
fn test_duration_parser_builder_set_inner_delimiter() {
let builder = DurationParserBuilder::new().inner_delimiter(|byte| byte == b'a');
assert!((builder.config.inner_delimiter)(b'a'));
assert!(!(builder.config.inner_delimiter)(b' '));
}
#[test]
fn test_duration_parser_builder_set_outer_delimiter() {
let builder = DurationParserBuilder::new().outer_delimiter(|byte| byte == b'a');
assert!((builder.config.outer_delimiter)(b'a'));
assert!(!(builder.config.outer_delimiter)(b' '));
}
}