// SPDX-FileCopyrightText: Copyright (C) 2024 Roland Csaszar // SPDX-License-Identifier: MPL-2.0 // // Project: token-string // File: test_builder.rs // Date: 24.Nov.2024 // ============================================================================= //! Test the concatenation of `TokenStrings`s. #![expect(clippy::tests_outside_test_module, reason = "tests directory")] mod errors { use assert2::{check, let_assert}; use token_string::{Builder, MAX_LENGTH, TkStrError, TokenString}; #[test] fn too_many() { let_assert!(Ok(s1) = TokenString::try_from("Hello")); let_assert!(Ok(s2) = TokenString::try_from(", ")); let_assert!(Ok(s3) = TokenString::try_from("world")); let_assert!(Ok(s4) = TokenString::try_from("!")); let mut builder = Builder::<'_, 3>::new(&s1); let_assert!(Ok(_) = builder.concat_checked(&s2)); let_assert!(Ok(_) = builder.concat_checked(&s3)); let_assert!(Err(e) = builder.concat_checked(&s4)); check!(e == TkStrError::TooMany(3)); } #[test] fn too_big() { let_assert!(Ok(s1) = TokenString::try_from("Hello")); let_assert!(Ok(s2) = TokenString::try_from(", ")); let_assert!(Ok(s3) = TokenString::try_from("world")); let big = vec![b'1'; MAX_LENGTH].into_boxed_slice(); let_assert!(Ok(s4) = TokenString::try_from(&*big)); let mut builder = Builder::<'_, 4>::new(&s1); let_assert!(Ok(_) = builder.concat_checked(&s2)); let_assert!(Ok(_) = builder.concat_checked(&s3)); let_assert!(Err(e) = builder.concat_checked(&s4)); check!(e == TkStrError::TooBig(65547)); } #[test] fn too_many_panic() { let_assert!(Ok(s1) = TokenString::try_from("Hello")); let_assert!(Ok(s2) = TokenString::try_from(", ")); let_assert!(Ok(s3) = TokenString::try_from("world")); let_assert!(Ok(s4) = TokenString::try_from("!")); let_assert!( Err(panics) = std::panic::catch_unwind(|| { let mut builder = Builder::<'_, 3>::new(&s1); let_assert!(Ok(_) = builder.concat_checked(&s2)); let_assert!(Ok(_) = builder.concat_checked(&s3)); let _c = builder.concat_unchecked(&s4); }) ); let_assert!(Some(msg) = panics.downcast_ref::<&str>()); check!( msg == &"more strings concatenated than reserved space in Builder" ); } #[test] fn not_zero_panic() { let_assert!(Ok(s1) = TokenString::try_from("Hello")); let_assert!( Err(panics) = std::panic::catch_unwind(|| { let mut _builder = Builder::<'_, 0>::new(&s1); }) ); let_assert!(Some(msg) = panics.downcast_ref::<&str>()); check!(msg == &"the number of elements must not be 0"); } } mod func { use assert2::{check, let_assert}; use token_string::{Builder, Collect as _, Concat as _, TokenString}; #[test] fn concat_collect() { let_assert!(Ok(s1) = TokenString::try_from("Hello")); let_assert!(Ok(s2) = TokenString::try_from(", ")); let_assert!(Ok(s3) = TokenString::try_from("world")); let_assert!(Ok(s4) = TokenString::try_from("!")); let mut builder = Builder::<'_, 4>::new(&s1); let builder_2 = builder.concat(&s2).concat(&s3).concat(&s4); let_assert!(Ok(res) = builder_2.collect()); check!(&res == "Hello, world!"); } #[test] fn collect_unchecked_concat() { let_assert!(Ok(s1) = TokenString::try_from("Hello")); let_assert!(Ok(s2) = TokenString::try_from(", ")); let_assert!(Ok(s3) = TokenString::try_from("world")); let_assert!(Ok(s4) = TokenString::try_from("!")); let mut builder = Builder::<'_, 4>::new(&s1); let builder_2 = builder .concat_unchecked(&s2) .concat_unchecked(&s3) .concat_unchecked(&s4); let_assert!(Ok(res) = builder_2.collect()); check!(&res == "Hello, world!"); } #[test] fn to_string() { let_assert!(Ok(s1) = TokenString::try_from("Hello")); let_assert!(Ok(s2) = TokenString::try_from(", ")); let_assert!(Ok(s3) = TokenString::try_from("world")); let_assert!(Ok(s4) = TokenString::try_from("!")); let mut builder = Builder::<'_, 4>::new(&s1); let_assert!( Ok(builder_2) = builder.concat(&s2).concat(&s3).concat(&s4) ); check!( builder_2.to_string() == "Builder < 'Hello' + ', ' + 'world' + '!' >" ); } } mod properties { use assert2::let_assert; use proptest::prelude::*; use token_string::{Builder, TokenString}; fn vec_of_string(len: usize) -> impl Strategy> { prop::collection::vec(".*", 1 .. len).prop_flat_map(Just) } proptest! { #[test] fn concat_2(a in ".*", b in ".*") { let_assert!(Ok(s1) = TokenString::try_from(&a)); let_assert!(Ok(s2) = TokenString::try_from(&b)); let mut builder = Builder::<'_, 2>::new(&s1); let_assert!(Ok(c) = builder.concat_checked(&s2)); let_assert!(Ok(res) = c.collect_checked()); let mut exp = a; exp.push_str(&b); prop_assert!(res == exp); } #[test] #[cfg_attr(miri, ignore)] // takes too long for miri - 10 hours! fn concat_many(v in vec_of_string(100)) { let strings: Vec = v.iter() .map(|s| {TokenString::from_str_unchecked(s)}).collect(); let mut builder = Builder::<'_, 100>::new(&strings[0]); let mut exp = strings[0].as_string(); for s in strings.iter().skip(1) { let_assert!(Ok(_c) = builder.concat_checked(s)); exp.push_str(s.as_str()); } let_assert!(Ok(res) = builder.collect_checked()); prop_assert!(res == exp); } } }