|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
// NOTE: This code is derived from an implementation originally in dotnet/runtime:
// https://github.com/dotnet/runtime/blob/v8.0.3/src/libraries/Common/tests/System/Collections/TestingTypes.cs
//
// See the commentary in https://github.com/dotnet/roslyn/pull/50156 for notes on incorporating changes made to the
// reference implementation.
#pragma warning disable CA1067 // Override Object.Equals(object) when implementing IEquatable<T>
using System;
using System.Collections;
using System.Collections.Generic;
namespace Microsoft.CodeAnalysis.UnitTests.Collections
{
#region Comparers and Equatables
// Use parity only as a hashcode so as to have many collisions.
[Serializable]
public class BadIntEqualityComparer : IEqualityComparer<int>
{
public bool Equals(int x, int y)
{
return x == y;
}
public int GetHashCode(int obj)
{
return obj % 2;
}
public override bool Equals(object? obj)
{
return obj is BadIntEqualityComparer; // Equal to all other instances of this type, not to anything else.
}
public override int GetHashCode()
{
return unchecked((int)0xC001CAFE); // Doesn't matter as long as its constant.
}
}
[Serializable]
public class EquatableBackwardsOrder : IEquatable<EquatableBackwardsOrder?>, IComparable<EquatableBackwardsOrder>, IComparable
{
private readonly int _value;
public EquatableBackwardsOrder(int value)
{
_value = value;
}
public int CompareTo(EquatableBackwardsOrder? other) //backwards from the usual integer ordering
{
if (other is null)
return -1;
return other._value - _value;
}
public override int GetHashCode() => _value;
public override bool Equals(object? obj)
{
return obj is EquatableBackwardsOrder other && Equals(other);
}
public bool Equals(EquatableBackwardsOrder? other)
{
return _value == other?._value;
}
int IComparable.CompareTo(object? obj)
{
if (obj != null && obj.GetType() == typeof(EquatableBackwardsOrder))
return ((EquatableBackwardsOrder)obj)._value - _value;
else return -1;
}
}
[Serializable]
public class Comparer_SameAsDefaultComparer : IEqualityComparer<int>, IComparer<int>
{
public int Compare(int x, int y)
{
return x - y;
}
public bool Equals(int x, int y)
{
return x == y;
}
public int GetHashCode(int obj)
{
return obj.GetHashCode();
}
}
[Serializable]
public class Comparer_HashCodeAlwaysReturnsZero : IEqualityComparer<int>, IComparer<int>
{
public int Compare(int x, int y)
{
return x - y;
}
public bool Equals(int x, int y)
{
return x == y;
}
public int GetHashCode(int obj)
{
return 0;
}
}
[Serializable]
public class Comparer_ModOfInt : IEqualityComparer<int>, IComparer<int>
{
private readonly int _mod;
public Comparer_ModOfInt(int mod)
{
_mod = mod;
}
public Comparer_ModOfInt()
{
_mod = 500;
}
public int Compare(int x, int y)
{
return ((x % _mod) - (y % _mod));
}
public bool Equals(int x, int y)
{
return ((x % _mod) == (y % _mod));
}
public int GetHashCode(int x)
{
return (x % _mod);
}
}
[Serializable]
public class Comparer_AbsOfInt : IEqualityComparer<int>, IComparer<int>
{
public int Compare(int x, int y)
{
return Math.Abs(x) - Math.Abs(y);
}
public bool Equals(int x, int y)
{
return Math.Abs(x) == Math.Abs(y);
}
public int GetHashCode(int x)
{
return Math.Abs(x);
}
}
#endregion
#region TestClasses
[Serializable]
public struct SimpleInt : IStructuralComparable, IStructuralEquatable, IComparable, IComparable<SimpleInt>
{
private int _val;
public SimpleInt(int t)
{
_val = t;
}
public int Val
{
get { return _val; }
set { _val = value; }
}
public int CompareTo(SimpleInt other)
{
return other.Val - _val;
}
public int CompareTo(object? obj)
{
if (obj?.GetType() == typeof(SimpleInt))
{
return ((SimpleInt)obj).Val - _val;
}
return -1;
}
public int CompareTo(object? other, IComparer comparer)
{
if (other?.GetType() == typeof(SimpleInt))
return ((SimpleInt)other).Val - _val;
return -1;
}
public bool Equals(object? other, IEqualityComparer comparer)
{
if (other?.GetType() == typeof(SimpleInt))
return ((SimpleInt)other).Val == _val;
return false;
}
public int GetHashCode(IEqualityComparer comparer)
{
return comparer.GetHashCode(_val);
}
}
[Serializable]
public class WrapStructural_Int : IEqualityComparer<int>, IComparer<int>
{
public int Compare(int x, int y)
{
return StructuralComparisons.StructuralComparer.Compare(x, y);
}
public bool Equals(int x, int y)
{
return StructuralComparisons.StructuralEqualityComparer.Equals(x, y);
}
public int GetHashCode(int obj)
{
return StructuralComparisons.StructuralEqualityComparer.GetHashCode(obj);
}
}
[Serializable]
public class WrapStructural_SimpleInt : IEqualityComparer<SimpleInt>, IComparer<SimpleInt>
{
public int Compare(SimpleInt x, SimpleInt y)
{
return StructuralComparisons.StructuralComparer.Compare(x, y);
}
public bool Equals(SimpleInt x, SimpleInt y)
{
return StructuralComparisons.StructuralEqualityComparer.Equals(x, y);
}
public int GetHashCode(SimpleInt obj)
{
return StructuralComparisons.StructuralEqualityComparer.GetHashCode(obj);
}
}
public class GenericComparable : IComparable<GenericComparable>
{
private readonly int _value;
public GenericComparable(int value)
{
_value = value;
}
public int CompareTo(GenericComparable? other) => _value.CompareTo(other?._value);
}
public class NonGenericComparable : IComparable
{
private readonly GenericComparable _inner;
public NonGenericComparable(int value)
{
_inner = new GenericComparable(value);
}
public int CompareTo(object? other) =>
_inner.CompareTo(((NonGenericComparable?)other)?._inner);
}
public class BadlyBehavingComparable : IComparable<BadlyBehavingComparable>, IComparable
{
public int CompareTo(BadlyBehavingComparable? other) => 1;
public int CompareTo(object? other) => -1;
}
public class MutatingComparable : IComparable<MutatingComparable>, IComparable
{
private int _state;
public MutatingComparable(int initialState)
{
_state = initialState;
}
public int State => _state;
public int CompareTo(object? other) => _state++;
public int CompareTo(MutatingComparable? other) => _state++;
}
public static class ValueComparable
{
// Convenience method so the compiler can work its type inference magic.
public static ValueComparable<T> Create<T>(T value) where T : IComparable<T>
{
return new ValueComparable<T>(value);
}
}
public readonly struct ValueComparable<T> : IComparable<ValueComparable<T>> where T : IComparable<T>
{
public ValueComparable(T value)
{
Value = value;
}
public T Value { get; }
public int CompareTo(ValueComparable<T> other) =>
Value.CompareTo(other.Value);
}
public class Equatable : IEquatable<Equatable>
{
public Equatable(int value)
{
Value = value;
}
public int Value { get; }
// Equals(object) is not implemented on purpose.
// EqualityComparer is only supposed to call through to the strongly-typed Equals since we implement IEquatable.
public bool Equals(Equatable? other)
{
return other != null && Value == other.Value;
}
public override int GetHashCode() => Value;
}
public struct NonEquatableValueType
{
public NonEquatableValueType(int value)
{
Value = value;
}
public int Value { get; set; }
}
public class DelegateEquatable : IEquatable<DelegateEquatable>
{
public DelegateEquatable()
{
EqualsWorker = _ => false;
}
public Func<DelegateEquatable?, bool> EqualsWorker { get; set; }
public bool Equals(DelegateEquatable? other) => EqualsWorker(other);
}
public struct ValueDelegateEquatable : IEquatable<ValueDelegateEquatable>
{
public Func<ValueDelegateEquatable, bool> EqualsWorker { get; set; }
public bool Equals(ValueDelegateEquatable other) => EqualsWorker(other);
}
public sealed class TrackingEqualityComparer<T> : IEqualityComparer<T>
{
public int EqualsCalls { get; set; }
public int GetHashCodeCalls { get; set; }
public bool Equals(T? x, T? y)
{
EqualsCalls++;
return EqualityComparer<T>.Default.Equals(x, y);
}
public int GetHashCode(T obj)
{
GetHashCodeCalls++;
return EqualityComparer<T>.Default.GetHashCode(obj!);
}
}
public sealed class EqualityComparerConstantHashCode<T> : IEqualityComparer<T>
{
private readonly IEqualityComparer<T> _comparer;
public EqualityComparerConstantHashCode(IEqualityComparer<T> comparer) => _comparer = comparer;
public bool Equals(T? x, T? y) => _comparer.Equals(x, y);
public int GetHashCode(T? obj) => 42;
}
#endregion
}
|