mrot_test_utils/
argument.rs

1//! Contains the arguments used in test implementation and the instructions how to parse them from
2//! a string.
3
4use crate::Error;
5use chrono::{naive::NaiveDate, DateTime};
6use libmrot::{MealRecord, Period};
7use std::{fmt, str::FromStr};
8
9const NAIVE_DATE_PARSE_FROM_STRING_FORMAT: &str = "%Y-%m-%d";
10
11/// Holds strings which are parsable date expressions
12#[derive(Default)]
13pub struct TextDate(String);
14
15impl FromStr for TextDate {
16    type Err = Error;
17
18    fn from_str(s: &str) -> Result<Self, Self::Err> {
19        Ok(TextDate(String::from(s)))
20    }
21}
22
23impl fmt::Debug for TextDate {
24    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
25        write!(f, "TextDate({})", self.0)
26    }
27}
28
29/// Holds multiple [`TextDate`]s.
30#[derive(Default)]
31pub struct TextDates(Vec<TextDate>);
32
33impl TextDates {
34    pub fn to_vec_string(&self) -> Vec<String> {
35        self.0.iter().map(|date| date.0.clone()).collect()
36    }
37}
38
39impl FromStr for TextDates {
40    type Err = Error;
41
42    fn from_str(s: &str) -> Result<Self, Self::Err> {
43        let dates: Result<Vec<TextDate>, _> = s.split("; ").map(TextDate::from_str).collect();
44        dates.map(TextDates)
45    }
46}
47
48impl fmt::Debug for TextDates {
49    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
50        f.debug_list().entries(&self.0).finish()
51    }
52}
53
54/// Holds multiple [`NaiveDates`].
55#[derive(Default)]
56pub struct NaiveDates(Vec<NaiveDate>);
57
58impl NaiveDates {
59    pub fn to_vec_naivedate(&self) -> Vec<NaiveDate> {
60        self.0.clone()
61    }
62}
63
64impl FromStr for NaiveDates {
65    type Err = Error;
66
67    fn from_str(s: &str) -> Result<Self, Self::Err> {
68        let dates: Result<Vec<NaiveDate>, _> = s
69            .split(", ")
70            .map(|date_str| {
71                NaiveDate::parse_from_str(date_str, NAIVE_DATE_PARSE_FROM_STRING_FORMAT)
72            })
73            .collect();
74        Ok(dates.map(NaiveDates)?)
75    }
76}
77
78impl fmt::Debug for NaiveDates {
79    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
80        f.debug_list().entries(&self.0).finish()
81    }
82}
83
84/// Holds multiple strings which are meals
85#[derive(Default)]
86pub struct Meals(Vec<String>);
87
88impl Meals {
89    pub fn to_vec_string(&self) -> Vec<String> {
90        self.0.clone()
91    }
92}
93
94impl FromStr for Meals {
95    type Err = Error;
96
97    fn from_str(s: &str) -> Result<Self, Self::Err> {
98        let meals: Vec<String> = s.split(", ").map(String::from).collect();
99        Ok(Meals(meals))
100    }
101}
102
103impl fmt::Debug for Meals {
104    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
105        f.debug_list().entries(&self.0).finish()
106    }
107}
108
109/// By this we transform a timestamp string to a [`NaiveDate`] string.
110#[derive(Default)]
111pub struct DateString(String);
112
113impl FromStr for DateString {
114    type Err = Error;
115
116    fn from_str(s: &str) -> Result<Self, Self::Err> {
117        let timestamp = i64::from_str(s)?;
118        let dt = DateTime::from_timestamp(timestamp, 0)
119            .ok_or(libmrot::Error::InvalidTimestamp(timestamp))?;
120        let naive_date = dt.date_naive();
121        let result_string = naive_date
122            .format(NAIVE_DATE_PARSE_FROM_STRING_FORMAT)
123            .to_string();
124        Ok(DateString(result_string))
125    }
126}
127
128impl fmt::Debug for DateString {
129    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
130        write!(f, "DateString({})", self.0)
131    }
132}
133
134impl fmt::Display for DateString {
135    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
136        write!(f, "{}", self.0)
137    }
138}
139
140/// Holds multiple [`MealRecord`]s.
141#[derive(Default)]
142pub struct MealRecords(Vec<MealRecord>);
143
144impl MealRecords {
145    pub fn to_vec_mealrecord(&self) -> Vec<MealRecord> {
146        self.0
147            .iter()
148            .map(|meal_record| meal_record.clone())
149            .collect()
150    }
151}
152
153impl FromStr for MealRecords {
154    type Err = Error;
155
156    fn from_str(s: &str) -> Result<Self, Self::Err> {
157        if s == "" {
158            return Ok(MealRecords::default());
159        }
160        let meal_records: Result<Vec<MealRecord>, _> =
161            s.split("; ").map(MealRecord::from_str).collect();
162        Ok(meal_records.map(MealRecords)?)
163    }
164}
165
166impl fmt::Debug for MealRecords {
167    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
168        f.debug_list().entries(&self.0).finish()
169    }
170}
171
172/// Wraps a [`Period`] so we can create it from a string from the feature files.
173#[derive(Default)]
174pub struct WrappedPeriod(Option<Period>);
175
176impl WrappedPeriod {
177    pub fn to_option_period(&self) -> Option<Period> {
178        match self.0 {
179            None => None,
180            Some(ref period) => Some(period.clone()),
181        }
182    }
183}
184
185impl FromStr for WrappedPeriod {
186    type Err = Error;
187
188    /// Construct a WrappedPeriod from a string.
189    /// The string `"None"` constructs WrappedPeriod containing `None`.
190    /// Other strings try to construct a WrappedPeriod containing `Some(Period {...})`.
191    fn from_str(s: &str) -> Result<Self, Self::Err> {
192        let option_period = match s {
193            "None" => None,
194            _ => Some(Period::new(s)?),
195        };
196        Ok(WrappedPeriod(option_period))
197    }
198}