]>
Commit | Line | Data |
---|---|---|
9346a6ac | 1 | // Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT |
c34b1796 AL |
2 | // file at the top-level directory of this distribution and at |
3 | // http://rust-lang.org/COPYRIGHT. | |
4 | // | |
5 | // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or | |
6 | // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license | |
7 | // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your | |
8 | // option. This file may not be copied, modified, or distributed | |
9 | // except according to those terms. | |
10 | ||
7453a54e | 11 | use std::borrow::Cow; |
c34b1796 | 12 | use std::cmp::Ordering::{Equal, Greater, Less}; |
62682a34 | 13 | use std::str::from_utf8; |
c34b1796 AL |
14 | |
15 | #[test] | |
16 | fn test_le() { | |
17 | assert!("" <= ""); | |
18 | assert!("" <= "foo"); | |
19 | assert!("foo" <= "foo"); | |
20 | assert!("foo" != "bar"); | |
21 | } | |
22 | ||
c34b1796 AL |
23 | #[test] |
24 | fn test_find() { | |
25 | assert_eq!("hello".find('l'), Some(2)); | |
26 | assert_eq!("hello".find(|c:char| c == 'o'), Some(4)); | |
27 | assert!("hello".find('x').is_none()); | |
28 | assert!("hello".find(|c:char| c == 'x').is_none()); | |
29 | assert_eq!("ประเทศไทย中华Việt Nam".find('华'), Some(30)); | |
30 | assert_eq!("ประเทศไทย中华Việt Nam".find(|c: char| c == '华'), Some(30)); | |
31 | } | |
32 | ||
33 | #[test] | |
34 | fn test_rfind() { | |
35 | assert_eq!("hello".rfind('l'), Some(3)); | |
36 | assert_eq!("hello".rfind(|c:char| c == 'o'), Some(4)); | |
37 | assert!("hello".rfind('x').is_none()); | |
38 | assert!("hello".rfind(|c:char| c == 'x').is_none()); | |
39 | assert_eq!("ประเทศไทย中华Việt Nam".rfind('华'), Some(30)); | |
40 | assert_eq!("ประเทศไทย中华Việt Nam".rfind(|c: char| c == '华'), Some(30)); | |
41 | } | |
42 | ||
43 | #[test] | |
44 | fn test_collect() { | |
b039eaaf | 45 | let empty = ""; |
c34b1796 AL |
46 | let s: String = empty.chars().collect(); |
47 | assert_eq!(empty, s); | |
b039eaaf | 48 | let data = "ประเทศไทย中"; |
c34b1796 AL |
49 | let s: String = data.chars().collect(); |
50 | assert_eq!(data, s); | |
51 | } | |
52 | ||
53 | #[test] | |
54 | fn test_into_bytes() { | |
62682a34 | 55 | let data = String::from("asdf"); |
c34b1796 AL |
56 | let buf = data.into_bytes(); |
57 | assert_eq!(buf, b"asdf"); | |
58 | } | |
59 | ||
60 | #[test] | |
61 | fn test_find_str() { | |
62 | // byte positions | |
63 | assert_eq!("".find(""), Some(0)); | |
64 | assert!("banana".find("apple pie").is_none()); | |
65 | ||
66 | let data = "abcabc"; | |
67 | assert_eq!(data[0..6].find("ab"), Some(0)); | |
68 | assert_eq!(data[2..6].find("ab"), Some(3 - 2)); | |
69 | assert!(data[2..4].find("ab").is_none()); | |
70 | ||
71 | let string = "ประเทศไทย中华Việt Nam"; | |
62682a34 | 72 | let mut data = String::from(string); |
c34b1796 AL |
73 | data.push_str(string); |
74 | assert!(data.find("ไท华").is_none()); | |
75 | assert_eq!(data[0..43].find(""), Some(0)); | |
76 | assert_eq!(data[6..43].find(""), Some(6 - 6)); | |
77 | ||
78 | assert_eq!(data[0..43].find("ประ"), Some( 0)); | |
79 | assert_eq!(data[0..43].find("ทศไ"), Some(12)); | |
80 | assert_eq!(data[0..43].find("ย中"), Some(24)); | |
81 | assert_eq!(data[0..43].find("iệt"), Some(34)); | |
82 | assert_eq!(data[0..43].find("Nam"), Some(40)); | |
83 | ||
84 | assert_eq!(data[43..86].find("ประ"), Some(43 - 43)); | |
85 | assert_eq!(data[43..86].find("ทศไ"), Some(55 - 43)); | |
86 | assert_eq!(data[43..86].find("ย中"), Some(67 - 43)); | |
87 | assert_eq!(data[43..86].find("iệt"), Some(77 - 43)); | |
88 | assert_eq!(data[43..86].find("Nam"), Some(83 - 43)); | |
c34b1796 | 89 | |
b039eaaf | 90 | // find every substring -- assert that it finds it, or an earlier occurrence. |
e9174d1e SL |
91 | let string = "Việt Namacbaabcaabaaba"; |
92 | for (i, ci) in string.char_indices() { | |
93 | let ip = i + ci.len_utf8(); | |
94 | for j in string[ip..].char_indices() | |
95 | .map(|(i, _)| i) | |
96 | .chain(Some(string.len() - ip)) | |
97 | { | |
98 | let pat = &string[i..ip + j]; | |
99 | assert!(match string.find(pat) { | |
100 | None => false, | |
101 | Some(x) => x <= i, | |
102 | }); | |
103 | assert!(match string.rfind(pat) { | |
104 | None => false, | |
105 | Some(x) => x >= i, | |
106 | }); | |
107 | } | |
c34b1796 | 108 | } |
c34b1796 AL |
109 | } |
110 | ||
111 | fn s(x: &str) -> String { x.to_string() } | |
112 | ||
113 | macro_rules! test_concat { | |
114 | ($expected: expr, $string: expr) => { | |
115 | { | |
116 | let s: String = $string.concat(); | |
117 | assert_eq!($expected, s); | |
118 | } | |
119 | } | |
120 | } | |
121 | ||
122 | #[test] | |
123 | fn test_concat_for_different_types() { | |
124 | test_concat!("ab", vec![s("a"), s("b")]); | |
125 | test_concat!("ab", vec!["a", "b"]); | |
c34b1796 AL |
126 | } |
127 | ||
128 | #[test] | |
129 | fn test_concat_for_different_lengths() { | |
130 | let empty: &[&str] = &[]; | |
131 | test_concat!("", empty); | |
132 | test_concat!("a", ["a"]); | |
133 | test_concat!("ab", ["a", "b"]); | |
134 | test_concat!("abc", ["", "a", "bc"]); | |
135 | } | |
136 | ||
c1a9b12d | 137 | macro_rules! test_join { |
c34b1796 AL |
138 | ($expected: expr, $string: expr, $delim: expr) => { |
139 | { | |
c1a9b12d | 140 | let s = $string.join($delim); |
c34b1796 AL |
141 | assert_eq!($expected, s); |
142 | } | |
143 | } | |
144 | } | |
145 | ||
146 | #[test] | |
c1a9b12d SL |
147 | fn test_join_for_different_types() { |
148 | test_join!("a-b", ["a", "b"], "-"); | |
c34b1796 | 149 | let hyphen = "-".to_string(); |
c1a9b12d SL |
150 | test_join!("a-b", [s("a"), s("b")], &*hyphen); |
151 | test_join!("a-b", vec!["a", "b"], &*hyphen); | |
152 | test_join!("a-b", &*vec!["a", "b"], "-"); | |
153 | test_join!("a-b", vec![s("a"), s("b")], "-"); | |
c34b1796 AL |
154 | } |
155 | ||
156 | #[test] | |
c1a9b12d | 157 | fn test_join_for_different_lengths() { |
c34b1796 | 158 | let empty: &[&str] = &[]; |
c1a9b12d SL |
159 | test_join!("", empty, "-"); |
160 | test_join!("a", ["a"], "-"); | |
161 | test_join!("a-b", ["a", "b"], "-"); | |
162 | test_join!("-a-bc", ["", "a", "bc"], "-"); | |
c34b1796 AL |
163 | } |
164 | ||
94b46f34 XL |
165 | // join has fast paths for small separators up to 4 bytes |
166 | // this tests the slow paths. | |
167 | #[test] | |
168 | fn test_join_for_different_lengths_with_long_separator() { | |
169 | assert_eq!("~~~~~".len(), 15); | |
170 | ||
171 | let empty: &[&str] = &[]; | |
172 | test_join!("", empty, "~~~~~"); | |
173 | test_join!("a", ["a"], "~~~~~"); | |
174 | test_join!("a~~~~~b", ["a", "b"], "~~~~~"); | |
175 | test_join!("~~~~~a~~~~~bc", ["", "a", "bc"], "~~~~~"); | |
176 | } | |
177 | ||
c34b1796 AL |
178 | #[test] |
179 | fn test_unsafe_slice() { | |
8faf50e0 XL |
180 | assert_eq!("ab", unsafe {"abc".get_unchecked(0..2)}); |
181 | assert_eq!("bc", unsafe {"abc".get_unchecked(1..3)}); | |
182 | assert_eq!("", unsafe {"abc".get_unchecked(1..1)}); | |
c34b1796 AL |
183 | fn a_million_letter_a() -> String { |
184 | let mut i = 0; | |
185 | let mut rs = String::new(); | |
186 | while i < 100000 { | |
187 | rs.push_str("aaaaaaaaaa"); | |
188 | i += 1; | |
189 | } | |
190 | rs | |
191 | } | |
192 | fn half_a_million_letter_a() -> String { | |
193 | let mut i = 0; | |
194 | let mut rs = String::new(); | |
195 | while i < 100000 { | |
196 | rs.push_str("aaaaa"); | |
197 | i += 1; | |
198 | } | |
199 | rs | |
200 | } | |
201 | let letters = a_million_letter_a(); | |
b039eaaf | 202 | assert_eq!(half_a_million_letter_a(), |
8faf50e0 | 203 | unsafe { letters.get_unchecked(0..500000)}); |
c34b1796 AL |
204 | } |
205 | ||
206 | #[test] | |
207 | fn test_starts_with() { | |
3157f602 XL |
208 | assert!("".starts_with("")); |
209 | assert!("abc".starts_with("")); | |
210 | assert!("abc".starts_with("a")); | |
211 | assert!(!"a".starts_with("abc")); | |
212 | assert!(!"".starts_with("abc")); | |
213 | assert!(!"ödd".starts_with("-")); | |
214 | assert!("ödd".starts_with("öd")); | |
c34b1796 AL |
215 | } |
216 | ||
217 | #[test] | |
218 | fn test_ends_with() { | |
3157f602 XL |
219 | assert!("".ends_with("")); |
220 | assert!("abc".ends_with("")); | |
221 | assert!("abc".ends_with("c")); | |
222 | assert!(!"a".ends_with("abc")); | |
223 | assert!(!"".ends_with("abc")); | |
224 | assert!(!"ddö".ends_with("-")); | |
225 | assert!("ddö".ends_with("dö")); | |
c34b1796 AL |
226 | } |
227 | ||
228 | #[test] | |
229 | fn test_is_empty() { | |
230 | assert!("".is_empty()); | |
231 | assert!(!"a".is_empty()); | |
232 | } | |
233 | ||
9e0c209e SL |
234 | #[test] |
235 | fn test_replacen() { | |
236 | assert_eq!("".replacen('a', "b", 5), ""); | |
237 | assert_eq!("acaaa".replacen("a", "b", 3), "bcbba"); | |
238 | assert_eq!("aaaa".replacen("a", "b", 0), "aaaa"); | |
239 | ||
240 | let test = "test"; | |
241 | assert_eq!(" test test ".replacen(test, "toast", 3), " toast toast "); | |
242 | assert_eq!(" test test ".replacen(test, "toast", 0), " test test "); | |
243 | assert_eq!(" test test ".replacen(test, "", 5), " "); | |
244 | ||
245 | assert_eq!("qwer123zxc789".replacen(char::is_numeric, "", 3), "qwerzxc789"); | |
246 | } | |
247 | ||
c34b1796 AL |
248 | #[test] |
249 | fn test_replace() { | |
250 | let a = "a"; | |
b039eaaf SL |
251 | assert_eq!("".replace(a, "b"), ""); |
252 | assert_eq!("a".replace(a, "b"), "b"); | |
253 | assert_eq!("ab".replace(a, "b"), "bb"); | |
c34b1796 | 254 | let test = "test"; |
b039eaaf SL |
255 | assert_eq!(" test test ".replace(test, "toast"), " toast toast "); |
256 | assert_eq!(" test test ".replace(test, ""), " "); | |
c34b1796 AL |
257 | } |
258 | ||
259 | #[test] | |
260 | fn test_replace_2a() { | |
261 | let data = "ประเทศไทย中华"; | |
262 | let repl = "دولة الكويت"; | |
263 | ||
264 | let a = "ประเ"; | |
265 | let a2 = "دولة الكويتทศไทย中华"; | |
266 | assert_eq!(data.replace(a, repl), a2); | |
267 | } | |
268 | ||
269 | #[test] | |
270 | fn test_replace_2b() { | |
271 | let data = "ประเทศไทย中华"; | |
272 | let repl = "دولة الكويت"; | |
273 | ||
274 | let b = "ะเ"; | |
275 | let b2 = "ปรدولة الكويتทศไทย中华"; | |
276 | assert_eq!(data.replace(b, repl), b2); | |
277 | } | |
278 | ||
279 | #[test] | |
280 | fn test_replace_2c() { | |
281 | let data = "ประเทศไทย中华"; | |
282 | let repl = "دولة الكويت"; | |
283 | ||
284 | let c = "中华"; | |
285 | let c2 = "ประเทศไทยدولة الكويت"; | |
286 | assert_eq!(data.replace(c, repl), c2); | |
287 | } | |
288 | ||
289 | #[test] | |
290 | fn test_replace_2d() { | |
291 | let data = "ประเทศไทย中华"; | |
292 | let repl = "دولة الكويت"; | |
293 | ||
294 | let d = "ไท华"; | |
295 | assert_eq!(data.replace(d, repl), data); | |
296 | } | |
297 | ||
9cc50fc6 SL |
298 | #[test] |
299 | fn test_replace_pattern() { | |
300 | let data = "abcdαβγδabcdαβγδ"; | |
301 | assert_eq!(data.replace("dαβ", "😺😺😺"), "abc😺😺😺γδabc😺😺😺γδ"); | |
302 | assert_eq!(data.replace('γ', "😺😺😺"), "abcdαβ😺😺😺δabcdαβ😺😺😺δ"); | |
303 | assert_eq!(data.replace(&['a', 'γ'] as &[_], "😺😺😺"), "😺😺😺bcdαβ😺😺😺δ😺😺😺bcdαβ😺😺😺δ"); | |
304 | assert_eq!(data.replace(|c| c == 'γ', "😺😺😺"), "abcdαβ😺😺😺δabcdαβ😺😺😺δ"); | |
305 | } | |
306 | ||
94b46f34 XL |
307 | // The current implementation of SliceIndex fails to handle methods |
308 | // orthogonally from range types; therefore, it is worth testing | |
309 | // all of the indexing operations on each input. | |
310 | mod slice_index { | |
311 | // Test a slicing operation **that should succeed,** | |
312 | // testing it on all of the indexing methods. | |
313 | // | |
314 | // This is not suitable for testing failure on invalid inputs. | |
315 | macro_rules! assert_range_eq { | |
316 | ($s:expr, $range:expr, $expected:expr) | |
317 | => { | |
318 | let mut s: String = $s.to_owned(); | |
319 | let mut expected: String = $expected.to_owned(); | |
320 | { | |
321 | let s: &str = &s; | |
322 | let expected: &str = &expected; | |
323 | ||
324 | assert_eq!(&s[$range], expected, "(in assertion for: index)"); | |
325 | assert_eq!(s.get($range), Some(expected), "(in assertion for: get)"); | |
326 | unsafe { | |
327 | assert_eq!( | |
328 | s.get_unchecked($range), expected, | |
329 | "(in assertion for: get_unchecked)", | |
330 | ); | |
331 | } | |
332 | } | |
333 | { | |
334 | let s: &mut str = &mut s; | |
335 | let expected: &mut str = &mut expected; | |
336 | ||
337 | assert_eq!( | |
338 | &mut s[$range], expected, | |
339 | "(in assertion for: index_mut)", | |
340 | ); | |
341 | assert_eq!( | |
342 | s.get_mut($range), Some(&mut expected[..]), | |
343 | "(in assertion for: get_mut)", | |
344 | ); | |
345 | unsafe { | |
346 | assert_eq!( | |
347 | s.get_unchecked_mut($range), expected, | |
348 | "(in assertion for: get_unchecked_mut)", | |
349 | ); | |
350 | } | |
351 | } | |
352 | } | |
353 | } | |
c34b1796 | 354 | |
94b46f34 XL |
355 | // Make sure the macro can actually detect bugs, |
356 | // because if it can't, then what are we even doing here? | |
357 | // | |
358 | // (Be aware this only demonstrates the ability to detect bugs | |
359 | // in the FIRST method that panics, as the macro is not designed | |
360 | // to be used in `should_panic`) | |
361 | #[test] | |
362 | #[should_panic(expected = "out of bounds")] | |
363 | fn assert_range_eq_can_fail_by_panic() { | |
364 | assert_range_eq!("abc", 0..5, "abc"); | |
365 | } | |
c34b1796 | 366 | |
94b46f34 XL |
367 | // (Be aware this only demonstrates the ability to detect bugs |
368 | // in the FIRST method it calls, as the macro is not designed | |
369 | // to be used in `should_panic`) | |
370 | #[test] | |
371 | #[should_panic(expected = "==")] | |
372 | fn assert_range_eq_can_fail_by_inequality() { | |
373 | assert_range_eq!("abc", 0..2, "abc"); | |
c34b1796 | 374 | } |
94b46f34 XL |
375 | |
376 | // Generates test cases for bad index operations. | |
377 | // | |
378 | // This generates `should_panic` test cases for Index/IndexMut | |
379 | // and `None` test cases for get/get_mut. | |
380 | macro_rules! panic_cases { | |
381 | ($( | |
382 | in mod $case_name:ident { | |
383 | data: $data:expr; | |
384 | ||
385 | // optional: | |
386 | // | |
387 | // a similar input for which DATA[input] succeeds, and the corresponding | |
388 | // output str. This helps validate "critical points" where an input range | |
389 | // straddles the boundary between valid and invalid. | |
390 | // (such as the input `len..len`, which is just barely valid) | |
391 | $( | |
392 | good: data[$good:expr] == $output:expr; | |
393 | )* | |
394 | ||
395 | bad: data[$bad:expr]; | |
396 | message: $expect_msg:expr; // must be a literal | |
397 | } | |
398 | )*) => {$( | |
399 | mod $case_name { | |
400 | #[test] | |
401 | fn pass() { | |
402 | let mut v: String = $data.into(); | |
403 | ||
404 | $( assert_range_eq!(v, $good, $output); )* | |
405 | ||
406 | { | |
407 | let v: &str = &v; | |
408 | assert_eq!(v.get($bad), None, "(in None assertion for get)"); | |
409 | } | |
410 | ||
411 | { | |
412 | let v: &mut str = &mut v; | |
413 | assert_eq!(v.get_mut($bad), None, "(in None assertion for get_mut)"); | |
414 | } | |
415 | } | |
416 | ||
417 | #[test] | |
418 | #[should_panic(expected = $expect_msg)] | |
419 | fn index_fail() { | |
420 | let v: String = $data.into(); | |
421 | let v: &str = &v; | |
422 | let _v = &v[$bad]; | |
423 | } | |
424 | ||
425 | #[test] | |
426 | #[should_panic(expected = $expect_msg)] | |
427 | fn index_mut_fail() { | |
428 | let mut v: String = $data.into(); | |
429 | let v: &mut str = &mut v; | |
430 | let _v = &mut v[$bad]; | |
431 | } | |
432 | } | |
433 | )*}; | |
434 | } | |
435 | ||
436 | #[test] | |
437 | fn simple_ascii() { | |
438 | assert_range_eq!("abc", .., "abc"); | |
439 | ||
440 | assert_range_eq!("abc", 0..2, "ab"); | |
441 | assert_range_eq!("abc", 0..=1, "ab"); | |
442 | assert_range_eq!("abc", ..2, "ab"); | |
443 | assert_range_eq!("abc", ..=1, "ab"); | |
444 | ||
445 | assert_range_eq!("abc", 1..3, "bc"); | |
446 | assert_range_eq!("abc", 1..=2, "bc"); | |
447 | assert_range_eq!("abc", 1..1, ""); | |
448 | assert_range_eq!("abc", 1..=0, ""); | |
449 | } | |
450 | ||
451 | #[test] | |
452 | fn simple_unicode() { | |
453 | // 日本 | |
454 | assert_range_eq!("\u{65e5}\u{672c}", .., "\u{65e5}\u{672c}"); | |
455 | ||
456 | assert_range_eq!("\u{65e5}\u{672c}", 0..3, "\u{65e5}"); | |
457 | assert_range_eq!("\u{65e5}\u{672c}", 0..=2, "\u{65e5}"); | |
458 | assert_range_eq!("\u{65e5}\u{672c}", ..3, "\u{65e5}"); | |
459 | assert_range_eq!("\u{65e5}\u{672c}", ..=2, "\u{65e5}"); | |
460 | ||
461 | assert_range_eq!("\u{65e5}\u{672c}", 3..6, "\u{672c}"); | |
462 | assert_range_eq!("\u{65e5}\u{672c}", 3..=5, "\u{672c}"); | |
463 | assert_range_eq!("\u{65e5}\u{672c}", 3.., "\u{672c}"); | |
464 | ||
465 | let data = "ประเทศไทย中华"; | |
466 | assert_range_eq!(data, 0..3, "ป"); | |
467 | assert_range_eq!(data, 3..6, "ร"); | |
468 | assert_range_eq!(data, 3..3, ""); | |
469 | assert_range_eq!(data, 30..33, "华"); | |
470 | ||
471 | /*0: 中 | |
472 | 3: 华 | |
473 | 6: V | |
474 | 7: i | |
475 | 8: ệ | |
476 | 11: t | |
477 | 12: | |
478 | 13: N | |
479 | 14: a | |
480 | 15: m */ | |
481 | let ss = "中华Việt Nam"; | |
482 | assert_range_eq!(ss, 3..6, "华"); | |
483 | assert_range_eq!(ss, 6..16, "Việt Nam"); | |
484 | assert_range_eq!(ss, 6..=15, "Việt Nam"); | |
485 | assert_range_eq!(ss, 6.., "Việt Nam"); | |
486 | ||
487 | assert_range_eq!(ss, 0..3, "中"); | |
488 | assert_range_eq!(ss, 3..7, "华V"); | |
489 | assert_range_eq!(ss, 3..=6, "华V"); | |
490 | assert_range_eq!(ss, 3..3, ""); | |
491 | assert_range_eq!(ss, 3..=2, ""); | |
492 | } | |
493 | ||
494 | #[test] | |
495 | #[cfg(not(target_arch = "asmjs"))] // hits an OOM | |
496 | fn simple_big() { | |
497 | fn a_million_letter_x() -> String { | |
498 | let mut i = 0; | |
499 | let mut rs = String::new(); | |
500 | while i < 100000 { | |
501 | rs.push_str("华华华华华华华华华华"); | |
502 | i += 1; | |
503 | } | |
504 | rs | |
c34b1796 | 505 | } |
94b46f34 XL |
506 | fn half_a_million_letter_x() -> String { |
507 | let mut i = 0; | |
508 | let mut rs = String::new(); | |
509 | while i < 100000 { | |
510 | rs.push_str("华华华华华"); | |
511 | i += 1; | |
512 | } | |
513 | rs | |
514 | } | |
515 | let letters = a_million_letter_x(); | |
516 | assert_range_eq!(letters, 0..3 * 500000, half_a_million_letter_x()); | |
c34b1796 | 517 | } |
c34b1796 | 518 | |
94b46f34 XL |
519 | #[test] |
520 | #[should_panic] | |
521 | fn test_slice_fail() { | |
522 | &"中华Việt Nam"[0..2]; | |
523 | } | |
c34b1796 | 524 | |
94b46f34 XL |
525 | panic_cases! { |
526 | in mod rangefrom_len { | |
527 | data: "abcdef"; | |
528 | good: data[6..] == ""; | |
529 | bad: data[7..]; | |
530 | message: "out of bounds"; | |
531 | } | |
c34b1796 | 532 | |
94b46f34 XL |
533 | in mod rangeto_len { |
534 | data: "abcdef"; | |
535 | good: data[..6] == "abcdef"; | |
536 | bad: data[..7]; | |
537 | message: "out of bounds"; | |
538 | } | |
c34b1796 | 539 | |
94b46f34 XL |
540 | in mod rangetoinclusive_len { |
541 | data: "abcdef"; | |
542 | good: data[..=5] == "abcdef"; | |
543 | bad: data[..=6]; | |
544 | message: "out of bounds"; | |
545 | } | |
c34b1796 | 546 | |
94b46f34 XL |
547 | in mod range_len_len { |
548 | data: "abcdef"; | |
549 | good: data[6..6] == ""; | |
550 | bad: data[7..7]; | |
551 | message: "out of bounds"; | |
552 | } | |
c34b1796 | 553 | |
94b46f34 XL |
554 | in mod rangeinclusive_len_len { |
555 | data: "abcdef"; | |
556 | good: data[6..=5] == ""; | |
557 | bad: data[7..=6]; | |
558 | message: "out of bounds"; | |
559 | } | |
560 | } | |
041b39d2 | 561 | |
94b46f34 XL |
562 | panic_cases! { |
563 | in mod range_neg_width { | |
564 | data: "abcdef"; | |
565 | good: data[4..4] == ""; | |
566 | bad: data[4..3]; | |
567 | message: "begin <= end (4 <= 3)"; | |
568 | } | |
041b39d2 | 569 | |
94b46f34 XL |
570 | in mod rangeinclusive_neg_width { |
571 | data: "abcdef"; | |
572 | good: data[4..=3] == ""; | |
573 | bad: data[4..=2]; | |
574 | message: "begin <= end (4 <= 3)"; | |
575 | } | |
576 | } | |
041b39d2 | 577 | |
94b46f34 XL |
578 | mod overflow { |
579 | panic_cases! { | |
580 | in mod rangeinclusive { | |
581 | data: "hello"; | |
582 | // note: using 0 specifically ensures that the result of overflowing is 0..0, | |
583 | // so that `get` doesn't simply return None for the wrong reason. | |
584 | bad: data[0..=usize::max_value()]; | |
585 | message: "maximum usize"; | |
586 | } | |
587 | ||
588 | in mod rangetoinclusive { | |
589 | data: "hello"; | |
590 | bad: data[..=usize::max_value()]; | |
591 | message: "maximum usize"; | |
592 | } | |
593 | } | |
594 | } | |
041b39d2 | 595 | |
94b46f34 XL |
596 | mod boundary { |
597 | const DATA: &'static str = "abcαβγ"; | |
598 | ||
599 | const BAD_START: usize = 4; | |
600 | const GOOD_START: usize = 3; | |
601 | const BAD_END: usize = 6; | |
602 | const GOOD_END: usize = 7; | |
603 | const BAD_END_INCL: usize = BAD_END - 1; | |
604 | const GOOD_END_INCL: usize = GOOD_END - 1; | |
605 | ||
606 | // it is especially important to test all of the different range types here | |
607 | // because some of the logic may be duplicated as part of micro-optimizations | |
608 | // to dodge unicode boundary checks on half-ranges. | |
609 | panic_cases! { | |
610 | in mod range_1 { | |
611 | data: super::DATA; | |
612 | bad: data[super::BAD_START..super::GOOD_END]; | |
613 | message: | |
614 | "byte index 4 is not a char boundary; it is inside 'α' (bytes 3..5) of"; | |
615 | } | |
616 | ||
617 | in mod range_2 { | |
618 | data: super::DATA; | |
619 | bad: data[super::GOOD_START..super::BAD_END]; | |
620 | message: | |
621 | "byte index 6 is not a char boundary; it is inside 'β' (bytes 5..7) of"; | |
622 | } | |
623 | ||
624 | in mod rangefrom { | |
625 | data: super::DATA; | |
626 | bad: data[super::BAD_START..]; | |
627 | message: | |
628 | "byte index 4 is not a char boundary; it is inside 'α' (bytes 3..5) of"; | |
629 | } | |
630 | ||
631 | in mod rangeto { | |
632 | data: super::DATA; | |
633 | bad: data[..super::BAD_END]; | |
634 | message: | |
635 | "byte index 6 is not a char boundary; it is inside 'β' (bytes 5..7) of"; | |
636 | } | |
637 | ||
638 | in mod rangeinclusive_1 { | |
639 | data: super::DATA; | |
640 | bad: data[super::BAD_START..=super::GOOD_END_INCL]; | |
641 | message: | |
642 | "byte index 4 is not a char boundary; it is inside 'α' (bytes 3..5) of"; | |
643 | } | |
644 | ||
645 | in mod rangeinclusive_2 { | |
646 | data: super::DATA; | |
647 | bad: data[super::GOOD_START..=super::BAD_END_INCL]; | |
648 | message: | |
649 | "byte index 6 is not a char boundary; it is inside 'β' (bytes 5..7) of"; | |
650 | } | |
651 | ||
652 | in mod rangetoinclusive { | |
653 | data: super::DATA; | |
654 | bad: data[..=super::BAD_END_INCL]; | |
655 | message: | |
656 | "byte index 6 is not a char boundary; it is inside 'β' (bytes 5..7) of"; | |
657 | } | |
658 | } | |
041b39d2 | 659 | } |
94b46f34 XL |
660 | |
661 | const LOREM_PARAGRAPH: &'static str = "\ | |
662 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse quis lorem \ | |
663 | sit amet dolor ultricies condimentum. Praesent iaculis purus elit, ac malesuada \ | |
664 | quam malesuada in. Duis sed orci eros. Suspendisse sit amet magna mollis, mollis \ | |
665 | nunc luctus, imperdiet mi. Integer fringilla non sem ut lacinia. Fusce varius \ | |
666 | tortor a risus porttitor hendrerit. Morbi mauris dui, ultricies nec tempus vel, \ | |
667 | gravida nec quam."; | |
668 | ||
669 | // check the panic includes the prefix of the sliced string | |
670 | #[test] | |
671 | #[should_panic(expected="byte index 1024 is out of bounds of `Lorem ipsum dolor sit amet")] | |
672 | fn test_slice_fail_truncated_1() { | |
673 | &LOREM_PARAGRAPH[..1024]; | |
674 | } | |
675 | // check the truncation in the panic message | |
676 | #[test] | |
677 | #[should_panic(expected="luctus, im`[...]")] | |
678 | fn test_slice_fail_truncated_2() { | |
679 | &LOREM_PARAGRAPH[..1024]; | |
041b39d2 XL |
680 | } |
681 | } | |
a7813a04 | 682 | |
0531ce1d XL |
683 | #[test] |
684 | fn test_str_slice_rangetoinclusive_ok() { | |
685 | let s = "abcαβγ"; | |
686 | assert_eq!(&s[..=2], "abc"); | |
687 | assert_eq!(&s[..=4], "abcα"); | |
688 | } | |
689 | ||
690 | #[test] | |
691 | #[should_panic] | |
692 | fn test_str_slice_rangetoinclusive_notok() { | |
693 | let s = "abcαβγ"; | |
694 | &s[..=3]; | |
695 | } | |
696 | ||
697 | #[test] | |
698 | fn test_str_slicemut_rangetoinclusive_ok() { | |
699 | let mut s = "abcαβγ".to_owned(); | |
700 | let s: &mut str = &mut s; | |
701 | assert_eq!(&mut s[..=2], "abc"); | |
702 | assert_eq!(&mut s[..=4], "abcα"); | |
703 | } | |
704 | ||
705 | #[test] | |
706 | #[should_panic] | |
707 | fn test_str_slicemut_rangetoinclusive_notok() { | |
708 | let mut s = "abcαβγ".to_owned(); | |
709 | let s: &mut str = &mut s; | |
710 | &mut s[..=3]; | |
711 | } | |
712 | ||
a7813a04 XL |
713 | #[test] |
714 | fn test_is_char_boundary() { | |
715 | let s = "ศไทย中华Việt Nam β-release 🐱123"; | |
716 | assert!(s.is_char_boundary(0)); | |
717 | assert!(s.is_char_boundary(s.len())); | |
718 | assert!(!s.is_char_boundary(s.len() + 1)); | |
719 | for (i, ch) in s.char_indices() { | |
720 | // ensure character locations are boundaries and continuation bytes are not | |
721 | assert!(s.is_char_boundary(i), "{} is a char boundary in {:?}", i, s); | |
722 | for j in 1..ch.len_utf8() { | |
723 | assert!(!s.is_char_boundary(i + j), | |
724 | "{} should not be a char boundary in {:?}", i + j, s); | |
725 | } | |
726 | } | |
727 | } | |
c34b1796 AL |
728 | |
729 | #[test] | |
730 | fn test_trim_left_matches() { | |
731 | let v: &[char] = &[]; | |
732 | assert_eq!(" *** foo *** ".trim_left_matches(v), " *** foo *** "); | |
733 | let chars: &[char] = &['*', ' ']; | |
734 | assert_eq!(" *** foo *** ".trim_left_matches(chars), "foo *** "); | |
735 | assert_eq!(" *** *** ".trim_left_matches(chars), ""); | |
736 | assert_eq!("foo *** ".trim_left_matches(chars), "foo *** "); | |
737 | ||
738 | assert_eq!("11foo1bar11".trim_left_matches('1'), "foo1bar11"); | |
739 | let chars: &[char] = &['1', '2']; | |
740 | assert_eq!("12foo1bar12".trim_left_matches(chars), "foo1bar12"); | |
741 | assert_eq!("123foo1bar123".trim_left_matches(|c: char| c.is_numeric()), "foo1bar123"); | |
742 | } | |
743 | ||
744 | #[test] | |
745 | fn test_trim_right_matches() { | |
746 | let v: &[char] = &[]; | |
747 | assert_eq!(" *** foo *** ".trim_right_matches(v), " *** foo *** "); | |
748 | let chars: &[char] = &['*', ' ']; | |
749 | assert_eq!(" *** foo *** ".trim_right_matches(chars), " *** foo"); | |
750 | assert_eq!(" *** *** ".trim_right_matches(chars), ""); | |
751 | assert_eq!(" *** foo".trim_right_matches(chars), " *** foo"); | |
752 | ||
753 | assert_eq!("11foo1bar11".trim_right_matches('1'), "11foo1bar"); | |
754 | let chars: &[char] = &['1', '2']; | |
755 | assert_eq!("12foo1bar12".trim_right_matches(chars), "12foo1bar"); | |
756 | assert_eq!("123foo1bar123".trim_right_matches(|c: char| c.is_numeric()), "123foo1bar"); | |
757 | } | |
758 | ||
759 | #[test] | |
760 | fn test_trim_matches() { | |
761 | let v: &[char] = &[]; | |
762 | assert_eq!(" *** foo *** ".trim_matches(v), " *** foo *** "); | |
763 | let chars: &[char] = &['*', ' ']; | |
764 | assert_eq!(" *** foo *** ".trim_matches(chars), "foo"); | |
765 | assert_eq!(" *** *** ".trim_matches(chars), ""); | |
766 | assert_eq!("foo".trim_matches(chars), "foo"); | |
767 | ||
768 | assert_eq!("11foo1bar11".trim_matches('1'), "foo1bar"); | |
769 | let chars: &[char] = &['1', '2']; | |
770 | assert_eq!("12foo1bar12".trim_matches(chars), "foo1bar"); | |
771 | assert_eq!("123foo1bar123".trim_matches(|c: char| c.is_numeric()), "foo1bar"); | |
772 | } | |
773 | ||
774 | #[test] | |
775 | fn test_trim_left() { | |
776 | assert_eq!("".trim_left(), ""); | |
777 | assert_eq!("a".trim_left(), "a"); | |
778 | assert_eq!(" ".trim_left(), ""); | |
779 | assert_eq!(" blah".trim_left(), "blah"); | |
780 | assert_eq!(" \u{3000} wut".trim_left(), "wut"); | |
781 | assert_eq!("hey ".trim_left(), "hey "); | |
782 | } | |
783 | ||
784 | #[test] | |
785 | fn test_trim_right() { | |
786 | assert_eq!("".trim_right(), ""); | |
787 | assert_eq!("a".trim_right(), "a"); | |
788 | assert_eq!(" ".trim_right(), ""); | |
789 | assert_eq!("blah ".trim_right(), "blah"); | |
790 | assert_eq!("wut \u{3000} ".trim_right(), "wut"); | |
791 | assert_eq!(" hey".trim_right(), " hey"); | |
792 | } | |
793 | ||
794 | #[test] | |
795 | fn test_trim() { | |
796 | assert_eq!("".trim(), ""); | |
797 | assert_eq!("a".trim(), "a"); | |
798 | assert_eq!(" ".trim(), ""); | |
799 | assert_eq!(" blah ".trim(), "blah"); | |
800 | assert_eq!("\nwut \u{3000} ".trim(), "wut"); | |
801 | assert_eq!(" hey dude ".trim(), "hey dude"); | |
802 | } | |
803 | ||
804 | #[test] | |
805 | fn test_is_whitespace() { | |
806 | assert!("".chars().all(|c| c.is_whitespace())); | |
807 | assert!(" ".chars().all(|c| c.is_whitespace())); | |
808 | assert!("\u{2009}".chars().all(|c| c.is_whitespace())); // Thin space | |
809 | assert!(" \n\t ".chars().all(|c| c.is_whitespace())); | |
810 | assert!(!" _ ".chars().all(|c| c.is_whitespace())); | |
811 | } | |
812 | ||
c34b1796 AL |
813 | #[test] |
814 | fn test_is_utf8() { | |
815 | // deny overlong encodings | |
816 | assert!(from_utf8(&[0xc0, 0x80]).is_err()); | |
817 | assert!(from_utf8(&[0xc0, 0xae]).is_err()); | |
818 | assert!(from_utf8(&[0xe0, 0x80, 0x80]).is_err()); | |
819 | assert!(from_utf8(&[0xe0, 0x80, 0xaf]).is_err()); | |
820 | assert!(from_utf8(&[0xe0, 0x81, 0x81]).is_err()); | |
821 | assert!(from_utf8(&[0xf0, 0x82, 0x82, 0xac]).is_err()); | |
822 | assert!(from_utf8(&[0xf4, 0x90, 0x80, 0x80]).is_err()); | |
823 | ||
824 | // deny surrogates | |
825 | assert!(from_utf8(&[0xED, 0xA0, 0x80]).is_err()); | |
826 | assert!(from_utf8(&[0xED, 0xBF, 0xBF]).is_err()); | |
827 | ||
828 | assert!(from_utf8(&[0xC2, 0x80]).is_ok()); | |
829 | assert!(from_utf8(&[0xDF, 0xBF]).is_ok()); | |
830 | assert!(from_utf8(&[0xE0, 0xA0, 0x80]).is_ok()); | |
831 | assert!(from_utf8(&[0xED, 0x9F, 0xBF]).is_ok()); | |
832 | assert!(from_utf8(&[0xEE, 0x80, 0x80]).is_ok()); | |
833 | assert!(from_utf8(&[0xEF, 0xBF, 0xBF]).is_ok()); | |
834 | assert!(from_utf8(&[0xF0, 0x90, 0x80, 0x80]).is_ok()); | |
835 | assert!(from_utf8(&[0xF4, 0x8F, 0xBF, 0xBF]).is_ok()); | |
836 | } | |
837 | ||
9cc50fc6 SL |
838 | #[test] |
839 | fn from_utf8_mostly_ascii() { | |
840 | // deny invalid bytes embedded in long stretches of ascii | |
841 | for i in 32..64 { | |
842 | let mut data = [0; 128]; | |
843 | data[i] = 0xC0; | |
844 | assert!(from_utf8(&data).is_err()); | |
845 | data[i] = 0xC2; | |
846 | assert!(from_utf8(&data).is_err()); | |
847 | } | |
848 | } | |
849 | ||
cc61c64b XL |
850 | #[test] |
851 | fn from_utf8_error() { | |
852 | macro_rules! test { | |
853 | ($input: expr, $expected_valid_up_to: expr, $expected_error_len: expr) => { | |
854 | let error = from_utf8($input).unwrap_err(); | |
855 | assert_eq!(error.valid_up_to(), $expected_valid_up_to); | |
856 | assert_eq!(error.error_len(), $expected_error_len); | |
857 | } | |
858 | } | |
859 | test!(b"A\xC3\xA9 \xFF ", 4, Some(1)); | |
860 | test!(b"A\xC3\xA9 \x80 ", 4, Some(1)); | |
861 | test!(b"A\xC3\xA9 \xC1 ", 4, Some(1)); | |
862 | test!(b"A\xC3\xA9 \xC1", 4, Some(1)); | |
863 | test!(b"A\xC3\xA9 \xC2", 4, None); | |
864 | test!(b"A\xC3\xA9 \xC2 ", 4, Some(1)); | |
865 | test!(b"A\xC3\xA9 \xC2\xC0", 4, Some(1)); | |
866 | test!(b"A\xC3\xA9 \xE0", 4, None); | |
867 | test!(b"A\xC3\xA9 \xE0\x9F", 4, Some(1)); | |
868 | test!(b"A\xC3\xA9 \xE0\xA0", 4, None); | |
869 | test!(b"A\xC3\xA9 \xE0\xA0\xC0", 4, Some(2)); | |
870 | test!(b"A\xC3\xA9 \xE0\xA0 ", 4, Some(2)); | |
871 | test!(b"A\xC3\xA9 \xED\xA0\x80 ", 4, Some(1)); | |
872 | test!(b"A\xC3\xA9 \xF1", 4, None); | |
873 | test!(b"A\xC3\xA9 \xF1\x80", 4, None); | |
874 | test!(b"A\xC3\xA9 \xF1\x80\x80", 4, None); | |
875 | test!(b"A\xC3\xA9 \xF1 ", 4, Some(1)); | |
876 | test!(b"A\xC3\xA9 \xF1\x80 ", 4, Some(2)); | |
877 | test!(b"A\xC3\xA9 \xF1\x80\x80 ", 4, Some(3)); | |
878 | } | |
879 | ||
c34b1796 AL |
880 | #[test] |
881 | fn test_as_bytes() { | |
882 | // no null | |
883 | let v = [ | |
884 | 224, 184, 168, 224, 185, 132, 224, 184, 151, 224, 184, 162, 228, | |
885 | 184, 173, 229, 141, 142, 86, 105, 225, 187, 135, 116, 32, 78, 97, | |
886 | 109 | |
887 | ]; | |
888 | let b: &[u8] = &[]; | |
889 | assert_eq!("".as_bytes(), b); | |
890 | assert_eq!("abc".as_bytes(), b"abc"); | |
891 | assert_eq!("ศไทย中华Việt Nam".as_bytes(), v); | |
892 | } | |
893 | ||
894 | #[test] | |
895 | #[should_panic] | |
896 | fn test_as_bytes_fail() { | |
897 | // Don't double free. (I'm not sure if this exercises the | |
898 | // original problem code path anymore.) | |
62682a34 | 899 | let s = String::from(""); |
c34b1796 AL |
900 | let _bytes = s.as_bytes(); |
901 | panic!(); | |
902 | } | |
903 | ||
904 | #[test] | |
905 | fn test_as_ptr() { | |
906 | let buf = "hello".as_ptr(); | |
907 | unsafe { | |
908 | assert_eq!(*buf.offset(0), b'h'); | |
909 | assert_eq!(*buf.offset(1), b'e'); | |
910 | assert_eq!(*buf.offset(2), b'l'); | |
911 | assert_eq!(*buf.offset(3), b'l'); | |
912 | assert_eq!(*buf.offset(4), b'o'); | |
913 | } | |
914 | } | |
915 | ||
c34b1796 AL |
916 | #[test] |
917 | fn vec_str_conversions() { | |
62682a34 | 918 | let s1: String = String::from("All mimsy were the borogoves"); |
c34b1796 AL |
919 | |
920 | let v: Vec<u8> = s1.as_bytes().to_vec(); | |
62682a34 | 921 | let s2: String = String::from(from_utf8(&v).unwrap()); |
c34b1796 AL |
922 | let mut i = 0; |
923 | let n1 = s1.len(); | |
924 | let n2 = v.len(); | |
925 | assert_eq!(n1, n2); | |
926 | while i < n1 { | |
927 | let a: u8 = s1.as_bytes()[i]; | |
928 | let b: u8 = s2.as_bytes()[i]; | |
c34b1796 AL |
929 | assert_eq!(a, b); |
930 | i += 1; | |
931 | } | |
932 | } | |
933 | ||
934 | #[test] | |
935 | fn test_contains() { | |
936 | assert!("abcde".contains("bcd")); | |
937 | assert!("abcde".contains("abcd")); | |
938 | assert!("abcde".contains("bcde")); | |
939 | assert!("abcde".contains("")); | |
940 | assert!("".contains("")); | |
941 | assert!(!"abcde".contains("def")); | |
942 | assert!(!"".contains("a")); | |
943 | ||
944 | let data = "ประเทศไทย中华Việt Nam"; | |
945 | assert!(data.contains("ประเ")); | |
946 | assert!(data.contains("ะเ")); | |
947 | assert!(data.contains("中华")); | |
948 | assert!(!data.contains("ไท华")); | |
949 | } | |
950 | ||
951 | #[test] | |
952 | fn test_contains_char() { | |
953 | assert!("abc".contains('b')); | |
954 | assert!("a".contains('a')); | |
955 | assert!(!"abc".contains('d')); | |
956 | assert!(!"".contains('a')); | |
957 | } | |
958 | ||
62682a34 SL |
959 | #[test] |
960 | fn test_split_at() { | |
961 | let s = "ศไทย中华Việt Nam"; | |
962 | for (index, _) in s.char_indices() { | |
963 | let (a, b) = s.split_at(index); | |
964 | assert_eq!(&s[..a.len()], a); | |
965 | assert_eq!(&s[a.len()..], b); | |
966 | } | |
967 | let (a, b) = s.split_at(s.len()); | |
968 | assert_eq!(a, s); | |
969 | assert_eq!(b, ""); | |
970 | } | |
971 | ||
c1a9b12d SL |
972 | #[test] |
973 | fn test_split_at_mut() { | |
c1a9b12d SL |
974 | let mut s = "Hello World".to_string(); |
975 | { | |
976 | let (a, b) = s.split_at_mut(5); | |
977 | a.make_ascii_uppercase(); | |
978 | b.make_ascii_lowercase(); | |
979 | } | |
980 | assert_eq!(s, "HELLO world"); | |
981 | } | |
982 | ||
62682a34 SL |
983 | #[test] |
984 | #[should_panic] | |
985 | fn test_split_at_boundscheck() { | |
986 | let s = "ศไทย中华Việt Nam"; | |
c1a9b12d | 987 | s.split_at(1); |
62682a34 SL |
988 | } |
989 | ||
c34b1796 AL |
990 | #[test] |
991 | fn test_escape_unicode() { | |
b039eaaf SL |
992 | assert_eq!("abc".escape_unicode(), "\\u{61}\\u{62}\\u{63}"); |
993 | assert_eq!("a c".escape_unicode(), "\\u{61}\\u{20}\\u{63}"); | |
994 | assert_eq!("\r\n\t".escape_unicode(), "\\u{d}\\u{a}\\u{9}"); | |
995 | assert_eq!("'\"\\".escape_unicode(), "\\u{27}\\u{22}\\u{5c}"); | |
996 | assert_eq!("\x00\x01\u{fe}\u{ff}".escape_unicode(), "\\u{0}\\u{1}\\u{fe}\\u{ff}"); | |
997 | assert_eq!("\u{100}\u{ffff}".escape_unicode(), "\\u{100}\\u{ffff}"); | |
998 | assert_eq!("\u{10000}\u{10ffff}".escape_unicode(), "\\u{10000}\\u{10ffff}"); | |
999 | assert_eq!("ab\u{fb00}".escape_unicode(), "\\u{61}\\u{62}\\u{fb00}"); | |
1000 | assert_eq!("\u{1d4ea}\r".escape_unicode(), "\\u{1d4ea}\\u{d}"); | |
c34b1796 AL |
1001 | } |
1002 | ||
5bcae85e SL |
1003 | #[test] |
1004 | fn test_escape_debug() { | |
94b46f34 XL |
1005 | // Note that there are subtleties with the number of backslashes |
1006 | // on the left- and right-hand sides. In particular, Unicode code points | |
1007 | // are usually escaped with two backslashes on the right-hand side, as | |
1008 | // they are escaped. However, when the character is unescaped (e.g. for | |
1009 | // printable characters), only a single backslash appears (as the character | |
1010 | // itself appears in the debug string). | |
5bcae85e SL |
1011 | assert_eq!("abc".escape_debug(), "abc"); |
1012 | assert_eq!("a c".escape_debug(), "a c"); | |
1013 | assert_eq!("éèê".escape_debug(), "éèê"); | |
1014 | assert_eq!("\r\n\t".escape_debug(), "\\r\\n\\t"); | |
1015 | assert_eq!("'\"\\".escape_debug(), "\\'\\\"\\\\"); | |
1016 | assert_eq!("\u{7f}\u{ff}".escape_debug(), "\\u{7f}\u{ff}"); | |
1017 | assert_eq!("\u{100}\u{ffff}".escape_debug(), "\u{100}\\u{ffff}"); | |
1018 | assert_eq!("\u{10000}\u{10ffff}".escape_debug(), "\u{10000}\\u{10ffff}"); | |
1019 | assert_eq!("ab\u{200b}".escape_debug(), "ab\\u{200b}"); | |
1020 | assert_eq!("\u{10d4ea}\r".escape_debug(), "\\u{10d4ea}\\r"); | |
94b46f34 | 1021 | assert_eq!("\u{301}a\u{301}bé\u{e000}".escape_debug(), "\\u{301}a\u{301}bé\\u{e000}"); |
5bcae85e SL |
1022 | } |
1023 | ||
c34b1796 AL |
1024 | #[test] |
1025 | fn test_escape_default() { | |
b039eaaf SL |
1026 | assert_eq!("abc".escape_default(), "abc"); |
1027 | assert_eq!("a c".escape_default(), "a c"); | |
5bcae85e | 1028 | assert_eq!("éèê".escape_default(), "\\u{e9}\\u{e8}\\u{ea}"); |
b039eaaf SL |
1029 | assert_eq!("\r\n\t".escape_default(), "\\r\\n\\t"); |
1030 | assert_eq!("'\"\\".escape_default(), "\\'\\\"\\\\"); | |
5bcae85e | 1031 | assert_eq!("\u{7f}\u{ff}".escape_default(), "\\u{7f}\\u{ff}"); |
b039eaaf SL |
1032 | assert_eq!("\u{100}\u{ffff}".escape_default(), "\\u{100}\\u{ffff}"); |
1033 | assert_eq!("\u{10000}\u{10ffff}".escape_default(), "\\u{10000}\\u{10ffff}"); | |
5bcae85e SL |
1034 | assert_eq!("ab\u{200b}".escape_default(), "ab\\u{200b}"); |
1035 | assert_eq!("\u{10d4ea}\r".escape_default(), "\\u{10d4ea}\\r"); | |
c34b1796 AL |
1036 | } |
1037 | ||
1038 | #[test] | |
1039 | fn test_total_ord() { | |
b039eaaf SL |
1040 | assert_eq!("1234".cmp("123"), Greater); |
1041 | assert_eq!("123".cmp("1234"), Less); | |
1042 | assert_eq!("1234".cmp("1234"), Equal); | |
1043 | assert_eq!("12345555".cmp("123456"), Less); | |
1044 | assert_eq!("22".cmp("1234"), Greater); | |
c34b1796 AL |
1045 | } |
1046 | ||
c34b1796 AL |
1047 | #[test] |
1048 | fn test_iterator() { | |
1049 | let s = "ศไทย中华Việt Nam"; | |
1050 | let v = ['ศ','ไ','ท','ย','中','华','V','i','ệ','t',' ','N','a','m']; | |
1051 | ||
1052 | let mut pos = 0; | |
1053 | let it = s.chars(); | |
1054 | ||
1055 | for c in it { | |
1056 | assert_eq!(c, v[pos]); | |
1057 | pos += 1; | |
1058 | } | |
1059 | assert_eq!(pos, v.len()); | |
476ff2be | 1060 | assert_eq!(s.chars().count(), v.len()); |
c34b1796 AL |
1061 | } |
1062 | ||
1063 | #[test] | |
1064 | fn test_rev_iterator() { | |
1065 | let s = "ศไทย中华Việt Nam"; | |
1066 | let v = ['m', 'a', 'N', ' ', 't', 'ệ','i','V','华','中','ย','ท','ไ','ศ']; | |
1067 | ||
1068 | let mut pos = 0; | |
1069 | let it = s.chars().rev(); | |
1070 | ||
1071 | for c in it { | |
1072 | assert_eq!(c, v[pos]); | |
1073 | pos += 1; | |
1074 | } | |
1075 | assert_eq!(pos, v.len()); | |
1076 | } | |
1077 | ||
1078 | #[test] | |
1079 | fn test_chars_decoding() { | |
c30ab7b3 | 1080 | let mut bytes = [0; 4]; |
c34b1796 | 1081 | for c in (0..0x110000).filter_map(::std::char::from_u32) { |
c30ab7b3 | 1082 | let s = c.encode_utf8(&mut bytes); |
c34b1796 AL |
1083 | if Some(c) != s.chars().next() { |
1084 | panic!("character {:x}={} does not decode correctly", c as u32, c); | |
1085 | } | |
1086 | } | |
1087 | } | |
1088 | ||
1089 | #[test] | |
1090 | fn test_chars_rev_decoding() { | |
c30ab7b3 | 1091 | let mut bytes = [0; 4]; |
c34b1796 | 1092 | for c in (0..0x110000).filter_map(::std::char::from_u32) { |
c30ab7b3 | 1093 | let s = c.encode_utf8(&mut bytes); |
c34b1796 AL |
1094 | if Some(c) != s.chars().rev().next() { |
1095 | panic!("character {:x}={} does not decode correctly", c as u32, c); | |
1096 | } | |
1097 | } | |
1098 | } | |
1099 | ||
1100 | #[test] | |
1101 | fn test_iterator_clone() { | |
1102 | let s = "ศไทย中华Việt Nam"; | |
1103 | let mut it = s.chars(); | |
1104 | it.next(); | |
1105 | assert!(it.clone().zip(it).all(|(x,y)| x == y)); | |
1106 | } | |
1107 | ||
476ff2be SL |
1108 | #[test] |
1109 | fn test_iterator_last() { | |
1110 | let s = "ศไทย中华Việt Nam"; | |
1111 | let mut it = s.chars(); | |
1112 | it.next(); | |
1113 | assert_eq!(it.last(), Some('m')); | |
1114 | } | |
1115 | ||
c34b1796 AL |
1116 | #[test] |
1117 | fn test_bytesator() { | |
1118 | let s = "ศไทย中华Việt Nam"; | |
1119 | let v = [ | |
1120 | 224, 184, 168, 224, 185, 132, 224, 184, 151, 224, 184, 162, 228, | |
1121 | 184, 173, 229, 141, 142, 86, 105, 225, 187, 135, 116, 32, 78, 97, | |
1122 | 109 | |
1123 | ]; | |
1124 | let mut pos = 0; | |
1125 | ||
1126 | for b in s.bytes() { | |
1127 | assert_eq!(b, v[pos]); | |
1128 | pos += 1; | |
1129 | } | |
1130 | } | |
1131 | ||
1132 | #[test] | |
1133 | fn test_bytes_revator() { | |
1134 | let s = "ศไทย中华Việt Nam"; | |
1135 | let v = [ | |
1136 | 224, 184, 168, 224, 185, 132, 224, 184, 151, 224, 184, 162, 228, | |
1137 | 184, 173, 229, 141, 142, 86, 105, 225, 187, 135, 116, 32, 78, 97, | |
1138 | 109 | |
1139 | ]; | |
1140 | let mut pos = v.len(); | |
1141 | ||
1142 | for b in s.bytes().rev() { | |
1143 | pos -= 1; | |
1144 | assert_eq!(b, v[pos]); | |
1145 | } | |
1146 | } | |
1147 | ||
e9174d1e SL |
1148 | #[test] |
1149 | fn test_bytesator_nth() { | |
1150 | let s = "ศไทย中华Việt Nam"; | |
1151 | let v = [ | |
1152 | 224, 184, 168, 224, 185, 132, 224, 184, 151, 224, 184, 162, 228, | |
1153 | 184, 173, 229, 141, 142, 86, 105, 225, 187, 135, 116, 32, 78, 97, | |
1154 | 109 | |
1155 | ]; | |
1156 | ||
1157 | let mut b = s.bytes(); | |
1158 | assert_eq!(b.nth(2).unwrap(), v[2]); | |
1159 | assert_eq!(b.nth(10).unwrap(), v[10]); | |
1160 | assert_eq!(b.nth(200), None); | |
1161 | } | |
1162 | ||
1163 | #[test] | |
1164 | fn test_bytesator_count() { | |
1165 | let s = "ศไทย中华Việt Nam"; | |
1166 | ||
1167 | let b = s.bytes(); | |
1168 | assert_eq!(b.count(), 28) | |
1169 | } | |
1170 | ||
1171 | #[test] | |
1172 | fn test_bytesator_last() { | |
1173 | let s = "ศไทย中华Việt Nam"; | |
1174 | ||
1175 | let b = s.bytes(); | |
1176 | assert_eq!(b.last().unwrap(), 109) | |
1177 | } | |
1178 | ||
c34b1796 AL |
1179 | #[test] |
1180 | fn test_char_indicesator() { | |
1181 | let s = "ศไทย中华Việt Nam"; | |
1182 | let p = [0, 3, 6, 9, 12, 15, 18, 19, 20, 23, 24, 25, 26, 27]; | |
1183 | let v = ['ศ','ไ','ท','ย','中','华','V','i','ệ','t',' ','N','a','m']; | |
1184 | ||
1185 | let mut pos = 0; | |
1186 | let it = s.char_indices(); | |
1187 | ||
1188 | for c in it { | |
1189 | assert_eq!(c, (p[pos], v[pos])); | |
1190 | pos += 1; | |
1191 | } | |
1192 | assert_eq!(pos, v.len()); | |
1193 | assert_eq!(pos, p.len()); | |
1194 | } | |
1195 | ||
1196 | #[test] | |
1197 | fn test_char_indices_revator() { | |
1198 | let s = "ศไทย中华Việt Nam"; | |
1199 | let p = [27, 26, 25, 24, 23, 20, 19, 18, 15, 12, 9, 6, 3, 0]; | |
1200 | let v = ['m', 'a', 'N', ' ', 't', 'ệ','i','V','华','中','ย','ท','ไ','ศ']; | |
1201 | ||
1202 | let mut pos = 0; | |
1203 | let it = s.char_indices().rev(); | |
1204 | ||
1205 | for c in it { | |
1206 | assert_eq!(c, (p[pos], v[pos])); | |
1207 | pos += 1; | |
1208 | } | |
1209 | assert_eq!(pos, v.len()); | |
1210 | assert_eq!(pos, p.len()); | |
1211 | } | |
1212 | ||
476ff2be SL |
1213 | #[test] |
1214 | fn test_char_indices_last() { | |
1215 | let s = "ศไทย中华Việt Nam"; | |
1216 | let mut it = s.char_indices(); | |
1217 | it.next(); | |
1218 | assert_eq!(it.last(), Some((27, 'm'))); | |
1219 | } | |
1220 | ||
c34b1796 AL |
1221 | #[test] |
1222 | fn test_splitn_char_iterator() { | |
1223 | let data = "\nMäry häd ä little lämb\nLittle lämb\n"; | |
1224 | ||
1225 | let split: Vec<&str> = data.splitn(4, ' ').collect(); | |
1226 | assert_eq!(split, ["\nMäry", "häd", "ä", "little lämb\nLittle lämb\n"]); | |
1227 | ||
1228 | let split: Vec<&str> = data.splitn(4, |c: char| c == ' ').collect(); | |
1229 | assert_eq!(split, ["\nMäry", "häd", "ä", "little lämb\nLittle lämb\n"]); | |
1230 | ||
1231 | // Unicode | |
1232 | let split: Vec<&str> = data.splitn(4, 'ä').collect(); | |
1233 | assert_eq!(split, ["\nM", "ry h", "d ", " little lämb\nLittle lämb\n"]); | |
1234 | ||
1235 | let split: Vec<&str> = data.splitn(4, |c: char| c == 'ä').collect(); | |
1236 | assert_eq!(split, ["\nM", "ry h", "d ", " little lämb\nLittle lämb\n"]); | |
1237 | } | |
1238 | ||
1239 | #[test] | |
1240 | fn test_split_char_iterator_no_trailing() { | |
1241 | let data = "\nMäry häd ä little lämb\nLittle lämb\n"; | |
1242 | ||
1243 | let split: Vec<&str> = data.split('\n').collect(); | |
1244 | assert_eq!(split, ["", "Märy häd ä little lämb", "Little lämb", ""]); | |
1245 | ||
1246 | let split: Vec<&str> = data.split_terminator('\n').collect(); | |
1247 | assert_eq!(split, ["", "Märy häd ä little lämb", "Little lämb"]); | |
1248 | } | |
1249 | ||
1250 | #[test] | |
1251 | fn test_rsplit() { | |
1252 | let data = "\nMäry häd ä little lämb\nLittle lämb\n"; | |
1253 | ||
1254 | let split: Vec<&str> = data.rsplit(' ').collect(); | |
1255 | assert_eq!(split, ["lämb\n", "lämb\nLittle", "little", "ä", "häd", "\nMäry"]); | |
1256 | ||
1257 | let split: Vec<&str> = data.rsplit("lämb").collect(); | |
1258 | assert_eq!(split, ["\n", "\nLittle ", "\nMäry häd ä little "]); | |
1259 | ||
1260 | let split: Vec<&str> = data.rsplit(|c: char| c == 'ä').collect(); | |
1261 | assert_eq!(split, ["mb\n", "mb\nLittle l", " little l", "d ", "ry h", "\nM"]); | |
1262 | } | |
1263 | ||
1264 | #[test] | |
1265 | fn test_rsplitn() { | |
1266 | let data = "\nMäry häd ä little lämb\nLittle lämb\n"; | |
1267 | ||
1268 | let split: Vec<&str> = data.rsplitn(2, ' ').collect(); | |
1269 | assert_eq!(split, ["lämb\n", "\nMäry häd ä little lämb\nLittle"]); | |
1270 | ||
1271 | let split: Vec<&str> = data.rsplitn(2, "lämb").collect(); | |
1272 | assert_eq!(split, ["\n", "\nMäry häd ä little lämb\nLittle "]); | |
1273 | ||
1274 | let split: Vec<&str> = data.rsplitn(2, |c: char| c == 'ä').collect(); | |
1275 | assert_eq!(split, ["mb\n", "\nMäry häd ä little lämb\nLittle l"]); | |
1276 | } | |
1277 | ||
1278 | #[test] | |
d9579d0f | 1279 | fn test_split_whitespace() { |
c34b1796 | 1280 | let data = "\n \tMäry häd\tä little lämb\nLittle lämb\n"; |
d9579d0f | 1281 | let words: Vec<&str> = data.split_whitespace().collect(); |
c34b1796 AL |
1282 | assert_eq!(words, ["Märy", "häd", "ä", "little", "lämb", "Little", "lämb"]) |
1283 | } | |
1284 | ||
c34b1796 AL |
1285 | #[test] |
1286 | fn test_lines() { | |
e9174d1e | 1287 | let data = "\nMäry häd ä little lämb\n\r\nLittle lämb\n"; |
c34b1796 AL |
1288 | let lines: Vec<&str> = data.lines().collect(); |
1289 | assert_eq!(lines, ["", "Märy häd ä little lämb", "", "Little lämb"]); | |
1290 | ||
e9174d1e | 1291 | let data = "\r\nMäry häd ä little lämb\n\nLittle lämb"; // no trailing \n |
c34b1796 AL |
1292 | let lines: Vec<&str> = data.lines().collect(); |
1293 | assert_eq!(lines, ["", "Märy häd ä little lämb", "", "Little lämb"]); | |
1294 | } | |
1295 | ||
c34b1796 AL |
1296 | #[test] |
1297 | fn test_splitator() { | |
1298 | fn t(s: &str, sep: &str, u: &[&str]) { | |
1299 | let v: Vec<&str> = s.split(sep).collect(); | |
1300 | assert_eq!(v, u); | |
1301 | } | |
1302 | t("--1233345--", "12345", &["--1233345--"]); | |
1303 | t("abc::hello::there", "::", &["abc", "hello", "there"]); | |
1304 | t("::hello::there", "::", &["", "hello", "there"]); | |
1305 | t("hello::there::", "::", &["hello", "there", ""]); | |
1306 | t("::hello::there::", "::", &["", "hello", "there", ""]); | |
1307 | t("ประเทศไทย中华Việt Nam", "中华", &["ประเทศไทย", "Việt Nam"]); | |
1308 | t("zzXXXzzYYYzz", "zz", &["", "XXX", "YYY", ""]); | |
1309 | t("zzXXXzYYYz", "XXX", &["zz", "zYYYz"]); | |
1310 | t(".XXX.YYY.", ".", &["", "XXX", "YYY", ""]); | |
1311 | t("", ".", &[""]); | |
1312 | t("zz", "zz", &["",""]); | |
1313 | t("ok", "z", &["ok"]); | |
1314 | t("zzz", "zz", &["","z"]); | |
1315 | t("zzzzz", "zz", &["","","z"]); | |
1316 | } | |
1317 | ||
1318 | #[test] | |
1319 | fn test_str_default() { | |
1320 | use std::default::Default; | |
1321 | ||
1322 | fn t<S: Default + AsRef<str>>() { | |
1323 | let s: S = Default::default(); | |
1324 | assert_eq!(s.as_ref(), ""); | |
1325 | } | |
1326 | ||
1327 | t::<&str>(); | |
1328 | t::<String>(); | |
94b46f34 | 1329 | t::<&mut str>(); |
c34b1796 AL |
1330 | } |
1331 | ||
1332 | #[test] | |
1333 | fn test_str_container() { | |
1334 | fn sum_len(v: &[&str]) -> usize { | |
1335 | v.iter().map(|x| x.len()).sum() | |
1336 | } | |
1337 | ||
b039eaaf | 1338 | let s = "01234"; |
c34b1796 | 1339 | assert_eq!(5, sum_len(&["012", "", "34"])); |
b039eaaf SL |
1340 | assert_eq!(5, sum_len(&["01", "2", "34", ""])); |
1341 | assert_eq!(5, sum_len(&[s])); | |
c34b1796 AL |
1342 | } |
1343 | ||
1344 | #[test] | |
1345 | fn test_str_from_utf8() { | |
1346 | let xs = b"hello"; | |
1347 | assert_eq!(from_utf8(xs), Ok("hello")); | |
1348 | ||
1349 | let xs = "ศไทย中华Việt Nam".as_bytes(); | |
1350 | assert_eq!(from_utf8(xs), Ok("ศไทย中华Việt Nam")); | |
1351 | ||
1352 | let xs = b"hello\xFF"; | |
9346a6ac AL |
1353 | assert!(from_utf8(xs).is_err()); |
1354 | } | |
1355 | ||
1356 | #[test] | |
1357 | fn test_pattern_deref_forward() { | |
1358 | let data = "aabcdaa"; | |
1359 | assert!(data.contains("bcd")); | |
1360 | assert!(data.contains(&"bcd")); | |
1361 | assert!(data.contains(&"bcd".to_string())); | |
1362 | } | |
1363 | ||
1364 | #[test] | |
1365 | fn test_empty_match_indices() { | |
1366 | let data = "aä中!"; | |
1367 | let vec: Vec<_> = data.match_indices("").collect(); | |
b039eaaf | 1368 | assert_eq!(vec, [(0, ""), (1, ""), (3, ""), (6, ""), (7, "")]); |
9346a6ac AL |
1369 | } |
1370 | ||
1371 | #[test] | |
1372 | fn test_bool_from_str() { | |
1373 | assert_eq!("true".parse().ok(), Some(true)); | |
1374 | assert_eq!("false".parse().ok(), Some(false)); | |
1375 | assert_eq!("not even a boolean".parse::<bool>().ok(), None); | |
1376 | } | |
1377 | ||
1378 | fn check_contains_all_substrings(s: &str) { | |
1379 | assert!(s.contains("")); | |
1380 | for i in 0..s.len() { | |
1381 | for j in i+1..s.len() + 1 { | |
1382 | assert!(s.contains(&s[i..j])); | |
1383 | } | |
1384 | } | |
1385 | } | |
1386 | ||
1387 | #[test] | |
1388 | fn strslice_issue_16589() { | |
1389 | assert!("bananas".contains("nana")); | |
1390 | ||
1391 | // prior to the fix for #16589, x.contains("abcdabcd") returned false | |
1392 | // test all substrings for good measure | |
1393 | check_contains_all_substrings("012345678901234567890123456789bcdabcdabcd"); | |
1394 | } | |
1395 | ||
1396 | #[test] | |
1397 | fn strslice_issue_16878() { | |
1398 | assert!(!"1234567ah012345678901ah".contains("hah")); | |
1399 | assert!(!"00abc01234567890123456789abc".contains("bcabc")); | |
1400 | } | |
1401 | ||
1402 | ||
1403 | #[test] | |
1404 | fn test_strslice_contains() { | |
1405 | let x = "There are moments, Jeeves, when one asks oneself, 'Do trousers matter?'"; | |
1406 | check_contains_all_substrings(x); | |
1407 | } | |
1408 | ||
1409 | #[test] | |
1410 | fn test_rsplitn_char_iterator() { | |
1411 | let data = "\nMäry häd ä little lämb\nLittle lämb\n"; | |
1412 | ||
1413 | let mut split: Vec<&str> = data.rsplitn(4, ' ').collect(); | |
1414 | split.reverse(); | |
1415 | assert_eq!(split, ["\nMäry häd ä", "little", "lämb\nLittle", "lämb\n"]); | |
1416 | ||
1417 | let mut split: Vec<&str> = data.rsplitn(4, |c: char| c == ' ').collect(); | |
1418 | split.reverse(); | |
1419 | assert_eq!(split, ["\nMäry häd ä", "little", "lämb\nLittle", "lämb\n"]); | |
1420 | ||
1421 | // Unicode | |
1422 | let mut split: Vec<&str> = data.rsplitn(4, 'ä').collect(); | |
1423 | split.reverse(); | |
1424 | assert_eq!(split, ["\nMäry häd ", " little l", "mb\nLittle l", "mb\n"]); | |
1425 | ||
1426 | let mut split: Vec<&str> = data.rsplitn(4, |c: char| c == 'ä').collect(); | |
1427 | split.reverse(); | |
1428 | assert_eq!(split, ["\nMäry häd ", " little l", "mb\nLittle l", "mb\n"]); | |
1429 | } | |
1430 | ||
1431 | #[test] | |
1432 | fn test_split_char_iterator() { | |
1433 | let data = "\nMäry häd ä little lämb\nLittle lämb\n"; | |
1434 | ||
1435 | let split: Vec<&str> = data.split(' ').collect(); | |
1436 | assert_eq!( split, ["\nMäry", "häd", "ä", "little", "lämb\nLittle", "lämb\n"]); | |
1437 | ||
1438 | let mut rsplit: Vec<&str> = data.split(' ').rev().collect(); | |
1439 | rsplit.reverse(); | |
1440 | assert_eq!(rsplit, ["\nMäry", "häd", "ä", "little", "lämb\nLittle", "lämb\n"]); | |
1441 | ||
1442 | let split: Vec<&str> = data.split(|c: char| c == ' ').collect(); | |
1443 | assert_eq!( split, ["\nMäry", "häd", "ä", "little", "lämb\nLittle", "lämb\n"]); | |
1444 | ||
1445 | let mut rsplit: Vec<&str> = data.split(|c: char| c == ' ').rev().collect(); | |
1446 | rsplit.reverse(); | |
1447 | assert_eq!(rsplit, ["\nMäry", "häd", "ä", "little", "lämb\nLittle", "lämb\n"]); | |
1448 | ||
1449 | // Unicode | |
1450 | let split: Vec<&str> = data.split('ä').collect(); | |
1451 | assert_eq!( split, ["\nM", "ry h", "d ", " little l", "mb\nLittle l", "mb\n"]); | |
1452 | ||
1453 | let mut rsplit: Vec<&str> = data.split('ä').rev().collect(); | |
1454 | rsplit.reverse(); | |
1455 | assert_eq!(rsplit, ["\nM", "ry h", "d ", " little l", "mb\nLittle l", "mb\n"]); | |
1456 | ||
1457 | let split: Vec<&str> = data.split(|c: char| c == 'ä').collect(); | |
1458 | assert_eq!( split, ["\nM", "ry h", "d ", " little l", "mb\nLittle l", "mb\n"]); | |
1459 | ||
1460 | let mut rsplit: Vec<&str> = data.split(|c: char| c == 'ä').rev().collect(); | |
1461 | rsplit.reverse(); | |
1462 | assert_eq!(rsplit, ["\nM", "ry h", "d ", " little l", "mb\nLittle l", "mb\n"]); | |
1463 | } | |
1464 | ||
1465 | #[test] | |
1466 | fn test_rev_split_char_iterator_no_trailing() { | |
1467 | let data = "\nMäry häd ä little lämb\nLittle lämb\n"; | |
1468 | ||
1469 | let mut split: Vec<&str> = data.split('\n').rev().collect(); | |
1470 | split.reverse(); | |
1471 | assert_eq!(split, ["", "Märy häd ä little lämb", "Little lämb", ""]); | |
1472 | ||
1473 | let mut split: Vec<&str> = data.split_terminator('\n').rev().collect(); | |
1474 | split.reverse(); | |
1475 | assert_eq!(split, ["", "Märy häd ä little lämb", "Little lämb"]); | |
1476 | } | |
1477 | ||
1478 | #[test] | |
1479 | fn test_utf16_code_units() { | |
83c7162d | 1480 | assert_eq!("é\u{1F4A9}".encode_utf16().collect::<Vec<u16>>(), |
9346a6ac AL |
1481 | [0xE9, 0xD83D, 0xDCA9]) |
1482 | } | |
1483 | ||
1484 | #[test] | |
1485 | fn starts_with_in_unicode() { | |
1486 | assert!(!"├── Cargo.toml".starts_with("# ")); | |
1487 | } | |
1488 | ||
1489 | #[test] | |
1490 | fn starts_short_long() { | |
1491 | assert!(!"".starts_with("##")); | |
1492 | assert!(!"##".starts_with("####")); | |
1493 | assert!("####".starts_with("##")); | |
1494 | assert!(!"##ä".starts_with("####")); | |
1495 | assert!("####ä".starts_with("##")); | |
1496 | assert!(!"##".starts_with("####ä")); | |
1497 | assert!("##ä##".starts_with("##ä")); | |
1498 | ||
1499 | assert!("".starts_with("")); | |
1500 | assert!("ä".starts_with("")); | |
1501 | assert!("#ä".starts_with("")); | |
1502 | assert!("##ä".starts_with("")); | |
1503 | assert!("ä###".starts_with("")); | |
1504 | assert!("#ä##".starts_with("")); | |
1505 | assert!("##ä#".starts_with("")); | |
1506 | } | |
1507 | ||
1508 | #[test] | |
1509 | fn contains_weird_cases() { | |
1510 | assert!("* \t".contains(' ')); | |
1511 | assert!(!"* \t".contains('?')); | |
1512 | assert!(!"* \t".contains('\u{1F4A9}')); | |
1513 | } | |
1514 | ||
1515 | #[test] | |
1516 | fn trim_ws() { | |
1517 | assert_eq!(" \t a \t ".trim_left_matches(|c: char| c.is_whitespace()), | |
1518 | "a \t "); | |
1519 | assert_eq!(" \t a \t ".trim_right_matches(|c: char| c.is_whitespace()), | |
1520 | " \t a"); | |
1521 | assert_eq!(" \t a \t ".trim_matches(|c: char| c.is_whitespace()), | |
1522 | "a"); | |
1523 | assert_eq!(" \t \t ".trim_left_matches(|c: char| c.is_whitespace()), | |
1524 | ""); | |
1525 | assert_eq!(" \t \t ".trim_right_matches(|c: char| c.is_whitespace()), | |
1526 | ""); | |
1527 | assert_eq!(" \t \t ".trim_matches(|c: char| c.is_whitespace()), | |
1528 | ""); | |
1529 | } | |
1530 | ||
62682a34 SL |
1531 | #[test] |
1532 | fn to_lowercase() { | |
1533 | assert_eq!("".to_lowercase(), ""); | |
1534 | assert_eq!("AÉDžaé ".to_lowercase(), "aédžaé "); | |
1535 | ||
1536 | // https://github.com/rust-lang/rust/issues/26035 | |
1537 | assert_eq!("ΑΣ".to_lowercase(), "ας"); | |
1538 | assert_eq!("Α'Σ".to_lowercase(), "α'ς"); | |
1539 | assert_eq!("Α''Σ".to_lowercase(), "α''ς"); | |
1540 | ||
1541 | assert_eq!("ΑΣ Α".to_lowercase(), "ας α"); | |
1542 | assert_eq!("Α'Σ Α".to_lowercase(), "α'ς α"); | |
1543 | assert_eq!("Α''Σ Α".to_lowercase(), "α''ς α"); | |
1544 | ||
1545 | assert_eq!("ΑΣ' Α".to_lowercase(), "ας' α"); | |
1546 | assert_eq!("ΑΣ'' Α".to_lowercase(), "ας'' α"); | |
1547 | ||
1548 | assert_eq!("Α'Σ' Α".to_lowercase(), "α'ς' α"); | |
1549 | assert_eq!("Α''Σ'' Α".to_lowercase(), "α''ς'' α"); | |
1550 | ||
1551 | assert_eq!("Α Σ".to_lowercase(), "α σ"); | |
1552 | assert_eq!("Α 'Σ".to_lowercase(), "α 'σ"); | |
1553 | assert_eq!("Α ''Σ".to_lowercase(), "α ''σ"); | |
1554 | ||
1555 | assert_eq!("Σ".to_lowercase(), "σ"); | |
1556 | assert_eq!("'Σ".to_lowercase(), "'σ"); | |
1557 | assert_eq!("''Σ".to_lowercase(), "''σ"); | |
1558 | ||
1559 | assert_eq!("ΑΣΑ".to_lowercase(), "ασα"); | |
1560 | assert_eq!("ΑΣ'Α".to_lowercase(), "ασ'α"); | |
1561 | assert_eq!("ΑΣ''Α".to_lowercase(), "ασ''α"); | |
1562 | } | |
1563 | ||
1564 | #[test] | |
1565 | fn to_uppercase() { | |
1566 | assert_eq!("".to_uppercase(), ""); | |
1567 | assert_eq!("aéDžßfiᾀ".to_uppercase(), "AÉDŽSSFIἈΙ"); | |
1568 | } | |
1569 | ||
c1a9b12d SL |
1570 | #[test] |
1571 | fn test_into_string() { | |
1572 | // The only way to acquire a Box<str> in the first place is through a String, so just | |
1573 | // test that we can round-trip between Box<str> and String. | |
1574 | let string = String::from("Some text goes here"); | |
e9174d1e | 1575 | assert_eq!(string.clone().into_boxed_str().into_string(), string); |
c1a9b12d SL |
1576 | } |
1577 | ||
1578 | #[test] | |
1579 | fn test_box_slice_clone() { | |
1580 | let data = String::from("hello HELLO hello HELLO yes YES 5 中ä华!!!"); | |
e9174d1e | 1581 | let data2 = data.clone().into_boxed_str().clone().into_string(); |
c1a9b12d SL |
1582 | |
1583 | assert_eq!(data, data2); | |
1584 | } | |
1585 | ||
7453a54e SL |
1586 | #[test] |
1587 | fn test_cow_from() { | |
1588 | let borrowed = "borrowed"; | |
1589 | let owned = String::from("owned"); | |
1590 | match (Cow::from(owned.clone()), Cow::from(borrowed)) { | |
1591 | (Cow::Owned(o), Cow::Borrowed(b)) => assert!(o == owned && b == borrowed), | |
1592 | _ => panic!("invalid `Cow::from`"), | |
1593 | } | |
1594 | } | |
1595 | ||
c30ab7b3 SL |
1596 | #[test] |
1597 | fn test_repeat() { | |
1598 | assert_eq!("".repeat(3), ""); | |
1599 | assert_eq!("abc".repeat(0), ""); | |
1600 | assert_eq!("α".repeat(3), "ααα"); | |
1601 | } | |
1602 | ||
9346a6ac AL |
1603 | mod pattern { |
1604 | use std::str::pattern::Pattern; | |
1605 | use std::str::pattern::{Searcher, ReverseSearcher}; | |
1606 | use std::str::pattern::SearchStep::{self, Match, Reject, Done}; | |
1607 | ||
1608 | macro_rules! make_test { | |
1609 | ($name:ident, $p:expr, $h:expr, [$($e:expr,)*]) => { | |
62682a34 | 1610 | #[allow(unused_imports)] |
9346a6ac AL |
1611 | mod $name { |
1612 | use std::str::pattern::SearchStep::{Match, Reject}; | |
1613 | use super::{cmp_search_to_vec}; | |
1614 | #[test] | |
1615 | fn fwd() { | |
1616 | cmp_search_to_vec(false, $p, $h, vec![$($e),*]); | |
1617 | } | |
1618 | #[test] | |
1619 | fn bwd() { | |
1620 | cmp_search_to_vec(true, $p, $h, vec![$($e),*]); | |
1621 | } | |
1622 | } | |
1623 | } | |
1624 | } | |
1625 | ||
1626 | fn cmp_search_to_vec<'a, P: Pattern<'a>>(rev: bool, pat: P, haystack: &'a str, | |
1627 | right: Vec<SearchStep>) | |
1628 | where P::Searcher: ReverseSearcher<'a> | |
1629 | { | |
1630 | let mut searcher = pat.into_searcher(haystack); | |
1631 | let mut v = vec![]; | |
1632 | loop { | |
1633 | match if !rev {searcher.next()} else {searcher.next_back()} { | |
1634 | Match(a, b) => v.push(Match(a, b)), | |
1635 | Reject(a, b) => v.push(Reject(a, b)), | |
1636 | Done => break, | |
1637 | } | |
1638 | } | |
1639 | if rev { | |
1640 | v.reverse(); | |
1641 | } | |
1642 | ||
1643 | let mut first_index = 0; | |
1644 | let mut err = None; | |
1645 | ||
1646 | for (i, e) in right.iter().enumerate() { | |
1647 | match *e { | |
1648 | Match(a, b) | Reject(a, b) | |
1649 | if a <= b && a == first_index => { | |
1650 | first_index = b; | |
1651 | } | |
1652 | _ => { | |
1653 | err = Some(i); | |
1654 | break; | |
1655 | } | |
1656 | } | |
1657 | } | |
1658 | ||
1659 | if let Some(err) = err { | |
1660 | panic!("Input skipped range at {}", err); | |
1661 | } | |
1662 | ||
1663 | if first_index != haystack.len() { | |
1664 | panic!("Did not cover whole input"); | |
1665 | } | |
1666 | ||
1667 | assert_eq!(v, right); | |
1668 | } | |
1669 | ||
1670 | make_test!(str_searcher_ascii_haystack, "bb", "abbcbbd", [ | |
1671 | Reject(0, 1), | |
1672 | Match (1, 3), | |
1673 | Reject(3, 4), | |
1674 | Match (4, 6), | |
1675 | Reject(6, 7), | |
1676 | ]); | |
c1a9b12d SL |
1677 | make_test!(str_searcher_ascii_haystack_seq, "bb", "abbcbbbbd", [ |
1678 | Reject(0, 1), | |
1679 | Match (1, 3), | |
1680 | Reject(3, 4), | |
1681 | Match (4, 6), | |
1682 | Match (6, 8), | |
1683 | Reject(8, 9), | |
1684 | ]); | |
9346a6ac AL |
1685 | make_test!(str_searcher_empty_needle_ascii_haystack, "", "abbcbbd", [ |
1686 | Match (0, 0), | |
1687 | Reject(0, 1), | |
1688 | Match (1, 1), | |
1689 | Reject(1, 2), | |
1690 | Match (2, 2), | |
1691 | Reject(2, 3), | |
1692 | Match (3, 3), | |
1693 | Reject(3, 4), | |
1694 | Match (4, 4), | |
1695 | Reject(4, 5), | |
1696 | Match (5, 5), | |
1697 | Reject(5, 6), | |
1698 | Match (6, 6), | |
1699 | Reject(6, 7), | |
1700 | Match (7, 7), | |
1701 | ]); | |
ff7c6d11 | 1702 | make_test!(str_searcher_multibyte_haystack, " ", "├──", [ |
9346a6ac AL |
1703 | Reject(0, 3), |
1704 | Reject(3, 6), | |
1705 | Reject(6, 9), | |
1706 | ]); | |
ff7c6d11 | 1707 | make_test!(str_searcher_empty_needle_multibyte_haystack, "", "├──", [ |
9346a6ac AL |
1708 | Match (0, 0), |
1709 | Reject(0, 3), | |
1710 | Match (3, 3), | |
1711 | Reject(3, 6), | |
1712 | Match (6, 6), | |
1713 | Reject(6, 9), | |
1714 | Match (9, 9), | |
1715 | ]); | |
1716 | make_test!(str_searcher_empty_needle_empty_haystack, "", "", [ | |
1717 | Match(0, 0), | |
1718 | ]); | |
1719 | make_test!(str_searcher_nonempty_needle_empty_haystack, "├", "", [ | |
1720 | ]); | |
1721 | make_test!(char_searcher_ascii_haystack, 'b', "abbcbbd", [ | |
1722 | Reject(0, 1), | |
1723 | Match (1, 2), | |
1724 | Match (2, 3), | |
1725 | Reject(3, 4), | |
1726 | Match (4, 5), | |
1727 | Match (5, 6), | |
1728 | Reject(6, 7), | |
1729 | ]); | |
ff7c6d11 | 1730 | make_test!(char_searcher_multibyte_haystack, ' ', "├──", [ |
9346a6ac AL |
1731 | Reject(0, 3), |
1732 | Reject(3, 6), | |
1733 | Reject(6, 9), | |
1734 | ]); | |
1735 | make_test!(char_searcher_short_haystack, '\u{1F4A9}', "* \t", [ | |
1736 | Reject(0, 1), | |
1737 | Reject(1, 2), | |
1738 | Reject(2, 3), | |
1739 | ]); | |
1740 | ||
1741 | } | |
1742 | ||
1743 | macro_rules! generate_iterator_test { | |
1744 | { | |
1745 | $name:ident { | |
1746 | $( | |
1747 | ($($arg:expr),*) -> [$($t:tt)*]; | |
1748 | )* | |
1749 | } | |
1750 | with $fwd:expr, $bwd:expr; | |
1751 | } => { | |
1752 | #[test] | |
1753 | fn $name() { | |
1754 | $( | |
1755 | { | |
1756 | let res = vec![$($t)*]; | |
1757 | ||
1758 | let fwd_vec: Vec<_> = ($fwd)($($arg),*).collect(); | |
1759 | assert_eq!(fwd_vec, res); | |
1760 | ||
1761 | let mut bwd_vec: Vec<_> = ($bwd)($($arg),*).collect(); | |
1762 | bwd_vec.reverse(); | |
1763 | assert_eq!(bwd_vec, res); | |
1764 | } | |
1765 | )* | |
1766 | } | |
1767 | }; | |
1768 | { | |
1769 | $name:ident { | |
1770 | $( | |
1771 | ($($arg:expr),*) -> [$($t:tt)*]; | |
1772 | )* | |
1773 | } | |
1774 | with $fwd:expr; | |
1775 | } => { | |
1776 | #[test] | |
1777 | fn $name() { | |
1778 | $( | |
1779 | { | |
1780 | let res = vec![$($t)*]; | |
1781 | ||
1782 | let fwd_vec: Vec<_> = ($fwd)($($arg),*).collect(); | |
1783 | assert_eq!(fwd_vec, res); | |
1784 | } | |
1785 | )* | |
1786 | } | |
1787 | } | |
1788 | } | |
1789 | ||
1790 | generate_iterator_test! { | |
1791 | double_ended_split { | |
1792 | ("foo.bar.baz", '.') -> ["foo", "bar", "baz"]; | |
1793 | ("foo::bar::baz", "::") -> ["foo", "bar", "baz"]; | |
1794 | } | |
1795 | with str::split, str::rsplit; | |
1796 | } | |
1797 | ||
1798 | generate_iterator_test! { | |
1799 | double_ended_split_terminator { | |
1800 | ("foo;bar;baz;", ';') -> ["foo", "bar", "baz"]; | |
1801 | } | |
1802 | with str::split_terminator, str::rsplit_terminator; | |
1803 | } | |
1804 | ||
1805 | generate_iterator_test! { | |
1806 | double_ended_matches { | |
1807 | ("a1b2c3", char::is_numeric) -> ["1", "2", "3"]; | |
1808 | } | |
1809 | with str::matches, str::rmatches; | |
1810 | } | |
1811 | ||
1812 | generate_iterator_test! { | |
1813 | double_ended_match_indices { | |
b039eaaf | 1814 | ("a1b2c3", char::is_numeric) -> [(1, "1"), (3, "2"), (5, "3")]; |
9346a6ac AL |
1815 | } |
1816 | with str::match_indices, str::rmatch_indices; | |
1817 | } | |
1818 | ||
1819 | generate_iterator_test! { | |
1820 | not_double_ended_splitn { | |
1821 | ("foo::bar::baz", 2, "::") -> ["foo", "bar::baz"]; | |
1822 | } | |
1823 | with str::splitn; | |
1824 | } | |
1825 | ||
1826 | generate_iterator_test! { | |
1827 | not_double_ended_rsplitn { | |
1828 | ("foo::bar::baz", 2, "::") -> ["baz", "foo::bar"]; | |
1829 | } | |
1830 | with str::rsplitn; | |
c34b1796 AL |
1831 | } |
1832 | ||
54a0048b SL |
1833 | #[test] |
1834 | fn different_str_pattern_forwarding_lifetimes() { | |
1835 | use std::str::pattern::Pattern; | |
1836 | ||
1837 | fn foo<'a, P>(p: P) where for<'b> &'b P: Pattern<'a> { | |
1838 | for _ in 0..3 { | |
1839 | "asdf".find(&p); | |
1840 | } | |
1841 | } | |
1842 | ||
1843 | foo::<&str>("x"); | |
1844 | } |