dsq_functions/builtin/
replace.rs1use dsq_shared::value::Value;
2use dsq_shared::Result;
3use inventory;
4
5pub fn builtin_replace(args: &[Value]) -> Result<Value> {
6 if args.len() != 3 {
7 return Err(dsq_shared::error::operation_error(
8 "replace() expects 3 arguments",
9 ));
10 }
11
12 match (&args[0], &args[1], &args[2]) {
13 (Value::String(s), Value::String(from), Value::String(to)) => {
14 Ok(Value::String(s.replace(from, to)))
15 }
16 _ => Err(dsq_shared::error::operation_error(
17 "replace() requires string arguments",
18 )),
19 }
20}
21
22inventory::submit! {
23 crate::FunctionRegistration {
24 name: "replace",
25 func: builtin_replace,
26 }
27}
28
29#[cfg(test)]
30mod tests {
31 use super::*;
32 use dsq_shared::value::Value;
33
34 #[test]
35 fn test_replace_basic() {
36 let result = builtin_replace(&[
37 Value::String("hello world".to_string()),
38 Value::String("world".to_string()),
39 Value::String("universe".to_string()),
40 ])
41 .unwrap();
42 assert_eq!(result, Value::String("hello universe".to_string()));
43 }
44
45 #[test]
46 fn test_replace_no_match() {
47 let result = builtin_replace(&[
48 Value::String("hello world".to_string()),
49 Value::String("foo".to_string()),
50 Value::String("bar".to_string()),
51 ])
52 .unwrap();
53 assert_eq!(result, Value::String("hello world".to_string()));
54 }
55
56 #[test]
57 fn test_replace_multiple_occurrences() {
58 let result = builtin_replace(&[
59 Value::String("foo foo foo".to_string()),
60 Value::String("foo".to_string()),
61 Value::String("bar".to_string()),
62 ])
63 .unwrap();
64 assert_eq!(result, Value::String("bar bar bar".to_string()));
65 }
66
67 #[test]
68 fn test_replace_empty_from() {
69 let result = builtin_replace(&[
70 Value::String("ab".to_string()),
71 Value::String("".to_string()),
72 Value::String("x".to_string()),
73 ])
74 .unwrap();
75 assert_eq!(result, Value::String("xaxbx".to_string()));
77 }
78
79 #[test]
80 fn test_replace_non_string_args() {
81 let result = builtin_replace(&[
82 Value::Int(123),
83 Value::String("2".to_string()),
84 Value::String("3".to_string()),
85 ]);
86 assert!(result.is_err());
87 assert!(result
88 .unwrap_err()
89 .to_string()
90 .contains("requires string arguments"));
91 }
92
93 #[test]
94 fn test_replace_wrong_number_of_args() {
95 let result = builtin_replace(&[Value::String("test".to_string())]);
96 assert!(result.is_err());
97 assert!(result
98 .unwrap_err()
99 .to_string()
100 .contains("expects 3 arguments"));
101
102 let result = builtin_replace(&[
103 Value::String("test".to_string()),
104 Value::String("t".to_string()),
105 Value::String("r".to_string()),
106 Value::String("extra".to_string()),
107 ]);
108 assert!(result.is_err());
109 assert!(result
110 .unwrap_err()
111 .to_string()
112 .contains("expects 3 arguments"));
113 }
114
115 #[test]
116 fn test_replace_unicode() {
117 let result = builtin_replace(&[
118 Value::String("héllo wörld".to_string()),
119 Value::String("wörld".to_string()),
120 Value::String("universe".to_string()),
121 ])
122 .unwrap();
123 assert_eq!(result, Value::String("héllo universe".to_string()));
124 }
125
126 #[test]
127 fn test_replace_overlapping() {
128 let result = builtin_replace(&[
129 Value::String("aaa".to_string()),
130 Value::String("aa".to_string()),
131 Value::String("b".to_string()),
132 ])
133 .unwrap();
134 assert_eq!(result, Value::String("ba".to_string()));
136 }
137}