agentic_forge_core/validation/
mod.rs1use crate::types::{ForgeError, ForgeResult};
4use serde_json::Value;
5
6pub struct McpValidator;
7
8impl McpValidator {
9 pub fn require_string(params: &Value, field: &str) -> ForgeResult<String> {
10 params
11 .get(field)
12 .and_then(|v| v.as_str())
13 .map(|s| s.to_string())
14 .ok_or_else(|| ForgeError::MissingField(field.to_string()))
15 }
16
17 pub fn optional_string(params: &Value, field: &str) -> Option<String> {
18 params
19 .get(field)
20 .and_then(|v| v.as_str())
21 .map(|s| s.to_string())
22 }
23
24 pub fn require_u64(params: &Value, field: &str) -> ForgeResult<u64> {
25 params
26 .get(field)
27 .and_then(|v| v.as_u64())
28 .ok_or_else(|| ForgeError::MissingField(field.to_string()))
29 }
30
31 pub fn optional_u64(params: &Value, field: &str) -> Option<u64> {
32 params.get(field).and_then(|v| v.as_u64())
33 }
34
35 pub fn require_f64(params: &Value, field: &str) -> ForgeResult<f64> {
36 params
37 .get(field)
38 .and_then(|v| v.as_f64())
39 .ok_or_else(|| ForgeError::MissingField(field.to_string()))
40 }
41
42 pub fn optional_f64(params: &Value, field: &str) -> Option<f64> {
43 params.get(field).and_then(|v| v.as_f64())
44 }
45
46 pub fn require_bool(params: &Value, field: &str) -> ForgeResult<bool> {
47 params
48 .get(field)
49 .and_then(|v| v.as_bool())
50 .ok_or_else(|| ForgeError::MissingField(field.to_string()))
51 }
52
53 pub fn optional_bool(params: &Value, field: &str) -> Option<bool> {
54 params.get(field).and_then(|v| v.as_bool())
55 }
56
57 pub fn require_array<'a>(params: &'a Value, field: &str) -> ForgeResult<&'a Vec<Value>> {
58 params
59 .get(field)
60 .and_then(|v| v.as_array())
61 .ok_or_else(|| ForgeError::MissingField(field.to_string()))
62 }
63
64 pub fn optional_array<'a>(params: &'a Value, field: &str) -> Option<&'a Vec<Value>> {
65 params.get(field).and_then(|v| v.as_array())
66 }
67
68 pub fn require_object<'a>(
69 params: &'a Value,
70 field: &str,
71 ) -> ForgeResult<&'a serde_json::Map<String, Value>> {
72 params
73 .get(field)
74 .and_then(|v| v.as_object())
75 .ok_or_else(|| ForgeError::MissingField(field.to_string()))
76 }
77}
78
79#[cfg(test)]
80mod tests {
81 use super::*;
82 use serde_json::json;
83
84 #[test]
85 fn test_require_string() {
86 let params = json!({"name": "test"});
87 assert_eq!(
88 McpValidator::require_string(¶ms, "name").unwrap(),
89 "test"
90 );
91 assert!(McpValidator::require_string(¶ms, "missing").is_err());
92 }
93
94 #[test]
95 fn test_optional_string() {
96 let params = json!({"name": "test"});
97 assert_eq!(
98 McpValidator::optional_string(¶ms, "name"),
99 Some("test".into())
100 );
101 assert_eq!(McpValidator::optional_string(¶ms, "missing"), None);
102 }
103
104 #[test]
105 fn test_require_u64() {
106 let params = json!({"count": 42});
107 assert_eq!(McpValidator::require_u64(¶ms, "count").unwrap(), 42);
108 assert!(McpValidator::require_u64(¶ms, "missing").is_err());
109 }
110
111 #[test]
112 fn test_require_f64() {
113 let params = json!({"score": 3.14});
114 let val = McpValidator::require_f64(¶ms, "score").unwrap();
115 assert!((val - 3.14).abs() < f64::EPSILON);
116 }
117
118 #[test]
119 fn test_require_bool() {
120 let params = json!({"active": true});
121 assert!(McpValidator::require_bool(¶ms, "active").unwrap());
122 assert!(McpValidator::require_bool(¶ms, "missing").is_err());
123 }
124
125 #[test]
126 fn test_require_array() {
127 let params = json!({"items": [1, 2, 3]});
128 assert_eq!(
129 McpValidator::require_array(¶ms, "items").unwrap().len(),
130 3
131 );
132 }
133
134 #[test]
135 fn test_require_object() {
136 let params = json!({"meta": {"key": "value"}});
137 let obj = McpValidator::require_object(¶ms, "meta").unwrap();
138 assert!(obj.contains_key("key"));
139 }
140
141 #[test]
142 fn test_optional_u64() {
143 let params = json!({"count": 5});
144 assert_eq!(McpValidator::optional_u64(¶ms, "count"), Some(5));
145 assert_eq!(McpValidator::optional_u64(¶ms, "missing"), None);
146 }
147
148 #[test]
149 fn test_optional_f64() {
150 let params = json!({"score": 2.5});
151 assert!(McpValidator::optional_f64(¶ms, "score").is_some());
152 assert!(McpValidator::optional_f64(¶ms, "missing").is_none());
153 }
154
155 #[test]
156 fn test_optional_bool() {
157 let params = json!({"flag": false});
158 assert_eq!(McpValidator::optional_bool(¶ms, "flag"), Some(false));
159 }
160
161 #[test]
162 fn test_optional_array() {
163 let params = json!({"tags": ["a", "b"]});
164 assert!(McpValidator::optional_array(¶ms, "tags").is_some());
165 assert!(McpValidator::optional_array(¶ms, "missing").is_none());
166 }
167}