diff --git a/src/collection/models.rs b/src/collection/models.rs index 3a3698ea..88e4d4b0 100644 --- a/src/collection/models.rs +++ b/src/collection/models.rs @@ -50,6 +50,24 @@ pub struct Profile { pub data: IndexMap, } +impl Profile { + /// Get a presentable name for this profile + pub fn name(&self) -> &str { + self.name.as_deref().unwrap_or(&self.id) + } +} + +#[cfg(test)] +impl crate::test_util::Factory for Profile { + fn factory(_: ()) -> Self { + Self { + id: "profile1".into(), + name: None, + data: IndexMap::new(), + } + } +} + #[derive( Clone, Debug, @@ -65,6 +83,20 @@ pub struct Profile { )] pub struct ProfileId(String); +#[cfg(test)] +impl From<&str> for ProfileId { + fn from(value: &str) -> Self { + value.to_owned().into() + } +} + +#[cfg(test)] +impl crate::test_util::Factory for ProfileId { + fn factory(_: ()) -> Self { + uuid::Uuid::new_v4().to_string().into() + } +} + /// A gathering of like-minded recipes and/or folders #[derive(Clone, Debug, Serialize, Deserialize)] #[cfg_attr(test, derive(PartialEq))] @@ -82,6 +114,47 @@ pub struct Folder { pub children: IndexMap, } +impl Folder { + /// Get a presentable name for this folder + pub fn name(&self) -> &str { + self.name.as_deref().unwrap_or(&self.id) + } +} + +#[cfg(test)] +impl crate::test_util::Factory for Folder { + fn factory(_: ()) -> Self { + Self { + id: "folder1".into(), + name: None, + children: IndexMap::new(), + } + } +} + +impl Recipe { + /// Get a presentable name for this recipe + pub fn name(&self) -> &str { + self.name.as_deref().unwrap_or(&self.id) + } +} + +#[cfg(test)] +impl crate::test_util::Factory for Recipe { + fn factory(_: ()) -> Self { + Self { + id: "recipe1".into(), + name: None, + method: Method::Get, + url: "http://localhost/url".into(), + body: None, + authentication: None, + query: IndexMap::new(), + headers: IndexMap::new(), + } + } +} + /// A definition of how to make a request. This is *not* called `Request` in /// order to distinguish it from a single instance of an HTTP request. And it's /// not called `RequestTemplate` because the word "template" has a specific @@ -121,6 +194,20 @@ pub struct Recipe { )] pub struct RecipeId(String); +#[cfg(test)] +impl From<&str> for RecipeId { + fn from(value: &str) -> Self { + value.to_owned().into() + } +} + +#[cfg(test)] +impl crate::test_util::Factory for RecipeId { + fn factory(_: ()) -> Self { + uuid::Uuid::new_v4().to_string().into() + } +} + /// HTTP method. This is duplicated from reqwest's Method so we can enforce /// the method is valid during deserialization. This is also generally more /// ergonomic at the cost of some flexibility. @@ -152,6 +239,31 @@ pub enum Method { Trace, } +/// For serialization +impl From for String { + fn from(method: Method) -> Self { + method.to_string() + } +} + +#[cfg(test)] +impl crate::test_util::Factory for Chain { + fn factory(_: ()) -> Self { + Self { + id: "chain1".into(), + source: ChainSource::Request { + recipe: "recipe1".into(), + trigger: Default::default(), + section: Default::default(), + }, + sensitive: false, + selector: None, + content_type: None, + trim: ChainOutputTrim::default(), + } + } +} + /// Shortcut for defining authentication method. If this is defined in addition /// to the `Authorization` header, that header will end up being included in the /// request twice. @@ -261,6 +373,18 @@ pub enum ChainSource { }, } +/// Test-only helpers +#[cfg(test)] +impl ChainSource { + /// Build a new [Self::Command] variant from [command, ...args] + pub fn command(cmd: [&str; N]) -> ChainSource { + ChainSource::Command { + command: cmd.into_iter().map(Template::from).collect(), + stdin: None, + } + } +} + /// The component of the response to use as the chain source #[derive(Clone, Debug, Default, Serialize, Deserialize)] #[cfg_attr(test, derive(PartialEq))] @@ -341,79 +465,6 @@ impl crate::test_util::Factory for Collection { } } -#[cfg(test)] -impl crate::test_util::Factory for ProfileId { - fn factory(_: ()) -> Self { - uuid::Uuid::new_v4().to_string().into() - } -} - -#[cfg(test)] -impl crate::test_util::Factory for RecipeId { - fn factory(_: ()) -> Self { - uuid::Uuid::new_v4().to_string().into() - } -} - -impl Profile { - /// Get a presentable name for this profile - pub fn name(&self) -> &str { - self.name.as_deref().unwrap_or(&self.id) - } -} - -#[cfg(test)] -impl crate::test_util::Factory for Profile { - fn factory(_: ()) -> Self { - Self { - id: "profile1".into(), - name: None, - data: IndexMap::new(), - } - } -} - -impl Folder { - /// Get a presentable name for this folder - pub fn name(&self) -> &str { - self.name.as_deref().unwrap_or(&self.id) - } -} - -#[cfg(test)] -impl crate::test_util::Factory for Folder { - fn factory(_: ()) -> Self { - Self { - id: "folder1".into(), - name: None, - children: IndexMap::new(), - } - } -} - -impl Recipe { - /// Get a presentable name for this recipe - pub fn name(&self) -> &str { - self.name.as_deref().unwrap_or(&self.id) - } -} - -#[cfg(test)] -impl crate::test_util::Factory for Recipe { - fn factory(_: ()) -> Self { - Self { - id: "recipe1".into(), - name: None, - method: Method::Get, - url: "http://localhost/url".into(), - body: None, - authentication: None, - query: IndexMap::new(), - headers: IndexMap::new(), - } - } -} - /// For deserialization impl TryFrom for Method { type Error = anyhow::Error; @@ -428,40 +479,3 @@ impl TryFrom for Method { }) } } - -/// For serialization -impl From for String { - fn from(method: Method) -> Self { - method.to_string() - } -} - -#[cfg(test)] -impl crate::test_util::Factory for Chain { - fn factory(_: ()) -> Self { - Self { - id: "chain1".into(), - source: ChainSource::Request { - recipe: "recipe1".into(), - trigger: Default::default(), - section: Default::default(), - }, - sensitive: false, - selector: None, - content_type: None, - trim: ChainOutputTrim::default(), - } - } -} - -/// Test-only helpers -#[cfg(test)] -impl ChainSource { - /// Build a new [Self::Command] variant from [command, ...args] - pub fn command(cmd: [&str; N]) -> ChainSource { - ChainSource::Command { - command: cmd.into_iter().map(Template::from).collect(), - stdin: None, - } - } -} diff --git a/src/collection/recipe_tree.rs b/src/collection/recipe_tree.rs index fd59cb04..a4354c54 100644 --- a/src/collection/recipe_tree.rs +++ b/src/collection/recipe_tree.rs @@ -181,6 +181,24 @@ impl<'de> Deserialize<'de> for RecipeTree { } } +#[cfg(test)] +impl From> for RecipeTree { + fn from(value: IndexMap) -> Self { + value + .into_iter() + .map(|(id, recipe)| (id, RecipeNode::Recipe(recipe))) + .collect::>() + .into() + } +} + +#[cfg(test)] +impl From> for RecipeTree { + fn from(tree: IndexMap) -> Self { + Self::new(tree).expect("Duplicate recipe ID") + } +} + impl RecipeNode { /// Get the ID of the inner folder or recipe pub fn id(&self) -> &RecipeId { diff --git a/src/test_util.rs b/src/test_util.rs index a7528897..e8f241cf 100644 --- a/src/test_util.rs +++ b/src/test_util.rs @@ -1,7 +1,7 @@ //! General test utilities, that apply to all parts of the program use crate::{ - collection::{HasId, ProfileId, Recipe, RecipeId, RecipeNode, RecipeTree}, + collection::HasId, template::{Prompt, Prompter, Template}, util::ResultExt, }; @@ -91,29 +91,6 @@ impl Prompter for TestPrompter { } } -// Some helpful conversion implementations -impl From<&str> for ProfileId { - fn from(value: &str) -> Self { - value.to_owned().into() - } -} - -impl From> for RecipeTree { - fn from(value: IndexMap) -> Self { - let tree = value - .into_iter() - .map(|(id, recipe)| (id, RecipeNode::Recipe(recipe))) - .collect(); - Self::new(tree).expect("Duplicate recipe ID") - } -} - -impl From<&str> for RecipeId { - fn from(value: &str) -> Self { - value.to_owned().into() - } -} - impl From<&str> for Template { fn from(value: &str) -> Self { value.to_owned().try_into().unwrap()