Modify tests to use new ITagHelperDescriptorResolver signature.

- Updated all of the tests to use the new ITagHelperDescriptorResolver signature so instead of passing strings they now construct TagHelperDescriptorResolutionContexts.
- Removed several tests from the AddOrRemoveTagHelperSpanVisitorTests. This was due to the change in responsibility of managing the found TagHelperDescriptors; the TagHelperDescriptorResolver now does this.
- Added several new tests to verify the TagHelperDescriptorResolver manages resolved TagHelperDescriptors based on the given TagHelperDirectiveDescriptors.

#214
This commit is contained in:
N. Taylor Mullen 2014-10-31 15:04:41 -07:00
parent c35d19142c
commit c67ec264ed
4 changed files with 459 additions and 192 deletions

View File

@ -61,7 +61,8 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
}
}
private static bool IsTagHelper(TypeInfo typeInfo)
// Internal for testing.
internal virtual bool IsTagHelper(TypeInfo typeInfo)
{
return typeInfo.IsPublic &&
!typeInfo.IsAbstract &&

View File

@ -15,44 +15,322 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
private static readonly string AssemblyName =
typeof(TagHelperDescriptorFactoryTest).GetTypeInfo().Assembly.GetName().Name;
private static readonly Type Valid_PlainTagHelperType = typeof(Valid_PlainTagHelper);
private static readonly Type Valid_InheritedTagHelperType = typeof(Valid_InheritedTagHelper);
private static TagHelperDescriptor Valid_PlainTagHelperDescriptor
{
get
{
return new TagHelperDescriptor("Valid_Plain",
Valid_PlainTagHelperType.FullName,
AssemblyName,
ContentBehavior.None);
}
}
private static TagHelperDescriptor Valid_InheritedTagHelperDescriptor
{
get
{
return new TagHelperDescriptor("Valid_Inherited",
Valid_InheritedTagHelperType.FullName,
AssemblyName,
ContentBehavior.None);
}
}
[Theory]
[InlineData("MyType, MyAssembly", "MyAssembly")]
[InlineData("MyAssembly2", "MyAssembly2")]
public void Resolve_AllowsOverridenResolveDescriptorsInAssembly(string lookupText, string expectedAssemblyName)
{
// Arrange
var tagHelperDescriptorResolver = new TestTagHelperDescriptorResolver();
var tagHelperDescriptorResolver = new AssemblyCheckingTagHelperDescriptorResolver();
var context = new TagHelperDescriptorResolutionContext(
new[] { new TagHelperDirectiveDescriptor(lookupText, TagHelperDirectiveType.AddTagHelper) });
// Act
tagHelperDescriptorResolver.Resolve(lookupText);
tagHelperDescriptorResolver.Resolve(context);
// Assert
Assert.Equal(expectedAssemblyName, tagHelperDescriptorResolver.CalledWithAssemblyName);
}
public static TheoryData ResolveDirectiveDescriptorsData
{
get
{
var assemblyA = AssemblyName;
var stringType = typeof(string);
var assemblyB = stringType.GetTypeInfo().Assembly.GetName().Name;
// We're treating 'string' as a TagHelper so we can test TagHelpers in multiple assemblies without
// building a separate assembly with a single TagHelper.
var stringTagHelperDescriptor =
new TagHelperDescriptor("string",
"System.String",
assemblyB,
ContentBehavior.None);
return new TheoryData<Dictionary<string, IEnumerable<Type>>, // descriptorAssemblyLookups
IEnumerable<TagHelperDirectiveDescriptor>, // directiveDescriptors
IEnumerable<TagHelperDescriptor>> // expectedDescriptors
{
{
new Dictionary<string, IEnumerable<Type>>
{
{ assemblyA, new [] { Valid_PlainTagHelperType } }
},
new []
{
new TagHelperDirectiveDescriptor(assemblyA, TagHelperDirectiveType.AddTagHelper)
},
new [] { Valid_PlainTagHelperDescriptor }
},
{
new Dictionary<string, IEnumerable<Type>>
{
{ assemblyA, new [] { Valid_PlainTagHelperType } },
{ assemblyB, new [] { stringType } }
},
new []
{
new TagHelperDirectiveDescriptor(assemblyA, TagHelperDirectiveType.AddTagHelper),
new TagHelperDirectiveDescriptor(assemblyB, TagHelperDirectiveType.AddTagHelper)
},
new [] { Valid_PlainTagHelperDescriptor, stringTagHelperDescriptor }
},
{
new Dictionary<string, IEnumerable<Type>>
{
{ assemblyA, new [] { Valid_PlainTagHelperType } },
{ assemblyB, new [] { stringType } }
},
new []
{
new TagHelperDirectiveDescriptor(assemblyA, TagHelperDirectiveType.AddTagHelper),
new TagHelperDirectiveDescriptor(assemblyB, TagHelperDirectiveType.RemoveTagHelper)
},
new [] { Valid_PlainTagHelperDescriptor }
},
{
new Dictionary<string, IEnumerable<Type>>
{
{ assemblyA, new [] { Valid_PlainTagHelperType, Valid_InheritedTagHelperType } },
{ assemblyB, new [] { stringType } }
},
new []
{
new TagHelperDirectiveDescriptor(assemblyA, TagHelperDirectiveType.AddTagHelper),
new TagHelperDirectiveDescriptor(assemblyB, TagHelperDirectiveType.AddTagHelper),
new TagHelperDirectiveDescriptor(assemblyA, TagHelperDirectiveType.RemoveTagHelper)
},
new [] { stringTagHelperDescriptor }
},
{
new Dictionary<string, IEnumerable<Type>>
{
{ assemblyA, new [] { Valid_PlainTagHelperType, Valid_InheritedTagHelperType } }
},
new []
{
new TagHelperDirectiveDescriptor(
Valid_PlainTagHelperType.FullName + ", " + assemblyA,
TagHelperDirectiveType.AddTagHelper),
new TagHelperDirectiveDescriptor(assemblyA, TagHelperDirectiveType.AddTagHelper)
},
new [] { Valid_PlainTagHelperDescriptor, Valid_InheritedTagHelperDescriptor }
},
{
new Dictionary<string, IEnumerable<Type>>
{
{ assemblyA, new [] { Valid_PlainTagHelperType, Valid_InheritedTagHelperType } }
},
new []
{
new TagHelperDirectiveDescriptor(assemblyA, TagHelperDirectiveType.AddTagHelper),
new TagHelperDirectiveDescriptor(
Valid_PlainTagHelperType.FullName + ", " + assemblyA,
TagHelperDirectiveType.RemoveTagHelper)
},
new [] { Valid_InheritedTagHelperDescriptor }
},
{
new Dictionary<string, IEnumerable<Type>>
{
{ assemblyA, new [] { Valid_PlainTagHelperType, Valid_InheritedTagHelperType } },
},
new []
{
new TagHelperDirectiveDescriptor(assemblyA, TagHelperDirectiveType.AddTagHelper),
new TagHelperDirectiveDescriptor(
Valid_PlainTagHelperType.FullName + ", " + assemblyA,
TagHelperDirectiveType.RemoveTagHelper),
new TagHelperDirectiveDescriptor(assemblyA, TagHelperDirectiveType.AddTagHelper)
},
new [] { Valid_InheritedTagHelperDescriptor, Valid_PlainTagHelperDescriptor }
},
{
new Dictionary<string, IEnumerable<Type>>
{
{ assemblyA, new [] { Valid_PlainTagHelperType, Valid_InheritedTagHelperType } },
},
new []
{
new TagHelperDirectiveDescriptor(assemblyA, TagHelperDirectiveType.AddTagHelper),
new TagHelperDirectiveDescriptor(assemblyA, TagHelperDirectiveType.AddTagHelper),
},
new [] { Valid_InheritedTagHelperDescriptor, Valid_PlainTagHelperDescriptor }
}
};
}
}
[Theory]
[MemberData(nameof(ResolveDirectiveDescriptorsData))]
public void Resolve_ReturnsDescriptorsBasedOnDirectiveDescriptors(
Dictionary<string, IEnumerable<Type>> descriptorAssemblyLookups,
IEnumerable<TagHelperDirectiveDescriptor> directiveDescriptors,
IEnumerable<TagHelperDescriptor> expectedDescriptors)
{
// Arrange
var tagHelperDescriptorResolver =
new TestTagHelperDescriptorResolver(
new LookupBasedTagHelperTypeResolver(descriptorAssemblyLookups));
var resolutionContext = new TagHelperDescriptorResolutionContext(directiveDescriptors);
// Act
var descriptors = tagHelperDescriptorResolver.Resolve(resolutionContext);
// Assert
Assert.Equal(expectedDescriptors.Count(), descriptors.Count());
foreach (var expectedDescriptor in expectedDescriptors)
{
Assert.Contains(expectedDescriptor, descriptors, TagHelperDescriptorComparer.Default);
}
}
public static TheoryData ResolveDirectiveDescriptorsData_EmptyResult
{
get
{
var assemblyA = AssemblyName;
var stringType = typeof(string);
var assemblyB = stringType.GetTypeInfo().Assembly.GetName().Name;
var stringTagHelperDescriptor =
new TagHelperDescriptor("string",
"System.String",
assemblyB,
ContentBehavior.None);
return new TheoryData<Dictionary<string, IEnumerable<Type>>, // descriptorAssemblyLookups
IEnumerable<TagHelperDirectiveDescriptor>> // directiveDescriptors
{
{
new Dictionary<string, IEnumerable<Type>>
{
{ assemblyA, new [] { Valid_PlainTagHelperType } },
},
new []
{
new TagHelperDirectiveDescriptor(assemblyA, TagHelperDirectiveType.AddTagHelper),
new TagHelperDirectiveDescriptor(assemblyA, TagHelperDirectiveType.RemoveTagHelper),
}
},
{
new Dictionary<string, IEnumerable<Type>>
{
{ assemblyA, new [] { Valid_PlainTagHelperType, Valid_InheritedTagHelperType } },
},
new []
{
new TagHelperDirectiveDescriptor(assemblyA, TagHelperDirectiveType.AddTagHelper),
new TagHelperDirectiveDescriptor(Valid_PlainTagHelperType.FullName + ", " + assemblyA, TagHelperDirectiveType.RemoveTagHelper),
new TagHelperDirectiveDescriptor(Valid_InheritedTagHelperType.FullName + ", " + assemblyA, TagHelperDirectiveType.RemoveTagHelper)
}
},
{
new Dictionary<string, IEnumerable<Type>>
{
{ assemblyA, new [] { Valid_PlainTagHelperType, Valid_InheritedTagHelperType } },
{ assemblyB, new [] { stringType } },
},
new []
{
new TagHelperDirectiveDescriptor(assemblyA, TagHelperDirectiveType.AddTagHelper),
new TagHelperDirectiveDescriptor(assemblyB, TagHelperDirectiveType.AddTagHelper),
new TagHelperDirectiveDescriptor(assemblyA, TagHelperDirectiveType.RemoveTagHelper),
new TagHelperDirectiveDescriptor(assemblyB, TagHelperDirectiveType.RemoveTagHelper)
}
},
{
new Dictionary<string, IEnumerable<Type>>
{
{ assemblyA, new [] { Valid_PlainTagHelperType, Valid_InheritedTagHelperType } },
{ assemblyB, new [] { stringType } },
},
new []
{
new TagHelperDirectiveDescriptor(assemblyA, TagHelperDirectiveType.AddTagHelper),
new TagHelperDirectiveDescriptor(assemblyB, TagHelperDirectiveType.AddTagHelper),
new TagHelperDirectiveDescriptor(Valid_PlainTagHelperType.FullName + ", " + assemblyA, TagHelperDirectiveType.RemoveTagHelper),
new TagHelperDirectiveDescriptor(Valid_InheritedTagHelperType.FullName + ", " + assemblyA, TagHelperDirectiveType.RemoveTagHelper),
new TagHelperDirectiveDescriptor(stringType.FullName + ", " + assemblyB, TagHelperDirectiveType.RemoveTagHelper)
}
},
{
new Dictionary<string, IEnumerable<Type>>(),
new []
{
new TagHelperDirectiveDescriptor(assemblyA, TagHelperDirectiveType.RemoveTagHelper),
new TagHelperDirectiveDescriptor(Valid_PlainTagHelperType.FullName + ", " + assemblyA, TagHelperDirectiveType.RemoveTagHelper),
}
}
};
}
}
[Theory]
[MemberData(nameof(ResolveDirectiveDescriptorsData_EmptyResult))]
public void Resolve_CanReturnEmptyDescriptorsBasedOnDirectiveDescriptors(
Dictionary<string, IEnumerable<Type>> descriptorAssemblyLookups,
IEnumerable<TagHelperDirectiveDescriptor> directiveDescriptors)
{
// Arrange
var tagHelperDescriptorResolver =
new TestTagHelperDescriptorResolver(
new LookupBasedTagHelperTypeResolver(descriptorAssemblyLookups));
var resolutionContext = new TagHelperDescriptorResolutionContext(directiveDescriptors);
// Act
var descriptors = tagHelperDescriptorResolver.Resolve(resolutionContext);
// Assert
Assert.Empty(descriptors);
}
[Fact]
public void DescriptorResolver_DoesNotReturnInvalidTagHelpersWhenSpecified()
{
// Arrange
var tagHelperDescriptorResolver =
new TagHelperDescriptorResolver(
new TestTagHelperDescriptorResolver(
new TestTagHelperTypeResolver(TestableTagHelpers));
// Act
var descriptors = tagHelperDescriptorResolver.Resolve(
"Microsoft.AspNet.Razor.Runtime.Test.TagHelpers.Invalid_AbstractTagHelper, MyAssembly");
descriptors = descriptors.Concat(tagHelperDescriptorResolver.Resolve(
"Microsoft.AspNet.Razor.Runtime.Test.TagHelpers.Invalid_GenericTagHelper`, MyAssembly"));
descriptors = descriptors.Concat(tagHelperDescriptorResolver.Resolve(
"Microsoft.AspNet.Razor.Runtime.Test.TagHelpers.Invalid_NestedPublicTagHelper, MyAssembly"));
descriptors = descriptors.Concat(tagHelperDescriptorResolver.Resolve(
"Microsoft.AspNet.Razor.Runtime.Test.TagHelpers.Invalid_NestedInternalTagHelper, MyAssembly"));
descriptors = descriptors.Concat(tagHelperDescriptorResolver.Resolve(
"Microsoft.AspNet.Razor.Runtime.Test.TagHelpers.Invalid_PrivateTagHelper, MyAssembly"));
descriptors = descriptors.Concat(tagHelperDescriptorResolver.Resolve(
"Microsoft.AspNet.Razor.Runtime.Test.TagHelpers.Invalid_ProtectedTagHelper, MyAssembly"));
descriptors = descriptors.Concat(tagHelperDescriptorResolver.Resolve(
"Microsoft.AspNet.Razor.Runtime.Test.TagHelpers.Invalid_InternalTagHelper, MyAssembly"));
"Microsoft.AspNet.Razor.Runtime.Test.TagHelpers.Invalid_AbstractTagHelper, " + AssemblyName,
"Microsoft.AspNet.Razor.Runtime.Test.TagHelpers.Invalid_GenericTagHelper`, " + AssemblyName,
"Microsoft.AspNet.Razor.Runtime.Test.TagHelpers.Invalid_NestedPublicTagHelper, " + AssemblyName,
"Microsoft.AspNet.Razor.Runtime.Test.TagHelpers.Invalid_NestedInternalTagHelper, " + AssemblyName,
"Microsoft.AspNet.Razor.Runtime.Test.TagHelpers.Invalid_PrivateTagHelper, " + AssemblyName,
"Microsoft.AspNet.Razor.Runtime.Test.TagHelpers.Invalid_ProtectedTagHelper, " + AssemblyName,
"Microsoft.AspNet.Razor.Runtime.Test.TagHelpers.Invalid_InternalTagHelper, " + AssemblyName);
// Assert
Assert.Empty(descriptors);
@ -78,84 +356,75 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
Assert.Equal("MyAssembly", assemblyName.Name);
}
};
var tagHelperDescriptorResolver = new TagHelperDescriptorResolver(tagHelperTypeResolver);
var expectedDescriptor = new TagHelperDescriptor("Valid_Plain",
typeof(Valid_PlainTagHelper).FullName,
AssemblyName,
ContentBehavior.None);
var tagHelperDescriptorResolver = new TestTagHelperDescriptorResolver(tagHelperTypeResolver);
// Act
var descriptors = tagHelperDescriptorResolver.Resolve(lookupText);
// Assert
var descriptor = Assert.Single(descriptors);
Assert.Equal(expectedDescriptor, descriptor, CompleteTagHelperDescriptorComparer.Default);
Assert.Empty(descriptors);
}
[Fact]
public void DescriptorResolver_ResolvesOnlyTypeResolverProvidedTypes()
{
// Arrange
var resolver = new TagHelperDescriptorResolver(
var resolver = new TestTagHelperDescriptorResolver(
new LookupBasedTagHelperTypeResolver(
new Dictionary<string, IEnumerable<Type>>(StringComparer.OrdinalIgnoreCase)
{
{ "lookupText1", ValidTestableTagHelpers },
{ "lookupText2", new Type[]{ typeof(Valid_PlainTagHelper) } }
{ AssemblyName, ValidTestableTagHelpers },
{
Valid_PlainTagHelperType.FullName + ", " + AssemblyName,
new Type[] { Valid_PlainTagHelperType }
}
}));
var expectedDescriptor = new TagHelperDescriptor("Valid_Plain",
typeof(Valid_PlainTagHelper).FullName,
AssemblyName,
ContentBehavior.None);
// Act
var descriptors = resolver.Resolve("lookupText2");
var descriptors = resolver.Resolve(Valid_PlainTagHelperType + ", " + AssemblyName);
// Assert
var descriptor = Assert.Single(descriptors);
Assert.Equal(descriptor, expectedDescriptor, CompleteTagHelperDescriptorComparer.Default);
Assert.Equal(Valid_PlainTagHelperDescriptor, descriptor, CompleteTagHelperDescriptorComparer.Default);
}
[Fact]
public void DescriptorResolver_ResolvesMultipleTypes()
{
// Arrange
var resolver = new TagHelperDescriptorResolver(
var resolver = new TestTagHelperDescriptorResolver(
new LookupBasedTagHelperTypeResolver(
new Dictionary<string, IEnumerable<Type>>(StringComparer.OrdinalIgnoreCase)
{
{ "lookupText", new Type[]{ typeof(Valid_PlainTagHelper), typeof(Valid_InheritedTagHelper) } },
{ AssemblyName, new Type[]{ Valid_PlainTagHelperType, Valid_InheritedTagHelperType } },
}));
var expectedDescriptors = new TagHelperDescriptor[]
{
new TagHelperDescriptor("Valid_Plain",
typeof(Valid_PlainTagHelper).FullName,
AssemblyName,
ContentBehavior.None),
new TagHelperDescriptor("Valid_Inherited",
typeof(Valid_InheritedTagHelper).FullName,
AssemblyName,
ContentBehavior.None)
Valid_PlainTagHelperDescriptor,
Valid_InheritedTagHelperDescriptor
};
// Act
var descriptors = resolver.Resolve("lookupText").ToArray();
var descriptors = resolver.Resolve(AssemblyName).ToArray();
// Assert
Assert.Equal(descriptors.Length, 2);
Assert.Equal(descriptors, expectedDescriptors, CompleteTagHelperDescriptorComparer.Default);
Assert.Equal(expectedDescriptors, descriptors, CompleteTagHelperDescriptorComparer.Default);
}
[Fact]
public void DescriptorResolver_DoesNotResolveTypesForNoTypeResolvingLookupText()
{
// Arrange
var resolver = new TagHelperDescriptorResolver(
var resolver = new TestTagHelperDescriptorResolver(
new LookupBasedTagHelperTypeResolver(
new Dictionary<string, IEnumerable<Type>>(StringComparer.OrdinalIgnoreCase)
{
{ "lookupText1", ValidTestableTagHelpers },
{ "lookupText2", new Type[]{ typeof(Valid_PlainTagHelper) } }
{ AssemblyName, ValidTestableTagHelpers },
{
Valid_PlainTagHelperType.FullName + ", " + AssemblyName,
new Type[]{ Valid_PlainTagHelperType }
}
}));
// Act
@ -172,7 +441,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
{
// Arrange
var tagHelperDescriptorResolver =
new TagHelperDescriptorResolver(
new TestTagHelperDescriptorResolver(
new TestTagHelperTypeResolver(InvalidTestableTagHelpers));
var expectedMessage =
@ -190,6 +459,23 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
Assert.Equal(expectedMessage, ex.Message);
}
private class TestTagHelperDescriptorResolver : TagHelperDescriptorResolver
{
public TestTagHelperDescriptorResolver(TagHelperTypeResolver typeResolver)
: base(typeResolver)
{
}
public IEnumerable<TagHelperDescriptor> Resolve(params string[] lookupTexts)
{
return Resolve(
new TagHelperDescriptorResolutionContext(
lookupTexts.Select(
lookupText =>
new TagHelperDirectiveDescriptor(lookupText, TagHelperDirectiveType.AddTagHelper))));
}
}
private class LookupBasedTagHelperTypeResolver : TagHelperTypeResolver
{
private Dictionary<string, IEnumerable<Type>> _lookupValues;
@ -207,9 +493,14 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
return types?.Select(type => type.GetTypeInfo()) ?? Enumerable.Empty<TypeInfo>();
}
internal override bool IsTagHelper(TypeInfo typeInfo)
{
return true;
}
}
private class TestTagHelperDescriptorResolver : TagHelperDescriptorResolver
private class AssemblyCheckingTagHelperDescriptorResolver : TagHelperDescriptorResolver
{
public string CalledWithAssemblyName { get; set; }

View File

@ -40,9 +40,26 @@ namespace Microsoft.AspNet.Razor.Test.Generator
_tagHelperDescriptors = tagHelperDescriptors ?? Enumerable.Empty<TagHelperDescriptor>();
}
public IEnumerable<TagHelperDescriptor> Resolve(string lookupText)
public IEnumerable<TagHelperDescriptor> Resolve(TagHelperDescriptorResolutionContext resolutionContext)
{
return _tagHelperDescriptors;
IEnumerable<TagHelperDescriptor> descriptors = null;
foreach (var directiveDescriptor in resolutionContext.DirectiveDescriptors)
{
if (directiveDescriptor.DirectiveType == TagHelperDirectiveType.RemoveTagHelper)
{
// We don't yet support "typeName, assemblyName" for @removetaghelper in this test class. Will
// add that ability and add the corresponding end-to-end test verification in:
// https://github.com/aspnet/Razor/issues/222
descriptors = null;
}
else if (directiveDescriptor.DirectiveType == TagHelperDirectiveType.AddTagHelper)
{
descriptors = _tagHelperDescriptors;
}
}
return descriptors ?? Enumerable.Empty<TagHelperDescriptor>();
}
}

View File

@ -8,6 +8,7 @@ using Microsoft.AspNet.Razor.Parser;
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
using Microsoft.AspNet.Razor.Parser.TagHelpers;
using Microsoft.AspNet.Razor.Test.Framework;
using Microsoft.Internal.Web.Utils;
#if !ASPNETCORE50
using Moq;
#endif
@ -19,29 +20,14 @@ namespace Microsoft.AspNet.Razor.TagHelpers
{
private static readonly SpanFactory Factory = SpanFactory.CreateCsHtml();
private static TagHelperDescriptor PTagHelperDescriptor
{
get
{
return new TagHelperDescriptor("p", "PTagHelper", "SomeAssembly", ContentBehavior.None);
}
}
private static TagHelperDescriptor DivTagHelperDescriptor
{
get
{
return new TagHelperDescriptor("div", "DivTagHelper", "SomeAssembly", ContentBehavior.None);
}
}
#if !ASPNETCORE50
[Fact]
public void GetDescriptors_InvokesResolveForEachLookup()
public void GetDescriptors_InvokesResolveOnceForAllDirectives()
{
// Arrange
var resolver = new Mock<ITagHelperDescriptorResolver>();
resolver.Setup(mock => mock.Resolve(It.IsAny<string>())).Returns(Enumerable.Empty<TagHelperDescriptor>());
resolver.Setup(mock => mock.Resolve(It.IsAny<TagHelperDescriptorResolutionContext>()))
.Returns(Enumerable.Empty<TagHelperDescriptor>());
var addOrRemoveTagHelperSpanVisitor = new AddOrRemoveTagHelperSpanVisitor(resolver.Object);
var document = new MarkupBlock(
Factory.Code("\"one\"").AsAddTagHelper("one"),
@ -49,23 +35,68 @@ namespace Microsoft.AspNet.Razor.TagHelpers
Factory.Code("\"three\"").AsRemoveTagHelper("three"));
// Act
var descriptors = addOrRemoveTagHelperSpanVisitor.GetDescriptors(document);
addOrRemoveTagHelperSpanVisitor.GetDescriptors(document);
// Assert
Assert.Empty(descriptors);
resolver.Verify(mock => mock.Resolve(It.IsAny<string>()), Times.Exactly(3));
resolver.Verify(mock => mock.Resolve(It.IsAny<TagHelperDescriptorResolutionContext>()), Times.Once);
}
#endif
[Fact]
public void GetDescriptors_LocatesTagHelperCodeGenerator_CreatesDirectiveDescriptors()
{
// Arrange
var resolver = new TestTagHelperDescriptorResolver();
var addOrRemoveTagHelperSpanVisitor = new AddOrRemoveTagHelperSpanVisitor(resolver);
var document = new MarkupBlock(
Factory.Code("\"one\"").AsAddTagHelper("one"),
Factory.Code("\"two\"").AsRemoveTagHelper("two"),
Factory.Code("\"three\"").AsRemoveTagHelper("three"));
var expectedRegistrations = new TagHelperDirectiveDescriptor[]
{
new TagHelperDirectiveDescriptor("one", TagHelperDirectiveType.AddTagHelper),
new TagHelperDirectiveDescriptor("two", TagHelperDirectiveType.RemoveTagHelper),
new TagHelperDirectiveDescriptor("three", TagHelperDirectiveType.RemoveTagHelper),
};
// Act
addOrRemoveTagHelperSpanVisitor.GetDescriptors(document);
// Assert
Assert.Equal(expectedRegistrations,
resolver.DirectiveDescriptors,
TagHelperDirectiveDescriptorComparer.Default);
}
[Fact]
public void GetDescriptors_LocatesAddTagHelperCodeGenerator()
{
// Arrange
var resolver = new TestTagHelperDescriptorResolver();
var addOrRemoveTagHelperSpanVisitor = new AddOrRemoveTagHelperSpanVisitor(resolver);
var document = new MarkupBlock(
new DirectiveBlock(
Factory.CodeTransition(),
Factory.MetaCode(SyntaxConstants.CSharp.RemoveTagHelperKeyword + " ")
.Accepts(AcceptedCharacters.None),
Factory.Code("\"something\"").AsAddTagHelper("something"))
);
var expectedRegistration =
new TagHelperDirectiveDescriptor("something", TagHelperDirectiveType.AddTagHelper);
// Act
addOrRemoveTagHelperSpanVisitor.GetDescriptors(document);
// Assert
var directiveDescriptor = Assert.Single(resolver.DirectiveDescriptors);
Assert.Equal(expectedRegistration, directiveDescriptor, TagHelperDirectiveDescriptorComparer.Default);
}
[Fact]
public void GetDescriptors_LocatesNestedRemoveTagHelperCodeGenerator()
{
// Arrange
var resolver = new TestTagHelperDescriptorResolver(
new Dictionary<string, IEnumerable<TagHelperDescriptor>>
{
{ "something", new[] { PTagHelperDescriptor } }
});
var resolver = new TestTagHelperDescriptorResolver();
var addOrRemoveTagHelperSpanVisitor = new AddOrRemoveTagHelperSpanVisitor(resolver);
var document = new MarkupBlock(
new DirectiveBlock(
@ -74,146 +105,73 @@ namespace Microsoft.AspNet.Razor.TagHelpers
.Accepts(AcceptedCharacters.None),
Factory.Code("\"something\"").AsRemoveTagHelper("something"))
);
var expectedRegistration =
new TagHelperDirectiveDescriptor("something", TagHelperDirectiveType.RemoveTagHelper);
// Act
var descriptors = addOrRemoveTagHelperSpanVisitor.GetDescriptors(document);
addOrRemoveTagHelperSpanVisitor.GetDescriptors(document);
// Assert
Assert.Empty(descriptors);
var lookup = Assert.Single(resolver.Lookups);
Assert.Equal("something", lookup);
}
[Fact]
public void GetDescriptors_RemovesSpecifiedTagHelper()
{
// Arrange
var resolver = new TestTagHelperDescriptorResolver(
new Dictionary<string, IEnumerable<TagHelperDescriptor>>
{
{ "twoTagHelpers", new[] { PTagHelperDescriptor, DivTagHelperDescriptor } },
{ "singleTagHelper", new [] { PTagHelperDescriptor } }
});
var addOrRemoveTagHelperSpanVisitor = new AddOrRemoveTagHelperSpanVisitor(resolver);
var document = new MarkupBlock(
Factory.Code("\"twoTagHelpers\"").AsAddTagHelper("twoTagHelpers"),
Factory.Code("\"singleTagHelper\"").AsRemoveTagHelper("singleTagHelper"));
// Act
var descriptors = addOrRemoveTagHelperSpanVisitor.GetDescriptors(document);
// Assert
var descriptor = Assert.Single(descriptors);
Assert.Equal(DivTagHelperDescriptor, descriptor, TagHelperDescriptorComparer.Default);
Assert.Equal(2, resolver.Lookups.Count);
Assert.Contains("twoTagHelpers", resolver.Lookups);
Assert.Contains("singleTagHelper", resolver.Lookups);
}
[Fact]
public void GetDescriptors_RemovesAddedTagHelpers()
{
// Arrange
var resolver = new TestTagHelperDescriptorResolver(
new Dictionary<string, IEnumerable<TagHelperDescriptor>>
{
{ "twoTagHelpers", new[] { PTagHelperDescriptor, DivTagHelperDescriptor } }
});
var addOrRemoveTagHelperSpanVisitor = new AddOrRemoveTagHelperSpanVisitor(resolver);
var document = new MarkupBlock(
Factory.Code("\"twoTagHelpers\"").AsAddTagHelper("twoTagHelpers"),
Factory.Code("\"twoTagHelpers\"").AsRemoveTagHelper("twoTagHelpers"));
// Act
var descriptors = addOrRemoveTagHelperSpanVisitor.GetDescriptors(document);
// Assert
Assert.Empty(descriptors);
Assert.Equal(Enumerable.Repeat("twoTagHelpers", 2), resolver.Lookups);
}
[Fact]
public void GetDescriptors_RemoveTagHelper_OrderMatters()
{
// Arrange
var expectedDescriptors = new[] { PTagHelperDescriptor, DivTagHelperDescriptor };
var resolver = new TestTagHelperDescriptorResolver(
new Dictionary<string, IEnumerable<TagHelperDescriptor>>
{
{ "twoTagHelpers", expectedDescriptors }
});
var addOrRemoveTagHelperSpanVisitor = new AddOrRemoveTagHelperSpanVisitor(resolver);
var document = new MarkupBlock(
Factory.Code("\"twoTagHelpers\"").AsRemoveTagHelper("twoTagHelpers"),
Factory.Code("\"twoTagHelpers\"").AsAddTagHelper("twoTagHelpers"));
// Act
var descriptors = addOrRemoveTagHelperSpanVisitor.GetDescriptors(document);
// Assert
Assert.Equal(expectedDescriptors, descriptors, TagHelperDescriptorComparer.Default);
Assert.Equal(Enumerable.Repeat("twoTagHelpers", 2), resolver.Lookups);
}
[Fact]
public void GetDescriptors_RemoveTagHelperInDocument_ThrowsIfNullResolver()
{
// Arrange
var addOrRemoveTagHelperSpanVisitor = new AddOrRemoveTagHelperSpanVisitor(descriptorResolver: null);
var document = new MarkupBlock(
Factory.Code("\"something\"").AsRemoveTagHelper("something"));
var expectedMessage = "Cannot use directive 'removetaghelper' when a Microsoft.AspNet.Razor.TagHelpers." +
"ITagHelperDescriptorResolver has not been provided to the Microsoft.AspNet.Razor." +
"Parser.RazorParser.";
// Act & Assert
var ex = Assert.Throws<InvalidOperationException>(() =>
{
addOrRemoveTagHelperSpanVisitor.GetDescriptors(document);
});
Assert.Equal(expectedMessage, ex.Message);
var directiveDescriptor = Assert.Single(resolver.DirectiveDescriptors);
Assert.Equal(expectedRegistration, directiveDescriptor, TagHelperDirectiveDescriptorComparer.Default);
}
[Fact]
public void GetDescriptors_RemoveTagHelperNotInDocument_DoesNotThrow()
{
// Arrange
var addOrRemoveTagHelperSpanVisitor = new AddOrRemoveTagHelperSpanVisitor(descriptorResolver: null);
var addOrRemoveTagHelperSpanVisitor =
new AddOrRemoveTagHelperSpanVisitor(
new TestTagHelperDescriptorResolver());
var document = new MarkupBlock(Factory.Markup("Hello World"));
// Act & Assert
Assert.DoesNotThrow(() => addOrRemoveTagHelperSpanVisitor.GetDescriptors(document));
}
// TODO: Add @addtaghelper directive unit tests. Tracked by https://github.com/aspnet/Razor/issues/202.
private class TestTagHelperDescriptorResolver : ITagHelperDescriptorResolver
{
private readonly IReadOnlyDictionary<string, IEnumerable<TagHelperDescriptor>> _lookupTable;
public TestTagHelperDescriptorResolver(
IReadOnlyDictionary<string, IEnumerable<TagHelperDescriptor>> lookupTable)
public TestTagHelperDescriptorResolver()
{
_lookupTable = lookupTable;
Lookups = new List<string>();
DirectiveDescriptors = new List<TagHelperDirectiveDescriptor>();
}
public List<string> Lookups { get; private set; }
public List<TagHelperDirectiveDescriptor> DirectiveDescriptors { get; }
public IEnumerable<TagHelperDescriptor> Resolve(string lookupText)
public IEnumerable<TagHelperDescriptor> Resolve(TagHelperDescriptorResolutionContext resolutionContext)
{
Lookups.Add(lookupText);
IEnumerable<TagHelperDescriptor> descriptors;
if (_lookupTable.TryGetValue(lookupText, out descriptors))
{
return descriptors;
}
DirectiveDescriptors.AddRange(resolutionContext.DirectiveDescriptors);
return Enumerable.Empty<TagHelperDescriptor>();
}
}
private class TagHelperDirectiveDescriptorComparer : IEqualityComparer<TagHelperDirectiveDescriptor>
{
public static readonly TagHelperDirectiveDescriptorComparer Default =
new TagHelperDirectiveDescriptorComparer();
private TagHelperDirectiveDescriptorComparer()
{
}
public bool Equals(TagHelperDirectiveDescriptor directiveDescriptorX,
TagHelperDirectiveDescriptor directiveDescriptorY)
{
return string.Equals(directiveDescriptorX.LookupText,
directiveDescriptorY.LookupText,
StringComparison.Ordinal) &&
directiveDescriptorX.DirectiveType == directiveDescriptorY.DirectiveType;
}
public int GetHashCode(TagHelperDirectiveDescriptor directiveDescriptor)
{
return HashCodeCombiner.Start()
.Add(base.GetHashCode())
.Add(directiveDescriptor.LookupText)
.Add(directiveDescriptor.DirectiveType)
.CombinedHash;
}
}
}
}