Removing ITypeInfo and related types

This commit is contained in:
Pranav K 2016-01-11 17:42:17 -08:00
parent c05551e167
commit b4d631e2f6
18 changed files with 237 additions and 1535 deletions

View File

@ -1,30 +0,0 @@
// 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
{
/// <summary>
/// Metadata common to types and properties.
/// </summary>
public interface IMemberInfo
{
/// <summary>
/// Gets the name.
/// </summary>
string Name { get; }
/// <summary>
/// Retrieves a collection of custom <see cref="Attribute"/>s of type <typeparamref name="TAttribute"/> applied
/// to this instance of <see cref="IMemberInfo"/>.
/// </summary>
/// <typeparam name="TAttribute">The type of <see cref="Attribute"/> to search for.</typeparam>
/// <returns>A sequence of custom <see cref="Attribute"/>s of type
/// <typeparamref name="TAttribute"/>.</returns>
/// <remarks>Result not include inherited <see cref="Attribute"/>s.</remarks>
IEnumerable<TAttribute> GetCustomAttributes<TAttribute>()
where TAttribute : Attribute;
}
}

View File

@ -1,26 +0,0 @@
// 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.
namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
{
/// <summary>
/// Contains property metadata.
/// </summary>
public interface IPropertyInfo : IMemberInfo
{
/// <summary>
/// Gets a value indicating whether this property has a public getter.
/// </summary>
bool HasPublicGetter { get; }
/// <summary>
/// Gets a value indicating whether this property has a public setter.
/// </summary>
bool HasPublicSetter { get; }
/// <summary>
/// Gets the <see cref="ITypeInfo"/> of the property.
/// </summary>
ITypeInfo PropertyType { get; }
}
}

View File

@ -1,74 +0,0 @@
// 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
{
/// <summary>
/// Contains type metadata.
/// </summary>
public interface ITypeInfo : IMemberInfo, IEquatable<ITypeInfo>
{
/// <summary>
/// Fully qualified name of the type.
/// </summary>
/// <remarks>
/// On CoreCLR, some BCL types get type forwarded to the full desktop framework implementations at
/// runtime. For e.g. we compile against System.String in System.Runtime which is type forwarded to
/// mscorlib at runtime. Consequently for generic types where the <see cref="FullName"/> includes the assembly
/// qualified name of generic parameters, FullNames would not match.
/// Use <see cref="IEquatable{ITypeInfo}.Equals(ITypeInfo)"/> to compare <see cref="ITypeInfo"/>s instead.
/// </remarks>
string FullName { get; }
/// <summary>
/// Gets <see cref="IPropertyInfo"/>s for all properties of the current type excluding indexers.
/// </summary>
/// <remarks>
/// Indexers in this context refer to the CLR notion of an indexer (<c>this [string name]</c>
/// and does not overlap with the semantics of
/// <see cref="Razor.Compilation.TagHelpers.TagHelperAttributeDescriptor.IsIndexer"/>.
/// </remarks>
IEnumerable<IPropertyInfo> Properties { get; }
/// <summary>
/// Gets a value indicating whether the type is an <see cref="Enum"/>.
/// </summary>
bool IsEnum { get; }
/// <summary>
/// Gets a value indicating whether the type is public.
/// </summary>
bool IsPublic { get; }
/// <summary>
/// Gets a value indicating whether the type is abstract or an interface.
/// </summary>
bool IsAbstract { get; }
/// <summary>
/// Gets a value indicating whether the type is generic.
/// </summary>
bool IsGenericType { get; }
/// <summary>
/// Gets a value indicating whether the type implements the <param name="interfaceTypeInfo"/> interface.
/// </summary>
bool ImplementsInterface(ITypeInfo interfaceTypeInfo);
/// <summary>
/// Gets the <see cref="ITypeInfo[]"/> for the <c>TKey</c> and <c>TValue</c> parameters of
/// <see cref="IDictionary{TKey, TValue}"/>.
/// </summary>
/// <returns>
/// The <see cref="ITypeInfo"/> of <c>TKey</c> and <c>TValue</c>
/// parameters if the type implements <see cref="IDictionary{TKey, TValue}"/>, otherwise <c>null</c>.
/// </returns>
/// <remarks>
/// For open generic types, <see cref="ITypeInfo" /> for generic type parameters is <c>null</c>.
/// </remarks>
ITypeInfo[] GetGenericDictionaryParameters();
}
}

View File

@ -1,54 +0,0 @@
// 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;
using System.Reflection;
namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
{
/// <summary>
/// <see cref="IPropertyInfo"/> adapter for <see cref="PropertyInfo"/> instances.
/// </summary>
public class RuntimePropertyInfo : IPropertyInfo
{
/// <summary>
/// Initializes a new instance of <see cref="RuntimePropertyInfo"/>.
/// </summary>
/// <param name="propertyInfo">The <see cref="PropertyInfo"/> instance to adapt.</param>
public RuntimePropertyInfo(PropertyInfo propertyInfo)
{
if (propertyInfo == null)
{
throw new ArgumentNullException(nameof(propertyInfo));
}
Property = propertyInfo;
}
/// <summary>
/// The <see cref="PropertyInfo"/> instance.
/// </summary>
public PropertyInfo Property { get; }
/// <inheritdoc />
public bool HasPublicGetter => Property.GetMethod != null && Property.GetMethod.IsPublic;
/// <inheritdoc />
public bool HasPublicSetter => Property.SetMethod != null && Property.SetMethod.IsPublic;
/// <inheritdoc />
public string Name => Property.Name;
/// <inheritdoc />
public ITypeInfo PropertyType => new RuntimeTypeInfo(Property.PropertyType.GetTypeInfo());
/// <inheritdoc />
public IEnumerable<TAttribute> GetCustomAttributes<TAttribute>() where TAttribute : Attribute
=> Property.GetCustomAttributes<TAttribute>(inherit: false);
/// <inheritdoc />
public override string ToString() =>
Property.ToString();
}
}

View File

@ -1,182 +0,0 @@
// 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;
using System.Linq;
using System.Reflection;
using System.Text.RegularExpressions;
using Microsoft.AspNet.Razor.TagHelpers;
using Microsoft.Extensions.Internal;
namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
{
/// <summary>
/// <see cref="ITypeInfo"/> adapter for <see cref="System.Reflection.TypeInfo"/> instances.
/// </summary>
public class RuntimeTypeInfo : ITypeInfo
{
private static readonly Regex _fullNameSanitizer = new Regex(
@", [A-Za-z\.]+, Version=\d+\.\d+\.\d+\.\d+, Culture=neutral, PublicKeyToken=\w+",
RegexOptions.ExplicitCapture,
Constants.RegexMatchTimeout);
private static readonly TypeInfo TagHelperTypeInfo = typeof(ITagHelper).GetTypeInfo();
private IEnumerable<IPropertyInfo> _properties;
private string _sanitizedFullName;
/// <summary>
/// Initializes a new instance of <see cref="RuntimeTypeInfo"/>
/// </summary>
/// <param name="propertyInfo">The <see cref="System.Reflection.TypeInfo"/> instance to adapt.</param>
public RuntimeTypeInfo(TypeInfo typeInfo)
{
if (typeInfo == null)
{
throw new ArgumentNullException(nameof(typeInfo));
}
TypeInfo = typeInfo;
}
/// <summary>
/// The <see cref="System.Reflection.TypeInfo"/> instance.
/// </summary>
public TypeInfo TypeInfo { get; }
/// <inheritdoc />
public string Name => TypeInfo.Name;
/// <inheritdoc />
public string FullName => TypeInfo.FullName;
/// <inheritdoc />
public bool IsEnum => TypeInfo.IsEnum;
/// <inheritdoc />
public bool IsAbstract => TypeInfo.IsAbstract;
/// <inheritdoc />
public bool IsGenericType => TypeInfo.IsGenericType;
/// <inheritdoc />
public bool IsPublic => TypeInfo.IsPublic;
/// <inheritdoc />
public IEnumerable<IPropertyInfo> Properties
{
get
{
if (_properties == null)
{
_properties = TypeInfo
.AsType()
.GetRuntimeProperties()
.Where(property => property.GetIndexParameters().Length == 0)
.Select(property => new RuntimePropertyInfo(property));
}
return _properties;
}
}
/// <inheritdoc />
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
{
get
{
if (_sanitizedFullName == null)
{
_sanitizedFullName = SanitizeFullName(FullName);
}
return _sanitizedFullName;
}
}
/// <inheritdoc />
public IEnumerable<TAttribute> GetCustomAttributes<TAttribute>() where TAttribute : Attribute =>
TypeInfo.GetCustomAttributes<TAttribute>(inherit: false);
/// <inheritdoc />
public ITypeInfo[] GetGenericDictionaryParameters()
{
return ClosedGenericMatcher.ExtractGenericInterface(
TypeInfo.AsType(),
typeof(IDictionary<,>))
?.GenericTypeArguments
.Select(type => type.IsGenericParameter ? null : new RuntimeTypeInfo(type.GetTypeInfo()))
.ToArray();
}
/// <inheritdoc />
public override string ToString() => TypeInfo.ToString();
/// <inheritdoc />
public override bool Equals(object obj)
{
return Equals(obj as ITypeInfo);
}
/// <inheritdoc />
public bool Equals(ITypeInfo other)
{
if (other == null)
{
return false;
}
var otherRuntimeType = other as RuntimeTypeInfo;
if (otherRuntimeType != null)
{
return otherRuntimeType.TypeInfo == TypeInfo;
}
return string.Equals(
SanitizedFullName,
SanitizeFullName(other.FullName),
StringComparison.Ordinal);
}
/// <inheritdoc />
public override int GetHashCode() => SanitizedFullName.GetHashCode();
/// <summary>
/// Removes assembly qualification from generic type parameters for the specified <paramref name="fullName"/>.
/// </summary>
/// <param name="fullName">Full name.</param>
/// <returns>Full name without fully qualified generic parameters.</returns>
/// <example>
/// <c>typeof(<see cref="List{string}"/>).FullName</c> is
/// List`1[[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]
/// <c>Sanitize(typeof(<see cref="List{string}"/>.FullName</c> returns
/// List`1[[System.String]
/// </example>
public static string SanitizeFullName(string fullName)
{
// In CoreCLR, some types (such as System.String) are type forwarded from System.Runtime
// to mscorlib at runtime. Type names of generic type parameters includes the assembly qualified name;
// consequently the type name generated at precompilation differs from the one at runtime. We'll
// avoid dealing with these inconsistencies by removing assembly information from TypeInfo.FullName.
return _fullNameSanitizer.Replace(fullName, string.Empty);
}
}
}

View File

@ -9,11 +9,12 @@ using System.Reflection;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using Microsoft.AspNet.Razor.Compilation.TagHelpers; using Microsoft.AspNet.Razor.Compilation.TagHelpers;
using Microsoft.AspNet.Razor.TagHelpers; using Microsoft.AspNet.Razor.TagHelpers;
using Microsoft.Extensions.Internal;
namespace Microsoft.AspNet.Razor.Runtime.TagHelpers namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
{ {
/// <summary> /// <summary>
/// Factory for <see cref="TagHelperDescriptor"/>s from <see cref="ITypeInfo"/>s. /// Factory for <see cref="TagHelperDescriptor"/>s from <see cref="Type"/>s.
/// </summary> /// </summary>
public class TagHelperDescriptorFactory public class TagHelperDescriptorFactory
{ {
@ -31,8 +32,6 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
RegexOptions.None, RegexOptions.None,
Constants.RegexMatchTimeout); Constants.RegexMatchTimeout);
private static readonly ITypeInfo StringTypeInfo = new RuntimeTypeInfo(typeof(string).GetTypeInfo());
#if !DOTNET5_4 #if !DOTNET5_4
private readonly TagHelperDesignTimeDescriptorFactory _designTimeDescriptorFactory; private readonly TagHelperDesignTimeDescriptorFactory _designTimeDescriptorFactory;
#endif #endif
@ -63,24 +62,24 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
} }
/// <summary> /// <summary>
/// Creates a <see cref="TagHelperDescriptor"/> from the given <paramref name="typeInfo"/>. /// Creates a <see cref="TagHelperDescriptor"/> from the given <paramref name="type"/>.
/// </summary> /// </summary>
/// <param name="assemblyName">The assembly name that contains <paramref name="type"/>.</param> /// <param name="assemblyName">The assembly name that contains <paramref name="type"/>.</param>
/// <param name="typeInfo">The <see cref="ITypeInfo"/> to create a <see cref="TagHelperDescriptor"/> from. /// <param name="type">The <see cref="Type"/> to create a <see cref="TagHelperDescriptor"/> from.
/// </param> /// </param>
/// <param name="errorSink">The <see cref="ErrorSink"/> used to collect <see cref="RazorError"/>s encountered /// <param name="errorSink">The <see cref="ErrorSink"/> used to collect <see cref="RazorError"/>s encountered
/// when creating <see cref="TagHelperDescriptor"/>s for the given <paramref name="typeInfo"/>.</param> /// when creating <see cref="TagHelperDescriptor"/>s for the given <paramref name="type"/>.</param>
/// <returns> /// <returns>
/// A collection of <see cref="TagHelperDescriptor"/>s that describe the given <paramref name="typeInfo"/>. /// A collection of <see cref="TagHelperDescriptor"/>s that describe the given <paramref name="type"/>.
/// </returns> /// </returns>
public virtual IEnumerable<TagHelperDescriptor> CreateDescriptors( public virtual IEnumerable<TagHelperDescriptor> CreateDescriptors(
string assemblyName, string assemblyName,
ITypeInfo typeInfo, Type type,
ErrorSink errorSink) ErrorSink errorSink)
{ {
if (typeInfo == null) if (type == null)
{ {
throw new ArgumentNullException(nameof(typeInfo)); throw new ArgumentNullException(nameof(type));
} }
if (errorSink == null) if (errorSink == null)
@ -88,18 +87,18 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
throw new ArgumentNullException(nameof(errorSink)); throw new ArgumentNullException(nameof(errorSink));
} }
if (ShouldSkipDescriptorCreation(typeInfo)) if (ShouldSkipDescriptorCreation(type.GetTypeInfo()))
{ {
return Enumerable.Empty<TagHelperDescriptor>(); return Enumerable.Empty<TagHelperDescriptor>();
} }
var attributeDescriptors = GetAttributeDescriptors(typeInfo, errorSink); var attributeDescriptors = GetAttributeDescriptors(type, errorSink);
var targetElementAttributes = GetValidHtmlTargetElementAttributes(typeInfo, errorSink); var targetElementAttributes = GetValidHtmlTargetElementAttributes(type, errorSink);
var allowedChildren = GetAllowedChildren(typeInfo, errorSink); var allowedChildren = GetAllowedChildren(type, errorSink);
var tagHelperDescriptors = var tagHelperDescriptors =
BuildTagHelperDescriptors( BuildTagHelperDescriptors(
typeInfo, type,
assemblyName, assemblyName,
attributeDescriptors, attributeDescriptors,
targetElementAttributes, targetElementAttributes,
@ -109,17 +108,18 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
} }
private static IEnumerable<HtmlTargetElementAttribute> GetValidHtmlTargetElementAttributes( private static IEnumerable<HtmlTargetElementAttribute> GetValidHtmlTargetElementAttributes(
ITypeInfo typeInfo, Type type,
ErrorSink errorSink) ErrorSink errorSink)
{ {
var targetElementAttributes = typeInfo.GetCustomAttributes<HtmlTargetElementAttribute>(); var targetElementAttributes = type
.GetTypeInfo()
.GetCustomAttributes<HtmlTargetElementAttribute>(inherit: false);
return targetElementAttributes.Where( return targetElementAttributes.Where(
attribute => ValidHtmlTargetElementAttributeNames(attribute, errorSink)); attribute => ValidHtmlTargetElementAttributeNames(attribute, errorSink));
} }
private IEnumerable<TagHelperDescriptor> BuildTagHelperDescriptors( private IEnumerable<TagHelperDescriptor> BuildTagHelperDescriptors(
ITypeInfo typeInfo, Type type,
string assemblyName, string assemblyName,
IEnumerable<TagHelperAttributeDescriptor> attributeDescriptors, IEnumerable<TagHelperAttributeDescriptor> attributeDescriptors,
IEnumerable<HtmlTargetElementAttribute> targetElementAttributes, IEnumerable<HtmlTargetElementAttribute> targetElementAttributes,
@ -130,21 +130,16 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
#if !DOTNET5_4 #if !DOTNET5_4
if (_designTime) if (_designTime)
{ {
var runtimeTypeInfo = typeInfo as RuntimeTypeInfo; typeDesignTimeDescriptor = _designTimeDescriptorFactory.CreateDescriptor(type);
if (runtimeTypeInfo != null)
{
typeDesignTimeDescriptor =
_designTimeDescriptorFactory.CreateDescriptor(runtimeTypeInfo.TypeInfo.AsType());
}
} }
#endif #endif
var typeName = typeInfo.FullName; var typeName = type.FullName;
// If there isn't an attribute specifying the tag name derive it from the name // If there isn't an attribute specifying the tag name derive it from the name
if (!targetElementAttributes.Any()) if (!targetElementAttributes.Any())
{ {
var name = typeInfo.Name; var name = type.Name;
if (name.EndsWith(TagHelperNameEnding, StringComparison.OrdinalIgnoreCase)) if (name.EndsWith(TagHelperNameEnding, StringComparison.OrdinalIgnoreCase))
{ {
@ -177,18 +172,16 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
typeDesignTimeDescriptor)); typeDesignTimeDescriptor));
} }
private static IEnumerable<string> GetAllowedChildren(ITypeInfo typeInfo, ErrorSink errorSink) private static IEnumerable<string> GetAllowedChildren(Type type, ErrorSink errorSink)
{ {
var restrictChildrenAttribute = typeInfo var restrictChildrenAttribute = type.GetTypeInfo().GetCustomAttribute<RestrictChildrenAttribute>(inherit: false);
.GetCustomAttributes<RestrictChildrenAttribute>()
.FirstOrDefault();
if (restrictChildrenAttribute == null) if (restrictChildrenAttribute == null)
{ {
return null; return null;
} }
var allowedChildren = restrictChildrenAttribute.ChildTags; var allowedChildren = restrictChildrenAttribute.ChildTags;
var validAllowedChildren = GetValidAllowedChildren(allowedChildren, typeInfo.FullName, errorSink); var validAllowedChildren = GetValidAllowedChildren(allowedChildren, type.FullName, errorSink);
if (validAllowedChildren.Any()) if (validAllowedChildren.Any())
{ {
@ -405,14 +398,14 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
return validName; return validName;
} }
private IEnumerable<TagHelperAttributeDescriptor> GetAttributeDescriptors(ITypeInfo type, ErrorSink errorSink) private IEnumerable<TagHelperAttributeDescriptor> GetAttributeDescriptors(Type type, ErrorSink errorSink)
{ {
var attributeDescriptors = new List<TagHelperAttributeDescriptor>(); var attributeDescriptors = new List<TagHelperAttributeDescriptor>();
// Keep indexer descriptors separate to avoid sorting the combined list later. // Keep indexer descriptors separate to avoid sorting the combined list later.
var indexerDescriptors = new List<TagHelperAttributeDescriptor>(); var indexerDescriptors = new List<TagHelperAttributeDescriptor>();
var accessibleProperties = type.Properties.Where(IsAccessibleProperty); var accessibleProperties = type.GetRuntimeProperties().Where(IsAccessibleProperty);
foreach (var property in accessibleProperties) foreach (var property in accessibleProperties)
{ {
if (ShouldSkipDescriptorCreation(property)) if (ShouldSkipDescriptorCreation(property))
@ -421,14 +414,14 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
} }
var attributeNameAttribute = property var attributeNameAttribute = property
.GetCustomAttributes<HtmlAttributeNameAttribute>() .GetCustomAttributes<HtmlAttributeNameAttribute>(inherit: false)
.FirstOrDefault(); .FirstOrDefault();
var hasExplicitName = var hasExplicitName =
attributeNameAttribute != null && !string.IsNullOrEmpty(attributeNameAttribute.Name); attributeNameAttribute != null && !string.IsNullOrEmpty(attributeNameAttribute.Name);
var attributeName = hasExplicitName ? attributeNameAttribute.Name : ToHtmlCase(property.Name); var attributeName = hasExplicitName ? attributeNameAttribute.Name : ToHtmlCase(property.Name);
TagHelperAttributeDescriptor mainDescriptor = null; TagHelperAttributeDescriptor mainDescriptor = null;
if (property.HasPublicSetter) if (property.SetMethod != null && property.SetMethod.IsPublic)
{ {
mainDescriptor = ToAttributeDescriptor(property, attributeName); mainDescriptor = ToAttributeDescriptor(property, attributeName);
if (!ValidateTagHelperAttributeDescriptor(mainDescriptor, type, errorSink)) if (!ValidateTagHelperAttributeDescriptor(mainDescriptor, type, errorSink))
@ -491,7 +484,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
// Internal for testing. // Internal for testing.
internal static bool ValidateTagHelperAttributeDescriptor( internal static bool ValidateTagHelperAttributeDescriptor(
TagHelperAttributeDescriptor attributeDescriptor, TagHelperAttributeDescriptor attributeDescriptor,
ITypeInfo parentType, Type parentType,
ErrorSink errorSink) ErrorSink errorSink)
{ {
string nameOrPrefix; string nameOrPrefix;
@ -523,13 +516,11 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
nameOrPrefix); nameOrPrefix);
} }
private bool ShouldSkipDescriptorCreation(IMemberInfo memberInfo) private bool ShouldSkipDescriptorCreation(MemberInfo memberInfo)
{ {
if (_designTime) if (_designTime)
{ {
var editorBrowsableAttribute = memberInfo var editorBrowsableAttribute = memberInfo.GetCustomAttribute<EditorBrowsableAttribute>(inherit: false);
.GetCustomAttributes<EditorBrowsableAttribute>()
.FirstOrDefault();
return editorBrowsableAttribute != null && return editorBrowsableAttribute != null &&
editorBrowsableAttribute.State == EditorBrowsableState.Never; editorBrowsableAttribute.State == EditorBrowsableState.Never;
@ -540,7 +531,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
private static bool ValidateTagHelperAttributeNameOrPrefix( private static bool ValidateTagHelperAttributeNameOrPrefix(
string attributeNameOrPrefix, string attributeNameOrPrefix,
ITypeInfo parentType, Type parentType,
string propertyName, string propertyName,
ErrorSink errorSink, ErrorSink errorSink,
string nameOrPrefix) string nameOrPrefix)
@ -608,28 +599,33 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
return isValid; return isValid;
} }
private TagHelperAttributeDescriptor ToAttributeDescriptor(IPropertyInfo property, string attributeName) private TagHelperAttributeDescriptor ToAttributeDescriptor(PropertyInfo property, string attributeName)
{ {
return ToAttributeDescriptor( return ToAttributeDescriptor(
property, property,
attributeName, attributeName,
property.PropertyType.FullName, property.PropertyType.FullName,
isIndexer: false, isIndexer: false,
isStringProperty: StringTypeInfo.Equals(property.PropertyType)); isStringProperty: typeof(string) == property.PropertyType);
} }
private TagHelperAttributeDescriptor ToIndexerAttributeDescriptor( private TagHelperAttributeDescriptor ToIndexerAttributeDescriptor(
IPropertyInfo property, PropertyInfo property,
HtmlAttributeNameAttribute attributeNameAttribute, HtmlAttributeNameAttribute attributeNameAttribute,
ITypeInfo parentType, Type parentType,
ErrorSink errorSink, ErrorSink errorSink,
string defaultPrefix, string defaultPrefix,
out bool isInvalid) out bool isInvalid)
{ {
isInvalid = false; isInvalid = false;
var hasPublicSetter = property.HasPublicSetter; var hasPublicSetter = property.SetMethod != null && property.SetMethod.IsPublic;
var dictionaryTypeArguments = property.PropertyType.GetGenericDictionaryParameters(); var dictionaryTypeArguments = ClosedGenericMatcher.ExtractGenericInterface(
if (!StringTypeInfo.Equals(dictionaryTypeArguments?[0])) property.PropertyType,
typeof(IDictionary<,>))
?.GenericTypeArguments
.Select(type => type.IsGenericParameter ? null : type)
.ToArray();
if (dictionaryTypeArguments?[0] != typeof(string))
{ {
if (attributeNameAttribute?.DictionaryAttributePrefix != null) if (attributeNameAttribute?.DictionaryAttributePrefix != null)
{ {
@ -698,11 +694,11 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
attributeName: prefix, attributeName: prefix,
typeName: dictionaryTypeArguments[1].FullName, typeName: dictionaryTypeArguments[1].FullName,
isIndexer: true, isIndexer: true,
isStringProperty: StringTypeInfo.Equals(dictionaryTypeArguments[1])); isStringProperty: typeof(string) == dictionaryTypeArguments[1]);
} }
private TagHelperAttributeDescriptor ToAttributeDescriptor( private TagHelperAttributeDescriptor ToAttributeDescriptor(
IPropertyInfo property, PropertyInfo property,
string attributeName, string attributeName,
string typeName, string typeName,
bool isIndexer, bool isIndexer,
@ -713,12 +709,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
#if !DOTNET5_4 #if !DOTNET5_4
if (_designTime) if (_designTime)
{ {
var runtimeProperty = property as RuntimePropertyInfo; propertyDesignTimeDescriptor = _designTimeDescriptorFactory.CreateAttributeDescriptor(property);
if (runtimeProperty != null)
{
propertyDesignTimeDescriptor =
_designTimeDescriptorFactory.CreateAttributeDescriptor(runtimeProperty.Property);
}
} }
#endif #endif
@ -726,7 +717,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
{ {
Name = attributeName, Name = attributeName,
PropertyName = property.Name, PropertyName = property.Name,
IsEnum = property.PropertyType.IsEnum, IsEnum = property.PropertyType.GetTypeInfo().IsEnum,
TypeName = typeName, TypeName = typeName,
IsStringProperty = isStringProperty, IsStringProperty = isStringProperty,
IsIndexer = isIndexer, IsIndexer = isIndexer,
@ -734,11 +725,13 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
}; };
} }
private static bool IsAccessibleProperty(IPropertyInfo property) private static bool IsAccessibleProperty(PropertyInfo property)
{ {
// Accessible properties are those with public getters and without [HtmlAttributeNotBound]. // Accessible properties are those with public getters and without [HtmlAttributeNotBound].
return property.HasPublicGetter && return property.GetIndexParameters().Length == 0 &&
property.GetCustomAttributes<HtmlAttributeNotBoundAttribute>().FirstOrDefault() == null; property.GetMethod != null &&
property.GetMethod.IsPublic &&
property.GetCustomAttribute<HtmlAttributeNotBoundAttribute>(inherit: false) == null;
} }
/// <summary> /// <summary>

View File

@ -14,7 +14,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
/// </summary> /// </summary>
public class TagHelperTypeResolver public class TagHelperTypeResolver
{ {
private static readonly ITypeInfo ITagHelperTypeInfo = new RuntimeTypeInfo(typeof(ITagHelper).GetTypeInfo()); private static readonly TypeInfo ITagHelperTypeInfo = 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"/>.
@ -25,8 +25,8 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
/// </param> /// </param>
/// <param name="errorSink">The <see cref="ErrorSink"/> used to record errors found when resolving /// <param name="errorSink">The <see cref="ErrorSink"/> used to record errors found when resolving
/// <see cref="ITagHelper"/> types.</param> /// <see cref="ITagHelper"/> types.</param>
/// <returns>An <see cref="IEnumerable{ITypeInfo}"/> of valid <see cref="ITagHelper"/> types.</returns> /// <returns>An <see cref="IEnumerable{Type}"/> of valid <see cref="ITagHelper"/> types.</returns>
public IEnumerable<ITypeInfo> Resolve( public IEnumerable<Type> Resolve(
string name, string name,
SourceLocation documentLocation, SourceLocation documentLocation,
ErrorSink errorSink) ErrorSink errorSink)
@ -44,15 +44,15 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
Resources.TagHelperTypeResolver_TagHelperAssemblyNameCannotBeEmptyOrNull, Resources.TagHelperTypeResolver_TagHelperAssemblyNameCannotBeEmptyOrNull,
errorLength); errorLength);
return Enumerable.Empty<ITypeInfo>(); return Type.EmptyTypes;
} }
var assemblyName = new AssemblyName(name); var assemblyName = new AssemblyName(name);
IEnumerable<ITypeInfo> libraryTypes; IEnumerable<TypeInfo> libraryTypes;
try try
{ {
libraryTypes = GetTopLevelExportedTypes(assemblyName); libraryTypes = GetExportedTypes(assemblyName);
} }
catch (Exception ex) catch (Exception ex)
{ {
@ -63,31 +63,10 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
ex.Message), ex.Message),
name.Length); name.Length);
return Enumerable.Empty<ITypeInfo>(); return Type.EmptyTypes;
} }
return libraryTypes.Where(IsTagHelper); return libraryTypes.Where(IsTagHelper).Select(t => t.AsType());
}
/// <summary>
/// Returns all non-nested exported types from the given <paramref name="assemblyName"/>
/// </summary>
/// <param name="assemblyName">The <see cref="AssemblyName"/> to get <see cref="ITypeInfo"/>s from.</param>
/// <returns>
/// An <see cref="IEnumerable{ITypeInfo}"/> of types exported from the given <paramref name="assemblyName"/>.
/// </returns>
protected virtual IEnumerable<ITypeInfo> GetTopLevelExportedTypes(AssemblyName assemblyName)
{
if (assemblyName == null)
{
throw new ArgumentNullException(nameof(assemblyName));
}
var exportedTypeInfos = GetExportedTypes(assemblyName);
return exportedTypeInfos
.Where(typeInfo => !typeInfo.IsNested)
.Select(typeInfo => new RuntimeTypeInfo(typeInfo));
} }
/// <summary> /// <summary>
@ -105,12 +84,14 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
} }
// Internal for testing. // Internal for testing.
internal virtual bool IsTagHelper(ITypeInfo typeInfo) internal virtual bool IsTagHelper(TypeInfo typeInfo)
{ {
return typeInfo.IsPublic && return
!typeInfo.IsAbstract && !typeInfo.IsNested &&
!typeInfo.IsGenericType && typeInfo.IsPublic &&
typeInfo.ImplementsInterface(ITagHelperTypeInfo); !typeInfo.IsAbstract &&
!typeInfo.IsGenericType &&
ITagHelperTypeInfo.IsAssignableFrom(typeInfo);
} }
} }
} }

View File

@ -1,160 +0,0 @@
// 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.Linq;
using System.Reflection;
using Microsoft.AspNet.Razor.TagHelpers;
using Xunit;
namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
{
public class RuntimePropertyInfoTest
{
[Fact]
public void PropertyInfo_ReturnsMetadataOfAdaptingProperty()
{
// Arrange
var property = GetPropertyInfo(nameof(TestType.Property));
var runtimePropertyInfo = new RuntimePropertyInfo(property);
// Act
var actual = runtimePropertyInfo.Property;
// Assert
Assert.Same(property, actual);
var runtimeTypeInfo = Assert.IsType<RuntimeTypeInfo>(runtimePropertyInfo.PropertyType);
Assert.Same(property.PropertyType, runtimeTypeInfo.TypeInfo);
}
[Theory]
[InlineData(nameof(TestType.Property))]
[InlineData(nameof(TestType.PrivateSetter))]
[InlineData(nameof(TestType.PropertyWithoutSetter))]
public void HasPublicGetter_ReturnsTrueIfGetterExistsAndIsPublic(string propertyName)
{
// Arrange
var property = GetPropertyInfo(propertyName);
var runtimePropertyInfo = new RuntimePropertyInfo(property);
// Act
var result = runtimePropertyInfo.HasPublicGetter;
// Assert
Assert.True(result);
}
[Theory]
[InlineData(nameof(TestType.PrivateGetter))]
[InlineData(nameof(TestType.PropertyWithoutGetter))]
[InlineData("ProtectedProperty")]
public void HasPublicGetter_ReturnsFalseIfGetterDoesNotExistOrIsNonPublic(string propertyName)
{
// Arrange
var property = GetPropertyInfo(propertyName);
var runtimePropertyInfo = new RuntimePropertyInfo(property);
// Act
var result = runtimePropertyInfo.HasPublicGetter;
// Assert
Assert.False(result);
}
[Theory]
[InlineData(nameof(TestType.Property))]
[InlineData(nameof(TestType.PrivateGetter))]
[InlineData(nameof(TestType.PropertyWithoutGetter))]
public void HasPublicSetter_ReturnsTrueIfSetterExistsAndIsPublic(string propertyName)
{
// Arrange
var property = GetPropertyInfo(propertyName);
var runtimePropertyInfo = new RuntimePropertyInfo(property);
// Act
var result = runtimePropertyInfo.HasPublicSetter;
// Assert
Assert.True(result);
}
[Theory]
[InlineData(nameof(TestType.PrivateSetter))]
[InlineData(nameof(TestType.PropertyWithoutSetter))]
[InlineData("ProtectedProperty")]
public void HasPublicSetter_ReturnsFalseIfGetterDoesNotExistOrIsNonPublic(string propertyName)
{
// Arrange
var property = GetPropertyInfo(propertyName);
var runtimePropertyInfo = new RuntimePropertyInfo(property);
// Act
var result = runtimePropertyInfo.HasPublicSetter;
// Assert
Assert.False(result);
}
[Fact]
public void GetAttributes_ReturnsCustomAttributesOfSpecifiedType()
{
// Arrange
var property = GetPropertyInfo(nameof(TestType.PropertyWithAttributes));
var runtimeProperty = new RuntimePropertyInfo(property);
// Act
var attributes = property.GetCustomAttributes<HtmlAttributeNameAttribute>();
// Assert
var htmlAttributeName = Assert.Single(attributes);
Assert.Equal("somename", htmlAttributeName.Name);
}
[Fact]
public void GetAttributes_DoesNotInheritAttributes()
{
// Arrange
var property = GetPropertyInfo(nameof(TestType.PropertyWithAttributes));
var runtimeProperty = new RuntimePropertyInfo(property);
// Act
var attributes = property.GetCustomAttributes<HtmlAttributeNotBoundAttribute>();
// Assert
Assert.Empty(attributes);
}
private static PropertyInfo GetPropertyInfo(string propertyName)
{
return typeof(TestType).GetRuntimeProperties()
.FirstOrDefault(p => p.Name == propertyName);
}
public class BaseType
{
[HtmlAttributeNotBound]
public virtual string PropertyWithAttributes { get; }
}
public class TestType : BaseType
{
public string Property { get; set; }
public int PrivateSetter { get; private set; }
public object PrivateGetter { private get; set; }
protected DateTimeOffset ProtectedProperty { get; set; }
public string PropertyWithoutGetter
{
set { }
}
public int PropertyWithoutSetter => 0;
[HtmlAttributeName("somename")]
public override string PropertyWithAttributes { get; }
}
}
}

View File

@ -1,159 +0,0 @@
// 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;
using System.Linq;
using System.Reflection;
using Microsoft.AspNet.Razor.Compilation.TagHelpers;
using Microsoft.AspNet.Razor.TagHelpers;
using Microsoft.AspNet.Razor.Test.Internal;
using Xunit;
namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
{
public class RuntimeTagHelperDescriptorFactoryTest : TagHelperDescriptorFactoryTest
{
public override ITypeInfo GetTypeInfo(Type tagHelperType) =>
new RuntimeTypeInfo(tagHelperType.GetTypeInfo());
[Fact]
public void CreateDescriptors_BuildsDescriptorsFromSimpleTypes()
{
// Arrange
var errorSink = new ErrorSink();
var objectAssemblyName = typeof(object).GetTypeInfo().Assembly.GetName().Name;
var expectedDescriptor =
CreateTagHelperDescriptor("object", "System.Object", objectAssemblyName);
var factory = new TagHelperDescriptorFactory(designTime: false);
// Act
var descriptors = factory.CreateDescriptors(
objectAssemblyName,
GetTypeInfo(typeof(object)),
errorSink: errorSink);
// Assert
Assert.Empty(errorSink.Errors);
var descriptor = Assert.Single(descriptors);
Assert.Equal(expectedDescriptor, descriptor, CaseSensitiveTagHelperDescriptorComparer.Default);
}
[Theory]
[MemberData(nameof(TagHelperWithPrefixData))]
public void CreateDescriptors_WithPrefixes_ReturnsExpectedAttributeDescriptors(
Type tagHelperType,
IEnumerable<TagHelperAttributeDescriptor> expectedAttributeDescriptors,
string[] expectedErrorMessages)
{
// Arrange
var errorSink = new ErrorSink();
var factory = new TagHelperDescriptorFactory(designTime: false);
// Act
var descriptors = factory.CreateDescriptors(
AssemblyName,
GetTypeInfo(tagHelperType),
errorSink: errorSink);
// Assert
var errors = errorSink.Errors.ToArray();
Assert.Equal(expectedErrorMessages.Length, errors.Length);
for (var i = 0; i < errors.Length; i++)
{
Assert.Equal(0, errors[i].Length);
Assert.Equal(SourceLocation.Zero, errors[i].Location);
Assert.Equal(expectedErrorMessages[i], errors[i].Message, StringComparer.Ordinal);
}
var descriptor = Assert.Single(descriptors);
Assert.Equal(
expectedAttributeDescriptors,
descriptor.Attributes,
TagHelperAttributeDescriptorComparer.Default);
}
// TagHelperDesignTimeDescriptors are not created in CoreCLR.
#if !DNXCORE50
public static TheoryData OutputElementHintData
{
get
{
// tagHelperType, expectedDescriptors
return new TheoryData<Type, TagHelperDescriptor[]>
{
{
typeof(OutputElementHintTagHelper),
new[]
{
new TagHelperDescriptor
{
TagName = "output-element-hint",
TypeName = typeof(OutputElementHintTagHelper).FullName,
AssemblyName = AssemblyName,
DesignTimeDescriptor = new TagHelperDesignTimeDescriptor
{
OutputElementHint = "strong"
}
}
}
},
{
typeof(MulitpleDescriptorTagHelperWithOutputElementHint),
new[]
{
new TagHelperDescriptor
{
TagName = "a",
TypeName = typeof(MulitpleDescriptorTagHelperWithOutputElementHint).FullName,
AssemblyName = AssemblyName,
DesignTimeDescriptor = new TagHelperDesignTimeDescriptor
{
OutputElementHint = "div"
}
},
new TagHelperDescriptor
{
TagName = "p",
TypeName = typeof(MulitpleDescriptorTagHelperWithOutputElementHint).FullName,
AssemblyName = AssemblyName,
DesignTimeDescriptor = new TagHelperDesignTimeDescriptor
{
OutputElementHint = "div"
}
}
}
}
};
}
}
[Theory]
[MemberData(nameof(OutputElementHintData))]
public void CreateDescriptors_CreatesDesignTimeDescriptorsWithOutputElementHint(
Type tagHelperType,
TagHelperDescriptor[] expectedDescriptors)
{
// Arrange
var errorSink = new ErrorSink();
var factory = new TagHelperDescriptorFactory(designTime: true);
// Act
var descriptors = factory.CreateDescriptors(
AssemblyName,
GetTypeInfo(tagHelperType),
errorSink: errorSink);
// Assert
Assert.Empty(errorSink.Errors);
// We don't care about order. Mono returns reflected attributes differently so we need to ensure order
// doesn't matter by sorting.
descriptors = descriptors.OrderBy(descriptor => descriptor.TagName);
Assert.Equal(expectedDescriptors, descriptors, CaseSensitiveTagHelperDescriptorComparer.Default);
}
#endif
}
}

View File

@ -1,535 +0,0 @@
// 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.ComponentModel;
using System.Reflection;
using System.Threading.Tasks;
using Microsoft.AspNet.Razor.TagHelpers;
using Microsoft.AspNet.Testing;
using Xunit;
namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
{
public class RuntimeTypeInfoTest
{
[Theory]
[InlineData(typeof(int))]
[InlineData(typeof(string))]
[InlineData(typeof(Tuple<>))]
[InlineData(typeof(Tuple<>))]
[InlineData(typeof(IDictionary<string, string>))]
[InlineData(typeof(IDictionary<string, IDictionary<string, CustomType>>))]
[InlineData(typeof(IList<IReadOnlyList<IDictionary<List<string>, Tuple<CustomType, object[]>>>>))]
[InlineData(typeof(AbstractType))]
[InlineData(typeof(PrivateType))]
[InlineData(typeof(KnownKeyDictionary<>))]
[InlineData(typeof(KnownKeyDictionary<string>))]
public void RuntimeTypeInfo_ReturnsMetadataOfAdaptingType(Type type)
{
// Arrange
var typeInfo = type.GetTypeInfo();
var runtimeTypeInfo = new RuntimeTypeInfo(typeInfo);
// Act and Assert
Assert.Same(typeInfo, runtimeTypeInfo.TypeInfo);
Assert.Equal(typeInfo.Name, runtimeTypeInfo.Name);
Assert.Equal(type.FullName, runtimeTypeInfo.FullName);
Assert.Equal(typeInfo.IsAbstract, runtimeTypeInfo.IsAbstract);
Assert.Equal(typeInfo.IsGenericType, runtimeTypeInfo.IsGenericType);
Assert.Equal(typeInfo.IsPublic, runtimeTypeInfo.IsPublic);
}
[Fact]
public void Properties_ReturnsPublicPropertiesOfAdaptingType()
{
// Arrange
var typeInfo = typeof(SubType).GetTypeInfo();
var runtimeTypeInfo = new RuntimeTypeInfo(typeInfo);
// Act and Assert
Assert.Collection(runtimeTypeInfo.Properties,
property =>
{
Assert.IsType<RuntimePropertyInfo>(property);
Assert.Equal("Property1", property.Name);
},
property =>
{
Assert.IsType<RuntimePropertyInfo>(property);
Assert.Equal("Property2", property.Name);
},
property =>
{
Assert.IsType<RuntimePropertyInfo>(property);
Assert.Equal("Property3", property.Name);
},
property =>
{
Assert.IsType<RuntimePropertyInfo>(property);
Assert.Equal("Property4", property.Name);
},
property =>
{
Assert.IsType<RuntimePropertyInfo>(property);
Assert.Equal("BaseTypeProperty", property.Name);
},
property =>
{
Assert.IsType<RuntimePropertyInfo>(property);
Assert.Equal("ProtectedProperty", property.Name);
});
}
[Fact]
public void GetCustomAttributes_ReturnsAllAttributesOfType()
{
// Arrange
var typeInfo = typeof(TypeWithAttributes).GetTypeInfo();
var runtimeTypeInfo = new RuntimeTypeInfo(typeInfo);
var expected = typeInfo.GetCustomAttributes<HtmlTargetElementAttribute>();
// Act
var actual = runtimeTypeInfo.GetCustomAttributes<HtmlTargetElementAttribute>();
// Assert
Assert.Equal(expected, actual);
}
[Fact]
public void GetCustomAttributes_DoesNotInheritAttributesFromBaseType()
{
// Arrange
var typeInfo = typeof(SubType).GetTypeInfo();
var runtimeTypeInfo = new RuntimeTypeInfo(typeInfo);
// Act
var actual = runtimeTypeInfo.GetCustomAttributes<EditorBrowsableAttribute>();
// Assert
Assert.Empty(actual);
}
[Fact]
public void ImplementsInterface_ThrowsIfArgumentIsNotRuntimeType()
{
// Arrange
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
var result = runtimeTypeInfo.ImplementsInterface(interfaceTypeInfo);
// Assert
Assert.True(result);
}
[Theory]
[InlineData(typeof(string), typeof(object))]
[InlineData(typeof(DerivesFromTagHelper), typeof(TagHelper))]
[InlineData(typeof(string), typeof(ITagHelper))]
[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
var runtimeTypeInfo = new RuntimeTypeInfo(runtimeType.GetTypeInfo());
var interfaceTypeInfo = new RuntimeTypeInfo(interfaceType.GetTypeInfo());
// Act
var result = runtimeTypeInfo.ImplementsInterface(interfaceTypeInfo);
// Assert
Assert.False(result);
}
[Theory]
[InlineData(typeof(Dictionary<string, string>), new[] { typeof(string), typeof(string) })]
[InlineData(typeof(DerivesFromDictionary), new[] { typeof(int), typeof(object) })]
[InlineData(typeof(ImplementsIDictionary), new[] { typeof(List<string>), typeof(string) })]
[InlineData(typeof(IDictionary<string, IDictionary<string, CustomType>>),
new[] { typeof(string), typeof(IDictionary<string, CustomType>) })]
[InlineData(typeof(KnownKeyDictionary<ImplementsIDictionary>),
new[] { typeof(string), typeof(ImplementsIDictionary) })]
public void GetGenericDictionaryParameters_ReturnsKeyAndValueParameterTypeNames(
Type type,
Type[] expectedTypes)
{
// Arrange
var runtimeTypeInfo = new RuntimeTypeInfo(type.GetTypeInfo());
// Act
var actual = runtimeTypeInfo.GetGenericDictionaryParameters();
// Assert
Assert.Collection(actual,
keyType =>
{
Assert.Equal(new RuntimeTypeInfo(expectedTypes[0].GetTypeInfo()), keyType);
},
valueType =>
{
Assert.Equal(new RuntimeTypeInfo(expectedTypes[1].GetTypeInfo()), valueType);
});
}
[Fact]
public void GetGenericDictionaryParameters_WorksWhenValueParameterIsOpen()
{
// Arrange
var runtimeTypeInfo = new RuntimeTypeInfo(typeof(KnownKeyDictionary<>).GetTypeInfo());
// Act
var actual = runtimeTypeInfo.GetGenericDictionaryParameters();
// Assert
Assert.Collection(actual,
keyType =>
{
Assert.Equal(new RuntimeTypeInfo(typeof(string).GetTypeInfo()), keyType);
},
valueType =>
{
Assert.Null(valueType);
});
}
[Fact]
public void GetGenericDictionaryParameters_WorksWhenKeyAndValueParametersAreOpen()
{
// Arrange
var runtimeTypeInfo = new RuntimeTypeInfo(typeof(Dictionary<,>).GetTypeInfo());
// Act
var actual = runtimeTypeInfo.GetGenericDictionaryParameters();
// Assert
Assert.Equal(new RuntimeTypeInfo[] { null, null }, actual);
}
[Theory]
[InlineData(typeof(int))]
[InlineData(typeof(string))]
[InlineData(typeof(List<string>))]
[InlineData(typeof(IDictionary))]
[InlineData(typeof(ITagHelper))]
public void GetGenericDictionaryParameterNames_ReturnsNullIfTypeDoesNotImplementGenericDictionary(Type type)
{
// Arrange
var runtimeTypeInfo = new RuntimeTypeInfo(type.GetTypeInfo());
// Act
var actual = runtimeTypeInfo.GetGenericDictionaryParameters();
// Assert
Assert.Null(actual);
}
[Theory]
[InlineData(typeof(string))]
[InlineData(typeof(IDictionary<,>))]
[InlineData(typeof(ITagHelper))]
[InlineData(typeof(TagHelper))]
public void Equals_ReturnsTrueIfTypeInfosAreIdentical(Type type)
{
// Arrange
var typeA = new RuntimeTypeInfo(type.GetTypeInfo());
var typeB = new RuntimeTypeInfo(type.GetTypeInfo());
// Act
var equals = typeA.Equals(typeB);
var hashCodeA = typeA.GetHashCode();
var hashCodeB = typeB.GetHashCode();
// Assert
Assert.True(equals);
Assert.Equal(hashCodeA, hashCodeB);
}
public static TheoryData Equals_ReturnsTrueIfTypeFullNamesAreIdenticalData =>
new TheoryData<Type, string>
{
{ typeof(string), typeof(string).FullName },
{ typeof(ITagHelper), typeof(ITagHelper).FullName },
{ typeof(TagHelper), typeof(TagHelper).FullName },
{ typeof(TagHelper), typeof(TagHelper).FullName },
{ typeof(IDictionary<,>), typeof(IDictionary<,>).FullName },
{
typeof(IDictionary<string,string>),
typeof(IDictionary<string, string>).FullName
},
};
[Theory]
[MemberData(nameof(Equals_ReturnsTrueIfTypeFullNamesAreIdenticalData))]
public void Equals_ReturnsTrueIfTypeInfoNamesAreIdentical(Type type, string fullName)
{
// Arrange
var typeA = new RuntimeTypeInfo(type.GetTypeInfo());
var typeB = new TestTypeInfo
{
FullName = fullName
};
// Act
var equals = typeA.Equals(typeB);
// Assert
Assert.True(equals);
}
[Theory]
[InlineData(typeof(string), typeof(object))]
[InlineData(typeof(IDictionary<,>), typeof(IDictionary<string, string>))]
[InlineData(typeof(KnownKeyDictionary<string>), typeof(IDictionary<string, string>))]
[InlineData(typeof(ITagHelper), typeof(TagHelper))]
public void Equals_ReturnsFalseIfTypeInfosAreDifferent(Type typeA, Type typeB)
{
// Arrange
var typeAInfo = new RuntimeTypeInfo(typeA.GetTypeInfo());
var typeBInfo = new RuntimeTypeInfo(typeB.GetTypeInfo());
// Act
var equals = typeAInfo.Equals(typeBInfo);
var hashCodeA = typeAInfo.GetHashCode();
var hashCodeB = typeBInfo.GetHashCode();
// Assert
Assert.False(equals);
Assert.NotEqual(hashCodeA, hashCodeB);
}
[Theory]
[MemberData(nameof(Equals_ReturnsTrueIfTypeFullNamesAreIdenticalData))]
public void Equals_ReturnsFalseIfTypeInfoNamesAreDifferent(Type type, string fullName)
{
// Arrange
var typeA = new RuntimeTypeInfo(type.GetTypeInfo());
var typeB = new TestTypeInfo
{
FullName = "Different" + fullName
};
// Act
var equals = typeA.Equals(typeB);
// Assert
Assert.False(equals);
}
public class AbstractType
{
}
internal class InternalType
{
}
private class PrivateType
{
}
[EditorBrowsable(EditorBrowsableState.Never)]
private class BaseType
{
public string this[string key]
{
get { return ""; }
set { }
}
public string BaseTypeProperty { get; set; }
protected int ProtectedProperty { get; set; }
}
private class SubType : BaseType
{
public string Property1 { get; set; }
public int Property2 { get; }
public object Property3 { private get; set; }
private int Property4 { get; set; }
}
[HtmlTargetElement("test1")]
[HtmlTargetElement("test2")]
private class TypeWithAttributes
{
}
private class DerivesFromTagHelper : TagHelper
{
}
private class ImplementsITagHelper : ITagHelper
{
public int Order { get; } = 0;
public void Init(TagHelperContext context)
{
}
public Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
{
throw new NotImplementedException();
}
}
private class DerivesFromDictionary : Dictionary<int, object>
{
}
private class ImplementsIDictionary : IDictionary<List<string>, string>, IReadOnlyList<int>
{
public int this[int index]
{
get
{
throw new NotImplementedException();
}
}
public string this[List<string> key]
{
get
{
throw new NotImplementedException();
}
set
{
throw new NotImplementedException();
}
}
public int Count
{
get
{
throw new NotImplementedException();
}
}
public bool IsReadOnly
{
get
{
throw new NotImplementedException();
}
}
public ICollection<List<string>> Keys
{
get
{
throw new NotImplementedException();
}
}
public ICollection<string> Values
{
get
{
throw new NotImplementedException();
}
}
public void Add(KeyValuePair<List<string>, string> item)
{
throw new NotImplementedException();
}
public void Add(List<string> key, string value)
{
throw new NotImplementedException();
}
public void Clear()
{
throw new NotImplementedException();
}
public bool Contains(KeyValuePair<List<string>, string> item)
{
throw new NotImplementedException();
}
public bool ContainsKey(List<string> key)
{
throw new NotImplementedException();
}
public void CopyTo(KeyValuePair<List<string>, string>[] array, int arrayIndex)
{
throw new NotImplementedException();
}
public IEnumerator<KeyValuePair<List<string>, string>> GetEnumerator()
{
throw new NotImplementedException();
}
public bool Remove(KeyValuePair<List<string>, string> item)
{
throw new NotImplementedException();
}
public bool Remove(List<string> key)
{
throw new NotImplementedException();
}
public bool TryGetValue(List<string> key, out string value)
{
throw new NotImplementedException();
}
IEnumerator<int> IEnumerable<int>.GetEnumerator()
{
throw new NotImplementedException();
}
IEnumerator IEnumerable.GetEnumerator()
{
throw new NotImplementedException();
}
}
public class KnownKeyDictionary<TValue> : Dictionary<string, TValue>
{
}
private class CustomType
{
}
}
}

View File

@ -12,7 +12,7 @@ using Xunit;
namespace Microsoft.AspNet.Razor.Runtime.TagHelpers namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
{ {
public abstract class TagHelperDescriptorFactoryTest public class TagHelperDescriptorFactoryTest
{ {
protected static readonly AssemblyName TagHelperDescriptorFactoryTestAssembly = protected static readonly AssemblyName TagHelperDescriptorFactoryTestAssembly =
typeof(TagHelperDescriptorFactoryTest).GetTypeInfo().Assembly.GetName(); typeof(TagHelperDescriptorFactoryTest).GetTypeInfo().Assembly.GetName();
@ -93,7 +93,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
// Act // Act
var descriptors = factory.CreateDescriptors( var descriptors = factory.CreateDescriptors(
AssemblyName, AssemblyName,
GetTypeInfo(tagHelperType), tagHelperType,
errorSink: errorSink); errorSink: errorSink);
// Assert // Assert
@ -182,7 +182,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
// Act // Act
var descriptors = factory.CreateDescriptors( var descriptors = factory.CreateDescriptors(
AssemblyName, AssemblyName,
GetTypeInfo(tagHelperType), tagHelperType,
errorSink: errorSink); errorSink: errorSink);
// Assert // Assert
@ -252,7 +252,6 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
} }
} }
public abstract ITypeInfo GetTypeInfo(Type tagHelperType);
[Theory] [Theory]
[MemberData(nameof(RestrictChildrenData))] [MemberData(nameof(RestrictChildrenData))]
@ -267,7 +266,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
// Act // Act
var descriptors = factory.CreateDescriptors( var descriptors = factory.CreateDescriptors(
AssemblyName, AssemblyName,
GetTypeInfo(tagHelperType), tagHelperType,
errorSink: errorSink); errorSink: errorSink);
// Assert // Assert
@ -356,7 +355,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
// Act // Act
var descriptors = factory.CreateDescriptors( var descriptors = factory.CreateDescriptors(
AssemblyName, AssemblyName,
GetTypeInfo(tagHelperType), tagHelperType,
errorSink: errorSink); errorSink: errorSink);
// Assert // Assert
@ -592,7 +591,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
// Act // Act
var descriptors = factory.CreateDescriptors( var descriptors = factory.CreateDescriptors(
AssemblyName, AssemblyName,
GetTypeInfo(tagHelperType), tagHelperType,
errorSink); errorSink);
// Assert // Assert
@ -794,7 +793,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
// Act // Act
var descriptors = factory.CreateDescriptors( var descriptors = factory.CreateDescriptors(
AssemblyName, AssemblyName,
GetTypeInfo(tagHelperType), tagHelperType,
errorSink: errorSink); errorSink: errorSink);
// Assert // Assert
@ -843,7 +842,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
// Act // Act
var descriptors = factory.CreateDescriptors( var descriptors = factory.CreateDescriptors(
AssemblyName, AssemblyName,
GetTypeInfo(tagHelperType), tagHelperType,
errorSink: errorSink); errorSink: errorSink);
// Assert // Assert
@ -880,7 +879,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
// Act // Act
var descriptors = factory.CreateDescriptors( var descriptors = factory.CreateDescriptors(
AssemblyName, AssemblyName,
GetTypeInfo(typeof(OverriddenAttributeTagHelper)), typeof(OverriddenAttributeTagHelper),
errorSink: errorSink); errorSink: errorSink);
// Assert // Assert
@ -914,7 +913,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
// Act // Act
var descriptors = factory.CreateDescriptors( var descriptors = factory.CreateDescriptors(
AssemblyName, AssemblyName,
GetTypeInfo(typeof(InheritedOverriddenAttributeTagHelper)), typeof(InheritedOverriddenAttributeTagHelper),
errorSink: errorSink); errorSink: errorSink);
// Assert // Assert
@ -948,7 +947,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
// Act // Act
var descriptors = factory.CreateDescriptors( var descriptors = factory.CreateDescriptors(
AssemblyName, AssemblyName,
GetTypeInfo(typeof(InheritedNotOverriddenAttributeTagHelper)), typeof(InheritedNotOverriddenAttributeTagHelper),
errorSink: errorSink); errorSink: errorSink);
// Assert // Assert
Assert.Empty(errorSink.Errors); Assert.Empty(errorSink.Errors);
@ -978,7 +977,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
// Act // Act
var descriptors = factory.CreateDescriptors( var descriptors = factory.CreateDescriptors(
AssemblyName, AssemblyName,
GetTypeInfo(typeof(InheritedSingleAttributeTagHelper)), typeof(InheritedSingleAttributeTagHelper),
errorSink: errorSink); errorSink: errorSink);
// Assert // Assert
@ -1006,7 +1005,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
// Act // Act
var descriptors = factory.CreateDescriptors( var descriptors = factory.CreateDescriptors(
AssemblyName, AssemblyName,
GetTypeInfo(typeof(SingleAttributeTagHelper)), typeof(SingleAttributeTagHelper),
errorSink: new ErrorSink()); errorSink: new ErrorSink());
// Assert // Assert
@ -1035,7 +1034,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
// Act // Act
var descriptors = factory.CreateDescriptors( var descriptors = factory.CreateDescriptors(
AssemblyName, AssemblyName,
GetTypeInfo(typeof(MissingAccessorTagHelper)), typeof(MissingAccessorTagHelper),
errorSink: errorSink); errorSink: errorSink);
// Assert // Assert
@ -1064,7 +1063,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
// Act // Act
var descriptors = factory.CreateDescriptors( var descriptors = factory.CreateDescriptors(
AssemblyName, AssemblyName,
GetTypeInfo(typeof(NonPublicAccessorTagHelper)), typeof(NonPublicAccessorTagHelper),
errorSink: errorSink); errorSink: errorSink);
// Assert // Assert
@ -1096,7 +1095,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
// Act // Act
var descriptors = factory.CreateDescriptors( var descriptors = factory.CreateDescriptors(
AssemblyName, AssemblyName,
GetTypeInfo(typeof(NotBoundAttributeTagHelper)), typeof(NotBoundAttributeTagHelper),
errorSink: errorSink); errorSink: errorSink);
// Assert // Assert
@ -1115,7 +1114,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
// Act // Act
var descriptors = factory.CreateDescriptors( var descriptors = factory.CreateDescriptors(
AssemblyName, AssemblyName,
GetTypeInfo(typeof(DuplicateAttributeNameTagHelper)), typeof(DuplicateAttributeNameTagHelper),
errorSink: errorSink); errorSink: errorSink);
// Assert // Assert
@ -1164,7 +1163,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
// Act // Act
var descriptors = factory.CreateDescriptors( var descriptors = factory.CreateDescriptors(
AssemblyName, AssemblyName,
GetTypeInfo(typeof(MultiTagTagHelper)), typeof(MultiTagTagHelper),
errorSink: errorSink); errorSink: errorSink);
// Assert // Assert
@ -1196,7 +1195,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
// Act // Act
var descriptors = factory.CreateDescriptors( var descriptors = factory.CreateDescriptors(
AssemblyName, AssemblyName,
GetTypeInfo(typeof(InheritedMultiTagTagHelper)), typeof(InheritedMultiTagTagHelper),
errorSink: errorSink); errorSink: errorSink);
// Assert // Assert
@ -1226,7 +1225,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
// Act // Act
var descriptors = factory.CreateDescriptors( var descriptors = factory.CreateDescriptors(
AssemblyName, AssemblyName,
GetTypeInfo(typeof(DuplicateTagNameTagHelper)), typeof(DuplicateTagNameTagHelper),
errorSink: errorSink); errorSink: errorSink);
// Assert // Assert
@ -1256,7 +1255,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
// Act // Act
var descriptors = factory.CreateDescriptors( var descriptors = factory.CreateDescriptors(
AssemblyName, AssemblyName,
GetTypeInfo(typeof(OverrideNameTagHelper)), typeof(OverrideNameTagHelper),
errorSink: errorSink); errorSink: errorSink);
// Assert // Assert
@ -1444,7 +1443,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
// Act // Act
var descriptors = factory.CreateDescriptors( var descriptors = factory.CreateDescriptors(
AssemblyName, AssemblyName,
GetTypeInfo(type), type,
errorSink: errorSink); errorSink: errorSink);
// Assert // Assert
@ -1694,7 +1693,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
// Act // Act
var result = TagHelperDescriptorFactory.ValidateTagHelperAttributeDescriptor( var result = TagHelperDescriptorFactory.ValidateTagHelperAttributeDescriptor(
descriptor, descriptor,
GetTypeInfo(typeof(MultiTagTagHelper)), typeof(MultiTagTagHelper),
errorSink); errorSink);
// Assert // Assert
@ -1736,7 +1735,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
// Act // Act
var result = TagHelperDescriptorFactory.ValidateTagHelperAttributeDescriptor( var result = TagHelperDescriptorFactory.ValidateTagHelperAttributeDescriptor(
descriptor, descriptor,
GetTypeInfo(typeof(MultiTagTagHelper)), typeof(MultiTagTagHelper),
errorSink); errorSink);
// Assert // Assert
@ -1782,7 +1781,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
// Act // Act
var result = TagHelperDescriptorFactory.ValidateTagHelperAttributeDescriptor( var result = TagHelperDescriptorFactory.ValidateTagHelperAttributeDescriptor(
descriptor, descriptor,
GetTypeInfo(typeof(MultiTagTagHelper)), typeof(MultiTagTagHelper),
errorSink); errorSink);
// Assert // Assert
@ -1837,7 +1836,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
// Act // Act
var result = TagHelperDescriptorFactory.ValidateTagHelperAttributeDescriptor( var result = TagHelperDescriptorFactory.ValidateTagHelperAttributeDescriptor(
descriptor, descriptor,
GetTypeInfo(typeof(MultiTagTagHelper)), typeof(MultiTagTagHelper),
errorSink); errorSink);
// Assert // Assert
@ -1925,6 +1924,145 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
Assert.Equal(expectedErrors, errorSink.Errors); Assert.Equal(expectedErrors, errorSink.Errors);
} }
[Fact]
public void CreateDescriptors_BuildsDescriptorsFromSimpleTypes()
{
// Arrange
var errorSink = new ErrorSink();
var objectAssemblyName = typeof(object).GetTypeInfo().Assembly.GetName().Name;
var expectedDescriptor =
CreateTagHelperDescriptor("object", "System.Object", objectAssemblyName);
var factory = new TagHelperDescriptorFactory(designTime: false);
// Act
var descriptors = factory.CreateDescriptors(
objectAssemblyName,
typeof(object),
errorSink: errorSink);
// Assert
Assert.Empty(errorSink.Errors);
var descriptor = Assert.Single(descriptors);
Assert.Equal(expectedDescriptor, descriptor, CaseSensitiveTagHelperDescriptorComparer.Default);
}
[Theory]
[MemberData(nameof(TagHelperWithPrefixData))]
public void CreateDescriptors_WithPrefixes_ReturnsExpectedAttributeDescriptors(
Type tagHelperType,
IEnumerable<TagHelperAttributeDescriptor> expectedAttributeDescriptors,
string[] expectedErrorMessages)
{
// Arrange
var errorSink = new ErrorSink();
var factory = new TagHelperDescriptorFactory(designTime: false);
// Act
var descriptors = factory.CreateDescriptors(
AssemblyName,
tagHelperType,
errorSink: errorSink);
// Assert
var errors = errorSink.Errors.ToArray();
Assert.Equal(expectedErrorMessages.Length, errors.Length);
for (var i = 0; i < errors.Length; i++)
{
Assert.Equal(0, errors[i].Length);
Assert.Equal(SourceLocation.Zero, errors[i].Location);
Assert.Equal(expectedErrorMessages[i], errors[i].Message, StringComparer.Ordinal);
}
var descriptor = Assert.Single(descriptors);
Assert.Equal(
expectedAttributeDescriptors,
descriptor.Attributes,
TagHelperAttributeDescriptorComparer.Default);
}
// TagHelperDesignTimeDescriptors are not created in CoreCLR.
#if !DNXCORE50
public static TheoryData OutputElementHintData
{
get
{
// tagHelperType, expectedDescriptors
return new TheoryData<Type, TagHelperDescriptor[]>
{
{
typeof(OutputElementHintTagHelper),
new[]
{
new TagHelperDescriptor
{
TagName = "output-element-hint",
TypeName = typeof(OutputElementHintTagHelper).FullName,
AssemblyName = AssemblyName,
DesignTimeDescriptor = new TagHelperDesignTimeDescriptor
{
OutputElementHint = "strong"
}
}
}
},
{
typeof(MulitpleDescriptorTagHelperWithOutputElementHint),
new[]
{
new TagHelperDescriptor
{
TagName = "a",
TypeName = typeof(MulitpleDescriptorTagHelperWithOutputElementHint).FullName,
AssemblyName = AssemblyName,
DesignTimeDescriptor = new TagHelperDesignTimeDescriptor
{
OutputElementHint = "div"
}
},
new TagHelperDescriptor
{
TagName = "p",
TypeName = typeof(MulitpleDescriptorTagHelperWithOutputElementHint).FullName,
AssemblyName = AssemblyName,
DesignTimeDescriptor = new TagHelperDesignTimeDescriptor
{
OutputElementHint = "div"
}
}
}
}
};
}
}
[Theory]
[MemberData(nameof(OutputElementHintData))]
public void CreateDescriptors_CreatesDesignTimeDescriptorsWithOutputElementHint(
Type tagHelperType,
TagHelperDescriptor[] expectedDescriptors)
{
// Arrange
var errorSink = new ErrorSink();
var factory = new TagHelperDescriptorFactory(designTime: true);
// Act
var descriptors = factory.CreateDescriptors(
AssemblyName,
tagHelperType,
errorSink: errorSink);
// Assert
Assert.Empty(errorSink.Errors);
// We don't care about order. Mono returns reflected attributes differently so we need to ensure order
// doesn't matter by sorting.
descriptors = descriptors.OrderBy(descriptor => descriptor.TagName);
Assert.Equal(expectedDescriptors, descriptors, CaseSensitiveTagHelperDescriptorComparer.Default);
}
#endif
private static TheoryData<string, string[]> GetInvalidNameOrPrefixData( private static TheoryData<string, string[]> GetInvalidNameOrPrefixData(
Func<string, string, string> onNameError, Func<string, string, string> onNameError,
string whitespaceErrorString, string whitespaceErrorString,

View File

@ -1414,7 +1414,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
return types?.Select(type => type.GetTypeInfo()) ?? Enumerable.Empty<TypeInfo>(); return types?.Select(type => type.GetTypeInfo()) ?? Enumerable.Empty<TypeInfo>();
} }
internal override bool IsTagHelper(ITypeInfo typeInfo) internal override bool IsTagHelper(TypeInfo typeInfo)
{ {
return true; return true;
} }

View File

@ -66,13 +66,11 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
Assert.Collection(types, Assert.Collection(types,
type => type =>
{ {
var typeInfo = Assert.IsType<RuntimeTypeInfo>(type); Assert.Equal(typeof(Valid_PlainTagHelper), type);
Assert.Equal(typeof(Valid_PlainTagHelper).GetTypeInfo(), typeInfo.TypeInfo);
}, },
type => type =>
{ {
var typeInfo = Assert.IsType<RuntimeTypeInfo>(type); Assert.Equal(typeof(Valid_InheritedTagHelper), type);
Assert.Equal(typeof(Valid_InheritedTagHelper).GetTypeInfo(), typeInfo.TypeInfo);
}); });
} }

View File

@ -1,9 +0,0 @@
// 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.
namespace Microsoft.AspNet.Razor.Fake
{
public class DoesNotImplementRealITagHelper : Microsoft.AspNet.Razor.Fake.ITagHelper
{
}
}

View File

@ -1,14 +0,0 @@
// 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.Threading.Tasks;
using Microsoft.AspNet.Razor.TagHelpers;
namespace Microsoft.AspNet.Razor.Fake
{
public interface ITagHelper
{
}
}

View File

@ -1,30 +0,0 @@
// 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.Threading.Tasks;
using Microsoft.AspNet.Razor.TagHelpers;
namespace Microsoft.AspNet.Razor.Fake
{
public class ImplementsRealITagHelper : Microsoft.AspNet.Razor.TagHelpers.ITagHelper
{
public int Order
{
get
{
throw new NotImplementedException();
}
}
public void Init(TagHelperContext context)
{
}
public Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
{
throw new NotImplementedException();
}
}
}

View File

@ -429,58 +429,4 @@ namespace Microsoft.AspNet.Razor.TagHelpers
public class MulitpleDescriptorTagHelperWithOutputElementHint : TagHelper public class MulitpleDescriptorTagHelperWithOutputElementHint : TagHelper
{ {
} }
public class TypeDerivingFromITagHelper : ITagHelper
{
public int Order { get; } = 0;
public void Init(TagHelperContext context)
{
}
public Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
{
throw new NotImplementedException();
}
}
public class BaseAttribute : Attribute
{
public string BaseProperty { get; set; }
}
public class DerivedAttribute : BaseAttribute
{
public string DerivedProperty { get; set; }
}
public class BaseTagHelper : TagHelper
{
[Derived(DerivedProperty = "DerivedPropertyValue")]
public string BaseProperty { get; set; }
[HtmlAttributeNotBound]
public virtual string VirtualProperty { get; set; }
public int NewProperty { get; set; }
public virtual new string Order { get; set; }
}
public class DerivedTagHelper : BaseTagHelper
{
public override string VirtualProperty { get; set; }
[Base(BaseProperty = "BaseValue")]
public string DerivedProperty { get; set; }
[HtmlAttributeName("new-property")]
public new Type NewProperty { get; set; }
public override string Order { get; set; }
}
}
public class TagHelperInGlobalNamespace : TagHelper
{
} }

View File

@ -1,81 +0,0 @@
// 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 IsEnum
{
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();
}
}
}