#[cfg(test)]
mod tests {
use chrono::NaiveDate;
use kasl::db::{pauses::Pauses, workdays::Workdays};
use serial_test::serial;
use tempfile::TempDir;
use test_context::{TestContext, test_context};
struct ReportTestContext {
_temp_dir: TempDir,
}
impl TestContext for ReportTestContext {
fn setup() -> Self {
let temp_dir = tempfile::tempdir().unwrap();
unsafe {
std::env::set_var("HOME", temp_dir.path());
}
unsafe {
std::env::set_var("LOCALAPPDATA", temp_dir.path());
}
ReportTestContext { _temp_dir: temp_dir }
}
}
#[test_context(ReportTestContext)]
#[serial]
#[test]
fn test_report_with_pauses(_ctx: &mut ReportTestContext) {
let date = NaiveDate::from_ymd_opt(2025, 6, 24).unwrap();
let mut workdays = Workdays::new().unwrap();
workdays.insert_start(date).unwrap();
workdays
.conn
.execute(
"UPDATE workdays SET start = '2025-06-24 09:00:00', end = '2025-06-24 17:00:00' WHERE date = ?",
[&date.to_string()],
)
.unwrap();
let pauses_db = Pauses::new().unwrap();
let conn = pauses_db.conn.lock();
conn.execute(
"INSERT INTO pauses (start, end, duration) VALUES ('2025-06-24 10:00:00', '2025-06-24 10:30:00', ?)",
[(30 * 60).to_string()],
)
.unwrap();
conn.execute(
"INSERT INTO pauses (start, end, duration) VALUES ('2025-06-24 12:00:00', '2025-06-24 13:00:00', ?)",
[(60 * 60).to_string()],
)
.unwrap();
drop(conn);
let workday = workdays.fetch(date).unwrap().unwrap();
let pauses_vec = pauses_db.get_daily_pauses(date).unwrap();
let intervals = kasl::libs::report::calculate_work_intervals(&workday, &pauses_vec);
let output = kasl::libs::report::report_with_intervals(&workday, &intervals);
assert!(output.is_ok());
}
#[test_context(ReportTestContext)]
#[serial]
#[test]
fn test_report_no_pauses(_ctx: &mut ReportTestContext) {
let date = NaiveDate::from_ymd_opt(2025, 6, 25).unwrap();
let mut workdays = Workdays::new().unwrap();
workdays.insert_start(date).unwrap();
workdays
.conn
.execute(
"UPDATE workdays SET start = '2025-06-25 09:00:00', end = '2025-06-25 17:00:00' WHERE date = ?",
[&date.to_string()],
)
.unwrap();
let pauses_db = Pauses::new().unwrap();
let workday = workdays.fetch(date).unwrap().unwrap();
let pauses_vec = pauses_db.get_daily_pauses(date).unwrap();
assert_eq!(pauses_vec.len(), 0);
let intervals = kasl::libs::report::calculate_work_intervals(&workday, &pauses_vec);
let output = kasl::libs::report::report_with_intervals(&workday, &intervals);
assert!(output.is_ok());
}
#[test_context(ReportTestContext)]
#[serial]
#[test]
fn test_report_with_breaks_and_pauses(_ctx: &mut ReportTestContext) {
let date = NaiveDate::from_ymd_opt(2025, 6, 26).unwrap();
let mut workdays = Workdays::new().unwrap();
workdays.insert_start(date).unwrap();
workdays
.conn
.execute(
"UPDATE workdays SET start = '2025-06-26 09:00:00', end = '2025-06-26 17:00:00' WHERE date = ?",
[&date.to_string()],
)
.unwrap();
let pauses_db = Pauses::new().unwrap();
let conn = pauses_db.conn.lock();
conn.execute(
"INSERT INTO pauses (start, end, duration) VALUES ('2025-06-26 10:30:00', '2025-06-26 11:00:00', ?)",
[(30 * 60).to_string()],
)
.unwrap();
drop(conn);
pauses_db
.insert_manual(date.and_hms_opt(12, 0, 0).unwrap(), chrono::Duration::hours(1), true, Some("Lunch break"))
.unwrap();
let workday = workdays.fetch(date).unwrap().unwrap();
let pauses_vec = pauses_db.get_daily_pauses(date).unwrap();
assert_eq!(pauses_vec.len(), 2);
let intervals = kasl::libs::report::calculate_work_intervals(&workday, &pauses_vec);
assert_eq!(intervals.len(), 3);
assert_eq!(intervals[0].start, date.and_hms_opt(9, 0, 0).unwrap());
assert_eq!(intervals[0].end, date.and_hms_opt(10, 30, 0).unwrap());
assert_eq!(intervals[1].start, date.and_hms_opt(11, 0, 0).unwrap());
assert_eq!(intervals[1].end, date.and_hms_opt(12, 0, 0).unwrap());
assert_eq!(intervals[2].start, date.and_hms_opt(13, 0, 0).unwrap());
assert_eq!(intervals[2].end, date.and_hms_opt(17, 0, 0).unwrap());
let output = kasl::libs::report::report_with_intervals(&workday, &intervals);
assert!(output.is_ok());
let (_, productivity) = output.unwrap();
assert!(productivity > 0.0 && productivity <= 100.0);
}
}