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