]> git.lizzy.rs Git - rust.git/blob - library/alloc/tests/string.rs
Auto merge of #103158 - Bryanskiy:resolve_perf, r=petrochenkov
[rust.git] / library / alloc / tests / string.rs
1 use std::assert_matches::assert_matches;
2 use std::borrow::Cow;
3 use std::cell::Cell;
4 use std::collections::TryReserveErrorKind::*;
5 use std::ops::Bound;
6 use std::ops::Bound::*;
7 use std::ops::RangeBounds;
8 use std::panic;
9 use std::str;
10
11 pub trait IntoCow<'a, B: ?Sized>
12 where
13     B: ToOwned,
14 {
15     fn into_cow(self) -> Cow<'a, B>;
16 }
17
18 impl<'a> IntoCow<'a, str> for String {
19     fn into_cow(self) -> Cow<'a, str> {
20         Cow::Owned(self)
21     }
22 }
23
24 impl<'a> IntoCow<'a, str> for &'a str {
25     fn into_cow(self) -> Cow<'a, str> {
26         Cow::Borrowed(self)
27     }
28 }
29
30 #[test]
31 fn test_from_str() {
32     let owned: Option<std::string::String> = "string".parse().ok();
33     assert_eq!(owned.as_ref().map(|s| &**s), Some("string"));
34 }
35
36 #[test]
37 fn test_from_cow_str() {
38     assert_eq!(String::from(Cow::Borrowed("string")), "string");
39     assert_eq!(String::from(Cow::Owned(String::from("string"))), "string");
40 }
41
42 #[test]
43 fn test_unsized_to_string() {
44     let s: &str = "abc";
45     let _: String = (*s).to_string();
46 }
47
48 #[test]
49 fn test_from_utf8() {
50     let xs = b"hello".to_vec();
51     assert_eq!(String::from_utf8(xs).unwrap(), String::from("hello"));
52
53     let xs = "ศไทย中华Việt Nam".as_bytes().to_vec();
54     assert_eq!(String::from_utf8(xs).unwrap(), String::from("ศไทย中华Việt Nam"));
55
56     let xs = b"hello\xFF".to_vec();
57     let err = String::from_utf8(xs).unwrap_err();
58     assert_eq!(err.as_bytes(), b"hello\xff");
59     let err_clone = err.clone();
60     assert_eq!(err, err_clone);
61     assert_eq!(err.into_bytes(), b"hello\xff".to_vec());
62     assert_eq!(err_clone.utf8_error().valid_up_to(), 5);
63 }
64
65 #[test]
66 fn test_from_utf8_lossy() {
67     let xs = b"hello";
68     let ys: Cow<'_, str> = "hello".into_cow();
69     assert_eq!(String::from_utf8_lossy(xs), ys);
70
71     let xs = "ศไทย中华Việt Nam".as_bytes();
72     let ys: Cow<'_, str> = "ศไทย中华Việt Nam".into_cow();
73     assert_eq!(String::from_utf8_lossy(xs), ys);
74
75     let xs = b"Hello\xC2 There\xFF Goodbye";
76     assert_eq!(
77         String::from_utf8_lossy(xs),
78         String::from("Hello\u{FFFD} There\u{FFFD} Goodbye").into_cow()
79     );
80
81     let xs = b"Hello\xC0\x80 There\xE6\x83 Goodbye";
82     assert_eq!(
83         String::from_utf8_lossy(xs),
84         String::from("Hello\u{FFFD}\u{FFFD} There\u{FFFD} Goodbye").into_cow()
85     );
86
87     let xs = b"\xF5foo\xF5\x80bar";
88     assert_eq!(
89         String::from_utf8_lossy(xs),
90         String::from("\u{FFFD}foo\u{FFFD}\u{FFFD}bar").into_cow()
91     );
92
93     let xs = b"\xF1foo\xF1\x80bar\xF1\x80\x80baz";
94     assert_eq!(
95         String::from_utf8_lossy(xs),
96         String::from("\u{FFFD}foo\u{FFFD}bar\u{FFFD}baz").into_cow()
97     );
98
99     let xs = b"\xF4foo\xF4\x80bar\xF4\xBFbaz";
100     assert_eq!(
101         String::from_utf8_lossy(xs),
102         String::from("\u{FFFD}foo\u{FFFD}bar\u{FFFD}\u{FFFD}baz").into_cow()
103     );
104
105     let xs = b"\xF0\x80\x80\x80foo\xF0\x90\x80\x80bar";
106     assert_eq!(
107         String::from_utf8_lossy(xs),
108         String::from("\u{FFFD}\u{FFFD}\u{FFFD}\u{FFFD}foo\u{10000}bar").into_cow()
109     );
110
111     // surrogates
112     let xs = b"\xED\xA0\x80foo\xED\xBF\xBFbar";
113     assert_eq!(
114         String::from_utf8_lossy(xs),
115         String::from("\u{FFFD}\u{FFFD}\u{FFFD}foo\u{FFFD}\u{FFFD}\u{FFFD}bar").into_cow()
116     );
117 }
118
119 #[test]
120 fn test_from_utf16() {
121     let pairs = [
122         (
123             String::from("𐍅𐌿𐌻𐍆𐌹𐌻𐌰\n"),
124             vec![
125                 0xd800, 0xdf45, 0xd800, 0xdf3f, 0xd800, 0xdf3b, 0xd800, 0xdf46, 0xd800, 0xdf39,
126                 0xd800, 0xdf3b, 0xd800, 0xdf30, 0x000a,
127             ],
128         ),
129         (
130             String::from("𐐒𐑉𐐮𐑀𐐲𐑋 𐐏𐐲𐑍\n"),
131             vec![
132                 0xd801, 0xdc12, 0xd801, 0xdc49, 0xd801, 0xdc2e, 0xd801, 0xdc40, 0xd801, 0xdc32,
133                 0xd801, 0xdc4b, 0x0020, 0xd801, 0xdc0f, 0xd801, 0xdc32, 0xd801, 0xdc4d, 0x000a,
134             ],
135         ),
136         (
137             String::from("𐌀𐌖𐌋𐌄𐌑𐌉·𐌌𐌄𐌕𐌄𐌋𐌉𐌑\n"),
138             vec![
139                 0xd800, 0xdf00, 0xd800, 0xdf16, 0xd800, 0xdf0b, 0xd800, 0xdf04, 0xd800, 0xdf11,
140                 0xd800, 0xdf09, 0x00b7, 0xd800, 0xdf0c, 0xd800, 0xdf04, 0xd800, 0xdf15, 0xd800,
141                 0xdf04, 0xd800, 0xdf0b, 0xd800, 0xdf09, 0xd800, 0xdf11, 0x000a,
142             ],
143         ),
144         (
145             String::from("𐒋𐒘𐒈𐒑𐒛𐒒 𐒕𐒓 𐒈𐒚𐒍 𐒏𐒜𐒒𐒖𐒆 𐒕𐒆\n"),
146             vec![
147                 0xd801, 0xdc8b, 0xd801, 0xdc98, 0xd801, 0xdc88, 0xd801, 0xdc91, 0xd801, 0xdc9b,
148                 0xd801, 0xdc92, 0x0020, 0xd801, 0xdc95, 0xd801, 0xdc93, 0x0020, 0xd801, 0xdc88,
149                 0xd801, 0xdc9a, 0xd801, 0xdc8d, 0x0020, 0xd801, 0xdc8f, 0xd801, 0xdc9c, 0xd801,
150                 0xdc92, 0xd801, 0xdc96, 0xd801, 0xdc86, 0x0020, 0xd801, 0xdc95, 0xd801, 0xdc86,
151                 0x000a,
152             ],
153         ),
154         // Issue #12318, even-numbered non-BMP planes
155         (String::from("\u{20000}"), vec![0xD840, 0xDC00]),
156     ];
157
158     for p in &pairs {
159         let (s, u) = (*p).clone();
160         let s_as_utf16 = s.encode_utf16().collect::<Vec<u16>>();
161         let u_as_string = String::from_utf16(&u).unwrap();
162
163         assert!(core::char::decode_utf16(u.iter().cloned()).all(|r| r.is_ok()));
164         assert_eq!(s_as_utf16, u);
165
166         assert_eq!(u_as_string, s);
167         assert_eq!(String::from_utf16_lossy(&u), s);
168
169         assert_eq!(String::from_utf16(&s_as_utf16).unwrap(), s);
170         assert_eq!(u_as_string.encode_utf16().collect::<Vec<u16>>(), u);
171     }
172 }
173
174 #[test]
175 fn test_utf16_invalid() {
176     // completely positive cases tested above.
177     // lead + eof
178     assert!(String::from_utf16(&[0xD800]).is_err());
179     // lead + lead
180     assert!(String::from_utf16(&[0xD800, 0xD800]).is_err());
181
182     // isolated trail
183     assert!(String::from_utf16(&[0x0061, 0xDC00]).is_err());
184
185     // general
186     assert!(String::from_utf16(&[0xD800, 0xd801, 0xdc8b, 0xD800]).is_err());
187 }
188
189 #[test]
190 fn test_from_utf16_lossy() {
191     // completely positive cases tested above.
192     // lead + eof
193     assert_eq!(String::from_utf16_lossy(&[0xD800]), String::from("\u{FFFD}"));
194     // lead + lead
195     assert_eq!(String::from_utf16_lossy(&[0xD800, 0xD800]), String::from("\u{FFFD}\u{FFFD}"));
196
197     // isolated trail
198     assert_eq!(String::from_utf16_lossy(&[0x0061, 0xDC00]), String::from("a\u{FFFD}"));
199
200     // general
201     assert_eq!(
202         String::from_utf16_lossy(&[0xD800, 0xd801, 0xdc8b, 0xD800]),
203         String::from("\u{FFFD}𐒋\u{FFFD}")
204     );
205 }
206
207 #[test]
208 fn test_push_bytes() {
209     let mut s = String::from("ABC");
210     unsafe {
211         let mv = s.as_mut_vec();
212         mv.extend_from_slice(&[b'D']);
213     }
214     assert_eq!(s, "ABCD");
215 }
216
217 #[test]
218 fn test_push_str() {
219     let mut s = String::new();
220     s.push_str("");
221     assert_eq!(&s[0..], "");
222     s.push_str("abc");
223     assert_eq!(&s[0..], "abc");
224     s.push_str("ประเทศไทย中华Việt Nam");
225     assert_eq!(&s[0..], "abcประเทศไทย中华Việt Nam");
226 }
227
228 #[test]
229 fn test_add_assign() {
230     let mut s = String::new();
231     s += "";
232     assert_eq!(s.as_str(), "");
233     s += "abc";
234     assert_eq!(s.as_str(), "abc");
235     s += "ประเทศไทย中华Việt Nam";
236     assert_eq!(s.as_str(), "abcประเทศไทย中华Việt Nam");
237 }
238
239 #[test]
240 fn test_push() {
241     let mut data = String::from("ประเทศไทย中");
242     data.push('华');
243     data.push('b'); // 1 byte
244     data.push('¢'); // 2 byte
245     data.push('€'); // 3 byte
246     data.push('𤭢'); // 4 byte
247     assert_eq!(data, "ประเทศไทย中华b¢€𤭢");
248 }
249
250 #[test]
251 fn test_pop() {
252     let mut data = String::from("ประเทศไทย中华b¢€𤭢");
253     assert_eq!(data.pop().unwrap(), '𤭢'); // 4 bytes
254     assert_eq!(data.pop().unwrap(), '€'); // 3 bytes
255     assert_eq!(data.pop().unwrap(), '¢'); // 2 bytes
256     assert_eq!(data.pop().unwrap(), 'b'); // 1 bytes
257     assert_eq!(data.pop().unwrap(), '华');
258     assert_eq!(data, "ประเทศไทย中");
259 }
260
261 #[test]
262 fn test_split_off_empty() {
263     let orig = "Hello, world!";
264     let mut split = String::from(orig);
265     let empty: String = split.split_off(orig.len());
266     assert!(empty.is_empty());
267 }
268
269 #[test]
270 #[should_panic]
271 fn test_split_off_past_end() {
272     let orig = "Hello, world!";
273     let mut split = String::from(orig);
274     let _ = split.split_off(orig.len() + 1);
275 }
276
277 #[test]
278 #[should_panic]
279 fn test_split_off_mid_char() {
280     let mut shan = String::from("山");
281     let _broken_mountain = shan.split_off(1);
282 }
283
284 #[test]
285 fn test_split_off_ascii() {
286     let mut ab = String::from("ABCD");
287     let orig_capacity = ab.capacity();
288     let cd = ab.split_off(2);
289     assert_eq!(ab, "AB");
290     assert_eq!(cd, "CD");
291     assert_eq!(ab.capacity(), orig_capacity);
292 }
293
294 #[test]
295 fn test_split_off_unicode() {
296     let mut nihon = String::from("日本語");
297     let orig_capacity = nihon.capacity();
298     let go = nihon.split_off("日本".len());
299     assert_eq!(nihon, "日本");
300     assert_eq!(go, "語");
301     assert_eq!(nihon.capacity(), orig_capacity);
302 }
303
304 #[test]
305 fn test_str_truncate() {
306     let mut s = String::from("12345");
307     s.truncate(5);
308     assert_eq!(s, "12345");
309     s.truncate(3);
310     assert_eq!(s, "123");
311     s.truncate(0);
312     assert_eq!(s, "");
313
314     let mut s = String::from("12345");
315     let p = s.as_ptr();
316     s.truncate(3);
317     s.push_str("6");
318     let p_ = s.as_ptr();
319     assert_eq!(p_, p);
320 }
321
322 #[test]
323 fn test_str_truncate_invalid_len() {
324     let mut s = String::from("12345");
325     s.truncate(6);
326     assert_eq!(s, "12345");
327 }
328
329 #[test]
330 #[should_panic]
331 fn test_str_truncate_split_codepoint() {
332     let mut s = String::from("\u{FC}"); // ü
333     s.truncate(1);
334 }
335
336 #[test]
337 fn test_str_clear() {
338     let mut s = String::from("12345");
339     s.clear();
340     assert_eq!(s.len(), 0);
341     assert_eq!(s, "");
342 }
343
344 #[test]
345 fn test_str_add() {
346     let a = String::from("12345");
347     let b = a + "2";
348     let b = b + "2";
349     assert_eq!(b.len(), 7);
350     assert_eq!(b, "1234522");
351 }
352
353 #[test]
354 fn remove() {
355     let mut s = "ศไทย中华Việt Nam; foobar".to_string();
356     assert_eq!(s.remove(0), 'ศ');
357     assert_eq!(s.len(), 33);
358     assert_eq!(s, "ไทย中华Việt Nam; foobar");
359     assert_eq!(s.remove(17), 'ệ');
360     assert_eq!(s, "ไทย中华Vit Nam; foobar");
361 }
362
363 #[test]
364 #[should_panic]
365 fn remove_bad() {
366     "ศ".to_string().remove(1);
367 }
368
369 #[test]
370 fn test_remove_matches() {
371     let mut s = "abc".to_string();
372
373     s.remove_matches('b');
374     assert_eq!(s, "ac");
375     s.remove_matches('b');
376     assert_eq!(s, "ac");
377
378     let mut s = "abcb".to_string();
379
380     s.remove_matches('b');
381     assert_eq!(s, "ac");
382
383     let mut s = "ศไทย中华Việt Nam; foobarศ".to_string();
384     s.remove_matches('ศ');
385     assert_eq!(s, "ไทย中华Việt Nam; foobar");
386
387     let mut s = "".to_string();
388     s.remove_matches("");
389     assert_eq!(s, "");
390
391     let mut s = "aaaaa".to_string();
392     s.remove_matches('a');
393     assert_eq!(s, "");
394 }
395
396 #[test]
397 fn test_retain() {
398     let mut s = String::from("α_β_γ");
399
400     s.retain(|_| true);
401     assert_eq!(s, "α_β_γ");
402
403     s.retain(|c| c != '_');
404     assert_eq!(s, "αβγ");
405
406     s.retain(|c| c != 'β');
407     assert_eq!(s, "αγ");
408
409     s.retain(|c| c == 'α');
410     assert_eq!(s, "α");
411
412     s.retain(|_| false);
413     assert_eq!(s, "");
414
415     let mut s = String::from("0è0");
416     let _ = panic::catch_unwind(panic::AssertUnwindSafe(|| {
417         let mut count = 0;
418         s.retain(|_| {
419             count += 1;
420             match count {
421                 1 => false,
422                 2 => true,
423                 _ => panic!(),
424             }
425         });
426     }));
427     assert!(std::str::from_utf8(s.as_bytes()).is_ok());
428 }
429
430 #[test]
431 fn insert() {
432     let mut s = "foobar".to_string();
433     s.insert(0, 'ệ');
434     assert_eq!(s, "ệfoobar");
435     s.insert(6, 'ย');
436     assert_eq!(s, "ệfooยbar");
437 }
438
439 #[test]
440 #[should_panic]
441 fn insert_bad1() {
442     "".to_string().insert(1, 't');
443 }
444 #[test]
445 #[should_panic]
446 fn insert_bad2() {
447     "ệ".to_string().insert(1, 't');
448 }
449
450 #[test]
451 fn test_slicing() {
452     let s = "foobar".to_string();
453     assert_eq!("foobar", &s[..]);
454     assert_eq!("foo", &s[..3]);
455     assert_eq!("bar", &s[3..]);
456     assert_eq!("oob", &s[1..4]);
457 }
458
459 #[test]
460 fn test_simple_types() {
461     assert_eq!(1.to_string(), "1");
462     assert_eq!((-1).to_string(), "-1");
463     assert_eq!(200.to_string(), "200");
464     assert_eq!(2.to_string(), "2");
465     assert_eq!(true.to_string(), "true");
466     assert_eq!(false.to_string(), "false");
467     assert_eq!(("hi".to_string()).to_string(), "hi");
468 }
469
470 #[test]
471 fn test_vectors() {
472     let x: Vec<i32> = vec![];
473     assert_eq!(format!("{x:?}"), "[]");
474     assert_eq!(format!("{:?}", vec![1]), "[1]");
475     assert_eq!(format!("{:?}", vec![1, 2, 3]), "[1, 2, 3]");
476     assert!(format!("{:?}", vec![vec![], vec![1], vec![1, 1]]) == "[[], [1], [1, 1]]");
477 }
478
479 #[test]
480 fn test_from_iterator() {
481     let s = "ศไทย中华Việt Nam".to_string();
482     let t = "ศไทย中华";
483     let u = "Việt Nam";
484
485     let a: String = s.chars().collect();
486     assert_eq!(s, a);
487
488     let mut b = t.to_string();
489     b.extend(u.chars());
490     assert_eq!(s, b);
491
492     let c: String = [t, u].into_iter().collect();
493     assert_eq!(s, c);
494
495     let mut d = t.to_string();
496     d.extend(vec![u]);
497     assert_eq!(s, d);
498 }
499
500 #[test]
501 fn test_drain() {
502     let mut s = String::from("αβγ");
503     assert_eq!(s.drain(2..4).collect::<String>(), "β");
504     assert_eq!(s, "αγ");
505
506     let mut t = String::from("abcd");
507     t.drain(..0);
508     assert_eq!(t, "abcd");
509     t.drain(..1);
510     assert_eq!(t, "bcd");
511     t.drain(3..);
512     assert_eq!(t, "bcd");
513     t.drain(..);
514     assert_eq!(t, "");
515 }
516
517 #[test]
518 #[should_panic]
519 fn test_drain_start_overflow() {
520     let mut s = String::from("abc");
521     s.drain((Excluded(usize::MAX), Included(0)));
522 }
523
524 #[test]
525 #[should_panic]
526 fn test_drain_end_overflow() {
527     let mut s = String::from("abc");
528     s.drain((Included(0), Included(usize::MAX)));
529 }
530
531 #[test]
532 fn test_replace_range() {
533     let mut s = "Hello, world!".to_owned();
534     s.replace_range(7..12, "世界");
535     assert_eq!(s, "Hello, 世界!");
536 }
537
538 #[test]
539 #[should_panic]
540 fn test_replace_range_char_boundary() {
541     let mut s = "Hello, 世界!".to_owned();
542     s.replace_range(..8, "");
543 }
544
545 #[test]
546 fn test_replace_range_inclusive_range() {
547     let mut v = String::from("12345");
548     v.replace_range(2..=3, "789");
549     assert_eq!(v, "127895");
550     v.replace_range(1..=2, "A");
551     assert_eq!(v, "1A895");
552 }
553
554 #[test]
555 #[should_panic]
556 fn test_replace_range_out_of_bounds() {
557     let mut s = String::from("12345");
558     s.replace_range(5..6, "789");
559 }
560
561 #[test]
562 #[should_panic]
563 fn test_replace_range_inclusive_out_of_bounds() {
564     let mut s = String::from("12345");
565     s.replace_range(5..=5, "789");
566 }
567
568 #[test]
569 #[should_panic]
570 fn test_replace_range_start_overflow() {
571     let mut s = String::from("123");
572     s.replace_range((Excluded(usize::MAX), Included(0)), "");
573 }
574
575 #[test]
576 #[should_panic]
577 fn test_replace_range_end_overflow() {
578     let mut s = String::from("456");
579     s.replace_range((Included(0), Included(usize::MAX)), "");
580 }
581
582 #[test]
583 fn test_replace_range_empty() {
584     let mut s = String::from("12345");
585     s.replace_range(1..2, "");
586     assert_eq!(s, "1345");
587 }
588
589 #[test]
590 fn test_replace_range_unbounded() {
591     let mut s = String::from("12345");
592     s.replace_range(.., "");
593     assert_eq!(s, "");
594 }
595
596 #[test]
597 fn test_replace_range_evil_start_bound() {
598     struct EvilRange(Cell<bool>);
599
600     impl RangeBounds<usize> for EvilRange {
601         fn start_bound(&self) -> Bound<&usize> {
602             Bound::Included(if self.0.get() {
603                 &1
604             } else {
605                 self.0.set(true);
606                 &0
607             })
608         }
609         fn end_bound(&self) -> Bound<&usize> {
610             Bound::Unbounded
611         }
612     }
613
614     let mut s = String::from("🦀");
615     s.replace_range(EvilRange(Cell::new(false)), "");
616     assert_eq!(Ok(""), str::from_utf8(s.as_bytes()));
617 }
618
619 #[test]
620 fn test_replace_range_evil_end_bound() {
621     struct EvilRange(Cell<bool>);
622
623     impl RangeBounds<usize> for EvilRange {
624         fn start_bound(&self) -> Bound<&usize> {
625             Bound::Included(&0)
626         }
627         fn end_bound(&self) -> Bound<&usize> {
628             Bound::Excluded(if self.0.get() {
629                 &3
630             } else {
631                 self.0.set(true);
632                 &4
633             })
634         }
635     }
636
637     let mut s = String::from("🦀");
638     s.replace_range(EvilRange(Cell::new(false)), "");
639     assert_eq!(Ok(""), str::from_utf8(s.as_bytes()));
640 }
641
642 #[test]
643 fn test_extend_ref() {
644     let mut a = "foo".to_string();
645     a.extend(&['b', 'a', 'r']);
646
647     assert_eq!(&a, "foobar");
648 }
649
650 #[test]
651 fn test_into_boxed_str() {
652     let xs = String::from("hello my name is bob");
653     let ys = xs.into_boxed_str();
654     assert_eq!(&*ys, "hello my name is bob");
655 }
656
657 #[test]
658 fn test_reserve_exact() {
659     // This is all the same as test_reserve
660
661     let mut s = String::new();
662     assert_eq!(s.capacity(), 0);
663
664     s.reserve_exact(2);
665     assert!(s.capacity() >= 2);
666
667     for _i in 0..16 {
668         s.push('0');
669     }
670
671     assert!(s.capacity() >= 16);
672     s.reserve_exact(16);
673     assert!(s.capacity() >= 32);
674
675     s.push('0');
676
677     s.reserve_exact(16);
678     assert!(s.capacity() >= 33)
679 }
680
681 #[test]
682 #[cfg_attr(miri, ignore)] // Miri does not support signalling OOM
683 #[cfg_attr(target_os = "android", ignore)] // Android used in CI has a broken dlmalloc
684 fn test_try_reserve() {
685     // These are the interesting cases:
686     // * exactly isize::MAX should never trigger a CapacityOverflow (can be OOM)
687     // * > isize::MAX should always fail
688     //    * On 16/32-bit should CapacityOverflow
689     //    * On 64-bit should OOM
690     // * overflow may trigger when adding `len` to `cap` (in number of elements)
691     // * overflow may trigger when multiplying `new_cap` by size_of::<T> (to get bytes)
692
693     const MAX_CAP: usize = isize::MAX as usize;
694     const MAX_USIZE: usize = usize::MAX;
695
696     {
697         // Note: basic stuff is checked by test_reserve
698         let mut empty_string: String = String::new();
699
700         // Check isize::MAX doesn't count as an overflow
701         if let Err(CapacityOverflow) = empty_string.try_reserve(MAX_CAP).map_err(|e| e.kind()) {
702             panic!("isize::MAX shouldn't trigger an overflow!");
703         }
704         // Play it again, frank! (just to be sure)
705         if let Err(CapacityOverflow) = empty_string.try_reserve(MAX_CAP).map_err(|e| e.kind()) {
706             panic!("isize::MAX shouldn't trigger an overflow!");
707         }
708
709         // Check isize::MAX + 1 does count as overflow
710         assert_matches!(
711             empty_string.try_reserve(MAX_CAP + 1).map_err(|e| e.kind()),
712             Err(CapacityOverflow),
713             "isize::MAX + 1 should trigger an overflow!"
714         );
715
716         // Check usize::MAX does count as overflow
717         assert_matches!(
718             empty_string.try_reserve(MAX_USIZE).map_err(|e| e.kind()),
719             Err(CapacityOverflow),
720             "usize::MAX should trigger an overflow!"
721         );
722     }
723
724     {
725         // Same basic idea, but with non-zero len
726         let mut ten_bytes: String = String::from("0123456789");
727
728         if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_CAP - 10).map_err(|e| e.kind()) {
729             panic!("isize::MAX shouldn't trigger an overflow!");
730         }
731         if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_CAP - 10).map_err(|e| e.kind()) {
732             panic!("isize::MAX shouldn't trigger an overflow!");
733         }
734
735         assert_matches!(
736             ten_bytes.try_reserve(MAX_CAP - 9).map_err(|e| e.kind()),
737             Err(CapacityOverflow),
738             "isize::MAX + 1 should trigger an overflow!"
739         );
740
741         // Should always overflow in the add-to-len
742         assert_matches!(
743             ten_bytes.try_reserve(MAX_USIZE).map_err(|e| e.kind()),
744             Err(CapacityOverflow),
745             "usize::MAX should trigger an overflow!"
746         );
747     }
748 }
749
750 #[test]
751 #[cfg_attr(miri, ignore)] // Miri does not support signalling OOM
752 #[cfg_attr(target_os = "android", ignore)] // Android used in CI has a broken dlmalloc
753 fn test_try_reserve_exact() {
754     // This is exactly the same as test_try_reserve with the method changed.
755     // See that test for comments.
756
757     const MAX_CAP: usize = isize::MAX as usize;
758     const MAX_USIZE: usize = usize::MAX;
759
760     {
761         let mut empty_string: String = String::new();
762
763         if let Err(CapacityOverflow) = empty_string.try_reserve_exact(MAX_CAP).map_err(|e| e.kind())
764         {
765             panic!("isize::MAX shouldn't trigger an overflow!");
766         }
767         if let Err(CapacityOverflow) = empty_string.try_reserve_exact(MAX_CAP).map_err(|e| e.kind())
768         {
769             panic!("isize::MAX shouldn't trigger an overflow!");
770         }
771
772         assert_matches!(
773             empty_string.try_reserve_exact(MAX_CAP + 1).map_err(|e| e.kind()),
774             Err(CapacityOverflow),
775             "isize::MAX + 1 should trigger an overflow!"
776         );
777
778         assert_matches!(
779             empty_string.try_reserve_exact(MAX_USIZE).map_err(|e| e.kind()),
780             Err(CapacityOverflow),
781             "usize::MAX should trigger an overflow!"
782         );
783     }
784
785     {
786         let mut ten_bytes: String = String::from("0123456789");
787
788         if let Err(CapacityOverflow) =
789             ten_bytes.try_reserve_exact(MAX_CAP - 10).map_err(|e| e.kind())
790         {
791             panic!("isize::MAX shouldn't trigger an overflow!");
792         }
793         if let Err(CapacityOverflow) =
794             ten_bytes.try_reserve_exact(MAX_CAP - 10).map_err(|e| e.kind())
795         {
796             panic!("isize::MAX shouldn't trigger an overflow!");
797         }
798
799         assert_matches!(
800             ten_bytes.try_reserve_exact(MAX_CAP - 9).map_err(|e| e.kind()),
801             Err(CapacityOverflow),
802             "isize::MAX + 1 should trigger an overflow!"
803         );
804
805         assert_matches!(
806             ten_bytes.try_reserve_exact(MAX_USIZE).map_err(|e| e.kind()),
807             Err(CapacityOverflow),
808             "usize::MAX should trigger an overflow!"
809         );
810     }
811 }
812
813 #[test]
814 fn test_from_char() {
815     assert_eq!(String::from('a'), 'a'.to_string());
816     let s: String = 'x'.into();
817     assert_eq!(s, 'x'.to_string());
818 }
819
820 #[test]
821 fn test_str_concat() {
822     let a: String = "hello".to_string();
823     let b: String = "world".to_string();
824     let s: String = format!("{a}{b}");
825     assert_eq!(s.as_bytes()[9], 'd' as u8);
826 }