From 9055da1894d2df0aaabe642498a94c5001a01981 Mon Sep 17 00:00:00 2001 From: "N. Taylor Mullen" Date: Fri, 12 Jun 2015 14:49:22 -0700 Subject: [PATCH] Add tests to validate creation of TagHelperUsageDescriptors. - Could not add tests to validate the full TagHelperDescriptorFactory.CreateDescriptors => TagHelperUsageDescriptors due to how the runtime loads assemblies (does it in memory without XML). - Added serialization tests to include TagHelperUsageDescriptors. - Updated existing tests to use new TagHelperDescriptor/TagHelperAttributeDescriptor constructors. #352 --- ...iveTagHelperAttributeDescriptorComparer.cs | 44 -- ...aseSensitiveTagHelperDescriptorComparer.cs | 4 +- .../TagHelpers/CommonTagHelpers.cs | 31 ++ .../TagHelperAttributeDescriptorComparer.cs | 51 +++ .../TagHelperDescriptorFactoryTest.cs | 137 +++++-- .../TagHelperDescriptorResolverTest.cs | 11 +- .../TagHelperUsageDescriptorComparer.cs | 41 ++ .../TagHelperUsageDescriptorFactoryTest.cs | 385 ++++++++++++++++++ .../TagHelperDocumentation.nl-BE.xml | 34 ++ .../en-GB/TagHelperDocumentation.xml | 34 ++ .../Localized/en/TagHelperDocumentation.xml | 34 ++ .../fr-FR/TagHelperDocumentation.fr-FR.xml | 34 ++ .../fr/TagHelperDocumentation.fr.xml | 34 ++ .../NotLocalized/TagHelperDocumentation.xml | 34 ++ .../XmlDocumentationProviderTest.cs | 155 +++++++ .../project.json | 36 +- .../CSharpTagHelperRenderingTest.cs | 48 ++- .../TagHelpers/TagHelperBlockRewriterTest.cs | 56 ++- .../TagHelperDescriptorProviderTest.cs | 3 +- .../TagHelpers/TagHelperDescriptorTest.cs | 93 +++-- .../TagHelperParseTreeRewriterTest.cs | 21 +- .../TagHelperUsageDescriptorComparer.cs | 40 ++ 22 files changed, 1182 insertions(+), 178 deletions(-) delete mode 100644 test/Microsoft.AspNet.Razor.Runtime.Test/TagHelpers/CaseSensitiveTagHelperAttributeDescriptorComparer.cs create mode 100644 test/Microsoft.AspNet.Razor.Runtime.Test/TagHelpers/TagHelperAttributeDescriptorComparer.cs create mode 100644 test/Microsoft.AspNet.Razor.Runtime.Test/TagHelpers/TagHelperUsageDescriptorComparer.cs create mode 100644 test/Microsoft.AspNet.Razor.Runtime.Test/TagHelpers/TagHelperUsageDescriptorFactoryTest.cs create mode 100644 test/Microsoft.AspNet.Razor.Runtime.Test/TestFiles/Localized/TagHelperDocumentation.nl-BE.xml create mode 100644 test/Microsoft.AspNet.Razor.Runtime.Test/TestFiles/Localized/en-GB/TagHelperDocumentation.xml create mode 100644 test/Microsoft.AspNet.Razor.Runtime.Test/TestFiles/Localized/en/TagHelperDocumentation.xml create mode 100644 test/Microsoft.AspNet.Razor.Runtime.Test/TestFiles/Localized/fr-FR/TagHelperDocumentation.fr-FR.xml create mode 100644 test/Microsoft.AspNet.Razor.Runtime.Test/TestFiles/Localized/fr/TagHelperDocumentation.fr.xml create mode 100644 test/Microsoft.AspNet.Razor.Runtime.Test/TestFiles/NotLocalized/TagHelperDocumentation.xml create mode 100644 test/Microsoft.AspNet.Razor.Runtime.Test/XmlDocumentationProviderTest.cs create mode 100644 test/Microsoft.AspNet.Razor.Test/TagHelpers/TagHelperUsageDescriptorComparer.cs diff --git a/test/Microsoft.AspNet.Razor.Runtime.Test/TagHelpers/CaseSensitiveTagHelperAttributeDescriptorComparer.cs b/test/Microsoft.AspNet.Razor.Runtime.Test/TagHelpers/CaseSensitiveTagHelperAttributeDescriptorComparer.cs deleted file mode 100644 index b31394fbef..0000000000 --- a/test/Microsoft.AspNet.Razor.Runtime.Test/TagHelpers/CaseSensitiveTagHelperAttributeDescriptorComparer.cs +++ /dev/null @@ -1,44 +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 Microsoft.AspNet.Razor.TagHelpers; -using Microsoft.Internal.Web.Utils; - -namespace Microsoft.AspNet.Razor.Runtime.TagHelpers -{ - public class CaseSensitiveTagHelperAttributeDescriptorComparer : TagHelperAttributeDescriptorComparer - { - public new static readonly CaseSensitiveTagHelperAttributeDescriptorComparer Default = - new CaseSensitiveTagHelperAttributeDescriptorComparer(); - - private CaseSensitiveTagHelperAttributeDescriptorComparer() - : base() - { - } - - public override bool Equals(TagHelperAttributeDescriptor descriptorX, TagHelperAttributeDescriptor descriptorY) - { - if (descriptorX == descriptorY) - { - return true; - } - - // Base comparer does not care about Name case but in tests we do. Also double-check IsStringProperty - // though it is inferred from TypeName. - return base.Equals(descriptorX, descriptorY) && - descriptorX.IsStringProperty == descriptorY.IsStringProperty && - string.Equals(descriptorX.Name, descriptorY.Name, StringComparison.Ordinal); - } - - public override int GetHashCode(TagHelperAttributeDescriptor descriptor) - { - // Ignore IsStringProperty because it is directly inferred from TypeName and thus won't vary the hash - // bucket. Base comparer does not care about Name case in its hash code but in tests we do. - return HashCodeCombiner.Start() - .Add(base.GetHashCode(descriptor)) - .Add(descriptor.Name, StringComparer.Ordinal) - .CombinedHash; - } - } -} \ No newline at end of file diff --git a/test/Microsoft.AspNet.Razor.Runtime.Test/TagHelpers/CaseSensitiveTagHelperDescriptorComparer.cs b/test/Microsoft.AspNet.Razor.Runtime.Test/TagHelpers/CaseSensitiveTagHelperDescriptorComparer.cs index 3bdfade638..280d6dfb51 100644 --- a/test/Microsoft.AspNet.Razor.Runtime.Test/TagHelpers/CaseSensitiveTagHelperDescriptorComparer.cs +++ b/test/Microsoft.AspNet.Razor.Runtime.Test/TagHelpers/CaseSensitiveTagHelperDescriptorComparer.cs @@ -36,7 +36,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers StringComparer.Ordinal) && descriptorX.Attributes.SequenceEqual( descriptorY.Attributes, - CaseSensitiveTagHelperAttributeDescriptorComparer.Default); + TagHelperAttributeDescriptorComparer.Default); } public override int GetHashCode(TagHelperDescriptor descriptor) @@ -53,7 +53,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers foreach (var attribute in descriptor.Attributes) { - hashCodeCombiner.Add(CaseSensitiveTagHelperAttributeDescriptorComparer.Default.GetHashCode(attribute)); + hashCodeCombiner.Add(TagHelperAttributeDescriptorComparer.Default.GetHashCode(attribute)); } return hashCodeCombiner.CombinedHash; diff --git a/test/Microsoft.AspNet.Razor.Runtime.Test/TagHelpers/CommonTagHelpers.cs b/test/Microsoft.AspNet.Razor.Runtime.Test/TagHelpers/CommonTagHelpers.cs index e6ebbbdb06..67d2433f49 100644 --- a/test/Microsoft.AspNet.Razor.Runtime.Test/TagHelpers/CommonTagHelpers.cs +++ b/test/Microsoft.AspNet.Razor.Runtime.Test/TagHelpers/CommonTagHelpers.cs @@ -1,6 +1,8 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +using System.Collections.Generic; + namespace Microsoft.AspNet.Razor.Runtime.TagHelpers { public class Valid_PlainTagHelper : TagHelper @@ -32,4 +34,33 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers internal string InvalidInternalAttribute { get; set; } protected internal string InvalidProtectedInternalAttribute { get; set; } } + + /// + /// The summary for . + /// + /// + /// Inherits from . + /// + public class DocumentedTagHelper : TagHelper + { + /// + /// This is of type . + /// + public string SummaryProperty { get; set; } + + /// + /// The may be null. + /// + public int RemarksProperty { get; set; } + + /// + /// This is a complex . + /// + /// + /// + /// + public IDictionary RemarksAndSummaryProperty { get; set; } + + public bool UndocumentedProperty { get; set; } + } } \ No newline at end of file diff --git a/test/Microsoft.AspNet.Razor.Runtime.Test/TagHelpers/TagHelperAttributeDescriptorComparer.cs b/test/Microsoft.AspNet.Razor.Runtime.Test/TagHelpers/TagHelperAttributeDescriptorComparer.cs new file mode 100644 index 0000000000..d08024bb70 --- /dev/null +++ b/test/Microsoft.AspNet.Razor.Runtime.Test/TagHelpers/TagHelperAttributeDescriptorComparer.cs @@ -0,0 +1,51 @@ +// 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 Microsoft.AspNet.Razor.TagHelpers; +using Microsoft.Internal.Web.Utils; + +namespace Microsoft.AspNet.Razor.Runtime.TagHelpers +{ + public class TagHelperAttributeDescriptorComparer : IEqualityComparer + { + public static readonly TagHelperAttributeDescriptorComparer Default = + new TagHelperAttributeDescriptorComparer(); + + private TagHelperAttributeDescriptorComparer() + { + } + + public bool Equals(TagHelperAttributeDescriptor descriptorX, TagHelperAttributeDescriptor descriptorY) + { + if (descriptorX == descriptorY) + { + return true; + } + + return descriptorX != null && + descriptorY != null && + descriptorX.IsIndexer == descriptorY.IsIndexer && + string.Equals(descriptorX.Name, descriptorY.Name, StringComparison.Ordinal) && + string.Equals(descriptorX.PropertyName, descriptorY.PropertyName, StringComparison.Ordinal) && + string.Equals(descriptorX.TypeName, descriptorY.TypeName, StringComparison.Ordinal) && + TagHelperUsageDescriptorComparer.Default.Equals( + descriptorX.UsageDescriptor, + descriptorY.UsageDescriptor); + } + + public int GetHashCode(TagHelperAttributeDescriptor descriptor) + { + // Ignore IsStringProperty because it is directly inferred from TypeName and thus won't vary the hash + // bucket. + return HashCodeCombiner.Start() + .Add(descriptor.IsIndexer) + .Add(descriptor.Name, StringComparer.Ordinal) + .Add(descriptor.PropertyName, StringComparer.Ordinal) + .Add(descriptor.TypeName, StringComparer.Ordinal) + .Add(TagHelperUsageDescriptorComparer.Default.GetHashCode(descriptor.UsageDescriptor)) + .CombinedHash; + } + } +} \ No newline at end of file diff --git a/test/Microsoft.AspNet.Razor.Runtime.Test/TagHelpers/TagHelperDescriptorFactoryTest.cs b/test/Microsoft.AspNet.Razor.Runtime.Test/TagHelpers/TagHelperDescriptorFactoryTest.cs index ea2d645178..85f8b3cd35 100644 --- a/test/Microsoft.AspNet.Razor.Runtime.Test/TagHelpers/TagHelperDescriptorFactoryTest.cs +++ b/test/Microsoft.AspNet.Razor.Runtime.Test/TagHelpers/TagHelperDescriptorFactoryTest.cs @@ -3,7 +3,6 @@ using System; using System.Collections.Generic; -using System.ComponentModel; using System.Linq; using System.Reflection; using Microsoft.AspNet.Razor.TagHelpers; @@ -210,7 +209,8 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers var descriptors = TagHelperDescriptorFactory.CreateDescriptors( AssemblyName, tagHelperType, - errorSink); + designTime: false, + errorSink: errorSink); // Assert Assert.Empty(errorSink.Errors); @@ -258,7 +258,8 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers var descriptors = TagHelperDescriptorFactory.CreateDescriptors( AssemblyName, tagHelperType, - errorSink); + designTime: false, + errorSink: errorSink); // Assert Assert.Empty(errorSink.Errors); @@ -294,7 +295,8 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers var descriptors = TagHelperDescriptorFactory.CreateDescriptors( AssemblyName, typeof(OverriddenAttributeTagHelper), - errorSink); + designTime: false, + errorSink: errorSink); // Assert Assert.Empty(errorSink.Errors); @@ -327,7 +329,8 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers var descriptors = TagHelperDescriptorFactory.CreateDescriptors( AssemblyName, typeof(InheritedOverriddenAttributeTagHelper), - errorSink); + designTime: false, + errorSink: errorSink); // Assert Assert.Empty(errorSink.Errors); @@ -360,7 +363,8 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers var descriptors = TagHelperDescriptorFactory.CreateDescriptors( AssemblyName, typeof(InheritedNotOverriddenAttributeTagHelper), - errorSink); + designTime: false, + errorSink: errorSink); // Assert Assert.Empty(errorSink.Errors); @@ -380,7 +384,8 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers var descriptors = TagHelperDescriptorFactory.CreateDescriptors( objectAssemblyName, typeof(object), - errorSink); + designTime: false, + errorSink: errorSink); // Assert Assert.Empty(errorSink.Errors); @@ -406,14 +411,16 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers nameof(InheritedSingleAttributeTagHelper.IntAttribute), typeof(int).FullName, isIndexer: false, - isStringProperty: false) + isStringProperty: false, + usageDescriptor: null) }); // Act var descriptors = TagHelperDescriptorFactory.CreateDescriptors( AssemblyName, typeof(InheritedSingleAttributeTagHelper), - errorSink); + designTime: false, + errorSink: errorSink); // Assert Assert.Empty(errorSink.Errors); @@ -440,7 +447,8 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers var descriptors = TagHelperDescriptorFactory.CreateDescriptors( AssemblyName, typeof(SingleAttributeTagHelper), - new ErrorSink()); + designTime: false, + errorSink: new ErrorSink()); // Assert Assert.Empty(errorSink.Errors); @@ -468,7 +476,8 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers var descriptors = TagHelperDescriptorFactory.CreateDescriptors( AssemblyName, typeof(MissingAccessorTagHelper), - errorSink); + designTime: false, + errorSink: errorSink); // Assert Assert.Empty(errorSink.Errors); @@ -496,7 +505,8 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers var descriptors = TagHelperDescriptorFactory.CreateDescriptors( AssemblyName, typeof(NonPublicAccessorTagHelper), - errorSink); + designTime: false, + errorSink: errorSink); // Assert Assert.Empty(errorSink.Errors); @@ -522,14 +532,16 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers nameof(NotBoundAttributeTagHelper.BoundProperty), typeof(object).FullName, isIndexer: false, - isStringProperty: false) + isStringProperty: false, + usageDescriptor: null) }); // Act var descriptors = TagHelperDescriptorFactory.CreateDescriptors( AssemblyName, typeof(NotBoundAttributeTagHelper), - errorSink); + designTime: false, + errorSink: errorSink); // Assert Assert.Empty(errorSink.Errors); @@ -547,7 +559,8 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers var descriptors = TagHelperDescriptorFactory.CreateDescriptors( AssemblyName, typeof(DuplicateAttributeNameTagHelper), - errorSink); + designTime: false, + errorSink: errorSink); // Assert Assert.Empty(descriptors); @@ -574,7 +587,8 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers nameof(MultiTagTagHelper.ValidAttribute), typeof(string).FullName, isIndexer: false, - isStringProperty: true) + isStringProperty: true, + usageDescriptor: null) }), new TagHelperDescriptor( "p", @@ -587,7 +601,8 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers nameof(MultiTagTagHelper.ValidAttribute), typeof(string).FullName, isIndexer: false, - isStringProperty: true) + isStringProperty: true, + usageDescriptor: null) }) }; @@ -595,7 +610,8 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers var descriptors = TagHelperDescriptorFactory.CreateDescriptors( AssemblyName, typeof(MultiTagTagHelper), - errorSink); + designTime: false, + errorSink: errorSink); // Assert Assert.Empty(errorSink.Errors); @@ -626,7 +642,8 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers var descriptors = TagHelperDescriptorFactory.CreateDescriptors( AssemblyName, typeof(InheritedMultiTagTagHelper), - errorSink); + designTime: false, + errorSink: errorSink); // Assert Assert.Empty(errorSink.Errors); @@ -655,7 +672,8 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers var descriptors = TagHelperDescriptorFactory.CreateDescriptors( AssemblyName, typeof(DuplicateTagNameTagHelper), - errorSink); + designTime: false, + errorSink: errorSink); // Assert Assert.Empty(errorSink.Errors); @@ -683,7 +701,8 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers var descriptors = TagHelperDescriptorFactory.CreateDescriptors( AssemblyName, typeof(OverrideNameTagHelper), - errorSink); + designTime: false, + errorSink: errorSink); // Assert Assert.Empty(errorSink.Errors); @@ -867,7 +886,11 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers var errorSink = new ErrorSink(); // Act - var descriptors = TagHelperDescriptorFactory.CreateDescriptors(AssemblyName, type, errorSink); + var descriptors = TagHelperDescriptorFactory.CreateDescriptors( + AssemblyName, + type, + designTime: false, + errorSink: errorSink); // Assert var actualErrors = errorSink.Errors.ToArray(); @@ -885,7 +908,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers Assert.Equal( expectedAttributeDescriptors, actualDescriptor.Attributes, - CaseSensitiveTagHelperAttributeDescriptorComparer.Default); + TagHelperAttributeDescriptorComparer.Default); } // tagTelperType, expectedAttributeDescriptors, expectedErrorMessages @@ -911,13 +934,15 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers propertyName: nameof(DefaultValidHtmlAttributePrefix.DictionaryProperty), typeName: typeof(IDictionary).FullName, isIndexer: false, - isStringProperty: false), + isStringProperty: false, + usageDescriptor: null), new TagHelperAttributeDescriptor( name: "dictionary-property-", propertyName: nameof(DefaultValidHtmlAttributePrefix.DictionaryProperty), typeName: typeof(string).FullName, isIndexer: true, - isStringProperty: true), + isStringProperty: true, + usageDescriptor: null), }, new string[0] }, @@ -930,13 +955,15 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers propertyName: nameof(SingleValidHtmlAttributePrefix.DictionaryProperty), typeName: typeof(IDictionary).FullName, isIndexer: false, - isStringProperty: false), + isStringProperty: false, + usageDescriptor: null), new TagHelperAttributeDescriptor( name: "valid-prefix", propertyName: nameof(SingleValidHtmlAttributePrefix.DictionaryProperty), typeName: typeof(string).FullName, isIndexer: true, - isStringProperty: true), + isStringProperty: true, + usageDescriptor: null), }, new string[0] }, @@ -949,67 +976,78 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers propertyName: nameof(MultipleValidHtmlAttributePrefix.DictionaryProperty), typeName: typeof(Dictionary).FullName, isIndexer: false, - isStringProperty: false), + isStringProperty: false, + usageDescriptor: null), new TagHelperAttributeDescriptor( name: "valid-name2", propertyName: nameof(MultipleValidHtmlAttributePrefix.DictionarySubclassProperty), typeName: typeof(DictionarySubclass).FullName, isIndexer: false, - isStringProperty: false), + isStringProperty: false, + usageDescriptor: null), new TagHelperAttributeDescriptor( name: "valid-name3", propertyName: nameof(MultipleValidHtmlAttributePrefix.DictionaryWithoutParameterlessConstructorProperty), typeName: typeof(DictionaryWithoutParameterlessConstructor).FullName, isIndexer: false, - isStringProperty: false), + isStringProperty: false, + usageDescriptor: null), new TagHelperAttributeDescriptor( name: "valid-name4", propertyName: nameof(MultipleValidHtmlAttributePrefix.GenericDictionarySubclassProperty), typeName: typeof(GenericDictionarySubclass).FullName, isIndexer: false, - isStringProperty: false), + isStringProperty: false, + usageDescriptor: null), new TagHelperAttributeDescriptor( name: "valid-name5", propertyName: nameof(MultipleValidHtmlAttributePrefix.SortedDictionaryProperty), typeName: typeof(SortedDictionary).FullName, isIndexer: false, - isStringProperty: false), + isStringProperty: false, + usageDescriptor: null), new TagHelperAttributeDescriptor( name: "valid-name6", propertyName: nameof(MultipleValidHtmlAttributePrefix.StringProperty), typeName: typeof(string).FullName, isIndexer: false, - isStringProperty: true), + isStringProperty: true, + usageDescriptor: null), new TagHelperAttributeDescriptor( name: "valid-prefix1-", propertyName: nameof(MultipleValidHtmlAttributePrefix.DictionaryProperty), typeName: typeof(object).FullName, isIndexer: true, - isStringProperty: false), + isStringProperty: false, + usageDescriptor: null), new TagHelperAttributeDescriptor( name: "valid-prefix2-", propertyName: nameof(MultipleValidHtmlAttributePrefix.DictionarySubclassProperty), typeName: typeof(string).FullName, isIndexer: true, - isStringProperty: true), + isStringProperty: true, + usageDescriptor: null), new TagHelperAttributeDescriptor( name: "valid-prefix3-", propertyName: nameof(MultipleValidHtmlAttributePrefix.DictionaryWithoutParameterlessConstructorProperty), typeName: typeof(string).FullName, isIndexer: true, - isStringProperty: true), + isStringProperty: true, + usageDescriptor: null), new TagHelperAttributeDescriptor( name: "valid-prefix4-", propertyName: nameof(MultipleValidHtmlAttributePrefix.GenericDictionarySubclassProperty), typeName: typeof(object).FullName, isIndexer: true, - isStringProperty: false), + isStringProperty: false, + usageDescriptor: null), new TagHelperAttributeDescriptor( name: "valid-prefix5-", propertyName: nameof(MultipleValidHtmlAttributePrefix.SortedDictionaryProperty), typeName: typeof(int).FullName, isIndexer: true, - isStringProperty: false), + isStringProperty: false, + usageDescriptor: null), }, new string[0] }, @@ -1032,7 +1070,8 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers propertyName: nameof(MultipleInvalidHtmlAttributePrefix.LongProperty), typeName: typeof(long).FullName, isIndexer: false, - isStringProperty: false), + isStringProperty: false, + usageDescriptor: null), }, new[] { @@ -1065,7 +1104,11 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers var errorSink = new ErrorSink(); // Act - var descriptors = TagHelperDescriptorFactory.CreateDescriptors(AssemblyName, tagHelperType, errorSink); + var descriptors = TagHelperDescriptorFactory.CreateDescriptors( + AssemblyName, + tagHelperType, + designTime: false, + errorSink: errorSink); // Assert var errors = errorSink.Errors.ToArray(); @@ -1082,7 +1125,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers Assert.Equal( expectedAttributeDescriptors, descriptor.Attributes, - CaseSensitiveTagHelperAttributeDescriptorComparer.Default); + TagHelperAttributeDescriptorComparer.Default); } public static TheoryData ValidAttributeNameOrPrefixData @@ -1112,7 +1155,8 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers name, propertyName: "ValidProperty", typeName: "PropertyType", - isIndexer: false); + isIndexer: false, + usageDescriptor: null); var errorSink = new ErrorSink(); // Act @@ -1135,7 +1179,8 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers name: prefix, propertyName: "ValidProperty", typeName: "PropertyType", - isIndexer: true); + isIndexer: true, + usageDescriptor: null); var errorSink = new ErrorSink(); // Act @@ -1180,7 +1225,8 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers name, propertyName: "InvalidProperty", typeName: "PropertyType", - isIndexer: false); + isIndexer: false, + usageDescriptor: null); var errorSink = new ErrorSink(); // Act @@ -1233,7 +1279,8 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers name: prefix, propertyName: "InvalidProperty", typeName: "ValuesType", - isIndexer: true); + isIndexer: true, + usageDescriptor: null); var errorSink = new ErrorSink(); // Act diff --git a/test/Microsoft.AspNet.Razor.Runtime.Test/TagHelpers/TagHelperDescriptorResolverTest.cs b/test/Microsoft.AspNet.Razor.Runtime.Test/TagHelpers/TagHelperDescriptorResolverTest.cs index 5dbe25c157..ce90151a9f 100644 --- a/test/Microsoft.AspNet.Razor.Runtime.Test/TagHelpers/TagHelperDescriptorResolverTest.cs +++ b/test/Microsoft.AspNet.Razor.Runtime.Test/TagHelpers/TagHelperDescriptorResolverTest.cs @@ -1368,7 +1368,8 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers typeName, assemblyName, attributes: Enumerable.Empty(), - requiredAttributes: Enumerable.Empty()); + requiredAttributes: Enumerable.Empty(), + usageDescriptor: null); } private static TagHelperDescriptor CreatePrefixedValidPlainDescriptor(string prefix) @@ -1403,7 +1404,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers private class TestTagHelperDescriptorResolver : TagHelperDescriptorResolver { public TestTagHelperDescriptorResolver(TagHelperTypeResolver typeResolver) - : base(typeResolver) + : base(typeResolver, designTime: false) { } @@ -1444,6 +1445,11 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers private class AssemblyCheckingTagHelperDescriptorResolver : TagHelperDescriptorResolver { + public AssemblyCheckingTagHelperDescriptorResolver() + : base(designTime: false) + { + } + public string CalledWithAssemblyName { get; set; } protected override IEnumerable ResolveDescriptorsInAssembly( @@ -1462,6 +1468,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers private readonly Exception _error; public ThrowingTagHelperDescriptorResolver(Exception error) + : base(designTime: false) { _error = error; } diff --git a/test/Microsoft.AspNet.Razor.Runtime.Test/TagHelpers/TagHelperUsageDescriptorComparer.cs b/test/Microsoft.AspNet.Razor.Runtime.Test/TagHelpers/TagHelperUsageDescriptorComparer.cs new file mode 100644 index 0000000000..0d61a01a59 --- /dev/null +++ b/test/Microsoft.AspNet.Razor.Runtime.Test/TagHelpers/TagHelperUsageDescriptorComparer.cs @@ -0,0 +1,41 @@ +// 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 Microsoft.AspNet.Razor.TagHelpers; +using Microsoft.Internal.Web.Utils; + +namespace Microsoft.AspNet.Razor.Runtime.TagHelpers +{ + public class TagHelperUsageDescriptorComparer : IEqualityComparer + { + public static readonly TagHelperUsageDescriptorComparer Default = new TagHelperUsageDescriptorComparer(); + + private TagHelperUsageDescriptorComparer() + { + } + + public bool Equals(TagHelperUsageDescriptor descriptorX, TagHelperUsageDescriptor descriptorY) + { + if (descriptorX == descriptorY) + { + return true; + } + + return descriptorX != null && + descriptorY != null && + string.Equals(descriptorX.Summary, descriptorY.Summary, StringComparison.Ordinal) && + string.Equals(descriptorX.Remarks, descriptorY.Remarks, StringComparison.Ordinal); + } + + public int GetHashCode(TagHelperUsageDescriptor descriptor) + { + return HashCodeCombiner + .Start() + .Add(descriptor.Summary, StringComparer.Ordinal) + .Add(descriptor.Remarks, StringComparer.Ordinal) + .CombinedHash; + } + } +} diff --git a/test/Microsoft.AspNet.Razor.Runtime.Test/TagHelpers/TagHelperUsageDescriptorFactoryTest.cs b/test/Microsoft.AspNet.Razor.Runtime.Test/TagHelpers/TagHelperUsageDescriptorFactoryTest.cs new file mode 100644 index 0000000000..1b2630cd02 --- /dev/null +++ b/test/Microsoft.AspNet.Razor.Runtime.Test/TagHelpers/TagHelperUsageDescriptorFactoryTest.cs @@ -0,0 +1,385 @@ +// 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. + +#if !DNXCORE50 +using System; +using System.IO; +using System.Reflection; +using Microsoft.AspNet.Razor.TagHelpers; +using Microsoft.AspNet.Testing; +using Moq; +using Xunit; + +namespace Microsoft.AspNet.Razor.Runtime.TagHelpers +{ + public class TagHelperUsageDescriptorFactoryTest + { + private const string TypeSummary = "The summary for ."; + private const string TypeRemarks = "Inherits from ."; + private const string PropertySummary = "This is of type ."; + private const string PropertyRemarks = "The may be null."; + private const string PropertyWithSummaryAndRemarks_Summary = "This is a complex ."; + private const string PropertyWithSummaryAndRemarks_Remarks = ""; + + // These test assemblies don't really exist. They are used to look up corresponding XML for a fake assembly + // which is based on the DocumentedTagHelper type. + public static readonly string DocumentedAssemblyLocation = + Directory.GetCurrentDirectory() + "/TestFiles/NotLocalized/TagHelperDocumentation.dll"; + public static readonly string LocalizedDocumentedAssemblyLocation = + Directory.GetCurrentDirectory() + "/TestFiles/Localized/TagHelperDocumentation.dll"; + public static readonly string DocumentedAssemblyCodeBase = + "file:///" + DocumentedAssemblyLocation; + + public static TheoryData CreateDescriptor_TypeDocumentationData + { + get + { + var defaultLocation = DocumentedAssemblyLocation; + var defaultCodeBase = DocumentedAssemblyCodeBase; + var nonExistentLocation = defaultLocation.Replace("TestFiles", "TestFile"); + var nonExistentCodeBase = defaultCodeBase.Replace("TestFiles", "TestFile"); + var invalidLocation = defaultLocation + '\0'; + var invalidCodeBase = defaultCodeBase + '\0'; + + // tagHelperType, expectedUsageDescriptor + return new TheoryData + { + { CreateDocumentationTagHelperType(location: null, codeBase: null), null }, + { + CreateDocumentationTagHelperType(defaultLocation, codeBase: null), + new TagHelperUsageDescriptor(TypeSummary, TypeRemarks) + }, + { + CreateDocumentationTagHelperType(location: null, codeBase: defaultCodeBase), + new TagHelperUsageDescriptor(TypeSummary, TypeRemarks) + }, + { + CreateDocumentationTagHelperType(defaultLocation, defaultCodeBase), + new TagHelperUsageDescriptor(TypeSummary, TypeRemarks) + }, + { CreateType(defaultLocation, defaultCodeBase), null }, + { CreateDocumentationTagHelperType(nonExistentLocation, codeBase: null), null }, + { CreateDocumentationTagHelperType(location: null, codeBase: nonExistentCodeBase), null }, + { CreateType(invalidLocation, codeBase: null), null }, + { CreateDocumentationTagHelperType(location: null, codeBase: invalidCodeBase), null }, + }; + } + } + + [Theory] + [MemberData(nameof(CreateDescriptor_TypeDocumentationData))] + public void CreateDescriptor_WithType_ReturnsExpectedDescriptors( + Type tagHelperType, + TagHelperUsageDescriptor expectedUsageDescriptor) + { + // Act + var usageDescriptor = TagHelperUsageDescriptorFactory.CreateDescriptor(tagHelperType); + + // Assert + Assert.Equal(expectedUsageDescriptor, usageDescriptor, TagHelperUsageDescriptorComparer.Default); + } + + public static TheoryData CreateDescriptor_LocalizedTypeDocumentationData + { + get + { + // tagHelperType, expectedUsageDescriptor, culture + return new TheoryData + { + { + CreateDocumentationTagHelperType(LocalizedDocumentedAssemblyLocation, codeBase: null), + new TagHelperUsageDescriptor( + summary: "en-GB: " + TypeSummary, + remarks: "en-GB: " + TypeRemarks), + "en-GB" + }, + { + CreateDocumentationTagHelperType(LocalizedDocumentedAssemblyLocation, codeBase: null), + new TagHelperUsageDescriptor( + summary: "en: " + TypeSummary, + remarks: "en: " + TypeRemarks), + "en-US" + }, + { + CreateDocumentationTagHelperType(LocalizedDocumentedAssemblyLocation, codeBase: null), + new TagHelperUsageDescriptor( + summary: "fr-FR: " + TypeSummary, + remarks: "fr-FR: " + TypeRemarks), + "fr-FR" + }, + { + CreateDocumentationTagHelperType(LocalizedDocumentedAssemblyLocation, codeBase: null), + new TagHelperUsageDescriptor( + summary: "fr: " + TypeSummary, + remarks: "fr: " + TypeRemarks), + "fr-BE" + }, + { + CreateDocumentationTagHelperType(LocalizedDocumentedAssemblyLocation, codeBase: null), + new TagHelperUsageDescriptor( + summary: "nl-BE: " + TypeSummary, + remarks: "nl-BE: " + TypeRemarks), + "nl-BE" + } + }; + } + } + + [Theory] + [MemberData(nameof(CreateDescriptor_LocalizedTypeDocumentationData))] + public void CreateDescriptor_WithLocalizedType_ReturnsExpectedDescriptors( + Type tagHelperType, + TagHelperUsageDescriptor expectedUsageDescriptor, + string culture) + { + // Arrange + TagHelperUsageDescriptor usageDescriptor; + + // Act + using (new CultureReplacer(culture)) + { + usageDescriptor = TagHelperUsageDescriptorFactory.CreateDescriptor(tagHelperType); + } + + // Assert + Assert.Equal(expectedUsageDescriptor, usageDescriptor, TagHelperUsageDescriptorComparer.Default); + } + + public static TheoryData CreateDescriptor_PropertyDocumentationData + { + get + { + var defaultLocation = DocumentedAssemblyLocation; + var defaultCodeBase = DocumentedAssemblyCodeBase; + var nonExistentLocation = defaultLocation.Replace("TestFiles", "TestFile"); + var nonExistentCodeBase = defaultCodeBase.Replace("TestFiles", "TestFile"); + var invalidLocation = defaultLocation + '\0'; + var invalidCodeBase = defaultCodeBase + '\0'; + + // tagHelperType, propertyName, expectedUsageDescriptor + return new TheoryData + { + { + CreateDocumentationTagHelperType(location: null, codeBase: null), + nameof(DocumentedTagHelper.SummaryProperty), + null + }, + { + CreateDocumentationTagHelperType(location: null, codeBase: null), + nameof(DocumentedTagHelper.RemarksProperty), + null + }, + { + CreateDocumentationTagHelperType(location: null, codeBase: null), + nameof(DocumentedTagHelper.RemarksAndSummaryProperty), + null + }, + { + CreateDocumentationTagHelperType(defaultLocation, defaultCodeBase), + nameof(DocumentedTagHelper.UndocumentedProperty), + null + }, + { + CreateDocumentationTagHelperType(defaultLocation, codeBase: null), + nameof(DocumentedTagHelper.SummaryProperty), + new TagHelperUsageDescriptor(PropertySummary, remarks: null) + }, + { + CreateDocumentationTagHelperType(defaultLocation, codeBase: null), + nameof(DocumentedTagHelper.RemarksProperty), + new TagHelperUsageDescriptor(summary: null, remarks: PropertyRemarks) + }, + { + CreateDocumentationTagHelperType(defaultLocation, codeBase: null), + nameof(DocumentedTagHelper.RemarksAndSummaryProperty), + new TagHelperUsageDescriptor( + PropertyWithSummaryAndRemarks_Summary, + PropertyWithSummaryAndRemarks_Remarks) + }, + { + CreateDocumentationTagHelperType(location: null, codeBase: defaultCodeBase), + nameof(DocumentedTagHelper.SummaryProperty), + new TagHelperUsageDescriptor(PropertySummary, remarks: null) + }, + { + CreateDocumentationTagHelperType(location: null, codeBase: defaultCodeBase), + nameof(DocumentedTagHelper.RemarksProperty), + new TagHelperUsageDescriptor(summary: null, remarks: PropertyRemarks) + }, + { + CreateDocumentationTagHelperType(location: null, codeBase: defaultCodeBase), + nameof(DocumentedTagHelper.RemarksAndSummaryProperty), + new TagHelperUsageDescriptor( + PropertyWithSummaryAndRemarks_Summary, + PropertyWithSummaryAndRemarks_Remarks) + }, + { + CreateDocumentationTagHelperType(defaultLocation, defaultCodeBase), + nameof(DocumentedTagHelper.SummaryProperty), + new TagHelperUsageDescriptor(PropertySummary, remarks: null) + }, + { + CreateDocumentationTagHelperType(defaultLocation, defaultCodeBase), + nameof(DocumentedTagHelper.RemarksProperty), + new TagHelperUsageDescriptor(summary: null, remarks: PropertyRemarks) + }, + { + CreateDocumentationTagHelperType(defaultLocation, defaultCodeBase), + nameof(DocumentedTagHelper.RemarksAndSummaryProperty), + new TagHelperUsageDescriptor( + PropertyWithSummaryAndRemarks_Summary, + PropertyWithSummaryAndRemarks_Remarks) + }, + { + CreateDocumentationTagHelperType(nonExistentLocation, codeBase: null), + nameof(DocumentedTagHelper.RemarksAndSummaryProperty), + null + }, + { + CreateDocumentationTagHelperType(location: null, codeBase: nonExistentCodeBase), + nameof(DocumentedTagHelper.RemarksAndSummaryProperty), + null + }, + { + CreateDocumentationTagHelperType(invalidLocation, codeBase: null), + nameof(DocumentedTagHelper.RemarksAndSummaryProperty), + null + }, + { + CreateDocumentationTagHelperType(location: null, codeBase: invalidCodeBase), + nameof(DocumentedTagHelper.RemarksAndSummaryProperty), + null + } + }; + } + } + + [Theory] + [MemberData(nameof(CreateDescriptor_PropertyDocumentationData))] + public void CreateDescriptor_WithProperty_ReturnsExpectedDescriptors( + Type tagHelperType, + string propertyName, + TagHelperUsageDescriptor expectedUsageDescriptor) + { + // Arrange + var mockPropertyInfo = new Mock(); + mockPropertyInfo.Setup(propertyInfo => propertyInfo.DeclaringType).Returns(tagHelperType); + mockPropertyInfo.Setup(propertyInfo => propertyInfo.Name).Returns(propertyName); + + // Act + var usageDescriptor = TagHelperUsageDescriptorFactory.CreateDescriptor(mockPropertyInfo.Object); + + // Assert + Assert.Equal(expectedUsageDescriptor, usageDescriptor, TagHelperUsageDescriptorComparer.Default); + } + + public static TheoryData CreateDescriptor_LocalizedPropertyData + { + get + { + // tagHelperType, expectedUsageDescriptor, culture + return new TheoryData + { + { + CreateDocumentationTagHelperType(LocalizedDocumentedAssemblyLocation, codeBase: null), + new TagHelperUsageDescriptor( + summary: "en-GB: " + PropertyWithSummaryAndRemarks_Summary, + remarks: "en-GB: " + PropertyWithSummaryAndRemarks_Remarks), + "en-GB" + }, + { + CreateDocumentationTagHelperType(LocalizedDocumentedAssemblyLocation, codeBase: null), + new TagHelperUsageDescriptor( + summary: "en: " + PropertyWithSummaryAndRemarks_Summary, + remarks: "en: " + PropertyWithSummaryAndRemarks_Remarks), + "en-US" + }, + { + CreateDocumentationTagHelperType(LocalizedDocumentedAssemblyLocation, codeBase: null), + new TagHelperUsageDescriptor( + summary: "fr-FR: " + PropertyWithSummaryAndRemarks_Summary, + remarks: "fr-FR: " + PropertyWithSummaryAndRemarks_Remarks), + "fr-FR" + }, + { + CreateDocumentationTagHelperType(LocalizedDocumentedAssemblyLocation, codeBase: null), + new TagHelperUsageDescriptor( + summary: "fr: " + PropertyWithSummaryAndRemarks_Summary, + remarks: "fr: " + PropertyWithSummaryAndRemarks_Remarks), + "fr-BE" + }, + { + CreateDocumentationTagHelperType(LocalizedDocumentedAssemblyLocation, codeBase: null), + new TagHelperUsageDescriptor( + summary: "nl-BE: " + PropertyWithSummaryAndRemarks_Summary, + remarks: "nl-BE: " + PropertyWithSummaryAndRemarks_Remarks), + "nl-BE" + } + }; + } + } + + [Theory] + [MemberData(nameof(CreateDescriptor_LocalizedPropertyData))] + public void CreateDescriptor_WithLocalizedProperty_ReturnsExpectedDescriptors( + Type tagHelperType, + TagHelperUsageDescriptor expectedUsageDescriptor, + string culture) + { + // Arrange + var mockPropertyInfo = new Mock(); + mockPropertyInfo.Setup(propertyInfo => propertyInfo.DeclaringType).Returns(tagHelperType); + mockPropertyInfo + .Setup(propertyInfo => propertyInfo.Name) + .Returns(nameof(DocumentedTagHelper.RemarksAndSummaryProperty)); + TagHelperUsageDescriptor usageDescriptor; + + // Act + using (new CultureReplacer(culture)) + { + usageDescriptor = TagHelperUsageDescriptorFactory.CreateDescriptor(mockPropertyInfo.Object); + } + + // Assert + Assert.Equal(expectedUsageDescriptor, usageDescriptor, TagHelperUsageDescriptorComparer.Default); + } + + private static Type CreateDocumentationTagHelperType(string location, string codeBase) + { + return CreateType(location, codeBase); + } + + private static Type CreateType(string location, string codeBase) + { + var testAssembly = new TestAssembly(location, codeBase); + var wrappedType = typeof(TWrappedType); + var mockType = new Mock(); + mockType.Setup(type => type.Assembly).Returns(testAssembly); + mockType.Setup(type => type.FullName).Returns(wrappedType.FullName); + mockType.Setup(type => type.DeclaringType).Returns(wrappedType.DeclaringType); + + return mockType.Object; + } + + private class TestAssembly : Assembly + { + public TestAssembly(string location, string codeBase) + { + Location = location; + CodeBase = codeBase; + } + + public override string Location { get; } + + public override string CodeBase { get; } + } + } +} +#endif \ No newline at end of file diff --git a/test/Microsoft.AspNet.Razor.Runtime.Test/TestFiles/Localized/TagHelperDocumentation.nl-BE.xml b/test/Microsoft.AspNet.Razor.Runtime.Test/TestFiles/Localized/TagHelperDocumentation.nl-BE.xml new file mode 100644 index 0000000000..d9852c18d4 --- /dev/null +++ b/test/Microsoft.AspNet.Razor.Runtime.Test/TestFiles/Localized/TagHelperDocumentation.nl-BE.xml @@ -0,0 +1,34 @@ + + + + Microsoft.AspNet.Razor.Runtime.Test + + + + + nl-BE: The summary for . + + + nl-BE: Inherits from . + + + + + nl-BE: This is of type . + + + + + nl-BE: The may be null. + + + + + nl-BE: This is a complex . + + + nl-BE: + + + + diff --git a/test/Microsoft.AspNet.Razor.Runtime.Test/TestFiles/Localized/en-GB/TagHelperDocumentation.xml b/test/Microsoft.AspNet.Razor.Runtime.Test/TestFiles/Localized/en-GB/TagHelperDocumentation.xml new file mode 100644 index 0000000000..55db1e096c --- /dev/null +++ b/test/Microsoft.AspNet.Razor.Runtime.Test/TestFiles/Localized/en-GB/TagHelperDocumentation.xml @@ -0,0 +1,34 @@ + + + + Microsoft.AspNet.Razor.Runtime.Test + + + + + en-GB: The summary for . + + + en-GB: Inherits from . + + + + + en-GB: This is of type . + + + + + en-GB: The may be null. + + + + + en-GB: This is a complex . + + + en-GB: + + + + diff --git a/test/Microsoft.AspNet.Razor.Runtime.Test/TestFiles/Localized/en/TagHelperDocumentation.xml b/test/Microsoft.AspNet.Razor.Runtime.Test/TestFiles/Localized/en/TagHelperDocumentation.xml new file mode 100644 index 0000000000..60bfaa6c5e --- /dev/null +++ b/test/Microsoft.AspNet.Razor.Runtime.Test/TestFiles/Localized/en/TagHelperDocumentation.xml @@ -0,0 +1,34 @@ + + + + Microsoft.AspNet.Razor.Runtime.Test + + + + + en: The summary for . + + + en: Inherits from . + + + + + en: This is of type . + + + + + en: The may be null. + + + + + en: This is a complex . + + + en: + + + + diff --git a/test/Microsoft.AspNet.Razor.Runtime.Test/TestFiles/Localized/fr-FR/TagHelperDocumentation.fr-FR.xml b/test/Microsoft.AspNet.Razor.Runtime.Test/TestFiles/Localized/fr-FR/TagHelperDocumentation.fr-FR.xml new file mode 100644 index 0000000000..fa0c2a3b6e --- /dev/null +++ b/test/Microsoft.AspNet.Razor.Runtime.Test/TestFiles/Localized/fr-FR/TagHelperDocumentation.fr-FR.xml @@ -0,0 +1,34 @@ + + + + Microsoft.AspNet.Razor.Runtime.Test + + + + + fr-FR: The summary for . + + + fr-FR: Inherits from . + + + + + fr-FR: This is of type . + + + + + fr-FR: The may be null. + + + + + fr-FR: This is a complex . + + + fr-FR: + + + + diff --git a/test/Microsoft.AspNet.Razor.Runtime.Test/TestFiles/Localized/fr/TagHelperDocumentation.fr.xml b/test/Microsoft.AspNet.Razor.Runtime.Test/TestFiles/Localized/fr/TagHelperDocumentation.fr.xml new file mode 100644 index 0000000000..5c409f564f --- /dev/null +++ b/test/Microsoft.AspNet.Razor.Runtime.Test/TestFiles/Localized/fr/TagHelperDocumentation.fr.xml @@ -0,0 +1,34 @@ + + + + Microsoft.AspNet.Razor.Runtime.Test + + + + + fr: The summary for . + + + fr: Inherits from . + + + + + fr: This is of type . + + + + + fr: The may be null. + + + + + fr: This is a complex . + + + fr: + + + + diff --git a/test/Microsoft.AspNet.Razor.Runtime.Test/TestFiles/NotLocalized/TagHelperDocumentation.xml b/test/Microsoft.AspNet.Razor.Runtime.Test/TestFiles/NotLocalized/TagHelperDocumentation.xml new file mode 100644 index 0000000000..e79e17403f --- /dev/null +++ b/test/Microsoft.AspNet.Razor.Runtime.Test/TestFiles/NotLocalized/TagHelperDocumentation.xml @@ -0,0 +1,34 @@ + + + + Microsoft.AspNet.Razor.Runtime.Test + + + + + The summary for . + + + Inherits from . + + + + + This is of type . + + + + + The may be null. + + + + + This is a complex . + + + + + + + diff --git a/test/Microsoft.AspNet.Razor.Runtime.Test/XmlDocumentationProviderTest.cs b/test/Microsoft.AspNet.Razor.Runtime.Test/XmlDocumentationProviderTest.cs new file mode 100644 index 0000000000..384f166f37 --- /dev/null +++ b/test/Microsoft.AspNet.Razor.Runtime.Test/XmlDocumentationProviderTest.cs @@ -0,0 +1,155 @@ +// 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. + +#if !DNXCORE50 +using System; +using System.Globalization; +using System.IO; +using System.Reflection; +using Microsoft.AspNet.Razor.Runtime.TagHelpers; +using Xunit; + +namespace Microsoft.AspNet.Razor.Runtime +{ + public class XmlDocumentationProviderTest + { + public static readonly string XmlTestFileLocation = + Directory.GetCurrentDirectory() + "/TestFiles/NotLocalized/TagHelperDocumentation.xml"; + private static readonly TypeInfo DocumentedTagHelperTypeInfo = typeof(DocumentedTagHelper).GetTypeInfo(); + private static readonly PropertyInfo DocumentedTagHelperSummaryPropertyInfo = + DocumentedTagHelperTypeInfo.GetProperty(nameof(DocumentedTagHelper.SummaryProperty)); + private static readonly PropertyInfo DocumentedTagHelperRemarksPropertyInfo = + DocumentedTagHelperTypeInfo.GetProperty(nameof(DocumentedTagHelper.RemarksProperty)); + private static readonly PropertyInfo DocumentedTagHelperRemarksSummaryPropertyInfo = + DocumentedTagHelperTypeInfo.GetProperty(nameof(DocumentedTagHelper.RemarksAndSummaryProperty)); + + [Fact] + public void CanReadXml() + { + // Act. Ensuring that reading the Xml file doesn't throw. + new XmlDocumentationProvider(XmlTestFileLocation); + } + + public static TheoryData SummaryDocumentationData + { + get + { + var fullTypeName = DocumentedTagHelperTypeInfo.FullName; + + // id, expectedSummary + return new TheoryData + { + { + $"T:{fullTypeName}", + "The summary for ." + }, + { + $"P:{fullTypeName}.{DocumentedTagHelperSummaryPropertyInfo.Name}", + "This is of type ." + }, + { + $"P:{fullTypeName}.{DocumentedTagHelperRemarksPropertyInfo.Name}", + null + }, + { + $"P:{fullTypeName}.{DocumentedTagHelperRemarksSummaryPropertyInfo.Name}", + "This is a complex ." + } + }; + } + } + + [Theory] + [MemberData(nameof(SummaryDocumentationData))] + public void GetSummary_ReturnsExpectedSummarys(string id, string expectedSummary) + { + // Arrange + var xmlDocumentationProvider = new XmlDocumentationProvider(XmlTestFileLocation); + + // Act + var summary = xmlDocumentationProvider.GetSummary(id); + + // Assert + Assert.Equal(expectedSummary, summary, StringComparer.Ordinal); + } + + public static TheoryData RemarksDocumentationData + { + get + { + var fullTypeName = DocumentedTagHelperTypeInfo.FullName; + + // id, expectedRemarks + return new TheoryData + { + { + $"T:{fullTypeName}", + "Inherits from ." + }, + { + $"P:{fullTypeName}.{DocumentedTagHelperSummaryPropertyInfo.Name}", + null + }, + { + $"P:{fullTypeName}.{DocumentedTagHelperRemarksPropertyInfo.Name}", + "The may be null." + }, + { + $"P:{fullTypeName}.{DocumentedTagHelperRemarksSummaryPropertyInfo.Name}", + "" + } + }; + } + } + + [Theory] + [MemberData(nameof(RemarksDocumentationData))] + public void GetRemarks_ReturnsExpectedRemarks(string id, string expectedRemarks) + { + // Arrange + var xmlDocumentationProvider = new XmlDocumentationProvider(XmlTestFileLocation); + + // Act + var remarks = xmlDocumentationProvider.GetRemarks(id); + + // Assert + Assert.Equal(expectedRemarks, remarks, StringComparer.Ordinal); + } + + [Fact] + public void GetId_UnderstandsTypeInfo() + { + // Arrange + var expectedId = "T:" + typeof(DocumentedTagHelper).FullName; + + // Act + var id = XmlDocumentationProvider.GetId(DocumentedTagHelperTypeInfo); + + // Assert + Assert.Equal(expectedId, id, StringComparer.Ordinal); + } + + [Fact] + public void GetId_UnderstandsPropertyInfo() + { + // Arrange + var expectedId = string.Format( + CultureInfo.InvariantCulture, + "P:{0}.{1}", + typeof(DocumentedTagHelper).FullName, + nameof(DocumentedTagHelper.RemarksAndSummaryProperty)); + + // Act + var id = XmlDocumentationProvider.GetId(DocumentedTagHelperRemarksSummaryPropertyInfo); + + // Assert + Assert.Equal(expectedId, id, StringComparer.Ordinal); + } + } +} +#endif \ No newline at end of file diff --git a/test/Microsoft.AspNet.Razor.Runtime.Test/project.json b/test/Microsoft.AspNet.Razor.Runtime.Test/project.json index 1e7e17a924..a37a57bfe0 100644 --- a/test/Microsoft.AspNet.Razor.Runtime.Test/project.json +++ b/test/Microsoft.AspNet.Razor.Runtime.Test/project.json @@ -1,20 +1,24 @@ { - "version": "1.0.0", - "dependencies": { - "Microsoft.AspNet.Razor.Runtime": "4.0.0-*", - "Microsoft.AspNet.Testing": "1.0.0-*", - "xunit.runner.aspnet": "2.0.0-aspnet-*" + "version": "1.0.0", + "dependencies": { + "Microsoft.AspNet.Razor.Runtime": "4.0.0-*", + "Microsoft.AspNet.Testing": "1.0.0-*", + "xunit.runner.aspnet": "2.0.0-aspnet-*" + }, + "commands": { + "test": "xunit.runner.aspnet" + }, + "frameworks": { + "dnx451": { + "dependencies": { + "Moq": "4.2.1312.1622" + } }, - "commands": { - "test": "xunit.runner.aspnet" - }, - "frameworks": { - "dnx451": { }, - "dnxcore50": { - "dependencies": { - "System.Reflection.TypeExtensions": "4.0.0-beta-*", - "System.Runtime.Extensions": "4.0.10-beta-*" - } - } + "dnxcore50": { + "dependencies": { + "System.Reflection.TypeExtensions": "4.0.0-beta-*", + "System.Runtime.Extensions": "4.0.10-beta-*" + } } + } } diff --git a/test/Microsoft.AspNet.Razor.Test/CodeGenerators/CSharpTagHelperRenderingTest.cs b/test/Microsoft.AspNet.Razor.Test/CodeGenerators/CSharpTagHelperRenderingTest.cs index 0ee768f192..69e2c49b90 100644 --- a/test/Microsoft.AspNet.Razor.Test/CodeGenerators/CSharpTagHelperRenderingTest.cs +++ b/test/Microsoft.AspNet.Razor.Test/CodeGenerators/CSharpTagHelperRenderingTest.cs @@ -35,7 +35,8 @@ namespace Microsoft.AspNet.Razor.Test.Generator "catchall-bound-string", "BoundRequiredString", typeof(string).FullName, - isIndexer: false), + isIndexer: false, + usageDescriptor: null), }, requiredAttributes: new[] { "catchall-unbound-required" }), new TagHelperDescriptor( @@ -48,12 +49,14 @@ namespace Microsoft.AspNet.Razor.Test.Generator "input-bound-required-string", "BoundRequiredString", typeof(string).FullName, - isIndexer: false), + isIndexer: false, + usageDescriptor: null), new TagHelperAttributeDescriptor( "input-bound-string", "BoundString", typeof(string).FullName, - isIndexer: false) + isIndexer: false, + usageDescriptor: null) }, requiredAttributes: new[] { "input-bound-required-string", "input-unbound-required" }), }; @@ -171,32 +174,38 @@ namespace Microsoft.AspNet.Razor.Test.Generator name: "int-prefix-grabber", propertyName: "IntProperty", typeName: typeof(int).FullName, - isIndexer: false), + isIndexer: false, + usageDescriptor: null), new TagHelperAttributeDescriptor( name: "int-dictionary", propertyName: "IntDictionaryProperty", typeName: typeof(IDictionary).FullName, - isIndexer: false), + isIndexer: false, + usageDescriptor: null), new TagHelperAttributeDescriptor( name: "string-dictionary", propertyName: "StringDictionaryProperty", typeName: "Namespace.DictionaryWithoutParameterlessConstructor", - isIndexer: false), + isIndexer: false, + usageDescriptor: null), new TagHelperAttributeDescriptor( name: "string-prefix-grabber", propertyName: "StringProperty", typeName: typeof(string).FullName, - isIndexer: false), + isIndexer: false, + usageDescriptor: null), new TagHelperAttributeDescriptor( name: "int-prefix-", propertyName: "IntDictionaryProperty", typeName: typeof(int).FullName, - isIndexer: true), + isIndexer: true, + usageDescriptor: null), new TagHelperAttributeDescriptor( name: "string-prefix-", propertyName: "StringDictionaryProperty", typeName: typeof(string).FullName, - isIndexer: true), + isIndexer: true, + usageDescriptor: null), }), new TagHelperDescriptor( tagName: "input", @@ -208,22 +217,26 @@ namespace Microsoft.AspNet.Razor.Test.Generator name: "int-dictionary", propertyName: "IntDictionaryProperty", typeName: typeof(IDictionary).FullName, - isIndexer: false), + isIndexer: false, + usageDescriptor: null), new TagHelperAttributeDescriptor( name: "string-dictionary", propertyName: "StringDictionaryProperty", typeName: "Namespace.DictionaryWithoutParameterlessConstructor", - isIndexer: false), + isIndexer: false, + usageDescriptor: null), new TagHelperAttributeDescriptor( name: "int-prefix-", propertyName: "IntDictionaryProperty", typeName: typeof(int).FullName, - isIndexer: true), + isIndexer: true, + usageDescriptor: null), new TagHelperAttributeDescriptor( name: "string-prefix-", propertyName: "StringDictionaryProperty", typeName: typeof(string).FullName, - isIndexer: true), + isIndexer: true, + usageDescriptor: null), }), }; } @@ -1051,7 +1064,8 @@ namespace Microsoft.AspNet.Razor.Test.Generator { new TagHelperAttributeDescriptor("age", pAgePropertyInfo) }, - requiredAttributes: Enumerable.Empty()), + requiredAttributes: Enumerable.Empty(), + usageDescriptor: null), new TagHelperDescriptor( prefix, tagName: "input", @@ -1061,7 +1075,8 @@ namespace Microsoft.AspNet.Razor.Test.Generator { new TagHelperAttributeDescriptor("type", inputTypePropertyInfo) }, - requiredAttributes: Enumerable.Empty()), + requiredAttributes: Enumerable.Empty(), + usageDescriptor: null), new TagHelperDescriptor( prefix, tagName: "input", @@ -1072,7 +1087,8 @@ namespace Microsoft.AspNet.Razor.Test.Generator new TagHelperAttributeDescriptor("type", inputTypePropertyInfo), new TagHelperAttributeDescriptor("checked", checkedPropertyInfo) }, - requiredAttributes: Enumerable.Empty()) + requiredAttributes: Enumerable.Empty(), + usageDescriptor: null) }; } diff --git a/test/Microsoft.AspNet.Razor.Test/TagHelpers/TagHelperBlockRewriterTest.cs b/test/Microsoft.AspNet.Razor.Test/TagHelpers/TagHelperBlockRewriterTest.cs index f45124d1c5..324d212ab4 100644 --- a/test/Microsoft.AspNet.Razor.Test/TagHelpers/TagHelperBlockRewriterTest.cs +++ b/test/Microsoft.AspNet.Razor.Test/TagHelpers/TagHelperBlockRewriterTest.cs @@ -766,13 +766,24 @@ namespace Microsoft.AspNet.Razor.TagHelpers new TagHelperDescriptor("person", "PersonTagHelper", "personAssembly", attributes: new[] { - new TagHelperAttributeDescriptor("age", "Age", typeof(int).FullName, isIndexer: false), new TagHelperAttributeDescriptor( - "birthday", - "BirthDay", - typeof(DateTime).FullName, - isIndexer: false), - new TagHelperAttributeDescriptor("name", "Name", typeof(string).FullName, isIndexer: false), + name: "age", + propertyName: "Age", + typeName: typeof(int).FullName, + isIndexer: false, + usageDescriptor: null), + new TagHelperAttributeDescriptor( + name: "birthday", + propertyName: "BirthDay", + typeName: typeof(DateTime).FullName, + isIndexer: false, + usageDescriptor: null), + new TagHelperAttributeDescriptor( + name: "name", + propertyName: "Name", + typeName: typeof(string).FullName, + isIndexer: false, + usageDescriptor: null), }) }; var providerContext = new TagHelperDescriptorProvider(descriptors); @@ -1772,12 +1783,14 @@ namespace Microsoft.AspNet.Razor.TagHelpers name: "bound", propertyName: "Bound", typeName: typeof(bool).FullName, - isIndexer: false), + isIndexer: false, + usageDescriptor: null), new TagHelperAttributeDescriptor( name: "name", propertyName: "Name", typeName: typeof(string).FullName, - isIndexer: false) + isIndexer: false, + usageDescriptor: null) }) }; var descriptorProvider = new TagHelperDescriptorProvider(descriptors); @@ -3266,7 +3279,8 @@ namespace Microsoft.AspNet.Razor.TagHelpers "bound-required-string", "BoundRequiredString", typeof(string).FullName, - isIndexer: false) + isIndexer: false, + usageDescriptor: null) }, requiredAttributes: new[] { "unbound-required" }), new TagHelperDescriptor( @@ -3279,7 +3293,8 @@ namespace Microsoft.AspNet.Razor.TagHelpers "bound-required-string", "BoundRequiredString", typeof(string).FullName, - isIndexer: false) + isIndexer: false, + usageDescriptor: null) }, requiredAttributes: new[] { "bound-required-string" }), new TagHelperDescriptor( @@ -3292,7 +3307,8 @@ namespace Microsoft.AspNet.Razor.TagHelpers "bound-required-int", "BoundRequiredInt", typeof(int).FullName, - isIndexer: false) + isIndexer: false, + usageDescriptor: null) }, requiredAttributes: new[] { "bound-required-int" }), new TagHelperDescriptor( @@ -3305,22 +3321,26 @@ namespace Microsoft.AspNet.Razor.TagHelpers "int-dictionary", "DictionaryOfIntProperty", typeof(IDictionary).FullName, - isIndexer: false), + isIndexer: false, + usageDescriptor: null), new TagHelperAttributeDescriptor( "string-dictionary", "DictionaryOfStringProperty", typeof(IDictionary).FullName, - isIndexer: false), + isIndexer: false, + usageDescriptor: null), new TagHelperAttributeDescriptor( "int-prefix-", "DictionaryOfIntProperty", typeof(int).FullName, - isIndexer: true), + isIndexer: true, + usageDescriptor: null), new TagHelperAttributeDescriptor( "string-prefix-", "DictionaryOfStringProperty", typeof(string).FullName, - isIndexer: true), + isIndexer: true, + usageDescriptor: null), }, requiredAttributes: Enumerable.Empty()), new TagHelperDescriptor( @@ -3333,12 +3353,14 @@ namespace Microsoft.AspNet.Razor.TagHelpers "bound-string", "BoundRequiredString", typeof(string).FullName, - isIndexer: false), + isIndexer: false, + usageDescriptor: null), new TagHelperAttributeDescriptor( "bound-int", "BoundRequiredString", typeof(int).FullName, - isIndexer: false) + isIndexer: false, + usageDescriptor: null) }, requiredAttributes: Enumerable.Empty()), }; diff --git a/test/Microsoft.AspNet.Razor.Test/TagHelpers/TagHelperDescriptorProviderTest.cs b/test/Microsoft.AspNet.Razor.Test/TagHelpers/TagHelperDescriptorProviderTest.cs index 14f9a98fd9..1ec532a4a3 100644 --- a/test/Microsoft.AspNet.Razor.Test/TagHelpers/TagHelperDescriptorProviderTest.cs +++ b/test/Microsoft.AspNet.Razor.Test/TagHelpers/TagHelperDescriptorProviderTest.cs @@ -320,7 +320,8 @@ namespace Microsoft.AspNet.Razor.TagHelpers typeName, assemblyName: "SomeAssembly", attributes: Enumerable.Empty(), - requiredAttributes: Enumerable.Empty()); + requiredAttributes: Enumerable.Empty(), + usageDescriptor: null); } } } \ No newline at end of file diff --git a/test/Microsoft.AspNet.Razor.Test/TagHelpers/TagHelperDescriptorTest.cs b/test/Microsoft.AspNet.Razor.Test/TagHelpers/TagHelperDescriptorTest.cs index ab545373c5..36dc73bf00 100644 --- a/test/Microsoft.AspNet.Razor.Test/TagHelpers/TagHelperDescriptorTest.cs +++ b/test/Microsoft.AspNet.Razor.Test/TagHelpers/TagHelperDescriptorTest.cs @@ -20,7 +20,9 @@ namespace Microsoft.AspNet.Razor.TagHelpers typeName: "type name", assemblyName: "assembly name", attributes: Enumerable.Empty(), - requiredAttributes: new[] { "required attribute one", "required attribute two" }); + requiredAttributes: new[] { "required attribute one", "required attribute two" }, + usageDescriptor: new TagHelperUsageDescriptor("usage summary", "usage remarks")); + var expectedSerializedDescriptor = $"{{\"{ nameof(TagHelperDescriptor.Prefix) }\":\"prefix:\"," + $"\"{ nameof(TagHelperDescriptor.TagName) }\":\"tag name\"," + @@ -29,7 +31,10 @@ namespace Microsoft.AspNet.Razor.TagHelpers $"\"{ nameof(TagHelperDescriptor.AssemblyName) }\":\"assembly name\"," + $"\"{ nameof(TagHelperDescriptor.Attributes) }\":[]," + $"\"{ nameof(TagHelperDescriptor.RequiredAttributes) }\":" + - "[\"required attribute one\",\"required attribute two\"]}"; + "[\"required attribute one\",\"required attribute two\"]," + + $"\"{ nameof(TagHelperDescriptor.UsageDescriptor) }\":{{"+ + $"\"{ nameof(TagHelperUsageDescriptor.Summary) }\":\"usage summary\"," + + $"\"{ nameof(TagHelperUsageDescriptor.Remarks) }\":\"usage remarks\"}}}}"; // Act var serializedDescriptor = JsonConvert.SerializeObject(descriptor); @@ -53,14 +58,17 @@ namespace Microsoft.AspNet.Razor.TagHelpers name: "attribute one", propertyName: "property name", typeName: "property type name", - isIndexer: false), + isIndexer: false, + usageDescriptor: null), new TagHelperAttributeDescriptor( name: "attribute two", propertyName: "property name", typeName: typeof(string).FullName, - isIndexer: false), + isIndexer: false, + usageDescriptor: null), }, - requiredAttributes: Enumerable.Empty()); + requiredAttributes: Enumerable.Empty(), + usageDescriptor: null); var expectedSerializedDescriptor = $"{{\"{ nameof(TagHelperDescriptor.Prefix) }\":\"prefix:\"," + $"\"{ nameof(TagHelperDescriptor.TagName) }\":\"tag name\"," + @@ -72,13 +80,16 @@ namespace Microsoft.AspNet.Razor.TagHelpers $"\"{ nameof(TagHelperAttributeDescriptor.IsStringProperty) }\":false," + $"\"{ nameof(TagHelperAttributeDescriptor.Name) }\":\"attribute one\"," + $"\"{ nameof(TagHelperAttributeDescriptor.PropertyName) }\":\"property name\"," + - $"\"{ nameof(TagHelperAttributeDescriptor.TypeName) }\":\"property type name\"}}," + + $"\"{ nameof(TagHelperAttributeDescriptor.TypeName) }\":\"property type name\"," + + $"\"{ nameof(TagHelperAttributeDescriptor.UsageDescriptor) }\":null}}," + $"{{\"{ nameof(TagHelperAttributeDescriptor.IsIndexer) }\":false," + $"\"{ nameof(TagHelperAttributeDescriptor.IsStringProperty) }\":true," + $"\"{ nameof(TagHelperAttributeDescriptor.Name) }\":\"attribute two\"," + $"\"{ nameof(TagHelperAttributeDescriptor.PropertyName) }\":\"property name\"," + - $"\"{ nameof(TagHelperAttributeDescriptor.TypeName) }\":\"{ typeof(string).FullName }\"}}]," + - $"\"{ nameof(TagHelperDescriptor.RequiredAttributes) }\":[]}}"; + $"\"{ nameof(TagHelperAttributeDescriptor.TypeName) }\":\"{ typeof(string).FullName }\"," + + $"\"{ nameof(TagHelperAttributeDescriptor.UsageDescriptor) }\":null}}]," + + $"\"{ nameof(TagHelperDescriptor.RequiredAttributes) }\":[]," + + $"\"{ nameof(TagHelperDescriptor.UsageDescriptor) }\":null}}"; // Act var serializedDescriptor = JsonConvert.SerializeObject(descriptor); @@ -102,14 +113,17 @@ namespace Microsoft.AspNet.Razor.TagHelpers name: "attribute one", propertyName: "property name", typeName: "property type name", - isIndexer: true), + isIndexer: true, + usageDescriptor: null), new TagHelperAttributeDescriptor( name: "attribute two", propertyName: "property name", typeName: typeof(string).FullName, - isIndexer: true), + isIndexer: true, + usageDescriptor: null), }, - requiredAttributes: Enumerable.Empty()); + requiredAttributes: Enumerable.Empty(), + usageDescriptor: null); var expectedSerializedDescriptor = $"{{\"{ nameof(TagHelperDescriptor.Prefix) }\":\"prefix:\"," + $"\"{ nameof(TagHelperDescriptor.TagName) }\":\"tag name\"," + @@ -121,13 +135,16 @@ namespace Microsoft.AspNet.Razor.TagHelpers $"\"{ nameof(TagHelperAttributeDescriptor.IsStringProperty) }\":false," + $"\"{ nameof(TagHelperAttributeDescriptor.Name) }\":\"attribute one\"," + $"\"{ nameof(TagHelperAttributeDescriptor.PropertyName) }\":\"property name\"," + - $"\"{ nameof(TagHelperAttributeDescriptor.TypeName) }\":\"property type name\"}}," + + $"\"{ nameof(TagHelperAttributeDescriptor.TypeName) }\":\"property type name\"," + + $"\"{ nameof(TagHelperAttributeDescriptor.UsageDescriptor) }\":null}}," + $"{{\"{ nameof(TagHelperAttributeDescriptor.IsIndexer) }\":true," + $"\"{ nameof(TagHelperAttributeDescriptor.IsStringProperty) }\":true," + $"\"{ nameof(TagHelperAttributeDescriptor.Name) }\":\"attribute two\"," + $"\"{ nameof(TagHelperAttributeDescriptor.PropertyName) }\":\"property name\"," + - $"\"{ nameof(TagHelperAttributeDescriptor.TypeName) }\":\"{ typeof(string).FullName }\"}}]," + - $"\"{ nameof(TagHelperDescriptor.RequiredAttributes) }\":[]}}"; + $"\"{ nameof(TagHelperAttributeDescriptor.TypeName) }\":\"{ typeof(string).FullName }\"," + + $"\"{ nameof(TagHelperAttributeDescriptor.UsageDescriptor) }\":null}}]," + + $"\"{ nameof(TagHelperDescriptor.RequiredAttributes) }\":[]," + + $"\"{ nameof(TagHelperDescriptor.UsageDescriptor) }\":null}}"; // Act var serializedDescriptor = JsonConvert.SerializeObject(descriptor); @@ -148,14 +165,18 @@ namespace Microsoft.AspNet.Razor.TagHelpers $"\"{nameof(TagHelperDescriptor.AssemblyName)}\":\"assembly name\"," + $"\"{nameof(TagHelperDescriptor.Attributes)}\":[]," + $"\"{nameof(TagHelperDescriptor.RequiredAttributes)}\":" + - "[\"required attribute one\",\"required attribute two\"]}"; + "[\"required attribute one\",\"required attribute two\"]," + + $"\"{ nameof(TagHelperDescriptor.UsageDescriptor) }\":{{" + + $"\"{ nameof(TagHelperUsageDescriptor.Summary) }\":\"usage summary\"," + + $"\"{ nameof(TagHelperUsageDescriptor.Remarks) }\":\"usage remarks\"}}}}"; var expectedDescriptor = new TagHelperDescriptor( prefix: "prefix:", tagName: "tag name", typeName: "type name", assemblyName: "assembly name", attributes: Enumerable.Empty(), - requiredAttributes: new[] { "required attribute one", "required attribute two" }); + requiredAttributes: new[] { "required attribute one", "required attribute two" }, + usageDescriptor: new TagHelperUsageDescriptor("usage summary", "usage remarks")); // Act var descriptor = JsonConvert.DeserializeObject(serializedDescriptor); @@ -169,6 +190,10 @@ namespace Microsoft.AspNet.Razor.TagHelpers Assert.Equal(expectedDescriptor.AssemblyName, descriptor.AssemblyName, StringComparer.Ordinal); Assert.Empty(descriptor.Attributes); Assert.Equal(expectedDescriptor.RequiredAttributes, descriptor.RequiredAttributes, StringComparer.Ordinal); + Assert.Equal( + expectedDescriptor.UsageDescriptor, + descriptor.UsageDescriptor, + TagHelperUsageDescriptorComparer.Default); } [Fact] @@ -186,13 +211,16 @@ namespace Microsoft.AspNet.Razor.TagHelpers $"\"{ nameof(TagHelperAttributeDescriptor.IsStringProperty) }\":false," + $"\"{ nameof(TagHelperAttributeDescriptor.Name) }\":\"attribute one\"," + $"\"{ nameof(TagHelperAttributeDescriptor.PropertyName) }\":\"property name\"," + - $"\"{ nameof(TagHelperAttributeDescriptor.TypeName) }\":\"property type name\"}}," + + $"\"{ nameof(TagHelperAttributeDescriptor.TypeName) }\":\"property type name\"," + + $"\"{ nameof(TagHelperAttributeDescriptor.UsageDescriptor) }\":null}}," + $"{{\"{ nameof(TagHelperAttributeDescriptor.IsIndexer) }\":false," + $"\"{ nameof(TagHelperAttributeDescriptor.IsStringProperty) }\":true," + $"\"{ nameof(TagHelperAttributeDescriptor.Name) }\":\"attribute two\"," + $"\"{ nameof(TagHelperAttributeDescriptor.PropertyName) }\":\"property name\"," + - $"\"{ nameof(TagHelperAttributeDescriptor.TypeName) }\":\"{ typeof(string).FullName }\"}}]," + - $"\"{ nameof(TagHelperDescriptor.RequiredAttributes) }\":[]}}"; + $"\"{ nameof(TagHelperAttributeDescriptor.TypeName) }\":\"{ typeof(string).FullName }\"," + + $"\"{ nameof(TagHelperAttributeDescriptor.UsageDescriptor) }\":null}}]," + + $"\"{ nameof(TagHelperDescriptor.RequiredAttributes) }\":[]," + + $"\"{ nameof(TagHelperDescriptor.UsageDescriptor) }\":null}}"; var expectedDescriptor = new TagHelperDescriptor( prefix: "prefix:", tagName: "tag name", @@ -204,14 +232,17 @@ namespace Microsoft.AspNet.Razor.TagHelpers name: "attribute one", propertyName: "property name", typeName: "property type name", - isIndexer: false), + isIndexer: false, + usageDescriptor: null), new TagHelperAttributeDescriptor( name: "attribute two", propertyName: "property name", typeName: typeof(string).FullName, - isIndexer: false), + isIndexer: false, + usageDescriptor: null), }, - requiredAttributes: Enumerable.Empty()); + requiredAttributes: Enumerable.Empty(), + usageDescriptor: null); // Act var descriptor = JsonConvert.DeserializeObject(serializedDescriptor); @@ -267,13 +298,16 @@ namespace Microsoft.AspNet.Razor.TagHelpers $"\"{ nameof(TagHelperAttributeDescriptor.IsStringProperty) }\":false," + $"\"{ nameof(TagHelperAttributeDescriptor.Name) }\":\"attribute one\"," + $"\"{ nameof(TagHelperAttributeDescriptor.PropertyName) }\":\"property name\"," + - $"\"{ nameof(TagHelperAttributeDescriptor.TypeName) }\":\"property type name\"}}," + + $"\"{ nameof(TagHelperAttributeDescriptor.TypeName) }\":\"property type name\"," + + $"\"{ nameof(TagHelperAttributeDescriptor.UsageDescriptor) }\":null}}," + $"{{\"{ nameof(TagHelperAttributeDescriptor.IsIndexer) }\":true," + $"\"{ nameof(TagHelperAttributeDescriptor.IsStringProperty) }\":true," + $"\"{ nameof(TagHelperAttributeDescriptor.Name) }\":\"attribute two\"," + $"\"{ nameof(TagHelperAttributeDescriptor.PropertyName) }\":\"property name\"," + - $"\"{ nameof(TagHelperAttributeDescriptor.TypeName) }\":\"{ typeof(string).FullName }\"}}]," + - $"\"{ nameof(TagHelperDescriptor.RequiredAttributes) }\":[]}}"; + $"\"{ nameof(TagHelperAttributeDescriptor.TypeName) }\":\"{ typeof(string).FullName }\"," + + $"\"{ nameof(TagHelperAttributeDescriptor.UsageDescriptor) }\":null}}]," + + $"\"{ nameof(TagHelperDescriptor.RequiredAttributes) }\":[]," + + $"\"{ nameof(TagHelperDescriptor.UsageDescriptor) }\":null}}"; var expectedDescriptor = new TagHelperDescriptor( prefix: "prefix:", tagName: "tag name", @@ -285,14 +319,17 @@ namespace Microsoft.AspNet.Razor.TagHelpers name: "attribute one", propertyName: "property name", typeName: "property type name", - isIndexer: true), + isIndexer: true, + usageDescriptor: null), new TagHelperAttributeDescriptor( name: "attribute two", propertyName: "property name", typeName: typeof(string).FullName, - isIndexer: true), + isIndexer: true, + usageDescriptor: null), }, - requiredAttributes: Enumerable.Empty()); + requiredAttributes: Enumerable.Empty(), + usageDescriptor: null); // Act var descriptor = JsonConvert.DeserializeObject(serializedDescriptor); diff --git a/test/Microsoft.AspNet.Razor.Test/TagHelpers/TagHelperParseTreeRewriterTest.cs b/test/Microsoft.AspNet.Razor.Test/TagHelpers/TagHelperParseTreeRewriterTest.cs index bf5b6cce8f..f7d7138ae1 100644 --- a/test/Microsoft.AspNet.Razor.Test/TagHelpers/TagHelperParseTreeRewriterTest.cs +++ b/test/Microsoft.AspNet.Razor.Test/TagHelpers/TagHelperParseTreeRewriterTest.cs @@ -910,7 +910,8 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers typeName: "mythTagHelper", assemblyName: "SomeAssembly", attributes: Enumerable.Empty(), - requiredAttributes: Enumerable.Empty()), + requiredAttributes: Enumerable.Empty(), + usageDescriptor: null), new TagHelperDescriptor( prefix: "th:", tagName: "myth2", @@ -922,9 +923,11 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers name: "bound", propertyName: "Bound", typeName: typeof(bool).FullName, - isIndexer: false), + isIndexer: false, + usageDescriptor: null), }, - requiredAttributes: Enumerable.Empty()) + requiredAttributes: Enumerable.Empty(), + usageDescriptor: null) }; var availableDescriptorsText = new TagHelperDescriptor[] { @@ -934,7 +937,8 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers typeName: "mythTagHelper", assemblyName: "SomeAssembly", attributes: Enumerable.Empty(), - requiredAttributes: Enumerable.Empty()), + requiredAttributes: Enumerable.Empty(), + usageDescriptor: null), new TagHelperDescriptor( prefix: "PREFIX", tagName: "myth2", @@ -946,9 +950,11 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers name: "bound", propertyName: "Bound", typeName: typeof(bool).FullName, - isIndexer: false), + isIndexer: false, + usageDescriptor: null), }, - requiredAttributes: Enumerable.Empty()) + requiredAttributes: Enumerable.Empty(), + usageDescriptor: null) }; var availableDescriptorsCatchAll = new TagHelperDescriptor[] { @@ -958,7 +964,8 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers typeName: "mythTagHelper", assemblyName: "SomeAssembly", attributes: Enumerable.Empty(), - requiredAttributes: Enumerable.Empty()), + requiredAttributes: Enumerable.Empty(), + usageDescriptor: null), }; // documentContent, expectedOutput, availableDescriptors diff --git a/test/Microsoft.AspNet.Razor.Test/TagHelpers/TagHelperUsageDescriptorComparer.cs b/test/Microsoft.AspNet.Razor.Test/TagHelpers/TagHelperUsageDescriptorComparer.cs new file mode 100644 index 0000000000..2d77b702ae --- /dev/null +++ b/test/Microsoft.AspNet.Razor.Test/TagHelpers/TagHelperUsageDescriptorComparer.cs @@ -0,0 +1,40 @@ +// 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 Microsoft.Internal.Web.Utils; + +namespace Microsoft.AspNet.Razor.TagHelpers +{ + public class TagHelperUsageDescriptorComparer : IEqualityComparer + { + public static readonly TagHelperUsageDescriptorComparer Default = new TagHelperUsageDescriptorComparer(); + + private TagHelperUsageDescriptorComparer() + { + } + + public bool Equals(TagHelperUsageDescriptor descriptorX, TagHelperUsageDescriptor descriptorY) + { + if (descriptorX == descriptorY) + { + return true; + } + + return descriptorX != null && + descriptorY != null && + string.Equals(descriptorX.Summary, descriptorY.Summary, StringComparison.Ordinal) && + string.Equals(descriptorX.Remarks, descriptorY.Remarks, StringComparison.Ordinal); + } + + public int GetHashCode(TagHelperUsageDescriptor descriptor) + { + return HashCodeCombiner + .Start() + .Add(descriptor.Summary, StringComparer.Ordinal) + .Add(descriptor.Remarks, StringComparer.Ordinal) + .CombinedHash; + } + } +}