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 #[cfg_attr(miri, ignore)] // Miri is too slow
1636 fn test_strslice_contains() {
1637 let x = "There are moments, Jeeves, when one asks oneself, 'Do trousers matter?'";
1638 check_contains_all_substrings(x);
1642 fn test_rsplitn_char_iterator() {
1643 let data = "\nMäry häd ä little lämb\nLittle lämb\n";
1645 let mut split: Vec<&str> = data.rsplitn(4, ' ').collect();
1647 assert_eq!(split, ["\nMäry häd ä", "little", "lämb\nLittle", "lämb\n"]);
1649 let mut split: Vec<&str> = data.rsplitn(4, |c: char| c == ' ').collect();
1651 assert_eq!(split, ["\nMäry häd ä", "little", "lämb\nLittle", "lämb\n"]);
1654 let mut split: Vec<&str> = data.rsplitn(4, 'ä').collect();
1656 assert_eq!(split, ["\nMäry häd ", " little l", "mb\nLittle l", "mb\n"]);
1658 let mut split: Vec<&str> = data.rsplitn(4, |c: char| c == 'ä').collect();
1660 assert_eq!(split, ["\nMäry häd ", " little l", "mb\nLittle l", "mb\n"]);
1664 fn test_split_char_iterator() {
1665 let data = "\nMäry häd ä little lämb\nLittle lämb\n";
1667 let split: Vec<&str> = data.split(' ').collect();
1668 assert_eq!(split, ["\nMäry", "häd", "ä", "little", "lämb\nLittle", "lämb\n"]);
1670 let mut rsplit: Vec<&str> = data.split(' ').rev().collect();
1672 assert_eq!(rsplit, ["\nMäry", "häd", "ä", "little", "lämb\nLittle", "lämb\n"]);
1674 let split: Vec<&str> = data.split(|c: char| c == ' ').collect();
1675 assert_eq!(split, ["\nMäry", "häd", "ä", "little", "lämb\nLittle", "lämb\n"]);
1677 let mut rsplit: Vec<&str> = data.split(|c: char| c == ' ').rev().collect();
1679 assert_eq!(rsplit, ["\nMäry", "häd", "ä", "little", "lämb\nLittle", "lämb\n"]);
1682 let split: Vec<&str> = data.split('ä').collect();
1683 assert_eq!(split, ["\nM", "ry h", "d ", " little l", "mb\nLittle l", "mb\n"]);
1685 let mut rsplit: Vec<&str> = data.split('ä').rev().collect();
1687 assert_eq!(rsplit, ["\nM", "ry h", "d ", " little l", "mb\nLittle l", "mb\n"]);
1689 let split: Vec<&str> = data.split(|c: char| c == 'ä').collect();
1690 assert_eq!(split, ["\nM", "ry h", "d ", " little l", "mb\nLittle l", "mb\n"]);
1692 let mut rsplit: Vec<&str> = data.split(|c: char| c == 'ä').rev().collect();
1694 assert_eq!(rsplit, ["\nM", "ry h", "d ", " little l", "mb\nLittle l", "mb\n"]);
1698 fn test_rev_split_char_iterator_no_trailing() {
1699 let data = "\nMäry häd ä little lämb\nLittle lämb\n";
1701 let mut split: Vec<&str> = data.split('\n').rev().collect();
1703 assert_eq!(split, ["", "Märy häd ä little lämb", "Little lämb", ""]);
1705 let mut split: Vec<&str> = data.split_terminator('\n').rev().collect();
1707 assert_eq!(split, ["", "Märy häd ä little lämb", "Little lämb"]);
1711 fn test_utf16_code_units() {
1712 assert_eq!("é\u{1F4A9}".encode_utf16().collect::<Vec<u16>>(), [0xE9, 0xD83D, 0xDCA9])
1716 fn starts_with_in_unicode() {
1717 assert!(!"├── Cargo.toml".starts_with("# "));
1721 fn starts_short_long() {
1722 assert!(!"".starts_with("##"));
1723 assert!(!"##".starts_with("####"));
1724 assert!("####".starts_with("##"));
1725 assert!(!"##ä".starts_with("####"));
1726 assert!("####ä".starts_with("##"));
1727 assert!(!"##".starts_with("####ä"));
1728 assert!("##ä##".starts_with("##ä"));
1730 assert!("".starts_with(""));
1731 assert!("ä".starts_with(""));
1732 assert!("#ä".starts_with(""));
1733 assert!("##ä".starts_with(""));
1734 assert!("ä###".starts_with(""));
1735 assert!("#ä##".starts_with(""));
1736 assert!("##ä#".starts_with(""));
1740 fn contains_weird_cases() {
1741 assert!("* \t".contains(' '));
1742 assert!(!"* \t".contains('?'));
1743 assert!(!"* \t".contains('\u{1F4A9}'));
1748 assert_eq!(" \t a \t ".trim_start_matches(|c: char| c.is_whitespace()), "a \t ");
1749 assert_eq!(" \t a \t ".trim_end_matches(|c: char| c.is_whitespace()), " \t a");
1750 assert_eq!(" \t a \t ".trim_start_matches(|c: char| c.is_whitespace()), "a \t ");
1751 assert_eq!(" \t a \t ".trim_end_matches(|c: char| c.is_whitespace()), " \t a");
1752 assert_eq!(" \t a \t ".trim_matches(|c: char| c.is_whitespace()), "a");
1753 assert_eq!(" \t \t ".trim_start_matches(|c: char| c.is_whitespace()), "");
1754 assert_eq!(" \t \t ".trim_end_matches(|c: char| c.is_whitespace()), "");
1755 assert_eq!(" \t \t ".trim_start_matches(|c: char| c.is_whitespace()), "");
1756 assert_eq!(" \t \t ".trim_end_matches(|c: char| c.is_whitespace()), "");
1757 assert_eq!(" \t \t ".trim_matches(|c: char| c.is_whitespace()), "");
1762 assert_eq!("".to_lowercase(), "");
1763 assert_eq!("AÉDžaé ".to_lowercase(), "aédžaé ");
1765 // https://github.com/rust-lang/rust/issues/26035
1766 assert_eq!("ΑΣ".to_lowercase(), "ας");
1767 assert_eq!("Α'Σ".to_lowercase(), "α'ς");
1768 assert_eq!("Α''Σ".to_lowercase(), "α''ς");
1770 assert_eq!("ΑΣ Α".to_lowercase(), "ας α");
1771 assert_eq!("Α'Σ Α".to_lowercase(), "α'ς α");
1772 assert_eq!("Α''Σ Α".to_lowercase(), "α''ς α");
1774 assert_eq!("ΑΣ' Α".to_lowercase(), "ας' α");
1775 assert_eq!("ΑΣ'' Α".to_lowercase(), "ας'' α");
1777 assert_eq!("Α'Σ' Α".to_lowercase(), "α'ς' α");
1778 assert_eq!("Α''Σ'' Α".to_lowercase(), "α''ς'' α");
1780 assert_eq!("Α Σ".to_lowercase(), "α σ");
1781 assert_eq!("Α 'Σ".to_lowercase(), "α 'σ");
1782 assert_eq!("Α ''Σ".to_lowercase(), "α ''σ");
1784 assert_eq!("Σ".to_lowercase(), "σ");
1785 assert_eq!("'Σ".to_lowercase(), "'σ");
1786 assert_eq!("''Σ".to_lowercase(), "''σ");
1788 assert_eq!("ΑΣΑ".to_lowercase(), "ασα");
1789 assert_eq!("ΑΣ'Α".to_lowercase(), "ασ'α");
1790 assert_eq!("ΑΣ''Α".to_lowercase(), "ασ''α");
1792 // a really long string that has it's lowercase form
1793 // even longer. this tests that implementations don't assume
1794 // an incorrect upper bound on allocations
1795 let upper = str::repeat("İ", 512);
1796 let lower = str::repeat("i̇", 512);
1797 assert_eq!(upper.to_lowercase(), lower);
1799 // a really long ascii-only string.
1800 // This test that the ascii hot-path
1801 // functions correctly
1802 let upper = str::repeat("A", 511);
1803 let lower = str::repeat("a", 511);
1804 assert_eq!(upper.to_lowercase(), lower);
1809 assert_eq!("".to_uppercase(), "");
1810 assert_eq!("aéDžßfiᾀ".to_uppercase(), "AÉDŽSSFIἈΙ");
1814 fn test_into_string() {
1815 // The only way to acquire a Box<str> in the first place is through a String, so just
1816 // test that we can round-trip between Box<str> and String.
1817 let string = String::from("Some text goes here");
1818 assert_eq!(string.clone().into_boxed_str().into_string(), string);
1822 fn test_box_slice_clone() {
1823 let data = String::from("hello HELLO hello HELLO yes YES 5 中ä华!!!");
1824 let data2 = data.clone().into_boxed_str().clone().into_string();
1826 assert_eq!(data, data2);
1830 fn test_cow_from() {
1831 let borrowed = "borrowed";
1832 let owned = String::from("owned");
1833 match (Cow::from(owned.clone()), Cow::from(borrowed)) {
1834 (Cow::Owned(o), Cow::Borrowed(b)) => assert!(o == owned && b == borrowed),
1835 _ => panic!("invalid `Cow::from`"),
1841 assert_eq!("".repeat(3), "");
1842 assert_eq!("abc".repeat(0), "");
1843 assert_eq!("α".repeat(3), "ααα");
1847 use std::str::pattern::SearchStep::{self, Done, Match, Reject};
1848 use std::str::pattern::{Pattern, ReverseSearcher, Searcher};
1850 macro_rules! make_test {
1851 ($name:ident, $p:expr, $h:expr, [$($e:expr,)*]) => {
1852 #[allow(unused_imports)]
1854 use std::str::pattern::SearchStep::{Match, Reject};
1855 use super::{cmp_search_to_vec};
1858 cmp_search_to_vec(false, $p, $h, vec![$($e),*]);
1862 cmp_search_to_vec(true, $p, $h, vec![$($e),*]);
1868 fn cmp_search_to_vec<'a>(
1870 pat: impl Pattern<'a, Searcher: ReverseSearcher<'a>>,
1872 right: Vec<SearchStep>,
1874 let mut searcher = pat.into_searcher(haystack);
1877 match if !rev { searcher.next() } else { searcher.next_back() } {
1878 Match(a, b) => v.push(Match(a, b)),
1879 Reject(a, b) => v.push(Reject(a, b)),
1887 let mut first_index = 0;
1890 for (i, e) in right.iter().enumerate() {
1892 Match(a, b) | Reject(a, b) if a <= b && a == first_index => {
1902 if let Some(err) = err {
1903 panic!("Input skipped range at {err}");
1906 if first_index != haystack.len() {
1907 panic!("Did not cover whole input");
1910 assert_eq!(v, right);
1914 str_searcher_ascii_haystack,
1917 [Reject(0, 1), Match(1, 3), Reject(3, 4), Match(4, 6), Reject(6, 7),]
1920 str_searcher_ascii_haystack_seq,
1923 [Reject(0, 1), Match(1, 3), Reject(3, 4), Match(4, 6), Match(6, 8), Reject(8, 9),]
1926 str_searcher_empty_needle_ascii_haystack,
1948 str_searcher_multibyte_haystack,
1951 [Reject(0, 3), Reject(3, 6), Reject(6, 9),]
1954 str_searcher_empty_needle_multibyte_haystack,
1967 make_test!(str_searcher_empty_needle_empty_haystack, "", "", [Match(0, 0),]);
1968 make_test!(str_searcher_nonempty_needle_empty_haystack, "├", "", []);
1970 char_searcher_ascii_haystack,
1984 char_searcher_multibyte_haystack,
1987 [Reject(0, 3), Reject(3, 6), Reject(6, 9),]
1990 char_searcher_short_haystack,
1993 [Reject(0, 1), Reject(1, 2), Reject(2, 3),]
1998 fn str_searcher_empty_needle_after_done() {
1999 // Empty needle and haystack
2001 let mut searcher = "".into_searcher("");
2003 assert_eq!(searcher.next(), SearchStep::Match(0, 0));
2004 assert_eq!(searcher.next(), SearchStep::Done);
2005 assert_eq!(searcher.next(), SearchStep::Done);
2006 assert_eq!(searcher.next(), SearchStep::Done);
2008 let mut searcher = "".into_searcher("");
2010 assert_eq!(searcher.next_back(), SearchStep::Match(0, 0));
2011 assert_eq!(searcher.next_back(), SearchStep::Done);
2012 assert_eq!(searcher.next_back(), SearchStep::Done);
2013 assert_eq!(searcher.next_back(), SearchStep::Done);
2015 // Empty needle and non-empty haystack
2017 let mut searcher = "".into_searcher("a");
2019 assert_eq!(searcher.next(), SearchStep::Match(0, 0));
2020 assert_eq!(searcher.next(), SearchStep::Reject(0, 1));
2021 assert_eq!(searcher.next(), SearchStep::Match(1, 1));
2022 assert_eq!(searcher.next(), SearchStep::Done);
2023 assert_eq!(searcher.next(), SearchStep::Done);
2024 assert_eq!(searcher.next(), SearchStep::Done);
2026 let mut searcher = "".into_searcher("a");
2028 assert_eq!(searcher.next_back(), SearchStep::Match(1, 1));
2029 assert_eq!(searcher.next_back(), SearchStep::Reject(0, 1));
2030 assert_eq!(searcher.next_back(), SearchStep::Match(0, 0));
2031 assert_eq!(searcher.next_back(), SearchStep::Done);
2032 assert_eq!(searcher.next_back(), SearchStep::Done);
2033 assert_eq!(searcher.next_back(), SearchStep::Done);
2038 macro_rules! generate_iterator_test {
2042 ($($arg:expr),*) -> [$($t:tt)*];
2045 with $fwd:expr, $bwd:expr;
2051 let res = vec![$($t)*];
2053 let fwd_vec: Vec<_> = ($fwd)($($arg),*).collect();
2054 assert_eq!(fwd_vec, res);
2056 let mut bwd_vec: Vec<_> = ($bwd)($($arg),*).collect();
2058 assert_eq!(bwd_vec, res);
2066 ($($arg:expr),*) -> [$($t:tt)*];
2075 let res = vec![$($t)*];
2077 let fwd_vec: Vec<_> = ($fwd)($($arg),*).collect();
2078 assert_eq!(fwd_vec, res);
2085 generate_iterator_test! {
2086 double_ended_split {
2087 ("foo.bar.baz", '.') -> ["foo", "bar", "baz"];
2088 ("foo::bar::baz", "::") -> ["foo", "bar", "baz"];
2090 with str::split, str::rsplit;
2093 generate_iterator_test! {
2094 double_ended_split_terminator {
2095 ("foo;bar;baz;", ';') -> ["foo", "bar", "baz"];
2097 with str::split_terminator, str::rsplit_terminator;
2100 generate_iterator_test! {
2101 double_ended_matches {
2102 ("a1b2c3", char::is_numeric) -> ["1", "2", "3"];
2104 with str::matches, str::rmatches;
2107 generate_iterator_test! {
2108 double_ended_match_indices {
2109 ("a1b2c3", char::is_numeric) -> [(1, "1"), (3, "2"), (5, "3")];
2111 with str::match_indices, str::rmatch_indices;
2114 generate_iterator_test! {
2115 not_double_ended_splitn {
2116 ("foo::bar::baz", 2, "::") -> ["foo", "bar::baz"];
2121 generate_iterator_test! {
2122 not_double_ended_rsplitn {
2123 ("foo::bar::baz", 2, "::") -> ["baz", "foo::bar"];
2129 fn different_str_pattern_forwarding_lifetimes() {
2130 use std::str::pattern::Pattern;
2134 for<'b> &'b P: Pattern<'a>,
2145 fn test_str_multiline() {
2146 let a: String = "this \
2149 let b: String = "this \
2154 assert_eq!(a, "this is a test".to_string());
2155 assert_eq!(b, "this is another test".to_string());
2159 fn test_str_escapes() {
2162 assert_eq!(x, r"\\"); // extraneous whitespace stripped
2166 fn const_str_ptr() {
2167 const A: [u8; 2] = ['h' as u8, 'i' as u8];
2168 const B: &'static [u8; 2] = &A;
2169 const C: *const u8 = B as *const u8;
2171 // Miri does not deduplicate consts (https://github.com/rust-lang/miri/issues/131)
2174 let foo = &A as *const u8;
2179 assert_eq!(from_utf8_unchecked(&A), "hi");
2180 assert_eq!(*C, A[0]);
2181 assert_eq!(*(&B[0] as *const u8), A[0]);
2187 let yen: char = '¥'; // 0xa5
2188 let c_cedilla: char = 'ç'; // 0xe7
2189 let thorn: char = 'þ'; // 0xfe
2190 let y_diaeresis: char = 'ÿ'; // 0xff
2191 let pi: char = 'Π'; // 0x3a0
2193 assert_eq!(yen as isize, 0xa5);
2194 assert_eq!(c_cedilla as isize, 0xe7);
2195 assert_eq!(thorn as isize, 0xfe);
2196 assert_eq!(y_diaeresis as isize, 0xff);
2197 assert_eq!(pi as isize, 0x3a0);
2199 assert_eq!(pi as isize, '\u{3a0}' as isize);
2200 assert_eq!('\x0a' as isize, '\n' as isize);
2202 let bhutan: String = "འབྲུག་ཡུལ།".to_string();
2203 let japan: String = "日本".to_string();
2204 let uzbekistan: String = "Ўзбекистон".to_string();
2205 let austria: String = "Österreich".to_string();
2207 let bhutan_e: String =
2208 "\u{f60}\u{f56}\u{fb2}\u{f74}\u{f42}\u{f0b}\u{f61}\u{f74}\u{f63}\u{f0d}".to_string();
2209 let japan_e: String = "\u{65e5}\u{672c}".to_string();
2210 let uzbekistan_e: String =
2211 "\u{40e}\u{437}\u{431}\u{435}\u{43a}\u{438}\u{441}\u{442}\u{43e}\u{43d}".to_string();
2212 let austria_e: String = "\u{d6}sterreich".to_string();
2215 assert_eq!(oo as isize, 0xd6);
2217 fn check_str_eq(a: String, b: String) {
2218 let mut i: isize = 0;
2219 for ab in a.bytes() {
2222 let bb: u8 = b.as_bytes()[i as usize];
2229 check_str_eq(bhutan, bhutan_e);
2230 check_str_eq(japan, japan_e);
2231 check_str_eq(uzbekistan, uzbekistan_e);
2232 check_str_eq(austria, austria_e);
2237 // Chars of 1, 2, 3, and 4 bytes
2238 let chs: Vec<char> = vec!['e', 'é', '€', '\u{10000}'];
2239 let s: String = chs.iter().cloned().collect();
2240 let schs: Vec<char> = s.chars().collect();
2242 assert_eq!(s.len(), 10);
2243 assert_eq!(s.chars().count(), 4);
2244 assert_eq!(schs.len(), 4);
2245 assert_eq!(schs.iter().cloned().collect::<String>(), s);
2247 assert!((from_utf8(s.as_bytes()).is_ok()));
2249 assert!((!from_utf8(&[0x80]).is_ok()));
2250 // invalid 2 byte prefix
2251 assert!((!from_utf8(&[0xc0]).is_ok()));
2252 assert!((!from_utf8(&[0xc0, 0x10]).is_ok()));
2253 // invalid 3 byte prefix
2254 assert!((!from_utf8(&[0xe0]).is_ok()));
2255 assert!((!from_utf8(&[0xe0, 0x10]).is_ok()));
2256 assert!((!from_utf8(&[0xe0, 0xff, 0x10]).is_ok()));
2257 // invalid 4 byte prefix
2258 assert!((!from_utf8(&[0xf0]).is_ok()));
2259 assert!((!from_utf8(&[0xf0, 0x10]).is_ok()));
2260 assert!((!from_utf8(&[0xf0, 0xff, 0x10]).is_ok()));
2261 assert!((!from_utf8(&[0xf0, 0xff, 0xff, 0x10]).is_ok()));
2265 fn utf8_char_counts() {
2266 let strs = [("e", 1), ("é", 1), ("€", 1), ("\u{10000}", 1), ("eé€\u{10000}", 4)];
2267 let spread = if cfg!(miri) { 4 } else { 8 };
2268 let mut reps = [8, 64, 256, 512]
2271 .flat_map(|n| n - spread..=n + spread)
2272 .collect::<Vec<usize>>();
2273 if cfg!(not(miri)) {
2274 reps.extend([1024, 1 << 16].iter().copied().flat_map(|n| n - spread..=n + spread));
2276 let counts = if cfg!(miri) { 0..1 } else { 0..8 };
2277 let padding = counts.map(|len| " ".repeat(len)).collect::<Vec<String>>();
2279 for repeat in reps {
2280 for (tmpl_str, tmpl_char_count) in strs {
2281 for pad_start in &padding {
2282 for pad_end in &padding {
2283 // Create a string with padding...
2285 format!("{}{}{}", pad_start, tmpl_str.repeat(repeat), pad_end);
2286 // ...and then skip past that padding. This should ensure
2287 // that we test several different alignments for both head
2289 let si = pad_start.len();
2290 let ei = with_padding.len() - pad_end.len();
2291 let target = &with_padding[si..ei];
2293 assert!(!target.starts_with(" ") && !target.ends_with(" "));
2294 let expected_count = tmpl_char_count * repeat;
2297 target.chars().count(),
2298 "wrong count for `{:?}.repeat({})` (padding: `{:?}`)",
2301 (pad_start.len(), pad_end.len()),
2310 fn floor_char_boundary() {
2311 fn check_many(s: &str, arg: impl IntoIterator<Item = usize>, ret: usize) {
2314 s.floor_char_boundary(idx),
2316 "{:?}.floor_char_boundary({:?}) != {:?}",
2325 check_many("", [0, 1, isize::MAX as usize, usize::MAX], 0);
2328 check_many("x", [0], 0);
2329 check_many("x", [1, isize::MAX as usize, usize::MAX], 1);
2332 check_many("jp", [0], 0);
2333 check_many("jp", [1], 1);
2334 check_many("jp", 2..4, 2);
2337 check_many("ĵƥ", 0..2, 0);
2338 check_many("ĵƥ", 2..4, 2);
2339 check_many("ĵƥ", 4..6, 4);
2342 check_many("日本", 0..3, 0);
2343 check_many("日本", 3..6, 3);
2344 check_many("日本", 6..8, 6);
2347 check_many("🇯🇵", 0..4, 0);
2348 check_many("🇯🇵", 4..8, 4);
2349 check_many("🇯🇵", 8..10, 8);
2353 fn ceil_char_boundary() {
2354 fn check_many(s: &str, arg: impl IntoIterator<Item = usize>, ret: usize) {
2357 s.ceil_char_boundary(idx),
2359 "{:?}.ceil_char_boundary({:?}) != {:?}",
2368 check_many("", [0], 0);
2371 check_many("x", [0], 0);
2372 check_many("x", [1], 1);
2375 check_many("jp", [0], 0);
2376 check_many("jp", [1], 1);
2377 check_many("jp", [2], 2);
2380 check_many("ĵƥ", 0..=0, 0);
2381 check_many("ĵƥ", 1..=2, 2);
2382 check_many("ĵƥ", 3..=4, 4);
2385 check_many("日本", 0..=0, 0);
2386 check_many("日本", 1..=3, 3);
2387 check_many("日本", 4..=6, 6);
2390 check_many("🇯🇵", 0..=0, 0);
2391 check_many("🇯🇵", 1..=4, 4);
2392 check_many("🇯🇵", 5..=8, 8);
2397 fn ceil_char_boundary_above_len_panic() {
2398 let _ = "x".ceil_char_boundary(2);