changepacks_core/
update_log.rs1use std::{collections::HashMap, path::PathBuf};
2
3use chrono::{DateTime, Utc};
4use serde::{Deserialize, Serialize};
5
6use crate::update_type::UpdateType;
7
8#[derive(Debug, Serialize, Deserialize)]
13pub struct ChangePackLog {
14 changes: HashMap<PathBuf, UpdateType>,
16 note: String,
18 date: DateTime<Utc>,
20}
21
22impl ChangePackLog {
23 #[must_use]
24 pub fn new(changes: HashMap<PathBuf, UpdateType>, note: String) -> Self {
25 Self {
26 changes,
27 note,
28 date: Utc::now(),
29 }
30 }
31
32 #[must_use]
33 pub fn changes(&self) -> &HashMap<PathBuf, UpdateType> {
34 &self.changes
35 }
36
37 #[must_use]
38 pub fn note(&self) -> &str {
39 &self.note
40 }
41}
42
43#[cfg(test)]
44mod tests {
45 use std::{collections::HashMap, path::PathBuf};
46
47 use chrono::{DateTime, Utc};
48
49 use super::*;
50
51 #[test]
52 fn test_changepack_log_new() {
53 let mut changes = HashMap::new();
54 changes.insert(
55 PathBuf::from("packages/foo/package.json"),
56 UpdateType::Minor,
57 );
58 let note = "Add feature X".to_string();
59
60 let log = ChangePackLog::new(changes.clone(), note.clone());
61
62 assert_eq!(log.changes(), &changes);
63 assert_eq!(log.note(), note);
64 }
65
66 #[test]
67 fn test_changepack_log_changes_accessor() {
68 let mut changes = HashMap::new();
69 changes.insert(
70 PathBuf::from("packages/foo/package.json"),
71 UpdateType::Major,
72 );
73 changes.insert(PathBuf::from("crates/core/Cargo.toml"), UpdateType::Patch);
74
75 let log = ChangePackLog::new(changes.clone(), "Update changes".to_string());
76
77 assert_eq!(log.changes().len(), 2);
78 assert_eq!(log.changes(), &changes);
79 assert_eq!(
80 log.changes()
81 .get(&PathBuf::from("packages/foo/package.json")),
82 Some(&UpdateType::Major)
83 );
84 assert_eq!(
85 log.changes().get(&PathBuf::from("crates/core/Cargo.toml")),
86 Some(&UpdateType::Patch)
87 );
88 }
89
90 #[test]
91 fn test_changepack_log_note_accessor() {
92 let mut changes = HashMap::new();
93 changes.insert(
94 PathBuf::from("packages/foo/package.json"),
95 UpdateType::Minor,
96 );
97
98 let log = ChangePackLog::new(changes, "Detailed changelog note".to_string());
99
100 assert_eq!(log.note(), "Detailed changelog note");
101 }
102
103 #[test]
104 fn test_changepack_log_empty_changes() {
105 let log = ChangePackLog::new(HashMap::new(), "No package updates".to_string());
106
107 assert!(log.changes().is_empty());
108 assert_eq!(log.note(), "No package updates");
109 }
110
111 #[test]
112 fn test_changepack_log_serialize_deserialize_roundtrip() {
113 let mut changes = HashMap::new();
114 changes.insert(
115 PathBuf::from("packages/foo/package.json"),
116 UpdateType::Minor,
117 );
118 changes.insert(PathBuf::from("crates/core/Cargo.toml"), UpdateType::Patch);
119 let log = ChangePackLog::new(changes, "Roundtrip changelog note".to_string());
120
121 let json = serde_json::to_string(&log).unwrap();
122 let deserialized: ChangePackLog = serde_json::from_str(&json).unwrap();
123
124 assert_eq!(deserialized.changes(), log.changes());
125 assert_eq!(deserialized.note(), log.note());
126 assert_eq!(deserialized.date, log.date);
127 }
128
129 #[test]
130 fn test_changepack_log_deserialize_from_json() {
131 let json = r#"{
132 "changes": {
133 "packages/foo/package.json": "Minor",
134 "crates/core/Cargo.toml": "Patch"
135 },
136 "note": "Ship feature and fix",
137 "date": "2025-12-19T10:27:00.000Z"
138 }"#;
139
140 let log: ChangePackLog = serde_json::from_str(json).unwrap();
141 let expected_date = DateTime::parse_from_rfc3339("2025-12-19T10:27:00.000Z")
142 .unwrap()
143 .with_timezone(&Utc);
144
145 assert_eq!(log.changes().len(), 2);
146 assert_eq!(
147 log.changes()
148 .get(&PathBuf::from("packages/foo/package.json")),
149 Some(&UpdateType::Minor)
150 );
151 assert_eq!(
152 log.changes().get(&PathBuf::from("crates/core/Cargo.toml")),
153 Some(&UpdateType::Patch)
154 );
155 assert_eq!(log.note(), "Ship feature and fix");
156 assert_eq!(log.date, expected_date);
157 }
158}