Short (up to 65,535 bytes) immutable strings to e.g. parse tokens, implemented in Rust. These are sometimes called "German Strings", because Germans have written the paper mentioning them
1// SPDX-FileCopyrightText: Copyright (C) 2024 Roland Csaszar
2// SPDX-License-Identifier: MPL-2.0
3//
4// Project: token-string
5// File: test-string.rs
6// Date: 23.Nov.2024
7// =============================================================================
8//! Test the `TokenString` methods.
9
10#![expect(clippy::tests_outside_test_module, reason = "tests directory")]
11#![expect(
12 clippy::std_instead_of_alloc,
13 reason = "We are testing, this needs std"
14)]
15
16mod func {
17 use core::borrow::Borrow as _;
18 use core::hash::{Hash as _, Hasher as _};
19 use std::hash::DefaultHasher;
20
21 use assert2::{check, let_assert};
22 use token_string::TokenString;
23
24 #[test]
25 fn empty_is_empty() {
26 let empty = TokenString::default();
27 check!(empty.is_empty());
28 check!(empty.len() == 0);
29 }
30
31 #[test]
32 fn is_not_empty() {
33 let_assert!(
34 Ok(res) = TokenString::try_from("Hello!"),
35 "this should be OK"
36 );
37 check!(res.is_empty() == false);
38 check!(res.len() == "Hello!".len());
39 }
40
41 #[test]
42 fn same_prefix_eq() {
43 let_assert!(
44 Ok(res) = TokenString::try_from("Hello!"),
45 "this should be OK"
46 );
47 check!(res == res);
48 check!(res.is_small());
49 }
50
51 #[test]
52 fn same_small_eq() {
53 let_assert!(
54 Ok(res) = TokenString::try_from("Hello World!"),
55 "this should be OK"
56 );
57 check!(res == res);
58 check!(res.is_small());
59 }
60
61 #[test]
62 fn same_heap_eq() {
63 let_assert!(
64 Ok(res) = TokenString::try_from("Hello funny world!"),
65 "this should be OK"
66 );
67 check!(res == res);
68 check!(!res.is_small());
69 }
70
71 #[test]
72 fn clone_prefix_eq() {
73 let_assert!(
74 Ok(s1) = TokenString::try_from("Hello!"),
75 "this should be OK"
76 );
77 let res = s1.clone();
78 check!(res == s1);
79 check!(res.is_small());
80 }
81
82 #[test]
83 fn clone_small_eq() {
84 let_assert!(
85 Ok(s1) = TokenString::try_from("Hello World!"),
86 "this should be OK"
87 );
88 let res = s1.clone();
89 check!(res == s1);
90 check!(res.is_small());
91 }
92
93 #[test]
94 fn clone_heap_eq() {
95 let_assert!(
96 Ok(s1) = TokenString::try_from("Hello funny world!"),
97 "this should be OK"
98 );
99 let res = s1.clone();
100 check!(res == s1);
101 check!(!res.is_small());
102 }
103
104 #[test]
105 fn as_ref() {
106 let_assert!(
107 Ok(res) = TokenString::try_from("Hello!"),
108 "this should be OK"
109 );
110 let s = res.as_ref();
111 check!(&res == s);
112 check!(res.is_small());
113 }
114
115 #[test]
116 fn borrow() {
117 let_assert!(
118 Ok(res) = TokenString::try_from("Hello!"),
119 "this should be OK"
120 );
121 let s: &str = res.borrow();
122 check!(&res == s);
123 check!(res.is_small());
124 }
125
126 #[test]
127 fn prefix_eq() {
128 let_assert!(
129 Ok(res) = TokenString::try_from("Hello!"),
130 "this should be OK"
131 );
132 let_assert!(
133 Ok(res2) = TokenString::try_from("Hello!"),
134 "this should be OK"
135 );
136 check!(res == res2);
137 check!(res.is_small());
138 }
139
140 #[test]
141 fn small_eq() {
142 let_assert!(
143 Ok(res) = TokenString::try_from("Hello World!"),
144 "this should be OK"
145 );
146 let_assert!(
147 Ok(res2) = TokenString::try_from("Hello World!"),
148 "this should be OK"
149 );
150 check!(res == res2);
151 check!(res.is_small());
152 }
153
154 #[test]
155 fn heap_eq() {
156 let_assert!(
157 Ok(res) = TokenString::try_from("Hello funny world!"),
158 "this should be OK"
159 );
160 let_assert!(
161 Ok(res2) = TokenString::try_from("Hello funny world!"),
162 "this should be OK"
163 );
164 check!(res == res2);
165 check!(!res.is_small());
166 }
167
168 #[test]
169 fn as_chars() {
170 let chars: Vec<char> = "Hello funny world!".chars().collect();
171 let_assert!(
172 Ok(res) = TokenString::try_from(chars.as_slice()),
173 "this should be OK"
174 );
175 check!(res.as_chars() == chars);
176 check!(!res.is_small());
177 }
178
179 #[test]
180 fn heap_string_display() {
181 let string = "Hello funny world!".to_owned();
182 let_assert!(
183 Ok(res) = TokenString::try_from(&string),
184 "this should be OK"
185 );
186 check!(res.to_string() == string);
187 check!(format!("{res}") == string);
188 check!(!res.is_small());
189 }
190
191 #[test]
192 fn prefix_neq() {
193 let_assert!(
194 Ok(res) = TokenString::try_from("Hello!"),
195 "this should be OK"
196 );
197 let_assert!(
198 Ok(res2) = TokenString::try_from("Hello1"),
199 "this should be OK"
200 );
201 check!(res != res2);
202 check!(res.is_small() == res2.is_small());
203 }
204
205 #[test]
206 fn small_neq() {
207 let_assert!(
208 Ok(res) = TokenString::try_from("Hello World!"),
209 "this should be OK"
210 );
211 let_assert!(
212 Ok(res2) = TokenString::try_from("Hello World1"),
213 "this should be OK"
214 );
215 check!(res != res2);
216 check!(res.is_small() == res2.is_small());
217 }
218
219 #[test]
220 fn heap_neq() {
221 let_assert!(
222 Ok(res) = TokenString::try_from("Hello funny world!"),
223 "this should be OK"
224 );
225 let_assert!(
226 Ok(res2) = TokenString::try_from("Hello funny world1"),
227 "this should be OK"
228 );
229 check!(res != res2);
230 check!(res.is_small() == res2.is_small());
231 }
232
233 #[test]
234 fn string_neq() {
235 let s = "Hello funny world!".to_owned();
236 let_assert!(
237 Ok(res) = TokenString::try_from("Hello funny world"),
238 "this should be OK"
239 );
240
241 check!(res != s);
242 check!(res.is_small() == false);
243 }
244
245 #[test]
246 fn prefix_str_neq() {
247 let_assert!(
248 Ok(res) = TokenString::try_from("Hello!"),
249 "this should be OK"
250 );
251 let res2 = "Hello";
252 check!(&res != res2);
253 }
254
255 #[test]
256 fn small_str_neq() {
257 let_assert!(
258 Ok(res) = TokenString::try_from("Hello World!"),
259 "this should be OK"
260 );
261 let res2 = "Hello World";
262 check!(&res != res2);
263 }
264
265 #[test]
266 fn heap_str_neq() {
267 let_assert!(
268 Ok(res) = TokenString::try_from("Hello funny world!"),
269 "this should be OK"
270 );
271 let res2 = "Hello funny world";
272 check!(&res != res2);
273 }
274
275 #[test]
276 fn debug_print_prefix() {
277 let_assert!(Ok(res) = TokenString::try_from("ࠀ\0¡"));
278 let a = format!("Debug: {res:?}");
279 check!(
280 a == "Debug: TokenString { len: 6, prefix: [224, 160, 128, 0, \
281 194, 161], small: [], string: \"ࠀ\\0¡\" }"
282 );
283 }
284
285 #[test]
286 fn debug_print_small() {
287 let_assert!(Ok(res) = TokenString::try_from("ࠀ\0A¡"));
288 let a = format!("Debug: {res:?}");
289 check!(
290 a == "Debug: TokenString { len: 7, prefix: [224, 160, 128, 0, 65, \
291 194], small: [161], string: \"ࠀ\\0A¡\" }"
292 );
293 }
294
295 #[test]
296 fn debug_print_heap() {
297 let_assert!(Ok(res) = TokenString::try_from("ࠀ\0A¡ \u{b}\u{b}ࠀ\0a"));
298 let a = format!("Debug: {res:?}");
299 let ptr_str = format!("{:?}", res.as_str().as_ptr());
300 check!(
301 a == format!(
302 "Debug: TokenString {{ len: 15, prefix: [224, 160, 128, 0, \
303 65, 194], ptr: ManuallyDrop {{ value: StringPtr {{ ptr: \
304 {ptr_str} }} }}, string: \"ࠀ\\0A¡ \\u{{b}}\\u{{b}}ࠀ\\0a\" }}"
305 )
306 );
307 }
308
309 #[test]
310 fn ord_array() {
311 let_assert!(Ok(s1) = TokenString::try_from("Aaaaaaaa"));
312 let_assert!(Ok(s2) = TokenString::try_from("Aaaaaaa"));
313 let_assert!(Ok(s3) = TokenString::try_from("Aaaaaa"));
314 let_assert!(Ok(s4) = TokenString::try_from("Aabaaa"));
315 let_assert!(Ok(s5) = TokenString::try_from("Aab"));
316 let res = [&s3, &s2, &s1, &s5, &s4];
317 let mut res2 = [&s4, &s1, &s3, &s2, &s5];
318 res2.sort();
319 check!(res2 == res);
320 }
321
322 #[test]
323 fn slice_prefix() {
324 let_assert!(
325 Ok(res) = TokenString::try_from("Hello!"),
326 "this should be OK"
327 );
328 let res2 = &res[0 .. 4];
329 check!(&res.as_str()[0 .. 4] == res2);
330 }
331
332 #[test]
333 fn slice_small() {
334 let_assert!(
335 Ok(res) = TokenString::try_from("Hello, world!"),
336 "this should be OK"
337 );
338 let res2 = &res[5 .. 12];
339 check!(&res.as_str()[5 .. 12] == res2);
340 }
341
342 #[test]
343 fn slice_heap() {
344 let_assert!(
345 Ok(res) = TokenString::try_from("Hello, funny world!"),
346 "this should be OK"
347 );
348 let res2 = &res[7 .. 12];
349 check!(&res.as_str()[7 .. 12] == res2);
350 }
351
352 #[test]
353 fn get_prefix() {
354 let_assert!(
355 Ok(res) = TokenString::try_from("Hello!"),
356 "this should be OK"
357 );
358 let_assert!(Ok(el) = res.get(4));
359 check!(el == b'o');
360 }
361
362 #[test]
363 fn get_small() {
364 let_assert!(
365 Ok(res) = TokenString::try_from("Hello, world!"),
366 "this should be OK"
367 );
368 let_assert!(Ok(el) = res.get(9));
369 check!(el == b'r');
370 }
371
372 #[test]
373 fn get_heap() {
374 let_assert!(
375 Ok(res) = TokenString::try_from("Hello, funny world!"),
376 "this should be OK"
377 );
378 let_assert!(Ok(el) = res.get(15));
379 check!(el == b'r');
380 }
381
382 #[test]
383 fn get_unchecked_prefix() {
384 let_assert!(
385 Ok(res) = TokenString::try_from("Hello!"),
386 "this should be OK"
387 );
388 let el = res.get_unchecked(4);
389 check!(el == b'o');
390 }
391
392 #[test]
393 fn get_unchecked_small() {
394 let_assert!(
395 Ok(res) = TokenString::try_from("Hello, world!"),
396 "this should be OK"
397 );
398 let el = res.get_unchecked(9);
399 check!(el == b'r');
400 }
401
402 #[test]
403 fn get_unchecked_heap() {
404 let_assert!(
405 Ok(res) = TokenString::try_from("Hello, funny world!"),
406 "this should be OK"
407 );
408 let el = res.get_unchecked(15);
409 check!(el == b'r');
410 }
411
412 #[test]
413 fn trim_prefix() {
414 let_assert!(
415 Ok(res) = TokenString::try_from(" Hell "),
416 "this should be OK"
417 );
418 check!(&res.trim_ascii() == "Hell");
419 }
420
421 #[test]
422 fn trim_small() {
423 let_assert!(
424 Ok(res) = TokenString::try_from(" Hello, world "),
425 "this should be OK"
426 );
427 check!(&res.trim_ascii() == "Hello, world");
428 check!(res.is_small() == true);
429 }
430
431 #[test]
432 fn trim_heap() {
433 let_assert!(
434 Ok(res) = TokenString::try_from(" Hello, funny world "),
435 "this should be OK"
436 );
437 check!(&res.trim_ascii() == "Hello, funny world");
438 check!(res.is_small() == false);
439 }
440
441 #[test]
442 fn trim_start_heap() {
443 let_assert!(
444 Ok(res) = TokenString::try_from(" Hello, funny world "),
445 "this should be OK"
446 );
447 check!(&res.trim_ascii_start() == "Hello, funny world ");
448 check!(res.is_small() == false);
449 }
450
451 #[test]
452 fn trim_end_heap() {
453 let_assert!(
454 Ok(res) = TokenString::try_from(" Hello, funny world "),
455 "this should be OK"
456 );
457 check!(&res.trim_ascii_end() == " Hello, funny world");
458 check!(res.is_small() == false);
459 }
460
461 #[test]
462 fn is_uppercase() {
463 let_assert!(
464 Ok(res) = TokenString::try_from("Hello!"),
465 "this should be OK"
466 );
467 check!(res.starts_ascii_uppercase() == true);
468 check!(res.starts_ascii_lowercase() == false);
469 }
470
471 #[test]
472 fn is_lowercase() {
473 let_assert!(
474 Ok(res) = TokenString::try_from("hello!"),
475 "this should be OK"
476 );
477 check!(res.starts_ascii_uppercase() == false);
478 check!(res.starts_ascii_lowercase() == true);
479 }
480
481 #[test]
482 fn is_ascii() {
483 let_assert!(
484 Ok(res) = TokenString::try_from("hello!"),
485 "this should be OK"
486 );
487 check!(res.is_ascii() == true);
488 }
489
490 #[test]
491 fn is_not_ascii() {
492 let_assert!(
493 Ok(res) = TokenString::try_from("hěllo!"),
494 "this should be OK"
495 );
496 check!(res.is_ascii() == false);
497 }
498
499 #[test]
500 fn starts_with() {
501 let_assert!(
502 Ok(res) = TokenString::try_from("hello!"),
503 "this should be OK"
504 );
505 let_assert!(
506 Ok(pref) = TokenString::try_from("hell"),
507 "this should be OK"
508 );
509 check!(res.starts_with(&pref) == true);
510 }
511
512 #[test]
513 fn starts_with_bytes() {
514 let_assert!(
515 Ok(res) = TokenString::try_from("hello!"),
516 "this should be OK"
517 );
518 check!(res.starts_with_bytes(b"hell") == true);
519 }
520
521 #[test]
522 fn starts_with_str() {
523 let_assert!(
524 Ok(res) = TokenString::try_from("hello!"),
525 "this should be OK"
526 );
527 check!(res.starts_with_str("hell") == true);
528 }
529
530 #[test]
531 fn ends_with() {
532 let_assert!(
533 Ok(res) = TokenString::try_from("hello world!"),
534 "this should be OK"
535 );
536 let_assert!(
537 Ok(suf) = TokenString::try_from("world!"),
538 "this should be OK"
539 );
540 check!(res.ends_with(&suf) == true);
541 }
542
543 #[test]
544 fn ends_with_str() {
545 let_assert!(
546 Ok(res) = TokenString::try_from("hello world!"),
547 "this should be OK"
548 );
549 check!(res.ends_with_str("world!") == true);
550 }
551
552 #[test]
553 fn ends_with_bytes() {
554 let_assert!(
555 Ok(res) = TokenString::try_from("hello world!"),
556 "this should be OK"
557 );
558 check!(res.ends_with_bytes(b"world!") == true);
559 }
560
561 #[test]
562 fn not_starts_with_bytes() {
563 let_assert!(
564 Ok(res) = TokenString::try_from("hello!"),
565 "this should be OK"
566 );
567 check!(res.starts_with_bytes(b"ell") == false);
568 }
569
570 #[test]
571 fn not_starts_with() {
572 let_assert!(
573 Ok(res) = TokenString::try_from("hello!"),
574 "this should be OK"
575 );
576 let_assert!(
577 Ok(pref) = TokenString::try_from("ell"),
578 "this should be OK"
579 );
580 check!(res.starts_with(&pref) == false);
581 }
582
583 #[test]
584 fn not_starts_with_str() {
585 let_assert!(
586 Ok(res) = TokenString::try_from("hello!"),
587 "this should be OK"
588 );
589 check!(res.starts_with_str("ell") == false);
590 }
591
592 #[test]
593 fn not_ends_with() {
594 let_assert!(
595 Ok(res) = TokenString::try_from("hello world!"),
596 "this should be OK"
597 );
598 let_assert!(
599 Ok(suf) = TokenString::try_from("world"),
600 "this should be OK"
601 );
602 check!(res.ends_with(&suf) == false);
603 }
604
605 #[test]
606 fn not_ends_with_str() {
607 let_assert!(
608 Ok(res) = TokenString::try_from("hello world!"),
609 "this should be OK"
610 );
611 check!(res.ends_with_str("world") == false);
612 }
613
614 #[test]
615 fn not_ends_with_bytes() {
616 let_assert!(
617 Ok(res) = TokenString::try_from("hello world!"),
618 "this should be OK"
619 );
620 check!(res.ends_with_bytes(b"world") == false);
621 }
622
623 #[test]
624 fn to_lower() {
625 let_assert!(
626 Ok(res) = TokenString::try_from("HELLO!"),
627 "this should be OK"
628 );
629 check!(&res.to_ascii_lowercase() == "hello!");
630 }
631
632 #[test]
633 fn to_upper_small() {
634 let_assert!(
635 Ok(res) = TokenString::try_from("hello!"),
636 "this should be OK"
637 );
638 check!(&res.to_ascii_uppercase() == "HELLO!");
639 }
640
641 #[test]
642 fn to_lower_small() {
643 let_assert!(
644 Ok(res) = TokenString::try_from("HELLO, FUNNY WORLD!"),
645 "this should be OK"
646 );
647 check!(&res.to_ascii_lowercase() == "hello, funny world!");
648 }
649
650 #[test]
651 fn to_upper() {
652 let_assert!(
653 Ok(res) = TokenString::try_from("hello, funny world!"),
654 "this should be OK"
655 );
656 check!(&res.to_ascii_uppercase() == "HELLO, FUNNY WORLD!");
657 }
658
659 #[test]
660 fn to_iter_owned() {
661 let_assert!(
662 Ok(res) = TokenString::try_from("hello!"),
663 "this should be OK"
664 );
665 let mut iter = res.into_iter();
666 check!(iter.next() == Some(b'h'));
667 }
668
669 #[test]
670 fn to_iter() {
671 let_assert!(
672 Ok(res) = TokenString::try_from("hello!"),
673 "this should be OK"
674 );
675 let mut iter = (&res).into_iter();
676 check!(iter.next() == Some(b'h'));
677 }
678
679 #[test]
680 fn hashing() {
681 let_assert!(
682 Ok(res) = TokenString::try_from("hello!"),
683 "this should be OK"
684 );
685 let_assert!(
686 Ok(res2) = TokenString::try_from("world"),
687 "this should be OK"
688 );
689 let mut hasher1 = DefaultHasher::new();
690 res.hash(&mut hasher1);
691 let hash1 = hasher1.finish();
692 let mut hasher2 = DefaultHasher::new();
693 res2.hash(&mut hasher2);
694 let hash2 = hasher2.finish();
695 check!(hash1 != hash2);
696 }
697
698 #[test]
699 #[cfg(feature = "pattern")]
700 fn strip_suffix() {
701 let_assert!(
702 Ok(res) = TokenString::try_from("hello world!"),
703 "this should be OK"
704 );
705 let_assert!(Some(stripped) = res.strip_suffix("world!"));
706 check!(&stripped == "hello ");
707 }
708
709 #[test]
710 #[cfg(feature = "pattern")]
711 fn strip_prefix() {
712 let_assert!(
713 Ok(res) = TokenString::try_from("hello world!"),
714 "this should be OK"
715 );
716 let_assert!(Some(stripped) = res.strip_prefix("hello "));
717 check!(&stripped == "world!");
718 }
719
720 #[test]
721 #[cfg(feature = "pattern")]
722 fn contains() {
723 let_assert!(
724 Ok(res) = TokenString::try_from("hello world!"),
725 "this should be OK"
726 );
727 check!(res.contains("o w") == true);
728 check!(res.contains("o q") == false);
729 }
730
731 #[test]
732 fn debug_iter() {
733 let act = " \u{b}\u{b}ࠀa";
734 let_assert!(Ok(res) = TokenString::try_from(act));
735 check!(res == *act, "{res:?} != '{act:?}'");
736 let_assert!(
737 Ok(string_from_iter) =
738 String::from_utf8(res.into_iter().collect::<Vec<u8>>())
739 );
740 check!(
741 string_from_iter.len() == act.len(),
742 "lengths differ {} != {}",
743 string_from_iter.len(),
744 act.len()
745 );
746 // prop_assert!(string_from_iter == act, "'{string_from_iter}' !=
747 // '{act}'");
748 check!(string_from_iter == act, "'{string_from_iter}' != '{act}'");
749 }
750}
751
752mod errors {
753 use assert2::{check, let_assert};
754 use token_string::{TkStrError, TokenString};
755
756 #[test]
757 fn too_long() {
758 let too_big = token_string::MAX_LENGTH + 10;
759 let_assert!(
760 Ok(s1) = std::string::String::from_utf8(vec![b'1'; too_big])
761 );
762 let_assert!(
763 Err(e) = TokenString::try_from(&s1),
764 "this should yield an Error"
765 );
766 check!(e == TkStrError::TooBig(too_big));
767 }
768
769 #[test]
770 fn invalid_utf8() {
771 // this is `0xDC00` as 3 bytes. `ED` is already invalid.
772 let s1: &[u8] = &[0xED, 0xB0, 0x80];
773 let_assert!(
774 Err(e) = TokenString::try_from(s1),
775 "this should yield an Error"
776 );
777 let_assert!(
778 TkStrError::UnicodeError(_) = e,
779 "this should yield an unicode error"
780 );
781 }
782
783 #[test]
784 fn out_of_bounds() {
785 let s1 = "Hello!";
786 #[expect(
787 clippy::cast_possible_truncation,
788 reason = "does not overflow u16"
789 )]
790 let too_big = s1.len() as u16;
791 let_assert!(Ok(res) = TokenString::try_from(s1));
792 let_assert!(Err(e) = res.get(too_big), "this must yield an error");
793 check!(e == TkStrError::OutOfBounds(too_big as usize));
794 }
795
796 #[test]
797 fn out_of_bounds_panic() {
798 let s1 = "Hello!";
799 #[expect(
800 clippy::cast_possible_truncation,
801 reason = "does not overflow u16"
802 )]
803 let too_big = s1.len() as u16;
804 let_assert!(Ok(res) = TokenString::try_from(s1));
805 let_assert!(
806 Err(panics) =
807 std::panic::catch_unwind(|| res.get_unchecked(too_big)),
808 "this should panic with an out of bounds message"
809 );
810 let_assert!(Some(msg) = panics.downcast_ref::<String>());
811 let exp = format!("index {too_big} out of bounds");
812 check!(msg == &exp);
813 }
814}
815
816mod properties {
817 use assert2::let_assert;
818 use proptest::prelude::*;
819 use token_string::TokenString;
820
821 proptest! {
822
823 #[test]
824 fn roundtrip(act in ".*") {
825 let_assert!(Ok(res) = TokenString::try_from(&act));
826 prop_assert!(res.len() == act.len(), "lengths differ: {} != {}",
827 res.len(), act.len());
828 prop_assert!(res == act, "{res:?} != '{act}'");
829 }
830
831 #[test]
832 fn roundtrip_bytes(s in ".*") {
833 let act = s.as_bytes();
834 let_assert!(Ok(res) = TokenString::try_from(act));
835 prop_assert!(res.len() == act.len(), "lengths differ: {} != {}",
836 res.len(), act.len());
837 prop_assert!(res == *act, "{res:?} != '{act:?}'");
838 }
839
840 #[test]
841 fn roundtrip_str(s in ".*") {
842 let act = s.as_str();
843 let_assert!(Ok(res) = TokenString::try_from(act));
844 prop_assert!(res.len() == act.len(), "lengths differ: {} != {}",
845 res.len(), act.len());
846 prop_assert!(res == *act, "{res:?} != '{act:?}'");
847 }
848
849 #[test]
850 fn roundtrip_to_string(act in ".*") {
851 let_assert!(Ok(res) = TokenString::try_from(&act));
852 prop_assert!(res.len() == act.len(), "lengths differ: {} != {}",
853 res.len(), act.len());
854 let res_ = res.to_string();
855 prop_assert!(res_ == *act, "{res:?} != '{act:?}'");
856 }
857
858 #[test]
859 fn roundtrip_iter_owned(act in ".*") {
860 let_assert!(Ok(res) = TokenString::try_from(&act));
861 prop_assert!(res == *act, "{res:?} != '{act:?}'");
862 let_assert!(
863 Ok(string_from_iter) =
864 String::from_utf8(res.into_iter().collect::<Vec<u8>>())
865 );
866 prop_assert!(
867 string_from_iter.len() == act.len(),
868 "lengths differ {} != {}",
869 string_from_iter.len(),
870 act.len()
871 );
872 prop_assert!(string_from_iter == act,
873 "'{string_from_iter}' != '{act}'");
874 }
875
876 #[test]
877 fn roundtrip_iter(act in ".*") {
878 let_assert!(Ok(res) = TokenString::try_from(&act));
879 prop_assert!(res == *act, "{res:?} != '{act:?}'");
880 let_assert!(
881 Ok(string_from_iter) =
882 String::from_utf8(res.iter().collect::<Vec<u8>>())
883 );
884 prop_assert!(
885 string_from_iter.len() == act.len(),
886 "lengths differ {} != {}",
887 string_from_iter.len(),
888 act.len()
889 );
890 prop_assert!(string_from_iter == act,
891 "'{string_from_iter}' != '{act}'");
892 }
893
894 #[test]
895 fn roundtrip_ref_iter(act in ".*") {
896 let_assert!(Ok(res) = TokenString::try_from(&act));
897 prop_assert!(res == act, "{res:?} != '{act:?}'");
898 let_assert!(
899 Ok(string_from_iter) =
900 String::from_utf8((&res).into_iter().collect::<Vec<u8>>())
901 );
902 prop_assert!(
903 string_from_iter.len() == act.len(),
904 "lengths differ {} != {}",
905 string_from_iter.len(),
906 act.len()
907 );
908 prop_assert!(string_from_iter == act,
909 "'{string_from_iter}' != '{act}'");
910 }
911
912 #[test]
913 fn roundtrip_char_iter(act in ".*") {
914 let_assert!(Ok(res) = TokenString::try_from(&act));
915 prop_assert!(res == *act, "{res:?} != '{act:?}'");
916 let string_from_iter = res.chars().collect::<String>();
917 prop_assert!(
918 string_from_iter.len() == act.len(),
919 "lengths differ {} != {}",
920 string_from_iter.len(),
921 act.len()
922 );
923 prop_assert!(string_from_iter == act,
924 "'{string_from_iter}' != '{act}'");
925 }
926
927 }
928}