• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 {
into_cow(self) -> Cow<'a, B>15     fn into_cow(self) -> Cow<'a, B>;
16 }
17 
18 impl<'a> IntoCow<'a, str> for String {
into_cow(self) -> Cow<'a, str>19     fn into_cow(self) -> Cow<'a, str> {
20         Cow::Owned(self)
21     }
22 }
23 
24 impl<'a> IntoCow<'a, str> for &'a str {
into_cow(self) -> Cow<'a, str>25     fn into_cow(self) -> Cow<'a, str> {
26         Cow::Borrowed(self)
27     }
28 }
29 
30 #[test]
test_from_str()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]
test_from_cow_str()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]
test_unsized_to_string()43 fn test_unsized_to_string() {
44     let s: &str = "abc";
45     let _: String = (*s).to_string();
46 }
47 
48 #[test]
test_from_utf8()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]
test_from_utf8_lossy()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]
test_from_utf16()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]
test_utf16_invalid()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]
test_from_utf16_lossy()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]
test_push_bytes()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]
test_push_str()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]
test_add_assign()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]
test_push()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]
test_pop()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]
test_split_off_empty()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]
test_split_off_past_end()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]
test_split_off_mid_char()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]
test_split_off_ascii()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]
test_split_off_unicode()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]
test_str_truncate()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]
test_str_truncate_invalid_len()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]
test_str_truncate_split_codepoint()331 fn test_str_truncate_split_codepoint() {
332     let mut s = String::from("\u{FC}"); // ü
333     s.truncate(1);
334 }
335 
336 #[test]
test_str_clear()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]
test_str_add()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]
remove()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]
remove_bad()365 fn remove_bad() {
366     "ศ".to_string().remove(1);
367 }
368 
369 #[test]
test_remove_matches()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 #[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")]
test_retain()398 fn test_retain() {
399     let mut s = String::from("α_β_γ");
400 
401     s.retain(|_| true);
402     assert_eq!(s, "α_β_γ");
403 
404     s.retain(|c| c != '_');
405     assert_eq!(s, "αβγ");
406 
407     s.retain(|c| c != 'β');
408     assert_eq!(s, "αγ");
409 
410     s.retain(|c| c == 'α');
411     assert_eq!(s, "α");
412 
413     s.retain(|_| false);
414     assert_eq!(s, "");
415 
416     let mut s = String::from("0è0");
417     let _ = panic::catch_unwind(panic::AssertUnwindSafe(|| {
418         let mut count = 0;
419         s.retain(|_| {
420             count += 1;
421             match count {
422                 1 => false,
423                 2 => true,
424                 _ => panic!(),
425             }
426         });
427     }));
428     assert!(std::str::from_utf8(s.as_bytes()).is_ok());
429 }
430 
431 #[test]
insert()432 fn insert() {
433     let mut s = "foobar".to_string();
434     s.insert(0, 'ệ');
435     assert_eq!(s, "ệfoobar");
436     s.insert(6, 'ย');
437     assert_eq!(s, "ệfooยbar");
438 }
439 
440 #[test]
441 #[should_panic]
insert_bad1()442 fn insert_bad1() {
443     "".to_string().insert(1, 't');
444 }
445 #[test]
446 #[should_panic]
insert_bad2()447 fn insert_bad2() {
448     "ệ".to_string().insert(1, 't');
449 }
450 
451 #[test]
test_slicing()452 fn test_slicing() {
453     let s = "foobar".to_string();
454     assert_eq!("foobar", &s[..]);
455     assert_eq!("foo", &s[..3]);
456     assert_eq!("bar", &s[3..]);
457     assert_eq!("oob", &s[1..4]);
458 }
459 
460 #[test]
test_simple_types()461 fn test_simple_types() {
462     assert_eq!(1.to_string(), "1");
463     assert_eq!((-1).to_string(), "-1");
464     assert_eq!(200.to_string(), "200");
465     assert_eq!(2.to_string(), "2");
466     assert_eq!(true.to_string(), "true");
467     assert_eq!(false.to_string(), "false");
468     assert_eq!(("hi".to_string()).to_string(), "hi");
469 }
470 
471 #[test]
test_vectors()472 fn test_vectors() {
473     let x: Vec<i32> = vec![];
474     assert_eq!(format!("{x:?}"), "[]");
475     assert_eq!(format!("{:?}", vec![1]), "[1]");
476     assert_eq!(format!("{:?}", vec![1, 2, 3]), "[1, 2, 3]");
477     assert!(format!("{:?}", vec![vec![], vec![1], vec![1, 1]]) == "[[], [1], [1, 1]]");
478 }
479 
480 #[test]
test_from_iterator()481 fn test_from_iterator() {
482     let s = "ศไทย中华Việt Nam".to_string();
483     let t = "ศไทย中华";
484     let u = "Việt Nam";
485 
486     let a: String = s.chars().collect();
487     assert_eq!(s, a);
488 
489     let mut b = t.to_string();
490     b.extend(u.chars());
491     assert_eq!(s, b);
492 
493     let c: String = [t, u].into_iter().collect();
494     assert_eq!(s, c);
495 
496     let mut d = t.to_string();
497     d.extend(vec![u]);
498     assert_eq!(s, d);
499 }
500 
501 #[test]
test_drain()502 fn test_drain() {
503     let mut s = String::from("αβγ");
504     assert_eq!(s.drain(2..4).collect::<String>(), "β");
505     assert_eq!(s, "αγ");
506 
507     let mut t = String::from("abcd");
508     t.drain(..0);
509     assert_eq!(t, "abcd");
510     t.drain(..1);
511     assert_eq!(t, "bcd");
512     t.drain(3..);
513     assert_eq!(t, "bcd");
514     t.drain(..);
515     assert_eq!(t, "");
516 }
517 
518 #[test]
519 #[should_panic]
test_drain_start_overflow()520 fn test_drain_start_overflow() {
521     let mut s = String::from("abc");
522     s.drain((Excluded(usize::MAX), Included(0)));
523 }
524 
525 #[test]
526 #[should_panic]
test_drain_end_overflow()527 fn test_drain_end_overflow() {
528     let mut s = String::from("abc");
529     s.drain((Included(0), Included(usize::MAX)));
530 }
531 
532 #[test]
test_replace_range()533 fn test_replace_range() {
534     let mut s = "Hello, world!".to_owned();
535     s.replace_range(7..12, "世界");
536     assert_eq!(s, "Hello, 世界!");
537 }
538 
539 #[test]
540 #[should_panic]
test_replace_range_char_boundary()541 fn test_replace_range_char_boundary() {
542     let mut s = "Hello, 世界!".to_owned();
543     s.replace_range(..8, "");
544 }
545 
546 #[test]
test_replace_range_inclusive_range()547 fn test_replace_range_inclusive_range() {
548     let mut v = String::from("12345");
549     v.replace_range(2..=3, "789");
550     assert_eq!(v, "127895");
551     v.replace_range(1..=2, "A");
552     assert_eq!(v, "1A895");
553 }
554 
555 #[test]
556 #[should_panic]
test_replace_range_out_of_bounds()557 fn test_replace_range_out_of_bounds() {
558     let mut s = String::from("12345");
559     s.replace_range(5..6, "789");
560 }
561 
562 #[test]
563 #[should_panic]
test_replace_range_inclusive_out_of_bounds()564 fn test_replace_range_inclusive_out_of_bounds() {
565     let mut s = String::from("12345");
566     s.replace_range(5..=5, "789");
567 }
568 
569 #[test]
570 #[should_panic]
test_replace_range_start_overflow()571 fn test_replace_range_start_overflow() {
572     let mut s = String::from("123");
573     s.replace_range((Excluded(usize::MAX), Included(0)), "");
574 }
575 
576 #[test]
577 #[should_panic]
test_replace_range_end_overflow()578 fn test_replace_range_end_overflow() {
579     let mut s = String::from("456");
580     s.replace_range((Included(0), Included(usize::MAX)), "");
581 }
582 
583 #[test]
test_replace_range_empty()584 fn test_replace_range_empty() {
585     let mut s = String::from("12345");
586     s.replace_range(1..2, "");
587     assert_eq!(s, "1345");
588 }
589 
590 #[test]
test_replace_range_unbounded()591 fn test_replace_range_unbounded() {
592     let mut s = String::from("12345");
593     s.replace_range(.., "");
594     assert_eq!(s, "");
595 }
596 
597 #[test]
test_replace_range_evil_start_bound()598 fn test_replace_range_evil_start_bound() {
599     struct EvilRange(Cell<bool>);
600 
601     impl RangeBounds<usize> for EvilRange {
602         fn start_bound(&self) -> Bound<&usize> {
603             Bound::Included(if self.0.get() {
604                 &1
605             } else {
606                 self.0.set(true);
607                 &0
608             })
609         }
610         fn end_bound(&self) -> Bound<&usize> {
611             Bound::Unbounded
612         }
613     }
614 
615     let mut s = String::from("��");
616     s.replace_range(EvilRange(Cell::new(false)), "");
617     assert_eq!(Ok(""), str::from_utf8(s.as_bytes()));
618 }
619 
620 #[test]
test_replace_range_evil_end_bound()621 fn test_replace_range_evil_end_bound() {
622     struct EvilRange(Cell<bool>);
623 
624     impl RangeBounds<usize> for EvilRange {
625         fn start_bound(&self) -> Bound<&usize> {
626             Bound::Included(&0)
627         }
628         fn end_bound(&self) -> Bound<&usize> {
629             Bound::Excluded(if self.0.get() {
630                 &3
631             } else {
632                 self.0.set(true);
633                 &4
634             })
635         }
636     }
637 
638     let mut s = String::from("��");
639     s.replace_range(EvilRange(Cell::new(false)), "");
640     assert_eq!(Ok(""), str::from_utf8(s.as_bytes()));
641 }
642 
643 #[test]
test_extend_ref()644 fn test_extend_ref() {
645     let mut a = "foo".to_string();
646     a.extend(&['b', 'a', 'r']);
647 
648     assert_eq!(&a, "foobar");
649 }
650 
651 #[test]
test_into_boxed_str()652 fn test_into_boxed_str() {
653     let xs = String::from("hello my name is bob");
654     let ys = xs.into_boxed_str();
655     assert_eq!(&*ys, "hello my name is bob");
656 }
657 
658 #[test]
test_reserve_exact()659 fn test_reserve_exact() {
660     // This is all the same as test_reserve
661 
662     let mut s = String::new();
663     assert_eq!(s.capacity(), 0);
664 
665     s.reserve_exact(2);
666     assert!(s.capacity() >= 2);
667 
668     for _i in 0..16 {
669         s.push('0');
670     }
671 
672     assert!(s.capacity() >= 16);
673     s.reserve_exact(16);
674     assert!(s.capacity() >= 32);
675 
676     s.push('0');
677 
678     s.reserve_exact(16);
679     assert!(s.capacity() >= 33)
680 }
681 
682 #[test]
683 #[cfg_attr(miri, ignore)] // Miri does not support signalling OOM
684 #[cfg_attr(target_os = "android", ignore)] // Android used in CI has a broken dlmalloc
test_try_reserve()685 fn test_try_reserve() {
686     // These are the interesting cases:
687     // * exactly isize::MAX should never trigger a CapacityOverflow (can be OOM)
688     // * > isize::MAX should always fail
689     //    * On 16/32-bit should CapacityOverflow
690     //    * On 64-bit should OOM
691     // * overflow may trigger when adding `len` to `cap` (in number of elements)
692     // * overflow may trigger when multiplying `new_cap` by size_of::<T> (to get bytes)
693 
694     const MAX_CAP: usize = isize::MAX as usize;
695     const MAX_USIZE: usize = usize::MAX;
696 
697     {
698         // Note: basic stuff is checked by test_reserve
699         let mut empty_string: String = String::new();
700 
701         // Check isize::MAX doesn't count as an overflow
702         if let Err(CapacityOverflow) = empty_string.try_reserve(MAX_CAP).map_err(|e| e.kind()) {
703             panic!("isize::MAX shouldn't trigger an overflow!");
704         }
705         // Play it again, frank! (just to be sure)
706         if let Err(CapacityOverflow) = empty_string.try_reserve(MAX_CAP).map_err(|e| e.kind()) {
707             panic!("isize::MAX shouldn't trigger an overflow!");
708         }
709 
710         // Check isize::MAX + 1 does count as overflow
711         assert_matches!(
712             empty_string.try_reserve(MAX_CAP + 1).map_err(|e| e.kind()),
713             Err(CapacityOverflow),
714             "isize::MAX + 1 should trigger an overflow!"
715         );
716 
717         // Check usize::MAX does count as overflow
718         assert_matches!(
719             empty_string.try_reserve(MAX_USIZE).map_err(|e| e.kind()),
720             Err(CapacityOverflow),
721             "usize::MAX should trigger an overflow!"
722         );
723     }
724 
725     {
726         // Same basic idea, but with non-zero len
727         let mut ten_bytes: String = String::from("0123456789");
728 
729         if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_CAP - 10).map_err(|e| e.kind()) {
730             panic!("isize::MAX shouldn't trigger an overflow!");
731         }
732         if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_CAP - 10).map_err(|e| e.kind()) {
733             panic!("isize::MAX shouldn't trigger an overflow!");
734         }
735 
736         assert_matches!(
737             ten_bytes.try_reserve(MAX_CAP - 9).map_err(|e| e.kind()),
738             Err(CapacityOverflow),
739             "isize::MAX + 1 should trigger an overflow!"
740         );
741 
742         // Should always overflow in the add-to-len
743         assert_matches!(
744             ten_bytes.try_reserve(MAX_USIZE).map_err(|e| e.kind()),
745             Err(CapacityOverflow),
746             "usize::MAX should trigger an overflow!"
747         );
748     }
749 }
750 
751 #[test]
752 #[cfg_attr(miri, ignore)] // Miri does not support signalling OOM
753 #[cfg_attr(target_os = "android", ignore)] // Android used in CI has a broken dlmalloc
test_try_reserve_exact()754 fn test_try_reserve_exact() {
755     // This is exactly the same as test_try_reserve with the method changed.
756     // See that test for comments.
757 
758     const MAX_CAP: usize = isize::MAX as usize;
759     const MAX_USIZE: usize = usize::MAX;
760 
761     {
762         let mut empty_string: String = String::new();
763 
764         if let Err(CapacityOverflow) = empty_string.try_reserve_exact(MAX_CAP).map_err(|e| e.kind())
765         {
766             panic!("isize::MAX shouldn't trigger an overflow!");
767         }
768         if let Err(CapacityOverflow) = empty_string.try_reserve_exact(MAX_CAP).map_err(|e| e.kind())
769         {
770             panic!("isize::MAX shouldn't trigger an overflow!");
771         }
772 
773         assert_matches!(
774             empty_string.try_reserve_exact(MAX_CAP + 1).map_err(|e| e.kind()),
775             Err(CapacityOverflow),
776             "isize::MAX + 1 should trigger an overflow!"
777         );
778 
779         assert_matches!(
780             empty_string.try_reserve_exact(MAX_USIZE).map_err(|e| e.kind()),
781             Err(CapacityOverflow),
782             "usize::MAX should trigger an overflow!"
783         );
784     }
785 
786     {
787         let mut ten_bytes: String = String::from("0123456789");
788 
789         if let Err(CapacityOverflow) =
790             ten_bytes.try_reserve_exact(MAX_CAP - 10).map_err(|e| e.kind())
791         {
792             panic!("isize::MAX shouldn't trigger an overflow!");
793         }
794         if let Err(CapacityOverflow) =
795             ten_bytes.try_reserve_exact(MAX_CAP - 10).map_err(|e| e.kind())
796         {
797             panic!("isize::MAX shouldn't trigger an overflow!");
798         }
799 
800         assert_matches!(
801             ten_bytes.try_reserve_exact(MAX_CAP - 9).map_err(|e| e.kind()),
802             Err(CapacityOverflow),
803             "isize::MAX + 1 should trigger an overflow!"
804         );
805 
806         assert_matches!(
807             ten_bytes.try_reserve_exact(MAX_USIZE).map_err(|e| e.kind()),
808             Err(CapacityOverflow),
809             "usize::MAX should trigger an overflow!"
810         );
811     }
812 }
813 
814 #[test]
test_from_char()815 fn test_from_char() {
816     assert_eq!(String::from('a'), 'a'.to_string());
817     let s: String = 'x'.into();
818     assert_eq!(s, 'x'.to_string());
819 }
820 
821 #[test]
test_str_concat()822 fn test_str_concat() {
823     let a: String = "hello".to_string();
824     let b: String = "world".to_string();
825     let s: String = format!("{a}{b}");
826     assert_eq!(s.as_bytes()[9], 'd' as u8);
827 }
828