1use thiserror::Error;
20
21#[derive(Debug, Error, PartialEq, Eq, Clone)]
23pub enum ConsentError {
24 #[error("invalid bailment state: expected {expected}, got {actual}")]
25 InvalidState { expected: String, actual: String },
26
27 #[error("unauthorized: {0}")]
28 Unauthorized(String),
29
30 #[error("expired: {0}")]
31 Expired(String),
32
33 #[error("no consent found for action: {0}")]
34 NoConsent(String),
35
36 #[error("invalid signature")]
37 InvalidSignature,
38
39 #[error("consent denied: {0}")]
40 Denied(String),
41
42 #[error("bailment has been revoked: {bailment_id}")]
43 Revoked { bailment_id: String },
44
45 #[error("consent audit sequence overflow for {counter}")]
46 SequenceOverflow { counter: String },
47
48 #[error("serialization error: {0}")]
49 Serialization(String),
50}
51
52#[cfg(test)]
53mod tests {
54 use super::*;
55
56 #[test]
57 fn error_display_invalid_state() {
58 let e = ConsentError::InvalidState {
59 expected: "Active".into(),
60 actual: "Proposed".into(),
61 };
62 assert!(e.to_string().contains("Active"));
63 assert!(e.to_string().contains("Proposed"));
64 }
65
66 #[test]
67 fn error_display_unauthorized() {
68 let e = ConsentError::Unauthorized("bad actor".into());
69 assert!(e.to_string().contains("bad actor"));
70 }
71
72 #[test]
73 fn error_display_expired() {
74 let e = ConsentError::Expired("ts 1000".into());
75 assert!(e.to_string().contains("ts 1000"));
76 }
77
78 #[test]
79 fn error_display_no_consent() {
80 let e = ConsentError::NoConsent("read".into());
81 assert!(e.to_string().contains("read"));
82 }
83
84 #[test]
85 fn error_display_invalid_signature() {
86 let e = ConsentError::InvalidSignature;
87 assert!(e.to_string().contains("invalid signature"));
88 }
89
90 #[test]
91 fn error_display_denied() {
92 let e = ConsentError::Denied("policy says no".into());
93 assert!(e.to_string().contains("policy says no"));
94 }
95
96 #[test]
97 fn error_clone_eq() {
98 let e1 = ConsentError::InvalidSignature;
99 let e2 = e1.clone();
100 assert_eq!(e1, e2);
101 }
102}