1use crate::types::PrinterState;
7
8#[derive(Debug, Clone, PartialEq, Eq, Hash)]
14#[non_exhaustive]
15pub enum DiscoveryEvent {
16 PrinterAdded(PrinterSnapshot),
18 PrinterRemoved {
20 id: String,
22 backend: String,
24 },
25 PrinterStateChanged {
27 id: String,
29 backend: String,
31 state: PrinterState,
33 accepting_jobs: bool,
35 },
36}
37
38#[derive(Debug, Clone, PartialEq, Eq, Hash)]
40pub struct PrinterSnapshot {
41 pub id: String,
43 pub name: String,
45 pub info: String,
47 pub location: String,
49 pub make_model: String,
51 pub state: PrinterState,
53 pub accepting_jobs: bool,
55 pub backend: String,
57}
58
59impl PrinterSnapshot {
60 pub fn is_ready(&self) -> bool {
62 self.state == PrinterState::Idle && self.accepting_jobs
63 }
64}
65
66impl std::fmt::Display for PrinterSnapshot {
67 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
68 write!(f, "{} [{}] ({})", self.name, self.id, self.state)
69 }
70}
71
72#[cfg(test)]
73mod tests {
74 use super::*;
75
76 fn sample_snapshot() -> PrinterSnapshot {
77 PrinterSnapshot {
78 id: "HP-LaserJet-Pro".to_string(),
79 name: "HP LaserJet Pro".to_string(),
80 info: "Office printer".to_string(),
81 location: "Room 42".to_string(),
82 make_model: "HP LaserJet Pro MFP".to_string(),
83 state: PrinterState::Idle,
84 accepting_jobs: true,
85 backend: "CUPS".to_string(),
86 }
87 }
88
89 #[test]
90 fn snapshot_is_ready_when_idle_and_accepting() {
91 let snap = sample_snapshot();
92 assert!(snap.is_ready());
93 }
94
95 #[test]
96 fn snapshot_not_ready_when_busy() {
97 let mut snap = sample_snapshot();
98 snap.state = PrinterState::Processing;
99 assert!(!snap.is_ready());
100 }
101
102 #[test]
103 fn snapshot_not_ready_when_not_accepting() {
104 let mut snap = sample_snapshot();
105 snap.accepting_jobs = false;
106 assert!(!snap.is_ready());
107 }
108
109 #[test]
110 fn snapshot_clones_correctly() {
111 let snap = sample_snapshot();
112 let clone = snap.clone();
113 assert_eq!(snap.id, clone.id);
114 assert_eq!(snap.backend, clone.backend);
115 }
116
117 #[test]
118 fn discovery_event_printer_added() {
119 let event = DiscoveryEvent::PrinterAdded(sample_snapshot());
120 assert!(matches!(event, DiscoveryEvent::PrinterAdded(_)));
121 }
122
123 #[test]
124 fn discovery_event_printer_removed() {
125 let event = DiscoveryEvent::PrinterRemoved {
126 id: "HP-123".to_string(),
127 backend: "CUPS".to_string(),
128 };
129 match &event {
130 DiscoveryEvent::PrinterRemoved { id, backend } => {
131 assert_eq!(id, "HP-123");
132 assert_eq!(backend, "CUPS");
133 }
134 _ => panic!("Expected PrinterRemoved"),
135 }
136 }
137
138 #[test]
139 fn discovery_event_state_changed() {
140 let event = DiscoveryEvent::PrinterStateChanged {
141 id: "HP-123".to_string(),
142 backend: "CUPS".to_string(),
143 state: PrinterState::Processing,
144 accepting_jobs: true,
145 };
146 match &event {
147 DiscoveryEvent::PrinterStateChanged {
148 state,
149 accepting_jobs,
150 ..
151 } => {
152 assert_eq!(state, &PrinterState::Processing);
153 assert!(*accepting_jobs);
154 }
155 _ => panic!("Expected PrinterStateChanged"),
156 }
157 }
158
159 #[test]
160 fn events_are_clone() {
161 let event = DiscoveryEvent::PrinterAdded(sample_snapshot());
162 let clone = event.clone();
163 assert!(matches!(clone, DiscoveryEvent::PrinterAdded(_)));
164 }
165
166 #[test]
167 fn snapshot_display() {
168 let snap = sample_snapshot();
169 assert_eq!(
170 format!("{}", snap),
171 "HP LaserJet Pro [HP-LaserJet-Pro] (idle)"
172 );
173 }
174
175 #[test]
176 fn snapshot_equality_and_hashing() {
177 use std::collections::HashSet;
178 let snap1 = sample_snapshot();
179 let snap2 = sample_snapshot();
180 assert_eq!(snap1, snap2);
181
182 let mut set = HashSet::new();
183 set.insert(snap1.clone());
184 assert!(set.contains(&snap2));
185 }
186}