stateset_core/errors/
product.rs1use uuid::Uuid;
4
5#[derive(Debug, thiserror::Error)]
16#[non_exhaustive]
17pub enum ProductError {
18 #[error("product not found: {0}")]
20 NotFound(Uuid),
21
22 #[error("product variant not found: {0}")]
24 VariantNotFound(Uuid),
25
26 #[error("duplicate product slug: {0}")]
28 DuplicateSlug(String),
29
30 #[error("product is not purchasable")]
32 NotPurchasable,
33
34 #[error(transparent)]
36 Other(Box<dyn std::error::Error + Send + Sync>),
37}
38
39impl ProductError {
40 #[inline]
42 #[track_caller]
43 #[must_use]
44 pub const fn not_found(id: Uuid) -> Self {
45 Self::NotFound(id)
46 }
47
48 #[inline]
50 #[track_caller]
51 #[must_use]
52 pub const fn variant_not_found(id: Uuid) -> Self {
53 Self::VariantNotFound(id)
54 }
55
56 #[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}