wordstat_rs/
report_list.rs

1use serde_json::Value;
2use crate::{WordstatError, check_status};
3use mockall_double::double;
4#[double] // For mocking the client in unit tests
5use crate::client::Client;
6
7
8/// Possible states of the report
9#[derive(Debug, PartialEq)]
10pub enum StatusCode {
11    Done,
12    Pending,
13    Failed,
14    Unknown
15}
16
17/// Struct describing the status of the report
18#[derive(Debug)]
19#[cfg_attr(test, derive(PartialEq))]
20pub struct ReportStatus {
21    /// The id of the report
22    pub report_id: i64,
23    /// Current status of the report
24    pub status: StatusCode
25}
26
27/// Sends a request to the API asking for a list of reports
28pub async fn get_report_list(client: &Client) -> Result<Vec<ReportStatus>, WordstatError> {
29    let method = "GetWordstatReportList";
30    let result = client.post(method, None).await?;
31
32    check_status(&result)?;
33
34    let Some(data) = result.get("data") else { return Err(WordstatError::BadResponse{ reason: "No data field in response" }) };
35    let Value::Array(reports) = data else { return Err(WordstatError::BadResponse{ reason: "Data field is not an array" }) };
36
37    parse_reports(&reports)
38}
39
40fn parse_reports(data: &Vec<Value>) -> Result<Vec<ReportStatus>, WordstatError> {
41    let mut reports: Vec<ReportStatus> = vec![];
42
43    for report in data {
44        reports.push(parse_report(report)?);
45    }
46
47    Ok(reports)
48}
49
50fn parse_report(report: &Value) -> Result<ReportStatus, WordstatError> {
51    let Some(id_val) = report.get("ReportID") else { return Err(WordstatError::BadResponse{ reason: "No ReportID field" }) };
52    let Some(report_id) = id_val.as_i64() else { return Err(WordstatError::BadResponse{ reason: "ReportID field is not an integer" }) };
53
54    let Some(status_val) = report.get("StatusReport") else { return Err(WordstatError::BadResponse{ reason: "No StatusReport field" }) };
55    let Value::String(status_str) = status_val else { return Err(WordstatError::BadResponse{ reason: "StatusReport field is not a string" }) };
56    let status = match status_str.as_str() {
57        "Done"      => { StatusCode::Done }
58        "Pending"   => { StatusCode::Pending }
59        "Failed"    => { StatusCode::Failed }
60        _           => { StatusCode::Unknown }
61    };
62
63    Ok(ReportStatus {
64        report_id,
65        status
66    })
67}
68
69#[cfg(test)]
70mod tests {
71    use super::*;
72
73    #[test]
74    fn parse_report() {
75        let data = r#"
76                {"ReportID":54312,"StatusReport":"Done"}
77            "#;
78        let input: Value = serde_json::from_str(data).unwrap();
79
80
81        let received = super::parse_report(&input).unwrap();
82
83
84        let expected = ReportStatus {
85            report_id: 54312,
86            status: StatusCode::Done
87        };
88        assert_eq!(received, expected)
89    }
90
91    #[test]
92    #[should_panic]
93    fn parse_invalid_report() {
94        let data = r#"
95                {"Report":54312,"StatusReport":"Done"}
96            "#;
97        let input: Value = serde_json::from_str(data).unwrap();
98
99
100        let received = super::parse_report(&input).unwrap();
101
102
103        let expected = ReportStatus {
104            report_id: 54312,
105            status: StatusCode::Done
106        };
107        assert_eq!(received, expected)
108    }
109
110    #[test]
111    fn get_reposts_list() {
112        let data = r#"
113                {"data" : 
114                [
115                    {"ReportID":54312,"StatusReport":"Done"},
116                    {"ReportID":542,"StatusReport":"Pending"},
117                    {"ReportID":5423,"StatusReport":"Failed"},
118                    {"ReportID":5424,"StatusReport":"what"}
119                ]}
120            "#;
121        let return_value = serde_json::from_str(data).unwrap();
122
123        let mut mock_client = Client::default();
124        mock_client.expect_post()
125            .withf(|method, _params| method == "GetWordstatReportList")
126            .return_once(move |_method, _params| Ok(return_value));
127
128
129        let received = futures::executor::block_on(super::get_report_list(&mock_client)).unwrap();
130
131
132        let expected = vec![
133            ReportStatus {
134                report_id: 54312,
135                status: StatusCode::Done,
136            },
137            ReportStatus {
138                report_id: 542,
139                status: StatusCode::Pending,
140            },
141            ReportStatus {
142                report_id: 5423,
143                status: StatusCode::Failed,
144            },
145            ReportStatus {
146                report_id: 5424,
147                status: StatusCode::Unknown,
148            },
149        ];
150
151        assert_eq!(received, expected)
152    }
153}