/// Asserts that both collections contain exactly the same elements found in the same order.
///
/// # Usage
/// ```
/// # #[macro_use] extern crate assertx;
/// # fn main() {
/// #   let actual = vec!["a", "b", "c"];
/// #   let expected = vec!["a", "b", "c"];
///     assert_contains_in_order!(actual, expected);
/// # }
/// ```
///
/// # Examples
///
/// Will succeed, both collections containt the same elements
/// ```
/// # #[macro_use] extern crate assertx;
/// # fn main() {
///     assert_contains_in_order!(vec!["a", "b", "c"], vec!["a", "b", "c"]);
/// # }
/// ```
///
/// Will succeed, actual collection has more elements, but all elements from the expectation are present in the same order.
/// ```
/// # #[macro_use] extern crate assertx;
/// # fn main() {
///     assert_contains_in_order!(vec!["a", "d", "b", "c"], vec!["a", "b", "c"]);
/// # }
/// ```
/// Will succeed, actual collection has a duplicate "a", but all elements from the expectation are present in the same order.
/// ```
/// # #[macro_use] extern crate assertx;
/// # fn main() {
///     assert_contains_in_order!(vec!["a", "a", "b", "c"], vec!["a", "b", "c"]);
/// # }
/// ```
///
/// Will fail, actual collection is missing "c"
/// ```should_panic
/// # #[macro_use] extern crate assertx;
/// # fn main() {
///     assert_contains_in_order!(vec!["a", "b"], vec!["a", "b", "c"]);
/// # }
/// ```
///
/// Will fail, actual collection is in a different order
/// ```should_panic
/// # #[macro_use] extern crate assertx;
/// # fn main() {
///     assert_contains_in_order!(vec!["a", "c", "b"], vec!["a", "b", "c"]);
/// # }
/// ```
#[macro_export]
macro_rules! assert_contains_in_order {
    ($actual: expr, $expected: expr) => {
        let actual = $actual.clone().into_iter();
        let expected = $expected.clone().into_iter();

        assert!(
            actual.len() >= expected.len(),
            "Expected to find each of {:?} in order in {:?}",
            expected.as_slice(),
            actual.as_slice()
        );

        let mut cur_pos = 0;
        for e in expected.clone() {
            if let Some(found) = actual.as_slice()[cur_pos..].iter().position(|it| it == &e) {
                cur_pos = found.clone();
            } else {
                panic!(
                    "Expected to find each of {:?} in order in {:?} - Missing {:?}",
                    expected.as_slice(), actual.as_slice(), e
                )
            }
        }
    };
}

#[cfg(test)]
mod tests {
    #[test]
    fn should_succeed_if_both_sides_empty() {
        assert_contains_in_order!(Vec::<bool>::new(), Vec::<bool>::new());
    }

    #[test]
    fn should_succeed_if_same_elements_in_same_order() {
        assert_contains_in_order!(vec![1, 2, 3], vec![1, 2, 3]);
    }

    #[test]
    fn should_succeed_if_same_duplicate_elements_in_same_order() {
        assert_contains_in_order!(vec![2, 1, 2], vec![2, 1, 2]);
    }

    #[test]
    fn should_succeed_if_actual_has_more_elememts_but_in_same_order() {
        assert_contains_in_order!(vec![1, 2, 3], vec![1, 3]);
    }

    #[test]
    fn should_succeed_if_actual_has_duplicate_elememts_but_in_same_order() {
        assert_contains_in_order!(vec![1, 3, 3], vec![1, 3]);
    }

    #[test]
    #[should_panic(expected = r"Expected to find each of [1, 2, 3] in order in [1, 2]")]
    fn should_fail_if_actual_has_fewer_elememts_even_in_same_order() {
        assert_contains_in_order!(vec![1, 2], vec![1, 2, 3]);
    }

    #[test]
    #[should_panic(expected = r"Expected to find each of [2] in order in [1] - Missing 2")]
    fn should_fail_if_elements_are_not_the_same() {
        assert_contains_in_order!(vec![1], vec![2]);
    }

    #[test]
    #[should_panic(expected = r"Expected to find each of [2, 1] in order in [1, 2] - Missing 1")]
    fn should_fail_if_same_elements_but_different_order() {
        assert_contains_in_order!(vec![1, 2], vec![2, 1]);
    }
}
