private static DeepTestResult CollectionsAreIntersectionEquivalent <T>(
            IEnumerable <T> collection,
            IEnumerable <T> expected,
            object[] customEqualityMatchers)
        {
            return(CollectionCompare(
                       collection,
                       expected,
                       (master, compare) =>
            {
                while (master.Any())
                {
                    var currentMaster = master.First();
                    var compareMatch =
                        compare.FirstOrDefault(
                            c => AreIntersectionEqual(
                                currentMaster,
                                c,
                                customEqualityMatchers).AreEqual);
                    // TODO: add information about mismatch
                    if (compareMatch == null)
                    {
                        return DeepTestResult.Fail(
                            $"Found no match for item\n{currentMaster.Stringify()}"
                            );
                    }

                    master.Remove(currentMaster);
                    compare.Remove(compareMatch);
                }

                return DeepTestResult.Pass;
            }));
        }
        private static DeepTestResult CollectionsAreDeepEqual <T>(
            IEnumerable <T> collection,
            IEnumerable <T> expected,
            object[] customEqualityComparers
            )
        {
            if (collection == null && expected == null)
            {
                return(DeepTestResult.Pass);
            }

            if (collection == null || expected == null)
            {
                return(DeepTestResult.Fail(
                           expected == null
                        ? $"Expected collection is null but actual is not"
                        : $"Actual collection is null but expected is not"
                           ));
            }

            var expectedCount   = expected.Count();
            var collectionCount = collection.Count();

            if (expectedCount != collectionCount)
            {
                return(DeepTestResult.Fail(
                           $"Expected collection with {expectedCount} items, but got {collectionCount}"
                           ));
            }

            return(CollectionCompare(
                       collection,
                       expected,
                       (master, compare)
                       => master.Zip(compare, Tuple.Create)
                       .Aggregate(
                           null as DeepTestResult,
                           (acc, cur) =>
            {
                if (acc != null)
                {
                    return acc;
                }

                var result =
                    AreDeepEqual(
                        cur.Item1, cur.Item2, customEqualityComparers);
                return result.AreEqual ? null : result;
            }
                           )
                       ) ?? DeepTestResult.Pass);
        }