1use std::collections::HashSet;
2
3use anyhow::Result;
4use rand::Rng;
5
6const SPECIALS: &[u8] = b"!@#%&*?=+:";
7
8pub fn all(reference: Vec<String>, query: Vec<String>) -> bool {
11 let r = make_string_set(reference);
12 let q = make_string_set(query);
13 q.is_subset(&r)
14}
15
16pub fn any(reference: Vec<String>, query: Vec<String>) -> bool {
19 let r = make_string_set(reference);
20 let q = make_string_set(query);
21 if r.intersection(&q).count() == 0 {
22 return false;
23 }
24 true
25}
26
27pub fn bincode_cfg() -> bincode::config::Configuration<
28 bincode::config::LittleEndian,
29 bincode::config::Fixint,
30 bincode::config::NoLimit,
31> {
32 bincode::config::legacy()
33}
34
35pub fn display(text: &str) -> Result<()> {
36 println!("{text}");
37 Ok(())
38}
39
40pub fn make_string_set(input: Vec<String>) -> HashSet<String> {
41 input.into_iter().collect()
42}
43
44pub fn random_specials(count: usize) -> Vec<u8> {
45 let mut specials: Vec<u8> = Vec::new();
46 let mut rng = rand::thread_rng();
47 for _ in 1..count + 1 {
48 specials.push(SPECIALS[rng.gen_range(0..SPECIALS.len())])
49 }
50 specials
51}
52
53#[cfg(test)]
54mod tests {
55 use super::*;
56
57 fn refset() -> Vec<String> {
58 ["a", "b", "c", "d", "e", "f"]
59 .iter()
60 .map(|e| e.to_string())
61 .collect()
62 }
63
64 fn query1() -> Vec<String> {
65 vec!["b".to_string(), "e".to_string()]
66 }
67
68 fn query2() -> Vec<String> {
69 vec!["b".to_string(), "g".to_string()]
70 }
71
72 fn query3() -> Vec<String> {
73 vec!["h".to_string(), "g".to_string()]
74 }
75
76 #[test]
77 fn all() {
78 assert!(super::all(refset(), query1()));
79 assert!(!super::all(refset(), query2()));
80 assert!(!super::all(refset(), query3()));
81 }
82
83 #[test]
84 fn test_all_empty_query() {
85 assert!(super::all(refset(), vec![]), "Empty query should be subset");
86 }
87
88 #[test]
89 fn test_all_empty_reference() {
90 assert!(
91 !super::all(vec![], query1()),
92 "Non-empty query can't be subset of empty reference"
93 );
94 }
95
96 #[test]
97 fn test_all_both_empty() {
98 assert!(
99 super::all(vec![], vec![]),
100 "Empty set is subset of empty set"
101 );
102 }
103
104 #[test]
105 fn test_all_identical_sets() {
106 let set = vec!["x".to_string(), "y".to_string()];
107 assert!(super::all(set.clone(), set));
108 }
109
110 #[test]
111 fn test_all_single_element() {
112 assert!(super::all(refset(), vec!["a".to_string()]));
113 assert!(!super::all(refset(), vec!["z".to_string()]));
114 }
115
116 #[test]
117 fn any() {
118 assert!(super::any(refset(), query1()));
119 assert!(super::any(refset(), query2()));
120 assert!(!super::any(refset(), query3()));
121 }
122
123 #[test]
124 fn test_any_empty_query() {
125 assert!(
126 !super::any(refset(), vec![]),
127 "Empty query has no intersection"
128 );
129 }
130
131 #[test]
132 fn test_any_empty_reference() {
133 assert!(
134 !super::any(vec![], query1()),
135 "Empty reference has no intersection"
136 );
137 }
138
139 #[test]
140 fn test_any_both_empty() {
141 assert!(
142 !super::any(vec![], vec![]),
143 "Empty sets have no intersection"
144 );
145 }
146
147 #[test]
148 fn test_any_single_match() {
149 let reference = vec!["a".to_string(), "b".to_string()];
150 let query = vec!["b".to_string(), "c".to_string()];
151 assert!(super::any(reference, query));
152 }
153
154 #[test]
155 fn test_any_no_match() {
156 let reference = vec!["a".to_string(), "b".to_string()];
157 let query = vec!["x".to_string(), "y".to_string()];
158 assert!(!super::any(reference, query));
159 }
160
161 #[test]
162 fn test_make_string_set_basic() {
163 let input = vec!["a".to_string(), "b".to_string(), "c".to_string()];
164 let set = make_string_set(input);
165 assert_eq!(set.len(), 3);
166 assert!(set.contains("a"));
167 assert!(set.contains("b"));
168 assert!(set.contains("c"));
169 }
170
171 #[test]
172 fn test_make_string_set_duplicates() {
173 let input = vec!["a".to_string(), "a".to_string(), "b".to_string()];
174 let set = make_string_set(input);
175 assert_eq!(set.len(), 2, "Duplicates should be removed");
176 }
177
178 #[test]
179 fn test_make_string_set_empty() {
180 let input: Vec<String> = vec![];
181 let set = make_string_set(input);
182 assert!(set.is_empty());
183 }
184
185 #[test]
186 fn test_display_simple() {
187 let result = display("Hello, World!");
188 assert!(result.is_ok());
189 }
190
191 #[test]
192 fn test_display_empty() {
193 let result = display("");
194 assert!(result.is_ok());
195 }
196
197 #[test]
198 fn test_display_multiline() {
199 let result = display("Line 1\nLine 2\nLine 3");
200 assert!(result.is_ok());
201 }
202
203 #[test]
204 fn test_display_unicode() {
205 let result = display("Hello δΈη π");
206 assert!(result.is_ok());
207 }
208
209 #[test]
210 fn test_random_specials_zero() {
211 let specials = random_specials(0);
212 assert_eq!(specials.len(), 0);
213 }
214
215 #[test]
216 fn test_random_specials_one() {
217 let specials = random_specials(1);
218 assert_eq!(specials.len(), 1);
219 assert!(SPECIALS.contains(&specials[0]));
220 }
221
222 #[test]
223 fn test_random_specials_multiple() {
224 let specials = random_specials(10);
225 assert_eq!(specials.len(), 10);
226 for &s in &specials {
227 assert!(
228 SPECIALS.contains(&s),
229 "All returned characters should be from SPECIALS"
230 );
231 }
232 }
233
234 #[test]
235 fn test_random_specials_all_valid() {
236 let specials = random_specials(100);
237 assert_eq!(specials.len(), 100);
238 for &s in &specials {
239 assert!(SPECIALS.contains(&s));
240 }
241 }
242
243 #[test]
244 fn test_bincode_cfg_returns_config() {
245 let _config = bincode_cfg();
246 }
248
249 #[test]
250 fn test_bincode_cfg_is_legacy() {
251 let config = bincode_cfg();
252 let data = vec![1u8, 2u8, 3u8];
254 let encoded = bincode::encode_to_vec(&data, config).unwrap();
255 let (decoded, _): (Vec<u8>, _) = bincode::decode_from_slice(&encoded, config).unwrap();
256 assert_eq!(data, decoded);
257 }
258
259 #[test]
260 fn test_specials_constant() {
261 assert_eq!(SPECIALS, b"!@#%&*?=+:");
262 assert_eq!(SPECIALS.len(), 10);
263 }
264}