| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151 |
- // Copyright (c) .NET Foundation. All rights reserved.
- // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Xml.Linq;
- using Xunit;
- namespace Microsoft.AspNetCore.DataProtection
- {
- /// <summary>
- /// Helpful XML-based assertions.
- /// </summary>
- public static class XmlAssert
- {
- public static readonly IEqualityComparer<XNode> EqualityComparer = new CallbackBasedEqualityComparer<XNode>(Core.AreEqual);
- /// <summary>
- /// Asserts that a <see cref="string"/> and an <see cref="XElement"/> are semantically equivalent.
- /// </summary>
- public static void Equal(string expected, XElement actual)
- {
- Assert.NotNull(expected);
- Assert.NotNull(actual);
- Equal(XElement.Parse(expected), actual);
- }
- /// <summary>
- /// Asserts that two <see cref="XElement"/> instances are semantically equivalent.
- /// </summary>
- public static void Equal(XElement expected, XElement actual)
- {
- Assert.NotNull(expected);
- Assert.NotNull(actual);
- if (!Core.AreEqual(expected, actual))
- {
- Assert.True(false,
- "Expected element:" + Environment.NewLine
- + expected.ToString() + Environment.NewLine
- + "Actual element:" + Environment.NewLine
- + actual.ToString());
- }
- }
- private static class Core
- {
- private static readonly IEqualityComparer<XAttribute> AttributeEqualityComparer = new CallbackBasedEqualityComparer<XAttribute>(AreEqual);
- private static bool AreEqual(XElement expected, XElement actual)
- {
- return expected.Name == actual.Name
- && AreEqual(expected.Attributes(), actual.Attributes())
- && AreEqual(expected.Nodes(), actual.Nodes());
- }
- private static bool AreEqual(IEnumerable<XNode> expected, IEnumerable<XNode> actual)
- {
- List<XNode> filteredExpected = expected.Where(ShouldIncludeNodeDuringComparison).ToList();
- List<XNode> filteredActual = actual.Where(ShouldIncludeNodeDuringComparison).ToList();
- return filteredExpected.SequenceEqual(filteredActual, EqualityComparer);
- }
- internal static bool AreEqual(XNode expected, XNode actual)
- {
- if (expected is XText && actual is XText)
- {
- return AreEqual((XText)expected, (XText)actual);
- }
- else if (expected is XElement && actual is XElement)
- {
- return AreEqual((XElement)expected, (XElement)actual);
- }
- else
- {
- return false;
- }
- }
- private static bool AreEqual(XText expected, XText actual)
- {
- return expected.Value == actual.Value;
- }
- private static bool AreEqual(IEnumerable<XAttribute> expected, IEnumerable<XAttribute> actual)
- {
- List<XAttribute> orderedExpected = expected
- .Where(ShouldIncludeAttributeDuringComparison)
- .OrderBy(attr => attr.Name.ToString())
- .ToList();
- List<XAttribute> orderedActual = actual
- .Where(ShouldIncludeAttributeDuringComparison)
- .OrderBy(attr => attr.Name.ToString())
- .ToList();
- return orderedExpected.SequenceEqual(orderedActual, AttributeEqualityComparer);
- }
- private static bool AreEqual(XAttribute expected, XAttribute actual)
- {
- return expected.Name == actual.Name
- && expected.Value == actual.Value;
- }
- private static bool ShouldIncludeAttributeDuringComparison(XAttribute attribute)
- {
- // exclude 'xmlns' attributes since they're already considered in the
- // actual element and attribute names
- return attribute.Name != (XName)"xmlns"
- && attribute.Name.Namespace != XNamespace.Xmlns;
- }
- private static bool ShouldIncludeNodeDuringComparison(XNode node)
- {
- if (node is XComment)
- {
- return false; // not contextually relevant
- }
- if (node is XText /* includes XCData */ || node is XElement)
- {
- return true; // relevant
- }
- throw new NotSupportedException(String.Format("Node of type '{0}' is not supported.", node.GetType().Name));
- }
- }
- private sealed class CallbackBasedEqualityComparer<T> : IEqualityComparer<T>
- {
- private readonly Func<T, T, bool> _equalityCheck;
- public CallbackBasedEqualityComparer(Func<T, T, bool> equalityCheck)
- {
- _equalityCheck = equalityCheck;
- }
- public bool Equals(T x, T y)
- {
- return _equalityCheck(x, y);
- }
- public int GetHashCode(T obj)
- {
- return obj.ToString().GetHashCode();
- }
- }
- }
- }
|