Change ITypeInfo.IsTagHelper to ITypeInfo.ImplementsInterface(ITypeInfo)
Fixes #511
This commit is contained in:
parent
d2a7a355cc
commit
e87f10e8f8
|
|
@ -18,13 +18,8 @@ namespace Microsoft.AspNet.Razor.Runtime.Precompilation
|
||||||
[DebuggerDisplay("{Name}")]
|
[DebuggerDisplay("{Name}")]
|
||||||
public class CodeAnalysisSymbolBasedTypeInfo : ITypeInfo
|
public class CodeAnalysisSymbolBasedTypeInfo : ITypeInfo
|
||||||
{
|
{
|
||||||
/// <summary>
|
private static readonly System.Reflection.TypeInfo OpenGenericDictionaryTypeInfo =
|
||||||
/// The <see cref="System.Reflection.TypeInfo"/> for <see cref="IDictionary{TKey, TValue}"/>.
|
|
||||||
/// </summary>
|
|
||||||
public static readonly System.Reflection.TypeInfo OpenGenericDictionaryTypeInfo =
|
|
||||||
typeof(IDictionary<,>).GetTypeInfo();
|
typeof(IDictionary<,>).GetTypeInfo();
|
||||||
private static readonly System.Reflection.TypeInfo TagHelperTypeInfo =
|
|
||||||
typeof(ITagHelper).GetTypeInfo();
|
|
||||||
private readonly ITypeSymbol _type;
|
private readonly ITypeSymbol _type;
|
||||||
private readonly ITypeSymbol _underlyingType;
|
private readonly ITypeSymbol _underlyingType;
|
||||||
private string _fullName;
|
private string _fullName;
|
||||||
|
|
@ -120,13 +115,33 @@ namespace Microsoft.AspNet.Razor.Runtime.Precompilation
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public bool IsTagHelper
|
public bool ImplementsInterface(ITypeInfo interfaceTypeInfo)
|
||||||
{
|
{
|
||||||
get
|
if (interfaceTypeInfo == null)
|
||||||
{
|
{
|
||||||
return _type.AllInterfaces.Any(
|
throw new ArgumentNullException(nameof(interfaceTypeInfo));
|
||||||
implementedInterface => IsType(implementedInterface, TagHelperTypeInfo));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var runtimeTypeInfo = interfaceTypeInfo as RuntimeTypeInfo;
|
||||||
|
if (runtimeTypeInfo != null)
|
||||||
|
{
|
||||||
|
return runtimeTypeInfo.TypeInfo.IsInterface &&
|
||||||
|
_type.AllInterfaces.Any(implementedInterface => IsType(implementedInterface, runtimeTypeInfo.TypeInfo));
|
||||||
|
}
|
||||||
|
|
||||||
|
var codeAnalysisTypeInfo = interfaceTypeInfo as CodeAnalysisSymbolBasedTypeInfo;
|
||||||
|
if (codeAnalysisTypeInfo != null)
|
||||||
|
{
|
||||||
|
return codeAnalysisTypeInfo.TypeSymbol.TypeKind == TypeKind.Interface &&
|
||||||
|
_type.AllInterfaces.Any(
|
||||||
|
implementedInterface => implementedInterface == codeAnalysisTypeInfo.TypeSymbol);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new ArgumentException(
|
||||||
|
Resources.FormatArgumentMustBeAnInstanceOf(
|
||||||
|
typeof(RuntimeTypeInfo).FullName,
|
||||||
|
typeof(CodeAnalysisSymbolBasedTypeInfo).FullName),
|
||||||
|
nameof(interfaceTypeInfo));
|
||||||
}
|
}
|
||||||
|
|
||||||
private string SanitizedFullName
|
private string SanitizedFullName
|
||||||
|
|
@ -193,8 +208,8 @@ namespace Microsoft.AspNet.Razor.Runtime.Precompilation
|
||||||
System.Reflection.TypeInfo targetTypeInfo)
|
System.Reflection.TypeInfo targetTypeInfo)
|
||||||
{
|
{
|
||||||
return string.Equals(
|
return string.Equals(
|
||||||
targetTypeInfo.FullName,
|
RuntimeTypeInfo.SanitizeFullName(targetTypeInfo.FullName),
|
||||||
GetFullName(sourceTypeSymbol),
|
RuntimeTypeInfo.SanitizeFullName(GetFullName(sourceTypeSymbol)),
|
||||||
StringComparison.Ordinal);
|
StringComparison.Ordinal);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,22 @@ namespace Microsoft.AspNet.Razor.Runtime.Precompilation
|
||||||
private static readonly ResourceManager _resourceManager
|
private static readonly ResourceManager _resourceManager
|
||||||
= new ResourceManager("Microsoft.AspNet.Razor.Runtime.Precompilation.Resources", typeof(Resources).GetTypeInfo().Assembly);
|
= new ResourceManager("Microsoft.AspNet.Razor.Runtime.Precompilation.Resources", typeof(Resources).GetTypeInfo().Assembly);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Argument must be an instance of '{0}' or '{1}'.
|
||||||
|
/// </summary>
|
||||||
|
internal static string ArgumentMustBeAnInstanceOf
|
||||||
|
{
|
||||||
|
get { return GetString("ArgumentMustBeAnInstanceOf"); }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Argument must be an instance of '{0}' or '{1}'.
|
||||||
|
/// </summary>
|
||||||
|
internal static string FormatArgumentMustBeAnInstanceOf(object p0, object p1)
|
||||||
|
{
|
||||||
|
return string.Format(CultureInfo.CurrentCulture, GetString("ArgumentMustBeAnInstanceOf"), p0, p1);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Unable to find a suitable constructor for type '{0}'.
|
/// Unable to find a suitable constructor for type '{0}'.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
||||||
|
|
@ -117,6 +117,9 @@
|
||||||
<resheader name="writer">
|
<resheader name="writer">
|
||||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
</resheader>
|
</resheader>
|
||||||
|
<data name="ArgumentMustBeAnInstanceOf" xml:space="preserve">
|
||||||
|
<value>Argument must be an instance of '{0}' or '{1}'.</value>
|
||||||
|
</data>
|
||||||
<data name="CodeAnalysisConstructorNotFound" xml:space="preserve">
|
<data name="CodeAnalysisConstructorNotFound" xml:space="preserve">
|
||||||
<value>Unable to find a suitable constructor for type '{0}'.</value>
|
<value>Unable to find a suitable constructor for type '{0}'.</value>
|
||||||
</data>
|
</data>
|
||||||
|
|
|
||||||
|
|
@ -442,6 +442,22 @@ namespace Microsoft.AspNet.Razor.Runtime
|
||||||
return GetString("TagHelperDescriptorFactory_ParentTag");
|
return GetString("TagHelperDescriptorFactory_ParentTag");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Argument must be an instance of '{0}'.
|
||||||
|
/// </summary>
|
||||||
|
internal static string ArgumentMustBeAnInstanceOf
|
||||||
|
{
|
||||||
|
get { return GetString("ArgumentMustBeAnInstanceOf"); }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Argument must be an instance of '{0}'.
|
||||||
|
/// </summary>
|
||||||
|
internal static string FormatArgumentMustBeAnInstanceOf(object p0)
|
||||||
|
{
|
||||||
|
return string.Format(CultureInfo.CurrentCulture, GetString("ArgumentMustBeAnInstanceOf"), p0);
|
||||||
|
}
|
||||||
|
|
||||||
private static string GetString(string name, params string[] formatterNames)
|
private static string GetString(string name, params string[] formatterNames)
|
||||||
{
|
{
|
||||||
var value = _resourceManager.GetString(name);
|
var value = _resourceManager.GetString(name);
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,17 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<root>
|
<root>
|
||||||
<!--
|
<!--
|
||||||
Microsoft ResX Schema
|
Microsoft ResX Schema
|
||||||
|
|
||||||
Version 2.0
|
Version 2.0
|
||||||
|
|
||||||
The primary goals of this format is to allow a simple XML format
|
The primary goals of this format is to allow a simple XML format
|
||||||
that is mostly human readable. The generation and parsing of the
|
that is mostly human readable. The generation and parsing of the
|
||||||
various data types are done through the TypeConverter classes
|
various data types are done through the TypeConverter classes
|
||||||
associated with the data types.
|
associated with the data types.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
... ado.net/XML headers & schema ...
|
... ado.net/XML headers & schema ...
|
||||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||||
<resheader name="version">2.0</resheader>
|
<resheader name="version">2.0</resheader>
|
||||||
|
|
@ -26,36 +26,36 @@
|
||||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||||
<comment>This is a comment</comment>
|
<comment>This is a comment</comment>
|
||||||
</data>
|
</data>
|
||||||
|
|
||||||
There are any number of "resheader" rows that contain simple
|
There are any number of "resheader" rows that contain simple
|
||||||
name/value pairs.
|
name/value pairs.
|
||||||
|
|
||||||
Each data row contains a name, and value. The row also contains a
|
Each data row contains a name, and value. The row also contains a
|
||||||
type or mimetype. Type corresponds to a .NET class that support
|
type or mimetype. Type corresponds to a .NET class that support
|
||||||
text/value conversion through the TypeConverter architecture.
|
text/value conversion through the TypeConverter architecture.
|
||||||
Classes that don't support this are serialized and stored with the
|
Classes that don't support this are serialized and stored with the
|
||||||
mimetype set.
|
mimetype set.
|
||||||
|
|
||||||
The mimetype is used for serialized objects, and tells the
|
The mimetype is used for serialized objects, and tells the
|
||||||
ResXResourceReader how to depersist the object. This is currently not
|
ResXResourceReader how to depersist the object. This is currently not
|
||||||
extensible. For a given mimetype the value must be set accordingly:
|
extensible. For a given mimetype the value must be set accordingly:
|
||||||
|
|
||||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||||
that the ResXResourceWriter will generate, however the reader can
|
that the ResXResourceWriter will generate, however the reader can
|
||||||
read any of the formats listed below.
|
read any of the formats listed below.
|
||||||
|
|
||||||
mimetype: application/x-microsoft.net.object.binary.base64
|
mimetype: application/x-microsoft.net.object.binary.base64
|
||||||
value : The object must be serialized with
|
value : The object must be serialized with
|
||||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||||
: and then encoded with base64 encoding.
|
: and then encoded with base64 encoding.
|
||||||
|
|
||||||
mimetype: application/x-microsoft.net.object.soap.base64
|
mimetype: application/x-microsoft.net.object.soap.base64
|
||||||
value : The object must be serialized with
|
value : The object must be serialized with
|
||||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||||
: and then encoded with base64 encoding.
|
: and then encoded with base64 encoding.
|
||||||
|
|
||||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||||
value : The object must be serialized into a byte array
|
value : The object must be serialized into a byte array
|
||||||
: using a System.ComponentModel.TypeConverter
|
: using a System.ComponentModel.TypeConverter
|
||||||
: and then encoded with base64 encoding.
|
: and then encoded with base64 encoding.
|
||||||
-->
|
-->
|
||||||
|
|
@ -198,4 +198,7 @@
|
||||||
<data name="TagHelperDescriptorFactory_ParentTag" xml:space="preserve">
|
<data name="TagHelperDescriptorFactory_ParentTag" xml:space="preserve">
|
||||||
<value>Parent Tag</value>
|
<value>Parent Tag</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="ArgumentMustBeAnInstanceOf" xml:space="preserve">
|
||||||
|
<value>Argument must be an instance of '{0}'.</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
||||||
|
|
@ -49,9 +49,9 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
|
||||||
bool IsGenericType { get; }
|
bool IsGenericType { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets a value indicating whether the type implements the <see cref="ITagHelper"/> interface.
|
/// Gets a value indicating whether the type implements the <param name="interfaceTypeInfo"/> interface.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
bool IsTagHelper { get; }
|
bool ImplementsInterface(ITypeInfo interfaceTypeInfo);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the <see cref="ITypeInfo[]"/> for the <c>TKey</c> and <c>TValue</c> parameters of
|
/// Gets the <see cref="ITypeInfo[]"/> for the <c>TKey</c> and <c>TValue</c> parameters of
|
||||||
|
|
|
||||||
|
|
@ -77,7 +77,23 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public bool IsTagHelper => TagHelperTypeInfo.IsAssignableFrom(TypeInfo);
|
public bool ImplementsInterface(ITypeInfo interfaceTypeInfo)
|
||||||
|
{
|
||||||
|
if (interfaceTypeInfo == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(interfaceTypeInfo));
|
||||||
|
}
|
||||||
|
|
||||||
|
var runtimeTypeInfo = interfaceTypeInfo as RuntimeTypeInfo;
|
||||||
|
if (runtimeTypeInfo == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentException(
|
||||||
|
Resources.FormatArgumentMustBeAnInstanceOf(typeof(RuntimeTypeInfo).FullName),
|
||||||
|
nameof(interfaceTypeInfo));
|
||||||
|
}
|
||||||
|
|
||||||
|
return runtimeTypeInfo.TypeInfo.IsInterface && runtimeTypeInfo.TypeInfo.IsAssignableFrom(TypeInfo);
|
||||||
|
}
|
||||||
|
|
||||||
private string SanitizedFullName
|
private string SanitizedFullName
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class TagHelperTypeResolver
|
public class TagHelperTypeResolver
|
||||||
{
|
{
|
||||||
private static readonly TypeInfo ITagHelperTypeInfo = typeof(ITagHelper).GetTypeInfo();
|
private static readonly ITypeInfo ITagHelperTypeInfo = new RuntimeTypeInfo(typeof(ITagHelper).GetTypeInfo());
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Locates valid <see cref="ITagHelper"/> types from the <see cref="Assembly"/> named <paramref name="name"/>.
|
/// Locates valid <see cref="ITagHelper"/> types from the <see cref="Assembly"/> named <paramref name="name"/>.
|
||||||
|
|
@ -109,7 +109,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
|
||||||
return typeInfo.IsPublic &&
|
return typeInfo.IsPublic &&
|
||||||
!typeInfo.IsAbstract &&
|
!typeInfo.IsAbstract &&
|
||||||
!typeInfo.IsGenericType &&
|
!typeInfo.IsGenericType &&
|
||||||
typeInfo.IsTagHelper;
|
typeInfo.ImplementsInterface(ITagHelperTypeInfo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -0,0 +1,38 @@
|
||||||
|
// 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;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNet.Razor.Runtime
|
||||||
|
{
|
||||||
|
public class DerivingFromIList : IReadOnlyList<string>
|
||||||
|
{
|
||||||
|
public string this[int index]
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int Count
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerator<string> GetEnumerator()
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
IEnumerator IEnumerable.GetEnumerator()
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
// 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.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNet.Razor.Runtime
|
||||||
|
{
|
||||||
|
public class DerivingFromList : List<string>
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -8,6 +8,7 @@ using System.ComponentModel.DataAnnotations;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using Microsoft.AspNet.Razor.Runtime.TagHelpers;
|
using Microsoft.AspNet.Razor.Runtime.TagHelpers;
|
||||||
|
using Microsoft.AspNet.Testing;
|
||||||
using Microsoft.CodeAnalysis.CSharp;
|
using Microsoft.CodeAnalysis.CSharp;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
|
|
@ -15,7 +16,7 @@ namespace Microsoft.AspNet.Razor.Runtime.Precompilation
|
||||||
{
|
{
|
||||||
public class PrecompilationTagHelperTypeResolverTest
|
public class PrecompilationTagHelperTypeResolverTest
|
||||||
{
|
{
|
||||||
private static readonly TypeInfo TagHelperTypeInfo = typeof(ITagHelper).GetTypeInfo();
|
private static readonly ITypeInfo TagHelperTypeInfo = new RuntimeTypeInfo(typeof(ITagHelper).GetTypeInfo());
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
[InlineData(typeof(TypeDerivingFromITagHelper))]
|
[InlineData(typeof(TypeDerivingFromITagHelper))]
|
||||||
|
|
@ -35,6 +36,60 @@ namespace Microsoft.AspNet.Razor.Runtime.Precompilation
|
||||||
AssertEqual(expected, actual);
|
AssertEqual(expected, actual);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ImplementsInterface_ThrowsIfPassedInParameterIsNotRuntimeTypeOrCodeAnalysisBasedTypeInfo()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var interfaceType = new TestTypeInfo();
|
||||||
|
var compilation = CompilationUtility.GetCompilation(nameof(DerivingFromList));
|
||||||
|
var tagHelperResolver = new PrecompilationTagHelperTypeResolver(compilation);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var exportedTypes = tagHelperResolver.GetExportedTypes(compilation.AssemblyName);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
var actual = Assert.Single(exportedTypes);
|
||||||
|
ExceptionAssert.ThrowsArgument(() => actual.ImplementsInterface(interfaceType),
|
||||||
|
"interfaceTypeInfo",
|
||||||
|
$"Argument must be an instance of '{typeof(RuntimeTypeInfo)}' or '{typeof(CodeAnalysisSymbolBasedTypeInfo)}'.");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData(typeof(DerivingFromList))]
|
||||||
|
[InlineData(typeof(DerivingFromIList))]
|
||||||
|
public void ImplementsInterface_ReturnsTrueIfTypeDerivesFromInterface(Type expected)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var interfaceType = new RuntimeTypeInfo(typeof(IEnumerable<string>).GetTypeInfo());
|
||||||
|
var compilation = CompilationUtility.GetCompilation(expected.Name);
|
||||||
|
var tagHelperResolver = new PrecompilationTagHelperTypeResolver(compilation);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var exportedTypes = tagHelperResolver.GetExportedTypes(compilation.AssemblyName);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
var actual = Assert.Single(exportedTypes);
|
||||||
|
Assert.True(actual.ImplementsInterface(interfaceType));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData(typeof(TagHelper))]
|
||||||
|
[InlineData(typeof(IEnumerable<string>))]
|
||||||
|
public void ImplementsInterface_ReturnsFalseIfTypeDoesNotDerivesFromInterface(Type interfaceType)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var interfaceTypeInfo = new RuntimeTypeInfo(interfaceType.GetTypeInfo());
|
||||||
|
var compilation = CompilationUtility.GetCompilation("TagHelperDescriptorFactoryTagHelpers");
|
||||||
|
var tagHelperResolver = new PrecompilationTagHelperTypeResolver(compilation);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var exportedTypes = tagHelperResolver.GetExportedTypes(compilation.AssemblyName);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
var actual = Assert.Single(exportedTypes, type => type.Name == nameof(RequiredParentTagHelper));
|
||||||
|
Assert.False(actual.ImplementsInterface(interfaceTypeInfo));
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void PropertyNamesForComplexPropertiesAreGeneratedCorrectly()
|
public void PropertyNamesForComplexPropertiesAreGeneratedCorrectly()
|
||||||
{
|
{
|
||||||
|
|
@ -472,7 +527,7 @@ namespace Microsoft.AspNet.Razor.Runtime.Precompilation
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
var type = Assert.Single(exportedTypes);
|
var type = Assert.Single(exportedTypes);
|
||||||
Assert.False(type.IsTagHelper);
|
Assert.False(type.ImplementsInterface(TagHelperTypeInfo));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void AssertAttributes<TAttribute>(
|
private static void AssertAttributes<TAttribute>(
|
||||||
|
|
@ -481,7 +536,7 @@ namespace Microsoft.AspNet.Razor.Runtime.Precompilation
|
||||||
Action<TAttribute, TAttribute> assertItem)
|
Action<TAttribute, TAttribute> assertItem)
|
||||||
where TAttribute : Attribute
|
where TAttribute : Attribute
|
||||||
{
|
{
|
||||||
AssertAttributes<TAttribute>(expected, actual, assertItem, attributes => attributes);
|
AssertAttributes(expected, actual, assertItem, attributes => attributes);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void AssertAttributes<TAttribute>(
|
private static void AssertAttributes<TAttribute>(
|
||||||
|
|
@ -519,7 +574,9 @@ namespace Microsoft.AspNet.Razor.Runtime.Precompilation
|
||||||
Assert.Equal(expected.IsPublic, actual.IsPublic);
|
Assert.Equal(expected.IsPublic, actual.IsPublic);
|
||||||
Assert.Equal(expected.IsAbstract, actual.IsAbstract);
|
Assert.Equal(expected.IsAbstract, actual.IsAbstract);
|
||||||
Assert.Equal(expected.IsGenericType, actual.IsGenericType);
|
Assert.Equal(expected.IsGenericType, actual.IsGenericType);
|
||||||
Assert.Equal(expected.IsTagHelper, actual.IsTagHelper);
|
Assert.Equal(
|
||||||
|
expected.ImplementsInterface(TagHelperTypeInfo),
|
||||||
|
actual.ImplementsInterface(TagHelperTypeInfo));
|
||||||
Assert.Equal(
|
Assert.Equal(
|
||||||
expected.GetGenericDictionaryParameters(),
|
expected.GetGenericDictionaryParameters(),
|
||||||
actual.GetGenericDictionaryParameters(),
|
actual.GetGenericDictionaryParameters(),
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ using System.Collections.Generic;
|
||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.AspNet.Testing;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
|
namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
|
||||||
|
|
@ -110,35 +111,58 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
|
||||||
Assert.Empty(actual);
|
Assert.Empty(actual);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory]
|
[Fact]
|
||||||
[InlineData(typeof(ITagHelper))]
|
public void ImplementsInterface_ThrowsIfArgumentIsNotRuntimeType()
|
||||||
[InlineData(typeof(TagHelper))]
|
|
||||||
[InlineData(typeof(ImplementsITagHelper))]
|
|
||||||
[InlineData(typeof(DerivesFromTagHelper))]
|
|
||||||
[InlineData(typeof(Fake.ImplementsRealITagHelper))]
|
|
||||||
public void IsTagHelper_ReturnsTrueIfTypeImplementsTagHelper(Type type)
|
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var runtimeTypeInfo = new RuntimeTypeInfo(type.GetTypeInfo());
|
var typeInfo = new RuntimeTypeInfo(typeof(object).GetTypeInfo());
|
||||||
|
var interfaceTypeInfo = new TestTypeInfo();
|
||||||
|
|
||||||
|
// Act and Assert
|
||||||
|
ExceptionAssert.ThrowsArgument(() => typeInfo.ImplementsInterface(interfaceTypeInfo),
|
||||||
|
"interfaceTypeInfo",
|
||||||
|
$"Argument must be an instance of '{typeof(RuntimeTypeInfo)}'.");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData(typeof(ITagHelper), typeof(ITagHelper))]
|
||||||
|
[InlineData(typeof(TagHelper), typeof(ITagHelper))]
|
||||||
|
[InlineData(typeof(ImplementsITagHelper), typeof(ITagHelper))]
|
||||||
|
[InlineData(typeof(DerivesFromTagHelper), typeof(ITagHelper))]
|
||||||
|
[InlineData(typeof(Fake.ImplementsRealITagHelper), typeof(ITagHelper))]
|
||||||
|
[InlineData(typeof(string), typeof(IEnumerable<char>))]
|
||||||
|
[InlineData(typeof(Dictionary<string, string>), typeof(IDictionary<string, string>))]
|
||||||
|
[InlineData(typeof(List<string>), typeof(IList<string>))]
|
||||||
|
[InlineData(typeof(IList<string>), typeof(IEnumerable<string>))]
|
||||||
|
public void ImplementsInterface_ReturnsTrueIfTypeImplementsInterface(Type runtimeType, Type interfaceType)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var runtimeTypeInfo = new RuntimeTypeInfo(runtimeType.GetTypeInfo());
|
||||||
|
var interfaceTypeInfo = new RuntimeTypeInfo(interfaceType.GetTypeInfo());
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var result = runtimeTypeInfo.IsTagHelper;
|
var result = runtimeTypeInfo.ImplementsInterface(interfaceTypeInfo);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.True(result);
|
Assert.True(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
[InlineData(typeof(string))]
|
[InlineData(typeof(string), typeof(object))]
|
||||||
[InlineData(typeof(SubType))]
|
[InlineData(typeof(DerivesFromTagHelper), typeof(TagHelper))]
|
||||||
[InlineData(typeof(Fake.DoesNotImplementRealITagHelper))]
|
[InlineData(typeof(string), typeof(ITagHelper))]
|
||||||
public void IsTagHelper_ReturnsFalseIfTypeDoesNotImplementTagHelper(Type type)
|
[InlineData(typeof(string), typeof(IList<char>))]
|
||||||
|
[InlineData(typeof(SubType), typeof(ITagHelper))]
|
||||||
|
[InlineData(typeof(Fake.DoesNotImplementRealITagHelper), typeof(ITagHelper))]
|
||||||
|
[InlineData(typeof(IDictionary<,>), typeof(IDictionary<string, string>))]
|
||||||
|
public void ImplementsInterface_ReturnsTrueIfTypeDoesNotImplementInterface(Type runtimeType, Type interfaceType)
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var runtimeTypeInfo = new RuntimeTypeInfo(type.GetTypeInfo());
|
var runtimeTypeInfo = new RuntimeTypeInfo(runtimeType.GetTypeInfo());
|
||||||
|
var interfaceTypeInfo = new RuntimeTypeInfo(interfaceType.GetTypeInfo());
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var result = runtimeTypeInfo.IsTagHelper;
|
var result = runtimeTypeInfo.ImplementsInterface(interfaceTypeInfo);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.False(result);
|
Assert.False(result);
|
||||||
|
|
@ -502,73 +526,5 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
|
||||||
private class CustomType
|
private class CustomType
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
private class TestTypeInfo : ITypeInfo
|
|
||||||
{
|
|
||||||
public string FullName { get; set; }
|
|
||||||
|
|
||||||
public bool IsAbstract
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsGenericType
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsPublic
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsTagHelper
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public string Name
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public IEnumerable<IPropertyInfo> Properties
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool Equals(ITypeInfo other)
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public IEnumerable<TAttribute> GetCustomAttributes<TAttribute>() where TAttribute : Attribute
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public ITypeInfo[] GetGenericDictionaryParameters()
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -0,0 +1,73 @@
|
||||||
|
// 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.Generic;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
|
||||||
|
{
|
||||||
|
public class TestTypeInfo : ITypeInfo
|
||||||
|
{
|
||||||
|
public string FullName { get; set; }
|
||||||
|
|
||||||
|
public bool IsAbstract
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsGenericType
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsPublic
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool ImplementsInterface(ITypeInfo other)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Name
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerable<IPropertyInfo> Properties
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Equals(ITypeInfo other)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerable<TAttribute> GetCustomAttributes<TAttribute>() where TAttribute : Attribute
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ITypeInfo[] GetGenericDictionaryParameters()
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue