#![allow(missing_docs)]
use std::collections::HashMap;
use std::path::Path;
use liquid_json::LiquidJsonValue;
use wick_packet::{InherentData, RuntimeConfig};
use super::template_config::Renderable;
use crate::config::{LiquidJsonConfig, TemplateConfig};
use crate::error::ManifestError;
#[derive(Debug, Clone, PartialEq, property::Property, serde::Serialize, derive_builder::Builder)]
#[property(get(public), set(private), mut(disable))]
pub struct TestCase {
#[builder(default)]
#[serde(skip_serializing_if = "Option::is_none")]
pub(crate) name: Option<String>,
#[builder(default, setter(into))]
pub(crate) operation: String,
#[builder(default)]
#[serde(skip_serializing_if = "Option::is_none")]
pub(crate) config: Option<LiquidJsonConfig>,
#[builder(default)]
#[serde(skip_serializing_if = "Option::is_none")]
pub(crate) inherent: Option<InherentConfig>,
#[builder(default)]
#[serde(skip_serializing_if = "Vec::is_empty")]
pub(crate) inputs: Vec<PacketData>,
#[builder(default)]
#[serde(skip_serializing_if = "Vec::is_empty")]
pub(crate) outputs: Vec<TestPacketData>,
}
impl Renderable for TestCase {
fn render_config(
&mut self,
source: Option<&Path>,
root_config: Option<&RuntimeConfig>,
env: Option<&HashMap<String, String>>,
) -> Result<(), ManifestError> {
if let Some(config) = self.config.as_mut() {
config.set_value(Some(config.render(
source,
root_config,
None,
env,
Some(&InherentData::unsafe_default()),
)?));
}
Ok(())
}
}
#[derive(Debug, Default, Clone, PartialEq, Copy, property::Property, serde::Serialize, derive_builder::Builder)]
#[property(get(public), set(private), mut(disable))]
pub struct InherentConfig {
#[builder(default)]
#[serde(skip_serializing_if = "Option::is_none")]
pub(crate) seed: Option<u64>,
#[builder(default)]
#[serde(skip_serializing_if = "Option::is_none")]
pub(crate) timestamp: Option<u64>,
}
#[derive(Debug, Clone, PartialEq, serde::Serialize)]
#[serde(rename_all = "kebab-case")]
pub enum PacketData {
#[serde(rename = "success")]
SuccessPacket(SuccessPayload),
#[serde(rename = "error")]
ErrorPacket(ErrorPayload),
}
#[derive(Debug, Clone, PartialEq, serde::Serialize)]
#[serde(rename_all = "kebab-case")]
pub enum TestPacketData {
#[serde(rename = "success")]
SuccessPacket(SuccessPayload),
#[serde(rename = "contains")]
PacketAssertion(PacketAssertionDef),
#[serde(rename = "error")]
ErrorPacket(ErrorPayload),
}
impl PacketData {
#[must_use]
pub fn success(port: impl Into<String>, data: Option<LiquidJsonValue>) -> Self {
Self::SuccessPacket(SuccessPayload {
port: port.into(),
flag: None,
data,
})
}
#[must_use]
pub fn error(port: impl Into<String>, error: impl Into<String>) -> Self {
Self::ErrorPacket(ErrorPayload {
port: port.into(),
flag: None,
error: TemplateConfig::new_template(error.into()),
})
}
#[must_use]
pub fn done(port: impl Into<String>) -> Self {
Self::SuccessPacket(SuccessPayload {
port: port.into(),
flag: Some(PacketFlag::Done),
data: None,
})
}
#[must_use]
pub fn open(port: impl Into<String>) -> Self {
Self::SuccessPacket(SuccessPayload {
port: port.into(),
flag: Some(PacketFlag::Open),
data: None,
})
}
#[must_use]
pub fn close(port: impl Into<String>) -> Self {
Self::SuccessPacket(SuccessPayload {
port: port.into(),
flag: Some(PacketFlag::Close),
data: None,
})
}
#[must_use]
pub fn port(&self) -> &str {
match self {
PacketData::SuccessPacket(data) => &data.port,
PacketData::ErrorPacket(data) => &data.port,
}
}
#[must_use]
pub const fn flag(&self) -> MaybePacketFlag {
MaybePacketFlag(match self {
PacketData::SuccessPacket(data) => data.flag,
PacketData::ErrorPacket(data) => data.flag,
})
}
#[must_use]
pub const fn data(&self) -> Option<&LiquidJsonValue> {
match self {
PacketData::SuccessPacket(data) => data.data.as_ref(),
PacketData::ErrorPacket(_) => None,
}
}
}
impl TestPacketData {
#[must_use]
pub fn success(port: impl Into<String>, data: Option<LiquidJsonValue>) -> Self {
Self::SuccessPacket(SuccessPayload {
port: port.into(),
flag: None,
data,
})
}
#[must_use]
pub fn error(port: impl Into<String>, error: impl Into<String>) -> Self {
Self::ErrorPacket(ErrorPayload {
port: port.into(),
flag: None,
error: TemplateConfig::new_template(error.into()),
})
}
#[must_use]
pub fn done(port: impl Into<String>) -> Self {
Self::SuccessPacket(SuccessPayload {
port: port.into(),
flag: Some(PacketFlag::Done),
data: None,
})
}
#[must_use]
pub fn open(port: impl Into<String>) -> Self {
Self::SuccessPacket(SuccessPayload {
port: port.into(),
flag: Some(PacketFlag::Open),
data: None,
})
}
#[must_use]
pub fn close(port: impl Into<String>) -> Self {
Self::SuccessPacket(SuccessPayload {
port: port.into(),
flag: Some(PacketFlag::Close),
data: None,
})
}
#[must_use]
pub fn port(&self) -> &str {
match self {
Self::SuccessPacket(data) => &data.port,
Self::ErrorPacket(data) => &data.port,
Self::PacketAssertion(data) => &data.port,
}
}
#[must_use]
pub const fn data(&self) -> Option<&LiquidJsonValue> {
match self {
Self::SuccessPacket(data) => data.data.as_ref(),
Self::ErrorPacket(_) => None,
Self::PacketAssertion(_) => None,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct MaybePacketFlag(Option<PacketFlag>);
impl std::ops::Deref for MaybePacketFlag {
type Target = Option<PacketFlag>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl MaybePacketFlag {
#[must_use]
pub const fn is_done(&self) -> bool {
matches!(self.0, Some(PacketFlag::Done))
}
#[must_use]
pub const fn is_open(&self) -> bool {
matches!(self.0, Some(PacketFlag::Open))
}
#[must_use]
pub const fn is_close(&self) -> bool {
matches!(self.0, Some(PacketFlag::Close))
}
}
#[derive(Debug, Clone, PartialEq, property::Property, serde::Serialize)]
#[property(get(public), set(private), mut(disable))]
pub struct SuccessPayload {
pub(crate) port: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub(crate) flag: Option<PacketFlag>,
#[serde(skip_serializing_if = "Option::is_none")]
pub(crate) data: Option<LiquidJsonValue>,
}
#[derive(Debug, Clone, serde::Serialize, PartialEq, property::Property)]
#[property(get(public), set(private), mut(disable))]
pub struct PacketAssertionDef {
pub(crate) port: String,
#[serde(skip_serializing_if = "Vec::is_empty")]
pub(crate) assertions: Vec<PacketAssertion>,
}
#[derive(Debug, Clone, serde::Serialize, PartialEq, property::Property)]
#[property(get(public), set(private), mut(disable))]
pub struct PacketAssertion {
#[serde(skip_serializing_if = "Option::is_none")]
pub(crate) path: Option<String>,
pub(crate) operator: AssertionOperator,
pub(crate) value: LiquidJsonValue,
}
#[derive(Debug, Clone, Copy, serde::Serialize, PartialEq)]
pub enum AssertionOperator {
Equals = 0,
LessThan = 1,
GreaterThan = 2,
Regex = 3,
Contains = 4,
}
#[derive(Debug, Clone, PartialEq, property::Property, serde::Serialize)]
#[property(get(public), set(private), mut(disable))]
pub struct ErrorPayload {
pub(crate) port: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub(crate) flag: Option<PacketFlag>,
pub(crate) error: TemplateConfig<String>,
}
#[derive(Debug, Clone, Copy, PartialEq, serde::Serialize)]
#[serde(rename_all = "kebab-case")]
pub enum PacketFlag {
Done = 0,
Open = 1,
Close = 2,
}