Skip to main content

stateset_core/errors/
product.rs

1//! Product-domain errors.
2
3use uuid::Uuid;
4
5/// Errors specific to product operations.
6///
7/// # Example
8///
9/// ```rust
10/// use stateset_core::errors::ProductError;
11///
12/// let err = ProductError::not_found(uuid::Uuid::nil());
13/// assert!(err.to_string().contains("not found"));
14/// ```
15#[derive(Debug, thiserror::Error)]
16#[non_exhaustive]
17pub enum ProductError {
18    /// Product with the given ID was not found.
19    #[error("product not found: {0}")]
20    NotFound(Uuid),
21
22    /// Product variant with the given ID was not found.
23    #[error("product variant not found: {0}")]
24    VariantNotFound(Uuid),
25
26    /// Duplicate product slug already exists.
27    #[error("duplicate product slug: {0}")]
28    DuplicateSlug(String),
29
30    /// Product is not available for purchase.
31    #[error("product is not purchasable")]
32    NotPurchasable,
33
34    /// Extensibility.
35    #[error(transparent)]
36    Other(Box<dyn std::error::Error + Send + Sync>),
37}
38
39impl ProductError {
40    /// Convenience constructor for `NotFound`.
41    #[inline]
42    #[track_caller]
43    #[must_use]
44    pub const fn not_found(id: Uuid) -> Self {
45        Self::NotFound(id)
46    }
47
48    /// Convenience constructor for `VariantNotFound`.
49    #[inline]
50    #[track_caller]
51    #[must_use]
52    pub const fn variant_not_found(id: Uuid) -> Self {
53        Self::VariantNotFound(id)
54    }
55
56    /// Convenience constructor for `DuplicateSlug`.
57    #[track_caller]
58    pub fn duplicate_slug(slug: impl Into<String>) -> Self {
59        Self::DuplicateSlug(slug.into())
60    }
61}
62
63#[cfg(test)]
64mod tests {
65    use super::*;
66
67    #[test]
68    fn not_found_display() {
69        let id = Uuid::nil();
70        let err = ProductError::not_found(id);
71        assert!(err.to_string().contains(&id.to_string()));
72    }
73
74    #[test]
75    fn variant_not_found_display() {
76        let err = ProductError::variant_not_found(Uuid::nil());
77        assert!(err.to_string().contains("variant"));
78    }
79
80    #[test]
81    fn duplicate_slug_display() {
82        let err = ProductError::duplicate_slug("cool-widget");
83        assert_eq!(err.to_string(), "duplicate product slug: cool-widget");
84    }
85
86    #[test]
87    fn not_purchasable_display() {
88        let err = ProductError::NotPurchasable;
89        assert_eq!(err.to_string(), "product is not purchasable");
90    }
91
92    #[test]
93    fn converts_to_commerce_error() {
94        use crate::errors::CommerceError;
95
96        let prod_err = ProductError::not_found(Uuid::nil());
97        let commerce_err: CommerceError = prod_err.into();
98        assert!(commerce_err.is_not_found());
99
100        let slug_err = ProductError::duplicate_slug("x");
101        let commerce_err: CommerceError = slug_err.into();
102        assert!(commerce_err.is_conflict());
103    }
104}