robinpath_modules/modules/
assert_mod.rs1use 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}