dpp_domain/domain/
error.rs1use thiserror::Error;
4
5use crate::domain::field_error::ValidationErrors;
6
7#[derive(Debug, Error)]
9#[non_exhaustive]
10pub enum DppError {
11 #[error("passport not found: {0}")]
12 NotFound(String),
13
14 #[error(
15 "passport is not in a state that allows this operation: current={current}, required={required}"
16 )]
17 InvalidTransition { current: String, required: String },
18
19 #[error("validation failed: {0}")]
20 Validation(ValidationErrors),
21
22 #[error("signing failed: {0}")]
23 Signing(String),
24
25 #[error("serialisation error: {0}")]
26 Serialisation(String),
27
28 #[error("passport is retention-locked: published passports cannot be deleted")]
33 RetentionLocked,
34
35 #[error("internal error: {0}")]
36 Internal(String),
37}
38
39impl From<ValidationErrors> for DppError {
40 fn from(errors: ValidationErrors) -> Self {
41 DppError::Validation(errors)
42 }
43}
44
45#[cfg(test)]
46mod tests {
47 use super::*;
48
49 #[test]
50 fn not_found_display() {
51 let e = DppError::NotFound("passport-123".to_owned());
52 assert_eq!(e.to_string(), "passport not found: passport-123");
53 }
54
55 #[test]
56 fn invalid_transition_display() {
57 let e = DppError::InvalidTransition {
58 current: "archived".to_owned(),
59 required: "draft".to_owned(),
60 };
61 let msg = e.to_string();
62 assert!(
63 msg.contains("archived"),
64 "message should contain current state"
65 );
66 assert!(
67 msg.contains("draft"),
68 "message should contain required state"
69 );
70 }
71
72 #[test]
73 fn validation_display() {
74 let e = DppError::Validation("product_name is required".into());
75 assert!(e.to_string().contains("product_name is required"));
76 }
77}