mirror of
https://github.com/SeCherkasov/util-linux-cal.git
synced 2026-03-29 23:51:07 +03:00
701 lines
19 KiB
Rust
701 lines
19 KiB
Rust
//! Integration tests for calendar calculation logic.
|
||
|
||
use chrono::Weekday;
|
||
use unicode_width::UnicodeWidthStr;
|
||
|
||
use cal::formatter::parse_month;
|
||
use cal::types::{CalContext, ColumnsMode, MonthData, ReformType, WeekType};
|
||
|
||
fn test_context() -> CalContext {
|
||
CalContext {
|
||
reform_year: ReformType::Year1752.reform_year(),
|
||
week_start: Weekday::Mon,
|
||
julian: false,
|
||
week_numbers: false,
|
||
week_type: WeekType::Iso,
|
||
color: false,
|
||
vertical: false,
|
||
today: chrono::NaiveDate::from_ymd_opt(2026, 2, 18).unwrap(),
|
||
show_year_in_header: true,
|
||
gutter_width: 2,
|
||
columns: ColumnsMode::Auto,
|
||
span: false,
|
||
#[cfg(feature = "plugins")]
|
||
holidays: false,
|
||
}
|
||
}
|
||
|
||
fn julian_context() -> CalContext {
|
||
CalContext {
|
||
reform_year: ReformType::Julian.reform_year(),
|
||
..test_context()
|
||
}
|
||
}
|
||
|
||
fn gregorian_context() -> CalContext {
|
||
CalContext {
|
||
reform_year: ReformType::Gregorian.reform_year(),
|
||
..test_context()
|
||
}
|
||
}
|
||
|
||
mod leap_year_tests {
|
||
use super::*;
|
||
|
||
#[test]
|
||
fn test_gregorian_leap_year_divisible_by_400() {
|
||
let ctx = gregorian_context();
|
||
assert!(ctx.is_leap_year(2000));
|
||
assert!(ctx.is_leap_year(2400));
|
||
}
|
||
|
||
#[test]
|
||
fn test_gregorian_leap_year_divisible_by_4_not_100() {
|
||
let ctx = gregorian_context();
|
||
assert!(ctx.is_leap_year(2024));
|
||
assert!(ctx.is_leap_year(2028));
|
||
assert!(!ctx.is_leap_year(2023));
|
||
assert!(!ctx.is_leap_year(2025));
|
||
}
|
||
|
||
#[test]
|
||
fn test_gregorian_not_leap_year_divisible_by_100() {
|
||
let ctx = gregorian_context();
|
||
assert!(!ctx.is_leap_year(1900));
|
||
assert!(!ctx.is_leap_year(2100));
|
||
}
|
||
|
||
#[test]
|
||
fn test_julian_leap_year() {
|
||
let ctx = julian_context();
|
||
assert!(ctx.is_leap_year(2024));
|
||
assert!(ctx.is_leap_year(2028));
|
||
assert!(ctx.is_leap_year(1900));
|
||
assert!(!ctx.is_leap_year(2023));
|
||
}
|
||
|
||
#[test]
|
||
fn test_year_1752_leap_year() {
|
||
let ctx = test_context();
|
||
assert!(ctx.is_leap_year(1752));
|
||
}
|
||
}
|
||
|
||
mod days_in_month_tests {
|
||
use super::*;
|
||
|
||
#[test]
|
||
fn test_31_day_months() {
|
||
let ctx = test_context();
|
||
for month in [1, 3, 5, 7, 8, 10, 12] {
|
||
assert_eq!(ctx.days_in_month(2024, month), 31);
|
||
}
|
||
}
|
||
|
||
#[test]
|
||
fn test_30_day_months() {
|
||
let ctx = test_context();
|
||
for month in [4, 6, 9, 11] {
|
||
assert_eq!(ctx.days_in_month(2024, month), 30);
|
||
}
|
||
}
|
||
|
||
#[test]
|
||
fn test_february_leap_year() {
|
||
let ctx = test_context();
|
||
assert_eq!(ctx.days_in_month(2024, 2), 29);
|
||
assert_eq!(ctx.days_in_month(2028, 2), 29);
|
||
}
|
||
|
||
#[test]
|
||
fn test_february_non_leap_year() {
|
||
let ctx = test_context();
|
||
assert_eq!(ctx.days_in_month(2023, 2), 28);
|
||
assert_eq!(ctx.days_in_month(2025, 2), 28);
|
||
}
|
||
}
|
||
|
||
mod first_day_tests {
|
||
use super::*;
|
||
|
||
#[test]
|
||
fn test_first_day_known_dates() {
|
||
let ctx = test_context();
|
||
|
||
assert_eq!(ctx.first_day_of_month(2024, 1), Weekday::Mon);
|
||
assert_eq!(ctx.first_day_of_month(2025, 1), Weekday::Wed);
|
||
assert_eq!(ctx.first_day_of_month(2024, 2), Weekday::Thu);
|
||
}
|
||
|
||
#[test]
|
||
fn test_first_day_september_1752() {
|
||
let ctx = test_context();
|
||
assert_eq!(ctx.first_day_of_month(1752, 9), Weekday::Fri);
|
||
}
|
||
}
|
||
|
||
mod reform_gap_tests {
|
||
use super::*;
|
||
|
||
#[test]
|
||
fn test_reform_gap_detection() {
|
||
let ctx = test_context();
|
||
|
||
assert!(ctx.is_reform_gap(1752, 9, 3));
|
||
assert!(ctx.is_reform_gap(1752, 9, 13));
|
||
assert!(ctx.is_reform_gap(1752, 9, 8));
|
||
|
||
assert!(!ctx.is_reform_gap(1752, 9, 2));
|
||
assert!(!ctx.is_reform_gap(1752, 9, 14));
|
||
|
||
assert!(!ctx.is_reform_gap(1752, 8, 5));
|
||
assert!(!ctx.is_reform_gap(1752, 10, 5));
|
||
assert!(!ctx.is_reform_gap(1751, 9, 5));
|
||
}
|
||
|
||
#[test]
|
||
fn test_no_reform_gap_gregorian() {
|
||
let ctx = gregorian_context();
|
||
assert!(!ctx.is_reform_gap(1752, 9, 5));
|
||
}
|
||
|
||
#[test]
|
||
fn test_no_reform_gap_julian() {
|
||
let ctx = julian_context();
|
||
assert!(!ctx.is_reform_gap(1752, 9, 5));
|
||
}
|
||
}
|
||
|
||
mod day_of_year_tests {
|
||
use super::*;
|
||
|
||
#[test]
|
||
fn test_day_of_year_non_leap() {
|
||
let ctx = test_context();
|
||
|
||
assert_eq!(ctx.day_of_year(2023, 1, 1), 1);
|
||
assert_eq!(ctx.day_of_year(2023, 1, 31), 31);
|
||
assert_eq!(ctx.day_of_year(2023, 2, 1), 32);
|
||
assert_eq!(ctx.day_of_year(2023, 12, 31), 365);
|
||
}
|
||
|
||
#[test]
|
||
fn test_day_of_year_leap() {
|
||
let ctx = test_context();
|
||
|
||
assert_eq!(ctx.day_of_year(2024, 1, 1), 1);
|
||
assert_eq!(ctx.day_of_year(2024, 2, 29), 60);
|
||
assert_eq!(ctx.day_of_year(2024, 3, 1), 61);
|
||
assert_eq!(ctx.day_of_year(2024, 12, 31), 366);
|
||
}
|
||
|
||
#[test]
|
||
fn test_day_of_year_reform_gap() {
|
||
let ctx = test_context();
|
||
|
||
assert_eq!(ctx.day_of_year(1752, 9, 2), 235);
|
||
assert_eq!(ctx.day_of_year(1752, 9, 14), 247);
|
||
}
|
||
}
|
||
|
||
mod month_data_tests {
|
||
use super::*;
|
||
|
||
#[test]
|
||
fn test_month_data_january_2024() {
|
||
let ctx = test_context();
|
||
let month = MonthData::new(&ctx, 2024, 1);
|
||
|
||
assert_eq!(month.year, 2024);
|
||
assert_eq!(month.month, 1);
|
||
assert_eq!(month.days.len(), 42);
|
||
|
||
// January 2024 starts on Monday
|
||
assert_eq!(month.days[0], Some(1));
|
||
assert_eq!(month.days[30], Some(31));
|
||
assert_eq!(month.days[31], None);
|
||
}
|
||
|
||
#[test]
|
||
fn test_month_data_february_2024_leap() {
|
||
let ctx = test_context();
|
||
let month = MonthData::new(&ctx, 2024, 2);
|
||
|
||
// February 2024 starts on Thursday
|
||
assert_eq!(month.days[0], None);
|
||
assert_eq!(month.days[1], None);
|
||
assert_eq!(month.days[2], None);
|
||
assert_eq!(month.days[3], Some(1));
|
||
assert_eq!(month.days[31], Some(29));
|
||
}
|
||
|
||
#[test]
|
||
fn test_month_data_september_1752_reform() {
|
||
let ctx = test_context();
|
||
let month = MonthData::new(&ctx, 1752, 9);
|
||
|
||
assert!(month.days.contains(&Some(2)));
|
||
assert!(!month.days.contains(&Some(3)));
|
||
assert!(!month.days.contains(&Some(13)));
|
||
assert!(month.days.contains(&Some(14)));
|
||
}
|
||
|
||
#[test]
|
||
fn test_month_data_weekday_alignment() {
|
||
let ctx = test_context();
|
||
|
||
for month in 1..=12 {
|
||
let month_data = MonthData::new(&ctx, 2024, month);
|
||
|
||
for (i, day) in month_data.days.iter().enumerate() {
|
||
if day.is_some() {
|
||
assert!(month_data.weekdays[i].is_some());
|
||
} else {
|
||
assert!(month_data.weekdays[i].is_none());
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
mod weekend_tests {
|
||
use super::*;
|
||
|
||
#[test]
|
||
fn test_is_weekend() {
|
||
let ctx = test_context();
|
||
|
||
assert!(ctx.is_weekend(Weekday::Sat));
|
||
assert!(ctx.is_weekend(Weekday::Sun));
|
||
assert!(!ctx.is_weekend(Weekday::Mon));
|
||
assert!(!ctx.is_weekend(Weekday::Tue));
|
||
assert!(!ctx.is_weekend(Weekday::Wed));
|
||
assert!(!ctx.is_weekend(Weekday::Thu));
|
||
assert!(!ctx.is_weekend(Weekday::Fri));
|
||
}
|
||
}
|
||
|
||
mod week_number_tests {
|
||
use super::*;
|
||
|
||
#[test]
|
||
fn test_iso_week_number() {
|
||
let mut ctx = test_context();
|
||
ctx.week_type = WeekType::Iso;
|
||
|
||
assert_eq!(ctx.week_number(2024, 1, 1), 1);
|
||
|
||
let week = ctx.week_number(2024, 12, 30);
|
||
assert!(week == 1 || week == 53);
|
||
}
|
||
|
||
#[test]
|
||
fn test_us_week_number() {
|
||
let mut ctx = test_context();
|
||
ctx.week_type = WeekType::Us;
|
||
|
||
assert_eq!(ctx.week_number(2024, 1, 1), 1);
|
||
}
|
||
}
|
||
|
||
mod context_validation_tests {
|
||
use super::*;
|
||
use cal::args::Args;
|
||
use clap::Parser;
|
||
|
||
#[test]
|
||
fn test_context_creation_default() {
|
||
let args = Args::parse_from(["cal"]);
|
||
let ctx = CalContext::new(&args);
|
||
assert!(ctx.is_ok());
|
||
}
|
||
|
||
#[test]
|
||
fn test_context_creation_with_options() {
|
||
let args = Args::parse_from(["cal", "-y", "-j", "-w"]);
|
||
let ctx = CalContext::new(&args);
|
||
assert!(ctx.is_ok());
|
||
let ctx = ctx.unwrap();
|
||
assert!(ctx.julian);
|
||
assert!(ctx.week_numbers);
|
||
}
|
||
|
||
#[test]
|
||
fn test_context_mutually_exclusive_options() {
|
||
let args = Args::parse_from(["cal", "-y", "-n", "5"]);
|
||
let result = CalContext::new(&args);
|
||
assert!(result.is_err());
|
||
let err = result.unwrap_err();
|
||
assert!(err.contains("mutually exclusive"));
|
||
}
|
||
|
||
#[test]
|
||
fn test_context_invalid_columns() {
|
||
let args = Args::parse_from(["cal", "-c", "0"]);
|
||
assert!(CalContext::new(&args).is_err());
|
||
|
||
let args = Args::parse_from(["cal", "-c", "abc"]);
|
||
assert!(CalContext::new(&args).is_err());
|
||
}
|
||
|
||
#[test]
|
||
fn test_context_sunday_start() {
|
||
let args = Args::parse_from(["cal", "-s"]);
|
||
let ctx = CalContext::new(&args).unwrap();
|
||
assert_eq!(ctx.week_start, Weekday::Sun);
|
||
}
|
||
|
||
#[test]
|
||
fn test_context_color_settings() {
|
||
let args = Args::parse_from(["cal"]);
|
||
let ctx = CalContext::new(&args).unwrap();
|
||
assert!(!ctx.color);
|
||
|
||
let args = Args::parse_from(["cal", "--color"]);
|
||
let ctx = CalContext::new(&args).unwrap();
|
||
assert!(!ctx.color);
|
||
}
|
||
|
||
#[test]
|
||
fn test_context_reform_types() {
|
||
let args = Args::parse_from(["cal", "--reform", "gregorian"]);
|
||
let ctx = CalContext::new(&args).unwrap();
|
||
assert_eq!(ctx.reform_year, i32::MIN);
|
||
|
||
let args = Args::parse_from(["cal", "--reform", "julian"]);
|
||
let ctx = CalContext::new(&args).unwrap();
|
||
assert_eq!(ctx.reform_year, i32::MAX);
|
||
|
||
let args = Args::parse_from(["cal", "--iso"]);
|
||
let ctx = CalContext::new(&args).unwrap();
|
||
assert_eq!(ctx.reform_year, i32::MIN);
|
||
}
|
||
}
|
||
|
||
mod parse_month_tests {
|
||
use super::*;
|
||
|
||
#[test]
|
||
fn test_parse_month_numeric() {
|
||
for (input, expected) in [
|
||
("1", Some(1)),
|
||
("2", Some(2)),
|
||
("12", Some(12)),
|
||
("0", None),
|
||
("13", None),
|
||
("abc", None),
|
||
] {
|
||
assert_eq!(parse_month(input), expected, "Failed for input: {}", input);
|
||
}
|
||
}
|
||
|
||
#[test]
|
||
fn test_parse_month_english_names() {
|
||
assert_eq!(parse_month("january"), Some(1));
|
||
assert_eq!(parse_month("January"), Some(1));
|
||
assert_eq!(parse_month("JANUARY"), Some(1));
|
||
assert_eq!(parse_month("february"), Some(2));
|
||
assert_eq!(parse_month("december"), Some(12));
|
||
}
|
||
|
||
#[test]
|
||
fn test_parse_month_english_short() {
|
||
assert_eq!(parse_month("jan"), Some(1));
|
||
assert_eq!(parse_month("feb"), Some(2));
|
||
assert_eq!(parse_month("mar"), Some(3));
|
||
assert_eq!(parse_month("apr"), Some(4));
|
||
assert_eq!(parse_month("jun"), Some(6));
|
||
assert_eq!(parse_month("jul"), Some(7));
|
||
assert_eq!(parse_month("aug"), Some(8));
|
||
assert_eq!(parse_month("sep"), Some(9));
|
||
assert_eq!(parse_month("oct"), Some(10));
|
||
assert_eq!(parse_month("nov"), Some(11));
|
||
assert_eq!(parse_month("dec"), Some(12));
|
||
}
|
||
|
||
#[test]
|
||
fn test_parse_month_russian() {
|
||
assert_eq!(parse_month("январь"), Some(1));
|
||
assert_eq!(parse_month("февраль"), Some(2));
|
||
assert_eq!(parse_month("декабрь"), Some(12));
|
||
}
|
||
}
|
||
|
||
mod layout_tests {
|
||
use super::*;
|
||
use cal::formatter::{
|
||
format_month_grid, format_month_header, format_weekday_headers, get_weekday_order,
|
||
};
|
||
|
||
#[test]
|
||
fn test_month_header_format() {
|
||
let header = format_month_header(2026, 2, 20, true, false);
|
||
assert!(header.contains("Февраль"));
|
||
assert!(header.contains("2026"));
|
||
assert!(header.width() >= 20);
|
||
}
|
||
|
||
#[test]
|
||
fn test_month_header_without_year() {
|
||
let header = format_month_header(2026, 2, 20, false, false);
|
||
assert!(header.contains("Февраль"));
|
||
assert!(!header.contains("2026"));
|
||
}
|
||
|
||
#[test]
|
||
fn test_month_header_with_color() {
|
||
let header = format_month_header(2026, 2, 20, true, true);
|
||
assert!(header.contains("\x1b[96m"));
|
||
assert!(header.contains("\x1b[0m"));
|
||
}
|
||
|
||
#[test]
|
||
fn test_weekday_header_structure_monday_start() {
|
||
let ctx = test_context();
|
||
let header = format_weekday_headers(&ctx, false);
|
||
|
||
assert!(header.contains("Пн"));
|
||
assert!(header.contains("Вт"));
|
||
assert!(header.contains("Ср"));
|
||
assert!(header.contains("Чт"));
|
||
assert!(header.contains("Пт"));
|
||
assert!(header.contains("Сб"));
|
||
assert!(header.contains("Вс"));
|
||
|
||
let mon_pos = header.find("Пн").unwrap();
|
||
let tue_pos = header.find("Вт").unwrap();
|
||
assert!(mon_pos < tue_pos);
|
||
}
|
||
|
||
#[test]
|
||
fn test_weekday_header_structure_sunday_start() {
|
||
let mut ctx = test_context();
|
||
ctx.week_start = chrono::Weekday::Sun;
|
||
let header = format_weekday_headers(&ctx, false);
|
||
|
||
let sun_pos = header.find("Вс").unwrap();
|
||
let mon_pos = header.find("Пн").unwrap();
|
||
assert!(sun_pos < mon_pos);
|
||
}
|
||
|
||
#[test]
|
||
fn test_weekday_header_with_week_numbers() {
|
||
let mut ctx = test_context();
|
||
ctx.week_numbers = true;
|
||
let header = format_weekday_headers(&ctx, false);
|
||
assert!(header.len() > 20);
|
||
}
|
||
|
||
#[test]
|
||
fn test_weekday_header_with_julian() {
|
||
let mut ctx = test_context();
|
||
ctx.julian = true;
|
||
let header = format_weekday_headers(&ctx, false);
|
||
assert!(header.starts_with(" "));
|
||
}
|
||
|
||
#[test]
|
||
fn test_month_grid_line_count() {
|
||
let ctx = test_context();
|
||
let month = MonthData::new(&ctx, 2024, 1);
|
||
let grid = format_month_grid(&ctx, &month);
|
||
|
||
assert!(grid.len() >= 8);
|
||
assert!(grid.len() <= 9);
|
||
}
|
||
|
||
#[test]
|
||
fn test_month_grid_first_line_is_header() {
|
||
let ctx = test_context();
|
||
let month = MonthData::new(&ctx, 2024, 1);
|
||
let grid = format_month_grid(&ctx, &month);
|
||
|
||
assert!(grid[0].contains("Январь"));
|
||
assert!(grid[0].contains("2024"));
|
||
}
|
||
|
||
#[test]
|
||
fn test_month_grid_second_line_is_weekdays() {
|
||
let ctx = test_context();
|
||
let month = MonthData::new(&ctx, 2024, 1);
|
||
let grid = format_month_grid(&ctx, &month);
|
||
|
||
assert!(grid[1].contains("Пн"));
|
||
}
|
||
|
||
#[test]
|
||
fn test_month_grid_contains_day_1() {
|
||
let ctx = test_context();
|
||
let month = MonthData::new(&ctx, 2024, 1);
|
||
let grid = format_month_grid(&ctx, &month);
|
||
|
||
let days_area: String = grid[2..].join("\n");
|
||
assert!(days_area.contains(" 1"));
|
||
}
|
||
|
||
#[test]
|
||
fn test_month_grid_contains_last_day() {
|
||
let ctx = test_context();
|
||
let month = MonthData::new(&ctx, 2024, 1);
|
||
let grid = format_month_grid(&ctx, &month);
|
||
|
||
let days_area: String = grid[2..].join("\n");
|
||
assert!(days_area.contains("31"));
|
||
}
|
||
|
||
#[test]
|
||
fn test_month_grid_february_leap_year() {
|
||
let ctx = test_context();
|
||
let month = MonthData::new(&ctx, 2024, 2);
|
||
let grid = format_month_grid(&ctx, &month);
|
||
|
||
let days_area: String = grid[2..].join("\n");
|
||
assert!(days_area.contains("29"));
|
||
}
|
||
|
||
#[test]
|
||
fn test_month_grid_february_non_leap_year() {
|
||
let ctx = test_context();
|
||
let month = MonthData::new(&ctx, 2023, 2);
|
||
let grid = format_month_grid(&ctx, &month);
|
||
|
||
let days_area: String = grid[2..].join("\n");
|
||
assert!(days_area.contains("28"));
|
||
assert!(!days_area.contains("29"));
|
||
}
|
||
|
||
#[test]
|
||
fn test_vertical_layout_weekday_order() {
|
||
let ctx = test_context();
|
||
let weekday_order = get_weekday_order(ctx.week_start);
|
||
|
||
assert_eq!(weekday_order[0], chrono::Weekday::Mon);
|
||
assert_eq!(weekday_order[6], chrono::Weekday::Sun);
|
||
}
|
||
|
||
#[test]
|
||
fn test_vertical_layout_days_in_columns() {
|
||
let ctx = test_context();
|
||
let month = MonthData::new(&ctx, 2024, 1);
|
||
|
||
let day1_pos = month.days.iter().position(|&d| d == Some(1)).unwrap();
|
||
let day8_pos = month.days.iter().position(|&d| d == Some(8)).unwrap();
|
||
|
||
assert_eq!(day8_pos - day1_pos, 7);
|
||
}
|
||
|
||
#[test]
|
||
fn test_three_months_structure() {
|
||
let ctx = test_context();
|
||
let prev = MonthData::new(&ctx, 2024, 1);
|
||
let curr = MonthData::new(&ctx, 2024, 2);
|
||
let next = MonthData::new(&ctx, 2024, 3);
|
||
|
||
assert_eq!(prev.month, 1);
|
||
assert_eq!(curr.month, 2);
|
||
assert_eq!(next.month, 3);
|
||
}
|
||
|
||
#[test]
|
||
fn test_three_months_year_boundary() {
|
||
let ctx = test_context();
|
||
|
||
let prev = MonthData::new(&ctx, 2023, 12);
|
||
let curr = MonthData::new(&ctx, 2024, 1);
|
||
let next = MonthData::new(&ctx, 2024, 2);
|
||
|
||
assert_eq!(prev.year, 2023);
|
||
assert_eq!(curr.year, 2024);
|
||
assert_eq!(next.year, 2024);
|
||
}
|
||
|
||
#[test]
|
||
fn test_color_codes_in_header() {
|
||
let header = format_month_header(2024, 1, 20, true, true);
|
||
assert!(header.starts_with("\x1b[96m"));
|
||
assert!(header.ends_with("\x1b[0m"));
|
||
}
|
||
|
||
#[test]
|
||
fn test_no_color_codes_when_disabled() {
|
||
let header = format_month_header(2024, 1, 20, true, false);
|
||
assert!(!header.contains("\x1b[96m"));
|
||
assert!(!header.contains("\x1b[0m"));
|
||
}
|
||
|
||
#[test]
|
||
fn test_weekday_header_color_placement() {
|
||
let mut ctx = test_context();
|
||
ctx.color = true;
|
||
let header = format_weekday_headers(&ctx, false);
|
||
|
||
assert!(header.starts_with("\x1b[93m"));
|
||
assert!(header.ends_with("\x1b[0m"));
|
||
}
|
||
|
||
#[test]
|
||
fn test_weekday_header_no_color_when_disabled() {
|
||
let mut ctx = test_context();
|
||
ctx.color = false;
|
||
let header = format_weekday_headers(&ctx, false);
|
||
|
||
assert!(!header.contains("\x1b[93m"));
|
||
assert!(!header.contains("\x1b[0m"));
|
||
}
|
||
|
||
#[test]
|
||
fn test_header_width_consistency() {
|
||
let width = 20;
|
||
let header1 = format_month_header(2024, 1, width, true, false);
|
||
let header2 = format_month_header(2024, 12, width, true, false);
|
||
|
||
assert_eq!(header1.width(), width);
|
||
assert_eq!(header2.width(), width);
|
||
}
|
||
|
||
#[test]
|
||
fn test_day_alignment_in_grid() {
|
||
let ctx = test_context();
|
||
let month = MonthData::new(&ctx, 2024, 1);
|
||
let grid = format_month_grid(&ctx, &month);
|
||
|
||
let expected_width = grid[2].width();
|
||
for (i, line) in grid.iter().enumerate().skip(2) {
|
||
assert_eq!(
|
||
line.width(),
|
||
expected_width,
|
||
"Line {} has inconsistent width",
|
||
i
|
||
);
|
||
}
|
||
}
|
||
}
|
||
|
||
mod get_display_date_tests {
|
||
use cal::args::{Args, get_display_date};
|
||
use clap::Parser;
|
||
|
||
#[test]
|
||
fn test_single_year_argument() {
|
||
let args = Args::parse_from(["cal", "2026"]);
|
||
let (year, _month, day) = get_display_date(&args).unwrap();
|
||
assert_eq!(year, 2026);
|
||
assert_eq!(day, None);
|
||
}
|
||
|
||
#[test]
|
||
fn test_single_month_argument() {
|
||
let args = Args::parse_from(["cal", "2"]);
|
||
let (_year, month, _day) = get_display_date(&args).unwrap();
|
||
assert_eq!(month, 2);
|
||
}
|
||
|
||
#[test]
|
||
fn test_month_year_arguments() {
|
||
let args = Args::parse_from(["cal", "2", "2026"]);
|
||
let (year, month, _day) = get_display_date(&args).unwrap();
|
||
assert_eq!(year, 2026);
|
||
assert_eq!(month, 2);
|
||
}
|
||
}
|