1 use std::assert_matches::assert_matches;
3 use std::cmp::Ordering::{Equal, Greater, Less};
4 use std::str::{from_utf8, from_utf8_unchecked};
10 assert!("foo" <= "foo");
11 assert_ne!("foo", "bar");
16 assert_eq!("hello".find('l'), Some(2));
17 assert_eq!("hello".find(|c: char| c == 'o'), Some(4));
18 assert!("hello".find('x').is_none());
19 assert!("hello".find(|c: char| c == 'x').is_none());
20 assert_eq!("ประเทศไทย中华Việt Nam".find('华'), Some(30));
21 assert_eq!("ประเทศไทย中华Việt Nam".find(|c: char| c == '华'), Some(30));
26 assert_eq!("hello".rfind('l'), Some(3));
27 assert_eq!("hello".rfind(|c: char| c == 'o'), Some(4));
28 assert!("hello".rfind('x').is_none());
29 assert!("hello".rfind(|c: char| c == 'x').is_none());
30 assert_eq!("ประเทศไทย中华Việt Nam".rfind('华'), Some(30));
31 assert_eq!("ประเทศไทย中华Việt Nam".rfind(|c: char| c == '华'), Some(30));
37 let s: String = empty.chars().collect();
39 let data = "ประเทศไทย中";
40 let s: String = data.chars().collect();
45 fn test_into_bytes() {
46 let data = String::from("asdf");
47 let buf = data.into_bytes();
48 assert_eq!(buf, b"asdf");
54 assert_eq!("".find(""), Some(0));
55 assert!("banana".find("apple pie").is_none());
58 assert_eq!(data[0..6].find("ab"), Some(0));
59 assert_eq!(data[2..6].find("ab"), Some(3 - 2));
60 assert!(data[2..4].find("ab").is_none());
62 let string = "ประเทศไทย中华Việt Nam";
63 let mut data = String::from(string);
64 data.push_str(string);
65 assert!(data.find("ไท华").is_none());
66 assert_eq!(data[0..43].find(""), Some(0));
67 assert_eq!(data[6..43].find(""), Some(6 - 6));
69 assert_eq!(data[0..43].find("ประ"), Some(0));
70 assert_eq!(data[0..43].find("ทศไ"), Some(12));
71 assert_eq!(data[0..43].find("ย中"), Some(24));
72 assert_eq!(data[0..43].find("iệt"), Some(34));
73 assert_eq!(data[0..43].find("Nam"), Some(40));
75 assert_eq!(data[43..86].find("ประ"), Some(43 - 43));
76 assert_eq!(data[43..86].find("ทศไ"), Some(55 - 43));
77 assert_eq!(data[43..86].find("ย中"), Some(67 - 43));
78 assert_eq!(data[43..86].find("iệt"), Some(77 - 43));
79 assert_eq!(data[43..86].find("Nam"), Some(83 - 43));
81 // find every substring -- assert that it finds it, or an earlier occurrence.
82 let string = "Việt Namacbaabcaabaaba";
83 for (i, ci) in string.char_indices() {
84 let ip = i + ci.len_utf8();
85 for j in string[ip..].char_indices().map(|(i, _)| i).chain(Some(string.len() - ip)) {
86 let pat = &string[i..ip + j];
87 assert!(match string.find(pat) {
91 assert!(match string.rfind(pat) {
99 fn s(x: &str) -> String {
103 macro_rules! test_concat {
104 ($expected: expr, $string: expr) => {{
105 let s: String = $string.concat();
106 assert_eq!($expected, s);
111 fn test_concat_for_different_types() {
112 test_concat!("ab", vec![s("a"), s("b")]);
113 test_concat!("ab", vec!["a", "b"]);
117 fn test_concat_for_different_lengths() {
118 let empty: &[&str] = &[];
119 test_concat!("", empty);
120 test_concat!("a", ["a"]);
121 test_concat!("ab", ["a", "b"]);
122 test_concat!("abc", ["", "a", "bc"]);
125 macro_rules! test_join {
126 ($expected: expr, $string: expr, $delim: expr) => {{
127 let s = $string.join($delim);
128 assert_eq!($expected, s);
133 fn test_join_for_different_types() {
134 test_join!("a-b", ["a", "b"], "-");
135 let hyphen = "-".to_string();
136 test_join!("a-b", [s("a"), s("b")], &*hyphen);
137 test_join!("a-b", vec!["a", "b"], &*hyphen);
138 test_join!("a-b", &*vec!["a", "b"], "-");
139 test_join!("a-b", vec![s("a"), s("b")], "-");
143 fn test_join_for_different_lengths() {
144 let empty: &[&str] = &[];
145 test_join!("", empty, "-");
146 test_join!("a", ["a"], "-");
147 test_join!("a-b", ["a", "b"], "-");
148 test_join!("-a-bc", ["", "a", "bc"], "-");
151 // join has fast paths for small separators up to 4 bytes
152 // this tests the slow paths.
154 fn test_join_for_different_lengths_with_long_separator() {
155 assert_eq!("~~~~~".len(), 15);
157 let empty: &[&str] = &[];
158 test_join!("", empty, "~~~~~");
159 test_join!("a", ["a"], "~~~~~");
160 test_join!("a~~~~~b", ["a", "b"], "~~~~~");
161 test_join!("~~~~~a~~~~~bc", ["", "a", "bc"], "~~~~~");
165 fn test_join_issue_80335() {
166 use core::{borrow::Borrow, cell::Cell};
172 impl Default for WeirdBorrow {
173 fn default() -> Self {
174 WeirdBorrow { state: Cell::new(false) }
178 impl Borrow<str> for WeirdBorrow {
179 fn borrow(&self) -> &str {
180 let state = self.state.get();
184 self.state.set(true);
190 let arr: [WeirdBorrow; 3] = Default::default();
191 test_join!("0-0-0", arr, "-");
195 #[cfg_attr(miri, ignore)] // Miri is too slow
196 fn test_unsafe_slice() {
197 assert_eq!("ab", unsafe { "abc".get_unchecked(0..2) });
198 assert_eq!("bc", unsafe { "abc".get_unchecked(1..3) });
199 assert_eq!("", unsafe { "abc".get_unchecked(1..1) });
200 fn a_million_letter_a() -> String {
202 let mut rs = String::new();
204 rs.push_str("aaaaaaaaaa");
209 fn half_a_million_letter_a() -> String {
211 let mut rs = String::new();
213 rs.push_str("aaaaa");
218 let letters = a_million_letter_a();
219 assert_eq!(half_a_million_letter_a(), unsafe { letters.get_unchecked(0..500000) });
223 fn test_starts_with() {
224 assert!("".starts_with(""));
225 assert!("abc".starts_with(""));
226 assert!("abc".starts_with("a"));
227 assert!(!"a".starts_with("abc"));
228 assert!(!"".starts_with("abc"));
229 assert!(!"ödd".starts_with("-"));
230 assert!("ödd".starts_with("öd"));
234 fn test_ends_with() {
235 assert!("".ends_with(""));
236 assert!("abc".ends_with(""));
237 assert!("abc".ends_with("c"));
238 assert!(!"a".ends_with("abc"));
239 assert!(!"".ends_with("abc"));
240 assert!(!"ddö".ends_with("-"));
241 assert!("ddö".ends_with("dö"));
246 assert!("".is_empty());
247 assert!(!"a".is_empty());
252 assert_eq!("".replacen('a', "b", 5), "");
253 assert_eq!("acaaa".replacen("a", "b", 3), "bcbba");
254 assert_eq!("aaaa".replacen("a", "b", 0), "aaaa");
257 assert_eq!(" test test ".replacen(test, "toast", 3), " toast toast ");
258 assert_eq!(" test test ".replacen(test, "toast", 0), " test test ");
259 assert_eq!(" test test ".replacen(test, "", 5), " ");
261 assert_eq!("qwer123zxc789".replacen(char::is_numeric, "", 3), "qwerzxc789");
267 assert_eq!("".replace(a, "b"), "");
268 assert_eq!("a".replace(a, "b"), "b");
269 assert_eq!("ab".replace(a, "b"), "bb");
271 assert_eq!(" test test ".replace(test, "toast"), " toast toast ");
272 assert_eq!(" test test ".replace(test, ""), " ");
276 fn test_replace_2a() {
277 let data = "ประเทศไทย中华";
278 let repl = "دولة الكويت";
281 let a2 = "دولة الكويتทศไทย中华";
282 assert_eq!(data.replace(a, repl), a2);
286 fn test_replace_2b() {
287 let data = "ประเทศไทย中华";
288 let repl = "دولة الكويت";
291 let b2 = "ปรدولة الكويتทศไทย中华";
292 assert_eq!(data.replace(b, repl), b2);
296 fn test_replace_2c() {
297 let data = "ประเทศไทย中华";
298 let repl = "دولة الكويت";
301 let c2 = "ประเทศไทยدولة الكويت";
302 assert_eq!(data.replace(c, repl), c2);
306 fn test_replace_2d() {
307 let data = "ประเทศไทย中华";
308 let repl = "دولة الكويت";
311 assert_eq!(data.replace(d, repl), data);
315 fn test_replace_pattern() {
316 let data = "abcdαβγδabcdαβγδ";
317 assert_eq!(data.replace("dαβ", "😺😺😺"), "abc😺😺😺γδabc😺😺😺γδ");
318 assert_eq!(data.replace('γ', "😺😺😺"), "abcdαβ😺😺😺δabcdαβ😺😺😺δ");
319 assert_eq!(data.replace(&['a', 'γ'] as &[_], "😺😺😺"), "😺😺😺bcdαβ😺😺😺δ😺😺😺bcdαβ😺😺😺δ");
320 assert_eq!(data.replace(|c| c == 'γ', "😺😺😺"), "abcdαβ😺😺😺δabcdαβ😺😺😺δ");
323 // The current implementation of SliceIndex fails to handle methods
324 // orthogonally from range types; therefore, it is worth testing
325 // all of the indexing operations on each input.
327 // Test a slicing operation **that should succeed,**
328 // testing it on all of the indexing methods.
330 // This is not suitable for testing failure on invalid inputs.
331 macro_rules! assert_range_eq {
332 ($s:expr, $range:expr, $expected:expr) => {
333 let mut s: String = $s.to_owned();
334 let mut expected: String = $expected.to_owned();
337 let expected: &str = &expected;
339 assert_eq!(&s[$range], expected, "(in assertion for: index)");
340 assert_eq!(s.get($range), Some(expected), "(in assertion for: get)");
343 s.get_unchecked($range),
345 "(in assertion for: get_unchecked)",
350 let s: &mut str = &mut s;
351 let expected: &mut str = &mut expected;
353 assert_eq!(&mut s[$range], expected, "(in assertion for: index_mut)",);
356 Some(&mut expected[..]),
357 "(in assertion for: get_mut)",
361 s.get_unchecked_mut($range),
363 "(in assertion for: get_unchecked_mut)",
370 // Make sure the macro can actually detect bugs,
371 // because if it can't, then what are we even doing here?
373 // (Be aware this only demonstrates the ability to detect bugs
374 // in the FIRST method that panics, as the macro is not designed
375 // to be used in `should_panic`)
377 #[should_panic(expected = "out of bounds")]
378 fn assert_range_eq_can_fail_by_panic() {
379 assert_range_eq!("abc", 0..5, "abc");
382 // (Be aware this only demonstrates the ability to detect bugs
383 // in the FIRST method it calls, as the macro is not designed
384 // to be used in `should_panic`)
386 #[should_panic(expected = "==")]
387 fn assert_range_eq_can_fail_by_inequality() {
388 assert_range_eq!("abc", 0..2, "abc");
391 // Generates test cases for bad index operations.
393 // This generates `should_panic` test cases for Index/IndexMut
394 // and `None` test cases for get/get_mut.
395 macro_rules! panic_cases {
397 in mod $case_name:ident {
402 // a similar input for which DATA[input] succeeds, and the corresponding
403 // output str. This helps validate "critical points" where an input range
404 // straddles the boundary between valid and invalid.
405 // (such as the input `len..len`, which is just barely valid)
407 good: data[$good:expr] == $output:expr;
410 bad: data[$bad:expr];
411 message: $expect_msg:expr; // must be a literal
417 let mut v: String = $data.into();
419 $( assert_range_eq!(v, $good, $output); )*
423 assert_eq!(v.get($bad), None, "(in None assertion for get)");
427 let v: &mut str = &mut v;
428 assert_eq!(v.get_mut($bad), None, "(in None assertion for get_mut)");
433 #[should_panic(expected = $expect_msg)]
435 let v: String = $data.into();
441 #[should_panic(expected = $expect_msg)]
442 fn index_mut_fail() {
443 let mut v: String = $data.into();
444 let v: &mut str = &mut v;
445 let _v = &mut v[$bad];
453 assert_range_eq!("abc", .., "abc");
455 assert_range_eq!("abc", 0..2, "ab");
456 assert_range_eq!("abc", 0..=1, "ab");
457 assert_range_eq!("abc", ..2, "ab");
458 assert_range_eq!("abc", ..=1, "ab");
460 assert_range_eq!("abc", 1..3, "bc");
461 assert_range_eq!("abc", 1..=2, "bc");
462 assert_range_eq!("abc", 1..1, "");
463 assert_range_eq!("abc", 1..=0, "");
467 fn simple_unicode() {
469 assert_range_eq!("\u{65e5}\u{672c}", .., "\u{65e5}\u{672c}");
471 assert_range_eq!("\u{65e5}\u{672c}", 0..3, "\u{65e5}");
472 assert_range_eq!("\u{65e5}\u{672c}", 0..=2, "\u{65e5}");
473 assert_range_eq!("\u{65e5}\u{672c}", ..3, "\u{65e5}");
474 assert_range_eq!("\u{65e5}\u{672c}", ..=2, "\u{65e5}");
476 assert_range_eq!("\u{65e5}\u{672c}", 3..6, "\u{672c}");
477 assert_range_eq!("\u{65e5}\u{672c}", 3..=5, "\u{672c}");
478 assert_range_eq!("\u{65e5}\u{672c}", 3.., "\u{672c}");
480 let data = "ประเทศไทย中华";
481 assert_range_eq!(data, 0..3, "ป");
482 assert_range_eq!(data, 3..6, "ร");
483 assert_range_eq!(data, 3..3, "");
484 assert_range_eq!(data, 30..33, "华");
496 let ss = "中华Việt Nam";
497 assert_range_eq!(ss, 3..6, "华");
498 assert_range_eq!(ss, 6..16, "Việt Nam");
499 assert_range_eq!(ss, 6..=15, "Việt Nam");
500 assert_range_eq!(ss, 6.., "Việt Nam");
502 assert_range_eq!(ss, 0..3, "中");
503 assert_range_eq!(ss, 3..7, "华V");
504 assert_range_eq!(ss, 3..=6, "华V");
505 assert_range_eq!(ss, 3..3, "");
506 assert_range_eq!(ss, 3..=2, "");
510 #[cfg_attr(target_os = "emscripten", ignore)] // hits an OOM
511 #[cfg_attr(miri, ignore)] // Miri is too slow
513 fn a_million_letter_x() -> String {
515 let mut rs = String::new();
517 rs.push_str("华华华华华华华华华华");
522 fn half_a_million_letter_x() -> String {
524 let mut rs = String::new();
526 rs.push_str("华华华华华");
531 let letters = a_million_letter_x();
532 assert_range_eq!(letters, 0..3 * 500000, half_a_million_letter_x());
537 fn test_slice_fail() {
538 let _ = &"中华Việt Nam"[0..2];
542 in mod rangefrom_len {
544 good: data[6..] == "";
546 message: "out of bounds";
551 good: data[..6] == "abcdef";
553 message: "out of bounds";
556 in mod rangetoinclusive_len {
558 good: data[..=5] == "abcdef";
560 message: "out of bounds";
563 in mod rangeinclusive_len {
565 good: data[0..=5] == "abcdef";
567 message: "out of bounds";
570 in mod range_len_len {
572 good: data[6..6] == "";
574 message: "out of bounds";
577 in mod rangeinclusive_len_len {
579 good: data[6..=5] == "";
581 message: "out of bounds";
586 in mod rangeinclusive_exhausted {
589 good: data[0..=5] == "abcdef";
591 let mut iter = 0..=5;
592 iter.by_ref().count(); // exhaust it
596 // 0..=6 is out of bounds before exhaustion, so it
597 // stands to reason that it still would be after.
599 let mut iter = 0..=6;
600 iter.by_ref().count(); // exhaust it
603 message: "out of bounds";
608 in mod range_neg_width {
610 good: data[4..4] == "";
612 message: "begin <= end (4 <= 3)";
615 in mod rangeinclusive_neg_width {
617 good: data[4..=3] == "";
619 message: "begin <= end (4 <= 3)";
625 in mod rangeinclusive {
627 // note: using 0 specifically ensures that the result of overflowing is 0..0,
628 // so that `get` doesn't simply return None for the wrong reason.
629 bad: data[0..=usize::MAX];
630 message: "maximum usize";
633 in mod rangetoinclusive {
635 bad: data[..=usize::MAX];
636 message: "maximum usize";
642 const DATA: &str = "abcαβγ";
644 const BAD_START: usize = 4;
645 const GOOD_START: usize = 3;
646 const BAD_END: usize = 6;
647 const GOOD_END: usize = 7;
648 const BAD_END_INCL: usize = BAD_END - 1;
649 const GOOD_END_INCL: usize = GOOD_END - 1;
651 // it is especially important to test all of the different range types here
652 // because some of the logic may be duplicated as part of micro-optimizations
653 // to dodge unicode boundary checks on half-ranges.
657 bad: data[super::BAD_START..super::GOOD_END];
659 "byte index 4 is not a char boundary; it is inside 'α' (bytes 3..5) of";
664 bad: data[super::GOOD_START..super::BAD_END];
666 "byte index 6 is not a char boundary; it is inside 'β' (bytes 5..7) of";
671 bad: data[super::BAD_START..];
673 "byte index 4 is not a char boundary; it is inside 'α' (bytes 3..5) of";
678 bad: data[..super::BAD_END];
680 "byte index 6 is not a char boundary; it is inside 'β' (bytes 5..7) of";
683 in mod rangeinclusive_1 {
685 bad: data[super::BAD_START..=super::GOOD_END_INCL];
687 "byte index 4 is not a char boundary; it is inside 'α' (bytes 3..5) of";
690 in mod rangeinclusive_2 {
692 bad: data[super::GOOD_START..=super::BAD_END_INCL];
694 "byte index 6 is not a char boundary; it is inside 'β' (bytes 5..7) of";
697 in mod rangetoinclusive {
699 bad: data[..=super::BAD_END_INCL];
701 "byte index 6 is not a char boundary; it is inside 'β' (bytes 5..7) of";
706 const LOREM_PARAGRAPH: &str = "\
707 Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse quis lorem \
708 sit amet dolor ultricies condimentum. Praesent iaculis purus elit, ac malesuada \
709 quam malesuada in. Duis sed orci eros. Suspendisse sit amet magna mollis, mollis \
710 nunc luctus, imperdiet mi. Integer fringilla non sem ut lacinia. Fusce varius \
711 tortor a risus porttitor hendrerit. Morbi mauris dui, ultricies nec tempus vel, \
714 // check the panic includes the prefix of the sliced string
716 #[should_panic(expected = "byte index 1024 is out of bounds of `Lorem ipsum dolor sit amet")]
717 fn test_slice_fail_truncated_1() {
718 let _ = &LOREM_PARAGRAPH[..1024];
720 // check the truncation in the panic message
722 #[should_panic(expected = "luctus, im`[...]")]
723 fn test_slice_fail_truncated_2() {
724 let _ = &LOREM_PARAGRAPH[..1024];
729 fn test_str_slice_rangetoinclusive_ok() {
731 assert_eq!(&s[..=2], "abc");
732 assert_eq!(&s[..=4], "abcα");
737 fn test_str_slice_rangetoinclusive_notok() {
743 fn test_str_slicemut_rangetoinclusive_ok() {
744 let mut s = "abcαβγ".to_owned();
745 let s: &mut str = &mut s;
746 assert_eq!(&mut s[..=2], "abc");
747 assert_eq!(&mut s[..=4], "abcα");
752 fn test_str_slicemut_rangetoinclusive_notok() {
753 let mut s = "abcαβγ".to_owned();
754 let s: &mut str = &mut s;
755 let _ = &mut s[..=3];
759 fn test_is_char_boundary() {
760 let s = "ศไทย中华Việt Nam β-release 🐱123";
761 assert!(s.is_char_boundary(0));
762 assert!(s.is_char_boundary(s.len()));
763 assert!(!s.is_char_boundary(s.len() + 1));
764 for (i, ch) in s.char_indices() {
765 // ensure character locations are boundaries and continuation bytes are not
766 assert!(s.is_char_boundary(i), "{} is a char boundary in {:?}", i, s);
767 for j in 1..ch.len_utf8() {
769 !s.is_char_boundary(i + j),
770 "{} should not be a char boundary in {:?}",
779 fn test_trim_start_matches() {
780 let v: &[char] = &[];
781 assert_eq!(" *** foo *** ".trim_start_matches(v), " *** foo *** ");
782 let chars: &[char] = &['*', ' '];
783 assert_eq!(" *** foo *** ".trim_start_matches(chars), "foo *** ");
784 assert_eq!(" *** *** ".trim_start_matches(chars), "");
785 assert_eq!("foo *** ".trim_start_matches(chars), "foo *** ");
787 assert_eq!("11foo1bar11".trim_start_matches('1'), "foo1bar11");
788 let chars: &[char] = &['1', '2'];
789 assert_eq!("12foo1bar12".trim_start_matches(chars), "foo1bar12");
790 assert_eq!("123foo1bar123".trim_start_matches(|c: char| c.is_numeric()), "foo1bar123");
794 fn test_trim_end_matches() {
795 let v: &[char] = &[];
796 assert_eq!(" *** foo *** ".trim_end_matches(v), " *** foo *** ");
797 let chars: &[char] = &['*', ' '];
798 assert_eq!(" *** foo *** ".trim_end_matches(chars), " *** foo");
799 assert_eq!(" *** *** ".trim_end_matches(chars), "");
800 assert_eq!(" *** foo".trim_end_matches(chars), " *** foo");
802 assert_eq!("11foo1bar11".trim_end_matches('1'), "11foo1bar");
803 let chars: &[char] = &['1', '2'];
804 assert_eq!("12foo1bar12".trim_end_matches(chars), "12foo1bar");
805 assert_eq!("123foo1bar123".trim_end_matches(|c: char| c.is_numeric()), "123foo1bar");
809 fn test_trim_matches() {
810 let v: &[char] = &[];
811 assert_eq!(" *** foo *** ".trim_matches(v), " *** foo *** ");
812 let chars: &[char] = &['*', ' '];
813 assert_eq!(" *** foo *** ".trim_matches(chars), "foo");
814 assert_eq!(" *** *** ".trim_matches(chars), "");
815 assert_eq!("foo".trim_matches(chars), "foo");
817 assert_eq!("11foo1bar11".trim_matches('1'), "foo1bar");
818 let chars: &[char] = &['1', '2'];
819 assert_eq!("12foo1bar12".trim_matches(chars), "foo1bar");
820 assert_eq!("123foo1bar123".trim_matches(|c: char| c.is_numeric()), "foo1bar");
824 fn test_trim_start() {
825 assert_eq!("".trim_start(), "");
826 assert_eq!("a".trim_start(), "a");
827 assert_eq!(" ".trim_start(), "");
828 assert_eq!(" blah".trim_start(), "blah");
829 assert_eq!(" \u{3000} wut".trim_start(), "wut");
830 assert_eq!("hey ".trim_start(), "hey ");
835 assert_eq!("".trim_end(), "");
836 assert_eq!("a".trim_end(), "a");
837 assert_eq!(" ".trim_end(), "");
838 assert_eq!("blah ".trim_end(), "blah");
839 assert_eq!("wut \u{3000} ".trim_end(), "wut");
840 assert_eq!(" hey".trim_end(), " hey");
845 assert_eq!("".trim(), "");
846 assert_eq!("a".trim(), "a");
847 assert_eq!(" ".trim(), "");
848 assert_eq!(" blah ".trim(), "blah");
849 assert_eq!("\nwut \u{3000} ".trim(), "wut");
850 assert_eq!(" hey dude ".trim(), "hey dude");
854 fn test_is_whitespace() {
855 assert!("".chars().all(|c| c.is_whitespace()));
856 assert!(" ".chars().all(|c| c.is_whitespace()));
857 assert!("\u{2009}".chars().all(|c| c.is_whitespace())); // Thin space
858 assert!(" \n\t ".chars().all(|c| c.is_whitespace()));
859 assert!(!" _ ".chars().all(|c| c.is_whitespace()));
864 // deny overlong encodings
865 assert!(from_utf8(&[0xc0, 0x80]).is_err());
866 assert!(from_utf8(&[0xc0, 0xae]).is_err());
867 assert!(from_utf8(&[0xe0, 0x80, 0x80]).is_err());
868 assert!(from_utf8(&[0xe0, 0x80, 0xaf]).is_err());
869 assert!(from_utf8(&[0xe0, 0x81, 0x81]).is_err());
870 assert!(from_utf8(&[0xf0, 0x82, 0x82, 0xac]).is_err());
871 assert!(from_utf8(&[0xf4, 0x90, 0x80, 0x80]).is_err());
874 assert!(from_utf8(&[0xED, 0xA0, 0x80]).is_err());
875 assert!(from_utf8(&[0xED, 0xBF, 0xBF]).is_err());
877 assert!(from_utf8(&[0xC2, 0x80]).is_ok());
878 assert!(from_utf8(&[0xDF, 0xBF]).is_ok());
879 assert!(from_utf8(&[0xE0, 0xA0, 0x80]).is_ok());
880 assert!(from_utf8(&[0xED, 0x9F, 0xBF]).is_ok());
881 assert!(from_utf8(&[0xEE, 0x80, 0x80]).is_ok());
882 assert!(from_utf8(&[0xEF, 0xBF, 0xBF]).is_ok());
883 assert!(from_utf8(&[0xF0, 0x90, 0x80, 0x80]).is_ok());
884 assert!(from_utf8(&[0xF4, 0x8F, 0xBF, 0xBF]).is_ok());
888 fn test_const_is_utf8() {
890 // deny overlong encodings
891 assert!(from_utf8(&[0xc0, 0x80]).is_err());
892 assert!(from_utf8(&[0xc0, 0xae]).is_err());
893 assert!(from_utf8(&[0xe0, 0x80, 0x80]).is_err());
894 assert!(from_utf8(&[0xe0, 0x80, 0xaf]).is_err());
895 assert!(from_utf8(&[0xe0, 0x81, 0x81]).is_err());
896 assert!(from_utf8(&[0xf0, 0x82, 0x82, 0xac]).is_err());
897 assert!(from_utf8(&[0xf4, 0x90, 0x80, 0x80]).is_err());
900 assert!(from_utf8(&[0xED, 0xA0, 0x80]).is_err());
901 assert!(from_utf8(&[0xED, 0xBF, 0xBF]).is_err());
903 assert!(from_utf8(&[0xC2, 0x80]).is_ok());
904 assert!(from_utf8(&[0xDF, 0xBF]).is_ok());
905 assert!(from_utf8(&[0xE0, 0xA0, 0x80]).is_ok());
906 assert!(from_utf8(&[0xED, 0x9F, 0xBF]).is_ok());
907 assert!(from_utf8(&[0xEE, 0x80, 0x80]).is_ok());
908 assert!(from_utf8(&[0xEF, 0xBF, 0xBF]).is_ok());
909 assert!(from_utf8(&[0xF0, 0x90, 0x80, 0x80]).is_ok());
910 assert!(from_utf8(&[0xF4, 0x8F, 0xBF, 0xBF]).is_ok());
915 fn from_utf8_mostly_ascii() {
916 // deny invalid bytes embedded in long stretches of ascii
918 let mut data = [0; 128];
920 assert!(from_utf8(&data).is_err());
922 assert!(from_utf8(&data).is_err());
927 fn const_from_utf8_mostly_ascii() {
929 // deny invalid bytes embedded in long stretches of ascii
932 let mut data = [0; 128];
934 assert!(from_utf8(&data).is_err());
936 assert!(from_utf8(&data).is_err());
944 fn from_utf8_error() {
946 ($input: expr, $expected_valid_up_to:pat, $expected_error_len:pat) => {
947 let error = from_utf8($input).unwrap_err();
948 assert_matches!(error.valid_up_to(), $expected_valid_up_to);
949 assert_matches!(error.error_len(), $expected_error_len);
952 match from_utf8($input) {
954 let valid_up_to = error.valid_up_to();
955 let error_len = error.error_len();
957 assert!(matches!(valid_up_to, $expected_valid_up_to));
958 assert!(matches!(error_len, $expected_error_len));
960 Ok(_) => unreachable!(),
965 test!(b"A\xC3\xA9 \xFF ", 4, Some(1));
966 test!(b"A\xC3\xA9 \x80 ", 4, Some(1));
967 test!(b"A\xC3\xA9 \xC1 ", 4, Some(1));
968 test!(b"A\xC3\xA9 \xC1", 4, Some(1));
969 test!(b"A\xC3\xA9 \xC2", 4, None);
970 test!(b"A\xC3\xA9 \xC2 ", 4, Some(1));
971 test!(b"A\xC3\xA9 \xC2\xC0", 4, Some(1));
972 test!(b"A\xC3\xA9 \xE0", 4, None);
973 test!(b"A\xC3\xA9 \xE0\x9F", 4, Some(1));
974 test!(b"A\xC3\xA9 \xE0\xA0", 4, None);
975 test!(b"A\xC3\xA9 \xE0\xA0\xC0", 4, Some(2));
976 test!(b"A\xC3\xA9 \xE0\xA0 ", 4, Some(2));
977 test!(b"A\xC3\xA9 \xED\xA0\x80 ", 4, Some(1));
978 test!(b"A\xC3\xA9 \xF1", 4, None);
979 test!(b"A\xC3\xA9 \xF1\x80", 4, None);
980 test!(b"A\xC3\xA9 \xF1\x80\x80", 4, None);
981 test!(b"A\xC3\xA9 \xF1 ", 4, Some(1));
982 test!(b"A\xC3\xA9 \xF1\x80 ", 4, Some(2));
983 test!(b"A\xC3\xA9 \xF1\x80\x80 ", 4, Some(3));
990 224, 184, 168, 224, 185, 132, 224, 184, 151, 224, 184, 162, 228, 184, 173, 229, 141, 142,
991 86, 105, 225, 187, 135, 116, 32, 78, 97, 109,
994 assert_eq!("".as_bytes(), b);
995 assert_eq!("abc".as_bytes(), b"abc");
996 assert_eq!("ศไทย中华Việt Nam".as_bytes(), v);
1001 fn test_as_bytes_fail() {
1002 // Don't double free. (I'm not sure if this exercises the
1003 // original problem code path anymore.)
1004 let s = String::from("");
1005 let _bytes = s.as_bytes();
1011 let buf = "hello".as_ptr();
1013 assert_eq!(*buf.add(0), b'h');
1014 assert_eq!(*buf.add(1), b'e');
1015 assert_eq!(*buf.add(2), b'l');
1016 assert_eq!(*buf.add(3), b'l');
1017 assert_eq!(*buf.add(4), b'o');
1022 fn vec_str_conversions() {
1023 let s1: String = String::from("All mimsy were the borogoves");
1025 let v: Vec<u8> = s1.as_bytes().to_vec();
1026 let s2: String = String::from(from_utf8(&v).unwrap());
1032 let a: u8 = s1.as_bytes()[i];
1033 let b: u8 = s2.as_bytes()[i];
1040 fn test_contains() {
1041 assert!("abcde".contains("bcd"));
1042 assert!("abcde".contains("abcd"));
1043 assert!("abcde".contains("bcde"));
1044 assert!("abcde".contains(""));
1045 assert!("".contains(""));
1046 assert!(!"abcde".contains("def"));
1047 assert!(!"".contains("a"));
1049 let data = "ประเทศไทย中华Việt Nam";
1050 assert!(data.contains("ประเ"));
1051 assert!(data.contains("ะเ"));
1052 assert!(data.contains("中华"));
1053 assert!(!data.contains("ไท华"));
1057 fn test_contains_char() {
1058 assert!("abc".contains('b'));
1059 assert!("a".contains('a'));
1060 assert!(!"abc".contains('d'));
1061 assert!(!"".contains('a'));
1065 fn test_split_at() {
1066 let s = "ศไทย中华Việt Nam";
1067 for (index, _) in s.char_indices() {
1068 let (a, b) = s.split_at(index);
1069 assert_eq!(&s[..a.len()], a);
1070 assert_eq!(&s[a.len()..], b);
1072 let (a, b) = s.split_at(s.len());
1078 fn test_split_at_mut() {
1079 let mut s = "Hello World".to_string();
1081 let (a, b) = s.split_at_mut(5);
1082 a.make_ascii_uppercase();
1083 b.make_ascii_lowercase();
1085 assert_eq!(s, "HELLO world");
1090 fn test_split_at_boundscheck() {
1091 let s = "ศไทย中华Việt Nam";
1092 let _ = s.split_at(1);
1096 fn test_escape_unicode() {
1097 assert_eq!("abc".escape_unicode().to_string(), "\\u{61}\\u{62}\\u{63}");
1098 assert_eq!("a c".escape_unicode().to_string(), "\\u{61}\\u{20}\\u{63}");
1099 assert_eq!("\r\n\t".escape_unicode().to_string(), "\\u{d}\\u{a}\\u{9}");
1100 assert_eq!("'\"\\".escape_unicode().to_string(), "\\u{27}\\u{22}\\u{5c}");
1101 assert_eq!("\x00\x01\u{fe}\u{ff}".escape_unicode().to_string(), "\\u{0}\\u{1}\\u{fe}\\u{ff}");
1102 assert_eq!("\u{100}\u{ffff}".escape_unicode().to_string(), "\\u{100}\\u{ffff}");
1103 assert_eq!("\u{10000}\u{10ffff}".escape_unicode().to_string(), "\\u{10000}\\u{10ffff}");
1104 assert_eq!("ab\u{fb00}".escape_unicode().to_string(), "\\u{61}\\u{62}\\u{fb00}");
1105 assert_eq!("\u{1d4ea}\r".escape_unicode().to_string(), "\\u{1d4ea}\\u{d}");
1109 fn test_escape_debug() {
1110 // Note that there are subtleties with the number of backslashes
1111 // on the left- and right-hand sides. In particular, Unicode code points
1112 // are usually escaped with two backslashes on the right-hand side, as
1113 // they are escaped. However, when the character is unescaped (e.g., for
1114 // printable characters), only a single backslash appears (as the character
1115 // itself appears in the debug string).
1116 assert_eq!("abc".escape_debug().to_string(), "abc");
1117 assert_eq!("a c".escape_debug().to_string(), "a c");
1118 assert_eq!("éèê".escape_debug().to_string(), "éèê");
1119 assert_eq!("\0\r\n\t".escape_debug().to_string(), "\\0\\r\\n\\t");
1120 assert_eq!("'\"\\".escape_debug().to_string(), "\\'\\\"\\\\");
1121 assert_eq!("\u{7f}\u{ff}".escape_debug().to_string(), "\\u{7f}\u{ff}");
1122 assert_eq!("\u{100}\u{ffff}".escape_debug().to_string(), "\u{100}\\u{ffff}");
1123 assert_eq!("\u{10000}\u{10ffff}".escape_debug().to_string(), "\u{10000}\\u{10ffff}");
1124 assert_eq!("ab\u{200b}".escape_debug().to_string(), "ab\\u{200b}");
1125 assert_eq!("\u{10d4ea}\r".escape_debug().to_string(), "\\u{10d4ea}\\r");
1127 "\u{301}a\u{301}bé\u{e000}".escape_debug().to_string(),
1128 "\\u{301}a\u{301}bé\\u{e000}"
1133 fn test_escape_default() {
1134 assert_eq!("abc".escape_default().to_string(), "abc");
1135 assert_eq!("a c".escape_default().to_string(), "a c");
1136 assert_eq!("éèê".escape_default().to_string(), "\\u{e9}\\u{e8}\\u{ea}");
1137 assert_eq!("\r\n\t".escape_default().to_string(), "\\r\\n\\t");
1138 assert_eq!("'\"\\".escape_default().to_string(), "\\'\\\"\\\\");
1139 assert_eq!("\u{7f}\u{ff}".escape_default().to_string(), "\\u{7f}\\u{ff}");
1140 assert_eq!("\u{100}\u{ffff}".escape_default().to_string(), "\\u{100}\\u{ffff}");
1141 assert_eq!("\u{10000}\u{10ffff}".escape_default().to_string(), "\\u{10000}\\u{10ffff}");
1142 assert_eq!("ab\u{200b}".escape_default().to_string(), "ab\\u{200b}");
1143 assert_eq!("\u{10d4ea}\r".escape_default().to_string(), "\\u{10d4ea}\\r");
1147 fn test_total_ord() {
1148 assert_eq!("1234".cmp("123"), Greater);
1149 assert_eq!("123".cmp("1234"), Less);
1150 assert_eq!("1234".cmp("1234"), Equal);
1151 assert_eq!("12345555".cmp("123456"), Less);
1152 assert_eq!("22".cmp("1234"), Greater);
1156 fn test_iterator() {
1157 let s = "ศไทย中华Việt Nam";
1158 let v = ['ศ', 'ไ', 'ท', 'ย', '中', '华', 'V', 'i', 'ệ', 't', ' ', 'N', 'a', 'm'];
1164 assert_eq!(c, v[pos]);
1167 assert_eq!(pos, v.len());
1168 assert_eq!(s.chars().count(), v.len());
1172 fn test_rev_iterator() {
1173 let s = "ศไทย中华Việt Nam";
1174 let v = ['m', 'a', 'N', ' ', 't', 'ệ', 'i', 'V', '华', '中', 'ย', 'ท', 'ไ', 'ศ'];
1177 let it = s.chars().rev();
1180 assert_eq!(c, v[pos]);
1183 assert_eq!(pos, v.len());
1187 fn test_to_lowercase_rev_iterator() {
1188 let s = "AÖßÜ💩ΣΤΙΓΜΑΣDžfiİ";
1189 let v = ['\u{307}', 'i', 'fi', 'dž', 'σ', 'α', 'μ', 'γ', 'ι', 'τ', 'σ', '💩', 'ü', 'ß', 'ö', 'a'];
1192 let it = s.chars().flat_map(|c| c.to_lowercase()).rev();
1195 assert_eq!(c, v[pos]);
1198 assert_eq!(pos, v.len());
1202 fn test_to_uppercase_rev_iterator() {
1203 let s = "aößü💩στιγμαςDžfiᾀ";
1205 ['Ι', 'Ἀ', 'I', 'F', 'DŽ', 'Σ', 'Α', 'Μ', 'Γ', 'Ι', 'Τ', 'Σ', '💩', 'Ü', 'S', 'S', 'Ö', 'A'];
1208 let it = s.chars().flat_map(|c| c.to_uppercase()).rev();
1211 assert_eq!(c, v[pos]);
1214 assert_eq!(pos, v.len());
1218 #[cfg_attr(miri, ignore)] // Miri is too slow
1219 fn test_chars_decoding() {
1220 let mut bytes = [0; 4];
1221 for c in (0..0x110000).filter_map(std::char::from_u32) {
1222 let s = c.encode_utf8(&mut bytes);
1223 if Some(c) != s.chars().next() {
1224 panic!("character {:x}={} does not decode correctly", c as u32, c);
1230 #[cfg_attr(miri, ignore)] // Miri is too slow
1231 fn test_chars_rev_decoding() {
1232 let mut bytes = [0; 4];
1233 for c in (0..0x110000).filter_map(std::char::from_u32) {
1234 let s = c.encode_utf8(&mut bytes);
1235 if Some(c) != s.chars().rev().next() {
1236 panic!("character {:x}={} does not decode correctly", c as u32, c);
1242 fn test_iterator_clone() {
1243 let s = "ศไทย中华Việt Nam";
1244 let mut it = s.chars();
1246 assert!(it.clone().zip(it).all(|(x, y)| x == y));
1250 fn test_iterator_last() {
1251 let s = "ศไทย中华Việt Nam";
1252 let mut it = s.chars();
1254 assert_eq!(it.last(), Some('m'));
1258 fn test_chars_debug() {
1259 let s = "ศไทย中华Việt Nam";
1263 r#"Chars(['ศ', 'ไ', 'ท', 'ย', '中', '华', 'V', 'i', 'ệ', 't', ' ', 'N', 'a', 'm'])"#
1268 fn test_bytesator() {
1269 let s = "ศไทย中华Việt Nam";
1271 224, 184, 168, 224, 185, 132, 224, 184, 151, 224, 184, 162, 228, 184, 173, 229, 141, 142,
1272 86, 105, 225, 187, 135, 116, 32, 78, 97, 109,
1276 for b in s.bytes() {
1277 assert_eq!(b, v[pos]);
1283 fn test_bytes_revator() {
1284 let s = "ศไทย中华Việt Nam";
1286 224, 184, 168, 224, 185, 132, 224, 184, 151, 224, 184, 162, 228, 184, 173, 229, 141, 142,
1287 86, 105, 225, 187, 135, 116, 32, 78, 97, 109,
1289 let mut pos = v.len();
1291 for b in s.bytes().rev() {
1293 assert_eq!(b, v[pos]);
1298 fn test_bytesator_nth() {
1299 let s = "ศไทย中华Việt Nam";
1301 224, 184, 168, 224, 185, 132, 224, 184, 151, 224, 184, 162, 228, 184, 173, 229, 141, 142,
1302 86, 105, 225, 187, 135, 116, 32, 78, 97, 109,
1305 let mut b = s.bytes();
1306 assert_eq!(b.nth(2).unwrap(), v[2]);
1307 assert_eq!(b.nth(10).unwrap(), v[10]);
1308 assert_eq!(b.nth(200), None);
1312 fn test_bytesator_count() {
1313 let s = "ศไทย中华Việt Nam";
1316 assert_eq!(b.count(), 28)
1320 fn test_bytesator_last() {
1321 let s = "ศไทย中华Việt Nam";
1324 assert_eq!(b.last().unwrap(), 109)
1328 fn test_char_indicesator() {
1329 let s = "ศไทย中华Việt Nam";
1330 let p = [0, 3, 6, 9, 12, 15, 18, 19, 20, 23, 24, 25, 26, 27];
1331 let v = ['ศ', 'ไ', 'ท', 'ย', '中', '华', 'V', 'i', 'ệ', 't', ' ', 'N', 'a', 'm'];
1334 let it = s.char_indices();
1337 assert_eq!(c, (p[pos], v[pos]));
1340 assert_eq!(pos, v.len());
1341 assert_eq!(pos, p.len());
1345 fn test_char_indices_revator() {
1346 let s = "ศไทย中华Việt Nam";
1347 let p = [27, 26, 25, 24, 23, 20, 19, 18, 15, 12, 9, 6, 3, 0];
1348 let v = ['m', 'a', 'N', ' ', 't', 'ệ', 'i', 'V', '华', '中', 'ย', 'ท', 'ไ', 'ศ'];
1351 let it = s.char_indices().rev();
1354 assert_eq!(c, (p[pos], v[pos]));
1357 assert_eq!(pos, v.len());
1358 assert_eq!(pos, p.len());
1362 fn test_char_indices_last() {
1363 let s = "ศไทย中华Việt Nam";
1364 let mut it = s.char_indices();
1366 assert_eq!(it.last(), Some((27, 'm')));
1370 fn test_splitn_char_iterator() {
1371 let data = "\nMäry häd ä little lämb\nLittle lämb\n";
1373 let split: Vec<&str> = data.splitn(4, ' ').collect();
1374 assert_eq!(split, ["\nMäry", "häd", "ä", "little lämb\nLittle lämb\n"]);
1376 let split: Vec<&str> = data.splitn(4, |c: char| c == ' ').collect();
1377 assert_eq!(split, ["\nMäry", "häd", "ä", "little lämb\nLittle lämb\n"]);
1380 let split: Vec<&str> = data.splitn(4, 'ä').collect();
1381 assert_eq!(split, ["\nM", "ry h", "d ", " little lämb\nLittle lämb\n"]);
1383 let split: Vec<&str> = data.splitn(4, |c: char| c == 'ä').collect();
1384 assert_eq!(split, ["\nM", "ry h", "d ", " little lämb\nLittle lämb\n"]);
1388 fn test_split_char_iterator_no_trailing() {
1389 let data = "\nMäry häd ä little lämb\nLittle lämb\n";
1391 let split: Vec<&str> = data.split('\n').collect();
1392 assert_eq!(split, ["", "Märy häd ä little lämb", "Little lämb", ""]);
1394 let split: Vec<&str> = data.split_terminator('\n').collect();
1395 assert_eq!(split, ["", "Märy häd ä little lämb", "Little lämb"]);
1399 fn test_split_char_iterator_inclusive() {
1400 let data = "\nMäry häd ä little lämb\nLittle lämb\n";
1402 let split: Vec<&str> = data.split_inclusive('\n').collect();
1403 assert_eq!(split, ["\n", "Märy häd ä little lämb\n", "Little lämb\n"]);
1405 let uppercase_separated = "SheePSharKTurtlECaT";
1406 let mut first_char = true;
1407 let split: Vec<&str> = uppercase_separated
1408 .split_inclusive(|c: char| {
1409 let split = !first_char && c.is_uppercase();
1414 assert_eq!(split, ["SheeP", "SharK", "TurtlE", "CaT"]);
1418 fn test_split_char_iterator_inclusive_rev() {
1419 let data = "\nMäry häd ä little lämb\nLittle lämb\n";
1421 let split: Vec<&str> = data.split_inclusive('\n').rev().collect();
1422 assert_eq!(split, ["Little lämb\n", "Märy häd ä little lämb\n", "\n"]);
1424 // Note that the predicate is stateful and thus dependent
1425 // on the iteration order.
1426 // (A different predicate is needed for reverse iterator vs normal iterator.)
1427 // Not sure if anything can be done though.
1428 let uppercase_separated = "SheePSharKTurtlECaT";
1429 let mut term_char = true;
1430 let split: Vec<&str> = uppercase_separated
1431 .split_inclusive(|c: char| {
1432 let split = term_char && c.is_uppercase();
1433 term_char = c.is_uppercase();
1438 assert_eq!(split, ["CaT", "TurtlE", "SharK", "SheeP"]);
1443 let data = "\nMäry häd ä little lämb\nLittle lämb\n";
1445 let split: Vec<&str> = data.rsplit(' ').collect();
1446 assert_eq!(split, ["lämb\n", "lämb\nLittle", "little", "ä", "häd", "\nMäry"]);
1448 let split: Vec<&str> = data.rsplit("lämb").collect();
1449 assert_eq!(split, ["\n", "\nLittle ", "\nMäry häd ä little "]);
1451 let split: Vec<&str> = data.rsplit(|c: char| c == 'ä').collect();
1452 assert_eq!(split, ["mb\n", "mb\nLittle l", " little l", "d ", "ry h", "\nM"]);
1457 let data = "\nMäry häd ä little lämb\nLittle lämb\n";
1459 let split: Vec<&str> = data.rsplitn(2, ' ').collect();
1460 assert_eq!(split, ["lämb\n", "\nMäry häd ä little lämb\nLittle"]);
1462 let split: Vec<&str> = data.rsplitn(2, "lämb").collect();
1463 assert_eq!(split, ["\n", "\nMäry häd ä little lämb\nLittle "]);
1465 let split: Vec<&str> = data.rsplitn(2, |c: char| c == 'ä').collect();
1466 assert_eq!(split, ["mb\n", "\nMäry häd ä little lämb\nLittle l"]);
1470 fn test_split_once() {
1471 assert_eq!("".split_once("->"), None);
1472 assert_eq!("-".split_once("->"), None);
1473 assert_eq!("->".split_once("->"), Some(("", "")));
1474 assert_eq!("a->".split_once("->"), Some(("a", "")));
1475 assert_eq!("->b".split_once("->"), Some(("", "b")));
1476 assert_eq!("a->b".split_once("->"), Some(("a", "b")));
1477 assert_eq!("a->b->c".split_once("->"), Some(("a", "b->c")));
1478 assert_eq!("---".split_once("--"), Some(("", "-")));
1482 fn test_rsplit_once() {
1483 assert_eq!("".rsplit_once("->"), None);
1484 assert_eq!("-".rsplit_once("->"), None);
1485 assert_eq!("->".rsplit_once("->"), Some(("", "")));
1486 assert_eq!("a->".rsplit_once("->"), Some(("a", "")));
1487 assert_eq!("->b".rsplit_once("->"), Some(("", "b")));
1488 assert_eq!("a->b".rsplit_once("->"), Some(("a", "b")));
1489 assert_eq!("a->b->c".rsplit_once("->"), Some(("a->b", "c")));
1490 assert_eq!("---".rsplit_once("--"), Some(("-", "")));
1494 fn test_split_whitespace() {
1495 let data = "\n \tMäry häd\tä little lämb\nLittle lämb\n";
1496 let words: Vec<&str> = data.split_whitespace().collect();
1497 assert_eq!(words, ["Märy", "häd", "ä", "little", "lämb", "Little", "lämb"])
1502 let data = "\nMäry häd ä little lämb\n\r\nLittle lämb\n";
1503 let lines: Vec<&str> = data.lines().collect();
1504 assert_eq!(lines, ["", "Märy häd ä little lämb", "", "Little lämb"]);
1506 let data = "\r\nMäry häd ä little lämb\n\nLittle lämb"; // no trailing \n
1507 let lines: Vec<&str> = data.lines().collect();
1508 assert_eq!(lines, ["", "Märy häd ä little lämb", "", "Little lämb"]);
1512 fn test_splitator() {
1513 fn t(s: &str, sep: &str, u: &[&str]) {
1514 let v: Vec<&str> = s.split(sep).collect();
1517 t("--1233345--", "12345", &["--1233345--"]);
1518 t("abc::hello::there", "::", &["abc", "hello", "there"]);
1519 t("::hello::there", "::", &["", "hello", "there"]);
1520 t("hello::there::", "::", &["hello", "there", ""]);
1521 t("::hello::there::", "::", &["", "hello", "there", ""]);
1522 t("ประเทศไทย中华Việt Nam", "中华", &["ประเทศไทย", "Việt Nam"]);
1523 t("zzXXXzzYYYzz", "zz", &["", "XXX", "YYY", ""]);
1524 t("zzXXXzYYYz", "XXX", &["zz", "zYYYz"]);
1525 t(".XXX.YYY.", ".", &["", "XXX", "YYY", ""]);
1527 t("zz", "zz", &["", ""]);
1528 t("ok", "z", &["ok"]);
1529 t("zzz", "zz", &["", "z"]);
1530 t("zzzzz", "zz", &["", "", "z"]);
1534 fn test_str_default() {
1535 use std::default::Default;
1537 fn t<S: Default + AsRef<str>>() {
1538 let s: S = Default::default();
1539 assert_eq!(s.as_ref(), "");
1548 fn test_str_container() {
1549 fn sum_len(v: &[&str]) -> usize {
1550 v.iter().map(|x| x.len()).sum()
1554 assert_eq!(5, sum_len(&["012", "", "34"]));
1555 assert_eq!(5, sum_len(&["01", "2", "34", ""]));
1556 assert_eq!(5, sum_len(&[s]));
1560 fn test_str_from_utf8() {
1562 assert_eq!(from_utf8(xs), Ok("hello"));
1564 let xs = "ศไทย中华Việt Nam".as_bytes();
1565 assert_eq!(from_utf8(xs), Ok("ศไทย中华Việt Nam"));
1567 let xs = b"hello\xFF";
1568 assert!(from_utf8(xs).is_err());
1572 fn test_pattern_deref_forward() {
1573 let data = "aabcdaa";
1574 assert!(data.contains("bcd"));
1575 assert!(data.contains(&"bcd"));
1576 assert!(data.contains(&"bcd".to_string()));
1580 fn test_empty_match_indices() {
1582 let vec: Vec<_> = data.match_indices("").collect();
1583 assert_eq!(vec, [(0, ""), (1, ""), (3, ""), (6, ""), (7, "")]);
1587 fn test_bool_from_str() {
1588 assert_eq!("true".parse().ok(), Some(true));
1589 assert_eq!("false".parse().ok(), Some(false));
1590 assert_eq!("not even a boolean".parse::<bool>().ok(), None);
1593 fn check_contains_all_substrings(haystack: &str) {
1594 let mut modified_needle = String::new();
1596 for i in 0..haystack.len() {
1597 // check different haystack lengths since we special-case short haystacks.
1598 let haystack = &haystack[0..i];
1599 assert!(haystack.contains(""));
1600 for j in 0..haystack.len() {
1601 for k in j + 1..=haystack.len() {
1602 let needle = &haystack[j..k];
1603 assert!(haystack.contains(needle));
1604 modified_needle.clear();
1605 modified_needle.push_str(needle);
1606 modified_needle.replace_range(0..1, "\0");
1607 assert!(!haystack.contains(&modified_needle));
1609 modified_needle.clear();
1610 modified_needle.push_str(needle);
1611 modified_needle.replace_range(needle.len() - 1..needle.len(), "\0");
1612 assert!(!haystack.contains(&modified_needle));
1619 #[cfg_attr(miri, ignore)] // Miri is too slow
1620 fn strslice_issue_16589() {
1621 assert!("bananas".contains("nana"));
1623 // prior to the fix for #16589, x.contains("abcdabcd") returned false
1624 // test all substrings for good measure
1625 check_contains_all_substrings("012345678901234567890123456789bcdabcdabcd");
1629 fn strslice_issue_16878() {
1630 assert!(!"1234567ah012345678901ah".contains("hah"));
1631 assert!(!"00abc01234567890123456789abc".contains("bcabc"));
1635 fn strslice_issue_104726() {
1636 // Edge-case in the simd_contains impl.
1637 // The first and last byte are the same so it backtracks by one byte
1638 // which aligns with the end of the string. Previously incorrect offset calculations
1639 // lead to out-of-bounds slicing.
1641 let needle = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaba";
1642 let haystack = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaab";
1643 assert!(!haystack.contains(needle));
1647 #[cfg_attr(miri, ignore)] // Miri is too slow
1648 fn test_strslice_contains() {
1649 let x = "There are moments, Jeeves, when one asks oneself, 'Do trousers matter?'";
1650 check_contains_all_substrings(x);
1654 fn test_rsplitn_char_iterator() {
1655 let data = "\nMäry häd ä little lämb\nLittle lämb\n";
1657 let mut split: Vec<&str> = data.rsplitn(4, ' ').collect();
1659 assert_eq!(split, ["\nMäry häd ä", "little", "lämb\nLittle", "lämb\n"]);
1661 let mut split: Vec<&str> = data.rsplitn(4, |c: char| c == ' ').collect();
1663 assert_eq!(split, ["\nMäry häd ä", "little", "lämb\nLittle", "lämb\n"]);
1666 let mut split: Vec<&str> = data.rsplitn(4, 'ä').collect();
1668 assert_eq!(split, ["\nMäry häd ", " little l", "mb\nLittle l", "mb\n"]);
1670 let mut split: Vec<&str> = data.rsplitn(4, |c: char| c == 'ä').collect();
1672 assert_eq!(split, ["\nMäry häd ", " little l", "mb\nLittle l", "mb\n"]);
1676 fn test_split_char_iterator() {
1677 let data = "\nMäry häd ä little lämb\nLittle lämb\n";
1679 let split: Vec<&str> = data.split(' ').collect();
1680 assert_eq!(split, ["\nMäry", "häd", "ä", "little", "lämb\nLittle", "lämb\n"]);
1682 let mut rsplit: Vec<&str> = data.split(' ').rev().collect();
1684 assert_eq!(rsplit, ["\nMäry", "häd", "ä", "little", "lämb\nLittle", "lämb\n"]);
1686 let split: Vec<&str> = data.split(|c: char| c == ' ').collect();
1687 assert_eq!(split, ["\nMäry", "häd", "ä", "little", "lämb\nLittle", "lämb\n"]);
1689 let mut rsplit: Vec<&str> = data.split(|c: char| c == ' ').rev().collect();
1691 assert_eq!(rsplit, ["\nMäry", "häd", "ä", "little", "lämb\nLittle", "lämb\n"]);
1694 let split: Vec<&str> = data.split('ä').collect();
1695 assert_eq!(split, ["\nM", "ry h", "d ", " little l", "mb\nLittle l", "mb\n"]);
1697 let mut rsplit: Vec<&str> = data.split('ä').rev().collect();
1699 assert_eq!(rsplit, ["\nM", "ry h", "d ", " little l", "mb\nLittle l", "mb\n"]);
1701 let split: Vec<&str> = data.split(|c: char| c == 'ä').collect();
1702 assert_eq!(split, ["\nM", "ry h", "d ", " little l", "mb\nLittle l", "mb\n"]);
1704 let mut rsplit: Vec<&str> = data.split(|c: char| c == 'ä').rev().collect();
1706 assert_eq!(rsplit, ["\nM", "ry h", "d ", " little l", "mb\nLittle l", "mb\n"]);
1710 fn test_rev_split_char_iterator_no_trailing() {
1711 let data = "\nMäry häd ä little lämb\nLittle lämb\n";
1713 let mut split: Vec<&str> = data.split('\n').rev().collect();
1715 assert_eq!(split, ["", "Märy häd ä little lämb", "Little lämb", ""]);
1717 let mut split: Vec<&str> = data.split_terminator('\n').rev().collect();
1719 assert_eq!(split, ["", "Märy häd ä little lämb", "Little lämb"]);
1723 fn test_utf16_code_units() {
1724 assert_eq!("é\u{1F4A9}".encode_utf16().collect::<Vec<u16>>(), [0xE9, 0xD83D, 0xDCA9])
1728 fn starts_with_in_unicode() {
1729 assert!(!"├── Cargo.toml".starts_with("# "));
1733 fn starts_short_long() {
1734 assert!(!"".starts_with("##"));
1735 assert!(!"##".starts_with("####"));
1736 assert!("####".starts_with("##"));
1737 assert!(!"##ä".starts_with("####"));
1738 assert!("####ä".starts_with("##"));
1739 assert!(!"##".starts_with("####ä"));
1740 assert!("##ä##".starts_with("##ä"));
1742 assert!("".starts_with(""));
1743 assert!("ä".starts_with(""));
1744 assert!("#ä".starts_with(""));
1745 assert!("##ä".starts_with(""));
1746 assert!("ä###".starts_with(""));
1747 assert!("#ä##".starts_with(""));
1748 assert!("##ä#".starts_with(""));
1752 fn contains_weird_cases() {
1753 assert!("* \t".contains(' '));
1754 assert!(!"* \t".contains('?'));
1755 assert!(!"* \t".contains('\u{1F4A9}'));
1760 assert_eq!(" \t a \t ".trim_start_matches(|c: char| c.is_whitespace()), "a \t ");
1761 assert_eq!(" \t a \t ".trim_end_matches(|c: char| c.is_whitespace()), " \t a");
1762 assert_eq!(" \t a \t ".trim_start_matches(|c: char| c.is_whitespace()), "a \t ");
1763 assert_eq!(" \t a \t ".trim_end_matches(|c: char| c.is_whitespace()), " \t a");
1764 assert_eq!(" \t a \t ".trim_matches(|c: char| c.is_whitespace()), "a");
1765 assert_eq!(" \t \t ".trim_start_matches(|c: char| c.is_whitespace()), "");
1766 assert_eq!(" \t \t ".trim_end_matches(|c: char| c.is_whitespace()), "");
1767 assert_eq!(" \t \t ".trim_start_matches(|c: char| c.is_whitespace()), "");
1768 assert_eq!(" \t \t ".trim_end_matches(|c: char| c.is_whitespace()), "");
1769 assert_eq!(" \t \t ".trim_matches(|c: char| c.is_whitespace()), "");
1774 assert_eq!("".to_lowercase(), "");
1775 assert_eq!("AÉDžaé ".to_lowercase(), "aédžaé ");
1777 // https://github.com/rust-lang/rust/issues/26035
1778 assert_eq!("ΑΣ".to_lowercase(), "ας");
1779 assert_eq!("Α'Σ".to_lowercase(), "α'ς");
1780 assert_eq!("Α''Σ".to_lowercase(), "α''ς");
1782 assert_eq!("ΑΣ Α".to_lowercase(), "ας α");
1783 assert_eq!("Α'Σ Α".to_lowercase(), "α'ς α");
1784 assert_eq!("Α''Σ Α".to_lowercase(), "α''ς α");
1786 assert_eq!("ΑΣ' Α".to_lowercase(), "ας' α");
1787 assert_eq!("ΑΣ'' Α".to_lowercase(), "ας'' α");
1789 assert_eq!("Α'Σ' Α".to_lowercase(), "α'ς' α");
1790 assert_eq!("Α''Σ'' Α".to_lowercase(), "α''ς'' α");
1792 assert_eq!("Α Σ".to_lowercase(), "α σ");
1793 assert_eq!("Α 'Σ".to_lowercase(), "α 'σ");
1794 assert_eq!("Α ''Σ".to_lowercase(), "α ''σ");
1796 assert_eq!("Σ".to_lowercase(), "σ");
1797 assert_eq!("'Σ".to_lowercase(), "'σ");
1798 assert_eq!("''Σ".to_lowercase(), "''σ");
1800 assert_eq!("ΑΣΑ".to_lowercase(), "ασα");
1801 assert_eq!("ΑΣ'Α".to_lowercase(), "ασ'α");
1802 assert_eq!("ΑΣ''Α".to_lowercase(), "ασ''α");
1804 // a really long string that has it's lowercase form
1805 // even longer. this tests that implementations don't assume
1806 // an incorrect upper bound on allocations
1807 let upper = str::repeat("İ", 512);
1808 let lower = str::repeat("i̇", 512);
1809 assert_eq!(upper.to_lowercase(), lower);
1811 // a really long ascii-only string.
1812 // This test that the ascii hot-path
1813 // functions correctly
1814 let upper = str::repeat("A", 511);
1815 let lower = str::repeat("a", 511);
1816 assert_eq!(upper.to_lowercase(), lower);
1821 assert_eq!("".to_uppercase(), "");
1822 assert_eq!("aéDžßfiᾀ".to_uppercase(), "AÉDŽSSFIἈΙ");
1826 fn test_into_string() {
1827 // The only way to acquire a Box<str> in the first place is through a String, so just
1828 // test that we can round-trip between Box<str> and String.
1829 let string = String::from("Some text goes here");
1830 assert_eq!(string.clone().into_boxed_str().into_string(), string);
1834 fn test_box_slice_clone() {
1835 let data = String::from("hello HELLO hello HELLO yes YES 5 中ä华!!!");
1836 let data2 = data.clone().into_boxed_str().clone().into_string();
1838 assert_eq!(data, data2);
1842 fn test_cow_from() {
1843 let borrowed = "borrowed";
1844 let owned = String::from("owned");
1845 match (Cow::from(owned.clone()), Cow::from(borrowed)) {
1846 (Cow::Owned(o), Cow::Borrowed(b)) => assert!(o == owned && b == borrowed),
1847 _ => panic!("invalid `Cow::from`"),
1853 assert_eq!("".repeat(3), "");
1854 assert_eq!("abc".repeat(0), "");
1855 assert_eq!("α".repeat(3), "ααα");
1859 use std::str::pattern::SearchStep::{self, Done, Match, Reject};
1860 use std::str::pattern::{Pattern, ReverseSearcher, Searcher};
1862 macro_rules! make_test {
1863 ($name:ident, $p:expr, $h:expr, [$($e:expr,)*]) => {
1864 #[allow(unused_imports)]
1866 use std::str::pattern::SearchStep::{Match, Reject};
1867 use super::{cmp_search_to_vec};
1870 cmp_search_to_vec(false, $p, $h, vec![$($e),*]);
1874 cmp_search_to_vec(true, $p, $h, vec![$($e),*]);
1880 fn cmp_search_to_vec<'a>(
1882 pat: impl Pattern<'a, Searcher: ReverseSearcher<'a>>,
1884 right: Vec<SearchStep>,
1886 let mut searcher = pat.into_searcher(haystack);
1889 match if !rev { searcher.next() } else { searcher.next_back() } {
1890 Match(a, b) => v.push(Match(a, b)),
1891 Reject(a, b) => v.push(Reject(a, b)),
1899 let mut first_index = 0;
1902 for (i, e) in right.iter().enumerate() {
1904 Match(a, b) | Reject(a, b) if a <= b && a == first_index => {
1914 if let Some(err) = err {
1915 panic!("Input skipped range at {err}");
1918 if first_index != haystack.len() {
1919 panic!("Did not cover whole input");
1922 assert_eq!(v, right);
1926 str_searcher_ascii_haystack,
1929 [Reject(0, 1), Match(1, 3), Reject(3, 4), Match(4, 6), Reject(6, 7),]
1932 str_searcher_ascii_haystack_seq,
1935 [Reject(0, 1), Match(1, 3), Reject(3, 4), Match(4, 6), Match(6, 8), Reject(8, 9),]
1938 str_searcher_empty_needle_ascii_haystack,
1960 str_searcher_multibyte_haystack,
1963 [Reject(0, 3), Reject(3, 6), Reject(6, 9),]
1966 str_searcher_empty_needle_multibyte_haystack,
1979 make_test!(str_searcher_empty_needle_empty_haystack, "", "", [Match(0, 0),]);
1980 make_test!(str_searcher_nonempty_needle_empty_haystack, "├", "", []);
1982 char_searcher_ascii_haystack,
1996 char_searcher_multibyte_haystack,
1999 [Reject(0, 3), Reject(3, 6), Reject(6, 9),]
2002 char_searcher_short_haystack,
2005 [Reject(0, 1), Reject(1, 2), Reject(2, 3),]
2010 fn str_searcher_empty_needle_after_done() {
2011 // Empty needle and haystack
2013 let mut searcher = "".into_searcher("");
2015 assert_eq!(searcher.next(), SearchStep::Match(0, 0));
2016 assert_eq!(searcher.next(), SearchStep::Done);
2017 assert_eq!(searcher.next(), SearchStep::Done);
2018 assert_eq!(searcher.next(), SearchStep::Done);
2020 let mut searcher = "".into_searcher("");
2022 assert_eq!(searcher.next_back(), SearchStep::Match(0, 0));
2023 assert_eq!(searcher.next_back(), SearchStep::Done);
2024 assert_eq!(searcher.next_back(), SearchStep::Done);
2025 assert_eq!(searcher.next_back(), SearchStep::Done);
2027 // Empty needle and non-empty haystack
2029 let mut searcher = "".into_searcher("a");
2031 assert_eq!(searcher.next(), SearchStep::Match(0, 0));
2032 assert_eq!(searcher.next(), SearchStep::Reject(0, 1));
2033 assert_eq!(searcher.next(), SearchStep::Match(1, 1));
2034 assert_eq!(searcher.next(), SearchStep::Done);
2035 assert_eq!(searcher.next(), SearchStep::Done);
2036 assert_eq!(searcher.next(), SearchStep::Done);
2038 let mut searcher = "".into_searcher("a");
2040 assert_eq!(searcher.next_back(), SearchStep::Match(1, 1));
2041 assert_eq!(searcher.next_back(), SearchStep::Reject(0, 1));
2042 assert_eq!(searcher.next_back(), SearchStep::Match(0, 0));
2043 assert_eq!(searcher.next_back(), SearchStep::Done);
2044 assert_eq!(searcher.next_back(), SearchStep::Done);
2045 assert_eq!(searcher.next_back(), SearchStep::Done);
2050 macro_rules! generate_iterator_test {
2054 ($($arg:expr),*) -> [$($t:tt)*];
2057 with $fwd:expr, $bwd:expr;
2063 let res = vec![$($t)*];
2065 let fwd_vec: Vec<_> = ($fwd)($($arg),*).collect();
2066 assert_eq!(fwd_vec, res);
2068 let mut bwd_vec: Vec<_> = ($bwd)($($arg),*).collect();
2070 assert_eq!(bwd_vec, res);
2078 ($($arg:expr),*) -> [$($t:tt)*];
2087 let res = vec![$($t)*];
2089 let fwd_vec: Vec<_> = ($fwd)($($arg),*).collect();
2090 assert_eq!(fwd_vec, res);
2097 generate_iterator_test! {
2098 double_ended_split {
2099 ("foo.bar.baz", '.') -> ["foo", "bar", "baz"];
2100 ("foo::bar::baz", "::") -> ["foo", "bar", "baz"];
2102 with str::split, str::rsplit;
2105 generate_iterator_test! {
2106 double_ended_split_terminator {
2107 ("foo;bar;baz;", ';') -> ["foo", "bar", "baz"];
2109 with str::split_terminator, str::rsplit_terminator;
2112 generate_iterator_test! {
2113 double_ended_matches {
2114 ("a1b2c3", char::is_numeric) -> ["1", "2", "3"];
2116 with str::matches, str::rmatches;
2119 generate_iterator_test! {
2120 double_ended_match_indices {
2121 ("a1b2c3", char::is_numeric) -> [(1, "1"), (3, "2"), (5, "3")];
2123 with str::match_indices, str::rmatch_indices;
2126 generate_iterator_test! {
2127 not_double_ended_splitn {
2128 ("foo::bar::baz", 2, "::") -> ["foo", "bar::baz"];
2133 generate_iterator_test! {
2134 not_double_ended_rsplitn {
2135 ("foo::bar::baz", 2, "::") -> ["baz", "foo::bar"];
2141 fn different_str_pattern_forwarding_lifetimes() {
2142 use std::str::pattern::Pattern;
2146 for<'b> &'b P: Pattern<'a>,
2157 fn test_str_multiline() {
2158 let a: String = "this \
2161 let b: String = "this \
2166 assert_eq!(a, "this is a test".to_string());
2167 assert_eq!(b, "this is another test".to_string());
2171 fn test_str_escapes() {
2174 assert_eq!(x, r"\\"); // extraneous whitespace stripped
2178 fn const_str_ptr() {
2179 const A: [u8; 2] = ['h' as u8, 'i' as u8];
2180 const B: &'static [u8; 2] = &A;
2181 const C: *const u8 = B as *const u8;
2183 // Miri does not deduplicate consts (https://github.com/rust-lang/miri/issues/131)
2186 let foo = &A as *const u8;
2191 assert_eq!(from_utf8_unchecked(&A), "hi");
2192 assert_eq!(*C, A[0]);
2193 assert_eq!(*(&B[0] as *const u8), A[0]);
2199 let yen: char = '¥'; // 0xa5
2200 let c_cedilla: char = 'ç'; // 0xe7
2201 let thorn: char = 'þ'; // 0xfe
2202 let y_diaeresis: char = 'ÿ'; // 0xff
2203 let pi: char = 'Π'; // 0x3a0
2205 assert_eq!(yen as isize, 0xa5);
2206 assert_eq!(c_cedilla as isize, 0xe7);
2207 assert_eq!(thorn as isize, 0xfe);
2208 assert_eq!(y_diaeresis as isize, 0xff);
2209 assert_eq!(pi as isize, 0x3a0);
2211 assert_eq!(pi as isize, '\u{3a0}' as isize);
2212 assert_eq!('\x0a' as isize, '\n' as isize);
2214 let bhutan: String = "འབྲུག་ཡུལ།".to_string();
2215 let japan: String = "日本".to_string();
2216 let uzbekistan: String = "Ўзбекистон".to_string();
2217 let austria: String = "Österreich".to_string();
2219 let bhutan_e: String =
2220 "\u{f60}\u{f56}\u{fb2}\u{f74}\u{f42}\u{f0b}\u{f61}\u{f74}\u{f63}\u{f0d}".to_string();
2221 let japan_e: String = "\u{65e5}\u{672c}".to_string();
2222 let uzbekistan_e: String =
2223 "\u{40e}\u{437}\u{431}\u{435}\u{43a}\u{438}\u{441}\u{442}\u{43e}\u{43d}".to_string();
2224 let austria_e: String = "\u{d6}sterreich".to_string();
2227 assert_eq!(oo as isize, 0xd6);
2229 fn check_str_eq(a: String, b: String) {
2230 let mut i: isize = 0;
2231 for ab in a.bytes() {
2234 let bb: u8 = b.as_bytes()[i as usize];
2241 check_str_eq(bhutan, bhutan_e);
2242 check_str_eq(japan, japan_e);
2243 check_str_eq(uzbekistan, uzbekistan_e);
2244 check_str_eq(austria, austria_e);
2249 // Chars of 1, 2, 3, and 4 bytes
2250 let chs: Vec<char> = vec!['e', 'é', '€', '\u{10000}'];
2251 let s: String = chs.iter().cloned().collect();
2252 let schs: Vec<char> = s.chars().collect();
2254 assert_eq!(s.len(), 10);
2255 assert_eq!(s.chars().count(), 4);
2256 assert_eq!(schs.len(), 4);
2257 assert_eq!(schs.iter().cloned().collect::<String>(), s);
2259 assert!((from_utf8(s.as_bytes()).is_ok()));
2261 assert!((!from_utf8(&[0x80]).is_ok()));
2262 // invalid 2 byte prefix
2263 assert!((!from_utf8(&[0xc0]).is_ok()));
2264 assert!((!from_utf8(&[0xc0, 0x10]).is_ok()));
2265 // invalid 3 byte prefix
2266 assert!((!from_utf8(&[0xe0]).is_ok()));
2267 assert!((!from_utf8(&[0xe0, 0x10]).is_ok()));
2268 assert!((!from_utf8(&[0xe0, 0xff, 0x10]).is_ok()));
2269 // invalid 4 byte prefix
2270 assert!((!from_utf8(&[0xf0]).is_ok()));
2271 assert!((!from_utf8(&[0xf0, 0x10]).is_ok()));
2272 assert!((!from_utf8(&[0xf0, 0xff, 0x10]).is_ok()));
2273 assert!((!from_utf8(&[0xf0, 0xff, 0xff, 0x10]).is_ok()));
2277 fn utf8_char_counts() {
2278 let strs = [("e", 1), ("é", 1), ("€", 1), ("\u{10000}", 1), ("eé€\u{10000}", 4)];
2279 let spread = if cfg!(miri) { 4 } else { 8 };
2280 let mut reps = [8, 64, 256, 512]
2283 .flat_map(|n| n - spread..=n + spread)
2284 .collect::<Vec<usize>>();
2285 if cfg!(not(miri)) {
2286 reps.extend([1024, 1 << 16].iter().copied().flat_map(|n| n - spread..=n + spread));
2288 let counts = if cfg!(miri) { 0..1 } else { 0..8 };
2289 let padding = counts.map(|len| " ".repeat(len)).collect::<Vec<String>>();
2291 for repeat in reps {
2292 for (tmpl_str, tmpl_char_count) in strs {
2293 for pad_start in &padding {
2294 for pad_end in &padding {
2295 // Create a string with padding...
2297 format!("{}{}{}", pad_start, tmpl_str.repeat(repeat), pad_end);
2298 // ...and then skip past that padding. This should ensure
2299 // that we test several different alignments for both head
2301 let si = pad_start.len();
2302 let ei = with_padding.len() - pad_end.len();
2303 let target = &with_padding[si..ei];
2305 assert!(!target.starts_with(" ") && !target.ends_with(" "));
2306 let expected_count = tmpl_char_count * repeat;
2309 target.chars().count(),
2310 "wrong count for `{:?}.repeat({})` (padding: `{:?}`)",
2313 (pad_start.len(), pad_end.len()),
2322 fn floor_char_boundary() {
2323 fn check_many(s: &str, arg: impl IntoIterator<Item = usize>, ret: usize) {
2326 s.floor_char_boundary(idx),
2328 "{:?}.floor_char_boundary({:?}) != {:?}",
2337 check_many("", [0, 1, isize::MAX as usize, usize::MAX], 0);
2340 check_many("x", [0], 0);
2341 check_many("x", [1, isize::MAX as usize, usize::MAX], 1);
2344 check_many("jp", [0], 0);
2345 check_many("jp", [1], 1);
2346 check_many("jp", 2..4, 2);
2349 check_many("ĵƥ", 0..2, 0);
2350 check_many("ĵƥ", 2..4, 2);
2351 check_many("ĵƥ", 4..6, 4);
2354 check_many("日本", 0..3, 0);
2355 check_many("日本", 3..6, 3);
2356 check_many("日本", 6..8, 6);
2359 check_many("🇯🇵", 0..4, 0);
2360 check_many("🇯🇵", 4..8, 4);
2361 check_many("🇯🇵", 8..10, 8);
2365 fn ceil_char_boundary() {
2366 fn check_many(s: &str, arg: impl IntoIterator<Item = usize>, ret: usize) {
2369 s.ceil_char_boundary(idx),
2371 "{:?}.ceil_char_boundary({:?}) != {:?}",
2380 check_many("", [0], 0);
2383 check_many("x", [0], 0);
2384 check_many("x", [1], 1);
2387 check_many("jp", [0], 0);
2388 check_many("jp", [1], 1);
2389 check_many("jp", [2], 2);
2392 check_many("ĵƥ", 0..=0, 0);
2393 check_many("ĵƥ", 1..=2, 2);
2394 check_many("ĵƥ", 3..=4, 4);
2397 check_many("日本", 0..=0, 0);
2398 check_many("日本", 1..=3, 3);
2399 check_many("日本", 4..=6, 6);
2402 check_many("🇯🇵", 0..=0, 0);
2403 check_many("🇯🇵", 1..=4, 4);
2404 check_many("🇯🇵", 5..=8, 8);
2409 fn ceil_char_boundary_above_len_panic() {
2410 let _ = "x".ceil_char_boundary(2);