use std::io::Read;
use super::TemplateResourceError;
pub trait ITemplateResource: Send + Sync {
fn get_description(&self) -> String;
fn get_base_name(&self) -> Option<String>;
fn exists(&self) -> bool;
fn reader(&self) -> std::io::Result<Box<dyn Read>>;
fn relative(
&self,
relative_location: Option<&str>,
) -> Result<Box<dyn ITemplateResource>, TemplateResourceError>;
}
#[cfg(test)]
mod tests {
use std::error::Error;
use std::io::{self, Cursor};
use super::ITemplateResource;
use crate::TemplateInputException;
use crate::templateresource::TemplateResourceError;
struct CustomResource;
impl ITemplateResource for CustomResource {
fn get_description(&self) -> String {
"custom".to_owned()
}
fn get_base_name(&self) -> Option<String> {
Some("base".to_owned())
}
fn exists(&self) -> bool {
false
}
fn reader(&self) -> io::Result<Box<dyn io::Read>> {
Ok(Box::new(Cursor::new(b"custom".to_vec())))
}
fn relative(
&self,
relative_location: Option<&str>,
) -> Result<Box<dyn ITemplateResource>, TemplateResourceError> {
match relative_location {
Some("child") => Ok(Box::new(Self)),
Some(_) | None => Err(TemplateResourceError::InvalidArgument(
"invalid relative location".to_owned(),
)),
}
}
}
#[test]
fn supports_dynamic_resources_without_forcing_thread_safety() {
let resource: &dyn ITemplateResource = &CustomResource;
assert_eq!(resource.get_description(), "custom");
assert_eq!(resource.get_base_name(), Some("base".to_owned()));
assert!(!resource.exists());
assert!(resource.reader().is_ok());
assert_eq!(
resource
.relative(Some("child"))
.expect("relative resource")
.get_description(),
"custom"
);
}
#[test]
fn preserves_resource_error_categories_messages_and_sources() {
let invalid = CustomResource
.relative(None)
.err()
.expect("null location is invalid");
assert_eq!(invalid.to_string(), "invalid relative location");
assert!(invalid.source().is_none());
let input = TemplateResourceError::Input(TemplateInputException::new(Some(
"input failure".to_owned(),
)));
assert_eq!(input.to_string(), "input failure");
assert!(input.source().is_none());
let malformed_source =
url::Url::parse("relative").expect_err("relative URL without a base must fail");
let malformed = TemplateResourceError::MalformedUrl {
location: "relative".to_owned(),
source: malformed_source,
};
assert!(malformed.to_string().contains("relative"));
assert!(malformed.source().is_some());
}
}