mockforge_plugin_sdk/
lib.rs

1//! # MockForge Plugin SDK
2//!
3//! Official SDK for developing MockForge plugins with ease.
4//!
5//! This SDK provides:
6//! - Helper macros for plugin creation
7//! - Builder patterns for manifests
8//! - Testing utilities
9//! - Type-safe plugin development
10//!
11//! ## Quick Start
12//!
13//! ```rust,no_run
14//! use mockforge_plugin_sdk::{export_plugin, prelude::*, Result as PluginCoreResult};
15//! use std::collections::HashMap;
16//!
17//! #[derive(Debug, Default)]
18//! pub struct MyPlugin;
19//!
20//! #[async_trait]
21//! impl AuthPlugin for MyPlugin {
22//!     fn capabilities(&self) -> PluginCapabilities {
23//!         PluginCapabilities::default()
24//!     }
25//!
26//!     async fn initialize(&self, _config: &AuthPluginConfig) -> PluginCoreResult<()> {
27//!         Ok(())
28//!     }
29//!
30//!     async fn authenticate(
31//!         &self,
32//!         _context: &PluginContext,
33//!         _request: &AuthRequest,
34//!         _config: &AuthPluginConfig,
35//!     ) -> PluginCoreResult<PluginResult<AuthResponse>> {
36//!         let identity = UserIdentity::new("user123");
37//!         let response = AuthResponse::success(identity, HashMap::new());
38//!         Ok(PluginResult::success(response, 0))
39//!     }
40//!
41//!     fn validate_config(&self, _config: &AuthPluginConfig) -> PluginCoreResult<()> {
42//!         Ok(())
43//!     }
44//!
45//!     fn supported_schemes(&self) -> Vec<String> {
46//!         vec!["basic".to_string()]
47//!     }
48//!
49//!     async fn cleanup(&self) -> PluginCoreResult<()> {
50//!         Ok(())
51//!     }
52//! }
53//!
54//! export_plugin!(MyPlugin);
55//! ```
56
57pub mod builders;
58pub mod macros;
59pub mod prelude;
60
61#[cfg(feature = "testing")]
62pub mod testing;
63
64// Re-export core plugin types
65pub use mockforge_plugin_core::*;
66
67/// SDK version
68pub const SDK_VERSION: &str = env!("CARGO_PKG_VERSION");
69
70/// Recommended WASM target
71pub const WASM_TARGET: &str = "wasm32-wasi";
72
73/// Plugin SDK result type
74pub type SdkResult<T> = std::result::Result<T, SdkError>;
75
76/// SDK-specific errors
77#[derive(Debug, thiserror::Error)]
78pub enum SdkError {
79    /// Plugin configuration error
80    #[error("Plugin configuration error: {0}")]
81    ConfigError(String),
82
83    /// Manifest generation error
84    #[error("Manifest generation error: {0}")]
85    ManifestError(String),
86
87    /// Build error
88    #[error("Build error: {0}")]
89    BuildError(String),
90
91    /// Template error
92    #[error("Template error: {0}")]
93    TemplateError(String),
94
95    /// IO error
96    #[error("IO error: {0}")]
97    IoError(#[from] std::io::Error),
98
99    /// Serialization error
100    #[error("Serialization error: {0}")]
101    SerializationError(String),
102}
103
104impl SdkError {
105    /// Create a configuration error
106    pub fn config<S: Into<String>>(msg: S) -> Self {
107        Self::ConfigError(msg.into())
108    }
109
110    /// Create a manifest error
111    pub fn manifest<S: Into<String>>(msg: S) -> Self {
112        Self::ManifestError(msg.into())
113    }
114
115    /// Create a build error
116    pub fn build<S: Into<String>>(msg: S) -> Self {
117        Self::BuildError(msg.into())
118    }
119
120    /// Create a template error
121    pub fn template<S: Into<String>>(msg: S) -> Self {
122        Self::TemplateError(msg.into())
123    }
124
125    /// Create a serialization error
126    pub fn serialization<S: Into<String>>(msg: S) -> Self {
127        Self::SerializationError(msg.into())
128    }
129}
130
131#[cfg(test)]
132mod tests {
133    use super::*;
134
135    // SDK constants tests
136    #[test]
137    fn test_sdk_version() {
138        assert!(!SDK_VERSION.is_empty());
139    }
140
141    #[test]
142    fn test_wasm_target() {
143        assert_eq!(WASM_TARGET, "wasm32-wasi");
144    }
145
146    // SdkError tests
147    #[test]
148    fn test_sdk_error_config() {
149        let error = SdkError::config("missing field");
150        assert_eq!(error.to_string(), "Plugin configuration error: missing field");
151    }
152
153    #[test]
154    fn test_sdk_error_manifest() {
155        let error = SdkError::manifest("invalid version");
156        assert_eq!(error.to_string(), "Manifest generation error: invalid version");
157    }
158
159    #[test]
160    fn test_sdk_error_build() {
161        let error = SdkError::build("compilation failed");
162        assert_eq!(error.to_string(), "Build error: compilation failed");
163    }
164
165    #[test]
166    fn test_sdk_error_template() {
167        let error = SdkError::template("invalid template");
168        assert_eq!(error.to_string(), "Template error: invalid template");
169    }
170
171    #[test]
172    fn test_sdk_error_serialization() {
173        let error = SdkError::serialization("JSON error");
174        assert_eq!(error.to_string(), "Serialization error: JSON error");
175    }
176
177    #[test]
178    fn test_sdk_error_from_io() {
179        let io_error = std::io::Error::new(std::io::ErrorKind::NotFound, "file not found");
180        let sdk_error: SdkError = io_error.into();
181        assert!(matches!(sdk_error, SdkError::IoError(_)));
182        assert!(sdk_error.to_string().contains("IO error"));
183    }
184
185    #[test]
186    fn test_sdk_error_debug() {
187        let error = SdkError::config("test");
188        let debug = format!("{:?}", error);
189        assert!(debug.contains("ConfigError"));
190    }
191
192    #[test]
193    fn test_sdk_error_config_with_string() {
194        let msg = String::from("config error message");
195        let error = SdkError::config(msg);
196        assert!(error.to_string().contains("config error message"));
197    }
198
199    #[test]
200    fn test_sdk_error_manifest_with_string() {
201        let msg = String::from("manifest error message");
202        let error = SdkError::manifest(msg);
203        assert!(error.to_string().contains("manifest error message"));
204    }
205
206    #[test]
207    fn test_sdk_error_build_with_string() {
208        let msg = String::from("build error message");
209        let error = SdkError::build(msg);
210        assert!(error.to_string().contains("build error message"));
211    }
212
213    // SdkResult tests
214    #[test]
215    fn test_sdk_result_ok() {
216        let result: SdkResult<i32> = Ok(42);
217        assert!(result.is_ok());
218        assert_eq!(result.unwrap(), 42);
219    }
220
221    #[test]
222    fn test_sdk_result_err() {
223        let result: SdkResult<i32> = Err(SdkError::config("test"));
224        assert!(result.is_err());
225    }
226
227    // Test error variants
228    #[test]
229    fn test_all_error_variants_display() {
230        let errors = vec![
231            SdkError::ConfigError("config".to_string()),
232            SdkError::ManifestError("manifest".to_string()),
233            SdkError::BuildError("build".to_string()),
234            SdkError::TemplateError("template".to_string()),
235            SdkError::SerializationError("serialization".to_string()),
236        ];
237
238        for error in errors {
239            let display = error.to_string();
240            assert!(!display.is_empty());
241        }
242    }
243}