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