1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
use crate::{Loader, LoaderError, LoaderTrait};
use json;

impl From<json::Error> for LoaderError<json::Error> {
    fn from(value: json::Error) -> Self {
        Self::FormatError(value)
    }
}

impl LoaderTrait<json::JsonValue, json::Error> for Loader<json::JsonValue, json::Error> {
    fn load_from_string(content: &str) -> Result<json::JsonValue, LoaderError<json::Error>>
    where
        Self: Sized,
    {
        json::parse(content).or_else(|json_error| Err(json_error.into()))
    }

    fn load_from_bytes(content: &[u8]) -> Result<json::JsonValue, LoaderError<json::Error>>
    where
        Self: Sized,
    {
        match std::str::from_utf8(content) {
            Ok(string_value) => Self::load_from_string(string_value),
            Err(_) => Err(json::Error::FailedUtf8Parsing.into()),
        }
    }
}

#[cfg(test)]
mod tests {
    use crate::{
        traits::loaders::JsonLoader,
        url_helpers::{test_data_file_url, UrlError},
        LoaderError, LoaderTrait,
    };
    use json;
    use std::{io, sync::Arc};
    use test_case::test_case;

    #[test]
    fn test_load_wrong_url_parse_error() {
        let expression_result = JsonLoader::default().load("this-is-a-wrong-url");
        if let Err(LoaderError::InvalidURL(UrlError::ParseError(url::ParseError::RelativeUrlWithoutBase))) = expression_result {
        } else {
            panic!(
                "Expected LoaderError::InvalidURL(UrlError::ParseError(url::ParseError::RelativeUrlWithoutBase)), received {:?}",
                expression_result
            );
        }
    }

    #[test]
    fn test_load_wrong_url_syntax_error() {
        let load_result = JsonLoader::default().load("http:/this-is-syntactically-invalid-url");
        if let Err(LoaderError::InvalidURL(UrlError::SyntaxViolation(url::SyntaxViolation::ExpectedDoubleSlash))) = load_result {
        } else {
            panic!(
                "Expected LoaderError::InvalidURL(UrlError::ParseError(url::ParseError::RelativeUrlWithoutBase)), received {:?}",
                load_result
            );
        }
    }

    #[test]
    fn test_load_from_not_existing_file() {
        let loader = JsonLoader::default();
        let mut non_exiting_file_url = test_data_file_url("json/Null.json");
        non_exiting_file_url.push_str("_not_existing");
        let load_result = loader.load(non_exiting_file_url);
        if let Err(LoaderError::IOError(value)) = load_result {
            assert_eq!(value.kind(), io::ErrorKind::NotFound);
        } else {
            panic!("Expected LoaderError::IOError(...), received {:?}", load_result);
        }
    }

    #[test_case("json/Boolean.json", rust_json![false])]
    #[test_case("json/Integer.json", rust_json![1])]
    #[test_case("json/Null.json", rust_json![null])]
    #[test_case("json/String.json", rust_json!["Some Text"])]
    fn test_load_from_file_valid_content(file_path: &str, expected_loaded_object: json::JsonValue) {
        let loader = JsonLoader::default();
        assert_eq!(loader.load(test_data_file_url(file_path)).ok().unwrap(), Arc::new(expected_loaded_object));
    }

    #[test]
    fn test_load_from_file_invalid_content() {
        let loader = JsonLoader::default();
        let load_result = loader.load(test_data_file_url("json/Invalid.json"));
        if let Err(LoaderError::FormatError(json::Error::UnexpectedEndOfJson)) = load_result {
        } else {
            panic!("Expected LoaderError::FormatError(json::Error::UnexpectedEndOfJson), received {:?}", load_result);
        }
    }

    #[test_case("json/Boolean.json", rust_json![false])]
    #[test_case("json/Integer.json", rust_json![1])]
    #[test_case("json/Null.json", rust_json![null])]
    #[test_case("json/String.json", rust_json!["Some Text"])]
    fn test_load_from_url_valid_content(file_path: &str, expected_loaded_object: json::JsonValue) {
        let loader = JsonLoader::default();
        assert_eq!(mock_loader_request!(loader, file_path).unwrap(), Arc::new(expected_loaded_object));
    }

    #[test]
    fn test_load_from_url_invalid_content() {
        let loader = JsonLoader::default();
        let load_result = mock_loader_request!(loader, "json/Invalid.json");
        if let Err(LoaderError::FormatError(json::Error::UnexpectedEndOfJson)) = load_result {
        } else {
            panic!("Expected LoaderError::FormatError(json::Error::UnexpectedEndOfJson), received {:?}", load_result);
        }
    }

    #[test]
    fn test_load_from_url_http_error() {
        let loader = JsonLoader::default();
        let load_result = mock_loader_request!(loader, 404, "json/Null.json");
        if let Err(LoaderError::FetchURLFailed(value)) = load_result {
            assert_eq!(value.status().and_then(|value| Some(value.as_u16())), Some(404))
        } else {
            panic!("Expected LoaderError::FetchURLFailed(...), received {:?}", load_result);
        }
    }
}