1 use js_sys::*;
2 use wasm_bindgen::prelude::*;
3 use wasm_bindgen::JsCast;
4 use wasm_bindgen::JsValue;
5 use wasm_bindgen_test::*;
6
7 #[wasm_bindgen(module = "tests/wasm/JsString.js")]
8 extern "C" {
new_string_object() -> JsValue9 fn new_string_object() -> JsValue;
get_replacer_function() -> Function10 fn get_replacer_function() -> Function;
11 }
12
13 #[wasm_bindgen_test]
js_string_inheritance()14 fn js_string_inheritance() {
15 let string = new_string_object();
16 assert!(string.is_instance_of::<JsString>());
17 assert!(string.is_instance_of::<Object>());
18 }
19
20 #[wasm_bindgen_test]
length()21 fn length() {
22 fn test(s: &str) {
23 assert_eq!(JsString::from(s).length(), s.len() as u32);
24 }
25 test("Mozilla");
26 test("");
27 }
28
29 #[wasm_bindgen_test]
char_at()30 fn char_at() {
31 let s = JsString::from("Brave new world");
32 assert_eq!(JsValue::from(s.char_at(0)), "B");
33 assert_eq!(JsValue::from(s.char_at(999)), "");
34 }
35
36 #[wasm_bindgen_test]
char_code_at()37 fn char_code_at() {
38 let s = "Brave new world";
39 let js = JsString::from(s);
40 for (i, b) in s.char_indices() {
41 assert_eq!(js.char_code_at(i as u32), b as u32 as f64);
42 }
43 assert!(js.char_code_at(s.len() as u32).is_nan());
44 }
45
46 #[wasm_bindgen_test]
code_point_at()47 fn code_point_at() {
48 assert_eq!(JsString::from("ABC").code_point_at(1), b'B');
49 assert!(JsString::from("ABC").code_point_at(42).is_undefined());
50 }
51
52 #[wasm_bindgen_test]
concat()53 fn concat() {
54 // TODO: Implement ability to receive multiple optional arguments
55 let s = JsString::from("Hello ").concat(&"World".into());
56 assert_eq!(JsValue::from(s), "Hello World");
57 let foo = JsString::from("foo");
58 assert_eq!(
59 JsValue::from(foo.concat(&Object::new().into())),
60 "foo[object Object]"
61 );
62 assert_eq!(JsValue::from(foo.concat(&Array::new().into())), "foo");
63 assert_eq!(JsValue::from(foo.concat(&JsValue::null())), "foonull");
64 assert_eq!(JsValue::from(foo.concat(&true.into())), "footrue");
65 assert_eq!(JsValue::from(foo.concat(&1234.into())), "foo1234");
66 }
67
68 #[wasm_bindgen_test]
ends_with()69 fn ends_with() {
70 let s = "To be, or not to be, that is the question.";
71 let js = JsString::from(s);
72
73 // TODO: remove third parameter once we have optional parameters
74 assert_eq!(js.ends_with("question.", s.len() as i32), true);
75 assert_eq!(js.ends_with("to be", s.len() as i32), false);
76 assert_eq!(js.ends_with("to be", 19), true);
77 }
78
79 #[wasm_bindgen_test]
from_char_code()80 fn from_char_code() {
81 let s = "½+¾=";
82 let codes: Vec<u32> = s.chars().map(|char| char as u32).collect();
83
84 assert_eq!(JsString::from_char_code1(codes[0]), "½");
85 assert_eq!(JsString::from_char_code2(codes[0], codes[1]), "½+");
86 assert_eq!(
87 JsString::from_char_code3(codes[0], codes[1], codes[2]),
88 "½+¾"
89 );
90 assert_eq!(
91 JsString::from_char_code4(codes[0], codes[1], codes[2], codes[3]),
92 "½+¾="
93 );
94
95 let codes_u16: Vec<u16> = codes
96 .into_iter()
97 .map(|code| {
98 assert!(code <= u32::from(u16::max_value()));
99 code as u16
100 })
101 .collect();
102
103 assert_eq!(JsString::from_char_code(&codes_u16), "½+¾=");
104 }
105
106 #[wasm_bindgen_test]
from_code_point()107 fn from_code_point() {
108 let s = "☃★♲你";
109 let codes: Vec<u32> = s.chars().map(|char| char as u32).collect();
110
111 assert_eq!(JsString::from_code_point1(codes[0]).unwrap(), "☃");
112 assert_eq!(
113 JsString::from_code_point2(codes[0], codes[1]).unwrap(),
114 "☃★"
115 );
116 assert_eq!(
117 JsString::from_code_point3(codes[0], codes[1], codes[2]).unwrap(),
118 "☃★♲"
119 );
120 assert_eq!(
121 JsString::from_code_point4(codes[0], codes[1], codes[2], codes[3]).unwrap(),
122 "☃★♲你"
123 );
124 assert_eq!(JsString::from_code_point(&codes).unwrap(), "☃★♲你");
125
126 assert!(!JsString::from_code_point1(0x10FFFF).is_err());
127 assert!(JsString::from_code_point1(0x110000).is_err());
128 assert!(JsString::from_code_point1(u32::max_value()).is_err());
129 }
130
131 #[wasm_bindgen_test]
includes()132 fn includes() {
133 let str = JsString::from("Blue Whale");
134
135 // TODO: remove second parameter once we have optional parameters
136 assert_eq!(str.includes("Blue", 0), true);
137 assert_eq!(str.includes("Blute", 0), false);
138 assert_eq!(str.includes("Whale", 0), true);
139 assert_eq!(str.includes("Whale", 5), true);
140 assert_eq!(str.includes("Whale", 7), false);
141 assert_eq!(str.includes("", 0), true);
142 assert_eq!(str.includes("", 16), true);
143 }
144
145 #[wasm_bindgen_test]
index_of()146 fn index_of() {
147 let str = JsString::from("Blue Whale");
148
149 // TODO: remove second parameter once we have optional parameters
150 assert_eq!(str.index_of("Blue", 0), 0);
151 // TODO: remove second parameter once we have optional parameters
152 assert_eq!(str.index_of("Blute", 0), -1);
153 assert_eq!(str.index_of("Whale", 0), 5);
154 assert_eq!(str.index_of("Whale", 5), 5);
155 assert_eq!(str.index_of("Whale", 7), -1);
156 // TODO: remove second parameter once we have optional parameters
157 assert_eq!(str.index_of("", 0), 0);
158 assert_eq!(str.index_of("", 9), 9);
159 assert_eq!(str.index_of("", 10), 10);
160 assert_eq!(str.index_of("", 11), 10);
161 }
162
163 #[wasm_bindgen_test]
last_index_of()164 fn last_index_of() {
165 let js = JsString::from("canal");
166 let len = js.length() as i32;
167
168 // TODO: remove second parameter once we have optional parameters
169 assert_eq!(js.last_index_of("a", len), 3);
170 assert_eq!(js.last_index_of("a", 2), 1);
171 assert_eq!(js.last_index_of("a", 0), -1);
172 // TODO: remove second parameter once we have optional parameters
173 assert_eq!(js.last_index_of("x", len), -1);
174 assert_eq!(js.last_index_of("c", -5), 0);
175 assert_eq!(js.last_index_of("c", 0), 0);
176 // TODO: remove second parameter once we have optional parameters
177 assert_eq!(js.last_index_of("", len), 5);
178 assert_eq!(js.last_index_of("", 2), 2);
179 }
180
181 #[wasm_bindgen_test]
match_()182 fn match_() {
183 let s = "The quick brown fox jumped over the lazy dog. It barked.";
184 let re = RegExp::new("[A-Z]", "g");
185 let result = JsString::from(s).match_(&re);
186 let obj = result.unwrap();
187
188 assert_eq!(Reflect::get(obj.as_ref(), &"0".into()).unwrap(), "T");
189 assert_eq!(Reflect::get(obj.as_ref(), &"1".into()).unwrap(), "I");
190
191 let result = JsString::from("foo").match_(&re);
192 assert!(result.is_none());
193
194 let s = "For more information, see Chapter 3.4.5.1";
195 let re = RegExp::new("see (chapter \\d+(\\.\\d)*)", "i");
196 let result = JsString::from(s).match_(&re);
197 let obj = result.unwrap();
198
199 assert_eq!(
200 Reflect::get(obj.as_ref(), &"0".into()).unwrap(),
201 "see Chapter 3.4.5.1"
202 );
203 assert_eq!(
204 Reflect::get(obj.as_ref(), &"1".into()).unwrap(),
205 "Chapter 3.4.5.1"
206 );
207 assert_eq!(Reflect::get(obj.as_ref(), &"2".into()).unwrap(), ".1");
208 assert_eq!(Reflect::get(obj.as_ref(), &"index".into()).unwrap(), 22);
209 assert_eq!(Reflect::get(obj.as_ref(), &"input".into()).unwrap(), s);
210 }
211
212 #[wasm_bindgen_test]
normalize()213 fn normalize() {
214 let js = JsString::from("\u{1E9B}\u{0323}");
215
216 // TODO: Handle undefined
217 assert_eq!(JsValue::from(js.normalize("NFC")), "\u{1E9B}\u{0323}");
218 assert_eq!(
219 JsValue::from(js.normalize("NFD")),
220 "\u{017F}\u{0323}\u{0307}"
221 );
222 assert_eq!(JsValue::from(js.normalize("NFKC")), "\u{1E69}");
223 assert_eq!(
224 JsValue::from(js.normalize("NFKD")),
225 "\u{0073}\u{0323}\u{0307}"
226 );
227 }
228
229 #[wasm_bindgen_test]
pad_end()230 fn pad_end() {
231 let js = JsString::from("abc");
232
233 // TODO: remove second parameter once we have optional parameters
234 assert_eq!(JsValue::from(js.pad_end(10, " ")), "abc ");
235 // TODO: remove second parameter once we have optional parameters
236 assert_eq!(JsValue::from(js.pad_end(10, " ")), "abc ");
237 assert_eq!(JsValue::from(js.pad_end(10, "foo")), "abcfoofoof");
238 assert_eq!(JsValue::from(js.pad_end(6, "123456")), "abc123");
239 // TODO: remove second parameter once we have optional parameters
240 assert_eq!(JsValue::from(js.pad_end(1, " ")), "abc");
241 }
242
243 #[wasm_bindgen_test]
pad_start()244 fn pad_start() {
245 let js = JsString::from("abc");
246
247 // TODO: remove second parameter once we have optional parameters
248 assert_eq!(js.pad_start(10, " "), " abc");
249 assert_eq!(js.pad_start(10, "foo"), "foofoofabc");
250 assert_eq!(js.pad_start(6, "123465"), "123abc");
251 assert_eq!(js.pad_start(8, "0"), "00000abc");
252 // TODO: remove second parameter once we have optional parameters
253 assert_eq!(js.pad_start(1, " "), "abc");
254 }
255
256 #[wasm_bindgen_test]
repeat()257 fn repeat() {
258 assert_eq!(JsString::from("test").repeat(3), "testtesttest");
259 }
260
261 #[wasm_bindgen_test]
replace()262 fn replace() {
263 let js = JsString::from(
264 "The quick brown fox jumped over the lazy dog. If the dog reacted, was it really lazy?",
265 );
266 let result = js.replace("dog", "ferret");
267
268 assert_eq!(
269 result,
270 "The quick brown fox jumped over the lazy ferret. If the dog reacted, was it really lazy?"
271 );
272
273 let js = JsString::from("borderTop");
274 let result = js.replace_with_function("T", &get_replacer_function());
275
276 assert_eq!(result, "border-top");
277
278 let js = JsString::from(
279 "The quick brown fox jumped over the lazy dog. If the dog reacted, was it really lazy?",
280 );
281 let re = RegExp::new("dog", "g");
282 let result = js.replace_by_pattern(&re, "ferret");
283
284 assert_eq!(result, "The quick brown fox jumped over the lazy ferret. If the ferret reacted, was it really lazy?");
285
286 let js = JsString::from("borderTop");
287 let re = RegExp::new("[A-Z]", "g");
288 let result = js.replace_by_pattern_with_function(&re, &get_replacer_function());
289
290 assert_eq!(result, "border-top");
291 }
292
293 #[wasm_bindgen_test]
search()294 fn search() {
295 let js = JsString::from(
296 "The quick brown fox jumped over the lazy dog. If the dog reacted, was it really lazy?",
297 );
298 let re = RegExp::new("[^\\w\\s]", "g");
299
300 assert_eq!(js.search(&re), 44);
301
302 let js = JsString::from("hey JudE");
303 let re1 = RegExp::new("[A-Z]", "g");
304 let re2 = RegExp::new("[.]", "g");
305
306 assert_eq!(js.search(&re1), 4);
307 assert_eq!(js.search(&re2), -1);
308 }
309
310 #[wasm_bindgen_test]
slice()311 fn slice() {
312 let characters = JsString::from("acxn18");
313 assert_eq!(characters.slice(1, 3), "cx");
314 }
315
316 #[wasm_bindgen_test]
split()317 fn split() {
318 let js = JsString::from("Oh brave new world");
319 let result = js.split(" ");
320
321 let mut v = Vec::with_capacity(result.length() as usize);
322 result.for_each(&mut |x, _, _| v.push(x));
323
324 assert_eq!(v[0], "Oh");
325 assert_eq!(v[1], "brave");
326 assert_eq!(v[2], "new");
327 assert_eq!(v[3], "world");
328
329 let js = JsString::from("Oct,Nov,Dec");
330 let result = js.split(",");
331
332 let mut v = Vec::with_capacity(result.length() as usize);
333 result.for_each(&mut |x, _, _| v.push(x));
334
335 assert_eq!(v[0], "Oct");
336 assert_eq!(v[1], "Nov");
337 assert_eq!(v[2], "Dec");
338
339 let result = js.split_limit(",", 2);
340
341 let mut v = Vec::with_capacity(result.length() as usize);
342 result.for_each(&mut |x, _, _| v.push(x));
343
344 assert_eq!(result.length(), 2);
345 assert_eq!(v[0], "Oct");
346 assert_eq!(v[1], "Nov");
347
348 let js = JsString::from("Oh brave new world");
349 let re = RegExp::new("\\s", "g");
350 let result = js.split_by_pattern(&re);
351
352 let mut v = Vec::with_capacity(result.length() as usize);
353 result.for_each(&mut |x, _, _| v.push(x));
354
355 assert_eq!(v[0], "Oh");
356 assert_eq!(v[1], "brave");
357 assert_eq!(v[2], "new");
358 assert_eq!(v[3], "world");
359
360 let result = js.split_by_pattern_limit(&re, 2);
361
362 let mut v = Vec::with_capacity(result.length() as usize);
363 result.for_each(&mut |x, _, _| v.push(x));
364
365 assert_eq!(result.length(), 2);
366 assert_eq!(v[0], "Oh");
367 assert_eq!(v[1], "brave");
368 }
369
370 #[wasm_bindgen_test]
starts_with()371 fn starts_with() {
372 let js = JsString::from("To be, or not to be, that is the question.");
373
374 // TODO: remove second parameter for both assertions once we have optional parameters
375 assert!(js.starts_with("To be", 0));
376 assert!(!js.starts_with("not to be", 0));
377 assert!(js.starts_with("not to be", 10));
378 }
379
380 #[wasm_bindgen_test]
substring()381 fn substring() {
382 let js = JsString::from("Mozilla");
383
384 assert_eq!(js.substring(0, 1), "M");
385 assert_eq!(js.substring(1, 0), "M");
386
387 assert_eq!(js.substring(0, 6), "Mozill");
388
389 // TODO: Add test once we have optional parameters
390 // assert_eq!(js.substring(4), "lla");
391 assert_eq!(js.substring(4, 7), "lla");
392 assert_eq!(js.substring(7, 4), "lla");
393
394 assert_eq!(js.substring(0, 7), "Mozilla");
395 assert_eq!(js.substring(0, 10), "Mozilla");
396 }
397
398 #[wasm_bindgen_test]
substr()399 fn substr() {
400 let js = JsString::from("Mozilla");
401
402 assert_eq!(js.substr(0, 1), "M");
403 assert_eq!(js.substr(1, 0), "");
404 assert_eq!(js.substr(-1, 1), "a");
405 assert_eq!(js.substr(1, -1), "");
406 // TODO: Uncomment and test these assertions, once we have support for optional parameters
407 // assert_eq!(js.substr(-3), "lla");
408 // assert_eq!(js.substr(1), "ozilla");
409 assert_eq!(js.substr(-20, 2), "Mo");
410 assert_eq!(js.substr(20, 2), "");
411 }
412
413 #[wasm_bindgen_test]
to_locale_lower_case()414 fn to_locale_lower_case() {
415 let js = JsString::from("Mozilla");
416 assert_eq!(js.to_locale_lower_case(None), "mozilla");
417 let s = JsString::from("\u{0130}");
418 assert_eq!(s.to_locale_lower_case(Some("tr".into())), "i");
419 assert_ne!(s.to_locale_lower_case(Some("en-US".into())), "i");
420 }
421
422 #[wasm_bindgen_test]
to_locale_upper_case()423 fn to_locale_upper_case() {
424 let js = JsString::from("mozilla");
425 assert_eq!(js.to_locale_upper_case(None), "MOZILLA");
426 let s = JsString::from("i\u{0307}");
427 assert_eq!(s.to_locale_upper_case(Some("lt".into())), "I");
428 assert_ne!(s.to_locale_upper_case(Some("en-US".into())), "I");
429 }
430
431 #[wasm_bindgen_test]
to_lower_case()432 fn to_lower_case() {
433 assert_eq!(JsString::from("Mozilla").to_lower_case(), "mozilla");
434 }
435
436 #[wasm_bindgen_test]
to_string()437 fn to_string() {
438 assert_eq!(JsString::from("foo").to_string(), "foo");
439 }
440
441 #[wasm_bindgen_test]
to_upper_case()442 fn to_upper_case() {
443 assert_eq!(JsString::from("Mozilla").to_upper_case(), "MOZILLA");
444 }
445
446 #[wasm_bindgen_test]
trim()447 fn trim() {
448 assert_eq!(JsString::from(" foo ").trim(), "foo");
449 // Another example of .trim() removing whitespace from just one side.
450 assert_eq!(JsString::from("foo ").trim(), "foo");
451 }
452
453 #[wasm_bindgen_test]
trim_end_and_trim_right()454 fn trim_end_and_trim_right() {
455 let greeting = JsString::from(" Hello world! ");
456 let trimmed = " Hello world!";
457 assert_eq!(greeting.trim_end(), trimmed);
458 assert_eq!(greeting.trim_right(), trimmed);
459 }
460
461 #[wasm_bindgen_test]
trim_start_and_trim_left()462 fn trim_start_and_trim_left() {
463 let greeting = JsString::from(" Hello world! ");
464 let trimmed = "Hello world! ";
465 assert_eq!(greeting.trim_start(), trimmed);
466 assert_eq!(greeting.trim_left(), trimmed);
467 }
468
469 #[wasm_bindgen_test]
value_of()470 fn value_of() {
471 let greeting = JsString::from("Hello world!");
472 assert_eq!(greeting.value_of(), "Hello world!");
473 }
474
475 #[wasm_bindgen_test]
raw()476 fn raw() {
477 let call_site = Object::new();
478 let raw = Array::of3(&"foo".into(), &"bar".into(), &"123".into());
479 Reflect::set(&call_site.as_ref(), &"raw".into(), &raw.into()).unwrap();
480 assert_eq!(
481 JsString::raw_2(&call_site, "5", "JavaScript").unwrap(),
482 "foo5barJavaScript123"
483 );
484 let substitutions = Array::of2(&"5".into(), &"JavaScript".into());
485 assert_eq!(
486 JsString::raw(&call_site, &substitutions).unwrap(),
487 "foo5barJavaScript123"
488 );
489 assert!(JsString::raw_0(&JsValue::null().unchecked_into()).is_err());
490 }
491
492 #[wasm_bindgen_test]
is_valid_utf16()493 fn is_valid_utf16() {
494 assert!(JsString::from("a").is_valid_utf16());
495 assert!(JsString::from("").is_valid_utf16());
496 assert!(JsString::from("").is_valid_utf16());
497 assert!(JsString::from("Why hello there this, , is and is ").is_valid_utf16());
498
499 assert!(JsString::from_char_code1(0x00).is_valid_utf16());
500 assert!(!JsString::from_char_code1(0xd800).is_valid_utf16());
501 assert!(!JsString::from_char_code1(0xdc00).is_valid_utf16());
502 }
503
504 #[wasm_bindgen_test]
as_char()505 fn as_char() {
506 assert_eq!(JsString::from('a').as_char(), Some('a'));
507 assert_eq!(JsString::from('').as_char(), Some(''));
508 assert_eq!(JsString::from("").as_char(), None);
509 assert_eq!(JsString::from("ab").as_char(), None);
510 assert_eq!(JsString::from_char_code1(0xd800).as_char(), None);
511 assert_eq!(JsString::from_char_code1(0xdc00).as_char(), None);
512 assert_eq!(JsString::from_char_code1(0xdfff).as_char(), None);
513 }
514