UniqueItemsConstraint
UniqueItemsConstraint tests whether all the items in a
collection are unique.
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
namespace NUnit.Framework.Constraints
{
public class UniqueItemsConstraint : CollectionItemsEqualConstraint
{
private static readonly MethodInfo ItemsUniqueMethod = typeof(UniqueItemsConstraint).GetMethod("ItemsUnique", BindingFlags.Static | BindingFlags.NonPublic);
public override string Description => "all items unique";
protected override bool Matches(IEnumerable actual)
{
return TryFastAlgorithm(actual) ?? OriginalAlgorithm(actual);
}
private bool OriginalAlgorithm(IEnumerable actual)
{
List<object> list = new List<object>();
foreach (object item in actual) {
foreach (object item2 in list) {
if (ItemsEqual(item, item2))
return false;
}
list.Add(item);
}
return true;
}
private bool? TryFastAlgorithm(IEnumerable actual)
{
if (base.UsingExternalComparer)
return null;
Type genericTypeArgument = GetGenericTypeArgument(actual);
if (genericTypeArgument == (Type)null || !IsSealed(genericTypeArgument) || IsHandledSpeciallyByNUnit(genericTypeArgument))
return null;
if (base.IgnoringCase) {
if (genericTypeArgument == typeof(string))
return StringsUniqueIgnoringCase((IEnumerable<string>)actual);
if (genericTypeArgument == typeof(char))
return CharsUniqueIgnoringCase((IEnumerable<char>)actual);
}
return (bool)ItemsUniqueMethod.MakeGenericMethod(genericTypeArgument).Invoke(null, new object[1] {
actual
});
}
private bool IsSealed(Type type)
{
return type.GetTypeInfo().IsSealed;
}
private static bool ItemsUnique<T>(IEnumerable<T> actual)
{
HashSet<T> hashSet = new HashSet<T>();
foreach (T item in actual) {
if (!hashSet.Add(item))
return false;
}
return true;
}
private static bool StringsUniqueIgnoringCase(IEnumerable<string> actual)
{
HashSet<string> hashSet = new HashSet<string>();
foreach (string item2 in actual) {
string item = item2.ToLower();
if (!hashSet.Add(item))
return false;
}
return true;
}
private static bool CharsUniqueIgnoringCase(IEnumerable<char> actual)
{
HashSet<char> hashSet = new HashSet<char>();
foreach (char item2 in actual) {
char item = char.ToLower(item2);
if (!hashSet.Add(item))
return false;
}
return true;
}
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;
}
private Type GetGenericTypeArgument(IEnumerable actual)
{
Type[] interfaces = actual.GetType().GetInterfaces();
foreach (Type type in interfaces) {
if (type.FullName.StartsWith("System.Collections.Generic.IEnumerable`1"))
return type.GenericTypeArguments[0];
}
return null;
}
}
}