1use thiserror::Error;
21
22#[derive(Debug, Error, Clone, PartialEq, Eq)]
28pub enum ConfigError {
29 #[error("API key cannot be empty. Please provide a valid Shopify API key.")]
31 EmptyApiKey,
32
33 #[error("API secret key cannot be empty. Please provide a valid Shopify API secret key.")]
35 EmptyApiSecretKey,
36
37 #[error("Invalid shop domain '{domain}'. Expected format: 'shop-name' or 'shop-name.myshopify.com'.")]
39 InvalidShopDomain {
40 domain: String,
42 },
43
44 #[error("Invalid API version '{version}'. Expected format: 'YYYY-MM' (e.g., '2024-01') or 'unstable'.")]
46 InvalidApiVersion {
47 version: String,
49 },
50
51 #[error("Invalid scopes: {reason}")]
53 InvalidScopes {
54 reason: String,
56 },
57
58 #[error("Missing required field: '{field}'. This field must be set before building the configuration.")]
60 MissingRequiredField {
61 field: &'static str,
63 },
64
65 #[error("Invalid host URL '{url}'. Please provide a valid URL with scheme (e.g., 'https://myapp.example.com').")]
67 InvalidHostUrl {
68 url: String,
70 },
71
72 #[error("API version '{version}' is deprecated. Please upgrade to '{latest}' or a newer supported version.")]
74 DeprecatedApiVersion {
75 version: String,
77 latest: String,
79 },
80}
81
82#[cfg(test)]
83mod tests {
84 use super::*;
85
86 #[test]
87 fn test_empty_api_key_error_message() {
88 let error = ConfigError::EmptyApiKey;
89 let message = error.to_string();
90 assert!(message.contains("API key cannot be empty"));
91 assert!(message.contains("valid Shopify API key"));
92 }
93
94 #[test]
95 fn test_invalid_shop_domain_error_message() {
96 let error = ConfigError::InvalidShopDomain {
97 domain: "bad domain!".to_string(),
98 };
99 let message = error.to_string();
100 assert!(message.contains("bad domain!"));
101 assert!(message.contains("Expected format"));
102 }
103
104 #[test]
105 fn test_missing_required_field_error_message() {
106 let error = ConfigError::MissingRequiredField { field: "api_key" };
107 let message = error.to_string();
108 assert!(message.contains("api_key"));
109 assert!(message.contains("must be set"));
110 }
111
112 #[test]
113 fn test_error_implements_std_error() {
114 let error = ConfigError::EmptyApiKey;
115 let _: &dyn std::error::Error = &error;
117 }
118
119 #[test]
120 fn test_deprecated_api_version_error_message() {
121 let error = ConfigError::DeprecatedApiVersion {
122 version: "2024-01".to_string(),
123 latest: "2025-10".to_string(),
124 };
125 let message = error.to_string();
126 assert!(message.contains("2024-01"));
127 assert!(message.contains("deprecated"));
128 assert!(message.contains("2025-10"));
129 assert!(message.contains("upgrade"));
130 }
131}