use crate::{
Point,
Span,
real::Scale,
Frame,
utc,
};
use crate::calendar::{
Calendar,
Utc,
Weekday
};
use crate::calendar::zone::{
Shift,
Unsteady
};
struct FakeUnsteady;
impl Shift for FakeUnsteady {
fn apply(&self, point: Point) -> Point {point}
}
impl Unsteady for FakeUnsteady {
fn revert_to_earliest(&self, point: Point) -> Point {point}
}
fn floor_check(case: Point, expected: Point, scale: Scale) {
let received = Calendar(Utc).date_floor(scale, case);
assert_eq!(
expected,
received,
"\n{} by {:?} should round down to {} but received {}",
Utc::lookup(case),
scale,
Utc::lookup(expected),
Utc::lookup(received)
)
}
fn fmt_frame<Z: Shift>(cal: &Calendar<Z>, frame: Frame) -> String {
let start = cal.lookup(frame.start);
let stop = cal.lookup(frame.stop);
format!("{start} → {stop}")
}
#[test]
fn date_floor() {
use crate::Span;
const JAN_1_UTC: Point = utc!(2020-01-01);
const JAN_2_UTC: Point = utc!(2020-01-02);
const JAN_31_UTC: Point = utc!(2020-01-31);
const DEC_31_UTC: Point = utc!(2020-12-31);
for scale in [Scale::Years, Scale::Months] {
floor_check(JAN_1_UTC, JAN_1_UTC, scale);
floor_check(JAN_2_UTC, JAN_1_UTC, scale);
floor_check(JAN_31_UTC, JAN_1_UTC, scale);
}
floor_check(DEC_31_UTC, JAN_1_UTC, Scale::Years);
let all_scales = [
Scale::Years,
Scale::Months,
Scale::Weeks,
Scale::Days,
Scale::Hours,
Scale::Minutes,
Scale::Seconds
];
const JAN_1_UTC_2018: Point = utc!(2018-01-01);
for scale in all_scales {
floor_check(JAN_1_UTC_2018, JAN_1_UTC_2018, scale);
}
const JAN_3_UTC: Point = utc!(2022-01-03);
for days in 0..6 {
let weekday = JAN_3_UTC + Span::from(Scale::Days) * days;
floor_check(weekday, JAN_3_UTC, Scale::Weeks);
}
const SEP_12_UTC: Point = utc!(2022-09-12);
for days in 0..6 {
let weekday = SEP_12_UTC + Span::from(Scale::Days) * days;
floor_check(weekday, SEP_12_UTC, Scale::Weeks);
}
}
#[test]
fn weekday() {
use Weekday::*;
let cases = [
(utc!(1969-12-29), Monday),
(utc!(1969-12-30), Tuesday),
(utc!(1969-12-31), Wednesday),
(utc!(1970-01-01), Thursday),
(utc!(1970-01-02), Friday),
(utc!(1970-01-03), Saturday),
(utc!(1970-01-04), Sunday),
(utc!(2018-01-01), Monday),
(utc!(2018-01-02), Tuesday),
(utc!(2018-01-03), Wednesday),
(utc!(2018-01-04), Thursday),
(utc!(2018-01-05), Friday),
(utc!(2018-01-06), Saturday),
(utc!(2018-01-07), Sunday),
(utc!(2018-01-08), Monday),
];
for (point, day) in cases {
assert_eq!(day, Calendar(Utc).weekday(point));
}
}
#[test]
fn frames() {
let cal = Calendar(FakeUnsteady);
let frames = cal.frames(Scale::Weeks, Point::now());
for f @ Frame {start, stop} in frames.take(10) {
assert_eq!(cal.weekday(start), Weekday::Monday);
assert_eq!(cal.weekday(stop), Weekday::Monday);
assert_eq!(f.span(), Scale::Weeks.into());
let start = cal.lookup(start);
let stop = cal.lookup(stop);
assert_eq!(start.1.as_seconds(), 0);
assert_eq!(stop.1.as_seconds(), 0);
println!("{start} → {stop}");
}
let all_scales_and_spans = [
(Scale::Years, &[Span::DAY * 365, Span::DAY * 366][..]),
(
Scale::Months,
&[
Span::DAY * 28,
Span::DAY * 29,
Span::DAY * 30,
Span::DAY * 31
]
),
(Scale::Weeks, &[Span::WEEK]),
(Scale::Days, &[Span::DAY]),
(Scale::Hours, &[Span::HOUR]),
(Scale::Minutes, &[Span::MINUTE]),
(Scale::Seconds, &[Span::SECOND])
];
for (scale, valid_spans) in all_scales_and_spans {
println!("\nScale: {scale:12?} | Start: {}", cal.lookup(Point::now()));
let mut frames = cal.frames(scale, Point::now());
assert_eq!(
frames.next().unwrap(),
frames.prev(),
"next != prev for Scale::{scale:?}"
);
let _ = frames.next();
assert_eq!(
frames.next().unwrap(),
frames.prev(),
"next != prev for Scale::{scale:?}"
);
let _ = frames.prev();
for (i, f @ Frame {start, stop}) in frames.take(10).enumerate() {
println!("{i} | {}", fmt_frame(&cal, f));
assert!(
valid_spans.contains(&f.span()),
"Incorrect frame duration {}",
f.span()
);
assert_eq!(
cal.date_floor_earliest(scale, start),
start,
"\nstart isn't date_floored: got {}, date_floor {}",
cal.lookup(start),
cal.lookup(cal.date_floor_earliest(scale, start))
);
assert_eq!(
cal.date_floor_earliest(scale, stop),
stop,
"\nstop isn't date_floored: got {}, date_floor {}",
cal.lookup(stop),
cal.lookup(cal.date_floor_earliest(scale, stop))
);
}
}
}
#[test]
fn frames_rev() {
let cal = Calendar(FakeUnsteady);
let frames = cal.frames(Scale::Weeks, Point::now()).rev();
for f @ Frame {start, stop} in frames.take(10) {
assert_eq!(cal.weekday(start), Weekday::Monday);
assert_eq!(cal.weekday(stop), Weekday::Monday);
assert_eq!(f.span(), Scale::Weeks.into());
let start = cal.lookup(start);
let stop = cal.lookup(stop);
assert_eq!(start.1.as_seconds(), 0);
assert_eq!(stop.1.as_seconds(), 0);
println!("{start} → {stop}");
}
let all_scales_and_spans = [
(Scale::Years, &[Span::DAY * 365, Span::DAY * 366][..]),
(
Scale::Months,
&[
Span::DAY * 28,
Span::DAY * 29,
Span::DAY * 30,
Span::DAY * 31
]
),
(Scale::Weeks, &[Span::WEEK]),
(Scale::Days, &[Span::DAY]),
(Scale::Hours, &[Span::HOUR]),
(Scale::Minutes, &[Span::MINUTE]),
(Scale::Seconds, &[Span::SECOND])
];
for (scale, valid_spans) in all_scales_and_spans {
println!("\nScale: {scale:12?} | Start: {}", cal.lookup(Point::now()));
let frames = cal.frames(scale, Point::now()).rev();
for (i, f @ Frame {start, stop}) in frames.take(10).enumerate() {
println!("{i} | {}", fmt_frame(&cal, f));
assert!(
valid_spans.contains(&f.span()),
"Incorrect frame duration {}",
f.span()
);
assert_eq!(
cal.date_floor_earliest(scale, start),
start,
"\nstart isn't date_floored: got {}, date_floor {}",
cal.lookup(start),
cal.lookup(cal.date_floor_earliest(scale, start))
);
assert_eq!(
cal.date_floor_earliest(scale, stop),
stop,
"\nstop isn't date_floored: got {}, date_floor {}",
cal.lookup(stop),
cal.lookup(cal.date_floor_earliest(scale, stop))
);
}
}
}