betfair_xml_parser/
exception_type.rs

1//! Betfair XML file <exceptionType> tag parser
2
3use serde::{Deserialize, Serialize};
4
5use crate::common::{Description, Parameter};
6
7/// Representation of the <exceptionType> tag
8#[derive(Debug, Serialize, Deserialize, PartialEq, Eq)]
9#[serde(rename_all = "camelCase")]
10pub struct ExceptionType {
11    /// The name of the exception
12    pub name: String,
13    /// The prefix of the exception
14    pub prefix: String,
15    /// Vector of possible values
16    #[serde(rename = "$value")]
17    pub values: Vec<ExceptionTypeItems>,
18}
19
20/// A child item of the <exceptionType> tag
21#[derive(Debug, Serialize, Deserialize, PartialEq, Eq)]
22#[serde(rename_all = "camelCase")]
23#[expect(clippy::module_name_repetitions)]
24pub enum ExceptionTypeItems {
25    /// The description of the exception
26    Description(Description),
27    /// A parameter tag of the exception
28    Parameter(Parameter),
29}
30
31#[cfg(test)]
32mod tests {
33    use rstest::rstest;
34    use serde_xml_rs::from_str;
35
36    use super::*;
37
38    #[rstest]
39    fn test_parse_aping_exception() {
40        let xml = r#"
41    <exceptionType name="APINGException" prefix="ANGX">
42        <description>This exception is thrown when an operation fails</description>
43        <parameter name="errorCode" type="string">
44            <description>the unique code for this error</description>
45            <validValues>
46                <value id="1" name="TOO_MUCH_DATA">
47                    <description>The operation requested too much data</description>
48                </value>
49                <value id="2" name="INVALID_INPUT_DATA">
50                    <description>Invalid input data</description>
51                </value>
52                <value id="3" name="INVALID_SESSION_INFORMATION">
53                    <description>The session token passed is invalid</description>
54                </value>
55                <value id="4" name="NO_APP_KEY">
56                    <description>An application key is required for this operation</description>
57                </value>
58                <value id="5" name="NO_SESSION">
59                    <description>A session token is required for this operation</description>
60                </value>
61                <value id="6" name="UNEXPECTED_ERROR">
62                    <description>An unexpected internal error occurred that prevented successful request processing.
63                    </description>
64                </value>
65                <value id="7" name="INVALID_APP_KEY">
66                    <description>The application key passed is invalid</description>
67                </value>
68                <value id="8" name="TOO_MANY_REQUESTS">
69                    <description>There are too many pending requests</description>
70                </value>
71                <value id="9" name="SERVICE_BUSY">
72                    <description>The service is currently too busy to service this request</description>
73                </value>
74                <value id="10" name="TIMEOUT_ERROR">
75                    <description>Internal call to downstream service timed out</description>
76                </value>
77                <value id="11" name="APP_KEY_CREATION_FAILED">
78                    <description>The application key creation has failed</description>
79                </value>
80                <value id="12" name="DUPLICATE_APP_NAME">
81                    <description>The application name specified already exists</description>
82                </value>
83                <value id="13" name="APP_CREATION_FAILED">
84                    <description>The application name specified is too long</description>
85                </value>
86                <value id="14" name="REQUEST_SIZE_EXCEEDS_LIMIT">
87                    <description>The request has exceeded the maximum allowed size</description>
88                </value>
89                <value id="15" name="ACCESS_DENIED">
90                    <description>The access to this functionality is not allowed</description>
91                </value>
92                <value id="16" name="INVALID_MARKET_GROUP">
93                    <description>
94                        Provided market group id does not identify a known market group
95                    </description>
96                </value>
97                <value id="17" name="EXPOSURE_LIMIT_NOT_EXIST">
98                    <description>
99                        Unable to delete/update limit as it doesn't exist
100                    </description>
101                </value>
102                <value id="18" name="MARKET_GROUP_NOT_BLOCKED">
103                    <description>
104                        Unable to unblock market group after exposure limit breach, market group is not blocked
105                    </description>
106                </value>
107            </validValues>
108        </parameter>
109        <parameter name="errorDetails" type="string">
110            <description>the stack trace of the error</description>
111        </parameter>
112        <parameter name="requestUUID" type="string">
113            <description/>
114        </parameter>
115    </exceptionType>
116    "#;
117
118        let exception = from_str::<ExceptionType>(xml);
119
120        match exception {
121            Ok(exception) => {
122                assert_eq!(exception.name, "APINGException");
123                assert_eq!(exception.prefix, "ANGX");
124                assert_eq!(exception.values.len(), 4);
125                assert!(exception.values.first().is_some_and(|item| {
126                    matches!(item, &ExceptionTypeItems::Description(Description {
127                        value: Some(ref desc)
128                    }) if desc == "This exception is thrown when an operation fails")
129                }));
130
131                assert!(
132                    exception
133                        .values
134                        .get(1)
135                        .is_some_and(|item| { matches!(item, &ExceptionTypeItems::Parameter(_)) })
136                );
137            }
138            Err(err) => {
139                log::error!("Failed to parse XML: {err}");
140            }
141        }
142    }
143}