rusty_dropbox_sdk 0.8.2

Unofficial SDK for dropbox in Rust
Documentation
/// Every request type targeted by `implement_tests!` needs a `default_test_extras()`
/// function that returns a `Self` with dummy values for all fields that
/// aren't `access_token` or `payload`. Most Request structs only have those
/// two fields; `default_test_extras()` is generated by `implement_utils!` as
/// an empty struct literal using struct-update syntax. Content-upload
/// Request structs override it to set `data: None`.
///
/// Macro to implement tests for both synchronous and asynchronous API calls.
/// This macro generates test functions that mock API endpoints and verify the expected behavior of requests.
///
/// # Parameters:
/// - `$endpoint`: The API endpoint being tested.
/// - `$headers`: A vector of headers to include in the request.
/// - `$req`: The request type used in the test (struct representing the API request).
/// - `$payload`: The type of the payload being sent in the request.
///
/// Each test now spins up its own ephemeral mockito server via
/// `tests_utils::with_test_server_*`. No shared mutex, no poison cascade,
/// safe to run in parallel.
#[macro_export]
macro_rules! implement_tests {
    ($endpoint:expr, $headers:expr, $req:ident, $payload:ty) => {
        // Generated tests use struct-update syntax (`..default_test_extras()`)
        // unconditionally; many Request structs don't have any fields beyond
        // those already supplied, which trips `clippy::needless_update`.
        #[allow(clippy::needless_update)]
        #[tokio::test]
        pub async fn test_async() -> Result<(), Box<dyn std::error::Error>> {
            let (body, response) = get_endpoint_test_body_response($endpoint);

            $crate::tests_utils::with_test_server_async(|mut server| async move {
                let url = get_endpoint_url($endpoint).2.expect("test url");
                let scheme_end = url.find("://").expect("scheme") + 3;
                let postfix_idx = url[scheme_end..]
                    .find('/')
                    .map(|i| scheme_end + i)
                    .expect("path");
                let path = &url[postfix_idx..];

                let mut mock = server.mock("POST", path).with_status(200);

                let headers: Vec<Headers> = $headers;

                let is_content_endpoint = headers
                    .iter()
                    .any(|h| matches!(h, Headers::ContentTypeAppOctetStream));

                for h in &headers {
                    mock = mock.with_header(h.get_str().0, h.get_str().1);
                }
                let is_download_endpoint_req = headers
                    .iter()
                    .any(|h| matches!(h, Headers::DropboxApiResult));
                if !is_content_endpoint && !is_download_endpoint_req {
                    if let Some(body) = &body {
                        mock = mock.match_body(mockito::Matcher::JsonString(body.to_string()));
                    }
                }

                if let Some(response) = &response {
                    if is_download_endpoint_req {
                        let compact = response.replace('\n', "");
                        mock = mock.with_header("Dropbox-API-Result", &compact);
                    } else {
                        mock = mock.with_body(response);
                    }
                }
                let mock = mock.create_async().await;

                let payload: Option<$payload>;
                if let Some(body) = body {
                    payload = Some(serde_json::from_str(&body).expect("failed to deserialize"));
                } else {
                    payload = None;
                }

                let request = $req {
                    access_token: &TEST_AUTH_TOKEN,
                    payload,
                    ..$req::default_test_extras()
                };

                let f = request.call();
                let _ = f.await?;

                mock.assert();
                Ok::<(), Box<dyn std::error::Error>>(())
            })
            .await
        }

        #[allow(clippy::needless_update)]
        #[test]
        pub fn test_sync_pass() -> Result<(), Box<dyn std::error::Error>> {
            let (body, response) = get_endpoint_test_body_response($endpoint);

            $crate::tests_utils::with_test_server_sync(|mut server| {
                let url = get_endpoint_url($endpoint).1.expect("test url");
                let scheme_end = url.find("://").expect("scheme") + 3;
                let postfix_idx = url[scheme_end..]
                    .find('/')
                    .map(|i| scheme_end + i)
                    .expect("path");
                let path = &url[postfix_idx..];

                let mut mock = server.mock("POST", path).with_status(200);

                let headers: Vec<Headers> = $headers;

                let is_content_endpoint = headers
                    .iter()
                    .any(|h| matches!(h, Headers::ContentTypeAppOctetStream));

                for h in &headers {
                    mock = mock.with_header(h.get_str().0, h.get_str().1);
                }
                let is_download_endpoint_req = headers
                    .iter()
                    .any(|h| matches!(h, Headers::DropboxApiResult));
                if !is_content_endpoint && !is_download_endpoint_req {
                    if let Some(body) = &body {
                        mock = mock.match_body(mockito::Matcher::JsonString(body.to_string()));
                    }
                }
                if let Some(response) = &response {
                    if is_download_endpoint_req {
                        let compact = response.replace('\n', "");
                        mock = mock.with_header("Dropbox-API-Result", &compact);
                    } else {
                        mock = mock.with_body(response);
                    }
                }
                let mock = mock.create();

                let payload: Option<$payload>;
                if let Some(body) = body {
                    payload = Some(serde_json::from_str(&body).expect("failed to deserialise"));
                } else {
                    payload = None;
                }

                let request = $req {
                    access_token: &TEST_AUTH_TOKEN,
                    payload,
                    ..$req::default_test_extras()
                };

                let _ = request.call_sync()?;
                mock.assert();
                Ok::<(), Box<dyn std::error::Error>>(())
            })
        }
    };
}