Example #1
0
        /// <summary>
        /// Compares two comments using the indicated comparison options.
        /// </summary>
        /// <param name="c1">The first comment to compare.</param>
        /// <param name="c2">The second comment to compare.</param>
        /// <param name="options">The options to use in the comparison.</param>
        /// <returns>true if the comments are equal, false otherwise.</returns>
        public static bool DeepEquals(this XComment c1, XComment c2, ComparisonOptions options)
        {
            if ((c1 ?? c2) == null)
                return true;
            if ((c1 == null) || (c2 == null))
                return false; // They are not both null, so if either is, then the other isn't

            return c1.Value == c2.Value;
        }
Example #2
0
        /// <summary>
        /// Compares two texts using the indicated comparison options.
        /// </summary>
        /// <param name="t1">The first text to compare.</param>
        /// <param name="t2">The second text to compare.</param>
        /// <param name="options">The options to use in the comparison.</param>
        /// <returns>true if the texts are equal, false otherwise.</returns>
        public static bool DeepEquals(this XText t1, XText t2, ComparisonOptions options)
        {
            if ((t1 ?? t2) == null)
                return true;
            if ((t1 == null) || (t2 == null))
                return false; // They are not both null, so if either is, then the other isn't

            return ((t1.NodeType == t2.NodeType) && (t1.Value == t1.Value));
        }
Example #3
0
 internal override int GetHashCode(ComparisonOptions options)
 {
     throw new NotImplementedException();
 }
 public static IEqualityComparer <SymbolKey> GetComparer(ComparisonOptions options)
 {
     return(EnsureInitialized(ref s_cachedComparers[options.FlagsValue], options));
 }
 private SymbolKeyComparer(ComparisonOptions options)
 {
     _options = options;
 }
Example #6
0
 /// <summary>
 /// Compare two objects for value differences
 /// </summary>
 /// <param name="left">Object A</param>
 /// <param name="right">Object B</param>
 /// <param name="comparisonOptions">Specify the comparison options</param>
 /// <param name="diffOptions">Specify custom diff options</param>
 /// <returns></returns>
 public static ICollection <Difference> Diff(this object left, object right, ComparisonOptions comparisonOptions, DiffOptions diffOptions)
 {
     return(Diff(left, right, DiffProvider.DefaultMaxDepth, comparisonOptions, diffOptions));
 }
 internal override bool Equals(SymbolKey other, ComparisonOptions options)
 {
     return ReferenceEquals(this, other);
 }
Example #8
0
        /// <summary>
        /// Compares two names.
        /// </summary>
        /// <param name="n1">The first name to compare.</param>
        /// <param name="n2">The second name to compare.</param>
        /// <param name="options">The options to use in the comparison.</param>
        /// <returns>true if the elements are equal, false otherwise.</returns>
        private static bool CompareNames(XName n1, XName n2, ComparisonOptions options)
        {
            // Compare the name
            if ((n1.LocalName != n2.LocalName) || (n1.Namespace != n2.Namespace))
                return false;
            else if ((options & ComparisonOptions.NamespacePrefix) == ComparisonOptions.NamespacePrefix)
                if (n1.NamespaceName != n2.NamespaceName)
                    return false;

            return true;
        }
Example #9
0
        /// <summary>
        /// Get the differences between two objects
        /// </summary>
        /// <param name="propertyName">The name of the property being compared</param>
        /// <param name="propertyType">The type of property being compared. The left property is assumed unless allowCompareDifferentObjects=true</param>
        /// <param name="typeConverter">An optional TypeConverter to treat the type as a different type</param>
        /// <param name="left">The left object to compare</param>
        /// <param name="right">The right object to compare</param>
        /// <param name="parent">The parent object</param>
        /// <param name="differences">A list of differences currently found in the tree</param>
        /// <param name="currentDepth">The current depth of the tree recursion</param>
        /// <param name="maxDepth">The maximum number of tree children to recurse</param>
        /// <param name="objectTree">A hash table containing the tree that has already been traversed, to prevent recursion loops</param>
        /// <param name="options">Specify the comparison options</param>
        /// <param name="propertyList">A list of property names or full path names to ignore</param>
        /// <returns></returns>
        private List <Difference> GetDifferences(string propertyName, string showName, Type propertyType, TypeConverter typeConverter, object left, object right, object parent, List <Difference> differences, int currentDepth, int maxDepth, ObjectHashcodeMap objectTree, string path, ComparisonOptions options, List <string> propertyList)
        {
            if (GetPropertyInclusionState(propertyName, path, options, propertyList, null) == FilterResult.Exclude)
            {
                return(differences);
            }

            object leftValue  = null;
            object rightValue = null;

            leftValue = left;

            if (options.BitwiseHasFlag(ComparisonOptions.AllowCompareDifferentObjects) && rightValue != null)
            {
                rightValue = GetValueForProperty(right, propertyName);
            }
            else
            {
                rightValue = right;
            }

            if (rightValue == null && leftValue != null || leftValue == null && rightValue != null)
            {
                differences.Add(new Difference((leftValue ?? rightValue).GetType(), propertyName, path, leftValue, rightValue, typeConverter));
                return(differences);
            }

            if (leftValue == null && rightValue == null)
            {
                return(differences);
            }

            var propertyTypeSupport = propertyType.GetExtendedType(DefaultTypeSupportOptions);
            var isCollection        = propertyType != typeof(string) && propertyType.GetInterface(nameof(IEnumerable)) != null;

            if (isCollection && options.BitwiseHasFlag(ComparisonOptions.CompareCollections))
            {
                var genericArguments = propertyType.GetGenericArguments();
                var isArray          = propertyTypeSupport.IsArray;
                var elementType      = propertyTypeSupport.ElementType;
                // iterate the collection
                var aValueCollection      = (leftValue as IEnumerable);
                var bValueCollection      = (rightValue as IEnumerable);
                var bValueCollectionCount = GetCountFromEnumerable(bValueCollection);
                var bValueEnumerator      = bValueCollection?.GetEnumerator();
                if (aValueCollection != null)
                {
                    if (!options.BitwiseHasFlag(ComparisonOptions.AllowCollectionsToBeOutOfOrder))
                    {
                        var arrayIndex = 0;
                        // compare elements must be the same order
                        foreach (var collectionItem in aValueCollection)
                        {
                            var hasValue = bValueEnumerator?.MoveNext() ?? false;
                            leftValue = collectionItem;
                            if (hasValue)
                            {
                                rightValue = bValueEnumerator?.Current;
                                if (leftValue == null && rightValue == null)
                                {
                                    continue;
                                }
                                if (leftValue == null && rightValue != null)
                                {
                                    differences.Add(new Difference(rightValue?.GetType() ?? elementType, propertyName, showName, path, arrayIndex, leftValue, rightValue, typeConverter));
                                }
                                // check array element for difference
                                if (leftValue != null && !leftValue.GetType().IsValueType&& leftValue.GetType() != typeof(string))
                                {
                                    differences = RecurseProperties(leftValue, rightValue, parent, differences, currentDepth, maxDepth, objectTree, path, options, propertyList);
                                }
                                else if (leftValue != null && leftValue.GetType().IsGenericType&& leftValue.GetType().GetGenericTypeDefinition() == typeof(KeyValuePair <,>))
                                {
                                    // compare keys and values of a KVP
                                    var leftKvpKey    = GetValueForProperty(leftValue, "Key");
                                    var leftKvpValue  = GetValueForProperty(leftValue, "Value");
                                    var rightKvpKey   = GetValueForProperty(rightValue, "Key");
                                    var rightKvpValue = GetValueForProperty(rightValue, "Value");

                                    Type leftKeyType   = leftKvpKey?.GetType() ?? genericArguments.First();
                                    Type leftValueType = leftKvpValue?.GetType() ?? genericArguments.Skip(1).First();

                                    // compare the key
                                    if (leftKvpKey != null && !leftKeyType.IsValueType && leftKeyType != typeof(string))
                                    {
                                        differences = RecurseProperties(leftKvpKey, rightKvpKey, leftValue, differences, currentDepth, maxDepth, objectTree, path, options, propertyList);
                                    }
                                    else
                                    {
                                        if (!IsMatch(leftKvpKey, rightKvpKey))
                                        {
                                            differences.Add(new Difference(leftKeyType, propertyName, path, showName, arrayIndex, leftKvpKey, rightKvpKey, typeConverter));
                                        }
                                    }

                                    // compare the value
                                    if (leftKvpValue != null && !leftValueType.IsValueType && leftValueType != typeof(string))
                                    {
                                        differences = RecurseProperties(leftKvpValue, rightKvpValue, leftValue, differences, currentDepth, maxDepth, objectTree, path, options, propertyList);
                                    }
                                    else
                                    {
                                        if (!IsMatch(leftValue, rightValue))
                                        {
                                            differences.Add(new Difference(leftValueType, propertyName, path, showName, arrayIndex, leftKvpValue, rightKvpValue, typeConverter));
                                        }
                                    }
                                }
                                else
                                {
                                    if (!IsMatch(leftValue, rightValue))
                                    {
                                        differences.Add(new Difference(leftValue?.GetType() ?? elementType, propertyName, showName, path, arrayIndex, leftValue, rightValue, typeConverter));
                                    }
                                }
                            }
                            else
                            {
                                // left has a value in collection, right does not. That's a difference
                                rightValue = null;
                                differences.Add(new Difference(leftValue?.GetType() ?? elementType, propertyName, showName, path, arrayIndex, leftValue, rightValue, typeConverter));
                            }
                            arrayIndex++;
                        }
                        if (bValueCollectionCount > arrayIndex)
                        {
                            // right side has extra elements
                            var rightSideExtraElements = bValueCollectionCount - arrayIndex;
                            if (bValueEnumerator != null)
                            {
                                for (var i = 0; i < rightSideExtraElements; i++)
                                {
                                    var hasValue = bValueEnumerator?.MoveNext() ?? false;
                                    if (hasValue)
                                    {
                                        differences.Add(new Difference(aValueCollection.GetType(), propertyName, showName, path, arrayIndex, null, bValueEnumerator.Current, typeConverter));
                                        arrayIndex++;
                                    }
                                }
                            }
                        }
                    }
                    else
                    {
                        // compare elements can be of different order (use the hashcode for this)
                        var leftHashCodeEntryList  = new Dictionary <int, CollectionKey>(); // hashcode, value/count
                        var rightHashCodeEntryList = new Dictionary <int, CollectionKey>(); // hashcode, value/count
                        var arrayIndex             = 0;
                        foreach (var collectionItem in aValueCollection)
                        {
                            var hashCode = collectionItem.GetHashCode();
                            if (leftHashCodeEntryList.ContainsKey(hashCode))
                            {
                                var val = leftHashCodeEntryList[hashCode];
                                val.Matches++;
                                val.OriginalIndex = arrayIndex; // populate the highest value
                            }
                            else
                            {
                                leftHashCodeEntryList.Add(hashCode, new CollectionKey(arrayIndex, collectionItem, 1));
                            }
                            arrayIndex++;
                        }
                        arrayIndex = 0;
                        foreach (var collectionItem in bValueCollection)
                        {
                            var hashCode = collectionItem.GetHashCode();
                            if (rightHashCodeEntryList.ContainsKey(hashCode))
                            {
                                var val = rightHashCodeEntryList[hashCode];
                                val.Matches++;
                                val.OriginalIndex = arrayIndex; // populate the highest value
                            }
                            else
                            {
                                rightHashCodeEntryList.Add(hashCode, new CollectionKey(arrayIndex, collectionItem, 1));
                            }
                            arrayIndex++;
                        }
                        var orderedLeft  = leftHashCodeEntryList.OrderBy(x => x.Key);
                        var orderedRight = rightHashCodeEntryList.OrderBy(x => x.Key);
                        // compare the left collection
                        foreach (var item in orderedLeft)
                        {
                            var matchFound = orderedRight.Where(x => x.Key == item.Key).Select(x => x.Value).FirstOrDefault();
                            if (matchFound == null)
                            {
                                differences.Add(new Difference((leftValue ?? rightValue).GetType(), propertyName, showName, path, item.Value.OriginalIndex, item.Value.Value, null, typeConverter));
                            }
                            else
                            {
                                var isEqual = CompareForObjectEquality(item.Value.Value.GetExtendedType(DefaultTypeSupportOptions), item.Value.Value, matchFound.Value);
                                if (!isEqual)
                                {
                                    differences.Add(new Difference((leftValue ?? rightValue).GetType(), propertyName, showName, path, item.Value.OriginalIndex, item.Value.Value, null, typeConverter));
                                }
                                else if (matchFound.Matches != item.Value.Matches && item.Value.Matches > matchFound.Matches)
                                {
                                    // also compare that the number of instances of the value in a collection are the same
                                    differences.Add(new Difference((leftValue ?? rightValue).GetType(), propertyName, showName, path, item.Value.OriginalIndex, item.Value.Value, null, typeConverter));
                                }
                            }
                        }
                        // compare the right collection
                        foreach (var item in orderedRight)
                        {
                            var matchFound = orderedLeft.Where(x => x.Key == item.Key).Select(x => x.Value).FirstOrDefault();
                            if (matchFound == null)
                            {
                                differences.Add(new Difference((leftValue ?? rightValue).GetType(), propertyName, showName, path, item.Value.OriginalIndex, null, item.Value.Value, typeConverter));
                            }
                            else
                            {
                                var isEqual = CompareForObjectEquality(item.Value.Value.GetExtendedType(DefaultTypeSupportOptions), item.Value.Value, matchFound.Value);
                                if (!isEqual)
                                {
                                    differences.Add(new Difference((leftValue ?? rightValue).GetType(), propertyName, showName, path, item.Value.OriginalIndex, null, item.Value.Value, typeConverter));
                                }
                                else if (matchFound.Matches != item.Value.Matches && item.Value.Matches > matchFound.Matches)
                                {
                                    // also compare that the number of instances of the value in a collection are the same
                                    differences.Add(new Difference((leftValue ?? rightValue).GetType(), propertyName, showName, path, item.Value.OriginalIndex, null, item.Value.Value, typeConverter));
                                }
                            }
                        }
                    }
                }
            }
            else if (!propertyType.IsValueType && propertyType != typeof(string))
            {
                differences = RecurseProperties(leftValue, rightValue, leftValue, differences, currentDepth, maxDepth, objectTree, path, options, propertyList);
            }
            else
            {
                if (!IsMatch(leftValue, rightValue))
                {
                    differences.Add(new Difference(propertyType, propertyName, showName, path, leftValue, rightValue, typeConverter));
                }
            }

            return(differences);
        }
Example #10
0
        /// <summary>
        /// Recurse the object's tree
        /// </summary>
        /// <param name="left">The left object to compare</param>
        /// <param name="right">The right object to compare</param>
        /// <param name="parent">The parent object</param>
        /// <param name="differences">A list of differences currently found in the tree</param>
        /// <param name="currentDepth">The current depth of the tree recursion</param>
        /// <param name="maxDepth">The maximum number of tree children to recurse</param>
        /// <param name="objectTree">A hash table containing the tree that has already been traversed, to prevent recursion loops</param>
        /// <param name="options">Specify the comparison options</param>
        /// <param name="propertyList">A list of property names or full path names to ignore</param>
        /// <returns></returns>
        private List <Difference> RecurseProperties(object left, object right, object parent, List <Difference> differences, int currentDepth, int maxDepth, ObjectHashcodeMap objectTree, string path, ComparisonOptions options, List <string> propertyList)
        {
            if (GetPropertyInclusionState(null, path, options, propertyList, null) == FilterResult.Exclude)
            {
                return(differences);
            }

            if (!options.BitwiseHasFlag(ComparisonOptions.AllowCompareDifferentObjects) &&
                left != null && right != null &&
                left?.GetType() != right?.GetType())
            {
                throw new ArgumentException("Objects Left and Right must be of the same type.");
            }

            if (left == null && right == null)
            {
                return(differences);
            }

            if (maxDepth > 0 && currentDepth >= maxDepth)
            {
                return(differences);
            }

            var typeSupport = new ExtendedType(left != null ? left.GetType() : right.GetType(), DefaultTypeSupportOptions);

            if (typeSupport.Attributes.Any(x => _ignoreAttributes.Contains(x)))
            {
                return(differences);
            }
            if (typeSupport.IsDelegate)
            {
                return(differences);
            }

            if (options.BitwiseHasFlag(ComparisonOptions.AllowEqualsOverride))
            {
                var objectEquality = CompareForObjectEquality(typeSupport, left, right);
                if (objectEquality)
                {
                    return(differences); // no differences found, no need to continue
                }
            }

            // increment the current recursion depth
            currentDepth++;

            // construct a hashtable of objects we have already inspected (simple recursion loop preventer)
            // we use this hashcode method as it does not use any custom hashcode handlers the object might implement
            if (left != null)
            {
                if (objectTree.Contains(left))
                {
                    return(differences);
                }
                objectTree.Add(left);
            }

            // get list of properties
            var properties = new List <ExtendedProperty>();

            if (options.BitwiseHasFlag(ComparisonOptions.CompareProperties))
            {
                var pis = left.GetProperties(PropertyOptions.All);
                foreach (var pi in pis)
                {
                    if (pi.PropertyInfo.CanWrite == false || pi.PropertyInfo.CanRead == false)
                    {
                        continue;
                    }

                    var atts   = pi.PropertyInfo.GetCustomAttributes(true);
                    var canAdd = true;
                    foreach (var att in atts)
                    {
                        var name = att.GetType().Name.ToLower();
                        if (name.Contains("ignore") || name.Contains("result"))
                        {
                            canAdd = false;
                            break;
                        }
                    }
                    if (canAdd)
                    {
                        properties.Add(pi);
                    }
                }
            }

            // get all fields, except for backed auto-property fields
            var fields = new List <ExtendedField>();

            if (options.BitwiseHasFlag(ComparisonOptions.CompareFields))
            {
                var fis = left.GetFields(FieldOptions.All);
                foreach (var fi in fis)
                {
                    if (fi.IsBackingField)
                    {
                        continue;
                    }

                    var atts   = fi.FieldInfo.GetCustomAttributes(true);
                    var canAdd = true;
                    foreach (var att in atts)
                    {
                        var name = att.GetType().Name.ToLower();
                        if (name.Contains("ignore") || name.Contains("result") || name.Contains("nonserialized"))
                        {
                            canAdd = false;
                            break;
                        }
                    }
                    if (canAdd)
                    {
                        fields.Add(fi);
                    }
                }
            }

            var rootPath  = path;
            var localPath = string.Empty;

            foreach (var property in properties)
            {
                localPath = $"{rootPath}.{property.Name}";
                if (GetPropertyInclusionState(property.Name, localPath, options, propertyList, property.CustomAttributes) == FilterResult.Exclude)
                {
                    continue;
                }
                object leftValue = null;
                try {
                    if (left != null)
                    {
                        leftValue = left.GetPropertyValue(property);
                    }
                } catch (Exception) {
                    // catch any exceptions accessing the property
                }
                object rightValue = null;
                try {
                    if (right != null)
                    {
                        rightValue = right.GetPropertyValue(property);
                    }
                } catch (Exception) {
                    // catch any exceptions accessing the property
                }
                var showName = property.Name;
                var attr     = property.PropertyInfo.GetCustomAttribute <DisplayNameAttribute>(true);
                if (attr != null)
                {
                    showName = attr.DisplayName;
                }

                differences = GetDifferences(property.Name, showName, property.Type, GetTypeConverter(property), leftValue, rightValue, parent, differences, currentDepth, maxDepth, objectTree, localPath, options, propertyList);
            }
            foreach (var field in fields)
            {
                localPath = $"{rootPath}.{field.Name}";
                if (GetPropertyInclusionState(field.Name, localPath, options, propertyList, field.CustomAttributes) == FilterResult.Exclude)
                {
                    continue;
                }
                object leftValue = null;
                if (left != null)
                {
                    leftValue = left.GetFieldValue(field);
                }
                object rightValue = null;
                if (right != null)
                {
                    rightValue = right.GetFieldValue(field);
                }
                var showName = field.Name;
                var attr     = field.FieldInfo.GetCustomAttribute <DisplayNameAttribute>(true);
                if (attr != null)
                {
                    showName = attr.DisplayName;
                }
                differences = GetDifferences(field.Name, showName, field.Type, GetTypeConverter(field), leftValue, rightValue, parent, differences, currentDepth, maxDepth, objectTree, localPath, options, propertyList);
            }

            return(differences);
        }
Example #11
0
 /// <summary>
 /// Compare two objects for value differences
 /// </summary>
 /// <param name="left"></param>
 /// <param name="right"></param>
 /// <param name="maxDepth"></param>
 /// <param name="options">Specify the comparison options</param>
 /// <param name="propertyList">A list of property names or full path names to ignore</param>
 /// <returns></returns>
 public List <Difference> ComputeDiff(object left, object right, int maxDepth, ComparisonOptions options, params string[] propertyList)
 {
     return(RecurseProperties(left, right, null, new List <Difference>(), 0, maxDepth, new ObjectHashcodeMap(), string.Empty, options, propertyList.ToList()));
 }
 /// <summary>
 /// Initializes a new instance of the <see cref="PostChangesRequest"/> class.
 /// </summary>
 /// <param name="comparisonOptions">Comparison options</param>
 public PostChangesRequest(ComparisonOptions comparisonOptions)
 {
     this.comparisonOptions = comparisonOptions;
 }
 /// <summary>
 /// Initializes a new instance of the <see cref="ComparisonsRequest"/> class.
 /// </summary>
 /// <param name="comparisonOptions">Comparison options</param>
 public ComparisonsRequest(ComparisonOptions comparisonOptions)
 {
     this.comparisonOptions = comparisonOptions;
 }
Example #14
0
 internal abstract int GetHashCode(ComparisonOptions options);
Example #15
0
 /// <summary>
 /// <para>
 /// When comparing symbols we need to handle recursion between method type parameters and
 /// methods.  For example, if we have two methods with the signature <c><![CDATA[Foo<T>(T t)]]></c> and we
 /// try to test for equality we must avoid the situation where we:
 /// <list type="number">
 ///   <item>First test if the methods are the same, which will in turn</item>
 ///   <item>test if the method's parameter types are the same, which will in turn</item>
 ///   <item>test if the type parameters are the same, which will in turn</item>
 ///   <item>test if the methods are the same, which causes infinite recursion.</item>
 /// </list>
 /// To avoid this we distinguish the cases where we're testing if two type parameters
 /// actually refer to the same thing, versus type parameters being referenced by parameters.
 /// For example, if we have:
 /// <code><![CDATA[
 /// Foo<T>(T t)
 /// Bar<T>(T t)
 /// ]]></code>
 /// then clearly the type parameter <c>T</c> in <c><![CDATA[Foo<T>]]></c> is different from the type parameter <c>T</c>
 /// in <c><![CDATA[Bar<T>]]></c>. When testing these type parameters for equality we *will* test to see
 /// if they have the same parent. This will end up returning false, and so we will consider
 /// them different.
 /// </para>
 /// <para>
 /// However, when we are testing if two signatures are the same, if we hit a method type
 /// parameter then we only need to compare by metadataName.  That's because we know we'll
 /// already have checked if the method and it's parents are the same, so we don't need to
 /// recurse through them again.
 /// </para>
 /// </summary>
 internal abstract bool Equals(SymbolKey other, ComparisonOptions options);
Example #16
0
        /// <summary>
        /// Compares two documents using the indicated comparison options.
        /// </summary>
        /// <param name="d1">The first document to compare.</param>
        /// <param name="d2">The second document to compare.</param>
        /// <param name="options">The options to use in the comparison.</param>
        /// <returns>true if the documents are equal, false otherwise.</returns>
        public static bool DeepEquals(this XDocument d1, XDocument d2, ComparisonOptions options)
        {
            if ((d1 ?? d2) == null)
                return true;
            if ((d1 == null) || (d2 == null))
                return false; // They are not both null, so if either is, then the other isn't

            return DeepEquals(d1.Root, d2.Root, options);
        }
Example #17
0
        /// <summary>
        /// Compares two nodes using the indicated comparison options.
        /// </summary>
        /// <param name="n1">The first node to compare.</param>
        /// <param name="n2">The second node to compare.</param>
        /// <param name="options">The options to use in the comparison.</param>
        /// <returns>true if the nodes are equal, false otherwise.</returns>
        public static bool DeepEquals(this XNode n1, XNode n2, ComparisonOptions options)
        {
            if ((n1 ?? n2) == null)
                return true;
            if ((n1 == null) || (n2 == null))
                return false; // They are not both null, so if either is, then the other isn't

            if ((n1 is XElement) && (n2 is XElement))
                return DeepEquals((XElement)n1, (XElement)n2, options);
            else if ((n1 is XComment) && (n2 is XComment))
                return DeepEquals((XComment)n1, (XComment)n2, options);
            else if ((n1 is XText) && (n2 is XText))
                return DeepEquals((XText)n1, (XText)n2, options);
            else if ((n1 is XProcessingInstruction) && (n2 is XProcessingInstruction))
                return DeepEquals((XProcessingInstruction)n1, (XProcessingInstruction)n2, options);
            else if (!(n1.GetType().IsAssignableFrom(n2.GetType()) || n2.GetType().IsAssignableFrom(n1.GetType())))
                return false;
            else
                throw new NotImplementedException();
        }
Example #18
0
 /// <summary>
 /// Compare two objects for value differences
 /// </summary>
 /// <param name="left">Object A</param>
 /// <param name="right">Object B</param>
 /// <param name="options">Specify the comparison options</param>
 /// <returns></returns>
 public List <Difference> ComputeDiff(object left, object right, ComparisonOptions options)
 {
     return(ComputeDiff(left, right, DefaultMaxDepth, options));
 }
Example #19
0
 /// <summary>
 /// Compare two objects for value differences
 /// </summary>
 /// <param name="left">Object A</param>
 /// <param name="right">Object B</param>
 /// <param name="options">Specify the comparison options</param>
 /// <param name="propertyList">A list of property names or full path names to ignore</param>
 /// <returns></returns>
 public List <Difference> ComputeDiff(object left, object right, ComparisonOptions options, params string[] propertyList)
 {
     return(ComputeDiff(left, right, DefaultMaxDepth, options, propertyList));
 }
Example #20
0
 /// <summary>
 /// Compare two objects for value differences
 /// </summary>
 /// <typeparam name="T"></typeparam>
 /// <param name="left"></param>
 /// <param name="right"></param>
 /// <param name="options">Specify the comparison options</param>
 /// <param name="propertyList"></param>
 /// <returns></returns>
 public List <Difference> ComputeDiff <T>(T left, T right, ComparisonOptions options, params Expression <Func <T, object> >[] propertyList)
 {
     return(ComputeDiff(left, right, DefaultMaxDepth, options, propertyList));
 }
Example #21
0
 private static bool ShouldCompareReferences(PropertyInfo property, string propertyNamespace, ComparisonOptions settings)
 {
     return(settings.PropertiesToCompareByReference.NullSafe().Any(r => propertyNamespace + property.Name == r));
 }
Example #22
0
 internal override bool Equals(MethodTypeParameterSymbol other, ComparisonOptions options)
 {
     return(Equals(options.IgnoreCase, other._metadataName, _metadataName) &&
            (options.CompareMethodTypeParametersByName || other._containerKey.Equals(_containerKey, options)));
 }
Example #23
0
 /// <summary>
 /// Compare two objects for value differences
 /// </summary>
 /// <param name="left">Object A</param>
 /// <param name="right">Object B</param>
 /// <param name="comparisonOptions">Specify the comparison options</param>
 /// <param name="diffOptions">Specify custom diff options</param>
 /// <param name="propertiesToExcludeOrInclude">A list of property names or full path names to include/exclude. Default is <seealso cref="ComparisonOptions.ExcludeList"/>. Specify <seealso cref="ComparisonOptions.ExcludeList"/> to exclude the specified properties from the Diff or <seealso cref="ComparisonOptions.IncludeList"/> to only Diff properties contained in the list.</param>
 /// <returns></returns>
 public static ICollection <Difference> Diff(this object left, object right, ComparisonOptions comparisonOptions, DiffOptions diffOptions, params string[] propertiesToExcludeOrInclude)
 {
     return(Diff(left, right, DiffProvider.DefaultMaxDepth, comparisonOptions, diffOptions, propertiesToExcludeOrInclude));
 }
Example #24
0
 internal override bool Equals(FieldSymbolKey other, ComparisonOptions options)
 {
     return
         (Equals(options.IgnoreCase, other._metadataName, _metadataName) &&
          other._containerKey.Equals(_containerKey, options));
 }
 private static SymbolKeyComparer EnsureInitialized(ref SymbolKeyComparer location, ComparisonOptions options)
 {
     // This doesn't need to be interlocked since comparers store no state
     return(location ?? (location = new SymbolKeyComparer(options)));
 }
 internal override bool Equals(AssemblySymbolKey other, ComparisonOptions options)
 {
     // isCaseSensitive doesn't apply here as AssemblyIdentity is always case
     // insensitive.
     return(options.IgnoreAssemblyKey || other.assemblyName == this.assemblyName);
 }
Example #27
0
 internal override bool Equals(NonDeclarationSymbolKey <TSymbol> other, ComparisonOptions options)
 {
     throw new NotImplementedException();
 }
 internal override int GetHashCode(ComparisonOptions options)
 {
     // isCaseSensitive doesn't apply here as AssemblyIdentity is always case
     // insensitive.
     return(options.IgnoreAssemblyKey ? 1 : this.assemblyName.GetHashCode());
 }
 internal override bool Equals(TypeParameterSymbolKey other, ComparisonOptions options)
 {
     return
         Equals(options.IgnoreCase, other.metadataName, this.metadataName) &&
         other.containerKey.Equals(this.containerKey, options);
 }
 internal override bool Equals(SymbolKey other, ComparisonOptions options)
 {
     return(ReferenceEquals(this, other));
 }
Example #31
0
        /// <summary>
        /// Compares two elements using the indicated comparison options.
        /// </summary>
        /// <param name="e1">The first element to compare.</param>
        /// <param name="e2">The second element to compare.</param>
        /// <param name="options">The options to use in the comparison.</param>
        /// <returns>true if the elements are equal, false otherwise.</returns>
        public static bool DeepEquals(this XElement e1, XElement e2, ComparisonOptions options)
        {
            if ((e1 ?? e2) == null)
                return true;
            if ((e1 == null) || (e2 == null))
                return false; // They are not both null, so if either is, then the other isn't

            // Compare the name
            if (!CompareNames(e1.Name, e2.Name, options))
                return false;

            // Performance tweak: compare attributes first, because they will often be faster to find a difference
            return AttributesEqual(e1, e2, options) && ContentsEqual(e1, e2, options);
        }
 internal override int GetHashCode(ComparisonOptions options)
 {
     return(RuntimeHelpers.GetHashCode(this));
 }
Example #33
0
        /// <summary>
        /// Compares two attributes using the indicated comparison options.
        /// </summary>
        /// <param name="a1">The first attribute to compare.</param>
        /// <param name="a2">The second attribute to compare.</param>
        /// <param name="options">The options to use in the comparison.</param>
        /// <returns>true if the attributes are equal, false otherwise.</returns>
        public static bool DeepEquals(this XAttribute a1, XAttribute a2, ComparisonOptions options)
        {
            if ((a1 ?? a2) == null)
                return true;
            if ((a1 == null) || (a2 == null))
                return false; // They are not both null, so if either is, then the other isn't

            // Compare the name
            if (!CompareNames(a1.Name, a2.Name, options))
                return false;

            return a1.Value == a2.Value;
        }
 internal override int GetHashCode(ComparisonOptions options)
 {
     return(Hash.Combine(
                GetHashCode(options.IgnoreCase, this.metadataName),
                this.containerKey.GetHashCode(options)));
 }
Example #35
0
        /// <summary>
        /// Checks if two elements have equal attributes.
        /// </summary>
        /// <param name="e1">The first element to compare.</param>
        /// <param name="e2">The second element to compare.</param>
        /// <param name="options">The options to use in the comparison.</param>
        /// <returns>true if the element attributes are equal, false otherwise.</returns>
        private static bool AttributesEqual(XElement e1, XElement e2, ComparisonOptions options)
        {
            // They must both have or not have attributes, and if they don't we're good and can exit early
            if (e1.HasAttributes != e2.HasAttributes)
                return false;
            if (!e1.HasAttributes)
                return true;

            var attributes1 = e1.Attributes();
            var attributes2 = e2.Attributes();

            // We will ignore attribute ordering
            if ((options & ComparisonOptions.AttributeOrdering) != ComparisonOptions.AttributeOrdering) {
                attributes1 = attributes1.OrderBy(x => x.Name.Namespace.NamespaceName + x.Name.LocalName);
                attributes2 = attributes2.OrderBy(x => x.Name.Namespace.NamespaceName + x.Name.LocalName);
            }

            var enum1 = attributes1.GetEnumerator();
            var enum2 = attributes2.GetEnumerator();
            var next1 = enum1.MoveNext();
            var next2 = enum2.MoveNext();

            while (next1 && next2) {
                if (enum1.Current.IsNamespaceDeclaration != enum2.Current.IsNamespaceDeclaration)
                    return false;
                if (!enum1.Current.IsNamespaceDeclaration || ((options & ComparisonOptions.NamespacePrefix) == ComparisonOptions.NamespacePrefix))
                    if (!DeepEquals(enum1.Current, enum2.Current, options))
                        return false;

                next1 = enum1.MoveNext();
                next2 = enum2.MoveNext();
            }

            // They have the same number of elements if these are equal
            return next1 == next2;
        }
Example #36
0
 /// <summary>
 /// Compare two objects for value differences
 /// </summary>
 /// <typeparam name="T"></typeparam>
 /// <param name="left">Object A</param>
 /// <param name="right">Object B</param>
 /// <param name="comparisonOptions">Specify the comparison options</param>
 /// <param name="diffOptions">Specify custom diff options</param>
 /// <param name="propertiesToExcludeOrInclude">A list of property names or full path names to include/exclude. Default is <seealso cref="ComparisonOptions.ExcludeList"/>. Specify <seealso cref="ComparisonOptions.ExcludeList"/> to exclude the specified properties from the Diff or <seealso cref="ComparisonOptions.IncludeList"/> to only Diff properties contained in the list.</param>
 /// <returns></returns>
 public static ICollection <Difference> Diff <T>(this T left, T right, ComparisonOptions comparisonOptions, DiffOptions diffOptions, params Expression <Func <T, object> >[] propertiesToExcludeOrInclude)
 {
     return(Diff(left, right, DiffProvider.DefaultMaxDepth, comparisonOptions, diffOptions, propertiesToExcludeOrInclude));
 }
Example #37
0
        /// <summary>
        /// Checks if two elements have equal content.
        /// </summary>
        /// <param name="e1">The first element to compare.</param>
        /// <param name="e2">The second element to compare.</param>
        /// <param name="options">The options to use in the comparison.</param>
        /// <returns>true if the element contents are equal, false otherwise.</returns>
        private static bool ContentsEqual(XElement e1, XElement e2, ComparisonOptions options)
        {
            if (e1.Value != e2.Value)
                return false;
            if ((e1.IsEmpty != e2.IsEmpty) && ((options & ComparisonOptions.EmptyTagStyle) == ComparisonOptions.EmptyTagStyle))
                return false;
            if (e1.IsEmpty && e2.IsEmpty)
                return true;

            var nodes1 = e1.Nodes();
            var nodes2 = e2.Nodes();

            // Exclude comments and notations
            if ((options & ComparisonOptions.CommentsAndNotations) != ComparisonOptions.CommentsAndNotations) {
                nodes1 = nodes1.Where(x => x.NodeType != XmlNodeType.Comment && x.NodeType != XmlNodeType.Notation);
                nodes2 = nodes2.Where(x => x.NodeType != XmlNodeType.Comment && x.NodeType != XmlNodeType.Notation);
            }

            // Order the nodes if required
            if ((options & ComparisonOptions.ElementOrdering) != ComparisonOptions.ElementOrdering) {
                nodes1 = nodes1.OrderBy(x => x.ToString());
                nodes2 = nodes2.OrderBy(x => x.ToString());
            }

            var enum1 = nodes1.GetEnumerator();
            var enum2 = nodes2.GetEnumerator();
            var next1 = enum1.MoveNext();
            var next2 = enum2.MoveNext();

            while (next1 && next2) {
                if (!DeepEquals(enum1.Current, enum2.Current, options))
                    return false;

                next1 = enum1.MoveNext();
                next2 = enum2.MoveNext();
            }

            // They have the same number of elements if these are equal
            return next1 == next2;
        }
Example #38
0
        /// <summary>
        /// Compare two objects for value differences
        /// </summary>
        /// <param name="left">Object A</param>
        /// <param name="right">Object B</param>
        /// <param name="maxDepth">Maximum recursion depth</param>
        /// <param name="comparisonOptions">Specify the comparison options</param>
        /// <param name="diffOptions">Specify custom diff options</param>
        /// <param name="propertiesToExcludeOrInclude">A list of property names or full path names to include/exclude. Default is <seealso cref="ComparisonOptions.ExcludeList"/>. Specify <seealso cref="ComparisonOptions.ExcludeList"/> to exclude the specified properties from the Diff or <seealso cref="ComparisonOptions.IncludeList"/> to only Diff properties contained in the list.</param>
        /// <returns></returns>
        public static ICollection <Difference> Diff(this object left, object right, int maxDepth, ComparisonOptions comparisonOptions, DiffOptions diffOptions, params string[] propertiesToExcludeOrInclude)
        {
            var diffProvider = new DiffProvider();

            return(diffProvider.ComputeDiff(left, right, maxDepth, comparisonOptions, diffOptions, propertiesToExcludeOrInclude));
        }
Example #39
0
        /// <summary>
        /// Compares two processing instructions using the indicated comparison options.
        /// </summary>
        /// <param name="p1">The first processing instruction to compare.</param>
        /// <param name="p2">The second processing instruction to compare.</param>
        /// <param name="options">The options to use in the comparison.</param>
        /// <returns>true if the processing instructions are equal, false otherwise.</returns>
        public static bool DeepEquals(this XProcessingInstruction p1, XProcessingInstruction p2, ComparisonOptions options)
        {
            if ((p1 ?? p2) == null)
                return true;
            if ((p1 == null) || (p2 == null))
                return false; // They are not both null, so if either is, then the other isn't

            return ((p1.Target == p2.Target) && (p1.Data == p1.Data));
        }
Example #40
0
        /// <summary>
        /// Compare two objects for value differences
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="left">Object A</param>
        /// <param name="right">Object B</param>
        /// <param name="maxDepth">Maximum recursion depth</param>
        /// <param name="comparisonOptions">Specify the comparison options</param>
        /// <param name="diffOptions">Specify custom diff options</param>
        /// <param name="propertiesToExcludeOrInclude">A list of property names or full path names to include/exclude. Default is <seealso cref="ComparisonOptions.ExcludeList"/>. Specify <seealso cref="ComparisonOptions.ExcludeList"/> to exclude the specified properties from the Diff or <seealso cref="ComparisonOptions.IncludeList"/> to only Diff properties contained in the list.</param>
        /// <returns></returns>
        public static ICollection <Difference> Diff <T>(this T left, T right, int maxDepth, ComparisonOptions comparisonOptions, DiffOptions diffOptions, params Expression <Func <T, object> >[] propertiesToExcludeOrInclude)
        {
            var diffProvider = new DiffProvider();

            return(diffProvider.ComputeDiff(left, right, maxDepth, comparisonOptions, diffOptions, propertiesToExcludeOrInclude));
        }
 internal override int GetHashCode(ComparisonOptions options)
 {
     return RuntimeHelpers.GetHashCode(this);
 }
Example #42
0
        // ReSharper restore CompareNonConstrainedGenericWithNull

        private static FilteredProperties FilterProperties(IEnumerable <PropertyInfo> properties, string propertyNamespace, ComparisonOptions settings)
        {
            var namespaceWithoutIndexes = _collectionIndexPattern.Replace(propertyNamespace, "[]");

            if (settings.ComparisonType == ComparisonType.Inclusive)
            {
                var toIgnore        = settings.PropertiesToIgnore.NullSafe().ToList();
                var splitProperties = properties.ToLookup(p => toIgnore.Contains(namespaceWithoutIndexes + p.Name));

                return(new FilteredProperties
                {
                    PropertiesToCompare = splitProperties[false].NullSafe().ToList(),
                    IgnoredPropertyNames = splitProperties[true].NullSafe().Select(p => propertyNamespace + p.Name).ToList()
                });
            }
            else
            {
                var toInclude       = settings.PropertiesToCompare.NullSafe().ToList();
                var splitProperties = properties.ToLookup(p => toInclude.Any(i => i.NullSafe().StartsWith(namespaceWithoutIndexes + p.Name)));

                return(new FilteredProperties
                {
                    PropertiesToCompare = splitProperties[true].NullSafe().ToList(),
                    IgnoredPropertyNames = splitProperties[false].NullSafe().Select(p => propertyNamespace + p.Name).ToList()
                });
            }
        }