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