use std::sync::Arc;
use crate::cache::ICacheEntryValidity;
use crate::{ITemplateResource, TemplateMode};
use super::TemplateResolutionError;
pub struct TemplateResolution {
template_resource: Arc<dyn ITemplateResource>,
template_resource_existence_verified: bool,
template_mode: TemplateMode,
use_decoupled_logic: bool,
validity: Arc<dyn ICacheEntryValidity>,
}
impl TemplateResolution {
pub fn new(
template_resource: Option<Arc<dyn ITemplateResource>>,
template_mode: Option<TemplateMode>,
validity: Option<Arc<dyn ICacheEntryValidity>>,
) -> Result<Self, TemplateResolutionError> {
Self::with_options(template_resource, false, template_mode, false, validity)
}
pub fn with_options(
template_resource: Option<Arc<dyn ITemplateResource>>,
template_resource_existence_verified: bool,
template_mode: Option<TemplateMode>,
use_decoupled_logic: bool,
validity: Option<Arc<dyn ICacheEntryValidity>>,
) -> Result<Self, TemplateResolutionError> {
let template_resource = template_resource.ok_or(
TemplateResolutionError::InvalidArgument("Template Resource cannot be null"),
)?;
let template_mode = template_mode.ok_or(TemplateResolutionError::InvalidArgument(
"Template mode cannot be null",
))?;
let validity = validity.ok_or(TemplateResolutionError::InvalidArgument(
"Validity cannot be null",
))?;
Ok(Self {
template_resource,
template_resource_existence_verified,
template_mode,
use_decoupled_logic,
validity,
})
}
#[must_use]
pub fn get_template_resource(&self) -> &dyn ITemplateResource {
self.template_resource.as_ref()
}
#[must_use]
pub(crate) fn get_template_resource_arc(&self) -> Arc<dyn ITemplateResource> {
Arc::clone(&self.template_resource)
}
#[must_use]
pub const fn get_template_mode(&self) -> TemplateMode {
self.template_mode
}
#[must_use]
pub const fn is_template_resource_existence_verified(&self) -> bool {
self.template_resource_existence_verified
}
#[must_use]
pub const fn get_use_decoupled_logic(&self) -> bool {
self.use_decoupled_logic
}
#[must_use]
pub fn get_validity(&self) -> &dyn ICacheEntryValidity {
self.validity.as_ref()
}
#[must_use]
pub(crate) fn get_validity_arc(&self) -> Arc<dyn ICacheEntryValidity> {
Arc::clone(&self.validity)
}
}
#[cfg(test)]
mod tests {
use std::sync::Arc;
use super::{TemplateResolution, TemplateResolutionError};
use crate::cache::{
AlwaysValidCacheEntryValidity, ICacheEntryValidity, NonCacheableCacheEntryValidity,
};
use crate::{ITemplateResource, StringTemplateResource, TemplateMode};
#[test]
fn validates_required_objects_in_java_order_with_exact_messages() {
assert_eq!(
TemplateResolution::with_options(None, true, None, true, None)
.err()
.expect("null resource"),
TemplateResolutionError::InvalidArgument("Template Resource cannot be null")
);
let resource: Arc<dyn ITemplateResource> =
Arc::new(StringTemplateResource::new(Some("template")).expect("string resource"));
assert_eq!(
TemplateResolution::new(Some(Arc::clone(&resource)), None, None)
.err()
.expect("null mode"),
TemplateResolutionError::InvalidArgument("Template mode cannot be null")
);
assert_eq!(
TemplateResolution::new(Some(resource), Some(TemplateMode::HTML), None)
.err()
.expect("null validity"),
TemplateResolutionError::InvalidArgument("Validity cannot be null")
);
}
#[test]
fn three_argument_constructor_preserves_identity_and_default_flags() {
let resource: Arc<dyn ITemplateResource> =
Arc::new(StringTemplateResource::new(Some("body")).expect("string resource"));
let validity: Arc<dyn ICacheEntryValidity> = Arc::new(AlwaysValidCacheEntryValidity::new());
let resolution = TemplateResolution::new(
Some(Arc::clone(&resource)),
Some(TemplateMode::HTML),
Some(Arc::clone(&validity)),
)
.expect("template resolution");
assert!(std::ptr::eq(
resolution.get_template_resource(),
resource.as_ref()
));
assert!(std::ptr::eq(resolution.get_validity(), validity.as_ref()));
assert_eq!(resolution.get_template_mode(), TemplateMode::HTML);
assert!(!resolution.is_template_resource_existence_verified());
assert!(!resolution.get_use_decoupled_logic());
assert!(resolution.get_template_resource().exists());
assert!(resolution.get_validity().is_cacheable());
}
#[test]
fn full_constructor_preserves_independent_flags_and_dynamic_contracts() {
let resource: Arc<dyn ITemplateResource> =
Arc::new(StringTemplateResource::new(Some("")).expect("empty resource"));
let validity: Arc<dyn ICacheEntryValidity> =
Arc::new(NonCacheableCacheEntryValidity::new());
let resolution = TemplateResolution::with_options(
Some(resource),
true,
Some(TemplateMode::RAW),
true,
Some(validity),
)
.expect("full template resolution");
assert!(resolution.is_template_resource_existence_verified());
assert!(resolution.get_use_decoupled_logic());
assert_eq!(resolution.get_template_mode(), TemplateMode::RAW);
assert!(!resolution.get_validity().is_cacheable());
assert!(!resolution.get_validity().is_cache_still_valid());
}
}