<PackageReference Include="NUnit" Version="4.1.0" />

UniqueItemsConstraint

UniqueItemsConstraint tests whether all the items in a collection are unique.
using NUnit.Framework.Internal; using System; using System.Collections; using System.Collections.Generic; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; namespace NUnit.Framework.Constraints { [System.Runtime.CompilerServices.NullableContext(1)] [System.Runtime.CompilerServices.Nullable(0)] public class UniqueItemsConstraint : CollectionItemsEqualConstraint { [System.Runtime.CompilerServices.NullableContext(0)] private sealed class NUnitStringEqualityComparer : IEqualityComparer<string> { private readonly bool _ignoreCase; public NUnitStringEqualityComparer(bool ignoreCase) { _ignoreCase = ignoreCase; } [System.Runtime.CompilerServices.NullableContext(2)] public bool Equals(string x, string y) { StringComparison comparisonType = _ignoreCase ? StringComparison.CurrentCultureIgnoreCase : StringComparison.Ordinal; return string.Equals(x, y, comparisonType); } [System.Runtime.CompilerServices.NullableContext(1)] public int GetHashCode(string obj) { if (obj == null) return 0; if (_ignoreCase) return StringComparer.CurrentCultureIgnoreCase.GetHashCode(obj); return obj.GetHashCode(); } } [System.Runtime.CompilerServices.Nullable(0)] internal sealed class UniqueItemsConstraintResult : ConstraintResult { internal ICollection NonUniqueItems { get; } public UniqueItemsConstraintResult(IConstraint constraint, [System.Runtime.CompilerServices.Nullable(2)] object actualValue, ICollection nonUniqueItems) : base(constraint, actualValue, nonUniqueItems.Count == 0) { NonUniqueItems = nonUniqueItems; } public override void WriteAdditionalLinesTo(MessageWriter writer) { if (base.Status == ConstraintStatus.Failure) { writer.Write(" Not unique items: "); string value = MsgUtils.FormatCollection(NonUniqueItems, 0, 10); writer.WriteLine(value); } } } private static readonly MethodInfo ItemsUniqueMethod = typeof(UniqueItemsConstraint).GetMethod("ItemsUnique", BindingFlags.Static | BindingFlags.NonPublic); private static readonly MethodInfo ItemsCastMethod = typeof(Enumerable).GetMethod("Cast", BindingFlags.Static | BindingFlags.Public); public override string Description => "all items unique"; protected override bool Matches(IEnumerable actual) { ICollection nonUniqueItems = GetNonUniqueItems(actual); return nonUniqueItems.Count == 0; } public override ConstraintResult ApplyTo<[System.Runtime.CompilerServices.Nullable(2)] TActual>(TActual actual) { IEnumerable actual2 = ConstraintUtils.RequireActual<IEnumerable>(actual, "actual", false); ICollection nonUniqueItems = GetNonUniqueItems(actual2); return new UniqueItemsConstraintResult(this, actual, nonUniqueItems); } private ICollection OriginalAlgorithm(IEnumerable actual) { List<object> list = new List<object>(); List<object> list2 = new List<object>(); foreach (object item in actual) { bool flag = true; bool flag2 = false; foreach (object item2 in list2) { if (ItemsEqual(item, item2)) { flag = false; flag2 = !list.Any((object o2) => ItemsEqual(item, o2)); break; } } if (flag) list2.Add(item); else if (flag2) { list.Add(item); if (list.Count == 10) return list; } } return list; } [return: System.Runtime.CompilerServices.Nullable(2)] private ICollection TryInferFastPath(IEnumerable actual) { List<Type> list = new List<Type>(); List<object> list2 = new List<object>(); foreach (object item in actual) { list2.Add(item); if (item != null) list.Add(item.GetType()); } if (list.Count == 0) return Array.Empty<object>(); List<Type> list3 = list.Distinct().ToList(); if (list3.Count == 1) { Type type = list3[0]; if (IsTypeSafeForFastPath(type)) { MethodInfo methodInfo = ItemsCastMethod.MakeGenericMethod(type); object[] parameters = new IEnumerable[1] { actual }; object obj = methodInfo.Invoke(null, parameters); if (base.IgnoringCase) { if (type == typeof(string)) return (ICollection)StringsUniqueIgnoringCase((IEnumerable<string>)obj); if (type == typeof(char)) return (ICollection)CharsUniqueIgnoringCase((IEnumerable<char>)obj); } return (ICollection)ItemsUniqueMethod.MakeGenericMethod(type).Invoke(null, new object[1] { obj }); } } else if (list3.All(delegate(Type o) { if (IsTypeSafeForFastPath(o)) return !IsSpecialComparisonType(o); return false; })) { return (ICollection)ItemsUnique(list2); } return null; } private static bool IsSpecialComparisonType(Type type) { if (type.IsGenericType) return type.FullName().StartsWith("System.Collections.Generic.KeyValuePair`2", StringComparison.Ordinal); if (Numerics.IsNumericType(type)) return true; if (!(type == typeof(string)) && !(type == typeof(char)) && !(type == typeof(DateTimeOffset))) return type == typeof(DictionaryEntry); return true; } private ICollection GetNonUniqueItems(IEnumerable actual) { if (base.UsingExternalComparer) return OriginalAlgorithm(actual); Type genericTypeArgument = GetGenericTypeArgument(actual); if ((object)genericTypeArgument == null) return TryInferFastPath(actual) ?? OriginalAlgorithm(actual); if (!IsTypeSafeForFastPath(genericTypeArgument)) return OriginalAlgorithm(actual); if (base.IgnoringCase) { if (genericTypeArgument == typeof(string)) return (ICollection)StringsUniqueIgnoringCase((IEnumerable<string>)actual); if (genericTypeArgument == typeof(char)) return (ICollection)CharsUniqueIgnoringCase((IEnumerable<char>)actual); } return (ICollection)ItemsUniqueMethod.MakeGenericMethod(genericTypeArgument).Invoke(null, new object[1] { actual }); } [System.Runtime.CompilerServices.NullableContext(2)] private static bool IsTypeSafeForFastPath(Type type) { if ((object)type != null && type.IsSealed) return !IsHandledSpeciallyByNUnit(type); return false; } private static ICollection<T> ItemsUnique<[System.Runtime.CompilerServices.Nullable(2)] T>(IEnumerable<T> actual) { return NonUniqueItemsInternal(actual, EqualityComparer<T>.Default); } private ICollection<string> StringsUniqueIgnoringCase(IEnumerable<string> actual) { return NonUniqueItemsInternal(actual, new NUnitStringEqualityComparer(base.IgnoringCase)); } private ICollection<char> CharsUniqueIgnoringCase(IEnumerable<char> actual) { ICollection<string> source = NonUniqueItemsInternal(from x in actual select x.ToString(), new NUnitStringEqualityComparer(base.IgnoringCase)); return (from x in source select x[0]).ToList(); } private static ICollection<T> NonUniqueItemsInternal<[System.Runtime.CompilerServices.Nullable(2)] T>(IEnumerable<T> actual, IEqualityComparer<T> comparer) { HashSet<T> hashSet = new HashSet<T>(comparer); HashSet<T> hashSet2 = new HashSet<T>(comparer); List<T> list = new List<T>(); foreach (T item in actual) { if (!hashSet.Add(item) && hashSet2.Add(item)) { list.Add(item); if (list.Count == 10) return list; } } return list; } private static bool IsHandledSpeciallyByNUnit(Type type) { if (type == typeof(string)) return false; if (!type.IsArray && !typeof(IEnumerable).IsAssignableFrom(type) && !typeof(Stream).IsAssignableFrom(type) && !typeof(DirectoryInfo).IsAssignableFrom(type) && !(type.FullName == "System.Tuple")) return type.FullName == "System.ValueTuple"; return true; } [return: System.Runtime.CompilerServices.Nullable(2)] private static Type GetGenericTypeArgument(IEnumerable actual) { Type[] interfaces = actual.GetType().GetInterfaces(); foreach (Type type in interfaces) { if (type.FullName().StartsWith("System.Collections.Generic.IEnumerable`1", StringComparison.Ordinal)) return type.GenericTypeArguments[0]; } return null; } } }