1use std::{error::Error, fmt};
7
8#[derive(Debug, Clone, PartialEq, Eq)]
13pub enum SorobanHelperError {
14 TransactionFailed(String),
16
17 TransactionSimulationFailed(String),
19
20 ContractCodeAlreadyExists,
22
23 NetworkRequestFailed(String),
25
26 SigningFailed(String),
28
29 XdrEncodingFailed(String),
31
32 InvalidArgument(String),
34
35 TransactionBuildFailed(String),
37
38 Unauthorized(String),
40
41 ContractDeployedConfigsNotSet,
43
44 FileReadError(String),
46
47 ConversionError(String),
49
50 NotSupported(String),
52}
53
54impl fmt::Display for SorobanHelperError {
55 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
56 match self {
57 Self::TransactionFailed(msg) => write!(f, "Transaction failed: {}", msg),
58 Self::TransactionSimulationFailed(msg) => {
59 write!(f, "Transaction simulation failed: {}", msg)
60 }
61 Self::ContractCodeAlreadyExists => write!(f, "Contract code already exists"),
62 Self::NetworkRequestFailed(msg) => write!(f, "Network request failed: {}", msg),
63 Self::SigningFailed(msg) => write!(f, "Signing operation failed: {}", msg),
64 Self::XdrEncodingFailed(msg) => write!(f, "XDR encoding failed: {}", msg),
65 Self::InvalidArgument(msg) => write!(f, "Invalid argument: {}", msg),
66 Self::TransactionBuildFailed(msg) => write!(f, "Transaction build failed: {}", msg),
67 Self::Unauthorized(msg) => write!(f, "Unauthorized: {}", msg),
68 Self::ContractDeployedConfigsNotSet => write!(f, "Contract deployed configs not set"),
69 Self::FileReadError(msg) => write!(f, "File read error: {}", msg),
70 Self::ConversionError(msg) => write!(f, "Conversion error: {}", msg),
71 Self::NotSupported(msg) => write!(f, "Not supported: {}", msg),
72 }
73 }
74}
75
76impl Error for SorobanHelperError {}
77
78impl From<stellar_xdr::curr::Error> for SorobanHelperError {
80 fn from(err: stellar_xdr::curr::Error) -> Self {
81 Self::XdrEncodingFailed(err.to_string())
82 }
83}
84
85impl From<std::io::Error> for SorobanHelperError {
87 fn from(err: std::io::Error) -> Self {
88 Self::InvalidArgument(format!("File operation failed: {}", err))
89 }
90}
91#[cfg(test)]
92mod tests {
93 use super::*;
94 use std::io::{Error as IoError, ErrorKind};
95
96 #[test]
97 fn test_display_implementations() {
98 let cases = [
99 (
100 SorobanHelperError::TransactionFailed("timeout".to_string()),
101 "Transaction failed: timeout",
102 ),
103 (
104 SorobanHelperError::ContractCodeAlreadyExists,
105 "Contract code already exists",
106 ),
107 (
108 SorobanHelperError::NetworkRequestFailed("connection refused".to_string()),
109 "Network request failed: connection refused",
110 ),
111 (
112 SorobanHelperError::SigningFailed("invalid key".to_string()),
113 "Signing operation failed: invalid key",
114 ),
115 (
116 SorobanHelperError::XdrEncodingFailed("invalid format".to_string()),
117 "XDR encoding failed: invalid format",
118 ),
119 (
120 SorobanHelperError::InvalidArgument("wrong type".to_string()),
121 "Invalid argument: wrong type",
122 ),
123 (
124 SorobanHelperError::TransactionBuildFailed("missing field".to_string()),
125 "Transaction build failed: missing field",
126 ),
127 (
128 SorobanHelperError::Unauthorized("missing signature".to_string()),
129 "Unauthorized: missing signature",
130 ),
131 (
132 SorobanHelperError::ContractDeployedConfigsNotSet,
133 "Contract deployed configs not set",
134 ),
135 (
136 SorobanHelperError::FileReadError("file not found".to_string()),
137 "File read error: file not found",
138 ),
139 (
140 SorobanHelperError::ConversionError("invalid type conversion".to_string()),
141 "Conversion error: invalid type conversion",
142 ),
143 (
144 SorobanHelperError::TransactionSimulationFailed("bad input".to_string()),
145 "Transaction simulation failed: bad input",
146 ),
147 (
148 SorobanHelperError::NotSupported("feature not implemented".to_string()),
149 "Not supported: feature not implemented",
150 ),
151 ];
152
153 for (error, expected_msg) in cases {
154 assert_eq!(error.to_string(), expected_msg);
155 }
156 }
157
158 #[test]
159 fn test_from_io_error() {
160 let io_error = IoError::new(ErrorKind::NotFound, "file not found");
161 let helper_error = SorobanHelperError::from(io_error);
162
163 assert!(
164 matches!(helper_error, SorobanHelperError::InvalidArgument(_)),
165 "Expected InvalidArgument variant"
166 );
167
168 let error_string = helper_error.to_string();
169 assert!(error_string.contains("file not found"));
170 assert!(error_string.contains("File operation failed"));
171 }
172
173 #[test]
174 fn test_from_xdr_error() {
175 let xdr_error = stellar_xdr::curr::Error::Invalid;
177 let helper_error = SorobanHelperError::from(xdr_error);
178
179 assert!(
180 matches!(helper_error, SorobanHelperError::XdrEncodingFailed(_)),
181 "Expected XdrEncodingFailed variant"
182 );
183
184 let error_string = helper_error.to_string();
185 assert!(error_string.contains("XDR encoding failed"));
186 }
187
188 #[test]
189 fn test_error_trait_implementation() {
190 let error = SorobanHelperError::InvalidArgument("test error".to_string());
192 let _: &dyn Error = &error; let debug_str = format!("{:?}", error);
196 assert!(debug_str.contains("InvalidArgument"));
197 }
198
199 #[test]
200 fn test_error_equality() {
201 let error1 = SorobanHelperError::InvalidArgument("test error".to_string());
203 let error2 = SorobanHelperError::InvalidArgument("test error".to_string());
204 let error3 = SorobanHelperError::InvalidArgument("different error".to_string());
205
206 assert_eq!(error1, error2);
207 assert_ne!(error1, error3);
208
209 let different_type = SorobanHelperError::NetworkRequestFailed("test error".to_string());
210 assert_ne!(error1, different_type);
211 }
212
213 #[test]
214 fn test_error_cloning() {
215 let original = SorobanHelperError::TransactionFailed("test failure".to_string());
217 let cloned = original.clone();
218
219 assert_eq!(original, cloned);
220 }
221}