google-maps-places 0.1.1

Simple crate to get Google Maps Place results
Documentation
#[cfg(test)]
use mockito;

use crate::error::GoogleMapPlaceError;
use crate::response::Response;

pub struct Places {
    pub api_key: String,
}

impl Places {
    pub fn get_map_place(&self, id: &str) -> Result<Response, GoogleMapPlaceError> {
        if id.is_empty() {
            return Err(GoogleMapPlaceError::BadRequest(
                "Place id is required".to_string(),
            ));
        }

        #[cfg(not(test))]
        let base_url = "https://maps.googleapis.com".to_string();

        #[cfg(test)]
        let base_url = mockito::server_url();

        let url = format!(
            "{}/maps/api/place/details/json?place_id={}&key={}",
            base_url, id, self.api_key
        );

        let res = match ureq::get(&url)
            .call() {
                Ok(r) => r,
                Err(e) => {
                    return Err(GoogleMapPlaceError::Unknown(e.to_string()));
                },
            };

        let body = match res.into_json::<Response>() {
            Ok(r) => r,
            Err(e) => {
                return Err(GoogleMapPlaceError::Unknown(e.to_string()));
            },
        };

        Ok(body)
    }
}

#[cfg(test)]
mod tests {
    use std::{fs::File, io::Read};

    use super::*;
    use mockito::{mock, Matcher, Mock};
    const API_KEY: &str = "google-maps-secret-key";

    fn setup_mock(place_id: &str) -> Mock {
        let mut file = File::open(format!("./test/{}.json", place_id)).unwrap();
        let mut data = String::new();
        file.read_to_string(&mut data).unwrap();

        mock("GET", "/maps/api/place/details/json")
            .match_query(Matcher::AllOf(vec![
                Matcher::UrlEncoded("place_id".into(), place_id.into()),
                Matcher::UrlEncoded("key".into(), API_KEY.into()),
            ]))
            .with_status(200)
            .with_body(data)
            .create()
    }

    #[test]
    fn test_valid_map_place() {
        let _m = setup_mock("place-001");
        let place = Places { api_key: API_KEY.into() };
        let res = match place.get_map_place("place-001") {
            Ok(b) => b,
            Err(_e) => {
                assert!(false);
                return;
            }
        };

        if let Response::OK { result } = res {
            assert_eq!(result.address_components.len(), 7);
        } else {
            assert!(false);
        }
    }

    #[test]
    fn test_invalid_map_place() {
        let _m = setup_mock("place-invalid");

        let place = Places { api_key: API_KEY.into() };
        let res = match place.get_map_place("place-invalid") {
            Ok(b) => b,
            Err(_e) => {
                assert!(false);
                return;
            }
        };

        if let Response::InvalidRequest = res {
            assert!(true);
        } else {
            assert!(false);
        }
    }

    #[test]
    fn test_denied_map_place() {
        let _m = setup_mock("place-denied");

        let place = Places { api_key: API_KEY.into() };
        let res = match place.get_map_place("place-denied") {
            Ok(b) => b,
            Err(_e) => {
                assert!(false);
                return;
            }
        };

        if let Response::RequestDenied { error_message } = res {
            assert!(true);
            assert_eq!(error_message, "The provided API key is invalid.");
        } else {
            assert!(false);
        }
    }
}