Update `TagHelperDesignTimeDescriptorFactory` to work in CoreCLR.

- After discussion offline to maintain consistency we decided to also remove `CodeBase` fallback in the net451 scenario. This will keep CoreCLR and net451 scenarios more consistent.
- Removed `CodeBase` validation tests.
- Added `GetAssemblyLocation` extensibility point to enable proper testing of the `TagHelperDesignTimeDescriptorFactory`.

#709
This commit is contained in:
N. Taylor Mullen 2016-03-16 14:53:26 -07:00
parent dd9c92a990
commit 3d0bf621f3
6 changed files with 103 additions and 177 deletions

View File

@ -34,9 +34,7 @@ namespace Microsoft.AspNetCore.Razor.Runtime.TagHelpers
RegexOptions.None, RegexOptions.None,
Constants.RegexMatchTimeout); Constants.RegexMatchTimeout);
#if !NETSTANDARD1_3
private readonly TagHelperDesignTimeDescriptorFactory _designTimeDescriptorFactory; private readonly TagHelperDesignTimeDescriptorFactory _designTimeDescriptorFactory;
#endif
private readonly bool _designTime; private readonly bool _designTime;
// TODO: Investigate if we should cache TagHelperDescriptors for types: // TODO: Investigate if we should cache TagHelperDescriptors for types:
@ -53,12 +51,10 @@ namespace Microsoft.AspNetCore.Razor.Runtime.TagHelpers
/// </param> /// </param>
public TagHelperDescriptorFactory(bool designTime) public TagHelperDescriptorFactory(bool designTime)
{ {
#if !NETSTANDARD1_3
if (designTime) if (designTime)
{ {
_designTimeDescriptorFactory = new TagHelperDesignTimeDescriptorFactory(); _designTimeDescriptorFactory = new TagHelperDesignTimeDescriptorFactory();
} }
#endif
_designTime = designTime; _designTime = designTime;
} }
@ -129,12 +125,10 @@ namespace Microsoft.AspNetCore.Razor.Runtime.TagHelpers
{ {
TagHelperDesignTimeDescriptor typeDesignTimeDescriptor = null; TagHelperDesignTimeDescriptor typeDesignTimeDescriptor = null;
#if !NETSTANDARD1_3
if (_designTime) if (_designTime)
{ {
typeDesignTimeDescriptor = _designTimeDescriptorFactory.CreateDescriptor(type); typeDesignTimeDescriptor = _designTimeDescriptorFactory.CreateDescriptor(type);
} }
#endif
var typeName = type.FullName; var typeName = type.FullName;
@ -689,12 +683,10 @@ namespace Microsoft.AspNetCore.Razor.Runtime.TagHelpers
{ {
TagHelperAttributeDesignTimeDescriptor propertyDesignTimeDescriptor = null; TagHelperAttributeDesignTimeDescriptor propertyDesignTimeDescriptor = null;
#if !NETSTANDARD1_3
if (_designTime) if (_designTime)
{ {
propertyDesignTimeDescriptor = _designTimeDescriptorFactory.CreateAttributeDescriptor(property); propertyDesignTimeDescriptor = _designTimeDescriptorFactory.CreateAttributeDescriptor(property);
} }
#endif
return new TagHelperAttributeDescriptor return new TagHelperAttributeDescriptor
{ {

View File

@ -1,7 +1,6 @@
// Copyright (c) .NET Foundation. All rights reserved. // 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. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
#if !NETSTANDARD1_3 // Cannot accurately resolve the location of the documentation XML file in coreclr.
using System; using System;
using System.Collections.Concurrent; using System.Collections.Concurrent;
using System.Collections.Generic; using System.Collections.Generic;
@ -40,10 +39,10 @@ namespace Microsoft.AspNetCore.Razor.Runtime.TagHelpers
} }
var id = XmlDocumentationProvider.GetId(type); var id = XmlDocumentationProvider.GetId(type);
var documentationDescriptor = CreateDocumentationDescriptor(type.Assembly, id); var documentationDescriptor = CreateDocumentationDescriptor(type.GetTypeInfo().Assembly, id);
// Purposefully not using the TypeInfo.GetCustomAttributes method here to make it easier to mock the Type.
var outputElementHintAttribute = type var outputElementHintAttribute = type
.GetTypeInfo()
.GetCustomAttributes(inherit: false) .GetCustomAttributes(inherit: false)
?.OfType<OutputElementHintAttribute>() ?.OfType<OutputElementHintAttribute>()
.FirstOrDefault(); .FirstOrDefault();
@ -79,7 +78,7 @@ namespace Microsoft.AspNetCore.Razor.Runtime.TagHelpers
} }
var id = XmlDocumentationProvider.GetId(propertyInfo); var id = XmlDocumentationProvider.GetId(propertyInfo);
var declaringAssembly = propertyInfo.DeclaringType.Assembly; var declaringAssembly = propertyInfo.DeclaringType.GetTypeInfo().Assembly;
var documentationDescriptor = CreateDocumentationDescriptor(declaringAssembly, id); var documentationDescriptor = CreateDocumentationDescriptor(declaringAssembly, id);
if (documentationDescriptor != null) if (documentationDescriptor != null)
{ {
@ -93,6 +92,18 @@ namespace Microsoft.AspNetCore.Razor.Runtime.TagHelpers
return null; return null;
} }
/// <summary>
/// Retrieves <paramref name="assembly"/>'s location on disk.
/// </summary>
/// <param name="assembly">The assembly.</param>
/// <returns>The path to the given <paramref name="assembly"/>.</returns>
public virtual string GetAssemblyLocation(Assembly assembly)
{
var assemblyLocation = assembly.Location;
return assemblyLocation;
}
private XmlDocumentationProvider GetXmlDocumentationProvider(Assembly assembly) private XmlDocumentationProvider GetXmlDocumentationProvider(Assembly assembly)
{ {
var hashCodeCombiner = HashCodeCombiner.Start(); var hashCodeCombiner = HashCodeCombiner.Start();
@ -102,15 +113,7 @@ namespace Microsoft.AspNetCore.Razor.Runtime.TagHelpers
var documentationProvider = _documentationProviderCache.GetOrAdd(cacheKey, valueFactory: _ => var documentationProvider = _documentationProviderCache.GetOrAdd(cacheKey, valueFactory: _ =>
{ {
var assemblyLocation = assembly.Location; var assemblyLocation = GetAssemblyLocation(assembly);
if (string.IsNullOrEmpty(assemblyLocation) && !string.IsNullOrEmpty(assembly.CodeBase))
{
var uri = new UriBuilder(assembly.CodeBase);
// Normalize the path to UNC path. This will remove things like file:// from start of uri.Path.
assemblyLocation = Uri.UnescapeDataString(uri.Path);
}
// Couldn't resolve a valid assemblyLocation. // Couldn't resolve a valid assemblyLocation.
if (string.IsNullOrEmpty(assemblyLocation)) if (string.IsNullOrEmpty(assemblyLocation))
@ -234,5 +237,4 @@ namespace Microsoft.AspNetCore.Razor.Runtime.TagHelpers
public string Remarks { get; set; } public string Remarks { get; set; }
} }
} }
} }
#endif

View File

@ -1,7 +1,6 @@
// Copyright (c) .NET Foundation. All rights reserved. // 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. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
#if !NETSTANDARD1_3
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
@ -125,5 +124,4 @@ namespace Microsoft.AspNetCore.Razor.Runtime.TagHelpers
return stringBuilder.ToString().Trim(); return stringBuilder.ToString().Trim();
} }
} }
} }
#endif

View File

@ -56,9 +56,12 @@
}, },
"netstandard1.3": { "netstandard1.3": {
"dependencies": { "dependencies": {
"System.Collections.Concurrent": "4.0.12-*",
"System.Reflection": "4.1.0-*",
"System.Reflection.Extensions": "4.0.1-*", "System.Reflection.Extensions": "4.0.1-*",
"System.Reflection.TypeExtensions": "4.1.0-*", "System.Reflection.TypeExtensions": "4.1.0-*",
"System.Text.RegularExpressions": "4.0.12-*" "System.Text.RegularExpressions": "4.0.12-*",
"System.Xml.XDocument": "4.0.11-*"
}, },
"imports": [ "imports": [
"dotnet5.4" "dotnet5.4"

View File

@ -1,7 +1,6 @@
// Copyright (c) .NET Foundation. All rights reserved. // 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. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
#if !NETSTANDARDAPP1_5
using System; using System;
using System.IO; using System.IO;
using System.Reflection; using System.Reflection;
@ -36,7 +35,7 @@ namespace Microsoft.AspNetCore.Razor.Runtime.TagHelpers
#if NET451 #if NET451
Path.GetFullPath(Path.Combine(Directory.GetCurrentDirectory(), "..", "..", "..", "..")); Path.GetFullPath(Path.Combine(Directory.GetCurrentDirectory(), "..", "..", "..", ".."));
#else #else
Path.GetFullPath(Path.Combine(Directory.GetCurrentDirectory(), "..", "..")); Directory.GetCurrentDirectory();
#endif #endif
public static readonly string DocumentedAssemblyLocation = public static readonly string DocumentedAssemblyLocation =
Path.Combine(TestRoot, "TestFiles", "NotLocalized", "TagHelperDocumentation.dll"); Path.Combine(TestRoot, "TestFiles", "NotLocalized", "TagHelperDocumentation.dll");
@ -104,12 +103,13 @@ namespace Microsoft.AspNetCore.Razor.Runtime.TagHelpers
OutputElementHint = "p" OutputElementHint = "p"
}; };
// tagHelperType, expectedDesignTimeDescriptor // tagHelperType, assemblyLocation, expectedDesignTimeDescriptor
return new TheoryData<Type, TagHelperDesignTimeDescriptor> return new TheoryData<Type, string, TagHelperDesignTimeDescriptor>
{ {
{ CreateDocumentationTagHelperType(location: null, codeBase: null), onlyHint }, { typeof(DocumentedTagHelper), null, onlyHint },
{ {
CreateDocumentationTagHelperType(defaultLocation, codeBase: null), typeof(DocumentedTagHelper),
defaultLocation,
new TagHelperDesignTimeDescriptor new TagHelperDesignTimeDescriptor
{ {
Summary = TypeSummary, Summary = TypeSummary,
@ -117,29 +117,9 @@ namespace Microsoft.AspNetCore.Razor.Runtime.TagHelpers
OutputElementHint = "p" OutputElementHint = "p"
} }
}, },
{ { typeof(SingleAttributeTagHelper), defaultLocation, null },
CreateDocumentationTagHelperType(location: null, codeBase: defaultCodeBase), { typeof(DocumentedTagHelper), nonExistentLocation, onlyHint },
new TagHelperDesignTimeDescriptor { typeof(SingleAttributeTagHelper), invalidLocation, null },
{
Summary = TypeSummary,
Remarks = TypeRemarks,
OutputElementHint = "p"
}
},
{
CreateDocumentationTagHelperType(defaultLocation, defaultCodeBase),
new TagHelperDesignTimeDescriptor
{
Summary = TypeSummary,
Remarks = TypeRemarks,
OutputElementHint = "p"
}
},
{ CreateType<SingleAttributeTagHelper>(defaultLocation, defaultCodeBase), null },
{ CreateDocumentationTagHelperType(nonExistentLocation, codeBase: null), onlyHint },
{ CreateDocumentationTagHelperType(location: null, codeBase: nonExistentCodeBase), onlyHint },
{ CreateType<SingleAttributeTagHelper>(invalidLocation, codeBase: null), null },
{ CreateDocumentationTagHelperType(location: null, codeBase: invalidCodeBase), onlyHint },
}; };
} }
} }
@ -148,10 +128,11 @@ namespace Microsoft.AspNetCore.Razor.Runtime.TagHelpers
[MemberData(nameof(CreateDescriptor_TypeDocumentationData))] [MemberData(nameof(CreateDescriptor_TypeDocumentationData))]
public void CreateDescriptor_WithType_ReturnsExpectedDescriptors( public void CreateDescriptor_WithType_ReturnsExpectedDescriptors(
Type tagHelperType, Type tagHelperType,
string assemblyLocation,
TagHelperDesignTimeDescriptor expectedDesignTimeDescriptor) TagHelperDesignTimeDescriptor expectedDesignTimeDescriptor)
{ {
// Arrange // Arrange
var factory = new TagHelperDesignTimeDescriptorFactory(); var factory = new TestTagHelperDesignTimeDescriptorFactory(assemblyLocation);
// Act // Act
var designTimeDescriptor = factory.CreateDescriptor(tagHelperType); var designTimeDescriptor = factory.CreateDescriptor(tagHelperType);
@ -164,11 +145,12 @@ namespace Microsoft.AspNetCore.Razor.Runtime.TagHelpers
{ {
get get
{ {
// tagHelperType, expectedDesignTimeDescriptor, culture // tagHelperType, assemblyLocation, expectedDesignTimeDescriptor, culture
return new TheoryData<Type, TagHelperDesignTimeDescriptor, string> return new TheoryData<Type, string, TagHelperDesignTimeDescriptor, string>
{ {
{ {
CreateDocumentationTagHelperType(LocalizedDocumentedAssemblyLocation, codeBase: null), typeof(DocumentedTagHelper),
LocalizedDocumentedAssemblyLocation,
new TagHelperDesignTimeDescriptor new TagHelperDesignTimeDescriptor
{ {
Summary = "en-GB: " + TypeSummary, Summary = "en-GB: " + TypeSummary,
@ -178,7 +160,8 @@ namespace Microsoft.AspNetCore.Razor.Runtime.TagHelpers
"en-GB" "en-GB"
}, },
{ {
CreateDocumentationTagHelperType(LocalizedDocumentedAssemblyLocation, codeBase: null), typeof(DocumentedTagHelper),
LocalizedDocumentedAssemblyLocation,
new TagHelperDesignTimeDescriptor new TagHelperDesignTimeDescriptor
{ {
Summary = "en: " + TypeSummary, Summary = "en: " + TypeSummary,
@ -188,7 +171,8 @@ namespace Microsoft.AspNetCore.Razor.Runtime.TagHelpers
"en-US" "en-US"
}, },
{ {
CreateDocumentationTagHelperType(LocalizedDocumentedAssemblyLocation, codeBase: null), typeof(DocumentedTagHelper),
LocalizedDocumentedAssemblyLocation,
new TagHelperDesignTimeDescriptor new TagHelperDesignTimeDescriptor
{ {
Summary = "fr-FR: " + TypeSummary, Summary = "fr-FR: " + TypeSummary,
@ -198,7 +182,8 @@ namespace Microsoft.AspNetCore.Razor.Runtime.TagHelpers
"fr-FR" "fr-FR"
}, },
{ {
CreateDocumentationTagHelperType(LocalizedDocumentedAssemblyLocation, codeBase: null), typeof(DocumentedTagHelper),
LocalizedDocumentedAssemblyLocation,
new TagHelperDesignTimeDescriptor new TagHelperDesignTimeDescriptor
{ {
Summary = "fr: " + TypeSummary, Summary = "fr: " + TypeSummary,
@ -208,7 +193,8 @@ namespace Microsoft.AspNetCore.Razor.Runtime.TagHelpers
"fr-BE" "fr-BE"
}, },
{ {
CreateDocumentationTagHelperType(LocalizedDocumentedAssemblyLocation, codeBase: null), typeof(DocumentedTagHelper),
LocalizedDocumentedAssemblyLocation,
new TagHelperDesignTimeDescriptor new TagHelperDesignTimeDescriptor
{ {
Summary = "nl-BE: " + TypeSummary, Summary = "nl-BE: " + TypeSummary,
@ -225,12 +211,13 @@ namespace Microsoft.AspNetCore.Razor.Runtime.TagHelpers
[MemberData(nameof(CreateDescriptor_LocalizedTypeDocumentationData))] [MemberData(nameof(CreateDescriptor_LocalizedTypeDocumentationData))]
public void CreateDescriptor_WithLocalizedType_ReturnsExpectedDescriptors( public void CreateDescriptor_WithLocalizedType_ReturnsExpectedDescriptors(
Type tagHelperType, Type tagHelperType,
string assemblyLocation,
TagHelperDesignTimeDescriptor expectedDesignTimeDescriptor, TagHelperDesignTimeDescriptor expectedDesignTimeDescriptor,
string culture) string culture)
{ {
// Arrange // Arrange
TagHelperDesignTimeDescriptor designTimeDescriptor; TagHelperDesignTimeDescriptor designTimeDescriptor;
var factory = new TagHelperDesignTimeDescriptorFactory(); var factory = new TestTagHelperDesignTimeDescriptorFactory(assemblyLocation);
// Act // Act
using (new CultureReplacer(culture)) using (new CultureReplacer(culture))
@ -246,7 +233,7 @@ namespace Microsoft.AspNetCore.Razor.Runtime.TagHelpers
public void CreateDescriptor_WithLocalizedType_CachesBasedOnCulture() public void CreateDescriptor_WithLocalizedType_CachesBasedOnCulture()
{ {
// Arrange // Arrange
var factory = new TagHelperDesignTimeDescriptorFactory(); var factory = new TestTagHelperDesignTimeDescriptorFactory(LocalizedDocumentedAssemblyLocation);
var expectedFRDesignTimeDescriptor = new TagHelperDesignTimeDescriptor var expectedFRDesignTimeDescriptor = new TagHelperDesignTimeDescriptor
{ {
Summary = "fr-FR: " + TypeSummary, Summary = "fr-FR: " + TypeSummary,
@ -259,7 +246,7 @@ namespace Microsoft.AspNetCore.Razor.Runtime.TagHelpers
Remarks = "nl-BE: " + TypeRemarks, Remarks = "nl-BE: " + TypeRemarks,
OutputElementHint = "p", OutputElementHint = "p",
}; };
var tagHelperType = CreateDocumentationTagHelperType(LocalizedDocumentedAssemblyLocation, codeBase: null); var tagHelperType = typeof(DocumentedTagHelper);
TagHelperDesignTimeDescriptor frDesignTimeDescriptor, nlBEDesignTimeDescriptor; TagHelperDesignTimeDescriptor frDesignTimeDescriptor, nlBEDesignTimeDescriptor;
// Act // Act
@ -294,48 +281,55 @@ namespace Microsoft.AspNetCore.Razor.Runtime.TagHelpers
var invalidLocation = defaultLocation + '\0'; var invalidLocation = defaultLocation + '\0';
var invalidCodeBase = defaultCodeBase + '\0'; var invalidCodeBase = defaultCodeBase + '\0';
// tagHelperType, propertyName, expectedDesignTimeDescriptor // tagHelperType, propertyName, assemblyLocation, expectedDesignTimeDescriptor
return new TheoryData<Type, string, TagHelperAttributeDesignTimeDescriptor> return new TheoryData<Type, string, string, TagHelperAttributeDesignTimeDescriptor>
{ {
{ {
CreateDocumentationTagHelperType(location: null, codeBase: null), typeof(DocumentedTagHelper),
nameof(DocumentedTagHelper.SummaryProperty), nameof(DocumentedTagHelper.SummaryProperty),
null,
null null
}, },
{ {
CreateDocumentationTagHelperType(location: null, codeBase: null), typeof(DocumentedTagHelper),
nameof(DocumentedTagHelper.RemarksProperty), nameof(DocumentedTagHelper.RemarksProperty),
null,
null null
}, },
{ {
CreateDocumentationTagHelperType(location: null, codeBase: null), typeof(DocumentedTagHelper),
nameof(DocumentedTagHelper.RemarksAndSummaryProperty), nameof(DocumentedTagHelper.RemarksAndSummaryProperty),
null,
null null
}, },
{ {
CreateDocumentationTagHelperType(defaultLocation, defaultCodeBase), typeof(DocumentedTagHelper),
nameof(DocumentedTagHelper.UndocumentedProperty), nameof(DocumentedTagHelper.UndocumentedProperty),
defaultLocation,
null null
}, },
{ {
CreateDocumentationTagHelperType(defaultLocation, codeBase: null), typeof(DocumentedTagHelper),
nameof(DocumentedTagHelper.SummaryProperty), nameof(DocumentedTagHelper.SummaryProperty),
defaultLocation,
new TagHelperAttributeDesignTimeDescriptor new TagHelperAttributeDesignTimeDescriptor
{ {
Summary = PropertySummary Summary = PropertySummary
} }
}, },
{ {
CreateDocumentationTagHelperType(defaultLocation, codeBase: null), typeof(DocumentedTagHelper),
nameof(DocumentedTagHelper.RemarksProperty), nameof(DocumentedTagHelper.RemarksProperty),
defaultLocation,
new TagHelperAttributeDesignTimeDescriptor new TagHelperAttributeDesignTimeDescriptor
{ {
Remarks = PropertyRemarks Remarks = PropertyRemarks
} }
}, },
{ {
CreateDocumentationTagHelperType(defaultLocation, codeBase: null), typeof(DocumentedTagHelper),
nameof(DocumentedTagHelper.RemarksAndSummaryProperty), nameof(DocumentedTagHelper.RemarksAndSummaryProperty),
defaultLocation,
new TagHelperAttributeDesignTimeDescriptor new TagHelperAttributeDesignTimeDescriptor
{ {
Summary = PropertyWithSummaryAndRemarks_Summary, Summary = PropertyWithSummaryAndRemarks_Summary,
@ -343,75 +337,35 @@ namespace Microsoft.AspNetCore.Razor.Runtime.TagHelpers
} }
}, },
{ {
CreateDocumentationTagHelperType(location: null, codeBase: defaultCodeBase), typeof(DocumentedTagHelper),
nameof(DocumentedTagHelper.SummaryProperty), nameof(DocumentedTagHelper.SummaryProperty),
defaultLocation,
new TagHelperAttributeDesignTimeDescriptor new TagHelperAttributeDesignTimeDescriptor
{ {
Summary = PropertySummary Summary = PropertySummary
} }
}, },
{ {
CreateDocumentationTagHelperType(location: null, codeBase: defaultCodeBase), typeof(DocumentedTagHelper),
nameof(DocumentedTagHelper.RemarksProperty), nameof(DocumentedTagHelper.RemarksProperty),
defaultLocation,
new TagHelperAttributeDesignTimeDescriptor new TagHelperAttributeDesignTimeDescriptor
{ {
Remarks = PropertyRemarks Remarks = PropertyRemarks
} }
}, },
{ {
CreateDocumentationTagHelperType(location: null, codeBase: defaultCodeBase), typeof(DocumentedTagHelper),
nameof(DocumentedTagHelper.RemarksAndSummaryProperty),
new TagHelperAttributeDesignTimeDescriptor
{
Summary = PropertyWithSummaryAndRemarks_Summary,
Remarks = PropertyWithSummaryAndRemarks_Remarks
}
},
{
CreateDocumentationTagHelperType(defaultLocation, defaultCodeBase),
nameof(DocumentedTagHelper.SummaryProperty),
new TagHelperAttributeDesignTimeDescriptor
{
Summary = PropertySummary
}
},
{
CreateDocumentationTagHelperType(defaultLocation, defaultCodeBase),
nameof(DocumentedTagHelper.RemarksProperty),
new TagHelperAttributeDesignTimeDescriptor
{
Remarks = PropertyRemarks
}
},
{
CreateDocumentationTagHelperType(defaultLocation, defaultCodeBase),
nameof(DocumentedTagHelper.RemarksAndSummaryProperty),
new TagHelperAttributeDesignTimeDescriptor
{
Summary = PropertyWithSummaryAndRemarks_Summary,
Remarks = PropertyWithSummaryAndRemarks_Remarks
}
},
{
CreateDocumentationTagHelperType(nonExistentLocation, codeBase: null),
nameof(DocumentedTagHelper.RemarksAndSummaryProperty), nameof(DocumentedTagHelper.RemarksAndSummaryProperty),
nonExistentLocation,
null null
}, },
{ {
CreateDocumentationTagHelperType(location: null, codeBase: nonExistentCodeBase), typeof(DocumentedTagHelper),
nameof(DocumentedTagHelper.RemarksAndSummaryProperty), nameof(DocumentedTagHelper.RemarksAndSummaryProperty),
invalidLocation,
null null
}, },
{
CreateDocumentationTagHelperType(invalidLocation, codeBase: null),
nameof(DocumentedTagHelper.RemarksAndSummaryProperty),
null
},
{
CreateDocumentationTagHelperType(location: null, codeBase: invalidCodeBase),
nameof(DocumentedTagHelper.RemarksAndSummaryProperty),
null
}
}; };
} }
} }
@ -421,13 +375,14 @@ namespace Microsoft.AspNetCore.Razor.Runtime.TagHelpers
public void CreateAttributeDescriptor_ReturnsExpectedDescriptors( public void CreateAttributeDescriptor_ReturnsExpectedDescriptors(
Type tagHelperType, Type tagHelperType,
string propertyName, string propertyName,
string assemblyLocation,
TagHelperAttributeDesignTimeDescriptor expectedDesignTimeDescriptor) TagHelperAttributeDesignTimeDescriptor expectedDesignTimeDescriptor)
{ {
// Arrange // Arrange
var mockPropertyInfo = new Mock<PropertyInfo>(); var mockPropertyInfo = new Mock<PropertyInfo>();
mockPropertyInfo.Setup(propertyInfo => propertyInfo.DeclaringType).Returns(tagHelperType); mockPropertyInfo.Setup(propertyInfo => propertyInfo.DeclaringType).Returns(tagHelperType);
mockPropertyInfo.Setup(propertyInfo => propertyInfo.Name).Returns(propertyName); mockPropertyInfo.Setup(propertyInfo => propertyInfo.Name).Returns(propertyName);
var factory = new TagHelperDesignTimeDescriptorFactory(); var factory = new TestTagHelperDesignTimeDescriptorFactory(assemblyLocation);
// Act // Act
var designTimeDescriptor = factory.CreateAttributeDescriptor( var designTimeDescriptor = factory.CreateAttributeDescriptor(
@ -444,11 +399,12 @@ namespace Microsoft.AspNetCore.Razor.Runtime.TagHelpers
{ {
get get
{ {
// tagHelperType, expectedDesignTimeDescriptor, culture // tagHelperType, assemblyLocation, expectedDesignTimeDescriptor, culture
return new TheoryData<Type, TagHelperAttributeDesignTimeDescriptor, string> return new TheoryData<Type, string, TagHelperAttributeDesignTimeDescriptor, string>
{ {
{ {
CreateDocumentationTagHelperType(LocalizedDocumentedAssemblyLocation, codeBase: null), typeof(DocumentedTagHelper),
LocalizedDocumentedAssemblyLocation,
new TagHelperAttributeDesignTimeDescriptor new TagHelperAttributeDesignTimeDescriptor
{ {
Summary = "en-GB: " + PropertyWithSummaryAndRemarks_Summary, Summary = "en-GB: " + PropertyWithSummaryAndRemarks_Summary,
@ -457,7 +413,8 @@ namespace Microsoft.AspNetCore.Razor.Runtime.TagHelpers
"en-GB" "en-GB"
}, },
{ {
CreateDocumentationTagHelperType(LocalizedDocumentedAssemblyLocation, codeBase: null), typeof(DocumentedTagHelper),
LocalizedDocumentedAssemblyLocation,
new TagHelperAttributeDesignTimeDescriptor new TagHelperAttributeDesignTimeDescriptor
{ {
Summary = "en: " + PropertyWithSummaryAndRemarks_Summary, Summary = "en: " + PropertyWithSummaryAndRemarks_Summary,
@ -466,7 +423,8 @@ namespace Microsoft.AspNetCore.Razor.Runtime.TagHelpers
"en-US" "en-US"
}, },
{ {
CreateDocumentationTagHelperType(LocalizedDocumentedAssemblyLocation, codeBase: null), typeof(DocumentedTagHelper),
LocalizedDocumentedAssemblyLocation,
new TagHelperAttributeDesignTimeDescriptor new TagHelperAttributeDesignTimeDescriptor
{ {
Summary = "fr-FR: " + PropertyWithSummaryAndRemarks_Summary, Summary = "fr-FR: " + PropertyWithSummaryAndRemarks_Summary,
@ -475,7 +433,8 @@ namespace Microsoft.AspNetCore.Razor.Runtime.TagHelpers
"fr-FR" "fr-FR"
}, },
{ {
CreateDocumentationTagHelperType(LocalizedDocumentedAssemblyLocation, codeBase: null), typeof(DocumentedTagHelper),
LocalizedDocumentedAssemblyLocation,
new TagHelperAttributeDesignTimeDescriptor new TagHelperAttributeDesignTimeDescriptor
{ {
Summary = "fr: " + PropertyWithSummaryAndRemarks_Summary, Summary = "fr: " + PropertyWithSummaryAndRemarks_Summary,
@ -484,7 +443,8 @@ namespace Microsoft.AspNetCore.Razor.Runtime.TagHelpers
"fr-BE" "fr-BE"
}, },
{ {
CreateDocumentationTagHelperType(LocalizedDocumentedAssemblyLocation, codeBase: null), typeof(DocumentedTagHelper),
LocalizedDocumentedAssemblyLocation,
new TagHelperAttributeDesignTimeDescriptor new TagHelperAttributeDesignTimeDescriptor
{ {
Summary = "nl-BE: " + PropertyWithSummaryAndRemarks_Summary, Summary = "nl-BE: " + PropertyWithSummaryAndRemarks_Summary,
@ -500,6 +460,7 @@ namespace Microsoft.AspNetCore.Razor.Runtime.TagHelpers
[MemberData(nameof(CreateAttributeDescriptor_LocalizedPropertyData))] [MemberData(nameof(CreateAttributeDescriptor_LocalizedPropertyData))]
public void CreateAttributeDescriptor_WithLocalizedProperty_ReturnsExpectedDescriptors( public void CreateAttributeDescriptor_WithLocalizedProperty_ReturnsExpectedDescriptors(
Type tagHelperType, Type tagHelperType,
string assemblyLocation,
TagHelperAttributeDesignTimeDescriptor expectedDesignTimeDescriptor, TagHelperAttributeDesignTimeDescriptor expectedDesignTimeDescriptor,
string culture) string culture)
{ {
@ -510,7 +471,7 @@ namespace Microsoft.AspNetCore.Razor.Runtime.TagHelpers
.Setup(propertyInfo => propertyInfo.Name) .Setup(propertyInfo => propertyInfo.Name)
.Returns(nameof(DocumentedTagHelper.RemarksAndSummaryProperty)); .Returns(nameof(DocumentedTagHelper.RemarksAndSummaryProperty));
TagHelperAttributeDesignTimeDescriptor designTimeDescriptor; TagHelperAttributeDesignTimeDescriptor designTimeDescriptor;
var factory = new TagHelperDesignTimeDescriptorFactory(); var factory = new TestTagHelperDesignTimeDescriptorFactory(assemblyLocation);
// Act // Act
using (new CultureReplacer(culture)) using (new CultureReplacer(culture))
@ -530,13 +491,13 @@ namespace Microsoft.AspNetCore.Razor.Runtime.TagHelpers
public void CreateDescriptor_WithLocalizedProperty_CachesBasedOnCulture() public void CreateDescriptor_WithLocalizedProperty_CachesBasedOnCulture()
{ {
// Arrange // Arrange
var tagHelperType = CreateDocumentationTagHelperType(LocalizedDocumentedAssemblyLocation, codeBase: null); var tagHelperType = typeof(DocumentedTagHelper);
var mockPropertyInfo = new Mock<PropertyInfo>(); var mockPropertyInfo = new Mock<PropertyInfo>();
mockPropertyInfo.Setup(propertyInfo => propertyInfo.DeclaringType).Returns(tagHelperType); mockPropertyInfo.Setup(propertyInfo => propertyInfo.DeclaringType).Returns(tagHelperType);
mockPropertyInfo mockPropertyInfo
.Setup(propertyInfo => propertyInfo.Name) .Setup(propertyInfo => propertyInfo.Name)
.Returns(nameof(DocumentedTagHelper.RemarksAndSummaryProperty)); .Returns(nameof(DocumentedTagHelper.RemarksAndSummaryProperty));
var factory = new TagHelperDesignTimeDescriptorFactory(); var factory = new TestTagHelperDesignTimeDescriptorFactory(LocalizedDocumentedAssemblyLocation);
var expectedFRDesignTimeDescriptor = new TagHelperAttributeDesignTimeDescriptor var expectedFRDesignTimeDescriptor = new TagHelperAttributeDesignTimeDescriptor
{ {
Summary = "fr-FR: " + PropertyWithSummaryAndRemarks_Summary, Summary = "fr-FR: " + PropertyWithSummaryAndRemarks_Summary,
@ -570,50 +531,20 @@ namespace Microsoft.AspNetCore.Razor.Runtime.TagHelpers
TagHelperAttributeDesignTimeDescriptorComparer.Default); TagHelperAttributeDesignTimeDescriptorComparer.Default);
} }
private static Type CreateDocumentationTagHelperType(string location, string codeBase) private class TestTagHelperDesignTimeDescriptorFactory : TagHelperDesignTimeDescriptorFactory
{ {
return CreateType<DocumentedTagHelper>(location, codeBase); private readonly string _assemblyLocation;
}
private static Type CreateType<TWrappedType>(string location, string codeBase) public TestTagHelperDesignTimeDescriptorFactory(string assemblyLocation)
{ : base()
var testAssembly = new TestAssembly(location, codeBase);
var wrappedType = typeof(TWrappedType);
var mockType = new Mock<Type>();
var mockReflectedType = mockType.As<IReflectableType>();
// TypeDelegator inherits from abstract TypeInfo class and has a constructor Moq can use.
var mockTypeInfo = new Mock<TypeDelegator>(mockType.Object);
mockReflectedType.Setup(type => type.GetTypeInfo()).Returns(mockTypeInfo.Object);
mockTypeInfo.Setup(typeInfo => typeInfo.Assembly).Returns(testAssembly);
mockTypeInfo.Setup(typeInfo => typeInfo.FullName).Returns(wrappedType.FullName);
mockType.Setup(type => type.Assembly).Returns(testAssembly);
mockType.Setup(type => type.FullName).Returns(wrappedType.FullName);
mockType.Setup(type => type.DeclaringType).Returns(wrappedType.DeclaringType);
mockType
.Setup(type => type.GetCustomAttributes(false))
.Returns(wrappedType == typeof(DocumentedTagHelper) ?
new[] { new OutputElementHintAttribute("p") } :
null);
return mockType.Object;
}
private class TestAssembly : Assembly
{
public TestAssembly(string location, string codeBase)
{ {
Location = location; _assemblyLocation = assemblyLocation;
CodeBase = codeBase;
} }
public override string Location { get; } public override string GetAssemblyLocation(Assembly assembly)
{
public override string CodeBase { get; } return _assemblyLocation;
}
public override AssemblyName GetName() { return new AssemblyName("TestAssembly"); }
} }
[OutputElementHint("hinted-value")] [OutputElementHint("hinted-value")]
@ -630,5 +561,4 @@ namespace Microsoft.AspNetCore.Razor.Runtime.TagHelpers
{ {
} }
} }
} }
#endif

View File

@ -23,7 +23,8 @@
"portable-net451+win8" "portable-net451+win8"
], ],
"dependencies": { "dependencies": {
"dotnet-test-xunit": "1.0.0-dev-*" "dotnet-test-xunit": "1.0.0-dev-*",
"moq.netcore": "4.4.0-beta8"
} }
}, },
"net451": { "net451": {