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
at main 928 lines 20 kB view raw
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: \"\\\" }" 282 ); 283 } 284 285 #[test] 286 fn debug_print_small() { 287 let_assert!(Ok(res) = TokenString::try_from("\0")); 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("\0\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}