@@ -126,7 +126,12 @@ fn parse_fields(line: &str) -> Result<HashMap<&str, &str>, String> { |
| 126 | let (key, value) = token | 126 | let (key, value) = token |
| 127 | .split_once('=') | 127 | .split_once('=') |
| 128 | .ok_or_else(|| format!("invalid token: {token}"))?; | 128 | .ok_or_else(|| format!("invalid token: {token}"))?; |
| 129 | - fields.insert(key, value); | 129 | + if !matches!(key, "id" | "sender" | "app_id" | "parent" | "state") { |
| | 130 | + return Err(format!("unknown field: {key}")); |
| | 131 | + } |
| | 132 | + if fields.insert(key, value).is_some() { |
| | 133 | + return Err(format!("duplicate field: {key}")); |
| | 134 | + } |
| 130 | } | 135 | } |
| 131 | Ok(fields) | 136 | Ok(fields) |
| 132 | } | 137 | } |
@@ -213,6 +218,33 @@ mod tests { |
| 213 | let _ = fs::remove_file(path); | 218 | let _ = fs::remove_file(path); |
| 214 | } | 219 | } |
| 215 | | 220 | |
| | 221 | + #[test] |
| | 222 | + fn duplicate_fields_fail_to_load() { |
| | 223 | + let path = unique_temp_file(); |
| | 224 | + fs::write(&path, "id=req-1\tid=req-2\tsender=:1.2\tstate=pending\n") |
| | 225 | + .expect("test file should be written"); |
| | 226 | + |
| | 227 | + let loaded = load_registry(&path, Duration::from_secs(5)); |
| | 228 | + assert!(loaded.is_err()); |
| | 229 | + |
| | 230 | + let _ = fs::remove_file(path); |
| | 231 | + } |
| | 232 | + |
| | 233 | + #[test] |
| | 234 | + fn unknown_fields_fail_to_load() { |
| | 235 | + let path = unique_temp_file(); |
| | 236 | + fs::write( |
| | 237 | + &path, |
| | 238 | + "id=req-1\tsender=:1.2\tstate=pending\tunexpected=1\n", |
| | 239 | + ) |
| | 240 | + .expect("test file should be written"); |
| | 241 | + |
| | 242 | + let loaded = load_registry(&path, Duration::from_secs(5)); |
| | 243 | + assert!(loaded.is_err()); |
| | 244 | + |
| | 245 | + let _ = fs::remove_file(path); |
| | 246 | + } |
| | 247 | + |
| 216 | #[test] | 248 | #[test] |
| 217 | fn persist_overwrites_previous_contents() { | 249 | fn persist_overwrites_previous_contents() { |
| 218 | let path = unique_temp_file(); | 250 | let path = unique_temp_file(); |