1use chrono::{DateTime, Utc};
2use git2::Signature;
3use std::str::FromStr;
4
5use crate::Error;
6
7pub struct Actor {
9 inner: Signature<'static>,
10}
11
12impl FromStr for Actor {
13 type Err = Error;
14
15 fn from_str(s: &str) -> Result<Self, Self::Err> {
23 let start_idx = s.find('<').unwrap_or_default();
24 let end_idx = s.find('>').unwrap_or_default();
25
26 let time = git2::Time::new(0, 0);
27 let sig = Signature::new(&s[..start_idx], &s[start_idx + 1..end_idx], &time)
29 .map_err(Error::Git)?;
30
31 Ok(Self::new(sig))
32 }
33}
34
35impl Actor {
36 pub fn new(signature: Signature<'_>) -> Self {
38 Self {
39 inner: signature.to_owned(),
40 }
41 }
42
43 pub fn name(&self) -> Option<&str> {
45 self.inner.name()
46 }
47
48 pub fn email(&self) -> Option<&str> {
50 self.inner.email()
51 }
52
53 pub fn timestamp(&self) -> Option<DateTime<Utc>> {
55 DateTime::from_timestamp_secs(self.inner.when().seconds())
56 }
57
58 pub fn offset(&self) -> i32 {
60 self.inner.when().offset_minutes()
61 }
62}
63
64#[cfg(test)]
65mod tests {
66 use super::*;
67
68 fn actor_factory() -> Actor {
69 let sig = Signature::new(
70 "test",
71 "test@example.com",
72 &git2::Time::new(1_600_000_000, -60),
73 )
74 .unwrap();
75
76 Actor::new(sig)
77 }
78
79 #[test]
80 fn test_name() {
81 let actor = actor_factory();
82 assert_eq!(actor.name(), Some("test"));
83 }
84
85 #[test]
86 fn test_email() {
87 let actor = actor_factory();
88 assert_eq!(actor.email(), Some("test@example.com"));
89 }
90
91 #[test]
92 fn test_time() {
93 let actor = actor_factory();
94 assert_eq!(actor.timestamp().unwrap().timestamp(), 1_600_000_000);
95 }
96
97 #[test]
98 fn test_offset() {
99 let actor = actor_factory();
100 assert_eq!(actor.offset(), -60);
101 }
102
103 #[test]
104 fn test_from_str() {
105 let actor = Actor::from_str("test <test@example.com>").unwrap();
106
107 assert_eq!(actor.name(), Some("test"));
108 assert_eq!(actor.email(), Some("test@example.com"));
109 assert_eq!(actor.timestamp().unwrap().timestamp(), 0);
110 assert_eq!(actor.offset(), 0);
111 }
112
113 #[test]
114 fn test_malformed_from_str() {
115 let result = Actor::from_str("some nonsense <>");
116
117 assert!(result.is_err())
118 }
119
120 #[test]
121 fn test_extended_from_str() {
122 let actor = Actor::from_str("test <test@example.com> nonsense").unwrap();
123
124 assert_eq!(actor.name(), Some("test"));
125 assert_eq!(actor.email(), Some("test@example.com"));
126 }
127
128 #[test]
129 fn test_surname() {
130 let actor = Actor::from_str("test surname <email>").unwrap();
131
132 assert_eq!(actor.name(), Some("test surname"));
133 }
134}