1use std::time::Duration;
28
29#[doc(inline)]
30use crate::date::DateTime;
31#[doc(inline)]
32use crate::entry::Entry;
33
34#[derive(Debug, Clone, Eq, Ord, PartialOrd, PartialEq)]
36pub struct TaskEvent {
37 start: DateTime,
39 proj: Option<String>,
41 dur: Duration
43}
44
45impl TaskEvent {
46 pub fn new<'a, OS>(start: DateTime, proj: OS, dur: Duration) -> Self
48 where
49 OS: Into<Option<&'a str>>
50 {
51 Self { start, proj: proj.into().map(ToString::to_string), dur }
52 }
53
54 pub fn from_entry(entry: &Entry) -> Self {
56 Self::new(entry.date_time(), entry.project(), Duration::default())
57 }
58
59 #[rustfmt::skip]
64 pub fn split(&self, dur: Duration) -> Option<(Self, Self)> {
65 Some((
66 Self {
67 start: self.start,
68 proj: self.proj(),
69 dur
70 },
71 Self {
72 start: (self.start + dur).ok()?,
73 proj: self.proj(),
74 dur: self.dur - dur
75 }
76 ))
77 }
78
79 pub fn proj(&self) -> Option<String> { self.proj.as_ref().map(|s| s.clone()) }
81
82 pub fn project(&self) -> String { self.proj().unwrap_or_default() }
84
85 pub fn hour(&self) -> usize { self.start.hour() as usize }
87
88 pub fn start(&self) -> &DateTime { &self.start }
90
91 pub fn add_dur(&mut self, dur: Duration) { self.dur += dur; }
93
94 pub fn duration(&self) -> Duration { self.dur }
96
97 pub fn as_secs(&self) -> u64 { self.dur.as_secs() }
99
100 pub fn second_offset(&self) -> u32 { self.start.second_offset() }
102}
103
104#[cfg(test)]
105mod tests {
106 use spectral::prelude::*;
107
108 use super::*;
109 use crate::DateTime;
110
111 #[test]
112 fn test_new_with_project() {
113 let task = TaskEvent::new(
114 DateTime::new((2022, 3, 20), (12, 34, 56)).expect("Failed to create DateTime"),
115 "proja",
116 Duration::from_secs(305)
117 );
118 assert_that!(task.proj()).is_some().contains(String::from("proja").as_str());
119 assert_that!(task.project()).is_equal_to(String::from("proja"));
120 let expect_start =
121 DateTime::new((2022, 3, 20), (12, 34, 56)).expect("Failed to create DateTime");
122 assert_that!(task.start()).is_equal_to(&expect_start);
123 assert_that!(task.hour()).is_equal_to(12);
124 assert_that!(task.duration()).is_equal_to(&Duration::from_secs(305));
125 }
126
127 #[test]
128 fn test_new_without_project() {
129 let task = TaskEvent::new(
130 DateTime::new((2022, 3, 20), (13, 24, 56)).expect("Failed to create DateTime"),
131 None,
132 Duration::from_secs(255)
133 );
134 assert_that!(task.proj()).is_none();
135 assert_that!(task.project()).is_equal_to(String::new());
136 let expect_start =
137 DateTime::new((2022, 3, 20), (13, 24, 56)).expect("Failed to create DateTime");
138 assert_that!(task.start()).is_equal_to(&expect_start);
139 assert_that!(task.hour()).is_equal_to(13);
140 assert_that!(task.duration()).is_equal_to(&Duration::from_secs(255));
141 }
142
143 #[test]
144 fn test_add_dur() {
145 let mut task = TaskEvent::new(
146 DateTime::new((2022, 3, 20), (12, 34, 56)).expect("Failed to create DateTime"),
147 "proja",
148 Duration::from_secs(305)
149 );
150
151 assert_that!(task.as_secs()).named("Initial value").is_equal_to(305);
152
153 task.add_dur(Duration::from_secs(3600));
154 assert_that!(task.as_secs()).named("After add_dur").is_equal_to(3905);
155 assert_that!(task.duration()).is_equal_to(Duration::from_secs(3905));
156 }
157
158 #[test]
159 fn test_second_offset() {
160 let task = TaskEvent::new(
161 DateTime::new((2022, 3, 20), (12, 34, 56)).expect("Failed to create DateTime"),
162 "proja",
163 Duration::from_secs(305)
164 );
165
166 assert_that!(task.second_offset()).is_equal_to(34 * 60 + 56);
167 }
168
169 #[test]
170 fn test_split() {
171 let task = TaskEvent::new(
172 DateTime::new((2022, 3, 20), (12, 34, 56)).expect("Failed to create DateTime"),
173 "proja",
174 Duration::from_secs(600)
175 );
176
177 let pair = task.split(Duration::from_secs(250));
178 assert_that!(pair).is_some();
179 let (first, second) = pair.unwrap();
180
181 assert_that!(first.start()).is_equal_to(
182 &DateTime::new((2022, 3, 20), (12, 34, 56)).expect("Failed to create DateTime")
183 );
184 assert_that!(first.duration()).is_equal_to(Duration::from_secs(250));
185
186 assert_that!(second.start()).is_equal_to(
187 &DateTime::new((2022, 3, 20), (12, 39, 6)).expect("Failed to create DateTime")
188 );
189 assert_that!(second.duration()).is_equal_to(Duration::from_secs(350));
190 }
191}