Skip to content

Commit

Permalink
feat: add unit tests
Browse files Browse the repository at this point in the history
  • Loading branch information
airenas committed Mar 18, 2024
1 parent 075e089 commit 332cdac
Show file tree
Hide file tree
Showing 4 changed files with 227 additions and 12 deletions.
9 changes: 6 additions & 3 deletions src/controller/status.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use anyhow::Result;
use chrono::Local;

use crate::data::activity;
use crate::data::activity::Activity;
Expand Down Expand Up @@ -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()
Expand All @@ -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();

Expand Down
103 changes: 96 additions & 7 deletions src/data/filter.rs
Original file line number Diff line number Diff line change
@@ -1,31 +1,120 @@
use crate::data::activity::Activity;

use chrono::{Datelike, Duration, Local, NaiveDate};
use chrono::{Datelike, Duration, NaiveDate};

pub struct Filters {}

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| {
activity.start.date() >= from_date && activity.start.date() <= to_date
}
}
}

#[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());
}
}
2 changes: 1 addition & 1 deletion src/data/processor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
125 changes: 124 additions & 1 deletion src/view/status.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(())
}
Expand Down Expand Up @@ -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
}
}

0 comments on commit 332cdac

Please sign in to comment.