1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
use std::{
    error::Error,
    fmt::{Display, Formatter, Result as FmtResult},
};

/// The error type used to convey Aspen errors.
#[derive(Debug, Eq, PartialEq)]
pub enum AspenError {
    /// An invalid action was specified in a policy. The string is the invalid action.
    InvalidAction(String),

    /// An invalid condition operator was specified in a condition clause. The string contains the invalid operator.
    InvalidConditionOperator(String),

    /// An invalid policy version was specified in a policy. The string contains the invalid version.
    InvalidPolicyVersion(String),

    /// An invalid principal was specified ina policy. The string contains the invalid principal.
    InvalidPrincipal(String),

    /// An invalid resource was specified in a policy. The string contains the invalid resource.
    InvalidResource(String),

    /// An invalid variable substitution was specified in a policy. The string contains the invalid variable.
    InvalidSubstitution(String),
}

impl Display for AspenError {
    fn fmt(&self, f: &mut Formatter) -> FmtResult {
        match self {
            Self::InvalidAction(action) => write!(f, "Invalid action: {action}"),
            Self::InvalidConditionOperator(operator) => write!(f, "Invalid condition operator: {operator}"),
            Self::InvalidPolicyVersion(version) => write!(f, "Invalid policy version: {version}"),
            Self::InvalidPrincipal(principal) => write!(f, "Invalid principal: {principal}"),
            Self::InvalidResource(resource) => write!(f, "Invalid resource: {resource}"),
            Self::InvalidSubstitution(element) => write!(f, "Invalid variable substitution: {element}"),
        }
    }
}

impl Error for AspenError {}

#[cfg(test)]
mod tests {
    use {
        crate::AspenError,
        pretty_assertions::{assert_eq, assert_ne},
    };

    #[test_log::test]
    fn test_display() {
        let _ = format!("{:?}", AspenError::InvalidAction("foo".to_string()));
        assert_eq!(AspenError::InvalidAction("foo".to_string()).to_string(), "Invalid action: foo");

        let _ = format!("{:?}", AspenError::InvalidPrincipal("foo".to_string()));
        assert_eq!(AspenError::InvalidPrincipal("foo".to_string()).to_string(), "Invalid principal: foo");

        let _ = format!("{:?}", AspenError::InvalidResource("foo".to_string()));
        assert_eq!(AspenError::InvalidResource("foo".to_string()).to_string(), "Invalid resource: foo");
    }

    #[test_log::test]
    fn test_eq() {
        let e1a = AspenError::InvalidAction("foo".to_string());
        let e1b = AspenError::InvalidAction("foo".to_string());
        let e2a = AspenError::InvalidPrincipal("foo".to_string());
        let e2b = AspenError::InvalidPrincipal("foo".to_string());
        let e3a = AspenError::InvalidResource("foo".to_string());
        let e3b = AspenError::InvalidResource("foo".to_string());
        let e4 = AspenError::InvalidAction("bar".to_string());
        let e5 = AspenError::InvalidPrincipal("bar".to_string());
        let e6 = AspenError::InvalidResource("bar".to_string());

        assert_eq!(e1a, e1b);
        assert_eq!(e2a, e2b);
        assert_eq!(e3a, e3b);
        assert_ne!(e1a, e2a);
        assert_ne!(e1a, e3a);
        assert_ne!(e1a, e4);
        assert_ne!(e1a, e5);
        assert_ne!(e1a, e6);
        assert_ne!(e2a, e3a);
        assert_ne!(e2a, e4);
        assert_ne!(e2a, e5);
        assert_ne!(e2a, e6);
        assert_ne!(e3a, e4);
        assert_ne!(e3a, e5);
        assert_ne!(e3a, e6);
    }
}