1use serde::{Deserialize, Serialize};
4
5use crate::common::{Description, Parameter};
6
7#[derive(Debug, Serialize, Deserialize, PartialEq, Eq)]
9#[serde(rename_all = "camelCase")]
10pub struct Operation {
11 pub name: String,
13 pub since: Option<String>,
15 #[serde(rename = "$value")]
17 pub values: Vec<OperationItem>,
18}
19
20#[derive(Debug, Serialize, Deserialize, PartialEq, Eq)]
22#[serde(rename_all = "camelCase")]
23#[expect(clippy::module_name_repetitions)]
24pub enum OperationItem {
25 Description(Description),
27 Parameters(Parameters),
29}
30
31#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
33pub struct Parameters {
34 #[serde(rename = "$value")]
36 pub values: Vec<ParametersItems>,
37}
38
39#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
41#[serde(rename_all = "camelCase")]
42pub enum ParametersItems {
43 Request(Request),
45 SimpleResponse(SimpleResponse),
47 Exceptions(Exceptions),
49}
50
51#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
53pub struct Request {
54 #[serde(rename = "$value")]
56 pub values: Option<Vec<Parameter>>,
57}
58
59#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
61pub struct SimpleResponse {
62 pub r#type: String,
64 pub description: Description,
66}
67
68#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
70pub struct Exceptions {
71 #[serde(rename = "$value")]
73 pub values: Vec<Exception>,
74}
75
76#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
78pub struct Exception {
79 pub r#type: String,
81 pub description: Description,
83}
84
85#[cfg(test)]
86#[expect(clippy::unwrap_used)]
87#[expect(clippy::indexing_slicing)]
88mod tests {
89 use rstest::rstest;
90 use serde_xml_rs::from_str;
91
92 use super::*;
93 use crate::common::ParameterItem;
94
95 #[rstest]
96 fn test_parse_request() {
97 let xml = r#"
98 <request>
99 <parameter mandatory="true" name="filter" type="MarketFilter">
100 <description>The filter to select desired markets. All markets that match the criteria in the filter
101 are selected.
102 </description>
103 </parameter>
104 <parameter name="locale" type="string">
105 <description>The language used for the response. If not specified, the default is returned.
106 </description>
107 </parameter>
108 </request>
109 "#;
110
111 let req = from_str::<Request>(xml).unwrap();
112 assert_eq!(req.values.unwrap().len(), 2);
113 }
114
115 #[rstest]
116 fn test_parse_simple_response() {
117 let xml = r#"
118 <simpleResponse type="list(EventTypeResult)">
119 <description>output data</description>
120 </simpleResponse>
121 "#;
122
123 let sr = from_str::<SimpleResponse>(xml).unwrap();
124 assert_eq!(sr.r#type, "list(EventTypeResult)");
125 assert_eq!(sr.description.value.unwrap().as_str(), "output data");
126 }
127
128 #[rstest]
129 fn test_parse_exceptions() {
130 let xml = r#"
131 <exceptions>
132 <exception type="APINGException">
133 <description>Generic exception that is thrown if this operation fails for any reason.</description>
134 </exception>
135 </exceptions>
136 "#;
137
138 let exceptions = from_str::<Exceptions>(xml).unwrap();
139 assert_eq!(exceptions.values.len(), 1);
140 assert_eq!(exceptions.values[0].r#type, "APINGException".to_owned());
141 }
142
143 #[rstest]
144 fn test_parse_parameters() {
145 let xml = r#"
146 <parameters>
147 <request>
148 <parameter mandatory="true" name="filter" type="MarketFilter">
149 <description>The filter to select desired markets. All markets that match the criteria in the filter
150 are selected.
151 </description>
152 </parameter>
153 <parameter name="locale" type="string">
154 <description>The language used for the response. If not specified, the default is returned.
155 </description>
156 </parameter>
157 </request>
158 <simpleResponse type="list(EventTypeResult)">
159 <description>output data</description>
160 </simpleResponse>
161 <exceptions>
162 <exception type="APINGException">
163 <description>Generic exception that is thrown if this operation fails for any reason.</description>
164 </exception>
165 </exceptions>
166 </parameters>
167 "#;
168
169 let params = from_str::<Parameters>(xml).unwrap();
170 assert_eq!(params.values.len(), 3);
171 assert!(matches!(params.values[0], ParametersItems::Request(_)));
172 assert!(matches!(
173 params.values[1],
174 ParametersItems::SimpleResponse(_)
175 ));
176 assert!(matches!(params.values[2], ParametersItems::Exceptions(_)));
177 }
178
179 #[rstest]
180 fn test_parse_operation() {
181 let xml = r#"
182 <operation name="listEventTypes" since="1.0.0">
183 <description>Returns a list of Event Types (i.e. Sports) associated with the markets selected by the MarketFilter.
184 </description>
185 <parameters>
186 <request>
187 <parameter mandatory="true" name="filter" type="MarketFilter">
188 <description>The filter to select desired markets. All markets that match the criteria in the filter are selected.
189 </description>
190 </parameter>
191 <parameter name="locale" type="string">
192 <description>The language used for the response. If not specified, the default is returned.
193 </description>
194 </parameter>
195 </request>
196 <simpleResponse type="list(EventTypeResult)">
197 <description>output data</description>
198 </simpleResponse>
199 <exceptions>
200 <exception type="APINGException">
201 <description>Generic exception that is thrown if this operation fails for any reason.</description>
202 </exception>
203 </exceptions>
204 </parameters>
205 </operation>
206 "#;
207
208 let op = from_str::<Operation>(xml).unwrap();
209 let expected = Operation {
210 name: "listEventTypes".to_owned(),
211 since: Some("1.0.0".to_owned()),
212 values: vec![
213 OperationItem::Description(Description {
214 value: Some("Returns a list of Event Types (i.e. Sports) associated with the markets selected by the MarketFilter.".to_owned())
215 }),
216 OperationItem::Parameters(Parameters {
217 values: vec![
218 ParametersItems::Request(Request {
219 values: Some(vec![
220 Parameter {
221 mandatory: Some(true),
222 name: "filter".to_owned(),
223 r#type: "MarketFilter".to_owned(),
224 items: vec![
225 ParameterItem::Description(Description {
226 value: Some("The filter to select desired markets. All markets that match the criteria in the filter are selected.".to_owned())
227 })
228 ]
229 },
230 Parameter {
231 mandatory: None,
232 name: "locale".to_owned(),
233 r#type: "string".to_owned(),
234 items: vec![
235 ParameterItem::Description(Description {
236 value: Some("The language used for the response. If not specified, the default is returned.".to_owned())
237 })
238 ]
239 }
240 ])
241 }),
242 ParametersItems::SimpleResponse(SimpleResponse {
243 r#type: "list(EventTypeResult)".to_owned(),
244 description: Description {
245 value: Some("output data".to_owned())
246 }
247 }),
248 ParametersItems::Exceptions(Exceptions {
249 values: vec![
250 Exception {
251 r#type: "APINGException".to_owned(),
252 description: Description {
253 value: Some("Generic exception that is thrown if this operation fails for any reason.".to_owned())
254 }
255 }
256 ]
257 })
258 ]
259 })
260 ]
261 };
262 assert_eq!(op, expected);
263 }
264
265 #[rstest]
266 fn test_parse_operation_2() {
267 let xml = r#"
268 <operation name="getDeveloperAppKeys" since="1.0.0">
269 <description>
270 Get all application keys owned by the given developer/vendor
271 </description>
272 <parameters>
273 <request/>
274 <simpleResponse type="list(DeveloperApp)">
275 <description>
276 A list of application keys owned by the given developer/vendor
277 </description>
278 </simpleResponse>
279 <exceptions>
280 <exception type="AccountAPINGException">
281 <description>Generic exception that is thrown if this operation fails for any reason.</description>
282 </exception>
283 </exceptions>
284 </parameters>
285 </operation>
286 "#;
287
288 let op = from_str::<Operation>(xml).unwrap();
289 let expected = Operation {
290 name: "getDeveloperAppKeys".to_owned(),
291 since: Some("1.0.0".to_owned()),
292 values: vec![
293 OperationItem::Description(Description {
294 value: Some("Get all application keys owned by the given developer/vendor".to_owned())
295 }),
296 OperationItem::Parameters(Parameters {
297 values: vec![
298 ParametersItems::Request(Request {
299 values: None
300 }),
301 ParametersItems::SimpleResponse(SimpleResponse {
302 description: Description {
303 value: Some("A list of application keys owned by the given developer/vendor".to_owned())
304 },
305 r#type: "list(DeveloperApp)".to_owned()
306 }),
307 ParametersItems::Exceptions(Exceptions {
308 values: vec![
309 Exception {
310 r#type: "AccountAPINGException".to_owned(),
311 description: Description {
312 value: Some("Generic exception that is thrown if this operation fails for any reason.".to_owned())
313 }
314 }
315 ]
316 })
317 ]
318 })
319 ]
320 };
321 assert_eq!(op, expected);
322 }
323}