use crate::error::Error;
#[derive(Debug, Clone, PartialEq, Eq)]
pub(crate) struct Refusal {
pub node: Option<String>,
pub field: Option<String>,
pub message: String,
}
impl Refusal {
pub(crate) fn plain(message: impl Into<String>) -> Self {
Self {
node: None,
field: None,
message: message.into(),
}
}
pub(crate) fn about(node: &str, message: impl Into<String>) -> Self {
Self {
node: Some(node.to_owned()),
field: None,
message: message.into(),
}
}
pub(crate) fn node(id: &str, what: impl AsRef<str>) -> Self {
Self::about(id, format!("node '{id}': {}", what.as_ref()))
}
#[must_use]
pub(crate) fn field(mut self, field: &str) -> Self {
self.field = Some(field.to_owned());
self
}
}
impl From<Refusal> for Error {
fn from(refusal: Refusal) -> Self {
Self::Invalid(refusal.message)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn a_node_refusal_prints_the_sentence_the_engine_has_always_printed() {
let refusal =
Refusal::node("build", "a direct agent node needs a persona").field("persona");
assert_eq!(
refusal.message,
"node 'build': a direct agent node needs a persona"
);
assert_eq!(refusal.node.as_deref(), Some("build"));
assert_eq!(refusal.field.as_deref(), Some("persona"));
assert_eq!(
Error::from(refusal).to_string(),
"invalid: node 'build': a direct agent node needs a persona"
);
}
#[test]
fn a_plan_refusal_is_about_no_node_and_no_field() {
let refusal = Refusal::plain("concurrency must be at least 1");
assert_eq!(refusal.node, None);
assert_eq!(refusal.field, None);
assert_eq!(refusal.message, "concurrency must be at least 1");
}
}