Skip to main content

supreme_fs/
errors.rs

1//! Error types shared across the crate's online and hybrid storage APIs.
2
3/// Error types for online storage operations
4#[derive(Debug, thiserror::Error)]
5pub enum OnlineStorageError {
6    #[cfg(feature = "online")]
7    #[error("Network error: {0}")]
8    NetworkError(#[from] Box<ureq::Error>),
9
10    #[error("Not found: {0}")]
11    NotFound(String),
12
13    #[error("Upload failed: {0}")]
14    UploadFailed(String),
15
16    #[error("IO error: {0}")]
17    IoError(#[from] std::io::Error),
18}
19
20#[cfg(feature = "online")]
21impl From<ureq::Error> for OnlineStorageError {
22    fn from(err: ureq::Error) -> Self {
23        Self::NetworkError(Box::new(err))
24    }
25}
26
27/// Error types for hybrid storage operations
28#[derive(Debug, thiserror::Error)]
29pub enum HybridStorageError {
30    #[cfg(feature = "online")]
31    #[error("Network error: {0}")]
32    NetworkError(#[from] Box<ureq::Error>),
33
34    #[error("Not found: {0}")]
35    NotFound(String),
36
37    #[error("Corrupted file: {0}")]
38    CorruptedFile(String),
39
40    #[error("Corrupted download: {0}")]
41    CorruptedDownload(String),
42
43    #[error("IO error: {0}")]
44    IoError(#[from] std::io::Error),
45
46    #[error("Hash mismatch: {0}")]
47    HashMismatch(String),
48
49    #[error("Upload failed: {0}")]
50    UploadFailed(String),
51
52    /// The server's backend does not implement an API the client needs: its
53    /// software predates the feature being used (typical signature: the
54    /// legacy catch-all that answers every JSON action POST as "File size
55    /// exceeds server limits.", HTTP 413, or "Unknown action: …"), or the
56    /// API URL does not point at the Supreme backend at all (HTML/empty
57    /// 404). Detected for any API action request, not a specific feature.
58    /// Carries the underlying server response for support/debugging; the
59    /// `Display` text is the end-user-facing message.
60    #[error(
61        "Server version mismatch: the server's backend software does \
62             not support this feature (it is outdated, or the server \
63             address is wrong). Please update the server's PHP backend \
64             files. [server answered: {0}]"
65    )]
66    ServerVersionMismatch(String),
67
68    #[error("Online error: {0}")]
69    OnlineError(#[from] OnlineStorageError),
70}
71
72#[cfg(feature = "online")]
73impl From<ureq::Error> for HybridStorageError {
74    fn from(err: ureq::Error) -> Self {
75        Self::NetworkError(Box::new(err))
76    }
77}
78
79#[cfg(test)]
80mod tests {
81    use super::*;
82
83    #[test]
84    fn hybrid_storage_error_display_messages_are_informative() {
85        assert_eq!(
86            HybridStorageError::NotFound("abc123".to_string()).to_string(),
87            "Not found: abc123"
88        );
89        assert_eq!(
90            HybridStorageError::CorruptedFile("save.dat".to_string()).to_string(),
91            "Corrupted file: save.dat"
92        );
93        assert_eq!(
94            HybridStorageError::CorruptedDownload("deadbeef".to_string()).to_string(),
95            "Corrupted download: deadbeef"
96        );
97        assert_eq!(
98            HybridStorageError::HashMismatch("deadbeef".to_string()).to_string(),
99            "Hash mismatch: deadbeef"
100        );
101        assert_eq!(
102            HybridStorageError::UploadFailed("HTTP 500".to_string()).to_string(),
103            "Upload failed: HTTP 500"
104        );
105        assert_eq!(
106            HybridStorageError::ServerVersionMismatch(
107                "File size exceeds server limits. (HTTP 413)".to_string()
108            )
109            .to_string(),
110            "Server version mismatch: the server's backend software does \
111             not support this feature (it is outdated, or the server \
112             address is wrong). Please update the server's PHP backend \
113             files. [server answered: File size exceeds server limits. \
114             (HTTP 413)]"
115        );
116    }
117
118    #[test]
119    fn online_storage_error_display_messages_are_informative() {
120        assert_eq!(
121            OnlineStorageError::NotFound("profile.json".to_string()).to_string(),
122            "Not found: profile.json"
123        );
124        assert_eq!(
125            OnlineStorageError::UploadFailed("timeout".to_string()).to_string(),
126            "Upload failed: timeout"
127        );
128    }
129
130    #[test]
131    fn io_error_converts_into_hybrid_storage_error() {
132        let io_err = std::io::Error::other("disk full");
133        let err: HybridStorageError = io_err.into();
134        assert!(matches!(err, HybridStorageError::IoError(_)));
135        assert!(err.to_string().starts_with("IO error:"));
136    }
137
138    #[test]
139    fn io_error_converts_into_online_storage_error() {
140        let io_err = std::io::Error::other("disk full");
141        let err: OnlineStorageError = io_err.into();
142        assert!(matches!(err, OnlineStorageError::IoError(_)));
143    }
144
145    #[test]
146    fn online_storage_error_converts_into_hybrid_storage_error() {
147        let online_err = OnlineStorageError::NotFound("x".to_string());
148        let err: HybridStorageError = online_err.into();
149        assert_eq!(err.to_string(), "Online error: Not found: x");
150    }
151}