chrono_datepicker_core/
utils.rs

1use chrono::{Datelike, NaiveDate};
2
3use crate::{
4    config::date_constraints::HasDateConstraints,
5    dialog_view_type::DialogViewType,
6    viewed_date::{year_group_end, year_group_start, ViewedDate},
7};
8
9/// Creates the text that should be the title of the datepicker dialog.
10pub fn create_dialog_title_text(
11    dialog_view_type: &DialogViewType,
12    viewed_date: &NaiveDate,
13    month_title_format: &str,
14) -> String {
15    match dialog_view_type {
16        DialogViewType::Days => viewed_date
17            .first_day_of_month()
18            .format(month_title_format)
19            .to_string(),
20        DialogViewType::Months => viewed_date.first_day_of_month().format("%Y").to_string(),
21        DialogViewType::Years => format!(
22            "{} - {}",
23            year_group_start(viewed_date.year()),
24            year_group_end(viewed_date.year())
25        ),
26    }
27}
28
29/// Returns true if the "previous" button should be displayed.
30pub fn should_display_previous_button<T: HasDateConstraints>(
31    dialog_view_type: &DialogViewType,
32    viewed_date: &NaiveDate,
33    config: &T,
34) -> bool {
35    match dialog_view_type {
36        DialogViewType::Days => !config.is_month_forbidden(&viewed_date.previous_month()),
37        DialogViewType::Months => !config.is_year_forbidden(viewed_date.previous_year().year()),
38        DialogViewType::Years => {
39            !config.is_year_group_forbidden(viewed_date.previous_year_group().year())
40        }
41    }
42}
43
44/// Returns true if the "next" button should be displayed.
45pub fn should_display_next_button<T: HasDateConstraints>(
46    dialog_view_type: &DialogViewType,
47    viewed_date: &NaiveDate,
48    config: &T,
49) -> bool {
50    match dialog_view_type {
51        DialogViewType::Days => !config.is_month_forbidden(&viewed_date.next_month()),
52        DialogViewType::Months => !config.is_year_forbidden(viewed_date.next_year().year()),
53        DialogViewType::Years => {
54            !config.is_year_group_forbidden(viewed_date.next_year_group().year())
55        }
56    }
57}
58
59#[cfg(test)]
60mod tests {
61    use super::*;
62    use crate::{config::date_constraints::MockHasDateConstraints, viewed_date::YearNumber};
63
64    use crate::rstest_utils::create_date;
65    use mockall::predicate;
66    use rstest::*;
67
68    #[rstest(
69        expected, dialog_view_type, viewed_date, month_title_format, //
70        case::days_default("Jan 1990", DialogViewType::Days, create_date(1990, 1, 1), "%b %Y"),
71        case::days_different_format("January 1990", DialogViewType::Days, create_date(1990, 1, 1), "%B %Y"),
72        case::months("1990", DialogViewType::Months, create_date(1990, 1, 1), ""),
73        case::years("1980 - 1999", DialogViewType::Years, create_date(1990, 1, 1), ""),
74    )]
75    fn test_create_dialog_title_text(
76        expected: &str,
77        dialog_view_type: DialogViewType,
78        viewed_date: NaiveDate,
79        month_title_format: &str,
80    ) {
81        assert_eq!(
82            expected,
83            create_dialog_title_text(&dialog_view_type, &viewed_date, month_title_format)
84        );
85    }
86
87    #[fixture(viewed_date=create_date(1990, 1, 1), retval=false)]
88    fn month_forbidden(viewed_date: NaiveDate, retval: bool) -> MockHasDateConstraints {
89        let mut mock = MockHasDateConstraints::new();
90        mock.expect_is_month_forbidden()
91            .with(predicate::eq(viewed_date))
92            .times(1)
93            .returning(move |_| retval);
94        mock
95    }
96
97    #[fixture(year = 1990, retval = false)]
98    fn year_forbidden(year: YearNumber, retval: bool) -> MockHasDateConstraints {
99        let mut mock = MockHasDateConstraints::new();
100        mock.expect_is_year_forbidden()
101            .with(predicate::eq(year))
102            .times(1)
103            .returning(move |_| retval);
104        mock
105    }
106
107    #[fixture(year = 1990, retval = false)]
108    fn year_group_forbidden(year: YearNumber, retval: bool) -> MockHasDateConstraints {
109        let mut mock = MockHasDateConstraints::new();
110        mock.expect_is_year_group_forbidden()
111            .with(predicate::eq(year))
112            .times(1)
113            .returning(move |_| retval);
114        mock
115    }
116
117    #[rstest(
118        expected, dialog_view_type, viewed_date, mock_constraints, //
119        case::month_forbidden(false, DialogViewType::Days, create_date(1990, 2, 16), month_forbidden(create_date(1990, 1, 1), true)),
120        case::month_allowed(true, DialogViewType::Days, create_date(1990, 3, 25), month_forbidden(create_date(1990, 2, 1), false)),
121        case::year_forbidden(false, DialogViewType::Months, create_date(1990, 4, 26), year_forbidden(1989, true)),
122        case::year_allowed(true, DialogViewType::Months, create_date(1990, 7, 18), year_forbidden(1989, false)),
123        case::year_group_forbidden(false, DialogViewType::Years, create_date(1990, 2, 16), year_group_forbidden(1979, true)),
124        case::year_group_allowed(true, DialogViewType::Years, create_date(1990, 2, 18), year_group_forbidden(1979, false)),
125    )]
126    fn test_should_display_previous_button(
127        expected: bool,
128        dialog_view_type: DialogViewType,
129        viewed_date: NaiveDate,
130        mock_constraints: MockHasDateConstraints,
131    ) {
132        assert_eq!(
133            expected,
134            should_display_previous_button(&dialog_view_type, &viewed_date, &mock_constraints)
135        );
136    }
137
138    #[rstest(
139        expected, dialog_view_type, viewed_date, mock_constraints, //
140        case::month_forbidden(false, DialogViewType::Days, create_date(1990, 2, 18), month_forbidden(create_date(1990, 3, 1), true)),
141        case::month_allowed(true, DialogViewType::Days, create_date(1990, 2, 15), month_forbidden(create_date(1990, 3, 1), false)),
142        case::year_forbidden(false, DialogViewType::Months, create_date(1990, 8, 16), year_forbidden(1991, true)),
143        case::year_allowed(true, DialogViewType::Months, create_date(1990, 4, 21), year_forbidden(1991, false)),
144        case::year_group_forbidden(false, DialogViewType::Years, create_date(1990, 11, 26), year_group_forbidden(2000, true)),
145        case::year_group_allowed(true, DialogViewType::Years, create_date(1990, 12, 23), year_group_forbidden(2000, false)),
146    )]
147    fn test_should_display_next_button(
148        expected: bool,
149        dialog_view_type: DialogViewType,
150        viewed_date: NaiveDate,
151        mock_constraints: MockHasDateConstraints,
152    ) {
153        assert_eq!(
154            expected,
155            should_display_next_button(&dialog_view_type, &viewed_date, &mock_constraints)
156        );
157    }
158}