private static void Equal(
            XElementAndSource expected,
            XElementAndSource actual,
            IEqualityComparer <XElement> customElementComparer,
            IEqualityComparer <XAttribute> customAttributeComparer,
            XmlAssertOptions options)
        {
            CheckAttributes(expected, actual, customAttributeComparer, options);

            if ((expected?.AllElements.Count ?? 0) == 0 && (actual?.AllElements.Count ?? 0) == 0)
            {
                if (XElementComparer.GetFor(options).Equals(expected?.Element, actual?.Element))
                {
                    return;
                }

                if (customElementComparer?.Equals(expected?.Element, actual?.Element) == true)
                {
                    return;
                }

                var message = CreateMessage(expected, actual);
                throw new AssertException(message);
            }

            var nameComparer = XNameComparer.GetFor(options);

            if (!nameComparer.Equals(expected?.Element.Name, actual?.Element.Name))
            {
                var message = CreateMessage(expected, actual);
                throw new AssertException(message);
            }

            if (!options.IsSet(XmlAssertOptions.IgnoreElementOrder))
            {
                var expectedElements = expected?.AllElements;
                var actualElements   = actual?.AllElements;
                CheckOrder(expectedElements,
                           actualElements,
                           x => x.Element.Name,
                           "  The order of elements is incorrect.",
                           options);
            }

            var expectedElementsToCheck = expected?.ElementsToCheck;
            var actualElementsToCheck   = actual?.ElementsToCheck;

            for (int i = 0; i < Math.Max(expectedElementsToCheck?.Count ?? 0, actualElementsToCheck?.Count ?? 0); i++)
            {
                var expectedChild = expectedElementsToCheck.ElementAtOrDefault(i);
                var actualChild   = actualElementsToCheck.ElementAtOrDefault(i);
                Equal(expectedChild, actualChild, customElementComparer, customAttributeComparer, options);
            }
        }
        private static void CheckAttributes(
            XElementAndSource expectedElement,
            XElementAndSource actualElement,
            IEqualityComparer <XAttribute> customAttributeComparer,
            XmlAssertOptions options)
        {
            if (!options.IsSet(XmlAssertOptions.IgnoreAttributeOrder))
            {
                var expectedAttributes = expectedElement?.AllAttributes;
                var actualAttributes   = actualElement?.AllAttributes;
                CheckOrder(expectedAttributes,
                           actualAttributes,
                           x => x.Attribute.Name,
                           "  The order of attributes is incorrect.",
                           options);
            }

            var expectedAttributesToCheck = expectedElement?.AttributesToCheck;
            var actualAttributesToCheck   = actualElement?.AttributesToCheck;

            var defaultAttributeComparer = XAttributeComparer.GetFor(options);

            for (int i = 0; i < Math.Max(expectedAttributesToCheck?.Count ?? 0, actualAttributesToCheck?.Count ?? 0); i++)
            {
                var expectedAttribute = expectedAttributesToCheck.ElementAtOrDefault(i);
                var actualAttribute   = actualAttributesToCheck.ElementAtOrDefault(i);

                if (defaultAttributeComparer.Equals(expectedAttribute?.Attribute, actualAttribute?.Attribute))
                {
                    continue;
                }

                if (customAttributeComparer?.Equals(expectedAttribute?.Attribute, actualAttribute?.Attribute) == true)
                {
                    continue;
                }

                var message = expectedAttribute == null || actualAttribute == null
                    ? CreateMessage(expectedElement, actualElement)
                    : CreateMessage(expectedAttribute, actualAttribute);

                throw new AssertException(message);
            }
        }