]> git.proxmox.com Git - rustc.git/blob - library/alloc/tests/str.rs
New upstream version 1.52.0+dfsg1
[rustc.git] / library / alloc / tests / str.rs
1 use std::borrow::Cow;
2 use std::cmp::Ordering::{Equal, Greater, Less};
3 use std::str::{from_utf8, from_utf8_unchecked};
4
5 #[test]
6 fn test_le() {
7 assert!("" <= "");
8 assert!("" <= "foo");
9 assert!("foo" <= "foo");
10 assert_ne!("foo", "bar");
11 }
12
13 #[test]
14 fn test_find() {
15 assert_eq!("hello".find('l'), Some(2));
16 assert_eq!("hello".find(|c: char| c == 'o'), Some(4));
17 assert!("hello".find('x').is_none());
18 assert!("hello".find(|c: char| c == 'x').is_none());
19 assert_eq!("ประเทศไทย中华Việt Nam".find('华'), Some(30));
20 assert_eq!("ประเทศไทย中华Việt Nam".find(|c: char| c == '华'), Some(30));
21 }
22
23 #[test]
24 fn test_rfind() {
25 assert_eq!("hello".rfind('l'), Some(3));
26 assert_eq!("hello".rfind(|c: char| c == 'o'), Some(4));
27 assert!("hello".rfind('x').is_none());
28 assert!("hello".rfind(|c: char| c == 'x').is_none());
29 assert_eq!("ประเทศไทย中华Việt Nam".rfind('华'), Some(30));
30 assert_eq!("ประเทศไทย中华Việt Nam".rfind(|c: char| c == '华'), Some(30));
31 }
32
33 #[test]
34 fn test_collect() {
35 let empty = "";
36 let s: String = empty.chars().collect();
37 assert_eq!(empty, s);
38 let data = "ประเทศไทย中";
39 let s: String = data.chars().collect();
40 assert_eq!(data, s);
41 }
42
43 #[test]
44 fn test_into_bytes() {
45 let data = String::from("asdf");
46 let buf = data.into_bytes();
47 assert_eq!(buf, b"asdf");
48 }
49
50 #[test]
51 fn test_find_str() {
52 // byte positions
53 assert_eq!("".find(""), Some(0));
54 assert!("banana".find("apple pie").is_none());
55
56 let data = "abcabc";
57 assert_eq!(data[0..6].find("ab"), Some(0));
58 assert_eq!(data[2..6].find("ab"), Some(3 - 2));
59 assert!(data[2..4].find("ab").is_none());
60
61 let string = "ประเทศไทย中华Việt Nam";
62 let mut data = String::from(string);
63 data.push_str(string);
64 assert!(data.find("ไท华").is_none());
65 assert_eq!(data[0..43].find(""), Some(0));
66 assert_eq!(data[6..43].find(""), Some(6 - 6));
67
68 assert_eq!(data[0..43].find("ประ"), Some(0));
69 assert_eq!(data[0..43].find("ทศไ"), Some(12));
70 assert_eq!(data[0..43].find("ย中"), Some(24));
71 assert_eq!(data[0..43].find("iệt"), Some(34));
72 assert_eq!(data[0..43].find("Nam"), Some(40));
73
74 assert_eq!(data[43..86].find("ประ"), Some(43 - 43));
75 assert_eq!(data[43..86].find("ทศไ"), Some(55 - 43));
76 assert_eq!(data[43..86].find("ย中"), Some(67 - 43));
77 assert_eq!(data[43..86].find("iệt"), Some(77 - 43));
78 assert_eq!(data[43..86].find("Nam"), Some(83 - 43));
79
80 // find every substring -- assert that it finds it, or an earlier occurrence.
81 let string = "Việt Namacbaabcaabaaba";
82 for (i, ci) in string.char_indices() {
83 let ip = i + ci.len_utf8();
84 for j in string[ip..].char_indices().map(|(i, _)| i).chain(Some(string.len() - ip)) {
85 let pat = &string[i..ip + j];
86 assert!(match string.find(pat) {
87 None => false,
88 Some(x) => x <= i,
89 });
90 assert!(match string.rfind(pat) {
91 None => false,
92 Some(x) => x >= i,
93 });
94 }
95 }
96 }
97
98 fn s(x: &str) -> String {
99 x.to_string()
100 }
101
102 macro_rules! test_concat {
103 ($expected: expr, $string: expr) => {{
104 let s: String = $string.concat();
105 assert_eq!($expected, s);
106 }};
107 }
108
109 #[test]
110 fn test_concat_for_different_types() {
111 test_concat!("ab", vec![s("a"), s("b")]);
112 test_concat!("ab", vec!["a", "b"]);
113 }
114
115 #[test]
116 fn test_concat_for_different_lengths() {
117 let empty: &[&str] = &[];
118 test_concat!("", empty);
119 test_concat!("a", ["a"]);
120 test_concat!("ab", ["a", "b"]);
121 test_concat!("abc", ["", "a", "bc"]);
122 }
123
124 macro_rules! test_join {
125 ($expected: expr, $string: expr, $delim: expr) => {{
126 let s = $string.join($delim);
127 assert_eq!($expected, s);
128 }};
129 }
130
131 #[test]
132 fn test_join_for_different_types() {
133 test_join!("a-b", ["a", "b"], "-");
134 let hyphen = "-".to_string();
135 test_join!("a-b", [s("a"), s("b")], &*hyphen);
136 test_join!("a-b", vec!["a", "b"], &*hyphen);
137 test_join!("a-b", &*vec!["a", "b"], "-");
138 test_join!("a-b", vec![s("a"), s("b")], "-");
139 }
140
141 #[test]
142 fn test_join_for_different_lengths() {
143 let empty: &[&str] = &[];
144 test_join!("", empty, "-");
145 test_join!("a", ["a"], "-");
146 test_join!("a-b", ["a", "b"], "-");
147 test_join!("-a-bc", ["", "a", "bc"], "-");
148 }
149
150 // join has fast paths for small separators up to 4 bytes
151 // this tests the slow paths.
152 #[test]
153 fn test_join_for_different_lengths_with_long_separator() {
154 assert_eq!("~~~~~".len(), 15);
155
156 let empty: &[&str] = &[];
157 test_join!("", empty, "~~~~~");
158 test_join!("a", ["a"], "~~~~~");
159 test_join!("a~~~~~b", ["a", "b"], "~~~~~");
160 test_join!("~~~~~a~~~~~bc", ["", "a", "bc"], "~~~~~");
161 }
162
163 #[test]
164 fn test_join_isue_80335() {
165 use core::{borrow::Borrow, cell::Cell};
166
167 struct WeirdBorrow {
168 state: Cell<bool>,
169 }
170
171 impl Default for WeirdBorrow {
172 fn default() -> Self {
173 WeirdBorrow { state: Cell::new(false) }
174 }
175 }
176
177 impl Borrow<str> for WeirdBorrow {
178 fn borrow(&self) -> &str {
179 let state = self.state.get();
180 if state {
181 "0"
182 } else {
183 self.state.set(true);
184 "123456"
185 }
186 }
187 }
188
189 let arr: [WeirdBorrow; 3] = Default::default();
190 test_join!("0-0-0", arr, "-");
191 }
192
193 #[test]
194 #[cfg_attr(miri, ignore)] // Miri is too slow
195 fn test_unsafe_slice() {
196 assert_eq!("ab", unsafe { "abc".get_unchecked(0..2) });
197 assert_eq!("bc", unsafe { "abc".get_unchecked(1..3) });
198 assert_eq!("", unsafe { "abc".get_unchecked(1..1) });
199 fn a_million_letter_a() -> String {
200 let mut i = 0;
201 let mut rs = String::new();
202 while i < 100000 {
203 rs.push_str("aaaaaaaaaa");
204 i += 1;
205 }
206 rs
207 }
208 fn half_a_million_letter_a() -> String {
209 let mut i = 0;
210 let mut rs = String::new();
211 while i < 100000 {
212 rs.push_str("aaaaa");
213 i += 1;
214 }
215 rs
216 }
217 let letters = a_million_letter_a();
218 assert_eq!(half_a_million_letter_a(), unsafe { letters.get_unchecked(0..500000) });
219 }
220
221 #[test]
222 fn test_starts_with() {
223 assert!("".starts_with(""));
224 assert!("abc".starts_with(""));
225 assert!("abc".starts_with("a"));
226 assert!(!"a".starts_with("abc"));
227 assert!(!"".starts_with("abc"));
228 assert!(!"ödd".starts_with("-"));
229 assert!("ödd".starts_with("öd"));
230 }
231
232 #[test]
233 fn test_ends_with() {
234 assert!("".ends_with(""));
235 assert!("abc".ends_with(""));
236 assert!("abc".ends_with("c"));
237 assert!(!"a".ends_with("abc"));
238 assert!(!"".ends_with("abc"));
239 assert!(!"ddö".ends_with("-"));
240 assert!("ddö".ends_with("dö"));
241 }
242
243 #[test]
244 fn test_is_empty() {
245 assert!("".is_empty());
246 assert!(!"a".is_empty());
247 }
248
249 #[test]
250 fn test_replacen() {
251 assert_eq!("".replacen('a', "b", 5), "");
252 assert_eq!("acaaa".replacen("a", "b", 3), "bcbba");
253 assert_eq!("aaaa".replacen("a", "b", 0), "aaaa");
254
255 let test = "test";
256 assert_eq!(" test test ".replacen(test, "toast", 3), " toast toast ");
257 assert_eq!(" test test ".replacen(test, "toast", 0), " test test ");
258 assert_eq!(" test test ".replacen(test, "", 5), " ");
259
260 assert_eq!("qwer123zxc789".replacen(char::is_numeric, "", 3), "qwerzxc789");
261 }
262
263 #[test]
264 fn test_replace() {
265 let a = "a";
266 assert_eq!("".replace(a, "b"), "");
267 assert_eq!("a".replace(a, "b"), "b");
268 assert_eq!("ab".replace(a, "b"), "bb");
269 let test = "test";
270 assert_eq!(" test test ".replace(test, "toast"), " toast toast ");
271 assert_eq!(" test test ".replace(test, ""), " ");
272 }
273
274 #[test]
275 fn test_replace_2a() {
276 let data = "ประเทศไทย中华";
277 let repl = "دولة الكويت";
278
279 let a = "ประเ";
280 let a2 = "دولة الكويتทศไทย中华";
281 assert_eq!(data.replace(a, repl), a2);
282 }
283
284 #[test]
285 fn test_replace_2b() {
286 let data = "ประเทศไทย中华";
287 let repl = "دولة الكويت";
288
289 let b = "ะเ";
290 let b2 = "ปรدولة الكويتทศไทย中华";
291 assert_eq!(data.replace(b, repl), b2);
292 }
293
294 #[test]
295 fn test_replace_2c() {
296 let data = "ประเทศไทย中华";
297 let repl = "دولة الكويت";
298
299 let c = "中华";
300 let c2 = "ประเทศไทยدولة الكويت";
301 assert_eq!(data.replace(c, repl), c2);
302 }
303
304 #[test]
305 fn test_replace_2d() {
306 let data = "ประเทศไทย中华";
307 let repl = "دولة الكويت";
308
309 let d = "ไท华";
310 assert_eq!(data.replace(d, repl), data);
311 }
312
313 #[test]
314 fn test_replace_pattern() {
315 let data = "abcdαβγδabcdαβγδ";
316 assert_eq!(data.replace("dαβ", "😺😺😺"), "abc😺😺😺γδabc😺😺😺γδ");
317 assert_eq!(data.replace('γ', "😺😺😺"), "abcdαβ😺😺😺δabcdαβ😺😺😺δ");
318 assert_eq!(data.replace(&['a', 'γ'] as &[_], "😺😺😺"), "😺😺😺bcdαβ😺😺😺δ😺😺😺bcdαβ😺😺😺δ");
319 assert_eq!(data.replace(|c| c == 'γ', "😺😺😺"), "abcdαβ😺😺😺δabcdαβ😺😺😺δ");
320 }
321
322 // The current implementation of SliceIndex fails to handle methods
323 // orthogonally from range types; therefore, it is worth testing
324 // all of the indexing operations on each input.
325 mod slice_index {
326 // Test a slicing operation **that should succeed,**
327 // testing it on all of the indexing methods.
328 //
329 // This is not suitable for testing failure on invalid inputs.
330 macro_rules! assert_range_eq {
331 ($s:expr, $range:expr, $expected:expr) => {
332 let mut s: String = $s.to_owned();
333 let mut expected: String = $expected.to_owned();
334 {
335 let s: &str = &s;
336 let expected: &str = &expected;
337
338 assert_eq!(&s[$range], expected, "(in assertion for: index)");
339 assert_eq!(s.get($range), Some(expected), "(in assertion for: get)");
340 unsafe {
341 assert_eq!(
342 s.get_unchecked($range),
343 expected,
344 "(in assertion for: get_unchecked)",
345 );
346 }
347 }
348 {
349 let s: &mut str = &mut s;
350 let expected: &mut str = &mut expected;
351
352 assert_eq!(&mut s[$range], expected, "(in assertion for: index_mut)",);
353 assert_eq!(
354 s.get_mut($range),
355 Some(&mut expected[..]),
356 "(in assertion for: get_mut)",
357 );
358 unsafe {
359 assert_eq!(
360 s.get_unchecked_mut($range),
361 expected,
362 "(in assertion for: get_unchecked_mut)",
363 );
364 }
365 }
366 };
367 }
368
369 // Make sure the macro can actually detect bugs,
370 // because if it can't, then what are we even doing here?
371 //
372 // (Be aware this only demonstrates the ability to detect bugs
373 // in the FIRST method that panics, as the macro is not designed
374 // to be used in `should_panic`)
375 #[test]
376 #[should_panic(expected = "out of bounds")]
377 fn assert_range_eq_can_fail_by_panic() {
378 assert_range_eq!("abc", 0..5, "abc");
379 }
380
381 // (Be aware this only demonstrates the ability to detect bugs
382 // in the FIRST method it calls, as the macro is not designed
383 // to be used in `should_panic`)
384 #[test]
385 #[should_panic(expected = "==")]
386 fn assert_range_eq_can_fail_by_inequality() {
387 assert_range_eq!("abc", 0..2, "abc");
388 }
389
390 // Generates test cases for bad index operations.
391 //
392 // This generates `should_panic` test cases for Index/IndexMut
393 // and `None` test cases for get/get_mut.
394 macro_rules! panic_cases {
395 ($(
396 in mod $case_name:ident {
397 data: $data:expr;
398
399 // optional:
400 //
401 // a similar input for which DATA[input] succeeds, and the corresponding
402 // output str. This helps validate "critical points" where an input range
403 // straddles the boundary between valid and invalid.
404 // (such as the input `len..len`, which is just barely valid)
405 $(
406 good: data[$good:expr] == $output:expr;
407 )*
408
409 bad: data[$bad:expr];
410 message: $expect_msg:expr; // must be a literal
411 }
412 )*) => {$(
413 mod $case_name {
414 #[test]
415 fn pass() {
416 let mut v: String = $data.into();
417
418 $( assert_range_eq!(v, $good, $output); )*
419
420 {
421 let v: &str = &v;
422 assert_eq!(v.get($bad), None, "(in None assertion for get)");
423 }
424
425 {
426 let v: &mut str = &mut v;
427 assert_eq!(v.get_mut($bad), None, "(in None assertion for get_mut)");
428 }
429 }
430
431 #[test]
432 #[should_panic(expected = $expect_msg)]
433 fn index_fail() {
434 let v: String = $data.into();
435 let v: &str = &v;
436 let _v = &v[$bad];
437 }
438
439 #[test]
440 #[should_panic(expected = $expect_msg)]
441 fn index_mut_fail() {
442 let mut v: String = $data.into();
443 let v: &mut str = &mut v;
444 let _v = &mut v[$bad];
445 }
446 }
447 )*};
448 }
449
450 #[test]
451 fn simple_ascii() {
452 assert_range_eq!("abc", .., "abc");
453
454 assert_range_eq!("abc", 0..2, "ab");
455 assert_range_eq!("abc", 0..=1, "ab");
456 assert_range_eq!("abc", ..2, "ab");
457 assert_range_eq!("abc", ..=1, "ab");
458
459 assert_range_eq!("abc", 1..3, "bc");
460 assert_range_eq!("abc", 1..=2, "bc");
461 assert_range_eq!("abc", 1..1, "");
462 assert_range_eq!("abc", 1..=0, "");
463 }
464
465 #[test]
466 fn simple_unicode() {
467 // 日本
468 assert_range_eq!("\u{65e5}\u{672c}", .., "\u{65e5}\u{672c}");
469
470 assert_range_eq!("\u{65e5}\u{672c}", 0..3, "\u{65e5}");
471 assert_range_eq!("\u{65e5}\u{672c}", 0..=2, "\u{65e5}");
472 assert_range_eq!("\u{65e5}\u{672c}", ..3, "\u{65e5}");
473 assert_range_eq!("\u{65e5}\u{672c}", ..=2, "\u{65e5}");
474
475 assert_range_eq!("\u{65e5}\u{672c}", 3..6, "\u{672c}");
476 assert_range_eq!("\u{65e5}\u{672c}", 3..=5, "\u{672c}");
477 assert_range_eq!("\u{65e5}\u{672c}", 3.., "\u{672c}");
478
479 let data = "ประเทศไทย中华";
480 assert_range_eq!(data, 0..3, "ป");
481 assert_range_eq!(data, 3..6, "ร");
482 assert_range_eq!(data, 3..3, "");
483 assert_range_eq!(data, 30..33, "华");
484
485 /*0: 中
486 3: 华
487 6: V
488 7: i
489 8: ệ
490 11: t
491 12:
492 13: N
493 14: a
494 15: m */
495 let ss = "中华Việt Nam";
496 assert_range_eq!(ss, 3..6, "华");
497 assert_range_eq!(ss, 6..16, "Việt Nam");
498 assert_range_eq!(ss, 6..=15, "Việt Nam");
499 assert_range_eq!(ss, 6.., "Việt Nam");
500
501 assert_range_eq!(ss, 0..3, "中");
502 assert_range_eq!(ss, 3..7, "华V");
503 assert_range_eq!(ss, 3..=6, "华V");
504 assert_range_eq!(ss, 3..3, "");
505 assert_range_eq!(ss, 3..=2, "");
506 }
507
508 #[test]
509 #[cfg_attr(target_os = "emscripten", ignore)] // hits an OOM
510 #[cfg_attr(miri, ignore)] // Miri is too slow
511 fn simple_big() {
512 fn a_million_letter_x() -> String {
513 let mut i = 0;
514 let mut rs = String::new();
515 while i < 100000 {
516 rs.push_str("华华华华华华华华华华");
517 i += 1;
518 }
519 rs
520 }
521 fn half_a_million_letter_x() -> String {
522 let mut i = 0;
523 let mut rs = String::new();
524 while i < 100000 {
525 rs.push_str("华华华华华");
526 i += 1;
527 }
528 rs
529 }
530 let letters = a_million_letter_x();
531 assert_range_eq!(letters, 0..3 * 500000, half_a_million_letter_x());
532 }
533
534 #[test]
535 #[should_panic]
536 fn test_slice_fail() {
537 &"中华Việt Nam"[0..2];
538 }
539
540 panic_cases! {
541 in mod rangefrom_len {
542 data: "abcdef";
543 good: data[6..] == "";
544 bad: data[7..];
545 message: "out of bounds";
546 }
547
548 in mod rangeto_len {
549 data: "abcdef";
550 good: data[..6] == "abcdef";
551 bad: data[..7];
552 message: "out of bounds";
553 }
554
555 in mod rangetoinclusive_len {
556 data: "abcdef";
557 good: data[..=5] == "abcdef";
558 bad: data[..=6];
559 message: "out of bounds";
560 }
561
562 in mod rangeinclusive_len {
563 data: "abcdef";
564 good: data[0..=5] == "abcdef";
565 bad: data[0..=6];
566 message: "out of bounds";
567 }
568
569 in mod range_len_len {
570 data: "abcdef";
571 good: data[6..6] == "";
572 bad: data[7..7];
573 message: "out of bounds";
574 }
575
576 in mod rangeinclusive_len_len {
577 data: "abcdef";
578 good: data[6..=5] == "";
579 bad: data[7..=6];
580 message: "out of bounds";
581 }
582 }
583
584 panic_cases! {
585 in mod rangeinclusive_exhausted {
586 data: "abcdef";
587
588 good: data[0..=5] == "abcdef";
589 good: data[{
590 let mut iter = 0..=5;
591 iter.by_ref().count(); // exhaust it
592 iter
593 }] == "";
594
595 // 0..=6 is out of bounds before exhaustion, so it
596 // stands to reason that it still would be after.
597 bad: data[{
598 let mut iter = 0..=6;
599 iter.by_ref().count(); // exhaust it
600 iter
601 }];
602 message: "out of bounds";
603 }
604 }
605
606 panic_cases! {
607 in mod range_neg_width {
608 data: "abcdef";
609 good: data[4..4] == "";
610 bad: data[4..3];
611 message: "begin <= end (4 <= 3)";
612 }
613
614 in mod rangeinclusive_neg_width {
615 data: "abcdef";
616 good: data[4..=3] == "";
617 bad: data[4..=2];
618 message: "begin <= end (4 <= 3)";
619 }
620 }
621
622 mod overflow {
623 panic_cases! {
624 in mod rangeinclusive {
625 data: "hello";
626 // note: using 0 specifically ensures that the result of overflowing is 0..0,
627 // so that `get` doesn't simply return None for the wrong reason.
628 bad: data[0..=usize::MAX];
629 message: "maximum usize";
630 }
631
632 in mod rangetoinclusive {
633 data: "hello";
634 bad: data[..=usize::MAX];
635 message: "maximum usize";
636 }
637 }
638 }
639
640 mod boundary {
641 const DATA: &str = "abcαβγ";
642
643 const BAD_START: usize = 4;
644 const GOOD_START: usize = 3;
645 const BAD_END: usize = 6;
646 const GOOD_END: usize = 7;
647 const BAD_END_INCL: usize = BAD_END - 1;
648 const GOOD_END_INCL: usize = GOOD_END - 1;
649
650 // it is especially important to test all of the different range types here
651 // because some of the logic may be duplicated as part of micro-optimizations
652 // to dodge unicode boundary checks on half-ranges.
653 panic_cases! {
654 in mod range_1 {
655 data: super::DATA;
656 bad: data[super::BAD_START..super::GOOD_END];
657 message:
658 "byte index 4 is not a char boundary; it is inside 'α' (bytes 3..5) of";
659 }
660
661 in mod range_2 {
662 data: super::DATA;
663 bad: data[super::GOOD_START..super::BAD_END];
664 message:
665 "byte index 6 is not a char boundary; it is inside 'β' (bytes 5..7) of";
666 }
667
668 in mod rangefrom {
669 data: super::DATA;
670 bad: data[super::BAD_START..];
671 message:
672 "byte index 4 is not a char boundary; it is inside 'α' (bytes 3..5) of";
673 }
674
675 in mod rangeto {
676 data: super::DATA;
677 bad: data[..super::BAD_END];
678 message:
679 "byte index 6 is not a char boundary; it is inside 'β' (bytes 5..7) of";
680 }
681
682 in mod rangeinclusive_1 {
683 data: super::DATA;
684 bad: data[super::BAD_START..=super::GOOD_END_INCL];
685 message:
686 "byte index 4 is not a char boundary; it is inside 'α' (bytes 3..5) of";
687 }
688
689 in mod rangeinclusive_2 {
690 data: super::DATA;
691 bad: data[super::GOOD_START..=super::BAD_END_INCL];
692 message:
693 "byte index 6 is not a char boundary; it is inside 'β' (bytes 5..7) of";
694 }
695
696 in mod rangetoinclusive {
697 data: super::DATA;
698 bad: data[..=super::BAD_END_INCL];
699 message:
700 "byte index 6 is not a char boundary; it is inside 'β' (bytes 5..7) of";
701 }
702 }
703 }
704
705 const LOREM_PARAGRAPH: &str = "\
706 Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse quis lorem \
707 sit amet dolor ultricies condimentum. Praesent iaculis purus elit, ac malesuada \
708 quam malesuada in. Duis sed orci eros. Suspendisse sit amet magna mollis, mollis \
709 nunc luctus, imperdiet mi. Integer fringilla non sem ut lacinia. Fusce varius \
710 tortor a risus porttitor hendrerit. Morbi mauris dui, ultricies nec tempus vel, \
711 gravida nec quam.";
712
713 // check the panic includes the prefix of the sliced string
714 #[test]
715 #[should_panic(expected = "byte index 1024 is out of bounds of `Lorem ipsum dolor sit amet")]
716 fn test_slice_fail_truncated_1() {
717 &LOREM_PARAGRAPH[..1024];
718 }
719 // check the truncation in the panic message
720 #[test]
721 #[should_panic(expected = "luctus, im`[...]")]
722 fn test_slice_fail_truncated_2() {
723 &LOREM_PARAGRAPH[..1024];
724 }
725 }
726
727 #[test]
728 fn test_str_slice_rangetoinclusive_ok() {
729 let s = "abcαβγ";
730 assert_eq!(&s[..=2], "abc");
731 assert_eq!(&s[..=4], "abcα");
732 }
733
734 #[test]
735 #[should_panic]
736 fn test_str_slice_rangetoinclusive_notok() {
737 let s = "abcαβγ";
738 &s[..=3];
739 }
740
741 #[test]
742 fn test_str_slicemut_rangetoinclusive_ok() {
743 let mut s = "abcαβγ".to_owned();
744 let s: &mut str = &mut s;
745 assert_eq!(&mut s[..=2], "abc");
746 assert_eq!(&mut s[..=4], "abcα");
747 }
748
749 #[test]
750 #[should_panic]
751 fn test_str_slicemut_rangetoinclusive_notok() {
752 let mut s = "abcαβγ".to_owned();
753 let s: &mut str = &mut s;
754 &mut s[..=3];
755 }
756
757 #[test]
758 fn test_is_char_boundary() {
759 let s = "ศไทย中华Việt Nam β-release 🐱123";
760 assert!(s.is_char_boundary(0));
761 assert!(s.is_char_boundary(s.len()));
762 assert!(!s.is_char_boundary(s.len() + 1));
763 for (i, ch) in s.char_indices() {
764 // ensure character locations are boundaries and continuation bytes are not
765 assert!(s.is_char_boundary(i), "{} is a char boundary in {:?}", i, s);
766 for j in 1..ch.len_utf8() {
767 assert!(
768 !s.is_char_boundary(i + j),
769 "{} should not be a char boundary in {:?}",
770 i + j,
771 s
772 );
773 }
774 }
775 }
776
777 #[test]
778 fn test_trim_start_matches() {
779 let v: &[char] = &[];
780 assert_eq!(" *** foo *** ".trim_start_matches(v), " *** foo *** ");
781 let chars: &[char] = &['*', ' '];
782 assert_eq!(" *** foo *** ".trim_start_matches(chars), "foo *** ");
783 assert_eq!(" *** *** ".trim_start_matches(chars), "");
784 assert_eq!("foo *** ".trim_start_matches(chars), "foo *** ");
785
786 assert_eq!("11foo1bar11".trim_start_matches('1'), "foo1bar11");
787 let chars: &[char] = &['1', '2'];
788 assert_eq!("12foo1bar12".trim_start_matches(chars), "foo1bar12");
789 assert_eq!("123foo1bar123".trim_start_matches(|c: char| c.is_numeric()), "foo1bar123");
790 }
791
792 #[test]
793 fn test_trim_end_matches() {
794 let v: &[char] = &[];
795 assert_eq!(" *** foo *** ".trim_end_matches(v), " *** foo *** ");
796 let chars: &[char] = &['*', ' '];
797 assert_eq!(" *** foo *** ".trim_end_matches(chars), " *** foo");
798 assert_eq!(" *** *** ".trim_end_matches(chars), "");
799 assert_eq!(" *** foo".trim_end_matches(chars), " *** foo");
800
801 assert_eq!("11foo1bar11".trim_end_matches('1'), "11foo1bar");
802 let chars: &[char] = &['1', '2'];
803 assert_eq!("12foo1bar12".trim_end_matches(chars), "12foo1bar");
804 assert_eq!("123foo1bar123".trim_end_matches(|c: char| c.is_numeric()), "123foo1bar");
805 }
806
807 #[test]
808 fn test_trim_matches() {
809 let v: &[char] = &[];
810 assert_eq!(" *** foo *** ".trim_matches(v), " *** foo *** ");
811 let chars: &[char] = &['*', ' '];
812 assert_eq!(" *** foo *** ".trim_matches(chars), "foo");
813 assert_eq!(" *** *** ".trim_matches(chars), "");
814 assert_eq!("foo".trim_matches(chars), "foo");
815
816 assert_eq!("11foo1bar11".trim_matches('1'), "foo1bar");
817 let chars: &[char] = &['1', '2'];
818 assert_eq!("12foo1bar12".trim_matches(chars), "foo1bar");
819 assert_eq!("123foo1bar123".trim_matches(|c: char| c.is_numeric()), "foo1bar");
820 }
821
822 #[test]
823 fn test_trim_start() {
824 assert_eq!("".trim_start(), "");
825 assert_eq!("a".trim_start(), "a");
826 assert_eq!(" ".trim_start(), "");
827 assert_eq!(" blah".trim_start(), "blah");
828 assert_eq!(" \u{3000} wut".trim_start(), "wut");
829 assert_eq!("hey ".trim_start(), "hey ");
830 }
831
832 #[test]
833 fn test_trim_end() {
834 assert_eq!("".trim_end(), "");
835 assert_eq!("a".trim_end(), "a");
836 assert_eq!(" ".trim_end(), "");
837 assert_eq!("blah ".trim_end(), "blah");
838 assert_eq!("wut \u{3000} ".trim_end(), "wut");
839 assert_eq!(" hey".trim_end(), " hey");
840 }
841
842 #[test]
843 fn test_trim() {
844 assert_eq!("".trim(), "");
845 assert_eq!("a".trim(), "a");
846 assert_eq!(" ".trim(), "");
847 assert_eq!(" blah ".trim(), "blah");
848 assert_eq!("\nwut \u{3000} ".trim(), "wut");
849 assert_eq!(" hey dude ".trim(), "hey dude");
850 }
851
852 #[test]
853 fn test_is_whitespace() {
854 assert!("".chars().all(|c| c.is_whitespace()));
855 assert!(" ".chars().all(|c| c.is_whitespace()));
856 assert!("\u{2009}".chars().all(|c| c.is_whitespace())); // Thin space
857 assert!(" \n\t ".chars().all(|c| c.is_whitespace()));
858 assert!(!" _ ".chars().all(|c| c.is_whitespace()));
859 }
860
861 #[test]
862 fn test_is_utf8() {
863 // deny overlong encodings
864 assert!(from_utf8(&[0xc0, 0x80]).is_err());
865 assert!(from_utf8(&[0xc0, 0xae]).is_err());
866 assert!(from_utf8(&[0xe0, 0x80, 0x80]).is_err());
867 assert!(from_utf8(&[0xe0, 0x80, 0xaf]).is_err());
868 assert!(from_utf8(&[0xe0, 0x81, 0x81]).is_err());
869 assert!(from_utf8(&[0xf0, 0x82, 0x82, 0xac]).is_err());
870 assert!(from_utf8(&[0xf4, 0x90, 0x80, 0x80]).is_err());
871
872 // deny surrogates
873 assert!(from_utf8(&[0xED, 0xA0, 0x80]).is_err());
874 assert!(from_utf8(&[0xED, 0xBF, 0xBF]).is_err());
875
876 assert!(from_utf8(&[0xC2, 0x80]).is_ok());
877 assert!(from_utf8(&[0xDF, 0xBF]).is_ok());
878 assert!(from_utf8(&[0xE0, 0xA0, 0x80]).is_ok());
879 assert!(from_utf8(&[0xED, 0x9F, 0xBF]).is_ok());
880 assert!(from_utf8(&[0xEE, 0x80, 0x80]).is_ok());
881 assert!(from_utf8(&[0xEF, 0xBF, 0xBF]).is_ok());
882 assert!(from_utf8(&[0xF0, 0x90, 0x80, 0x80]).is_ok());
883 assert!(from_utf8(&[0xF4, 0x8F, 0xBF, 0xBF]).is_ok());
884 }
885
886 #[test]
887 fn from_utf8_mostly_ascii() {
888 // deny invalid bytes embedded in long stretches of ascii
889 for i in 32..64 {
890 let mut data = [0; 128];
891 data[i] = 0xC0;
892 assert!(from_utf8(&data).is_err());
893 data[i] = 0xC2;
894 assert!(from_utf8(&data).is_err());
895 }
896 }
897
898 #[test]
899 fn from_utf8_error() {
900 macro_rules! test {
901 ($input: expr, $expected_valid_up_to: expr, $expected_error_len: expr) => {
902 let error = from_utf8($input).unwrap_err();
903 assert_eq!(error.valid_up_to(), $expected_valid_up_to);
904 assert_eq!(error.error_len(), $expected_error_len);
905 };
906 }
907 test!(b"A\xC3\xA9 \xFF ", 4, Some(1));
908 test!(b"A\xC3\xA9 \x80 ", 4, Some(1));
909 test!(b"A\xC3\xA9 \xC1 ", 4, Some(1));
910 test!(b"A\xC3\xA9 \xC1", 4, Some(1));
911 test!(b"A\xC3\xA9 \xC2", 4, None);
912 test!(b"A\xC3\xA9 \xC2 ", 4, Some(1));
913 test!(b"A\xC3\xA9 \xC2\xC0", 4, Some(1));
914 test!(b"A\xC3\xA9 \xE0", 4, None);
915 test!(b"A\xC3\xA9 \xE0\x9F", 4, Some(1));
916 test!(b"A\xC3\xA9 \xE0\xA0", 4, None);
917 test!(b"A\xC3\xA9 \xE0\xA0\xC0", 4, Some(2));
918 test!(b"A\xC3\xA9 \xE0\xA0 ", 4, Some(2));
919 test!(b"A\xC3\xA9 \xED\xA0\x80 ", 4, Some(1));
920 test!(b"A\xC3\xA9 \xF1", 4, None);
921 test!(b"A\xC3\xA9 \xF1\x80", 4, None);
922 test!(b"A\xC3\xA9 \xF1\x80\x80", 4, None);
923 test!(b"A\xC3\xA9 \xF1 ", 4, Some(1));
924 test!(b"A\xC3\xA9 \xF1\x80 ", 4, Some(2));
925 test!(b"A\xC3\xA9 \xF1\x80\x80 ", 4, Some(3));
926 }
927
928 #[test]
929 fn test_as_bytes() {
930 // no null
931 let v = [
932 224, 184, 168, 224, 185, 132, 224, 184, 151, 224, 184, 162, 228, 184, 173, 229, 141, 142,
933 86, 105, 225, 187, 135, 116, 32, 78, 97, 109,
934 ];
935 let b: &[u8] = &[];
936 assert_eq!("".as_bytes(), b);
937 assert_eq!("abc".as_bytes(), b"abc");
938 assert_eq!("ศไทย中华Việt Nam".as_bytes(), v);
939 }
940
941 #[test]
942 #[should_panic]
943 fn test_as_bytes_fail() {
944 // Don't double free. (I'm not sure if this exercises the
945 // original problem code path anymore.)
946 let s = String::from("");
947 let _bytes = s.as_bytes();
948 panic!();
949 }
950
951 #[test]
952 fn test_as_ptr() {
953 let buf = "hello".as_ptr();
954 unsafe {
955 assert_eq!(*buf.offset(0), b'h');
956 assert_eq!(*buf.offset(1), b'e');
957 assert_eq!(*buf.offset(2), b'l');
958 assert_eq!(*buf.offset(3), b'l');
959 assert_eq!(*buf.offset(4), b'o');
960 }
961 }
962
963 #[test]
964 fn vec_str_conversions() {
965 let s1: String = String::from("All mimsy were the borogoves");
966
967 let v: Vec<u8> = s1.as_bytes().to_vec();
968 let s2: String = String::from(from_utf8(&v).unwrap());
969 let mut i = 0;
970 let n1 = s1.len();
971 let n2 = v.len();
972 assert_eq!(n1, n2);
973 while i < n1 {
974 let a: u8 = s1.as_bytes()[i];
975 let b: u8 = s2.as_bytes()[i];
976 assert_eq!(a, b);
977 i += 1;
978 }
979 }
980
981 #[test]
982 fn test_contains() {
983 assert!("abcde".contains("bcd"));
984 assert!("abcde".contains("abcd"));
985 assert!("abcde".contains("bcde"));
986 assert!("abcde".contains(""));
987 assert!("".contains(""));
988 assert!(!"abcde".contains("def"));
989 assert!(!"".contains("a"));
990
991 let data = "ประเทศไทย中华Việt Nam";
992 assert!(data.contains("ประเ"));
993 assert!(data.contains("ะเ"));
994 assert!(data.contains("中华"));
995 assert!(!data.contains("ไท华"));
996 }
997
998 #[test]
999 fn test_contains_char() {
1000 assert!("abc".contains('b'));
1001 assert!("a".contains('a'));
1002 assert!(!"abc".contains('d'));
1003 assert!(!"".contains('a'));
1004 }
1005
1006 #[test]
1007 fn test_split_at() {
1008 let s = "ศไทย中华Việt Nam";
1009 for (index, _) in s.char_indices() {
1010 let (a, b) = s.split_at(index);
1011 assert_eq!(&s[..a.len()], a);
1012 assert_eq!(&s[a.len()..], b);
1013 }
1014 let (a, b) = s.split_at(s.len());
1015 assert_eq!(a, s);
1016 assert_eq!(b, "");
1017 }
1018
1019 #[test]
1020 fn test_split_at_mut() {
1021 let mut s = "Hello World".to_string();
1022 {
1023 let (a, b) = s.split_at_mut(5);
1024 a.make_ascii_uppercase();
1025 b.make_ascii_lowercase();
1026 }
1027 assert_eq!(s, "HELLO world");
1028 }
1029
1030 #[test]
1031 #[should_panic]
1032 fn test_split_at_boundscheck() {
1033 let s = "ศไทย中华Việt Nam";
1034 s.split_at(1);
1035 }
1036
1037 #[test]
1038 fn test_escape_unicode() {
1039 assert_eq!("abc".escape_unicode().to_string(), "\\u{61}\\u{62}\\u{63}");
1040 assert_eq!("a c".escape_unicode().to_string(), "\\u{61}\\u{20}\\u{63}");
1041 assert_eq!("\r\n\t".escape_unicode().to_string(), "\\u{d}\\u{a}\\u{9}");
1042 assert_eq!("'\"\\".escape_unicode().to_string(), "\\u{27}\\u{22}\\u{5c}");
1043 assert_eq!("\x00\x01\u{fe}\u{ff}".escape_unicode().to_string(), "\\u{0}\\u{1}\\u{fe}\\u{ff}");
1044 assert_eq!("\u{100}\u{ffff}".escape_unicode().to_string(), "\\u{100}\\u{ffff}");
1045 assert_eq!("\u{10000}\u{10ffff}".escape_unicode().to_string(), "\\u{10000}\\u{10ffff}");
1046 assert_eq!("ab\u{fb00}".escape_unicode().to_string(), "\\u{61}\\u{62}\\u{fb00}");
1047 assert_eq!("\u{1d4ea}\r".escape_unicode().to_string(), "\\u{1d4ea}\\u{d}");
1048 }
1049
1050 #[test]
1051 fn test_escape_debug() {
1052 // Note that there are subtleties with the number of backslashes
1053 // on the left- and right-hand sides. In particular, Unicode code points
1054 // are usually escaped with two backslashes on the right-hand side, as
1055 // they are escaped. However, when the character is unescaped (e.g., for
1056 // printable characters), only a single backslash appears (as the character
1057 // itself appears in the debug string).
1058 assert_eq!("abc".escape_debug().to_string(), "abc");
1059 assert_eq!("a c".escape_debug().to_string(), "a c");
1060 assert_eq!("éèê".escape_debug().to_string(), "éèê");
1061 assert_eq!("\r\n\t".escape_debug().to_string(), "\\r\\n\\t");
1062 assert_eq!("'\"\\".escape_debug().to_string(), "\\'\\\"\\\\");
1063 assert_eq!("\u{7f}\u{ff}".escape_debug().to_string(), "\\u{7f}\u{ff}");
1064 assert_eq!("\u{100}\u{ffff}".escape_debug().to_string(), "\u{100}\\u{ffff}");
1065 assert_eq!("\u{10000}\u{10ffff}".escape_debug().to_string(), "\u{10000}\\u{10ffff}");
1066 assert_eq!("ab\u{200b}".escape_debug().to_string(), "ab\\u{200b}");
1067 assert_eq!("\u{10d4ea}\r".escape_debug().to_string(), "\\u{10d4ea}\\r");
1068 assert_eq!(
1069 "\u{301}a\u{301}\u{e000}".escape_debug().to_string(),
1070 "\\u{301}a\u{301}\\u{e000}"
1071 );
1072 }
1073
1074 #[test]
1075 fn test_escape_default() {
1076 assert_eq!("abc".escape_default().to_string(), "abc");
1077 assert_eq!("a c".escape_default().to_string(), "a c");
1078 assert_eq!("éèê".escape_default().to_string(), "\\u{e9}\\u{e8}\\u{ea}");
1079 assert_eq!("\r\n\t".escape_default().to_string(), "\\r\\n\\t");
1080 assert_eq!("'\"\\".escape_default().to_string(), "\\'\\\"\\\\");
1081 assert_eq!("\u{7f}\u{ff}".escape_default().to_string(), "\\u{7f}\\u{ff}");
1082 assert_eq!("\u{100}\u{ffff}".escape_default().to_string(), "\\u{100}\\u{ffff}");
1083 assert_eq!("\u{10000}\u{10ffff}".escape_default().to_string(), "\\u{10000}\\u{10ffff}");
1084 assert_eq!("ab\u{200b}".escape_default().to_string(), "ab\\u{200b}");
1085 assert_eq!("\u{10d4ea}\r".escape_default().to_string(), "\\u{10d4ea}\\r");
1086 }
1087
1088 #[test]
1089 fn test_total_ord() {
1090 assert_eq!("1234".cmp("123"), Greater);
1091 assert_eq!("123".cmp("1234"), Less);
1092 assert_eq!("1234".cmp("1234"), Equal);
1093 assert_eq!("12345555".cmp("123456"), Less);
1094 assert_eq!("22".cmp("1234"), Greater);
1095 }
1096
1097 #[test]
1098 fn test_iterator() {
1099 let s = "ศไทย中华Việt Nam";
1100 let v = ['ศ', 'ไ', 'ท', 'ย', '中', '华', 'V', 'i', 'ệ', 't', ' ', 'N', 'a', 'm'];
1101
1102 let mut pos = 0;
1103 let it = s.chars();
1104
1105 for c in it {
1106 assert_eq!(c, v[pos]);
1107 pos += 1;
1108 }
1109 assert_eq!(pos, v.len());
1110 assert_eq!(s.chars().count(), v.len());
1111 }
1112
1113 #[test]
1114 fn test_rev_iterator() {
1115 let s = "ศไทย中华Việt Nam";
1116 let v = ['m', 'a', 'N', ' ', 't', 'ệ', 'i', 'V', '华', '中', 'ย', 'ท', 'ไ', 'ศ'];
1117
1118 let mut pos = 0;
1119 let it = s.chars().rev();
1120
1121 for c in it {
1122 assert_eq!(c, v[pos]);
1123 pos += 1;
1124 }
1125 assert_eq!(pos, v.len());
1126 }
1127
1128 #[test]
1129 #[cfg_attr(miri, ignore)] // Miri is too slow
1130 fn test_chars_decoding() {
1131 let mut bytes = [0; 4];
1132 for c in (0..0x110000).filter_map(std::char::from_u32) {
1133 let s = c.encode_utf8(&mut bytes);
1134 if Some(c) != s.chars().next() {
1135 panic!("character {:x}={} does not decode correctly", c as u32, c);
1136 }
1137 }
1138 }
1139
1140 #[test]
1141 #[cfg_attr(miri, ignore)] // Miri is too slow
1142 fn test_chars_rev_decoding() {
1143 let mut bytes = [0; 4];
1144 for c in (0..0x110000).filter_map(std::char::from_u32) {
1145 let s = c.encode_utf8(&mut bytes);
1146 if Some(c) != s.chars().rev().next() {
1147 panic!("character {:x}={} does not decode correctly", c as u32, c);
1148 }
1149 }
1150 }
1151
1152 #[test]
1153 fn test_iterator_clone() {
1154 let s = "ศไทย中华Việt Nam";
1155 let mut it = s.chars();
1156 it.next();
1157 assert!(it.clone().zip(it).all(|(x, y)| x == y));
1158 }
1159
1160 #[test]
1161 fn test_iterator_last() {
1162 let s = "ศไทย中华Việt Nam";
1163 let mut it = s.chars();
1164 it.next();
1165 assert_eq!(it.last(), Some('m'));
1166 }
1167
1168 #[test]
1169 fn test_chars_debug() {
1170 let s = "ศไทย中华Việt Nam";
1171 let c = s.chars();
1172 assert_eq!(
1173 format!("{:?}", c),
1174 r#"Chars(['ศ', 'ไ', 'ท', 'ย', '中', '华', 'V', 'i', 'ệ', 't', ' ', 'N', 'a', 'm'])"#
1175 );
1176 }
1177
1178 #[test]
1179 fn test_bytesator() {
1180 let s = "ศไทย中华Việt Nam";
1181 let v = [
1182 224, 184, 168, 224, 185, 132, 224, 184, 151, 224, 184, 162, 228, 184, 173, 229, 141, 142,
1183 86, 105, 225, 187, 135, 116, 32, 78, 97, 109,
1184 ];
1185 let mut pos = 0;
1186
1187 for b in s.bytes() {
1188 assert_eq!(b, v[pos]);
1189 pos += 1;
1190 }
1191 }
1192
1193 #[test]
1194 fn test_bytes_revator() {
1195 let s = "ศไทย中华Việt Nam";
1196 let v = [
1197 224, 184, 168, 224, 185, 132, 224, 184, 151, 224, 184, 162, 228, 184, 173, 229, 141, 142,
1198 86, 105, 225, 187, 135, 116, 32, 78, 97, 109,
1199 ];
1200 let mut pos = v.len();
1201
1202 for b in s.bytes().rev() {
1203 pos -= 1;
1204 assert_eq!(b, v[pos]);
1205 }
1206 }
1207
1208 #[test]
1209 fn test_bytesator_nth() {
1210 let s = "ศไทย中华Việt Nam";
1211 let v = [
1212 224, 184, 168, 224, 185, 132, 224, 184, 151, 224, 184, 162, 228, 184, 173, 229, 141, 142,
1213 86, 105, 225, 187, 135, 116, 32, 78, 97, 109,
1214 ];
1215
1216 let mut b = s.bytes();
1217 assert_eq!(b.nth(2).unwrap(), v[2]);
1218 assert_eq!(b.nth(10).unwrap(), v[10]);
1219 assert_eq!(b.nth(200), None);
1220 }
1221
1222 #[test]
1223 fn test_bytesator_count() {
1224 let s = "ศไทย中华Việt Nam";
1225
1226 let b = s.bytes();
1227 assert_eq!(b.count(), 28)
1228 }
1229
1230 #[test]
1231 fn test_bytesator_last() {
1232 let s = "ศไทย中华Việt Nam";
1233
1234 let b = s.bytes();
1235 assert_eq!(b.last().unwrap(), 109)
1236 }
1237
1238 #[test]
1239 fn test_char_indicesator() {
1240 let s = "ศไทย中华Việt Nam";
1241 let p = [0, 3, 6, 9, 12, 15, 18, 19, 20, 23, 24, 25, 26, 27];
1242 let v = ['ศ', 'ไ', 'ท', 'ย', '中', '华', 'V', 'i', 'ệ', 't', ' ', 'N', 'a', 'm'];
1243
1244 let mut pos = 0;
1245 let it = s.char_indices();
1246
1247 for c in it {
1248 assert_eq!(c, (p[pos], v[pos]));
1249 pos += 1;
1250 }
1251 assert_eq!(pos, v.len());
1252 assert_eq!(pos, p.len());
1253 }
1254
1255 #[test]
1256 fn test_char_indices_revator() {
1257 let s = "ศไทย中华Việt Nam";
1258 let p = [27, 26, 25, 24, 23, 20, 19, 18, 15, 12, 9, 6, 3, 0];
1259 let v = ['m', 'a', 'N', ' ', 't', 'ệ', 'i', 'V', '华', '中', 'ย', 'ท', 'ไ', 'ศ'];
1260
1261 let mut pos = 0;
1262 let it = s.char_indices().rev();
1263
1264 for c in it {
1265 assert_eq!(c, (p[pos], v[pos]));
1266 pos += 1;
1267 }
1268 assert_eq!(pos, v.len());
1269 assert_eq!(pos, p.len());
1270 }
1271
1272 #[test]
1273 fn test_char_indices_last() {
1274 let s = "ศไทย中华Việt Nam";
1275 let mut it = s.char_indices();
1276 it.next();
1277 assert_eq!(it.last(), Some((27, 'm')));
1278 }
1279
1280 #[test]
1281 fn test_splitn_char_iterator() {
1282 let data = "\nMäry häd ä little lämb\nLittle lämb\n";
1283
1284 let split: Vec<&str> = data.splitn(4, ' ').collect();
1285 assert_eq!(split, ["\nMäry", "häd", "ä", "little lämb\nLittle lämb\n"]);
1286
1287 let split: Vec<&str> = data.splitn(4, |c: char| c == ' ').collect();
1288 assert_eq!(split, ["\nMäry", "häd", "ä", "little lämb\nLittle lämb\n"]);
1289
1290 // Unicode
1291 let split: Vec<&str> = data.splitn(4, 'ä').collect();
1292 assert_eq!(split, ["\nM", "ry h", "d ", " little lämb\nLittle lämb\n"]);
1293
1294 let split: Vec<&str> = data.splitn(4, |c: char| c == 'ä').collect();
1295 assert_eq!(split, ["\nM", "ry h", "d ", " little lämb\nLittle lämb\n"]);
1296 }
1297
1298 #[test]
1299 fn test_split_char_iterator_no_trailing() {
1300 let data = "\nMäry häd ä little lämb\nLittle lämb\n";
1301
1302 let split: Vec<&str> = data.split('\n').collect();
1303 assert_eq!(split, ["", "Märy häd ä little lämb", "Little lämb", ""]);
1304
1305 let split: Vec<&str> = data.split_terminator('\n').collect();
1306 assert_eq!(split, ["", "Märy häd ä little lämb", "Little lämb"]);
1307 }
1308
1309 #[test]
1310 fn test_split_char_iterator_inclusive() {
1311 let data = "\nMäry häd ä little lämb\nLittle lämb\n";
1312
1313 let split: Vec<&str> = data.split_inclusive('\n').collect();
1314 assert_eq!(split, ["\n", "Märy häd ä little lämb\n", "Little lämb\n"]);
1315
1316 let uppercase_separated = "SheePSharKTurtlECaT";
1317 let mut first_char = true;
1318 let split: Vec<&str> = uppercase_separated
1319 .split_inclusive(|c: char| {
1320 let split = !first_char && c.is_uppercase();
1321 first_char = split;
1322 split
1323 })
1324 .collect();
1325 assert_eq!(split, ["SheeP", "SharK", "TurtlE", "CaT"]);
1326 }
1327
1328 #[test]
1329 fn test_split_char_iterator_inclusive_rev() {
1330 let data = "\nMäry häd ä little lämb\nLittle lämb\n";
1331
1332 let split: Vec<&str> = data.split_inclusive('\n').rev().collect();
1333 assert_eq!(split, ["Little lämb\n", "Märy häd ä little lämb\n", "\n"]);
1334
1335 // Note that the predicate is stateful and thus dependent
1336 // on the iteration order.
1337 // (A different predicate is needed for reverse iterator vs normal iterator.)
1338 // Not sure if anything can be done though.
1339 let uppercase_separated = "SheePSharKTurtlECaT";
1340 let mut term_char = true;
1341 let split: Vec<&str> = uppercase_separated
1342 .split_inclusive(|c: char| {
1343 let split = term_char && c.is_uppercase();
1344 term_char = c.is_uppercase();
1345 split
1346 })
1347 .rev()
1348 .collect();
1349 assert_eq!(split, ["CaT", "TurtlE", "SharK", "SheeP"]);
1350 }
1351
1352 #[test]
1353 fn test_rsplit() {
1354 let data = "\nMäry häd ä little lämb\nLittle lämb\n";
1355
1356 let split: Vec<&str> = data.rsplit(' ').collect();
1357 assert_eq!(split, ["lämb\n", "lämb\nLittle", "little", "ä", "häd", "\nMäry"]);
1358
1359 let split: Vec<&str> = data.rsplit("lämb").collect();
1360 assert_eq!(split, ["\n", "\nLittle ", "\nMäry häd ä little "]);
1361
1362 let split: Vec<&str> = data.rsplit(|c: char| c == 'ä').collect();
1363 assert_eq!(split, ["mb\n", "mb\nLittle l", " little l", "d ", "ry h", "\nM"]);
1364 }
1365
1366 #[test]
1367 fn test_rsplitn() {
1368 let data = "\nMäry häd ä little lämb\nLittle lämb\n";
1369
1370 let split: Vec<&str> = data.rsplitn(2, ' ').collect();
1371 assert_eq!(split, ["lämb\n", "\nMäry häd ä little lämb\nLittle"]);
1372
1373 let split: Vec<&str> = data.rsplitn(2, "lämb").collect();
1374 assert_eq!(split, ["\n", "\nMäry häd ä little lämb\nLittle "]);
1375
1376 let split: Vec<&str> = data.rsplitn(2, |c: char| c == 'ä').collect();
1377 assert_eq!(split, ["mb\n", "\nMäry häd ä little lämb\nLittle l"]);
1378 }
1379
1380 #[test]
1381 fn test_split_once() {
1382 assert_eq!("".split_once("->"), None);
1383 assert_eq!("-".split_once("->"), None);
1384 assert_eq!("->".split_once("->"), Some(("", "")));
1385 assert_eq!("a->".split_once("->"), Some(("a", "")));
1386 assert_eq!("->b".split_once("->"), Some(("", "b")));
1387 assert_eq!("a->b".split_once("->"), Some(("a", "b")));
1388 assert_eq!("a->b->c".split_once("->"), Some(("a", "b->c")));
1389 assert_eq!("---".split_once("--"), Some(("", "-")));
1390 }
1391
1392 #[test]
1393 fn test_rsplit_once() {
1394 assert_eq!("".rsplit_once("->"), None);
1395 assert_eq!("-".rsplit_once("->"), None);
1396 assert_eq!("->".rsplit_once("->"), Some(("", "")));
1397 assert_eq!("a->".rsplit_once("->"), Some(("a", "")));
1398 assert_eq!("->b".rsplit_once("->"), Some(("", "b")));
1399 assert_eq!("a->b".rsplit_once("->"), Some(("a", "b")));
1400 assert_eq!("a->b->c".rsplit_once("->"), Some(("a->b", "c")));
1401 assert_eq!("---".rsplit_once("--"), Some(("-", "")));
1402 }
1403
1404 #[test]
1405 fn test_split_whitespace() {
1406 let data = "\n \tMäry häd\tä little lämb\nLittle lämb\n";
1407 let words: Vec<&str> = data.split_whitespace().collect();
1408 assert_eq!(words, ["Märy", "häd", "ä", "little", "lämb", "Little", "lämb"])
1409 }
1410
1411 #[test]
1412 fn test_lines() {
1413 let data = "\nMäry häd ä little lämb\n\r\nLittle lämb\n";
1414 let lines: Vec<&str> = data.lines().collect();
1415 assert_eq!(lines, ["", "Märy häd ä little lämb", "", "Little lämb"]);
1416
1417 let data = "\r\nMäry häd ä little lämb\n\nLittle lämb"; // no trailing \n
1418 let lines: Vec<&str> = data.lines().collect();
1419 assert_eq!(lines, ["", "Märy häd ä little lämb", "", "Little lämb"]);
1420 }
1421
1422 #[test]
1423 fn test_splitator() {
1424 fn t(s: &str, sep: &str, u: &[&str]) {
1425 let v: Vec<&str> = s.split(sep).collect();
1426 assert_eq!(v, u);
1427 }
1428 t("--1233345--", "12345", &["--1233345--"]);
1429 t("abc::hello::there", "::", &["abc", "hello", "there"]);
1430 t("::hello::there", "::", &["", "hello", "there"]);
1431 t("hello::there::", "::", &["hello", "there", ""]);
1432 t("::hello::there::", "::", &["", "hello", "there", ""]);
1433 t("ประเทศไทย中华Việt Nam", "中华", &["ประเทศไทย", "Việt Nam"]);
1434 t("zzXXXzzYYYzz", "zz", &["", "XXX", "YYY", ""]);
1435 t("zzXXXzYYYz", "XXX", &["zz", "zYYYz"]);
1436 t(".XXX.YYY.", ".", &["", "XXX", "YYY", ""]);
1437 t("", ".", &[""]);
1438 t("zz", "zz", &["", ""]);
1439 t("ok", "z", &["ok"]);
1440 t("zzz", "zz", &["", "z"]);
1441 t("zzzzz", "zz", &["", "", "z"]);
1442 }
1443
1444 #[test]
1445 fn test_str_default() {
1446 use std::default::Default;
1447
1448 fn t<S: Default + AsRef<str>>() {
1449 let s: S = Default::default();
1450 assert_eq!(s.as_ref(), "");
1451 }
1452
1453 t::<&str>();
1454 t::<String>();
1455 t::<&mut str>();
1456 }
1457
1458 #[test]
1459 fn test_str_container() {
1460 fn sum_len(v: &[&str]) -> usize {
1461 v.iter().map(|x| x.len()).sum()
1462 }
1463
1464 let s = "01234";
1465 assert_eq!(5, sum_len(&["012", "", "34"]));
1466 assert_eq!(5, sum_len(&["01", "2", "34", ""]));
1467 assert_eq!(5, sum_len(&[s]));
1468 }
1469
1470 #[test]
1471 fn test_str_from_utf8() {
1472 let xs = b"hello";
1473 assert_eq!(from_utf8(xs), Ok("hello"));
1474
1475 let xs = "ศไทย中华Việt Nam".as_bytes();
1476 assert_eq!(from_utf8(xs), Ok("ศไทย中华Việt Nam"));
1477
1478 let xs = b"hello\xFF";
1479 assert!(from_utf8(xs).is_err());
1480 }
1481
1482 #[test]
1483 fn test_pattern_deref_forward() {
1484 let data = "aabcdaa";
1485 assert!(data.contains("bcd"));
1486 assert!(data.contains(&"bcd"));
1487 assert!(data.contains(&"bcd".to_string()));
1488 }
1489
1490 #[test]
1491 fn test_empty_match_indices() {
1492 let data = "aä中!";
1493 let vec: Vec<_> = data.match_indices("").collect();
1494 assert_eq!(vec, [(0, ""), (1, ""), (3, ""), (6, ""), (7, "")]);
1495 }
1496
1497 #[test]
1498 fn test_bool_from_str() {
1499 assert_eq!("true".parse().ok(), Some(true));
1500 assert_eq!("false".parse().ok(), Some(false));
1501 assert_eq!("not even a boolean".parse::<bool>().ok(), None);
1502 }
1503
1504 fn check_contains_all_substrings(s: &str) {
1505 assert!(s.contains(""));
1506 for i in 0..s.len() {
1507 for j in i + 1..=s.len() {
1508 assert!(s.contains(&s[i..j]));
1509 }
1510 }
1511 }
1512
1513 #[test]
1514 #[cfg_attr(miri, ignore)] // Miri is too slow
1515 fn strslice_issue_16589() {
1516 assert!("bananas".contains("nana"));
1517
1518 // prior to the fix for #16589, x.contains("abcdabcd") returned false
1519 // test all substrings for good measure
1520 check_contains_all_substrings("012345678901234567890123456789bcdabcdabcd");
1521 }
1522
1523 #[test]
1524 fn strslice_issue_16878() {
1525 assert!(!"1234567ah012345678901ah".contains("hah"));
1526 assert!(!"00abc01234567890123456789abc".contains("bcabc"));
1527 }
1528
1529 #[test]
1530 #[cfg_attr(miri, ignore)] // Miri is too slow
1531 fn test_strslice_contains() {
1532 let x = "There are moments, Jeeves, when one asks oneself, 'Do trousers matter?'";
1533 check_contains_all_substrings(x);
1534 }
1535
1536 #[test]
1537 fn test_rsplitn_char_iterator() {
1538 let data = "\nMäry häd ä little lämb\nLittle lämb\n";
1539
1540 let mut split: Vec<&str> = data.rsplitn(4, ' ').collect();
1541 split.reverse();
1542 assert_eq!(split, ["\nMäry häd ä", "little", "lämb\nLittle", "lämb\n"]);
1543
1544 let mut split: Vec<&str> = data.rsplitn(4, |c: char| c == ' ').collect();
1545 split.reverse();
1546 assert_eq!(split, ["\nMäry häd ä", "little", "lämb\nLittle", "lämb\n"]);
1547
1548 // Unicode
1549 let mut split: Vec<&str> = data.rsplitn(4, 'ä').collect();
1550 split.reverse();
1551 assert_eq!(split, ["\nMäry häd ", " little l", "mb\nLittle l", "mb\n"]);
1552
1553 let mut split: Vec<&str> = data.rsplitn(4, |c: char| c == 'ä').collect();
1554 split.reverse();
1555 assert_eq!(split, ["\nMäry häd ", " little l", "mb\nLittle l", "mb\n"]);
1556 }
1557
1558 #[test]
1559 fn test_split_char_iterator() {
1560 let data = "\nMäry häd ä little lämb\nLittle lämb\n";
1561
1562 let split: Vec<&str> = data.split(' ').collect();
1563 assert_eq!(split, ["\nMäry", "häd", "ä", "little", "lämb\nLittle", "lämb\n"]);
1564
1565 let mut rsplit: Vec<&str> = data.split(' ').rev().collect();
1566 rsplit.reverse();
1567 assert_eq!(rsplit, ["\nMäry", "häd", "ä", "little", "lämb\nLittle", "lämb\n"]);
1568
1569 let split: Vec<&str> = data.split(|c: char| c == ' ').collect();
1570 assert_eq!(split, ["\nMäry", "häd", "ä", "little", "lämb\nLittle", "lämb\n"]);
1571
1572 let mut rsplit: Vec<&str> = data.split(|c: char| c == ' ').rev().collect();
1573 rsplit.reverse();
1574 assert_eq!(rsplit, ["\nMäry", "häd", "ä", "little", "lämb\nLittle", "lämb\n"]);
1575
1576 // Unicode
1577 let split: Vec<&str> = data.split('ä').collect();
1578 assert_eq!(split, ["\nM", "ry h", "d ", " little l", "mb\nLittle l", "mb\n"]);
1579
1580 let mut rsplit: Vec<&str> = data.split('ä').rev().collect();
1581 rsplit.reverse();
1582 assert_eq!(rsplit, ["\nM", "ry h", "d ", " little l", "mb\nLittle l", "mb\n"]);
1583
1584 let split: Vec<&str> = data.split(|c: char| c == 'ä').collect();
1585 assert_eq!(split, ["\nM", "ry h", "d ", " little l", "mb\nLittle l", "mb\n"]);
1586
1587 let mut rsplit: Vec<&str> = data.split(|c: char| c == 'ä').rev().collect();
1588 rsplit.reverse();
1589 assert_eq!(rsplit, ["\nM", "ry h", "d ", " little l", "mb\nLittle l", "mb\n"]);
1590 }
1591
1592 #[test]
1593 fn test_rev_split_char_iterator_no_trailing() {
1594 let data = "\nMäry häd ä little lämb\nLittle lämb\n";
1595
1596 let mut split: Vec<&str> = data.split('\n').rev().collect();
1597 split.reverse();
1598 assert_eq!(split, ["", "Märy häd ä little lämb", "Little lämb", ""]);
1599
1600 let mut split: Vec<&str> = data.split_terminator('\n').rev().collect();
1601 split.reverse();
1602 assert_eq!(split, ["", "Märy häd ä little lämb", "Little lämb"]);
1603 }
1604
1605 #[test]
1606 fn test_utf16_code_units() {
1607 assert_eq!(\u{1F4A9}".encode_utf16().collect::<Vec<u16>>(), [0xE9, 0xD83D, 0xDCA9])
1608 }
1609
1610 #[test]
1611 fn starts_with_in_unicode() {
1612 assert!(!"├── Cargo.toml".starts_with("# "));
1613 }
1614
1615 #[test]
1616 fn starts_short_long() {
1617 assert!(!"".starts_with("##"));
1618 assert!(!"##".starts_with("####"));
1619 assert!("####".starts_with("##"));
1620 assert!(!"##ä".starts_with("####"));
1621 assert!("####ä".starts_with("##"));
1622 assert!(!"##".starts_with("####ä"));
1623 assert!("##ä##".starts_with("##ä"));
1624
1625 assert!("".starts_with(""));
1626 assert!("ä".starts_with(""));
1627 assert!("#ä".starts_with(""));
1628 assert!("##ä".starts_with(""));
1629 assert!("ä###".starts_with(""));
1630 assert!("#ä##".starts_with(""));
1631 assert!("##ä#".starts_with(""));
1632 }
1633
1634 #[test]
1635 fn contains_weird_cases() {
1636 assert!("* \t".contains(' '));
1637 assert!(!"* \t".contains('?'));
1638 assert!(!"* \t".contains('\u{1F4A9}'));
1639 }
1640
1641 #[test]
1642 fn trim_ws() {
1643 assert_eq!(" \t a \t ".trim_start_matches(|c: char| c.is_whitespace()), "a \t ");
1644 assert_eq!(" \t a \t ".trim_end_matches(|c: char| c.is_whitespace()), " \t a");
1645 assert_eq!(" \t a \t ".trim_start_matches(|c: char| c.is_whitespace()), "a \t ");
1646 assert_eq!(" \t a \t ".trim_end_matches(|c: char| c.is_whitespace()), " \t a");
1647 assert_eq!(" \t a \t ".trim_matches(|c: char| c.is_whitespace()), "a");
1648 assert_eq!(" \t \t ".trim_start_matches(|c: char| c.is_whitespace()), "");
1649 assert_eq!(" \t \t ".trim_end_matches(|c: char| c.is_whitespace()), "");
1650 assert_eq!(" \t \t ".trim_start_matches(|c: char| c.is_whitespace()), "");
1651 assert_eq!(" \t \t ".trim_end_matches(|c: char| c.is_whitespace()), "");
1652 assert_eq!(" \t \t ".trim_matches(|c: char| c.is_whitespace()), "");
1653 }
1654
1655 #[test]
1656 fn to_lowercase() {
1657 assert_eq!("".to_lowercase(), "");
1658 assert_eq!("AÉDžaé ".to_lowercase(), "aédžaé ");
1659
1660 // https://github.com/rust-lang/rust/issues/26035
1661 assert_eq!("ΑΣ".to_lowercase(), "ας");
1662 assert_eq!("Α'Σ".to_lowercase(), "α'ς");
1663 assert_eq!("Α''Σ".to_lowercase(), "α''ς");
1664
1665 assert_eq!("ΑΣ Α".to_lowercase(), "ας α");
1666 assert_eq!("Α'Σ Α".to_lowercase(), "α'ς α");
1667 assert_eq!("Α''Σ Α".to_lowercase(), "α''ς α");
1668
1669 assert_eq!("ΑΣ' Α".to_lowercase(), "ας' α");
1670 assert_eq!("ΑΣ'' Α".to_lowercase(), "ας'' α");
1671
1672 assert_eq!("Α'Σ' Α".to_lowercase(), "α'ς' α");
1673 assert_eq!("Α''Σ'' Α".to_lowercase(), "α''ς'' α");
1674
1675 assert_eq!("Α Σ".to_lowercase(), "α σ");
1676 assert_eq!("Α 'Σ".to_lowercase(), "α 'σ");
1677 assert_eq!("Α ''Σ".to_lowercase(), "α ''σ");
1678
1679 assert_eq!("Σ".to_lowercase(), "σ");
1680 assert_eq!("'Σ".to_lowercase(), "'σ");
1681 assert_eq!("''Σ".to_lowercase(), "''σ");
1682
1683 assert_eq!("ΑΣΑ".to_lowercase(), "ασα");
1684 assert_eq!("ΑΣ'Α".to_lowercase(), "ασ'α");
1685 assert_eq!("ΑΣ''Α".to_lowercase(), "ασ''α");
1686 }
1687
1688 #[test]
1689 fn to_uppercase() {
1690 assert_eq!("".to_uppercase(), "");
1691 assert_eq!("aéDžßfiᾀ".to_uppercase(), "AÉDŽSSFIἈΙ");
1692 }
1693
1694 #[test]
1695 fn test_into_string() {
1696 // The only way to acquire a Box<str> in the first place is through a String, so just
1697 // test that we can round-trip between Box<str> and String.
1698 let string = String::from("Some text goes here");
1699 assert_eq!(string.clone().into_boxed_str().into_string(), string);
1700 }
1701
1702 #[test]
1703 fn test_box_slice_clone() {
1704 let data = String::from("hello HELLO hello HELLO yes YES 5 中ä华!!!");
1705 let data2 = data.clone().into_boxed_str().clone().into_string();
1706
1707 assert_eq!(data, data2);
1708 }
1709
1710 #[test]
1711 fn test_cow_from() {
1712 let borrowed = "borrowed";
1713 let owned = String::from("owned");
1714 match (Cow::from(owned.clone()), Cow::from(borrowed)) {
1715 (Cow::Owned(o), Cow::Borrowed(b)) => assert!(o == owned && b == borrowed),
1716 _ => panic!("invalid `Cow::from`"),
1717 }
1718 }
1719
1720 #[test]
1721 fn test_repeat() {
1722 assert_eq!("".repeat(3), "");
1723 assert_eq!("abc".repeat(0), "");
1724 assert_eq!("α".repeat(3), "ααα");
1725 }
1726
1727 mod pattern {
1728 use std::str::pattern::SearchStep::{self, Done, Match, Reject};
1729 use std::str::pattern::{Pattern, ReverseSearcher, Searcher};
1730
1731 macro_rules! make_test {
1732 ($name:ident, $p:expr, $h:expr, [$($e:expr,)*]) => {
1733 #[allow(unused_imports)]
1734 mod $name {
1735 use std::str::pattern::SearchStep::{Match, Reject};
1736 use super::{cmp_search_to_vec};
1737 #[test]
1738 fn fwd() {
1739 cmp_search_to_vec(false, $p, $h, vec![$($e),*]);
1740 }
1741 #[test]
1742 fn bwd() {
1743 cmp_search_to_vec(true, $p, $h, vec![$($e),*]);
1744 }
1745 }
1746 }
1747 }
1748
1749 fn cmp_search_to_vec<'a>(
1750 rev: bool,
1751 pat: impl Pattern<'a, Searcher: ReverseSearcher<'a>>,
1752 haystack: &'a str,
1753 right: Vec<SearchStep>,
1754 ) {
1755 let mut searcher = pat.into_searcher(haystack);
1756 let mut v = vec![];
1757 loop {
1758 match if !rev { searcher.next() } else { searcher.next_back() } {
1759 Match(a, b) => v.push(Match(a, b)),
1760 Reject(a, b) => v.push(Reject(a, b)),
1761 Done => break,
1762 }
1763 }
1764 if rev {
1765 v.reverse();
1766 }
1767
1768 let mut first_index = 0;
1769 let mut err = None;
1770
1771 for (i, e) in right.iter().enumerate() {
1772 match *e {
1773 Match(a, b) | Reject(a, b) if a <= b && a == first_index => {
1774 first_index = b;
1775 }
1776 _ => {
1777 err = Some(i);
1778 break;
1779 }
1780 }
1781 }
1782
1783 if let Some(err) = err {
1784 panic!("Input skipped range at {}", err);
1785 }
1786
1787 if first_index != haystack.len() {
1788 panic!("Did not cover whole input");
1789 }
1790
1791 assert_eq!(v, right);
1792 }
1793
1794 make_test!(
1795 str_searcher_ascii_haystack,
1796 "bb",
1797 "abbcbbd",
1798 [Reject(0, 1), Match(1, 3), Reject(3, 4), Match(4, 6), Reject(6, 7),]
1799 );
1800 make_test!(
1801 str_searcher_ascii_haystack_seq,
1802 "bb",
1803 "abbcbbbbd",
1804 [Reject(0, 1), Match(1, 3), Reject(3, 4), Match(4, 6), Match(6, 8), Reject(8, 9),]
1805 );
1806 make_test!(
1807 str_searcher_empty_needle_ascii_haystack,
1808 "",
1809 "abbcbbd",
1810 [
1811 Match(0, 0),
1812 Reject(0, 1),
1813 Match(1, 1),
1814 Reject(1, 2),
1815 Match(2, 2),
1816 Reject(2, 3),
1817 Match(3, 3),
1818 Reject(3, 4),
1819 Match(4, 4),
1820 Reject(4, 5),
1821 Match(5, 5),
1822 Reject(5, 6),
1823 Match(6, 6),
1824 Reject(6, 7),
1825 Match(7, 7),
1826 ]
1827 );
1828 make_test!(
1829 str_searcher_multibyte_haystack,
1830 " ",
1831 "├──",
1832 [Reject(0, 3), Reject(3, 6), Reject(6, 9),]
1833 );
1834 make_test!(
1835 str_searcher_empty_needle_multibyte_haystack,
1836 "",
1837 "├──",
1838 [
1839 Match(0, 0),
1840 Reject(0, 3),
1841 Match(3, 3),
1842 Reject(3, 6),
1843 Match(6, 6),
1844 Reject(6, 9),
1845 Match(9, 9),
1846 ]
1847 );
1848 make_test!(str_searcher_empty_needle_empty_haystack, "", "", [Match(0, 0),]);
1849 make_test!(str_searcher_nonempty_needle_empty_haystack, "├", "", []);
1850 make_test!(
1851 char_searcher_ascii_haystack,
1852 'b',
1853 "abbcbbd",
1854 [
1855 Reject(0, 1),
1856 Match(1, 2),
1857 Match(2, 3),
1858 Reject(3, 4),
1859 Match(4, 5),
1860 Match(5, 6),
1861 Reject(6, 7),
1862 ]
1863 );
1864 make_test!(
1865 char_searcher_multibyte_haystack,
1866 ' ',
1867 "├──",
1868 [Reject(0, 3), Reject(3, 6), Reject(6, 9),]
1869 );
1870 make_test!(
1871 char_searcher_short_haystack,
1872 '\u{1F4A9}',
1873 "* \t",
1874 [Reject(0, 1), Reject(1, 2), Reject(2, 3),]
1875 );
1876 }
1877
1878 macro_rules! generate_iterator_test {
1879 {
1880 $name:ident {
1881 $(
1882 ($($arg:expr),*) -> [$($t:tt)*];
1883 )*
1884 }
1885 with $fwd:expr, $bwd:expr;
1886 } => {
1887 #[test]
1888 fn $name() {
1889 $(
1890 {
1891 let res = vec![$($t)*];
1892
1893 let fwd_vec: Vec<_> = ($fwd)($($arg),*).collect();
1894 assert_eq!(fwd_vec, res);
1895
1896 let mut bwd_vec: Vec<_> = ($bwd)($($arg),*).collect();
1897 bwd_vec.reverse();
1898 assert_eq!(bwd_vec, res);
1899 }
1900 )*
1901 }
1902 };
1903 {
1904 $name:ident {
1905 $(
1906 ($($arg:expr),*) -> [$($t:tt)*];
1907 )*
1908 }
1909 with $fwd:expr;
1910 } => {
1911 #[test]
1912 fn $name() {
1913 $(
1914 {
1915 let res = vec![$($t)*];
1916
1917 let fwd_vec: Vec<_> = ($fwd)($($arg),*).collect();
1918 assert_eq!(fwd_vec, res);
1919 }
1920 )*
1921 }
1922 }
1923 }
1924
1925 generate_iterator_test! {
1926 double_ended_split {
1927 ("foo.bar.baz", '.') -> ["foo", "bar", "baz"];
1928 ("foo::bar::baz", "::") -> ["foo", "bar", "baz"];
1929 }
1930 with str::split, str::rsplit;
1931 }
1932
1933 generate_iterator_test! {
1934 double_ended_split_terminator {
1935 ("foo;bar;baz;", ';') -> ["foo", "bar", "baz"];
1936 }
1937 with str::split_terminator, str::rsplit_terminator;
1938 }
1939
1940 generate_iterator_test! {
1941 double_ended_matches {
1942 ("a1b2c3", char::is_numeric) -> ["1", "2", "3"];
1943 }
1944 with str::matches, str::rmatches;
1945 }
1946
1947 generate_iterator_test! {
1948 double_ended_match_indices {
1949 ("a1b2c3", char::is_numeric) -> [(1, "1"), (3, "2"), (5, "3")];
1950 }
1951 with str::match_indices, str::rmatch_indices;
1952 }
1953
1954 generate_iterator_test! {
1955 not_double_ended_splitn {
1956 ("foo::bar::baz", 2, "::") -> ["foo", "bar::baz"];
1957 }
1958 with str::splitn;
1959 }
1960
1961 generate_iterator_test! {
1962 not_double_ended_rsplitn {
1963 ("foo::bar::baz", 2, "::") -> ["baz", "foo::bar"];
1964 }
1965 with str::rsplitn;
1966 }
1967
1968 #[test]
1969 fn different_str_pattern_forwarding_lifetimes() {
1970 use std::str::pattern::Pattern;
1971
1972 fn foo<'a, P>(p: P)
1973 where
1974 for<'b> &'b P: Pattern<'a>,
1975 {
1976 for _ in 0..3 {
1977 "asdf".find(&p);
1978 }
1979 }
1980
1981 foo::<&str>("x");
1982 }
1983
1984 #[test]
1985 fn test_str_multiline() {
1986 let a: String = "this \
1987 is a test"
1988 .to_string();
1989 let b: String = "this \
1990 is \
1991 another \
1992 test"
1993 .to_string();
1994 assert_eq!(a, "this is a test".to_string());
1995 assert_eq!(b, "this is another test".to_string());
1996 }
1997
1998 #[test]
1999 fn test_str_escapes() {
2000 let x = "\\\\\
2001 ";
2002 assert_eq!(x, r"\\"); // extraneous whitespace stripped
2003 }
2004
2005 #[test]
2006 fn const_str_ptr() {
2007 const A: [u8; 2] = ['h' as u8, 'i' as u8];
2008 const B: &'static [u8; 2] = &A;
2009 const C: *const u8 = B as *const u8;
2010
2011 // Miri does not deduplicate consts (https://github.com/rust-lang/miri/issues/131)
2012 #[cfg(not(miri))]
2013 {
2014 let foo = &A as *const u8;
2015 assert_eq!(foo, C);
2016 }
2017
2018 unsafe {
2019 assert_eq!(from_utf8_unchecked(&A), "hi");
2020 assert_eq!(*C, A[0]);
2021 assert_eq!(*(&B[0] as *const u8), A[0]);
2022 }
2023 }
2024
2025 #[test]
2026 fn utf8() {
2027 let yen: char = '¥'; // 0xa5
2028 let c_cedilla: char = 'ç'; // 0xe7
2029 let thorn: char = 'þ'; // 0xfe
2030 let y_diaeresis: char = 'ÿ'; // 0xff
2031 let pi: char = 'Π'; // 0x3a0
2032
2033 assert_eq!(yen as isize, 0xa5);
2034 assert_eq!(c_cedilla as isize, 0xe7);
2035 assert_eq!(thorn as isize, 0xfe);
2036 assert_eq!(y_diaeresis as isize, 0xff);
2037 assert_eq!(pi as isize, 0x3a0);
2038
2039 assert_eq!(pi as isize, '\u{3a0}' as isize);
2040 assert_eq!('\x0a' as isize, '\n' as isize);
2041
2042 let bhutan: String = "འབྲུག་ཡུལ།".to_string();
2043 let japan: String = "日本".to_string();
2044 let uzbekistan: String = "Ўзбекистон".to_string();
2045 let austria: String = "Österreich".to_string();
2046
2047 let bhutan_e: String =
2048 "\u{f60}\u{f56}\u{fb2}\u{f74}\u{f42}\u{f0b}\u{f61}\u{f74}\u{f63}\u{f0d}".to_string();
2049 let japan_e: String = "\u{65e5}\u{672c}".to_string();
2050 let uzbekistan_e: String =
2051 "\u{40e}\u{437}\u{431}\u{435}\u{43a}\u{438}\u{441}\u{442}\u{43e}\u{43d}".to_string();
2052 let austria_e: String = "\u{d6}sterreich".to_string();
2053
2054 let oo: char = 'Ö';
2055 assert_eq!(oo as isize, 0xd6);
2056
2057 fn check_str_eq(a: String, b: String) {
2058 let mut i: isize = 0;
2059 for ab in a.bytes() {
2060 println!("{}", i);
2061 println!("{}", ab);
2062 let bb: u8 = b.as_bytes()[i as usize];
2063 println!("{}", bb);
2064 assert_eq!(ab, bb);
2065 i += 1;
2066 }
2067 }
2068
2069 check_str_eq(bhutan, bhutan_e);
2070 check_str_eq(japan, japan_e);
2071 check_str_eq(uzbekistan, uzbekistan_e);
2072 check_str_eq(austria, austria_e);
2073 }
2074
2075 #[test]
2076 fn utf8_chars() {
2077 // Chars of 1, 2, 3, and 4 bytes
2078 let chs: Vec<char> = vec!['e', 'é', '€', '\u{10000}'];
2079 let s: String = chs.iter().cloned().collect();
2080 let schs: Vec<char> = s.chars().collect();
2081
2082 assert_eq!(s.len(), 10);
2083 assert_eq!(s.chars().count(), 4);
2084 assert_eq!(schs.len(), 4);
2085 assert_eq!(schs.iter().cloned().collect::<String>(), s);
2086
2087 assert!((from_utf8(s.as_bytes()).is_ok()));
2088 // invalid prefix
2089 assert!((!from_utf8(&[0x80]).is_ok()));
2090 // invalid 2 byte prefix
2091 assert!((!from_utf8(&[0xc0]).is_ok()));
2092 assert!((!from_utf8(&[0xc0, 0x10]).is_ok()));
2093 // invalid 3 byte prefix
2094 assert!((!from_utf8(&[0xe0]).is_ok()));
2095 assert!((!from_utf8(&[0xe0, 0x10]).is_ok()));
2096 assert!((!from_utf8(&[0xe0, 0xff, 0x10]).is_ok()));
2097 // invalid 4 byte prefix
2098 assert!((!from_utf8(&[0xf0]).is_ok()));
2099 assert!((!from_utf8(&[0xf0, 0x10]).is_ok()));
2100 assert!((!from_utf8(&[0xf0, 0xff, 0x10]).is_ok()));
2101 assert!((!from_utf8(&[0xf0, 0xff, 0xff, 0x10]).is_ok()));
2102 }