]> git.proxmox.com Git - rustc.git/blame - library/alloc/tests/string.rs
Merge tag 'debian/1.52.1+dfsg1-1_exp2' into proxmox/buster
[rustc.git] / library / alloc / tests / string.rs
CommitLineData
7453a54e 1use std::borrow::Cow;
5869c6ff 2use std::cell::Cell;
e1599b0c 3use std::collections::TryReserveError::*;
5869c6ff 4use std::ops::Bound;
1b1a35ee 5use std::ops::Bound::*;
5869c6ff 6use std::ops::RangeBounds;
29967ef6 7use std::panic;
5869c6ff 8use std::str;
c34b1796 9
dfeec247
XL
10pub trait IntoCow<'a, B: ?Sized>
11where
12 B: ToOwned,
13{
7453a54e
SL
14 fn into_cow(self) -> Cow<'a, B>;
15}
16
17impl<'a> IntoCow<'a, str> for String {
18 fn into_cow(self) -> Cow<'a, str> {
19 Cow::Owned(self)
20 }
21}
22
23impl<'a> IntoCow<'a, str> for &'a str {
24 fn into_cow(self) -> Cow<'a, str> {
25 Cow::Borrowed(self)
26 }
27}
28
c34b1796
AL
29#[test]
30fn test_from_str() {
9fa01778 31 let owned: Option<std::string::String> = "string".parse().ok();
3157f602 32 assert_eq!(owned.as_ref().map(|s| &**s), Some("string"));
c34b1796
AL
33}
34
c30ab7b3
SL
35#[test]
36fn 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
c34b1796
AL
41#[test]
42fn test_unsized_to_string() {
43 let s: &str = "abc";
44 let _: String = (*s).to_string();
45}
46
47#[test]
48fn test_from_utf8() {
49 let xs = b"hello".to_vec();
3157f602 50 assert_eq!(String::from_utf8(xs).unwrap(), String::from("hello"));
c34b1796
AL
51
52 let xs = "ศไทย中华Việt Nam".as_bytes().to_vec();
dfeec247 53 assert_eq!(String::from_utf8(xs).unwrap(), String::from("ศไทย中华Việt Nam"));
c34b1796
AL
54
55 let xs = b"hello\xFF".to_vec();
a7813a04 56 let err = String::from_utf8(xs).unwrap_err();
74b04a01
XL
57 assert_eq!(err.as_bytes(), b"hello\xff");
58 let err_clone = err.clone();
59 assert_eq!(err, err_clone);
c34b1796 60 assert_eq!(err.into_bytes(), b"hello\xff".to_vec());
74b04a01 61 assert_eq!(err_clone.utf8_error().valid_up_to(), 5);
c34b1796
AL
62}
63
64#[test]
65fn test_from_utf8_lossy() {
66 let xs = b"hello";
48663c56 67 let ys: Cow<'_, str> = "hello".into_cow();
c34b1796
AL
68 assert_eq!(String::from_utf8_lossy(xs), ys);
69
70 let xs = "ศไทย中华Việt Nam".as_bytes();
48663c56 71 let ys: Cow<'_, str> = "ศไทย中华Việt Nam".into_cow();
c34b1796
AL
72 assert_eq!(String::from_utf8_lossy(xs), ys);
73
74 let xs = b"Hello\xC2 There\xFF Goodbye";
dfeec247
XL
75 assert_eq!(
76 String::from_utf8_lossy(xs),
77 String::from("Hello\u{FFFD} There\u{FFFD} Goodbye").into_cow()
78 );
c34b1796
AL
79
80 let xs = b"Hello\xC0\x80 There\xE6\x83 Goodbye";
dfeec247
XL
81 assert_eq!(
82 String::from_utf8_lossy(xs),
83 String::from("Hello\u{FFFD}\u{FFFD} There\u{FFFD} Goodbye").into_cow()
84 );
c34b1796
AL
85
86 let xs = b"\xF5foo\xF5\x80bar";
dfeec247
XL
87 assert_eq!(
88 String::from_utf8_lossy(xs),
89 String::from("\u{FFFD}foo\u{FFFD}\u{FFFD}bar").into_cow()
90 );
c34b1796
AL
91
92 let xs = b"\xF1foo\xF1\x80bar\xF1\x80\x80baz";
dfeec247
XL
93 assert_eq!(
94 String::from_utf8_lossy(xs),
95 String::from("\u{FFFD}foo\u{FFFD}bar\u{FFFD}baz").into_cow()
96 );
c34b1796
AL
97
98 let xs = b"\xF4foo\xF4\x80bar\xF4\xBFbaz";
dfeec247
XL
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 );
c34b1796
AL
103
104 let xs = b"\xF0\x80\x80\x80foo\xF0\x90\x80\x80bar";
dfeec247
XL
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 );
c34b1796
AL
109
110 // surrogates
111 let xs = b"\xED\xA0\x80foo\xED\xBF\xBFbar";
dfeec247
XL
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 );
c34b1796
AL
116}
117
118#[test]
119fn test_from_utf16() {
dfeec247
XL
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 ];
c34b1796
AL
156
157 for p in &pairs {
158 let (s, u) = (*p).clone();
7453a54e 159 let s_as_utf16 = s.encode_utf16().collect::<Vec<u16>>();
c34b1796
AL
160 let u_as_string = String::from_utf16(&u).unwrap();
161
9fa01778 162 assert!(core::char::decode_utf16(u.iter().cloned()).all(|r| r.is_ok()));
c34b1796
AL
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);
7453a54e 169 assert_eq!(u_as_string.encode_utf16().collect::<Vec<u16>>(), u);
c34b1796
AL
170 }
171}
172
173#[test]
174fn 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]
189fn test_from_utf16_lossy() {
190 // completely positive cases tested above.
191 // lead + eof
dfeec247 192 assert_eq!(String::from_utf16_lossy(&[0xD800]), String::from("\u{FFFD}"));
c34b1796 193 // lead + lead
dfeec247 194 assert_eq!(String::from_utf16_lossy(&[0xD800, 0xD800]), String::from("\u{FFFD}\u{FFFD}"));
c34b1796
AL
195
196 // isolated trail
dfeec247 197 assert_eq!(String::from_utf16_lossy(&[0x0061, 0xDC00]), String::from("a\u{FFFD}"));
c34b1796
AL
198
199 // general
dfeec247
XL
200 assert_eq!(
201 String::from_utf16_lossy(&[0xD800, 0xd801, 0xdc8b, 0xD800]),
202 String::from("\u{FFFD}𐒋\u{FFFD}")
203 );
c34b1796
AL
204}
205
206#[test]
207fn test_push_bytes() {
62682a34 208 let mut s = String::from("ABC");
c34b1796
AL
209 unsafe {
210 let mv = s.as_mut_vec();
7453a54e 211 mv.extend_from_slice(&[b'D']);
c34b1796
AL
212 }
213 assert_eq!(s, "ABCD");
214}
215
216#[test]
217fn 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
5bcae85e
SL
227#[test]
228fn 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
c34b1796
AL
238#[test]
239fn test_push() {
62682a34 240 let mut data = String::from("ประเทศไทย中");
c34b1796
AL
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]
250fn test_pop() {
62682a34 251 let mut data = String::from("ประเทศไทย中华b¢€𤭢");
c34b1796
AL
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
476ff2be
SL
260#[test]
261fn 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]
270fn test_split_off_past_end() {
271 let orig = "Hello, world!";
272 let mut split = String::from(orig);
ba9703b0 273 let _ = split.split_off(orig.len() + 1);
476ff2be
SL
274}
275
276#[test]
277#[should_panic]
278fn test_split_off_mid_char() {
1b1a35ee
XL
279 let mut shan = String::from("山");
280 let _broken_mountain = shan.split_off(1);
476ff2be
SL
281}
282
283#[test]
284fn test_split_off_ascii() {
285 let mut ab = String::from("ABCD");
1b1a35ee 286 let orig_capacity = ab.capacity();
476ff2be
SL
287 let cd = ab.split_off(2);
288 assert_eq!(ab, "AB");
289 assert_eq!(cd, "CD");
1b1a35ee 290 assert_eq!(ab.capacity(), orig_capacity);
476ff2be
SL
291}
292
293#[test]
294fn test_split_off_unicode() {
295 let mut nihon = String::from("日本語");
1b1a35ee 296 let orig_capacity = nihon.capacity();
476ff2be
SL
297 let go = nihon.split_off("日本".len());
298 assert_eq!(nihon, "日本");
299 assert_eq!(go, "語");
1b1a35ee 300 assert_eq!(nihon.capacity(), orig_capacity);
476ff2be
SL
301}
302
c34b1796
AL
303#[test]
304fn test_str_truncate() {
62682a34 305 let mut s = String::from("12345");
c34b1796
AL
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
62682a34 313 let mut s = String::from("12345");
c34b1796
AL
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]
c34b1796 322fn test_str_truncate_invalid_len() {
62682a34 323 let mut s = String::from("12345");
c34b1796 324 s.truncate(6);
a7813a04 325 assert_eq!(s, "12345");
c34b1796
AL
326}
327
328#[test]
329#[should_panic]
330fn test_str_truncate_split_codepoint() {
62682a34 331 let mut s = String::from("\u{FC}"); // ü
c34b1796
AL
332 s.truncate(1);
333}
334
335#[test]
336fn test_str_clear() {
62682a34 337 let mut s = String::from("12345");
c34b1796
AL
338 s.clear();
339 assert_eq!(s.len(), 0);
340 assert_eq!(s, "");
341}
342
343#[test]
344fn test_str_add() {
62682a34 345 let a = String::from("12345");
c34b1796
AL
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]
353fn remove() {
b039eaaf 354 let mut s = "ศไทย中华Việt Nam; foobar".to_string();
c34b1796
AL
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
3157f602
XL
362#[test]
363#[should_panic]
c34b1796
AL
364fn remove_bad() {
365 "ศ".to_string().remove(1);
366}
367
6a06907d
XL
368#[test]
369fn test_remove_matches() {
370 let mut s = "abc".to_string();
371
372 s.remove_matches('b');
373 assert_eq!(s, "ac");
374 s.remove_matches('b');
375 assert_eq!(s, "ac");
376
377 let mut s = "abcb".to_string();
378
379 s.remove_matches('b');
380 assert_eq!(s, "ac");
381
382 let mut s = "ศไทย中华Việt Nam; foobarศ".to_string();
383 s.remove_matches('ศ');
384 assert_eq!(s, "ไทย中华Việt Nam; foobar");
385
386 let mut s = "".to_string();
387 s.remove_matches("");
388 assert_eq!(s, "");
389
390 let mut s = "aaaaa".to_string();
391 s.remove_matches('a');
392 assert_eq!(s, "");
393}
394
3b2f2976
XL
395#[test]
396fn test_retain() {
397 let mut s = String::from("α_β_γ");
398
399 s.retain(|_| true);
400 assert_eq!(s, "α_β_γ");
401
402 s.retain(|c| c != '_');
403 assert_eq!(s, "αβγ");
404
405 s.retain(|c| c != 'β');
406 assert_eq!(s, "αγ");
407
408 s.retain(|c| c == 'α');
409 assert_eq!(s, "α");
410
411 s.retain(|_| false);
412 assert_eq!(s, "");
29967ef6
XL
413
414 let mut s = String::from("0è0");
415 let _ = panic::catch_unwind(panic::AssertUnwindSafe(|| {
416 let mut count = 0;
417 s.retain(|_| {
418 count += 1;
419 match count {
420 1 => false,
421 2 => true,
422 _ => panic!(),
423 }
424 });
425 }));
426 assert!(std::str::from_utf8(s.as_bytes()).is_ok());
3b2f2976
XL
427}
428
c34b1796
AL
429#[test]
430fn insert() {
431 let mut s = "foobar".to_string();
432 s.insert(0, 'ệ');
433 assert_eq!(s, "ệfoobar");
434 s.insert(6, 'ย');
435 assert_eq!(s, "ệfooยbar");
436}
437
3157f602
XL
438#[test]
439#[should_panic]
440fn insert_bad1() {
441 "".to_string().insert(1, 't');
442}
443#[test]
444#[should_panic]
445fn insert_bad2() {
446 "ệ".to_string().insert(1, 't');
447}
c34b1796
AL
448
449#[test]
450fn test_slicing() {
451 let s = "foobar".to_string();
452 assert_eq!("foobar", &s[..]);
453 assert_eq!("foo", &s[..3]);
454 assert_eq!("bar", &s[3..]);
455 assert_eq!("oob", &s[1..4]);
456}
457
458#[test]
459fn test_simple_types() {
460 assert_eq!(1.to_string(), "1");
461 assert_eq!((-1).to_string(), "-1");
462 assert_eq!(200.to_string(), "200");
463 assert_eq!(2.to_string(), "2");
464 assert_eq!(true.to_string(), "true");
465 assert_eq!(false.to_string(), "false");
466 assert_eq!(("hi".to_string()).to_string(), "hi");
467}
468
469#[test]
470fn test_vectors() {
471 let x: Vec<i32> = vec![];
472 assert_eq!(format!("{:?}", x), "[]");
473 assert_eq!(format!("{:?}", vec![1]), "[1]");
474 assert_eq!(format!("{:?}", vec![1, 2, 3]), "[1, 2, 3]");
3157f602 475 assert!(format!("{:?}", vec![vec![], vec![1], vec![1, 1]]) == "[[], [1], [1, 1]]");
c34b1796
AL
476}
477
478#[test]
479fn test_from_iterator() {
480 let s = "ศไทย中华Việt Nam".to_string();
481 let t = "ศไทย中华";
482 let u = "Việt Nam";
483
484 let a: String = s.chars().collect();
485 assert_eq!(s, a);
486
487 let mut b = t.to_string();
488 b.extend(u.chars());
489 assert_eq!(s, b);
490
491 let c: String = vec![t, u].into_iter().collect();
492 assert_eq!(s, c);
493
494 let mut d = t.to_string();
62682a34 495 d.extend(vec![u]);
c34b1796
AL
496 assert_eq!(s, d);
497}
498
d9579d0f
AL
499#[test]
500fn test_drain() {
501 let mut s = String::from("αβγ");
502 assert_eq!(s.drain(2..4).collect::<String>(), "β");
503 assert_eq!(s, "αγ");
504
505 let mut t = String::from("abcd");
506 t.drain(..0);
507 assert_eq!(t, "abcd");
508 t.drain(..1);
509 assert_eq!(t, "bcd");
510 t.drain(3..);
511 assert_eq!(t, "bcd");
512 t.drain(..);
513 assert_eq!(t, "");
514}
515
1b1a35ee
XL
516#[test]
517#[should_panic]
518fn test_drain_start_overflow() {
519 let mut s = String::from("abc");
520 s.drain((Excluded(usize::MAX), Included(0)));
521}
522
523#[test]
524#[should_panic]
525fn test_drain_end_overflow() {
526 let mut s = String::from("abc");
527 s.drain((Included(0), Included(usize::MAX)));
528}
529
7cac9316 530#[test]
83c7162d 531fn test_replace_range() {
7cac9316 532 let mut s = "Hello, world!".to_owned();
83c7162d 533 s.replace_range(7..12, "世界");
7cac9316 534 assert_eq!(s, "Hello, 世界!");
7cac9316
XL
535}
536
537#[test]
538#[should_panic]
83c7162d 539fn test_replace_range_char_boundary() {
7cac9316 540 let mut s = "Hello, 世界!".to_owned();
83c7162d 541 s.replace_range(..8, "");
7cac9316
XL
542}
543
544#[test]
83c7162d 545fn test_replace_range_inclusive_range() {
7cac9316 546 let mut v = String::from("12345");
83c7162d 547 v.replace_range(2..=3, "789");
7cac9316 548 assert_eq!(v, "127895");
83c7162d 549 v.replace_range(1..=2, "A");
7cac9316 550 assert_eq!(v, "1A895");
7cac9316
XL
551}
552
553#[test]
554#[should_panic]
83c7162d 555fn test_replace_range_out_of_bounds() {
7cac9316 556 let mut s = String::from("12345");
83c7162d 557 s.replace_range(5..6, "789");
7cac9316
XL
558}
559
560#[test]
561#[should_panic]
83c7162d 562fn test_replace_range_inclusive_out_of_bounds() {
7cac9316 563 let mut s = String::from("12345");
83c7162d 564 s.replace_range(5..=5, "789");
7cac9316
XL
565}
566
1b1a35ee
XL
567#[test]
568#[should_panic]
569fn test_replace_range_start_overflow() {
570 let mut s = String::from("123");
571 s.replace_range((Excluded(usize::MAX), Included(0)), "");
572}
573
574#[test]
575#[should_panic]
576fn test_replace_range_end_overflow() {
577 let mut s = String::from("456");
578 s.replace_range((Included(0), Included(usize::MAX)), "");
579}
580
7cac9316 581#[test]
83c7162d 582fn test_replace_range_empty() {
7cac9316 583 let mut s = String::from("12345");
83c7162d 584 s.replace_range(1..2, "");
7cac9316 585 assert_eq!(s, "1345");
7cac9316
XL
586}
587
588#[test]
83c7162d 589fn test_replace_range_unbounded() {
7cac9316 590 let mut s = String::from("12345");
83c7162d 591 s.replace_range(.., "");
7cac9316 592 assert_eq!(s, "");
7cac9316
XL
593}
594
5869c6ff
XL
595#[test]
596fn test_replace_range_evil_start_bound() {
597 struct EvilRange(Cell<bool>);
598
599 impl RangeBounds<usize> for EvilRange {
600 fn start_bound(&self) -> Bound<&usize> {
601 Bound::Included(if self.0.get() {
602 &1
603 } else {
604 self.0.set(true);
605 &0
606 })
607 }
608 fn end_bound(&self) -> Bound<&usize> {
609 Bound::Unbounded
610 }
611 }
612
613 let mut s = String::from("🦀");
614 s.replace_range(EvilRange(Cell::new(false)), "");
615 assert_eq!(Ok(""), str::from_utf8(s.as_bytes()));
616}
617
618#[test]
619fn test_replace_range_evil_end_bound() {
620 struct EvilRange(Cell<bool>);
621
622 impl RangeBounds<usize> for EvilRange {
623 fn start_bound(&self) -> Bound<&usize> {
624 Bound::Included(&0)
625 }
626 fn end_bound(&self) -> Bound<&usize> {
627 Bound::Excluded(if self.0.get() {
628 &3
629 } else {
630 self.0.set(true);
631 &4
632 })
633 }
634 }
635
636 let mut s = String::from("🦀");
637 s.replace_range(EvilRange(Cell::new(false)), "");
638 assert_eq!(Ok(""), str::from_utf8(s.as_bytes()));
639}
640
62682a34
SL
641#[test]
642fn test_extend_ref() {
643 let mut a = "foo".to_string();
644 a.extend(&['b', 'a', 'r']);
645
646 assert_eq!(&a, "foobar");
647}
648
c1a9b12d 649#[test]
e9174d1e 650fn test_into_boxed_str() {
c1a9b12d 651 let xs = String::from("hello my name is bob");
e9174d1e 652 let ys = xs.into_boxed_str();
c1a9b12d
SL
653 assert_eq!(&*ys, "hello my name is bob");
654}
0531ce1d
XL
655
656#[test]
657fn test_reserve_exact() {
658 // This is all the same as test_reserve
659
660 let mut s = String::new();
661 assert_eq!(s.capacity(), 0);
662
663 s.reserve_exact(2);
664 assert!(s.capacity() >= 2);
665
666 for _i in 0..16 {
667 s.push('0');
668 }
669
670 assert!(s.capacity() >= 16);
671 s.reserve_exact(16);
672 assert!(s.capacity() >= 32);
673
674 s.push('0');
675
676 s.reserve_exact(16);
677 assert!(s.capacity() >= 33)
678}
679
680#[test]
60c5eb7d 681#[cfg_attr(miri, ignore)] // Miri does not support signalling OOM
ba9703b0 682#[cfg_attr(target_os = "android", ignore)] // Android used in CI has a broken dlmalloc
0531ce1d 683fn test_try_reserve() {
0531ce1d
XL
684 // These are the interesting cases:
685 // * exactly isize::MAX should never trigger a CapacityOverflow (can be OOM)
686 // * > isize::MAX should always fail
687 // * On 16/32-bit should CapacityOverflow
688 // * On 64-bit should OOM
689 // * overflow may trigger when adding `len` to `cap` (in number of elements)
690 // * overflow may trigger when multiplying `new_cap` by size_of::<T> (to get bytes)
691
692 const MAX_CAP: usize = isize::MAX as usize;
693 const MAX_USIZE: usize = usize::MAX;
694
695 // On 16/32-bit, we check that allocations don't exceed isize::MAX,
696 // on 64-bit, we assume the OS will give an OOM for such a ridiculous size.
697 // Any platform that succeeds for these requests is technically broken with
698 // ptr::offset because LLVM is the worst.
1b1a35ee 699 let guards_against_isize = usize::BITS < 64;
0531ce1d
XL
700
701 {
702 // Note: basic stuff is checked by test_reserve
703 let mut empty_string: String = String::new();
704
705 // Check isize::MAX doesn't count as an overflow
706 if let Err(CapacityOverflow) = empty_string.try_reserve(MAX_CAP) {
707 panic!("isize::MAX shouldn't trigger an overflow!");
708 }
709 // Play it again, frank! (just to be sure)
710 if let Err(CapacityOverflow) = empty_string.try_reserve(MAX_CAP) {
711 panic!("isize::MAX shouldn't trigger an overflow!");
712 }
713
714 if guards_against_isize {
715 // Check isize::MAX + 1 does count as overflow
716 if let Err(CapacityOverflow) = empty_string.try_reserve(MAX_CAP + 1) {
dfeec247
XL
717 } else {
718 panic!("isize::MAX + 1 should trigger an overflow!")
719 }
0531ce1d
XL
720
721 // Check usize::MAX does count as overflow
722 if let Err(CapacityOverflow) = empty_string.try_reserve(MAX_USIZE) {
dfeec247
XL
723 } else {
724 panic!("usize::MAX should trigger an overflow!")
725 }
0531ce1d
XL
726 } else {
727 // Check isize::MAX + 1 is an OOM
e1599b0c 728 if let Err(AllocError { .. }) = empty_string.try_reserve(MAX_CAP + 1) {
dfeec247
XL
729 } else {
730 panic!("isize::MAX + 1 should trigger an OOM!")
731 }
0531ce1d
XL
732
733 // Check usize::MAX is an OOM
e1599b0c 734 if let Err(AllocError { .. }) = empty_string.try_reserve(MAX_USIZE) {
dfeec247
XL
735 } else {
736 panic!("usize::MAX should trigger an OOM!")
737 }
0531ce1d
XL
738 }
739 }
740
0531ce1d
XL
741 {
742 // Same basic idea, but with non-zero len
743 let mut ten_bytes: String = String::from("0123456789");
744
745 if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_CAP - 10) {
746 panic!("isize::MAX shouldn't trigger an overflow!");
747 }
748 if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_CAP - 10) {
749 panic!("isize::MAX shouldn't trigger an overflow!");
750 }
751 if guards_against_isize {
752 if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_CAP - 9) {
dfeec247
XL
753 } else {
754 panic!("isize::MAX + 1 should trigger an overflow!");
755 }
0531ce1d 756 } else {
e1599b0c 757 if let Err(AllocError { .. }) = ten_bytes.try_reserve(MAX_CAP - 9) {
dfeec247
XL
758 } else {
759 panic!("isize::MAX + 1 should trigger an OOM!")
760 }
0531ce1d
XL
761 }
762 // Should always overflow in the add-to-len
763 if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_USIZE) {
dfeec247
XL
764 } else {
765 panic!("usize::MAX should trigger an overflow!")
766 }
0531ce1d 767 }
0531ce1d
XL
768}
769
770#[test]
60c5eb7d 771#[cfg_attr(miri, ignore)] // Miri does not support signalling OOM
ba9703b0 772#[cfg_attr(target_os = "android", ignore)] // Android used in CI has a broken dlmalloc
0531ce1d 773fn test_try_reserve_exact() {
0531ce1d
XL
774 // This is exactly the same as test_try_reserve with the method changed.
775 // See that test for comments.
776
777 const MAX_CAP: usize = isize::MAX as usize;
778 const MAX_USIZE: usize = usize::MAX;
779
1b1a35ee 780 let guards_against_isize = usize::BITS < 64;
0531ce1d
XL
781
782 {
783 let mut empty_string: String = String::new();
784
785 if let Err(CapacityOverflow) = empty_string.try_reserve_exact(MAX_CAP) {
786 panic!("isize::MAX shouldn't trigger an overflow!");
787 }
788 if let Err(CapacityOverflow) = empty_string.try_reserve_exact(MAX_CAP) {
789 panic!("isize::MAX shouldn't trigger an overflow!");
790 }
791
792 if guards_against_isize {
793 if let Err(CapacityOverflow) = empty_string.try_reserve_exact(MAX_CAP + 1) {
dfeec247
XL
794 } else {
795 panic!("isize::MAX + 1 should trigger an overflow!")
796 }
0531ce1d
XL
797
798 if let Err(CapacityOverflow) = empty_string.try_reserve_exact(MAX_USIZE) {
dfeec247
XL
799 } else {
800 panic!("usize::MAX should trigger an overflow!")
801 }
0531ce1d 802 } else {
e1599b0c 803 if let Err(AllocError { .. }) = empty_string.try_reserve_exact(MAX_CAP + 1) {
dfeec247
XL
804 } else {
805 panic!("isize::MAX + 1 should trigger an OOM!")
806 }
0531ce1d 807
e1599b0c 808 if let Err(AllocError { .. }) = empty_string.try_reserve_exact(MAX_USIZE) {
dfeec247
XL
809 } else {
810 panic!("usize::MAX should trigger an OOM!")
811 }
0531ce1d
XL
812 }
813 }
814
0531ce1d
XL
815 {
816 let mut ten_bytes: String = String::from("0123456789");
817
818 if let Err(CapacityOverflow) = ten_bytes.try_reserve_exact(MAX_CAP - 10) {
819 panic!("isize::MAX shouldn't trigger an overflow!");
820 }
821 if let Err(CapacityOverflow) = ten_bytes.try_reserve_exact(MAX_CAP - 10) {
822 panic!("isize::MAX shouldn't trigger an overflow!");
823 }
824 if guards_against_isize {
825 if let Err(CapacityOverflow) = ten_bytes.try_reserve_exact(MAX_CAP - 9) {
dfeec247
XL
826 } else {
827 panic!("isize::MAX + 1 should trigger an overflow!");
828 }
0531ce1d 829 } else {
e1599b0c 830 if let Err(AllocError { .. }) = ten_bytes.try_reserve_exact(MAX_CAP - 9) {
dfeec247
XL
831 } else {
832 panic!("isize::MAX + 1 should trigger an OOM!")
833 }
0531ce1d
XL
834 }
835 if let Err(CapacityOverflow) = ten_bytes.try_reserve_exact(MAX_USIZE) {
dfeec247
XL
836 } else {
837 panic!("usize::MAX should trigger an overflow!")
838 }
0531ce1d 839 }
0531ce1d 840}
f035d41b
XL
841
842#[test]
843fn test_from_char() {
844 assert_eq!(String::from('a'), 'a'.to_string());
845 let s: String = 'x'.into();
846 assert_eq!(s, 'x'.to_string());
847}
1b1a35ee
XL
848
849#[test]
850fn test_str_concat() {
851 let a: String = "hello".to_string();
852 let b: String = "world".to_string();
853 let s: String = format!("{}{}", a, b);
854 assert_eq!(s.as_bytes()[9], 'd' as u8);
855}