1use crate::assertions::{
94 CollectionContains, CollectionEqual, CollectionNotContain, CollectionNotEqual, Length,
95};
96use crate::{test_failed, Actual, Expected};
97use std::collections::HashMap;
98
99pub struct ListAssert<T> {
100 actual: Vec<Actual<T>>,
101}
102
103impl<T> ListAssert<T>
104where
105 T: 'static,
106{
107 pub fn assert_that(actual: Vec<Actual<T>>) -> ListAssert<T> {
108 ListAssert { actual }
109 }
110
111 pub fn with_element_matcher(self, element_matcher: fn(&T, &T) -> bool) -> ListElementAssert<T> {
112 ListElementAssert {
113 actual: self.actual,
114 element_matcher,
115 }
116 }
117
118 pub fn length(self) -> Box<dyn Length> {
119 Box::new(self)
120 }
121}
122
123pub struct ListElementAssert<T> {
124 actual: Vec<Actual<T>>,
125 element_matcher: fn(&T, &T) -> bool,
126}
127
128impl<T> ListElementAssert<T>
129where
130 T: 'static,
131{
132 pub fn contains(self, expected: Vec<Expected<T>>) -> Box<dyn CollectionContains<T>> {
133 Box::new(ListFinalAssert {
134 actual: self.actual,
135 expected,
136 element_matcher: self.element_matcher,
137 })
138 }
139
140 pub fn does_not_contain(self, expected: Vec<Expected<T>>) -> Box<dyn CollectionNotContain<T>> {
141 Box::new(ListFinalAssert {
142 actual: self.actual,
143 expected,
144 element_matcher: self.element_matcher,
145 })
146 }
147
148 pub fn is_equal_to(self, expected: Vec<Expected<T>>) -> Box<dyn CollectionEqual<T>> {
149 Box::new(ListFinalAssert {
150 actual: self.actual,
151 expected,
152 element_matcher: self.element_matcher,
153 })
154 }
155
156 pub fn is_not_equal_to(self, expected: Vec<Expected<T>>) -> Box<dyn CollectionNotEqual<T>> {
157 Box::new(ListFinalAssert {
158 actual: self.actual,
159 expected,
160 element_matcher: self.element_matcher,
161 })
162 }
163}
164
165struct ListFinalAssert<T> {
166 actual: Vec<Actual<T>>,
167 expected: Vec<Expected<T>>,
168 element_matcher: fn(&T, &T) -> bool,
169}
170
171type ActualIndex = usize;
172type ExpectedIndex = usize;
173
174impl<T> ListFinalAssert<T> {
175 fn vec_to_string(vec: &[Actual<T>]) -> String {
176 vec.iter()
177 .map(|val| val.to_string())
178 .collect::<Vec<String>>()
179 .join(",")
180 }
181
182 fn contains_in_any_order(&self) -> Result<(), String> {
183 let mut errors: Vec<String> = vec![];
186 let expected_diff = self.only_in_expected();
187 for expected_index in expected_diff {
188 errors.push(format!(
189 " - Expected element: ({}) - Not found",
190 self.expected[expected_index]
191 ));
192 }
193
194 if errors.is_empty() {
195 return Ok(());
196 }
197 Err(errors.join("\n"))
198 }
199
200 fn get_unchecked_index(
201 &self,
202 expected_elem: &Expected<T>,
203 checked_actual_indexes: &[usize],
204 ) -> Option<usize> {
205 for (actual_index, actual_elem) in self.actual.iter().enumerate() {
206 let actual_index_was_checked = checked_actual_indexes.get(actual_index).is_some();
207 if actual_index_was_checked {
208 continue;
209 }
210 if (self.element_matcher)(&actual_elem.value, &expected_elem.value) {
211 return Some(actual_index);
212 }
213 }
214
215 None
216 }
217
218 fn actual_contains_exact_expected_slice(&self, starting_position: usize) -> bool {
219 let mut matches_length = 0;
220 for (expected_index, expected_elem) in self.expected.iter().enumerate() {
221 let actual_index = expected_index + starting_position;
222 if actual_index >= self.actual.len() {
223 return false;
224 }
225 let actual_elem = &self.actual[actual_index];
226
227 if (self.element_matcher)(&actual_elem.value, &expected_elem.value) {
228 matches_length += 1;
229 } else {
230 break;
231 }
232 }
233
234 matches_length == self.expected.len()
235 }
236
237 fn actual_len_ge_expected(&self) -> Result<(), String> {
238 if self.actual.len() < self.expected.len() {
239 return Err(format!(
240 "\n The actual vec size ({}) is LESS then expected vec ({})\n",
241 self.actual.len(),
242 self.expected.len()
243 ));
244 };
245 Ok(())
246 }
247
248 fn list_test_failed(&self, error_message: &str) {
249 let list_error_message = format!(
250 "Actual vec: [{}] \n Expected vec: [{}] \n Detailed error: \n {}",
251 Self::vec_to_string(&self.actual),
252 Self::vec_to_string(&self.expected),
253 error_message
254 );
255 test_failed(&list_error_message);
256 }
257
258 fn only_in_expected(&self) -> Vec<ExpectedIndex> {
259 let (_, only_in_expected) = self.difference_ignoring_position();
260
261 only_in_expected
262 }
263
264 fn difference_ignoring_position(&self) -> (Vec<ActualIndex>, Vec<ExpectedIndex>) {
265 let intersection = self.intersection_indexes();
266 if intersection.len() == self.actual.len() && intersection.len() == self.expected.len() {
267 return (vec![], vec![]);
268 }
269
270 let mut actual_existing: Vec<bool> = vec![false; self.actual.len()];
271 let mut expected_existing: Vec<bool> = vec![false; self.expected.len()];
272 for (actual_index, expected_index) in intersection {
273 actual_existing[actual_index] = true;
274 expected_existing[expected_index] = true;
275 }
276
277 let mut only_in_actual = vec![];
278 for (index, exist) in actual_existing.iter().enumerate() {
279 if !exist {
280 only_in_actual.push(index);
281 }
282 }
283
284 let mut only_in_expected = vec![];
285 for (index, exist) in expected_existing.iter().enumerate() {
286 if !exist {
287 only_in_expected.push(index);
288 }
289 }
290
291 (only_in_actual, only_in_expected)
292 }
293
294 fn intersection_indexes(&self) -> HashMap<ActualIndex, ExpectedIndex> {
295 let mut equals_indexes: HashMap<usize, usize> = HashMap::new();
296
297 for (expected_index, expected_elem) in self.expected.iter().enumerate() {
298 for (actual_index, actual_elem) in self.actual.iter().enumerate() {
299 let actual_index_was_matched = equals_indexes.get(&actual_index).is_some();
300 if actual_index_was_matched {
301 continue;
302 }
303
304 let elements_matches =
305 (self.element_matcher)(&actual_elem.value, &expected_elem.value);
306 if elements_matches {
307 equals_indexes.insert(actual_index, expected_index);
308 break;
309 }
310 }
311 }
312
313 equals_indexes
314 }
315}
316
317impl<T> CollectionEqual<T> for ListFinalAssert<T> {
318 fn in_any_order(&self) {
319 let error = length_check(self.actual.len(), self.expected.len()).err();
320 if let Some(error_message) = error {
321 self.list_test_failed(&error_message);
322 }
323 let result = self.contains_in_any_order();
324 if let Some(error) = result.err() {
325 self.list_test_failed(&error);
326 }
327 }
328
329 fn in_order(&self) {
330 let error = length_check(self.actual.len(), self.expected.len()).err();
331 if let Some(error_message) = error {
332 self.list_test_failed(&error_message);
333 }
334 let mut errors: Vec<String> = vec![];
335
336 for index in 0..self.actual.len() {
337 let actual_elem = &self.actual[index];
338 let expected_elem = &self.expected[index];
339 if !(self.element_matcher)(&actual_elem.value, &expected_elem.value) {
340 errors.push(format!(
341 "Actual element: ({}) not equal to Expected: ({}) in position ({})\n",
342 actual_elem, expected_elem, index
343 ));
344 }
345 }
346
347 if !errors.is_empty() {
348 let error_message = format!("\n {}", errors.join("\n"));
349 self.list_test_failed(&error_message);
350 }
351 }
352}
353
354impl<T> CollectionNotEqual<T> for ListFinalAssert<T> {
355 fn in_any_order(&self) {
356 if self.actual.len() != self.expected.len() {
357 return;
358 }
359 let result = self.contains_in_any_order();
360 if result.is_ok() {
361 self.list_test_failed("Collections are equals, but should not. Collections considered equals if they has same elements in any order.");
362 }
363 }
364
365 fn in_order(&self) {
366 if self.actual.len() != self.expected.len() {
367 return;
368 }
369
370 for index in 0..self.actual.len() {
371 let actual_elem = &self.actual[index];
372 let expected_elem = &self.expected[index];
373 if !(self.element_matcher)(&actual_elem.value, &expected_elem.value) {
374 return;
375 }
376 }
377
378 self.list_test_failed("Collections has same elements in same order, they are equal");
379 }
380}
381
382impl<T> CollectionContains<T> for ListFinalAssert<T> {
383 fn in_any_order(&self) {
384 let result = self.contains_in_any_order();
385 if let Some(error) = result.err() {
386 self.list_test_failed(&error);
387 }
388 }
389
390 fn in_exact_order(&self) {
391 let error = self.actual_len_ge_expected().err();
393 if let Some(error_message) = error {
394 self.list_test_failed(&error_message);
395 }
396
397 let first_expected_elem = &self.expected[0];
398 let mut checked_actual_indexes: Vec<usize> = Vec::new();
399 let mut matched = false;
400 loop {
401 let starting_position =
402 self.get_unchecked_index(first_expected_elem, &checked_actual_indexes);
403 if starting_position.is_none() {
404 break;
405 }
406 let starting_position = starting_position.unwrap();
407 checked_actual_indexes.push(starting_position);
408
409 matched = self.actual_contains_exact_expected_slice(starting_position);
410 if matched {
411 break;
412 }
413 }
414
415 if !matched {
416 self.list_test_failed(
417 "\n the Actual vec doesn't contains Expected vec in Exact order",
418 );
419 }
420 }
421
422 fn just_in_order(&self) {
423 let result = self.actual_len_ge_expected();
425 if let Some(error_message) = result.err() {
426 self.list_test_failed(&error_message);
427 }
428 let mut prev_number_index: usize = 0;
429 let mut matched_length: usize = 0;
430 for expected_elem in &self.expected {
431 let start_index = prev_number_index;
432 for actual_index in start_index..self.actual.len() {
433 let actual_elem = &self.actual[actual_index];
434 if (self.element_matcher)(&actual_elem.value, &expected_elem.value) {
435 prev_number_index = actual_index;
436 matched_length += 1;
437 break;
438 }
439 }
440 }
441
442 if matched_length != self.expected.len() {
443 let error_message = format!("\n the Actual vec doesn't contains Expected vec Just in order. Matched only {} elements",
444 matched_length
445 );
446 self.list_test_failed(&error_message);
447 }
448 }
449}
450
451impl<T> CollectionNotContain<T> for ListFinalAssert<T> {
452 fn all(&self) {
453 if self.actual.len() < self.expected.len() {
454 return;
455 }
456
457 let intersection = self.intersection_indexes();
458 if intersection.is_empty() {
459 return;
460 }
461
462 let mut errors: Vec<String> = vec![];
463 for (actual_index, expected_index) in intersection {
464 errors.push(format!(
465 " - Element was found ({}). Actual index ({}), Expected index ({})",
466 &self.actual[actual_index], actual_index, expected_index,
467 ));
468 }
469 self.list_test_failed(&errors.join("\n"));
470 }
471
472 fn at_least_one(&self) {
473 let intersection = self.intersection_indexes();
474 if intersection.len() == self.expected.len() {
475 self.list_test_failed("All expected elements were found in Actual vec");
476 }
477 }
478}
479
480impl<T> Length for ListAssert<T> {
481 fn is(&self, expected: Expected<usize>) {
482 let error = length_check(self.actual.len(), expected.value).err();
483 if let Some(error_message) = error {
484 test_failed(&error_message);
485 }
486 }
487}
488
489fn length_check(actual: usize, expected: usize) -> Result<(), String> {
490 if actual != expected {
491 return Err(format!(
492 "\n Actual collection size: {} \n not equal to \n Expected: {} \n",
493 actual, expected,
494 ));
495 };
496 Ok(())
497}