1use chrono::{DateTime, NaiveDate, Utc};
4
5#[must_use]
17pub fn format_date(date: &NaiveDate) -> String {
18 date.format("%Y-%m-%d").to_string()
19}
20
21#[must_use]
33pub fn format_datetime(dt: &DateTime<Utc>) -> String {
34 dt.format("%Y-%m-%d %H:%M:%S UTC").to_string()
35}
36
37pub fn parse_date(date_str: &str) -> Result<NaiveDate, chrono::ParseError> {
56 NaiveDate::parse_from_str(date_str, "%Y-%m-%d")
57}
58
59#[must_use]
76pub fn is_valid_uuid(uuid_str: &str) -> bool {
77 uuid::Uuid::parse_str(uuid_str).is_ok()
78}
79
80#[must_use]
92pub fn truncate_string(s: &str, max_len: usize) -> String {
93 if s.len() <= max_len {
94 s.to_string()
95 } else {
96 format!("{}...", &s[..max_len.saturating_sub(3)])
97 }
98}
99
100#[cfg(test)]
101mod tests {
102 use super::*;
103 use chrono::{Datelike, TimeZone, Utc};
104
105 #[test]
106 fn test_format_date() {
107 let date = NaiveDate::from_ymd_opt(2023, 12, 25).unwrap();
108 let formatted = format_date(&date);
109 assert_eq!(formatted, "2023-12-25");
110
111 let date = NaiveDate::from_ymd_opt(2024, 1, 1).unwrap();
113 let formatted = format_date(&date);
114 assert_eq!(formatted, "2024-01-01");
115
116 let date = NaiveDate::from_ymd_opt(2024, 2, 29).unwrap(); let formatted = format_date(&date);
118 assert_eq!(formatted, "2024-02-29");
119 }
120
121 #[test]
122 fn test_format_datetime() {
123 let dt = Utc.with_ymd_and_hms(2023, 12, 25, 15, 30, 45).unwrap();
125 let formatted = format_datetime(&dt);
126 assert_eq!(formatted, "2023-12-25 15:30:45 UTC");
127
128 let dt = Utc.with_ymd_and_hms(2024, 1, 1, 0, 0, 0).unwrap();
130 let formatted = format_datetime(&dt);
131 assert_eq!(formatted, "2024-01-01 00:00:00 UTC");
132 }
133
134 #[test]
135 fn test_parse_date_valid() {
136 let result = parse_date("2023-12-25");
137 assert!(result.is_ok());
138 let date = result.unwrap();
139 assert_eq!(date.year(), 2023);
140 assert_eq!(date.month(), 12);
141 assert_eq!(date.day(), 25);
142
143 assert!(parse_date("2024-01-01").is_ok());
145 assert!(parse_date("2024-02-29").is_ok()); }
147
148 #[test]
149 fn test_parse_date_invalid() {
150 assert!(parse_date("2023/12/25").is_err());
152 assert!(parse_date("2023-13-01").is_err()); assert!(parse_date("2023-02-30").is_err()); assert!(parse_date("").is_err());
155 assert!(parse_date("not-a-date").is_err());
156 assert!(parse_date("2023-02-29").is_err()); }
158
159 #[test]
160 fn test_is_valid_uuid_valid() {
161 assert!(is_valid_uuid("550e8400-e29b-41d4-a716-446655440000"));
163 assert!(is_valid_uuid("6ba7b810-9dad-11d1-80b4-00c04fd430c8"));
164 assert!(is_valid_uuid("00000000-0000-0000-0000-000000000000"));
165 assert!(is_valid_uuid("ffffffff-ffff-ffff-ffff-ffffffffffff"));
166 assert!(is_valid_uuid("FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF")); }
168
169 #[test]
170 fn test_is_valid_uuid_invalid() {
171 assert!(!is_valid_uuid(""));
173 assert!(!is_valid_uuid("not-a-uuid"));
174 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")); }
178
179 #[test]
180 fn test_truncate_string() {
181 assert_eq!(truncate_string("hello", 10), "hello");
183 assert_eq!(truncate_string("hello", 5), "hello");
184
185 assert_eq!(truncate_string("hello world", 8), "hello...");
187 assert_eq!(truncate_string("hello world", 5), "he...");
188
189 assert_eq!(truncate_string("hello", 3), "...");
191 assert_eq!(truncate_string("hello", 4), "h...");
192 assert_eq!(truncate_string("", 10), "");
193 assert_eq!(truncate_string("", 0), "");
194 assert_eq!(truncate_string("test", 0), "...");
195 }
196
197 #[test]
198 fn test_integration() {
199 let date_str = "2023-12-25";
201 let parsed_date = parse_date(date_str).unwrap();
202 let formatted_date = format_date(&parsed_date);
203 assert_eq!(formatted_date, date_str);
204
205 let uuid = "550e8400-e29b-41d4-a716-446655440000";
207 assert!(is_valid_uuid(uuid));
208 let truncated = truncate_string(uuid, 20);
209 assert_eq!(truncated, "550e8400-e29b-41d...");
210 }
211
212 #[test]
213 fn test_comprehensive_coverage() {
214 for month in 1..=12 {
218 let date = NaiveDate::from_ymd_opt(2023, month, 1).unwrap();
219 let formatted = format_date(&date);
220 assert!(formatted.contains(&format!("{month:02}")));
221 }
222
223 let times = [(0, 0, 0), (12, 0, 0), (23, 59, 59)];
225 for (hour, min, sec) in times {
226 let dt = Utc.with_ymd_and_hms(2023, 6, 15, hour, min, sec).unwrap();
227 let formatted = format_datetime(&dt);
228 assert!(formatted.contains(&format!("{hour:02}:{min:02}:{sec:02}")));
229 assert!(formatted.ends_with("UTC"));
230 }
231
232 let invalid_dates = [
234 "2023",
235 "2023-01",
236 "01-01-2023",
237 "2023.01.01",
238 "2023-00-01",
239 "2023-01-00",
240 "2023-04-31",
241 ];
242 for date_str in &invalid_dates {
243 assert!(parse_date(date_str).is_err());
244 }
245
246 let invalid_uuids = [
248 "550e8400_e29b_41d4_a716_446655440000", "550e8400.e29b.41d4.a716.446655440000", " 550e8400-e29b-41d4-a716-446655440000", "550e8400-e29b-41d4-a716-446655440000 ", ];
253 for uuid in &invalid_uuids {
254 assert!(!is_valid_uuid(uuid));
255 }
256
257 assert_eq!(truncate_string("hello δΈη", 8), "hello...");
259 assert_eq!(truncate_string("π¦π¦π¦", 3), "...");
260 }
261}