Skip to main content

robinpath_modules/modules/
assert_mod.rs

1use robinpath::{RobinPath, Value};
2
3pub fn register(rp: &mut RobinPath) {
4    rp.register_builtin("assert.equal", |args, _| {
5        let actual = args.first().cloned().unwrap_or(Value::Null);
6        let expected = args.get(1).cloned().unwrap_or(Value::Null);
7        if actual.to_display_string() == expected.to_display_string() {
8            Ok(Value::Bool(true))
9        } else {
10            Err(format!(
11                "assert.equal failed: expected '{}', got '{}'",
12                expected.to_display_string(),
13                actual.to_display_string()
14            ))
15        }
16    });
17
18    rp.register_builtin("assert.notEqual", |args, _| {
19        let actual = args.first().cloned().unwrap_or(Value::Null);
20        let expected = args.get(1).cloned().unwrap_or(Value::Null);
21        if actual.to_display_string() != expected.to_display_string() {
22            Ok(Value::Bool(true))
23        } else {
24            Err(format!(
25                "assert.notEqual failed: values are equal: '{}'",
26                actual.to_display_string()
27            ))
28        }
29    });
30
31    rp.register_builtin("assert.deepEqual", |args, _| {
32        let actual = args.first().cloned().unwrap_or(Value::Null);
33        let expected = args.get(1).cloned().unwrap_or(Value::Null);
34        if actual.deep_eq(&expected) {
35            Ok(Value::Bool(true))
36        } else {
37            Err(format!(
38                "assert.deepEqual failed: expected '{}', got '{}'",
39                expected.to_json_string(),
40                actual.to_json_string()
41            ))
42        }
43    });
44
45    rp.register_builtin("assert.truthy", |args, _| {
46        let val = args.first().cloned().unwrap_or(Value::Null);
47        if val.is_truthy() {
48            Ok(Value::Bool(true))
49        } else {
50            Err(format!(
51                "assert.truthy failed: '{}' is not truthy",
52                val.to_display_string()
53            ))
54        }
55    });
56
57    rp.register_builtin("assert.falsy", |args, _| {
58        let val = args.first().cloned().unwrap_or(Value::Null);
59        if !val.is_truthy() {
60            Ok(Value::Bool(true))
61        } else {
62            Err(format!(
63                "assert.falsy failed: '{}' is not falsy",
64                val.to_display_string()
65            ))
66        }
67    });
68
69    rp.register_builtin("assert.isNull", |args, _| {
70        let val = args.first().cloned().unwrap_or(Value::Null);
71        if matches!(val, Value::Null) {
72            Ok(Value::Bool(true))
73        } else {
74            Err(format!(
75                "assert.isNull failed: '{}' is not null",
76                val.to_display_string()
77            ))
78        }
79    });
80
81    rp.register_builtin("assert.isNotNull", |args, _| {
82        let val = args.first().cloned().unwrap_or(Value::Null);
83        if !matches!(val, Value::Null) {
84            Ok(Value::Bool(true))
85        } else {
86            Err("assert.isNotNull failed: value is null".to_string())
87        }
88    });
89
90    rp.register_builtin("assert.isType", |args, _| {
91        let val = args.first().cloned().unwrap_or(Value::Null);
92        let expected_type = args.get(1).map(|v| v.to_display_string()).unwrap_or_default();
93        let actual_type = match &val {
94            Value::String(_) => "string",
95            Value::Number(_) => "number",
96            Value::Bool(_) => "boolean",
97            Value::Array(_) => "array",
98            Value::Object(_) => "object",
99            Value::Null => "null",
100            Value::Undefined => "undefined",
101        };
102        if actual_type == expected_type {
103            Ok(Value::Bool(true))
104        } else {
105            Err(format!(
106                "assert.isType failed: expected type '{}', got '{}'",
107                expected_type, actual_type
108            ))
109        }
110    });
111
112    rp.register_builtin("assert.includes", |args, _| {
113        let haystack = args.first().cloned().unwrap_or(Value::Null);
114        let needle = args.get(1).cloned().unwrap_or(Value::Null);
115        let found = match &haystack {
116            Value::String(s) => s.contains(&needle.to_display_string()),
117            Value::Array(arr) => arr.iter().any(|v| v.deep_eq(&needle)),
118            _ => false,
119        };
120        if found {
121            Ok(Value::Bool(true))
122        } else {
123            Err(format!(
124                "assert.includes failed: '{}' not found in '{}'",
125                needle.to_display_string(),
126                haystack.to_display_string()
127            ))
128        }
129    });
130
131    rp.register_builtin("assert.matches", |args, _| {
132        let s = args.first().map(|v| v.to_display_string()).unwrap_or_default();
133        let pattern = args.get(1).map(|v| v.to_display_string()).unwrap_or_default();
134        match regex::Regex::new(&pattern) {
135            Ok(re) => {
136                if re.is_match(&s) {
137                    Ok(Value::Bool(true))
138                } else {
139                    Err(format!(
140                        "assert.matches failed: '{}' does not match pattern '{}'",
141                        s, pattern
142                    ))
143                }
144            }
145            Err(e) => Err(format!("assert.matches: invalid regex: {}", e)),
146        }
147    });
148
149    rp.register_builtin("assert.lengthOf", |args, _| {
150        let val = args.first().cloned().unwrap_or(Value::Null);
151        let expected = args.get(1).map(|v| v.to_number() as usize).unwrap_or(0);
152        let actual_len = match &val {
153            Value::String(s) => s.len(),
154            Value::Array(arr) => arr.len(),
155            Value::Object(obj) => obj.len(),
156            _ => 0,
157        };
158        if actual_len == expected {
159            Ok(Value::Bool(true))
160        } else {
161            Err(format!(
162                "assert.lengthOf failed: expected length {}, got {}",
163                expected, actual_len
164            ))
165        }
166    });
167
168    rp.register_builtin("assert.hasProperty", |args, _| {
169        let obj = args.first().cloned().unwrap_or(Value::Null);
170        let prop = args.get(1).map(|v| v.to_display_string()).unwrap_or_default();
171        if let Value::Object(map) = &obj {
172            if map.contains_key(&prop) {
173                Ok(Value::Bool(true))
174            } else {
175                Err(format!(
176                    "assert.hasProperty failed: object does not have property '{}'",
177                    prop
178                ))
179            }
180        } else {
181            Err("assert.hasProperty failed: value is not an object".to_string())
182        }
183    });
184
185    rp.register_builtin("assert.isAbove", |args, _| {
186        let val = args.first().map(|v| v.to_number()).unwrap_or(0.0);
187        let threshold = args.get(1).map(|v| v.to_number()).unwrap_or(0.0);
188        if val > threshold {
189            Ok(Value::Bool(true))
190        } else {
191            Err(format!(
192                "assert.isAbove failed: {} is not above {}",
193                val, threshold
194            ))
195        }
196    });
197
198    rp.register_builtin("assert.isBelow", |args, _| {
199        let val = args.first().map(|v| v.to_number()).unwrap_or(0.0);
200        let threshold = args.get(1).map(|v| v.to_number()).unwrap_or(0.0);
201        if val < threshold {
202            Ok(Value::Bool(true))
203        } else {
204            Err(format!(
205                "assert.isBelow failed: {} is not below {}",
206                val, threshold
207            ))
208        }
209    });
210}