1use chrono::{DateTime, NaiveDate, Utc};
4
5#[must_use]
7pub fn format_date(date: &NaiveDate) -> String {
8 date.format("%Y-%m-%d").to_string()
9}
10
11#[must_use]
13pub fn format_datetime(dt: &DateTime<Utc>) -> String {
14 dt.format("%Y-%m-%d %H:%M:%S UTC").to_string()
15}
16
17pub fn parse_date(date_str: &str) -> Result<NaiveDate, chrono::ParseError> {
22 NaiveDate::parse_from_str(date_str, "%Y-%m-%d")
23}
24
25#[must_use]
27pub fn is_valid_uuid(uuid_str: &str) -> bool {
28 uuid::Uuid::parse_str(uuid_str).is_ok()
29}
30
31#[must_use]
43pub fn truncate_string(s: &str, max_len: usize) -> String {
44 if s.len() <= max_len {
45 s.to_string()
46 } else {
47 format!("{}...", &s[..max_len.saturating_sub(3)])
48 }
49}
50
51#[cfg(test)]
52mod tests {
53 use super::*;
54 use chrono::{Datelike, TimeZone, Utc};
55
56 #[test]
57 fn test_format_date() {
58 let date = NaiveDate::from_ymd_opt(2023, 12, 25).unwrap();
59 let formatted = format_date(&date);
60 assert_eq!(formatted, "2023-12-25");
61
62 let date = NaiveDate::from_ymd_opt(2024, 1, 1).unwrap();
64 let formatted = format_date(&date);
65 assert_eq!(formatted, "2024-01-01");
66
67 let date = NaiveDate::from_ymd_opt(2024, 2, 29).unwrap(); let formatted = format_date(&date);
69 assert_eq!(formatted, "2024-02-29");
70 }
71
72 #[test]
73 fn test_format_datetime() {
74 let dt = Utc.with_ymd_and_hms(2023, 12, 25, 15, 30, 45).unwrap();
76 let formatted = format_datetime(&dt);
77 assert_eq!(formatted, "2023-12-25 15:30:45 UTC");
78
79 let dt = Utc.with_ymd_and_hms(2024, 1, 1, 0, 0, 0).unwrap();
81 let formatted = format_datetime(&dt);
82 assert_eq!(formatted, "2024-01-01 00:00:00 UTC");
83 }
84
85 #[test]
86 fn test_parse_date_valid() {
87 let result = parse_date("2023-12-25");
88 assert!(result.is_ok());
89 let date = result.unwrap();
90 assert_eq!(date.year(), 2023);
91 assert_eq!(date.month(), 12);
92 assert_eq!(date.day(), 25);
93
94 assert!(parse_date("2024-01-01").is_ok());
96 assert!(parse_date("2024-02-29").is_ok()); }
98
99 #[test]
100 fn test_parse_date_invalid() {
101 assert!(parse_date("2023/12/25").is_err());
103 assert!(parse_date("2023-13-01").is_err()); assert!(parse_date("2023-02-30").is_err()); assert!(parse_date("").is_err());
106 assert!(parse_date("not-a-date").is_err());
107 assert!(parse_date("2023-02-29").is_err()); }
109
110 #[test]
111 fn test_is_valid_uuid_valid() {
112 assert!(is_valid_uuid("550e8400-e29b-41d4-a716-446655440000"));
114 assert!(is_valid_uuid("6ba7b810-9dad-11d1-80b4-00c04fd430c8"));
115 assert!(is_valid_uuid("00000000-0000-0000-0000-000000000000"));
116 assert!(is_valid_uuid("ffffffff-ffff-ffff-ffff-ffffffffffff"));
117 assert!(is_valid_uuid("FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF")); }
119
120 #[test]
121 fn test_is_valid_uuid_invalid() {
122 assert!(!is_valid_uuid(""));
124 assert!(!is_valid_uuid("not-a-uuid"));
125 assert!(!is_valid_uuid("550e8400-e29b-41d4-a716")); assert!(!is_valid_uuid("550e8400-e29b-41d4-a716-44665544000g")); assert!(!is_valid_uuid("550e8400-e29b-41d4-a716-446655440000-extra")); }
129
130 #[test]
131 fn test_truncate_string() {
132 assert_eq!(truncate_string("hello", 10), "hello");
134 assert_eq!(truncate_string("hello", 5), "hello");
135
136 assert_eq!(truncate_string("hello world", 8), "hello...");
138 assert_eq!(truncate_string("hello world", 5), "he...");
139
140 assert_eq!(truncate_string("hello", 3), "...");
142 assert_eq!(truncate_string("hello", 4), "h...");
143 assert_eq!(truncate_string("", 10), "");
144 assert_eq!(truncate_string("", 0), "");
145 assert_eq!(truncate_string("test", 0), "...");
146 }
147
148 #[test]
149 fn test_integration() {
150 let date_str = "2023-12-25";
152 let parsed_date = parse_date(date_str).unwrap();
153 let formatted_date = format_date(&parsed_date);
154 assert_eq!(formatted_date, date_str);
155
156 let uuid = "550e8400-e29b-41d4-a716-446655440000";
158 assert!(is_valid_uuid(uuid));
159 let truncated = truncate_string(uuid, 20);
160 assert_eq!(truncated, "550e8400-e29b-41d...");
161 }
162
163 #[test]
164 fn test_comprehensive_coverage() {
165 for month in 1..=12 {
169 let date = NaiveDate::from_ymd_opt(2023, month, 1).unwrap();
170 let formatted = format_date(&date);
171 assert!(formatted.contains(&format!("{month:02}")));
172 }
173
174 let times = [(0, 0, 0), (12, 0, 0), (23, 59, 59)];
176 for (hour, min, sec) in times {
177 let dt = Utc.with_ymd_and_hms(2023, 6, 15, hour, min, sec).unwrap();
178 let formatted = format_datetime(&dt);
179 assert!(formatted.contains(&format!("{hour:02}:{min:02}:{sec:02}")));
180 assert!(formatted.ends_with("UTC"));
181 }
182
183 let invalid_dates = [
185 "2023",
186 "2023-01",
187 "01-01-2023",
188 "2023.01.01",
189 "2023-00-01",
190 "2023-01-00",
191 "2023-04-31",
192 ];
193 for date_str in &invalid_dates {
194 assert!(parse_date(date_str).is_err());
195 }
196
197 let invalid_uuids = [
199 "550e8400_e29b_41d4_a716_446655440000", "550e8400.e29b.41d4.a716.446655440000", " 550e8400-e29b-41d4-a716-446655440000", "550e8400-e29b-41d4-a716-446655440000 ", ];
204 for uuid in &invalid_uuids {
205 assert!(!is_valid_uuid(uuid));
206 }
207
208 assert_eq!(truncate_string("hello δΈη", 8), "hello...");
210 assert_eq!(truncate_string("π¦π¦π¦", 3), "...");
211 }
212}