360 lines
12 KiB
C#
360 lines
12 KiB
C#
// 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;
|
|
using System.Collections.Generic;
|
|
using System.Collections.ObjectModel;
|
|
using Xunit;
|
|
|
|
namespace Microsoft.Extensions.Internal
|
|
{
|
|
public class ClosedGenericMatcherTest
|
|
{
|
|
// queryType, interfaceType, expectedResult
|
|
public static TheoryData<Type, Type, Type> ExtractGenericInterfaceDataSet
|
|
{
|
|
get
|
|
{
|
|
return new TheoryData<Type, Type, Type>
|
|
{
|
|
// Closed generic types that match given open generic type.
|
|
{
|
|
typeof(IEnumerable<BaseClass>),
|
|
typeof(IEnumerable<>),
|
|
typeof(IEnumerable<BaseClass>)
|
|
},
|
|
{
|
|
typeof(IReadOnlyList<int>),
|
|
typeof(IReadOnlyList<>),
|
|
typeof(IReadOnlyList<int>)
|
|
},
|
|
{
|
|
typeof(KeyValuePair<string, object>),
|
|
typeof(KeyValuePair<,>),
|
|
typeof(KeyValuePair<string, object>)
|
|
},
|
|
// Closed generic interfaces that implement sub-interface of given open generic type.
|
|
{
|
|
typeof(ICollection<BaseClass>),
|
|
typeof(IEnumerable<>),
|
|
typeof(IEnumerable<BaseClass>)
|
|
},
|
|
{
|
|
typeof(IReadOnlyList<int>),
|
|
typeof(IEnumerable<>),
|
|
typeof(IEnumerable<int>)
|
|
},
|
|
{
|
|
typeof(IDictionary<string, object>),
|
|
typeof(IEnumerable<>),
|
|
typeof(IEnumerable<KeyValuePair<string, object>>)
|
|
},
|
|
// Class that implements closed generic based on given open generic interface.
|
|
{
|
|
typeof(BaseClass),
|
|
typeof(IDictionary<,>),
|
|
typeof(IDictionary<string, object>)
|
|
},
|
|
{
|
|
typeof(BaseClass),
|
|
typeof(IEquatable<>),
|
|
typeof(IEquatable<BaseClass>)
|
|
},
|
|
{
|
|
typeof(BaseClass),
|
|
typeof(ICollection<>),
|
|
typeof(ICollection<KeyValuePair<string, object>>)
|
|
},
|
|
// Derived class that implements closed generic based on given open generic interface.
|
|
{
|
|
typeof(DerivedClass),
|
|
typeof(IDictionary<,>),
|
|
typeof(IDictionary<string, object>)
|
|
},
|
|
{
|
|
typeof(DerivedClass),
|
|
typeof(IEquatable<>),
|
|
typeof(IEquatable<BaseClass>)
|
|
},
|
|
{
|
|
typeof(DerivedClass),
|
|
typeof(ICollection<>),
|
|
typeof(ICollection<KeyValuePair<string, object>>)
|
|
},
|
|
// Derived class that also implements another interface.
|
|
{
|
|
typeof(DerivedClassWithComparable),
|
|
typeof(IDictionary<,>),
|
|
typeof(IDictionary<string, object>)
|
|
},
|
|
{
|
|
typeof(DerivedClassWithComparable),
|
|
typeof(IEquatable<>),
|
|
typeof(IEquatable<BaseClass>)
|
|
},
|
|
{
|
|
typeof(DerivedClassWithComparable),
|
|
typeof(ICollection<>),
|
|
typeof(ICollection<KeyValuePair<string, object>>)
|
|
},
|
|
{
|
|
typeof(DerivedClassWithComparable),
|
|
typeof(IComparable<>),
|
|
typeof(IComparable<DerivedClassWithComparable>)
|
|
},
|
|
// Derived class using system implementation.
|
|
{
|
|
typeof(DerivedClassFromSystemImplementation),
|
|
typeof(ICollection<>),
|
|
typeof(ICollection<BaseClass>)
|
|
},
|
|
{
|
|
typeof(DerivedClassFromSystemImplementation),
|
|
typeof(IReadOnlyList<>),
|
|
typeof(IReadOnlyList<BaseClass>)
|
|
},
|
|
{
|
|
typeof(DerivedClassFromSystemImplementation),
|
|
typeof(IEnumerable<>),
|
|
typeof(IEnumerable<BaseClass>)
|
|
},
|
|
// Not given an open generic type.
|
|
{
|
|
typeof(IEnumerable<BaseClass>),
|
|
typeof(IEnumerable<BaseClass>),
|
|
null
|
|
},
|
|
{
|
|
typeof(IEnumerable<BaseClass>),
|
|
typeof(IEnumerable),
|
|
null
|
|
},
|
|
{
|
|
typeof(IReadOnlyList<int>),
|
|
typeof(BaseClass),
|
|
null
|
|
},
|
|
{
|
|
typeof(KeyValuePair<,>),
|
|
typeof(KeyValuePair<string, object>),
|
|
null
|
|
},
|
|
// Not a match.
|
|
{
|
|
typeof(IEnumerable<BaseClass>),
|
|
typeof(IReadOnlyList<>),
|
|
null
|
|
},
|
|
{
|
|
typeof(IList<int>),
|
|
typeof(IReadOnlyList<>),
|
|
null
|
|
},
|
|
{
|
|
typeof(IDictionary<string, object>),
|
|
typeof(KeyValuePair<,>),
|
|
null
|
|
},
|
|
};
|
|
}
|
|
}
|
|
|
|
[Theory]
|
|
[MemberData(nameof(ExtractGenericInterfaceDataSet))]
|
|
public void ExtractGenericInterface_ReturnsExpectedType(
|
|
Type queryType,
|
|
Type interfaceType,
|
|
Type expectedResult)
|
|
{
|
|
// Arrange & Act
|
|
var result = ClosedGenericMatcher.ExtractGenericInterface(queryType, interfaceType);
|
|
|
|
// Assert
|
|
Assert.Equal(expectedResult, result);
|
|
}
|
|
|
|
// IEnumerable<int> is preferred because it is defined on the more-derived type.
|
|
[Fact]
|
|
public void ExtractGenericInterface_MultipleDefinitionsInherited()
|
|
{
|
|
// Arrange
|
|
var type = typeof(TwoIEnumerableImplementationsInherited);
|
|
|
|
// Act
|
|
var result = ClosedGenericMatcher.ExtractGenericInterface(type, typeof(IEnumerable<>));
|
|
|
|
// Sort
|
|
Assert.Equal(typeof(IEnumerable<int>), result);
|
|
}
|
|
|
|
// IEnumerable<int> is preferred because we sort by Ordinal on the full name.
|
|
[Fact]
|
|
public void ExtractGenericInterface_MultipleDefinitionsOnSameType()
|
|
{
|
|
// Arrange
|
|
var type = typeof(TwoIEnumerableImplementationsOnSameClass);
|
|
|
|
// Act
|
|
var result = ClosedGenericMatcher.ExtractGenericInterface(type, typeof(IEnumerable<>));
|
|
|
|
// Sort
|
|
Assert.Equal(typeof(IEnumerable<int>), result);
|
|
}
|
|
|
|
private class TwoIEnumerableImplementationsOnSameClass : IEnumerable<string>, IEnumerable<int>
|
|
{
|
|
IEnumerator<int> IEnumerable<int>.GetEnumerator()
|
|
{
|
|
throw new NotImplementedException();
|
|
}
|
|
|
|
IEnumerator IEnumerable.GetEnumerator()
|
|
{
|
|
throw new NotImplementedException();
|
|
}
|
|
|
|
IEnumerator<string> IEnumerable<string>.GetEnumerator()
|
|
{
|
|
throw new NotImplementedException();
|
|
}
|
|
}
|
|
|
|
private class TwoIEnumerableImplementationsInherited : List<int>, IEnumerable<string>
|
|
{
|
|
IEnumerator<string> IEnumerable<string>.GetEnumerator()
|
|
{
|
|
throw new NotImplementedException();
|
|
}
|
|
|
|
IEnumerator IEnumerable.GetEnumerator()
|
|
{
|
|
throw new NotImplementedException();
|
|
}
|
|
}
|
|
|
|
private class BaseClass : IDictionary<string, object>, IEquatable<BaseClass>
|
|
{
|
|
object IDictionary<string, object>.this[string key]
|
|
{
|
|
get
|
|
{
|
|
throw new NotImplementedException();
|
|
}
|
|
|
|
set
|
|
{
|
|
throw new NotImplementedException();
|
|
}
|
|
}
|
|
|
|
int ICollection<KeyValuePair<string, object>>.Count
|
|
{
|
|
get
|
|
{
|
|
throw new NotImplementedException();
|
|
}
|
|
}
|
|
|
|
bool ICollection<KeyValuePair<string, object>>.IsReadOnly
|
|
{
|
|
get
|
|
{
|
|
throw new NotImplementedException();
|
|
}
|
|
}
|
|
|
|
ICollection<string> IDictionary<string, object>.Keys
|
|
{
|
|
get
|
|
{
|
|
throw new NotImplementedException();
|
|
}
|
|
}
|
|
|
|
ICollection<object> IDictionary<string, object>.Values
|
|
{
|
|
get
|
|
{
|
|
throw new NotImplementedException();
|
|
}
|
|
}
|
|
|
|
public bool Equals(BaseClass other)
|
|
{
|
|
throw new NotImplementedException();
|
|
}
|
|
|
|
void ICollection<KeyValuePair<string, object>>.Add(KeyValuePair<string, object> item)
|
|
{
|
|
throw new NotImplementedException();
|
|
}
|
|
|
|
void IDictionary<string, object>.Add(string key, object value)
|
|
{
|
|
throw new NotImplementedException();
|
|
}
|
|
|
|
void ICollection<KeyValuePair<string, object>>.Clear()
|
|
{
|
|
throw new NotImplementedException();
|
|
}
|
|
|
|
bool ICollection<KeyValuePair<string, object>>.Contains(KeyValuePair<string, object> item)
|
|
{
|
|
throw new NotImplementedException();
|
|
}
|
|
|
|
bool IDictionary<string, object>.ContainsKey(string key)
|
|
{
|
|
throw new NotImplementedException();
|
|
}
|
|
|
|
void ICollection<KeyValuePair<string, object>>.CopyTo(KeyValuePair<string, object>[] array, int arrayIndex)
|
|
{
|
|
throw new NotImplementedException();
|
|
}
|
|
|
|
IEnumerator IEnumerable.GetEnumerator()
|
|
{
|
|
throw new NotImplementedException();
|
|
}
|
|
|
|
IEnumerator<KeyValuePair<string, object>> IEnumerable<KeyValuePair<string, object>>.GetEnumerator()
|
|
{
|
|
throw new NotImplementedException();
|
|
}
|
|
|
|
bool ICollection<KeyValuePair<string, object>>.Remove(KeyValuePair<string, object> item)
|
|
{
|
|
throw new NotImplementedException();
|
|
}
|
|
|
|
bool IDictionary<string, object>.Remove(string key)
|
|
{
|
|
throw new NotImplementedException();
|
|
}
|
|
|
|
bool IDictionary<string, object>.TryGetValue(string key, out object value)
|
|
{
|
|
throw new NotImplementedException();
|
|
}
|
|
}
|
|
|
|
private class DerivedClass : BaseClass
|
|
{
|
|
}
|
|
|
|
private class DerivedClassWithComparable : DerivedClass, IComparable<DerivedClassWithComparable>
|
|
{
|
|
public int CompareTo(DerivedClassWithComparable other)
|
|
{
|
|
throw new NotImplementedException();
|
|
}
|
|
}
|
|
|
|
private class DerivedClassFromSystemImplementation : Collection<BaseClass>
|
|
{
|
|
}
|
|
}
|
|
} |