Write tests for all delta steps

This commit is contained in:
Joscha 2021-12-06 01:17:54 +01:00
parent 09f687bea0
commit 32e036f337

View file

@ -7,8 +7,6 @@ use crate::files::primitives::{Span, Spanned, Time, Weekday};
use super::{util, Error, Result};
// TODO Test all these delta steps
/// Like [`commands::DeltaStep`] but includes a new constructor,
/// [`DeltaStep::Time`].
#[derive(Debug, Clone, Copy)]
@ -217,10 +215,20 @@ impl DeltaEval {
}
fn step_month_reverse(&mut self, span: Span, amount: i32) -> Result<()> {
// Offset from the last day of the month
let end_offset = self.curr.day() - util::month_length(self.curr.year(), self.curr.month());
// Calculate offset from the last day of the month
let month_length = util::month_length(self.curr.year(), self.curr.month()) as i32;
let end_offset = self.curr.day() as i32 - month_length;
let (year, month) = util::add_months(self.curr.year(), self.curr.month(), amount);
let day = end_offset + util::month_length(year, month);
// Calculate day based on the offset from earlier
let month_length = util::month_length(year, month) as i32;
let day = if end_offset + month_length > 0 {
(end_offset + month_length) as u32
} else {
return Err(self.err_step(span));
};
match NaiveDate::from_ymd_opt(year, month, day) {
None => Err(self.err_step(span)),
Some(next) => {
@ -318,3 +326,260 @@ impl Delta {
Ok((date, time.expect("time was not preserved")))
}
}
#[cfg(test)]
mod tests {
use chrono::NaiveDate;
use crate::files::primitives::{Span, Spanned, Time};
use super::super::Result;
use super::{Delta, DeltaStep as Step};
const SPAN: Span = Span { start: 12, end: 34 };
fn delta(step: Step) -> Delta {
Delta {
steps: vec![Spanned::new(SPAN, step)],
}
}
fn apply_d(step: Step, from: (i32, u32, u32)) -> Result<NaiveDate> {
delta(step).apply_date(NaiveDate::from_ymd(from.0, from.1, from.2))
}
fn test_d(step: Step, from: (i32, u32, u32), expected: (i32, u32, u32)) {
assert_eq!(
apply_d(step, from).unwrap(),
NaiveDate::from_ymd(expected.0, expected.1, expected.2)
);
}
fn apply_dt(step: Step, from: (i32, u32, u32, u32, u32)) -> Result<(NaiveDate, Time)> {
delta(step).apply_date_time(
NaiveDate::from_ymd(from.0, from.1, from.2),
Time::new(from.3, from.4).unwrap(),
)
}
#[allow(clippy::too_many_arguments)] // This is just for writing tests
fn test_dt(step: Step, from: (i32, u32, u32, u32, u32), expected: (i32, u32, u32, u32, u32)) {
assert_eq!(
apply_dt(step, from).unwrap(),
(
NaiveDate::from_ymd(expected.0, expected.1, expected.2),
Time::new(expected.3, expected.4).unwrap()
)
);
}
#[test]
fn delta_year() {
test_d(Step::Year(-10000), (2021, 7, 3), (-7979, 7, 3));
test_d(Step::Year(-100), (2021, 7, 3), (1921, 7, 3));
test_d(Step::Year(-10), (2021, 7, 3), (2011, 7, 3));
test_d(Step::Year(-2), (2021, 7, 3), (2019, 7, 3));
test_d(Step::Year(-1), (2021, 7, 3), (2020, 7, 3));
test_d(Step::Year(0), (2021, 7, 3), (2021, 7, 3));
test_d(Step::Year(1), (2021, 7, 3), (2022, 7, 3));
test_d(Step::Year(2), (2021, 7, 3), (2023, 7, 3));
test_d(Step::Year(10), (2021, 7, 3), (2031, 7, 3));
test_d(Step::Year(100), (2021, 7, 3), (2121, 7, 3));
test_d(Step::Year(10000), (2021, 7, 3), (12021, 7, 3));
// Leap year shenanigans
test_d(Step::Year(4), (2020, 2, 29), (2024, 2, 29));
test_d(Step::Year(2), (2020, 2, 28), (2022, 2, 28));
test_d(Step::Year(2), (2020, 3, 1), (2022, 3, 1));
test_d(Step::Year(-2), (2022, 2, 28), (2020, 2, 28));
test_d(Step::Year(-2), (2022, 3, 1), (2020, 3, 1));
assert!(apply_d(Step::Year(1), (2020, 2, 29)).is_err());
// Doesn't touch time
test_dt(Step::Year(1), (2021, 7, 3, 12, 34), (2022, 7, 3, 12, 34));
}
#[test]
fn delta_month() {
test_d(Step::Month(-48), (2021, 7, 3), (2017, 7, 3));
test_d(Step::Month(-12), (2021, 7, 3), (2020, 7, 3));
test_d(Step::Month(-2), (2021, 7, 3), (2021, 5, 3));
test_d(Step::Month(-1), (2021, 7, 3), (2021, 6, 3));
test_d(Step::Month(0), (2021, 7, 3), (2021, 7, 3));
test_d(Step::Month(1), (2021, 7, 3), (2021, 8, 3));
test_d(Step::Month(2), (2021, 7, 3), (2021, 9, 3));
test_d(Step::Month(12), (2021, 7, 3), (2022, 7, 3));
// At end of months
test_d(Step::Month(2), (2021, 1, 31), (2021, 3, 31));
test_d(Step::Month(3), (2021, 1, 30), (2021, 4, 30));
assert!(apply_d(Step::Month(1), (2021, 1, 31)).is_err());
// Leap year shenanigans
test_d(Step::Month(1), (2020, 1, 29), (2020, 2, 29));
assert!(apply_d(Step::Month(1), (2021, 1, 29)).is_err());
// Doesn't touch time
test_dt(Step::Month(1), (2021, 7, 3, 12, 34), (2021, 8, 3, 12, 34));
}
#[test]
fn delta_month_reverse() {
test_d(Step::MonthReverse(-48), (2021, 7, 31), (2017, 7, 31));
test_d(Step::MonthReverse(-12), (2021, 7, 31), (2020, 7, 31));
test_d(Step::MonthReverse(-2), (2021, 7, 31), (2021, 5, 31));
test_d(Step::MonthReverse(-1), (2021, 7, 31), (2021, 6, 30));
test_d(Step::MonthReverse(0), (2021, 7, 31), (2021, 7, 31));
test_d(Step::MonthReverse(1), (2021, 7, 31), (2021, 8, 31));
test_d(Step::MonthReverse(2), (2021, 7, 31), (2021, 9, 30));
test_d(Step::MonthReverse(12), (2021, 7, 31), (2022, 7, 31));
// At start of months
test_d(Step::MonthReverse(2), (2021, 1, 1), (2021, 3, 1));
test_d(Step::MonthReverse(3), (2021, 1, 2), (2021, 4, 1));
assert!(apply_d(Step::MonthReverse(1), (2021, 1, 1)).is_err());
// Leap year shenanigans
test_d(Step::MonthReverse(1), (2020, 1, 30), (2020, 2, 28));
test_d(Step::MonthReverse(-1), (2020, 2, 28), (2020, 1, 30));
test_d(Step::MonthReverse(1), (2021, 1, 31), (2021, 2, 28));
test_d(Step::MonthReverse(-1), (2021, 2, 28), (2021, 1, 31));
// Doesn't touch time
test_dt(
Step::MonthReverse(1),
(2021, 7, 3, 12, 34),
(2021, 8, 3, 12, 34),
);
}
#[test]
fn delta_day() {
test_d(Step::Day(-365), (2021, 7, 3), (2020, 7, 3));
test_d(Step::Day(-30), (2021, 7, 3), (2021, 6, 3));
test_d(Step::Day(-2), (2021, 7, 3), (2021, 7, 1));
test_d(Step::Day(-1), (2021, 7, 3), (2021, 7, 2));
test_d(Step::Day(0), (2021, 7, 3), (2021, 7, 3));
test_d(Step::Day(1), (2021, 7, 3), (2021, 7, 4));
test_d(Step::Day(2), (2021, 7, 3), (2021, 7, 5));
test_d(Step::Day(31), (2021, 7, 3), (2021, 8, 3));
test_d(Step::Day(365), (2021, 7, 3), (2022, 7, 3));
// Leap year shenanigans
test_d(Step::Day(1), (2020, 2, 28), (2020, 2, 29));
test_d(Step::Day(1), (2020, 2, 29), (2020, 3, 1));
test_d(Step::Day(1), (2021, 2, 28), (2021, 3, 1));
test_d(Step::Day(-1), (2020, 3, 1), (2020, 2, 29));
test_d(Step::Day(-1), (2020, 2, 29), (2020, 2, 28));
test_d(Step::Day(-1), (2021, 3, 1), (2021, 2, 28));
// Doesn't touch time
test_dt(Step::Day(1), (2021, 7, 3, 12, 34), (2021, 7, 4, 12, 34));
}
#[test]
fn delta_week() {
test_d(Step::Week(-2), (2021, 7, 3), (2021, 6, 19));
test_d(Step::Week(-1), (2021, 7, 3), (2021, 6, 26));
test_d(Step::Week(0), (2021, 7, 3), (2021, 7, 3));
test_d(Step::Week(1), (2021, 7, 3), (2021, 7, 10));
test_d(Step::Week(2), (2021, 7, 3), (2021, 7, 17));
// Leap year shenanigans
test_d(Step::Week(1), (2020, 2, 25), (2020, 3, 3));
test_d(Step::Week(1), (2021, 2, 25), (2021, 3, 4));
// Doesn't touch time
test_dt(Step::Week(1), (2021, 7, 3, 12, 34), (2021, 7, 10, 12, 34));
}
#[test]
fn delta_hour() {
test_dt(Step::Hour(-24), (2021, 7, 3, 12, 34), (2021, 7, 2, 12, 34));
test_dt(Step::Hour(-12), (2021, 7, 3, 12, 34), (2021, 7, 3, 0, 34));
test_dt(Step::Hour(-2), (2021, 7, 3, 12, 34), (2021, 7, 3, 10, 34));
test_dt(Step::Hour(-1), (2021, 7, 3, 12, 34), (2021, 7, 3, 11, 34));
test_dt(Step::Hour(0), (2021, 7, 3, 12, 34), (2021, 7, 3, 12, 34));
test_dt(Step::Hour(1), (2021, 7, 3, 12, 34), (2021, 7, 3, 13, 34));
test_dt(Step::Hour(2), (2021, 7, 3, 12, 34), (2021, 7, 3, 14, 34));
test_dt(Step::Hour(12), (2021, 7, 3, 12, 34), (2021, 7, 4, 0, 34));
test_dt(Step::Hour(24), (2021, 7, 3, 12, 34), (2021, 7, 4, 12, 34));
// 24:00 != 00:00
test_dt(Step::Hour(1), (2021, 7, 3, 23, 0), (2021, 7, 3, 24, 0));
test_dt(Step::Hour(2), (2021, 7, 3, 23, 0), (2021, 7, 4, 1, 0));
test_dt(Step::Hour(-1), (2021, 7, 3, 1, 0), (2021, 7, 3, 0, 0));
test_dt(Step::Hour(-2), (2021, 7, 3, 1, 0), (2021, 7, 2, 23, 0));
// Requires time
assert!(apply_d(Step::Hour(0), (2021, 7, 3)).is_err());
}
#[test]
fn delta_minute() {
test_dt(
Step::Minute(-60 * 24),
(2021, 7, 3, 12, 34),
(2021, 7, 2, 12, 34),
);
test_dt(
Step::Minute(-60),
(2021, 7, 3, 12, 34),
(2021, 7, 3, 11, 34),
);
test_dt(Step::Minute(-2), (2021, 7, 3, 12, 34), (2021, 7, 3, 12, 32));
test_dt(Step::Minute(-1), (2021, 7, 3, 12, 34), (2021, 7, 3, 12, 33));
test_dt(Step::Minute(0), (2021, 7, 3, 12, 34), (2021, 7, 3, 12, 34));
test_dt(Step::Minute(1), (2021, 7, 3, 12, 34), (2021, 7, 3, 12, 35));
test_dt(Step::Minute(2), (2021, 7, 3, 12, 34), (2021, 7, 3, 12, 36));
test_dt(Step::Minute(60), (2021, 7, 3, 12, 34), (2021, 7, 3, 13, 34));
test_dt(
Step::Minute(60 * 24),
(2021, 7, 3, 12, 34),
(2021, 7, 4, 12, 34),
);
// 24:00 != 00:00
test_dt(Step::Minute(1), (2021, 7, 3, 23, 59), (2021, 7, 3, 24, 0));
test_dt(Step::Minute(2), (2021, 7, 3, 23, 59), (2021, 7, 4, 0, 1));
test_dt(Step::Minute(-1), (2021, 7, 3, 0, 1), (2021, 7, 3, 0, 0));
test_dt(Step::Minute(-2), (2021, 7, 3, 0, 1), (2021, 7, 2, 23, 59));
// Requires time
assert!(apply_d(Step::Minute(0), (2021, 7, 3)).is_err());
}
#[test]
fn delta_time() {
test_dt(
Step::Time(Time::new(12, 33).unwrap()),
(2021, 7, 3, 12, 34),
(2021, 7, 4, 12, 33),
);
test_dt(
Step::Time(Time::new(12, 34).unwrap()),
(2021, 7, 3, 12, 34),
(2021, 7, 3, 12, 34),
);
test_dt(
Step::Time(Time::new(12, 35).unwrap()),
(2021, 7, 3, 12, 34),
(2021, 7, 3, 12, 35),
);
// 24:00 != 00:00
test_dt(
Step::Time(Time::new(24, 0).unwrap()),
(2021, 7, 3, 12, 0),
(2021, 7, 3, 24, 0),
);
test_dt(
Step::Time(Time::new(0, 0).unwrap()),
(2021, 7, 3, 12, 0),
(2021, 7, 4, 0, 0),
);
// Requires time
assert!(apply_d(Step::Time(Time::new(12, 34).unwrap()), (2021, 7, 3)).is_err());
}
}