|
5 | 5 | ******************************************************************************/ |
6 | 6 |
|
7 | 7 | use crate::error::codes::DeribitErrorCode; |
| 8 | +use crate::error::types::DeribitError; |
8 | 9 |
|
9 | | -// Conversion from i32 to DeribitErrorCode |
10 | | -impl From<i32> for DeribitErrorCode { |
11 | | - fn from(code: i32) -> Self { |
12 | | - match code { |
13 | | - 0 => Self::Success, |
14 | | - 10000 => Self::AuthorizationRequired, |
15 | | - 10001 => Self::Error, |
16 | | - 10002 => Self::QtyTooLow, |
17 | | - 10003 => Self::OrderOverlap, |
18 | | - 10004 => Self::OrderNotFound, |
19 | | - 10005 => Self::PriceTooLow, |
20 | | - 10006 => Self::PriceTooLow4Idx, |
21 | | - 10007 => Self::PriceTooHigh, |
22 | | - 10009 => Self::NotEnoughFunds, |
23 | | - 10010 => Self::AlreadyClosed, |
24 | | - 10011 => Self::PriceNotAllowed, |
25 | | - 10012 => Self::BookClosed, |
26 | | - 10013 => Self::PmeMaxTotalOpenOrders, |
27 | | - 10014 => Self::PmeMaxFutureOpenOrders, |
28 | | - 10015 => Self::PmeMaxOptionOpenOrders, |
29 | | - 10016 => Self::PmeMaxFutureOpenOrdersSize, |
30 | | - 10017 => Self::PmeMaxOptionOpenOrdersSize, |
31 | | - 10018 => Self::NonPmeMaxFuturePositionSize, |
32 | | - 10019 => Self::LockedByAdmin, |
33 | | - 10020 => Self::InvalidOrUnsupportedInstrument, |
34 | | - 10021 => Self::InvalidAmount, |
35 | | - 10022 => Self::InvalidQuantity, |
36 | | - 10023 => Self::InvalidPrice, |
37 | | - 10024 => Self::InvalidMaxShow, |
38 | | - 10025 => Self::InvalidOrderId, |
39 | | - 10026 => Self::PricePrecisionExceeded, |
40 | | - 10027 => Self::NonIntegerContractAmount, |
41 | | - 10028 => Self::TooManyRequests, |
42 | | - 10029 => Self::NotOwnerOfOrder, |
43 | | - 10030 => Self::MustBeWebsocketRequest, |
44 | | - 10031 => Self::InvalidArgsForInstrument, |
45 | | - 10032 => Self::WholeCostTooLow, |
46 | | - 10033 => Self::NotImplemented, |
47 | | - 10034 => Self::TriggerPriceTooHigh, |
48 | | - 10035 => Self::TriggerPriceTooLow, |
49 | | - 10036 => Self::InvalidMaxShowAmount, |
50 | | - 10037 => Self::NonPmeTotalShortOptionsPositionsSize, |
51 | | - 10038 => Self::PmeMaxRiskReducingOrders, |
52 | | - 10039 => Self::NotEnoughFundsInCurrency, |
53 | | - 10040 => Self::Retry, |
54 | | - 10041 => Self::SettlementInProgress, |
55 | | - 10043 => Self::PriceWrongTick, |
56 | | - 10044 => Self::TriggerPriceWrongTick, |
57 | | - 10045 => Self::CanNotCancelLiquidationOrder, |
58 | | - 10046 => Self::CanNotEditLiquidationOrder, |
59 | | - 10047 => Self::MatchingEngineQueueFull, |
60 | | - 10048 => Self::NotOnThisServer, |
61 | | - 10049 => Self::CancelOnDisconnectFailed, |
62 | | - 10066 => Self::TooManyConcurrentRequests, |
63 | | - 10072 => Self::DisabledWhilePositionLock, |
64 | | - 11008 => Self::AlreadyFilled, |
65 | | - 11013 => Self::MaxSpotOpenOrders, |
66 | | - 11021 => Self::PostOnlyPriceModificationNotPossible, |
67 | | - 11022 => Self::MaxSpotOrderQuantity, |
68 | | - 11029 => Self::InvalidArguments, |
69 | | - 11030 => Self::OtherReject, |
70 | | - 11031 => Self::OtherError, |
71 | | - 11035 => Self::NoMoreTriggers, |
72 | | - 11036 => Self::InvalidTriggerPrice, |
73 | | - 11037 => Self::OutdatedInstrumentForIvOrder, |
74 | | - 11038 => Self::NoAdvForFutures, |
75 | | - 11039 => Self::NoAdvPostonly, |
76 | | - 11041 => Self::NotAdvOrder, |
77 | | - 11042 => Self::PermissionDenied, |
78 | | - 11043 => Self::BadArgument, |
79 | | - 11044 => Self::NotOpenOrder, |
80 | | - 11045 => Self::InvalidEvent, |
81 | | - 11046 => Self::OutdatedInstrument, |
82 | | - 11047 => Self::UnsupportedArgCombination, |
83 | | - 11048 => Self::WrongMaxShowForOption, |
84 | | - 11049 => Self::BadArguments, |
85 | | - 11050 => Self::BadRequest, |
86 | | - 11051 => Self::SystemMaintenance, |
87 | | - 11052 => Self::SubscribeErrorUnsubscribed, |
88 | | - 11053 => Self::TransferNotFound, |
89 | | - 11054 => Self::PostOnlyReject, |
90 | | - 11055 => Self::PostOnlyNotAllowed, |
91 | | - 11056 => Self::UnauthenticatedPublicRequestsTemporarilyDisabled, |
92 | | - 11090 => Self::InvalidAddr, |
93 | | - 11091 => Self::InvalidTransferAddress, |
94 | | - 11092 => Self::AddressAlreadyExist, |
95 | | - 11093 => Self::MaxAddrCountExceeded, |
96 | | - 11094 => Self::InternalServerError, |
97 | | - 11095 => Self::DisabledDepositAddressCreation, |
98 | | - 11096 => Self::AddressBelongsToUser, |
99 | | - 11097 => Self::NoDepositAddress, |
100 | | - 11098 => Self::AccountLocked, |
101 | | - 12001 => Self::TooManySubaccounts, |
102 | | - 12002 => Self::WrongSubaccountName, |
103 | | - 12003 => Self::LoginOverLimit, |
104 | | - 12004 => Self::RegistrationOverLimit, |
105 | | - 12005 => Self::CountryIsBanned, |
106 | | - 12100 => Self::TransferNotAllowed, |
107 | | - 12998 => Self::SecurityKeyAuthorizationOverLimit, |
108 | | - 13004 => Self::InvalidCredentials, |
109 | | - 13005 => Self::PwdMatchError, |
110 | | - 13006 => Self::SecurityError, |
111 | | - 13007 => Self::UserNotFound, |
112 | | - 13008 => Self::RequestFailed, |
113 | | - 13009 => Self::Unauthorized, |
114 | | - 13010 => Self::ValueRequired, |
115 | | - 13011 => Self::ValueTooShort, |
116 | | - 13012 => Self::UnavailableInSubaccount, |
117 | | - 13013 => Self::InvalidPhoneNumber, |
118 | | - 13014 => Self::CannotSendSms, |
119 | | - 13015 => Self::InvalidSmsCode, |
120 | | - 13016 => Self::InvalidInput, |
121 | | - 13018 => Self::InvalidContentType, |
122 | | - 13019 => Self::OrderbookClosed, |
123 | | - 13020 => Self::NotFound, |
124 | | - 13021 => Self::Forbidden, |
125 | | - 13025 => Self::MethodSwitchedOffByAdmin, |
126 | | - 13028 => Self::TemporarilyUnavailable, |
127 | | - 13030 => Self::MmpTrigger, |
128 | | - 13031 => Self::VerificationRequired, |
129 | | - 13032 => Self::NonUniqueOrderLabel, |
130 | | - 13034 => Self::NoMoreSecurityKeysAllowed, |
131 | | - 13035 => Self::ActiveComboLimitReached, |
132 | | - 13036 => Self::UnavailableForComboBooks, |
133 | | - 13037 => Self::IncompleteKycData, |
134 | | - 13040 => Self::MmpRequired, |
135 | | - 13042 => Self::CodNotEnabled, |
136 | | - 13043 => Self::QuotesFrozen, |
137 | | - 13403 => Self::ScopeExceeded, |
138 | | - 13503 => Self::Unavailable, |
139 | | - 13666 => Self::RequestCancelledByUser, |
140 | | - 13777 => Self::Replaced, |
141 | | - 13778 => Self::RawSubscriptionsNotAvailableForUnauthorized, |
142 | | - 13780 => Self::MovePositionsOverLimit, |
143 | | - 13781 => Self::CouponAlreadyUsed, |
144 | | - 13791 => Self::KycTransferAlreadyInitiated, |
145 | | - _ => Self::Unknown(code), |
| 10 | +// Conversion from DeribitErrorCode to DeribitError |
| 11 | +impl From<DeribitErrorCode> for DeribitError { |
| 12 | + fn from(error_code: DeribitErrorCode) -> Self { |
| 13 | + DeribitError::Api { |
| 14 | + code: error_code.code(), |
| 15 | + message: error_code.message().to_string(), |
| 16 | + } |
| 17 | + } |
| 18 | +} |
| 19 | + |
| 20 | +// Conversion from HTTP status codes to DeribitErrorCode |
| 21 | +impl From<u16> for DeribitErrorCode { |
| 22 | + fn from(status: u16) -> Self { |
| 23 | + match status { |
| 24 | + 400 => DeribitErrorCode::BadRequest, |
| 25 | + 401 => DeribitErrorCode::Unauthorized, |
| 26 | + 403 => DeribitErrorCode::Forbidden, |
| 27 | + 404 => DeribitErrorCode::NotFound, |
| 28 | + 429 => DeribitErrorCode::TooManyRequests, |
| 29 | + 500 => DeribitErrorCode::InternalServerError, |
| 30 | + 503 => DeribitErrorCode::TemporarilyUnavailable, |
| 31 | + _ => DeribitErrorCode::Unknown(status as i32), |
| 32 | + } |
| 33 | + } |
| 34 | +} |
| 35 | + |
| 36 | +// Conversion from string error messages to DeribitError |
| 37 | +impl From<String> for DeribitError { |
| 38 | + fn from(message: String) -> Self { |
| 39 | + DeribitError::Connection(message) |
| 40 | + } |
| 41 | +} |
| 42 | + |
| 43 | +impl From<&str> for DeribitError { |
| 44 | + fn from(message: &str) -> Self { |
| 45 | + DeribitError::Connection(message.to_string()) |
| 46 | + } |
| 47 | +} |
| 48 | + |
| 49 | +// Conversion from serde_json::Error to DeribitError |
| 50 | +impl From<serde_json::Error> for DeribitError { |
| 51 | + fn from(error: serde_json::Error) -> Self { |
| 52 | + DeribitError::Serialization(error.to_string()) |
| 53 | + } |
| 54 | +} |
| 55 | + |
| 56 | +#[cfg(test)] |
| 57 | +mod tests { |
| 58 | + use super::*; |
| 59 | + |
| 60 | + #[test] |
| 61 | + fn test_error_code_to_deribit_error_conversion() { |
| 62 | + let error_code = DeribitErrorCode::AuthorizationRequired; |
| 63 | + let deribit_error: DeribitError = error_code.into(); |
| 64 | + |
| 65 | + match deribit_error { |
| 66 | + DeribitError::Api { code, message } => { |
| 67 | + assert_eq!(code, 10000); |
| 68 | + assert_eq!(message, "authorization_required"); |
| 69 | + } |
| 70 | + _ => panic!("Expected Api error"), |
| 71 | + } |
| 72 | + } |
| 73 | + |
| 74 | + #[test] |
| 75 | + fn test_http_status_to_error_code_conversion() { |
| 76 | + // Test HTTP status to DeribitErrorCode conversion |
| 77 | + let error_400 = DeribitErrorCode::from(400u16); |
| 78 | + assert_eq!(error_400, DeribitErrorCode::BadRequest); |
| 79 | + assert_eq!(error_400.code(), 11050); // BadRequest maps to 11050 |
| 80 | + |
| 81 | + let error_401 = DeribitErrorCode::from(401u16); |
| 82 | + assert_eq!(error_401, DeribitErrorCode::Unauthorized); |
| 83 | + assert_eq!(error_401.code(), 13009); // Unauthorized maps to 13009 |
| 84 | + |
| 85 | + let error_403 = DeribitErrorCode::from(403u16); |
| 86 | + assert_eq!(error_403, DeribitErrorCode::Forbidden); |
| 87 | + assert_eq!(error_403.code(), 13021); // Forbidden maps to 13021 |
| 88 | + |
| 89 | + let error_404 = DeribitErrorCode::from(404u16); |
| 90 | + assert_eq!(error_404, DeribitErrorCode::NotFound); |
| 91 | + assert_eq!(error_404.code(), 13020); // NotFound maps to 13020 |
| 92 | + |
| 93 | + let error_429 = DeribitErrorCode::from(429u16); |
| 94 | + assert_eq!(error_429, DeribitErrorCode::TooManyRequests); |
| 95 | + assert_eq!(error_429.code(), 10028); // TooManyRequests maps to 10028 |
| 96 | + |
| 97 | + let error_500 = DeribitErrorCode::from(500u16); |
| 98 | + assert_eq!(error_500, DeribitErrorCode::InternalServerError); |
| 99 | + assert_eq!(error_500.code(), 11094); // InternalServerError maps to 11094 |
| 100 | + |
| 101 | + let error_503 = DeribitErrorCode::from(503u16); |
| 102 | + assert_eq!(error_503, DeribitErrorCode::TemporarilyUnavailable); |
| 103 | + assert_eq!(error_503.code(), 13028); // TemporarilyUnavailable maps to 13028 |
| 104 | + |
| 105 | + // Test unknown status code |
| 106 | + let error_418 = DeribitErrorCode::from(418u16); |
| 107 | + assert_eq!(error_418, DeribitErrorCode::Unknown(418)); |
| 108 | + assert_eq!(error_418.code(), 418); |
| 109 | + |
| 110 | + // Verify all have proper messages |
| 111 | + for error in [ |
| 112 | + error_400, error_401, error_403, error_404, error_429, error_500, error_503, error_418, |
| 113 | + ] { |
| 114 | + assert!(!error.message().is_empty()); |
| 115 | + } |
| 116 | + } |
| 117 | + |
| 118 | + #[test] |
| 119 | + fn test_string_to_deribit_error_conversion() { |
| 120 | + let message = "Connection failed".to_string(); |
| 121 | + let error: DeribitError = message.clone().into(); |
| 122 | + |
| 123 | + match error { |
| 124 | + DeribitError::Connection(msg) => { |
| 125 | + assert_eq!(msg, message); |
| 126 | + } |
| 127 | + _ => panic!("Expected Connection error"), |
| 128 | + } |
| 129 | + } |
| 130 | + |
| 131 | + #[test] |
| 132 | + fn test_str_to_deribit_error_conversion() { |
| 133 | + let message = "Connection timeout"; |
| 134 | + let error: DeribitError = message.into(); |
| 135 | + |
| 136 | + match error { |
| 137 | + DeribitError::Connection(msg) => { |
| 138 | + assert_eq!(msg, message); |
| 139 | + } |
| 140 | + _ => panic!("Expected Connection error"), |
| 141 | + } |
| 142 | + } |
| 143 | + |
| 144 | + #[test] |
| 145 | + fn test_serde_json_error_conversion() { |
| 146 | + let invalid_json = r#"{"invalid": json}"#; |
| 147 | + let json_error = serde_json::from_str::<serde_json::Value>(invalid_json).unwrap_err(); |
| 148 | + let deribit_error: DeribitError = json_error.into(); |
| 149 | + |
| 150 | + match deribit_error { |
| 151 | + DeribitError::Serialization(message) => { |
| 152 | + assert!(!message.is_empty()); |
| 153 | + assert!(message.contains("expected")); |
| 154 | + } |
| 155 | + _ => panic!("Expected Serialization error"), |
| 156 | + } |
| 157 | + } |
| 158 | + |
| 159 | + #[test] |
| 160 | + fn test_comprehensive_error_code_conversions() { |
| 161 | + // Test various error codes to ensure they convert properly |
| 162 | + let error_codes = vec![ |
| 163 | + DeribitErrorCode::Success, |
| 164 | + DeribitErrorCode::Error, |
| 165 | + DeribitErrorCode::QtyTooLow, |
| 166 | + DeribitErrorCode::NotEnoughFunds, |
| 167 | + DeribitErrorCode::InvalidAmount, |
| 168 | + DeribitErrorCode::TooManyRequests, |
| 169 | + DeribitErrorCode::Unknown(99999), |
| 170 | + ]; |
| 171 | + |
| 172 | + for error_code in error_codes { |
| 173 | + let deribit_error: DeribitError = error_code.clone().into(); |
| 174 | + match deribit_error { |
| 175 | + DeribitError::Api { code, message } => { |
| 176 | + assert_eq!(code, error_code.code()); |
| 177 | + assert_eq!(message, error_code.message()); |
| 178 | + } |
| 179 | + _ => panic!("Expected Api error for {:?}", error_code), |
| 180 | + } |
| 181 | + } |
| 182 | + } |
| 183 | + |
| 184 | + #[test] |
| 185 | + fn test_error_chain_conversions() { |
| 186 | + // Test that we can chain conversions |
| 187 | + let status_code: u16 = 401; |
| 188 | + let error_code: DeribitErrorCode = status_code.into(); |
| 189 | + let deribit_error: DeribitError = error_code.into(); |
| 190 | + |
| 191 | + match deribit_error { |
| 192 | + DeribitError::Api { code, message } => { |
| 193 | + assert_eq!(code, 13009); // Unauthorized code |
| 194 | + assert_eq!(message, "unauthorized"); |
| 195 | + } |
| 196 | + _ => panic!("Expected Api error"), |
146 | 197 | } |
147 | 198 | } |
148 | 199 | } |
0 commit comments