feat: add unit tests

This commit is contained in:
Airenas Vaiciunas 2024-03-18 20:45:41 +02:00 committed by Nikolas Schmidt-Voigt
parent a5f06ab7d1
commit 4b8abdb4e1
4 changed files with 227 additions and 12 deletions

View file

@ -1,4 +1,5 @@
use anyhow::Result;
use chrono::Local;
use crate::data::activity;
use crate::data::activity::Activity;
@ -26,6 +27,8 @@ pub fn show_status(
filtered_activities.sort_by_key(|activity| activity.start);
let now = Local::now().naive_local();
let current: Option<&Activity> = filtered_activities
.clone()
.into_iter()
@ -36,20 +39,20 @@ pub fn show_status(
let today = filtered_activities
.clone()
.into_iter()
.filter(Filters::today())
.filter(Filters::today(now.date()))
.map(|f| f.get_duration())
.sum();
let current_week = filtered_activities
.clone()
.into_iter()
.filter(Filters::current_week())
.filter(Filters::current_week(now.date()))
.map(|f| f.get_duration())
.sum();
let current_month = filtered_activities
.into_iter()
.filter(Filters::current_month())
.filter(Filters::current_month(now.date()))
.map(|f| f.get_duration())
.sum();

View file

@ -1,6 +1,6 @@
use crate::data::activity::Activity;
use chrono::{Datelike, Duration, Local, NaiveDate};
use chrono::{Datelike, Duration, NaiveDate};
pub struct Filters {}
@ -8,20 +8,17 @@ impl Filters {
pub fn active(activity: &&Activity) -> bool {
!activity.is_stopped()
}
pub fn today() -> impl Fn(&&Activity) -> bool {
let today = Local::now().naive_local().date();
pub fn today(today: NaiveDate) -> impl Fn(&&Activity) -> bool {
move |activity: &&Activity| activity.start.date() == today
}
pub fn current_week() -> impl Fn(&&Activity) -> bool {
let today = Local::now().naive_local().date();
pub fn current_week(today: NaiveDate) -> impl Fn(&&Activity) -> bool {
let from_date = today - Duration::days(i64::from(today.weekday().num_days_from_monday()));
let to_date = today;
move |activity: &&Activity| {
activity.start.date() >= from_date && activity.start.date() <= to_date
}
}
pub fn current_month() -> impl Fn(&&Activity) -> bool {
let today = Local::now().naive_local().date();
pub fn current_month(today: NaiveDate) -> impl Fn(&&Activity) -> bool {
let from_date = NaiveDate::from_ymd_opt(today.year(), today.month(), 1).unwrap();
let to_date = today;
move |activity: &&Activity| {
@ -29,3 +26,95 @@ impl Filters {
}
}
}
#[cfg(test)]
mod tests {
use chrono::NaiveDateTime;
use crate::data::activity;
use super::*;
#[test]
fn filter_active() {
let activities = data();
let res: Vec<&Activity> = activities.iter().filter(Filters::active).collect();
assert_eq!(res.len(), 1);
assert_eq!(res.first().unwrap().description.as_str(), "d4");
}
#[test]
fn filter_today() {
let now = date(2024, 3, 19);
let activities = data();
let res: Vec<&Activity> = activities
.iter()
.filter(Filters::today(now.date()))
.collect();
assert_eq!(res.len(), 2);
assert_eq!(res.first().unwrap().description.as_str(), "d3");
}
#[test]
fn filter_current_week() {
let now = date(2024, 3, 19);
let activities = data();
let res: Vec<&Activity> = activities
.iter()
.filter(Filters::current_week(now.date()))
.collect();
assert_eq!(res.len(), 3);
assert_eq!(res.first().unwrap().description.as_str(), "d2");
}
#[test]
fn filter_current_month() {
let now = date(2024, 3, 19);
let activities = data();
let res: Vec<&Activity> = activities
.iter()
.filter(Filters::current_month(now.date()))
.collect();
assert_eq!(res.len(), 4);
assert_eq!(res.first().unwrap().description.as_str(), "d1");
}
fn data() -> Vec<Activity> {
let a0 = activity::Activity {
project: "p1".to_string(),
description: "d0".to_string(),
start: date(2024, 2, 11),
end: Some(date(2024, 2, 11) + Duration::hours(2)),
};
let a1 = activity::Activity {
project: "p1".to_string(),
description: "d1".to_string(),
start: date(2024, 3, 11),
end: Some(date(2024, 3, 11) + Duration::hours(2)),
};
let a2 = activity::Activity {
project: "p1".to_string(),
description: "d2".to_string(),
start: date(2024, 3, 18),
end: Some(date(2024, 3, 18) + Duration::hours(2)),
};
let a3 = activity::Activity {
project: "p1".to_string(),
description: "d3".to_string(),
start: date(2024, 3, 19),
end: Some(date(2024, 3, 19) + Duration::hours(2)),
};
let a4 = activity::Activity {
project: "p1".to_string(),
description: "d4".to_string(),
start: date(2024, 3, 19),
end: None,
};
return vec![a0, a1, a2, a3, a4];
}
fn date(year: i32, month: u32, day: u32) -> NaiveDateTime {
let date = NaiveDate::from_ymd_opt(year, month, day).unwrap();
return NaiveDateTime::new(date, chrono::NaiveTime::from_hms_opt(10, 0, 0).unwrap());
}
}

View file

@ -18,7 +18,7 @@ pub struct StatusReportData<'a> {
pub current_month: Duration,
}
pub trait StatusReportWriter {
fn process<'a>(&self, data: &'a StatusReportData) -> Result<()>;
fn process(&self, data: &StatusReportData) -> Result<()>;
}
pub struct RoundProcessor {

View file

@ -10,7 +10,7 @@ use crate::view::format_util;
pub struct StatusReport {}
impl StatusReportWriter for StatusReport {
fn process<'a>(&self, data: &'a StatusReportData) -> anyhow::Result<()> {
fn process(&self, data: &StatusReportData) -> anyhow::Result<()> {
println!("{data}");
Ok(())
}
@ -117,3 +117,126 @@ fn write_period(
)?;
Ok(())
}
#[cfg(test)]
mod tests {
use chrono::Local;
use super::*;
#[test]
fn report_test() {
let data = StatusReportData {
activity: None,
project: None,
current_month: Duration::hours(10),
current_week: Duration::hours(5),
today: Duration::minutes(30),
};
let expected = "\u{1b}[2m
=======<>[3m Status for <>[1mALL<>[3m projects <>[2m =======
<>[2;3m
NOW: <>[1m NO Activity
<>[3m <>[2;3m Today......................... <>[1m30m<>[3m
<>[3m <>[2;3m Current week.................. <>[1m5h 00m<>[3m
<>[3m <>[2;3m Current month................. <>[1m10h 00m<>[3m
\u{1b}[0m";
let res = data.to_string();
assert_eq!(clean(res.as_str()), clean(expected));
}
#[test]
fn report_project_test() {
let data = StatusReportData {
activity: None,
project: Some("project"),
current_month: Duration::hours(10),
current_week: Duration::hours(5),
today: Duration::minutes(30),
};
let expected = "\u{1b}[2m
=======<>[3m Status for project: <>[1mproject<>[2m =======
<>[2;3m
NOW: <>[1m NO Activity
<>[3m <>[2;3m Today......................... <>[1m30m<>[3m
<>[3m <>[2;3m Current week.................. <>[1m5h 00m<>[3m
<>[3m <>[2;3m Current month................. <>[1m10h 00m<>[3m
\u{1b}[0m";
let res = data.to_string();
assert_eq!(clean(res.as_str()), clean(expected));
}
#[test]
fn report_active_test() {
let now = Local::now().naive_local();
let act = activity::Activity {
start: now - Duration::minutes(10),
end: None,
project: "project".to_string(),
description: "olia".to_string(),
};
let data = StatusReportData {
activity: Some(&act),
project: Some("project"),
current_month: Duration::hours(10),
current_week: Duration::hours(5),
today: Duration::minutes(30),
};
let expected = "\u{1b}[2m
=======<>[3m Status for project: <>[1mproject<>[2m =======
<>[2;3m
NOW: <>[1;32molia<>[2m ...... <>[1m10m<>[2m
<>[3m <>[2;3m Today......................... <>[1m30m<>[3m
<>[3m <>[2;3m Current week.................. <>[1m5h 00m<>[3m
<>[3m <>[2;3m Current month................. <>[1m10h 00m<>[3m
\u{1b}[0m";
let res = data.to_string();
assert_eq!(clean(res.as_str()), clean(expected));
}
#[test]
fn report_active_and_project_test() {
let now = Local::now().naive_local();
let act = activity::Activity {
start: now - Duration::minutes(10),
end: None,
project: "project".to_string(),
description: "olia".to_string(),
};
let data = StatusReportData {
activity: Some(&act),
project: None,
current_month: Duration::hours(10),
current_week: Duration::hours(5),
today: Duration::minutes(30),
};
let expected = "\u{1b}[2m
=======<>[3m Status for <>[1mALL<>[3m projects <>[2m =======
<>[2;3m
NOW: <>[1;32molia<>[2;3m on <>[3mproject<>[2m ...... <>[1m10m<>[2m
<>[3m <>[2;3m Today......................... <>[1m30m<>[3m
<>[3m <>[2;3m Current week.................. <>[1m5h 00m<>[3m
<>[3m <>[2;3m Current month................. <>[1m10h 00m<>[3m
\u{1b}[0m";
let res = data.to_string();
assert_eq!(clean(res.as_str()), clean(expected));
}
fn clean(a: &str) -> String {
let st_f = "\u{1b}[0m\u{1b}";
let clean_res = a.replace(st_f, "<>");
clean_res
}
}