Skip to main content

exo_consent/
error.rs

1// Copyright 2026 Exochain Foundation
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at:
6//
7//     https://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14//
15// SPDX-License-Identifier: Apache-2.0
16
17//! Consent-specific error types.
18
19use thiserror::Error;
20
21/// Errors arising from consent operations.
22#[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}