1macro_rules! impl_partial_eq {
2 ($lhs:ty, $rhs:ty) => {
3 impl<'a, 'b> PartialEq<$rhs> for $lhs {
4 #[inline]
5 fn eq(&self, other: &$rhs) -> bool {
6 let other: &[u8] = other.as_ref();
7 PartialEq::eq(self.as_bytes(), other)
8 }
9 }
10
11 impl<'a, 'b> PartialEq<$lhs> for $rhs {
12 #[inline]
13 fn eq(&self, other: &$lhs) -> bool {
14 let this: &[u8] = self.as_ref();
15 PartialEq::eq(this, other.as_bytes())
16 }
17 }
18 };
19}
20
21macro_rules! impl_partial_eq_array {
22 ($lhs:ty, $rhs:ty) => {
23 impl<'a, 'b, const N: usize> PartialEq<$rhs> for $lhs {
24 #[inline]
25 fn eq(&self, other: &$rhs) -> bool {
26 let other: &[u8] = other.as_ref();
27 PartialEq::eq(self.as_bytes(), other)
28 }
29 }
30
31 impl<'a, 'b, const N: usize> PartialEq<$lhs> for $rhs {
32 #[inline]
33 fn eq(&self, other: &$lhs) -> bool {
34 let this: &[u8] = self.as_ref();
35 PartialEq::eq(this, other.as_bytes())
36 }
37 }
38 };
39}
40
41mod borrowed;
42mod case_change;
43mod inspect;
44mod owned;
45
46pub use borrowed::Codepoints;
47pub use borrowed::Utf8Str;
48pub use inspect::Inspect;
49pub use owned::Utf8String;
50
51#[cfg(test)]
52#[expect(clippy::invisible_characters, reason = "testing naughty UTF-8 strings")]
53mod tests {
54 use alloc::string::String;
55 use alloc::vec::Vec;
56 use core::str;
57
58 use super::{Utf8Str, Utf8String};
59 use crate::test::run_arbitrary;
60
61 const REPLACEMENT_CHARACTER_BYTES: [u8; 3] = [239, 191, 189];
62
63 #[test]
64 fn prop_fuzz_char_len_utf8_contents_utf8_string() {
65 run_arbitrary::<String>(|contents| {
66 let expected = contents.chars().count();
67 let s = Utf8String::from(contents);
68 assert_eq!(s.char_len(), expected);
69 });
70 }
71
72 #[test]
73 fn prop_fuzz_len_utf8_contents_utf8_string() {
74 run_arbitrary::<String>(|contents| {
75 let expected = contents.len();
76 let s = Utf8String::from(contents);
77 assert_eq!(s.len(), expected);
78 });
79 }
80
81 #[test]
82 fn prop_fuzz_char_len_binary_contents_utf8_string() {
83 run_arbitrary::<Vec<u8>>(|contents| {
84 if let Ok(utf8_contents) = str::from_utf8(&contents) {
85 let expected = utf8_contents.chars().count();
86 let s = Utf8String::from(contents);
87 assert_eq!(s.char_len(), expected);
88 } else {
89 let expected_at_most = contents.len();
90 let s = Utf8String::from(contents);
91 assert!(s.char_len() <= expected_at_most);
92 }
93 });
94 }
95
96 #[test]
97 fn prop_fuzz_len_binary_contents_utf8_string() {
98 run_arbitrary::<Vec<u8>>(|contents| {
99 let expected = contents.len();
100 let s = Utf8String::from(contents);
101 assert_eq!(s.len(), expected);
102 });
103 }
104
105 #[test]
106 fn constructs_empty_buffer() {
107 let s = Utf8String::from(Vec::new());
108 assert_eq!(0, s.len());
109 }
110
111 #[test]
112 fn char_len_empty() {
113 let s = Utf8String::from("");
114 assert_eq!(s.char_len(), 0);
115 }
116
117 #[test]
118 fn char_len_ascii() {
119 let s = Utf8String::from("Artichoke Ruby");
120 assert_eq!(s.char_len(), 14);
121 }
122
123 #[test]
124 fn char_len_emoji() {
125 let s = Utf8String::from("๐");
126 assert_eq!(s.char_len(), 1);
127 let s = Utf8String::from("๐๐ฆ๐");
128 assert_eq!(s.char_len(), 3);
129 let s = Utf8String::from("a๐b๐ฆc๐d");
130 assert_eq!(s.char_len(), 7);
131 let s = Utf8String::from(b"a\xF0\x9F\x92\x8E\xFFabc");
133 assert_eq!(s.char_len(), 6);
134 }
135
136 #[test]
137 fn char_len_unicode_replacement_character() {
138 let s = Utf8String::from("๏ฟฝ");
139 assert_eq!(s.char_len(), 1);
140 let s = Utf8String::from("๏ฟฝ๏ฟฝ๏ฟฝ");
141 assert_eq!(s.char_len(), 3);
142 let s = Utf8String::from("a๏ฟฝb๏ฟฝc๏ฟฝd");
143 assert_eq!(s.char_len(), 7);
144 let s = Utf8String::from("๏ฟฝ๐b๐ฆc๐๏ฟฝ");
145 assert_eq!(s.char_len(), 7);
146 let s = Utf8String::from(b"\xEF\xBF\xBD\xF0\x9F\x92\x8E\xFF\xEF\xBF\xBDab");
148 assert_eq!(s.char_len(), 6);
149 let s = Utf8String::from(REPLACEMENT_CHARACTER_BYTES);
150 assert_eq!(s.char_len(), 1);
151 }
152
153 #[test]
154 fn char_len_nul_byte() {
155 let s = Utf8String::from(b"\x00");
156 assert_eq!(s.char_len(), 1);
157 let s = Utf8String::from(b"abc\x00");
158 assert_eq!(s.char_len(), 4);
159 let s = Utf8String::from(b"abc\x00xyz");
160 assert_eq!(s.char_len(), 7);
161 }
162
163 #[test]
164 fn char_len_invalid_utf8_byte_sequences() {
165 let s = Utf8String::from(b"\x00\x00\xD8\x00");
166 assert_eq!(s.char_len(), 4);
167 let s = Utf8String::from(b"\xFF\xFE");
168 assert_eq!(s.char_len(), 2);
169 }
170
171 #[test]
172 fn char_len_binary() {
173 let bytes = &[
174 0xB3, 0x7E, 0x39, 0x70, 0x8E, 0xFD, 0xBB, 0x75, 0x62, 0x77, 0xE7, 0xDF, 0x6F, 0xF2, 0x76, 0x27, 0x81,
175 0x9A, 0x3A, 0x9D, 0xED, 0x6B, 0x4F, 0xAE, 0xC4, 0xE7, 0xA1, 0x66, 0x11, 0xF1, 0x08, 0x1C,
176 ];
177 let s = Utf8String::from(bytes);
178 assert_eq!(s.char_len(), 32);
179 let bytes = &[
181 b'?', b'!', b'a', b'b', b'c', 0xFD, 0xBB, 0x75, 0x62, 0x77, 0xE7, 0xDF, 0x6F, 0xF2, 0x76, 0x27, 0x81,
182 0x9A, 0x3A, 0x9D, 0xED, 0x6B, 0x4F, 0xAE, 0xC4, 0xE7, 0xA1, 0x66, 0x11, 0xF1, 0x08, 0x1C,
183 ];
184 let s = Utf8String::from(bytes);
185 assert_eq!(s.char_len(), 32);
186 }
187
188 #[test]
189 fn char_len_mixed_ascii_emoji_invalid_bytes() {
190 let s = Utf8String::from(b"\xF0\x9F\xA6\x80\x61\x62\x63\xF0\x9F\x92\x8E\xFF");
199 assert_eq!(s.char_len(), 6);
200 }
201
202 #[test]
203 fn char_len_utf8() {
204 let s = Utf8String::from("ฮฉโรงโโซหยตโคโฅรท");
206 assert_eq!(s.char_len(), 10);
207 let s = Utf8String::from("รฅรโฦยฉหโหยฌโฆรฆ");
208 assert_eq!(s.char_len(), 11);
209 let s = Utf8String::from("ลโยดยฎโ ยฅยจหรธฯโโ");
210 assert_eq!(s.char_len(), 12);
211 let s = Utf8String::from("ยกโขยฃยขโยงยถโขยชยบโโ ");
212 assert_eq!(s.char_len(), 12);
213 let s = Utf8String::from("ยธหรโฤฑหรยฏหยฟ");
214 assert_eq!(s.char_len(), 10);
215 let s = Utf8String::from("ร
รรรหรร๏ฃฟรรรโ");
216 assert_eq!(s.char_len(), 12);
217 let s = Utf8String::from("ลโยดโฐหรยจหรโโโ");
218 assert_eq!(s.char_len(), 12);
219 let s = Utf8String::from("`โโฌโนโบ๏ฌ๏ฌโกยฐยทโโยฑ");
220 assert_eq!(s.char_len(), 13);
221 let s = Utf8String::from("โ
โ
โ
โ
");
222 assert_eq!(s.char_len(), 4);
223 let s = Utf8String::from("ะะะะะ
ะะะะะะะะะะะะะะะะะะะะะะะะะะะ ะกะขะฃะคะฅะฆะงะจะฉะชะซะฌะญะฎะฏะฐะฑะฒะณะดะตะถะทะธะนะบะปะผะฝะพะฟัััััั
ัััััััััั");
224 assert_eq!(s.char_len(), 79);
225 }
226
227 #[test]
228 fn char_len_vmware_super_string() {
229 let s = Utf8String::from("่กจใใA้ทลรฉ๏ผข้รรยชฤ
รฑไธใ๐ ");
235 assert_eq!(s.char_len(), 17);
236 }
237
238 #[test]
239 fn char_len_two_byte_chars() {
240 let s = Utf8String::from("็ฐไธญใใใซใใใฆไธใใ");
242 assert_eq!(s.char_len(), 11);
243 let s = Utf8String::from("ใใผใใฃใผใธ่กใใชใใ");
244 assert_eq!(s.char_len(), 11);
245 let s = Utf8String::from("ๅ่ฃฝๆผข่ช");
246 assert_eq!(s.char_len(), 4);
247 let s = Utf8String::from("้จ่ฝๆ ผ");
248 assert_eq!(s.char_len(), 3);
249 let s = Utf8String::from("์ฌํ๊ณผํ์ ์ดํ์ฐ๊ตฌ์");
250 assert_eq!(s.char_len(), 11);
251 let s = Utf8String::from("์ฐฆ์ฐจ๋ฅผ ํ๊ณ ์จ ํฒ์๋งจ๊ณผ ์๋ค๋ฆฌ ๋ ๋ฐฉ๊ฐํ");
252 assert_eq!(s.char_len(), 22);
253 let s = Utf8String::from("็คพๆ็งๅญธ้ข่ชๅญธ็ ็ฉถๆ");
254 assert_eq!(s.char_len(), 10);
255 let s = Utf8String::from("์ธ๋๋ฐํ ๋ฅด");
256 assert_eq!(s.char_len(), 5);
257 let s = Utf8String::from("๐ ๐ ฑ๐ น๐ ฑ๐ ฑธ๐ ฒ๐ ณ");
258 assert_eq!(s.char_len(), 7);
259 }
260
261 #[test]
262 fn char_len_space_chars() {
263 let bytes = " ย
แโโโโโโ
โโโโโโโจโฉโฏโใ
277";
278 let s = Utf8String::from(bytes);
279 assert_eq!(s.char_len(), 25);
280 }
281
282 #[test]
283 fn casing_utf8_string_empty() {
284 let mut s = Utf8String::from(b"");
285
286 s.make_capitalized();
287 assert_eq!(s, "");
288
289 s.make_lowercase();
290 assert_eq!(s, "");
291
292 s.make_uppercase();
293 assert_eq!(s, "");
294
295 s.make_swapcase();
296 assert_eq!(s, "");
297 }
298
299 #[test]
300 fn casing_utf8_string_ascii() {
301 let lower = Utf8String::from(b"abc");
302 let mid_upper = Utf8String::from(b"aBc");
303 let upper = Utf8String::from(b"ABC");
304 let long = Utf8String::from(b"aBC, 123, ABC, baby you and me girl");
305
306 let capitalize: fn(&Utf8String) -> Utf8String = |value: &Utf8String| {
307 let mut value = value.clone();
308 value.make_capitalized();
309 value
310 };
311 let lowercase: fn(&Utf8String) -> Utf8String = |value: &Utf8String| {
312 let mut value = value.clone();
313 value.make_lowercase();
314 value
315 };
316 let uppercase: fn(&Utf8String) -> Utf8String = |value: &Utf8String| {
317 let mut value = value.clone();
318 value.make_uppercase();
319 value
320 };
321 let swapcase: fn(&Utf8String) -> Utf8String = |value: &Utf8String| {
322 let mut value = value.clone();
323 value.make_swapcase();
324 value
325 };
326
327 assert_eq!(capitalize(&lower), "Abc");
328 assert_eq!(capitalize(&mid_upper), "Abc");
329 assert_eq!(capitalize(&upper), "Abc");
330 assert_eq!(capitalize(&long), "Abc, 123, abc, baby you and me girl");
331
332 assert_eq!(lowercase(&lower), "abc");
333 assert_eq!(lowercase(&mid_upper), "abc");
334 assert_eq!(lowercase(&upper), "abc");
335 assert_eq!(lowercase(&long), "abc, 123, abc, baby you and me girl");
336
337 assert_eq!(uppercase(&lower), "ABC");
338 assert_eq!(uppercase(&mid_upper), "ABC");
339 assert_eq!(uppercase(&upper), "ABC");
340 assert_eq!(uppercase(&long), "ABC, 123, ABC, BABY YOU AND ME GIRL");
341
342 assert_eq!(swapcase(&lower), "ABC");
343 assert_eq!(swapcase(&mid_upper), "AbC");
344 assert_eq!(swapcase(&upper), "abc");
345 assert_eq!(swapcase(&long), "Abc, 123, abc, BABY YOU AND ME GIRL");
346 }
347
348 #[test]
349 fn casing_utf8_string_utf8() {
350 let sharp_s = Utf8String::from("ร");
357 let tomorrow = Utf8String::from("ฮฑฯฯฮนฮฟ");
358 let year = Utf8String::from("ฮญฯฮฟฯ");
359 let two_byte_chars = Utf8String::from("๐ ๐๐๐๐๐ก๐๐ ๐๐๐ก๐๐/๐๐๐๐๐ค๐ ๐๐๐ ๐๐ ๐ ๐ก๐๐๐๐ค๐๐ ๐ฑ๐ ๐ ๐๐๐๐๐ก๐๐ ๐๐๐
๐ค๐๐๐๐ก๐๐๐๐");
362 let varying_length = Utf8String::from("zศบศพ");
365 let rtl = Utf8String::from("ู
ุฑุญุจุง ุงูุฎุฑุดูู");
367
368 let capitalize: fn(&Utf8String) -> Utf8String = |value: &Utf8String| {
369 let mut value = value.clone();
370 value.make_capitalized();
371 value
372 };
373 let lowercase: fn(&Utf8String) -> Utf8String = |value: &Utf8String| {
374 let mut value = value.clone();
375 value.make_lowercase();
376 value
377 };
378 let uppercase: fn(&Utf8String) -> Utf8String = |value: &Utf8String| {
379 let mut value = value.clone();
380 value.make_uppercase();
381 value
382 };
383 let swapcase: fn(&Utf8String) -> Utf8String = |value: &Utf8String| {
384 let mut value = value.clone();
385 value.make_swapcase();
386 value
387 };
388
389 assert_eq!(capitalize(&sharp_s), "SS");
390 assert_eq!(capitalize(&tomorrow), "ฮฯฯฮนฮฟ");
391 assert_eq!(capitalize(&year), "ฮฯฮฟฯ");
392 assert_eq!(
393 capitalize(&two_byte_chars),
394 "๐ ๐ผ๐ฏ๐
๐จ๐๐ฏ๐ป ๐๐ฒ๐๐
๐ป/๐
๐ฏ๐ฟ๐ฒ๐๐ผ ๐บ๐ณ๐ฟ ๐บ๐ด ๐ ๐๐จ๐พ๐ฏ๐๐ป๐
๐ฑ๐ ๐ ๐ผ๐ฏ๐
๐จ๐๐ฏ๐ป ๐ท๐ฎ๐ญ๐๐ฎ๐๐ฒ๐๐
๐ฎ๐ป๐ฎ"
395 );
396 assert_eq!(capitalize(&varying_length), "Zโฑฅโฑฆ");
397 assert_eq!(capitalize(&rtl), "ู
ุฑุญุจุง ุงูุฎุฑุดูู");
398
399 assert_eq!(lowercase(&sharp_s), "ร");
400 assert_eq!(lowercase(&tomorrow), "ฮฑฯฯฮนฮฟ");
401 assert_eq!(lowercase(&year), "ฮญฯฮฟฯ");
402 assert_eq!(
403 lowercase(&two_byte_chars),
404 "๐ ๐ผ๐ฏ๐
๐จ๐๐ฏ๐ป ๐๐ฒ๐๐
๐ป/๐
๐ฏ๐ฟ๐ฒ๐๐ผ ๐บ๐ณ๐ฟ ๐บ๐ด ๐ ๐๐จ๐พ๐ฏ๐๐ป๐
๐ฑ๐ ๐ ๐ผ๐ฏ๐
๐จ๐๐ฏ๐ป ๐ท๐ฎ๐ญ๐๐ฎ๐๐ฒ๐๐
๐ฎ๐ป๐ฎ"
405 );
406 assert_eq!(lowercase(&varying_length), "zโฑฅโฑฆ");
407 assert_eq!(lowercase(&rtl), "ู
ุฑุญุจุง ุงูุฎุฑุดูู");
408
409 assert_eq!(uppercase(&sharp_s), "SS");
410 assert_eq!(uppercase(&tomorrow), "ฮฮฮกฮฮ");
411 assert_eq!(uppercase(&year), "ฮฮคฮฮฃ");
412 assert_eq!(
413 uppercase(&two_byte_chars),
414 "๐ ๐๐๐๐๐ก๐๐ ๐๐๐ก๐๐/๐๐๐๐๐ค๐ ๐๐๐ ๐๐ ๐ ๐ก๐๐๐๐ค๐๐ ๐๐ ๐ ๐๐๐๐๐ก๐๐ ๐๐๐
๐ค๐๐๐๐ก๐๐๐๐"
415 );
416 assert_eq!(uppercase(&varying_length), "Zศบศพ");
417 assert_eq!(uppercase(&rtl), "ู
ุฑุญุจุง ุงูุฎุฑุดูู");
418
419 let sharp_s = Utf8String::from("SS");
420 let tomorrow = Utf8String::from("ฮฯฯฮนฮฟ");
421 let year = Utf8String::from("ฮฯฮฟฯ");
422 let two_byte_chars = Utf8String::from("๐ ๐๐ฏ๐
๐จ๐๐ฏ๐ป ๐๐ฒ๐๐
๐ป/๐
๐ฏ๐ฟ๐ฒ๐๐ผ ๐๐ณ๐ฟ ๐๐ด ๐ ๐ก๐จ๐พ๐ฏ๐๐ป๐
๐๐ ๐ ๐๐ฏ๐
๐จ๐๐ฏ๐ป ๐๐ฎ๐ญ๐๐ฎ๐๐ฒ๐๐
๐ฎ๐ป๐ฎ");
424 let varying_length = Utf8String::from("Zโฑฅโฑฆ");
425 let rtl = Utf8String::from("ู
ุฑุญุจุง ุงูุฎุฑุดูู");
426 assert_eq!(swapcase(&sharp_s), "ss", "swapcase(SS) failed");
427 assert_eq!(swapcase(&tomorrow), "ฮฑฮฮกฮฮ", "swapcase(ฮฯฯฮนฮฟ) failed");
428 assert_eq!(swapcase(&year), "ฮญฮคฮฮฃ", "swapcase(ฮฯฮฟฯ) failed");
429 assert_eq!(
430 swapcase(&two_byte_chars),
431 "๐ ๐ผ๐๐๐๐ก๐๐ ๐๐๐ก๐๐/๐๐๐๐๐ค๐ ๐บ๐๐ ๐บ๐ ๐ ๐๐๐๐๐ค๐๐ ๐ฑ๐ ๐ ๐ผ๐๐๐๐ก๐๐ ๐ท๐๐
๐ค๐๐๐๐ก๐๐๐๐"
432 );
433 assert_eq!(swapcase(&varying_length), "zศบศพ", "swapcase(Zโฑฅโฑฆ) mismatch");
434 assert_eq!(swapcase(&rtl), "ู
ุฑุญุจุง ุงูุฎุฑุดูู", "swapcase(ู
ุฑุญุจุง ุงูุฎุฑุดูู) mismatch");
435 }
436
437 #[test]
438 fn casing_utf8_string_invalid_utf8() {
439 let mut s = Utf8String::from(b"\xFF\xFE");
440
441 s.make_capitalized();
442 assert_eq!(s, &b"\xFF\xFE"[..]);
443
444 s.make_lowercase();
445 assert_eq!(s, &b"\xFF\xFE"[..]);
446
447 s.make_uppercase();
448 assert_eq!(s, &b"\xFF\xFE"[..]);
449
450 s.make_swapcase();
451 assert_eq!(s, &b"\xFF\xFE"[..]);
452 }
453
454 #[test]
455 fn casing_utf8_string_unicode_replacement_character() {
456 let mut s = Utf8String::from("๏ฟฝ");
457
458 s.make_capitalized();
459 assert_eq!(s, "๏ฟฝ");
460
461 s.make_lowercase();
462 assert_eq!(s, "๏ฟฝ");
463
464 s.make_uppercase();
465 assert_eq!(s, "๏ฟฝ");
466
467 s.make_swapcase();
468 assert_eq!(s, "๏ฟฝ");
469 }
470
471 #[test]
472 fn chr_does_not_return_more_than_one_byte_for_invalid_utf8() {
473 let s = Utf8String::from(b"\xF0\x9F\x87");
484 assert_eq!(s.chr(), b"\xF0");
485 }
486
487 #[test]
488 fn get_char_slice_valid_range() {
489 let s = Utf8String::from(b"a\xF0\x9F\x92\x8E\xFF".to_vec()); assert_eq!(s.get_char_slice(0..0), Some(Utf8Str::empty()));
491 assert_eq!(s.get_char_slice(0..1), Some(Utf8Str::new(b"a")));
492 assert_eq!(s.get_char_slice(0..2), Some(Utf8Str::new("a๐")));
493 assert_eq!(s.get_char_slice(0..3), Some(Utf8Str::new(b"a\xF0\x9F\x92\x8E\xFF")));
494 assert_eq!(s.get_char_slice(0..4), Some(Utf8Str::new(b"a\xF0\x9F\x92\x8E\xFF")));
495 assert_eq!(s.get_char_slice(1..1), Some(Utf8Str::empty()));
496 assert_eq!(s.get_char_slice(1..2), Some(Utf8Str::new("๐")));
497 assert_eq!(s.get_char_slice(1..3), Some(Utf8Str::new(b"\xF0\x9F\x92\x8E\xFF")));
498 }
499
500 #[test]
501 #[expect(clippy::reversed_empty_ranges, reason = "testing behavior of reversed ranges")]
502 fn get_char_slice_invalid_range() {
503 let s = Utf8String::from(b"a\xF0\x9F\x92\x8E\xFF".to_vec()); assert_eq!(s.get_char_slice(4..5), None);
505 assert_eq!(s.get_char_slice(4..1), None);
506 assert_eq!(s.get_char_slice(3..1), Some(Utf8Str::empty()));
507 assert_eq!(s.get_char_slice(2..1), Some(Utf8Str::empty()));
508 assert_eq!(s.get_char_slice(7..10), None);
509 assert_eq!(s.get_char_slice(10..8), None);
510 assert_eq!(s.get_char_slice(10..5), None);
511 assert_eq!(s.get_char_slice(10..2), None);
512 }
513
514 #[test]
515 fn index_with_default_offset() {
516 let s = Utf8String::from("f๐oo");
517 assert_eq!(s.index("f".as_bytes(), 0), Some(0));
518 assert_eq!(s.index("o".as_bytes(), 0), Some(2));
519 assert_eq!(s.index("oo".as_bytes(), 0), Some(2));
520 assert_eq!(s.index("ooo".as_bytes(), 0), None);
521 }
522
523 #[test]
524 fn index_with_different_offset() {
525 let s = Utf8String::from("f๐oo");
526 assert_eq!(s.index("o".as_bytes(), 1), Some(2));
527 assert_eq!(s.index("o".as_bytes(), 2), Some(2));
528 assert_eq!(s.index("o".as_bytes(), 3), Some(3));
529 assert_eq!(s.index("o".as_bytes(), 4), None);
530 }
531
532 #[test]
533 fn rindex_with_default_offset() {
534 let s = Utf8String::from("f๐oo");
535 assert_eq!(s.rindex("f".as_bytes(), 3), Some(0));
536 assert_eq!(s.rindex("o".as_bytes(), 3), Some(3));
537 assert_eq!(s.rindex("oo".as_bytes(), 3), Some(2));
538 assert_eq!(s.rindex("ooo".as_bytes(), 3), None);
539 }
540
541 #[test]
542 fn rindex_with_different_offset() {
543 let s = Utf8String::from("f๐oo");
544 assert_eq!(s.rindex("o".as_bytes(), 4), Some(3));
545 assert_eq!(s.rindex("o".as_bytes(), 3), Some(3));
546 assert_eq!(s.rindex("o".as_bytes(), 2), Some(2));
547 assert_eq!(s.rindex("o".as_bytes(), 1), None);
548 assert_eq!(s.rindex("o".as_bytes(), 0), None);
549 }
550
551 #[test]
552 fn index_and_rindex_support_invalid_utf8_in_needle() {
553 let needle = &"๐".as_bytes()[..3];
555
556 assert_eq!(Utf8String::from("f๐oo").index(needle, 0), None); assert_eq!(Utf8String::from("f๐oo").rindex(needle, 3), None); }
559
560 #[test]
561 fn index_and_rindex_support_invalid_utf8_in_haystack() {
562 let mut haystack = Vec::new();
564 haystack.extend_from_slice(b"f");
565 haystack.extend_from_slice(&"๐".as_bytes()[..2]);
566 haystack.extend_from_slice(b"oo");
567 let haystack = Utf8String::from(haystack);
568
569 assert_eq!(haystack.index("๐".as_bytes(), 0), None);
570 assert_eq!(haystack.rindex("๐".as_bytes(), 3), None);
571 }
572
573 #[test]
574 fn index_empties() {
575 let s = Utf8String::from("");
584 assert_eq!(s.index(b"", 0), Some(0));
585
586 assert_eq!(s.index(b"a", 0), None);
587
588 let s = Utf8String::from("a");
589 assert_eq!(s.index(b"", 0), Some(0));
590 }
591
592 #[test]
593 fn rindex_empties() {
594 let s = Utf8String::from("");
603 assert_eq!(s.rindex(b"", usize::MAX), Some(0));
604 assert_eq!(s.rindex(b"", 1), Some(0));
605 assert_eq!(s.rindex(b"", 0), Some(0));
606
607 assert_eq!(s.rindex(b"a", usize::MAX), None);
608 assert_eq!(s.rindex(b"a", 1), None);
609 assert_eq!(s.rindex(b"a", 0), None);
610
611 let s = Utf8String::from("a");
612 assert_eq!(s.rindex(b"", usize::MAX), Some(1));
613 assert_eq!(s.rindex(b"", 1), Some(1));
614 }
615}