chrono_datepicker_core/config/
mod.rs1pub mod date_constraints;
2
3use crate::dialog_view_type::DialogViewType;
4use chrono::prelude::*;
5
6use self::date_constraints::HasDateConstraints;
7
8#[derive(Default, Debug, Builder, Getters)]
10#[builder(setter(strip_option))]
11#[builder(default)]
12#[builder(build_fn(validate = "Self::validate"))]
13pub struct PickerConfig<T: HasDateConstraints + Default + Clone> {
14    #[getter(skip)]
16    date_constraints: T,
17
18    initial_date: Option<NaiveDate>,
20
21    initial_view_type: DialogViewType,
23
24    selection_type: DialogViewType,
26
27    initially_opened: bool,
29
30    #[builder(default = "String::from(\"%b %Y\")", setter(into))]
32    month_title_format: String,
33}
34
35impl<T: HasDateConstraints + std::default::Default + Clone> HasDateConstraints for PickerConfig<T> {
36    fn is_day_forbidden(&self, date: &NaiveDate) -> bool {
37        self.date_constraints.is_day_forbidden(date)
38    }
39
40    fn is_month_forbidden(&self, year_month_info: &NaiveDate) -> bool {
41        self.date_constraints.is_month_forbidden(year_month_info)
42    }
43
44    fn is_year_forbidden(&self, year: i32) -> bool {
45        self.date_constraints.is_year_forbidden(year)
46    }
47
48    fn is_year_group_forbidden(&self, year: i32) -> bool {
49        self.date_constraints.is_year_group_forbidden(year)
50    }
51}
52
53impl<T: HasDateConstraints + std::default::Default + Clone> PickerConfigBuilder<T> {
54    fn validate(&self) -> Result<(), String> {
55        if self.initial_view_type > self.selection_type {
56            return Err("initial_view_type can have at most selection_type scale".into());
57        }
58        match (self.initial_date, &self.date_constraints) {
59            (Some(Some(initial_date)), Some(date_constraints)) => {
60                if date_constraints.is_day_forbidden(&initial_date) {
61                    return Err(format!(
62                        "The initial_date {:?} is forbidden by the date_constraints.",
63                        initial_date
64                    ));
65                }
66            }
67            (_, _) => {}
68        }
69        Ok(())
70    }
71}
72
73impl<T: HasDateConstraints + std::default::Default + Clone> PickerConfig<T> {
74    pub fn guess_allowed_year_month(&self) -> NaiveDate {
75        if let Some(init_date) = self.initial_date {
76            return init_date;
77        }
78        Local::now().date().naive_local()
80    }
81}
82
83#[cfg(test)]
84mod tests {
85    use super::*;
86
87    use super::date_constraints::MockHasDateConstraints;
88    use mockall::predicate;
89
90    #[test]
91    fn picker_config_initial_view_type_greater_than_selection_type() {
92        let config = PickerConfigBuilder::<MockHasDateConstraints>::default()
93            .initial_view_type(DialogViewType::Days)
94            .selection_type(DialogViewType::Months)
95            .build();
96        assert!(config.is_err());
97        assert_eq!(
98            config.unwrap_err().to_string(),
99            "initial_view_type can have at most selection_type scale"
100        );
101    }
102
103    #[test]
104    fn picker_config_initial_view_type_equal_to_selection_type() {
105        let config = PickerConfigBuilder::<MockHasDateConstraints>::default()
106            .initial_view_type(DialogViewType::Months)
107            .selection_type(DialogViewType::Months)
108            .build();
109        assert!(config.is_ok());
110    }
111
112    #[test]
113    fn picker_config_initial_view_type_smaller_than_selection_type() {
114        let config = PickerConfigBuilder::<MockHasDateConstraints>::default()
115            .initial_view_type(DialogViewType::Years)
116            .selection_type(DialogViewType::Months)
117            .build();
118        assert!(config.is_ok());
119    }
120
121    #[test]
122    fn picker_config_initial_date_forbidden() {
123        let mut date_constraints_mock = MockHasDateConstraints::new();
124        date_constraints_mock
125            .expect_is_day_forbidden()
126            .returning(|_| true);
127        let config = PickerConfigBuilder::default()
128            .initial_date(NaiveDate::from_ymd(2020, 1, 1))
129            .date_constraints(date_constraints_mock)
130            .build();
131        assert!(config.is_err());
132        assert_eq!(
133            config.unwrap_err().to_string(),
134            "The initial_date 2020-01-01 is forbidden by the date_constraints."
135        );
136    }
137
138    fn create_picker_config_with_mocked_date_constraints<
140        T: HasDateConstraints + Clone + std::default::Default,
141    >(
142        builder: PickerConfigBuilder<T>,
143        mock_constraints: T,
144    ) -> PickerConfig<T> {
145        let config = builder.build().unwrap();
146        PickerConfig {
147            date_constraints: mock_constraints,
148            initial_date: *config.initial_date(),
149            initial_view_type: *config.initial_view_type(),
150            selection_type: *config.selection_type(),
151            initially_opened: *config.initially_opened(),
152            month_title_format: config.month_title_format().to_owned().clone(),
153        }
154    }
155
156    #[test]
157    fn test_is_day_forbidden() {
158        let date = NaiveDate::from_ymd(2020, 1, 1);
159        let mut date_constraints_mock = MockHasDateConstraints::new();
160        date_constraints_mock
161            .expect_is_day_forbidden()
162            .with(predicate::eq(date))
163            .times(1)
164            .returning(|_| true);
165        let builder = PickerConfigBuilder::default();
166        let config =
167            create_picker_config_with_mocked_date_constraints(builder, date_constraints_mock);
168        assert!(config.is_day_forbidden(&date));
169    }
170
171    #[test]
172    fn test_is_month_forbidden() {
173        let year_month = NaiveDate::from_ymd(2000, 2, 24);
174        let mut date_constraints_mock = MockHasDateConstraints::new();
175        date_constraints_mock
176            .expect_is_month_forbidden()
177            .with(predicate::eq(year_month.clone()))
178            .times(1)
179            .returning(|_| true);
180        let builder = PickerConfigBuilder::default();
181        let config =
182            create_picker_config_with_mocked_date_constraints(builder, date_constraints_mock);
183        assert!(config.is_month_forbidden(&year_month));
184    }
185
186    #[test]
187    fn test_is_year_forbidden() {
188        let year = 2000i32;
189        let mut date_constraints_mock = MockHasDateConstraints::new();
190        date_constraints_mock
191            .expect_is_year_forbidden()
192            .with(predicate::eq(year))
193            .times(1)
194            .returning(|_| true);
195        let builder = PickerConfigBuilder::default();
196        let config =
197            create_picker_config_with_mocked_date_constraints(builder, date_constraints_mock);
198        assert!(config.is_year_forbidden(year));
199    }
200
201    #[test]
202    fn test_is_year_group_forbidden() {
203        let year = 2000i32;
204        let mut date_constraints_mock = MockHasDateConstraints::new();
205        date_constraints_mock
206            .expect_is_year_group_forbidden()
207            .with(predicate::eq(year))
208            .times(1)
209            .returning(|_| true);
210        let builder = PickerConfigBuilder::default();
211        let config =
212            create_picker_config_with_mocked_date_constraints(builder, date_constraints_mock);
213        assert!(config.is_year_group_forbidden(year));
214    }
215
216    #[test]
217    fn guess_allowed_year_month_with_initial_date() {
218        let initial_date = NaiveDate::from_ymd(2020, 3, 24);
219        let config = PickerConfigBuilder::<MockHasDateConstraints>::default()
220            .initial_date(initial_date)
221            .build()
222            .unwrap();
223        let expected = initial_date;
224        assert_eq!(expected, config.guess_allowed_year_month());
225    }
226}