Skip to main content

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        let version: &str = SDK_VERSION;
139        assert!(!version.is_empty(), "SDK_VERSION should not be empty");
140    }
141
142    #[test]
143    fn test_wasm_target() {
144        assert_eq!(WASM_TARGET, "wasm32-wasi");
145    }
146
147    // SdkError tests
148    #[test]
149    fn test_sdk_error_config() {
150        let error = SdkError::config("missing field");
151        assert_eq!(error.to_string(), "Plugin configuration error: missing field");
152    }
153
154    #[test]
155    fn test_sdk_error_manifest() {
156        let error = SdkError::manifest("invalid version");
157        assert_eq!(error.to_string(), "Manifest generation error: invalid version");
158    }
159
160    #[test]
161    fn test_sdk_error_build() {
162        let error = SdkError::build("compilation failed");
163        assert_eq!(error.to_string(), "Build error: compilation failed");
164    }
165
166    #[test]
167    fn test_sdk_error_template() {
168        let error = SdkError::template("invalid template");
169        assert_eq!(error.to_string(), "Template error: invalid template");
170    }
171
172    #[test]
173    fn test_sdk_error_serialization() {
174        let error = SdkError::serialization("JSON error");
175        assert_eq!(error.to_string(), "Serialization error: JSON error");
176    }
177
178    #[test]
179    fn test_sdk_error_from_io() {
180        let io_error = std::io::Error::new(std::io::ErrorKind::NotFound, "file not found");
181        let sdk_error: SdkError = io_error.into();
182        assert!(matches!(sdk_error, SdkError::IoError(_)));
183        assert!(sdk_error.to_string().contains("IO error"));
184    }
185
186    #[test]
187    fn test_sdk_error_debug() {
188        let error = SdkError::config("test");
189        let debug = format!("{:?}", error);
190        assert!(debug.contains("ConfigError"));
191    }
192
193    #[test]
194    fn test_sdk_error_config_with_string() {
195        let msg = String::from("config error message");
196        let error = SdkError::config(msg);
197        assert!(error.to_string().contains("config error message"));
198    }
199
200    #[test]
201    fn test_sdk_error_manifest_with_string() {
202        let msg = String::from("manifest error message");
203        let error = SdkError::manifest(msg);
204        assert!(error.to_string().contains("manifest error message"));
205    }
206
207    #[test]
208    fn test_sdk_error_build_with_string() {
209        let msg = String::from("build error message");
210        let error = SdkError::build(msg);
211        assert!(error.to_string().contains("build error message"));
212    }
213
214    // SdkResult tests
215    #[test]
216    fn test_sdk_result_ok() {
217        let result: SdkResult<i32> = Ok(42);
218        assert!(result.is_ok());
219        match result {
220            Ok(val) => assert_eq!(val, 42),
221            Err(_) => panic!("Expected Ok"),
222        }
223    }
224
225    #[test]
226    fn test_sdk_result_err() {
227        let result: SdkResult<i32> = Err(SdkError::config("test"));
228        assert!(result.is_err());
229    }
230
231    // Test error variants
232    #[test]
233    fn test_all_error_variants_display() {
234        let errors = vec![
235            SdkError::ConfigError("config".to_string()),
236            SdkError::ManifestError("manifest".to_string()),
237            SdkError::BuildError("build".to_string()),
238            SdkError::TemplateError("template".to_string()),
239            SdkError::SerializationError("serialization".to_string()),
240        ];
241
242        for error in errors {
243            let display = error.to_string();
244            assert!(!display.is_empty());
245        }
246    }
247}