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 170 lines 5.2 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_builder.rs 6// Date: 24.Nov.2024 7// ============================================================================= 8//! Test the concatenation of `TokenStrings`s. 9 10#![expect(clippy::tests_outside_test_module, reason = "tests directory")] 11 12mod errors { 13 14 use assert2::{check, let_assert}; 15 use token_string::{Builder, MAX_LENGTH, TkStrError, TokenString}; 16 17 #[test] 18 fn too_many() { 19 let_assert!(Ok(s1) = TokenString::try_from("Hello")); 20 let_assert!(Ok(s2) = TokenString::try_from(", ")); 21 let_assert!(Ok(s3) = TokenString::try_from("world")); 22 let_assert!(Ok(s4) = TokenString::try_from("!")); 23 let mut builder = Builder::<'_, 3>::new(&s1); 24 let_assert!(Ok(_) = builder.concat_checked(&s2)); 25 let_assert!(Ok(_) = builder.concat_checked(&s3)); 26 let_assert!(Err(e) = builder.concat_checked(&s4)); 27 check!(e == TkStrError::TooMany(3)); 28 } 29 30 #[test] 31 fn too_big() { 32 let_assert!(Ok(s1) = TokenString::try_from("Hello")); 33 let_assert!(Ok(s2) = TokenString::try_from(", ")); 34 let_assert!(Ok(s3) = TokenString::try_from("world")); 35 let big = vec![b'1'; MAX_LENGTH].into_boxed_slice(); 36 let_assert!(Ok(s4) = TokenString::try_from(&*big)); 37 let mut builder = Builder::<'_, 4>::new(&s1); 38 let_assert!(Ok(_) = builder.concat_checked(&s2)); 39 let_assert!(Ok(_) = builder.concat_checked(&s3)); 40 let_assert!(Err(e) = builder.concat_checked(&s4)); 41 check!(e == TkStrError::TooBig(65547)); 42 } 43 44 #[test] 45 fn too_many_panic() { 46 let_assert!(Ok(s1) = TokenString::try_from("Hello")); 47 let_assert!(Ok(s2) = TokenString::try_from(", ")); 48 let_assert!(Ok(s3) = TokenString::try_from("world")); 49 let_assert!(Ok(s4) = TokenString::try_from("!")); 50 51 let_assert!( 52 Err(panics) = std::panic::catch_unwind(|| { 53 let mut builder = Builder::<'_, 3>::new(&s1); 54 let_assert!(Ok(_) = builder.concat_checked(&s2)); 55 let_assert!(Ok(_) = builder.concat_checked(&s3)); 56 let _c = builder.concat_unchecked(&s4); 57 }) 58 ); 59 let_assert!(Some(msg) = panics.downcast_ref::<&str>()); 60 check!( 61 msg == &"more strings concatenated than reserved space in Builder" 62 ); 63 } 64 65 #[test] 66 fn not_zero_panic() { 67 let_assert!(Ok(s1) = TokenString::try_from("Hello")); 68 69 let_assert!( 70 Err(panics) = std::panic::catch_unwind(|| { 71 let mut _builder = Builder::<'_, 0>::new(&s1); 72 }) 73 ); 74 let_assert!(Some(msg) = panics.downcast_ref::<&str>()); 75 check!(msg == &"the number of elements must not be 0"); 76 } 77} 78 79mod func { 80 use assert2::{check, let_assert}; 81 use token_string::{Builder, Collect as _, Concat as _, TokenString}; 82 83 #[test] 84 fn concat_collect() { 85 let_assert!(Ok(s1) = TokenString::try_from("Hello")); 86 let_assert!(Ok(s2) = TokenString::try_from(", ")); 87 let_assert!(Ok(s3) = TokenString::try_from("world")); 88 let_assert!(Ok(s4) = TokenString::try_from("!")); 89 90 let mut builder = Builder::<'_, 4>::new(&s1); 91 let builder_2 = builder.concat(&s2).concat(&s3).concat(&s4); 92 let_assert!(Ok(res) = builder_2.collect()); 93 check!(&res == "Hello, world!"); 94 } 95 96 #[test] 97 fn collect_unchecked_concat() { 98 let_assert!(Ok(s1) = TokenString::try_from("Hello")); 99 let_assert!(Ok(s2) = TokenString::try_from(", ")); 100 let_assert!(Ok(s3) = TokenString::try_from("world")); 101 let_assert!(Ok(s4) = TokenString::try_from("!")); 102 103 let mut builder = Builder::<'_, 4>::new(&s1); 104 let builder_2 = builder 105 .concat_unchecked(&s2) 106 .concat_unchecked(&s3) 107 .concat_unchecked(&s4); 108 let_assert!(Ok(res) = builder_2.collect()); 109 check!(&res == "Hello, world!"); 110 } 111 112 #[test] 113 fn to_string() { 114 let_assert!(Ok(s1) = TokenString::try_from("Hello")); 115 let_assert!(Ok(s2) = TokenString::try_from(", ")); 116 let_assert!(Ok(s3) = TokenString::try_from("world")); 117 let_assert!(Ok(s4) = TokenString::try_from("!")); 118 119 let mut builder = Builder::<'_, 4>::new(&s1); 120 let_assert!( 121 Ok(builder_2) = builder.concat(&s2).concat(&s3).concat(&s4) 122 ); 123 check!( 124 builder_2.to_string() 125 == "Builder < 'Hello' + ', ' + 'world' + '!' >" 126 ); 127 } 128} 129 130mod properties { 131 use assert2::let_assert; 132 use proptest::prelude::*; 133 use token_string::{Builder, TokenString}; 134 135 fn vec_of_string(len: usize) -> impl Strategy<Value = Vec<String>> { 136 prop::collection::vec(".*", 1 .. len).prop_flat_map(Just) 137 } 138 139 proptest! { 140 141 #[test] 142 fn concat_2(a in ".*", b in ".*") { 143 let_assert!(Ok(s1) = TokenString::try_from(&a)); 144 let_assert!(Ok(s2) = TokenString::try_from(&b)); 145 let mut builder = Builder::<'_, 2>::new(&s1); 146 let_assert!(Ok(c) = builder.concat_checked(&s2)); 147 let_assert!(Ok(res) = c.collect_checked()); 148 let mut exp = a; 149 exp.push_str(&b); 150 prop_assert!(res == exp); 151 } 152 153 #[test] 154 #[cfg_attr(miri, ignore)] // takes too long for miri - 10 hours! 155 fn concat_many(v in vec_of_string(100)) { 156 let strings: Vec<TokenString> = v.iter() 157 .map(|s| {TokenString::from_str_unchecked(s)}).collect(); 158 159 let mut builder = Builder::<'_, 100>::new(&strings[0]); 160 let mut exp = strings[0].as_string(); 161 for s in strings.iter().skip(1) { 162 let_assert!(Ok(_c) = builder.concat_checked(s)); 163 exp.push_str(s.as_str()); 164 } 165 let_assert!(Ok(res) = builder.collect_checked()); 166 prop_assert!(res == exp); 167 } 168 169 } 170}