]>
Commit | Line | Data |
---|---|---|
7453a54e | 1 | use std::borrow::Cow; |
5869c6ff | 2 | use std::cell::Cell; |
e1599b0c | 3 | use std::collections::TryReserveError::*; |
5869c6ff | 4 | use std::ops::Bound; |
1b1a35ee | 5 | use std::ops::Bound::*; |
5869c6ff | 6 | use std::ops::RangeBounds; |
29967ef6 | 7 | use std::panic; |
5869c6ff | 8 | use std::str; |
c34b1796 | 9 | |
dfeec247 XL |
10 | pub trait IntoCow<'a, B: ?Sized> |
11 | where | |
12 | B: ToOwned, | |
13 | { | |
7453a54e SL |
14 | fn into_cow(self) -> Cow<'a, B>; |
15 | } | |
16 | ||
17 | impl<'a> IntoCow<'a, str> for String { | |
18 | fn into_cow(self) -> Cow<'a, str> { | |
19 | Cow::Owned(self) | |
20 | } | |
21 | } | |
22 | ||
23 | impl<'a> IntoCow<'a, str> for &'a str { | |
24 | fn into_cow(self) -> Cow<'a, str> { | |
25 | Cow::Borrowed(self) | |
26 | } | |
27 | } | |
28 | ||
c34b1796 AL |
29 | #[test] |
30 | fn 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] |
36 | fn test_from_cow_str() { | |
37 | assert_eq!(String::from(Cow::Borrowed("string")), "string"); | |
38 | assert_eq!(String::from(Cow::Owned(String::from("string"))), "string"); | |
39 | } | |
40 | ||
c34b1796 AL |
41 | #[test] |
42 | fn test_unsized_to_string() { | |
43 | let s: &str = "abc"; | |
44 | let _: String = (*s).to_string(); | |
45 | } | |
46 | ||
47 | #[test] | |
48 | fn test_from_utf8() { | |
49 | let xs = b"hello".to_vec(); | |
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] | |
65 | fn 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] | |
119 | fn 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] | |
174 | fn test_utf16_invalid() { | |
175 | // completely positive cases tested above. | |
176 | // lead + eof | |
177 | assert!(String::from_utf16(&[0xD800]).is_err()); | |
178 | // lead + lead | |
179 | assert!(String::from_utf16(&[0xD800, 0xD800]).is_err()); | |
180 | ||
181 | // isolated trail | |
182 | assert!(String::from_utf16(&[0x0061, 0xDC00]).is_err()); | |
183 | ||
184 | // general | |
185 | assert!(String::from_utf16(&[0xD800, 0xd801, 0xdc8b, 0xD800]).is_err()); | |
186 | } | |
187 | ||
188 | #[test] | |
189 | fn test_from_utf16_lossy() { | |
190 | // completely positive cases tested above. | |
191 | // lead + eof | |
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] | |
207 | fn 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] | |
217 | fn test_push_str() { | |
218 | let mut s = String::new(); | |
219 | s.push_str(""); | |
220 | assert_eq!(&s[0..], ""); | |
221 | s.push_str("abc"); | |
222 | assert_eq!(&s[0..], "abc"); | |
223 | s.push_str("ประเทศไทย中华Việt Nam"); | |
224 | assert_eq!(&s[0..], "abcประเทศไทย中华Việt Nam"); | |
225 | } | |
226 | ||
5bcae85e SL |
227 | #[test] |
228 | fn test_add_assign() { | |
229 | let mut s = String::new(); | |
230 | s += ""; | |
231 | assert_eq!(s.as_str(), ""); | |
232 | s += "abc"; | |
233 | assert_eq!(s.as_str(), "abc"); | |
234 | s += "ประเทศไทย中华Việt Nam"; | |
235 | assert_eq!(s.as_str(), "abcประเทศไทย中华Việt Nam"); | |
236 | } | |
237 | ||
c34b1796 AL |
238 | #[test] |
239 | fn 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] | |
250 | fn 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] |
261 | fn test_split_off_empty() { | |
262 | let orig = "Hello, world!"; | |
263 | let mut split = String::from(orig); | |
264 | let empty: String = split.split_off(orig.len()); | |
265 | assert!(empty.is_empty()); | |
266 | } | |
267 | ||
268 | #[test] | |
269 | #[should_panic] | |
270 | fn test_split_off_past_end() { | |
271 | let orig = "Hello, world!"; | |
272 | let mut split = String::from(orig); | |
ba9703b0 | 273 | let _ = split.split_off(orig.len() + 1); |
476ff2be SL |
274 | } |
275 | ||
276 | #[test] | |
277 | #[should_panic] | |
278 | fn 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] | |
284 | fn 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] | |
294 | fn 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] |
304 | fn 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 | 322 | fn 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] | |
330 | fn test_str_truncate_split_codepoint() { | |
62682a34 | 331 | let mut s = String::from("\u{FC}"); // ü |
c34b1796 AL |
332 | s.truncate(1); |
333 | } | |
334 | ||
335 | #[test] | |
336 | fn 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] | |
344 | fn 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] | |
353 | fn 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 |
364 | fn remove_bad() { |
365 | "ศ".to_string().remove(1); | |
366 | } | |
367 | ||
6a06907d XL |
368 | #[test] |
369 | fn 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] |
396 | fn 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] |
430 | fn 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] | |
440 | fn insert_bad1() { | |
441 | "".to_string().insert(1, 't'); | |
442 | } | |
443 | #[test] | |
444 | #[should_panic] | |
445 | fn insert_bad2() { | |
446 | "ệ".to_string().insert(1, 't'); | |
447 | } | |
c34b1796 AL |
448 | |
449 | #[test] | |
450 | fn 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] | |
459 | fn 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] | |
470 | fn 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] | |
479 | fn 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] |
500 | fn 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] | |
518 | fn 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] | |
525 | fn 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 | 531 | fn 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 | 539 | fn 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 | 545 | fn 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 | 555 | fn 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 | 562 | fn 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] | |
569 | fn 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] | |
576 | fn 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 | 582 | fn 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 | 589 | fn 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] |
596 | fn 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] | |
619 | fn 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] |
642 | fn 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 | 650 | fn 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] | |
657 | fn 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 | 683 | fn 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 | 773 | fn 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] | |
843 | fn 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] | |
850 | fn 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 | } |