1+ // Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
2+ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
4+ using System ;
5+ using System . Collections . Generic ;
6+ using System . Globalization ;
7+ using System . Linq ;
8+ using Microsoft . AspNet . Razor . Runtime . TagHelpers ;
9+ using Microsoft . AspNet . Razor . TagHelpers ;
10+ using Microsoft . Internal . Web . Utils ;
11+ using Xunit ;
12+
13+ namespace Microsoft . AspNet . Razor . Runtime . Test . TagHelpers
14+ {
15+ public class TagHelperDescriptorResolverTest
16+ {
17+ private static readonly CompleteTagHelperDescriptorComparer DefaultDescriptorComparer =
18+ new CompleteTagHelperDescriptorComparer ( ) ;
19+
20+ [ Fact ]
21+ public void DescriptorResolver_ResolvesOnlyTypeResolverProvidedTypes ( )
22+ {
23+ // Arrange
24+ var resolver = new TagHelperDescriptorResolver (
25+ new CustomTagHelperTypeResolver (
26+ new Dictionary < string , IEnumerable < Type > > ( StringComparer . OrdinalIgnoreCase )
27+ {
28+ { "lookupText1" , new Type [ ] { typeof ( string ) , typeof ( int ) } } ,
29+ { "lookupText2" , new Type [ ] { typeof ( object ) } }
30+ } ) ) ;
31+ var expectedDescriptor = new TagHelperDescriptor ( "Object" , "System.Object" , ContentBehavior . None ) ;
32+
33+ // Act
34+ var descriptors = resolver . Resolve ( "lookupText2" ) ;
35+
36+ // Assert
37+ var descriptor = Assert . Single ( descriptors ) ;
38+ Assert . Equal ( descriptor , expectedDescriptor , DefaultDescriptorComparer ) ;
39+ }
40+
41+ [ Fact ]
42+ public void DescriptorResolver_ResolvesMultipleTypes ( )
43+ {
44+ // Arrange
45+ var resolver = new TagHelperDescriptorResolver (
46+ new CustomTagHelperTypeResolver (
47+ new Dictionary < string , IEnumerable < Type > > ( StringComparer . OrdinalIgnoreCase )
48+ {
49+ { "lookupText" , new Type [ ] { typeof ( string ) , typeof ( int ) } } ,
50+ } ) ) ;
51+ var expectedDescriptors = new TagHelperDescriptor [ ]
52+ {
53+ new TagHelperDescriptor ( "String" , "System.String" , ContentBehavior . None ) ,
54+ new TagHelperDescriptor ( "Int32" , "System.Int32" , ContentBehavior . None ) ,
55+ } ;
56+
57+ // Act
58+ var descriptors = resolver . Resolve ( "lookupText" ) . ToArray ( ) ;
59+
60+ // Assert
61+ Assert . Equal ( descriptors . Length , 2 ) ;
62+ Assert . Equal ( descriptors , expectedDescriptors , DefaultDescriptorComparer ) ;
63+ }
64+
65+ [ Fact ]
66+ public void DescriptorResolver_ResolvesCustomTypeWithConventionName ( )
67+ {
68+ // Arrange
69+ var resolver = new TagHelperDescriptorResolver (
70+ new CustomTagHelperTypeResolver (
71+ new Dictionary < string , IEnumerable < Type > > ( StringComparer . OrdinalIgnoreCase )
72+ {
73+ { "lookupText" , new Type [ ] { typeof ( SingleAttributeTagHelper ) } } ,
74+ } ) ) ;
75+ var intProp = typeof ( SingleAttributeTagHelper ) . GetProperty ( nameof ( SingleAttributeTagHelper . IntAttribute ) ) ;
76+ var expectedDescriptor = new TagHelperDescriptor (
77+ "SingleAttribute" ,
78+ typeof ( SingleAttributeTagHelper ) . FullName ,
79+ ContentBehavior . None ,
80+ new [ ] {
81+ new TagHelperAttributeDescriptor ( nameof ( SingleAttributeTagHelper . IntAttribute ) , intProp )
82+ } ) ;
83+
84+ // Act
85+ var descriptors = resolver . Resolve ( "lookupText" ) . ToArray ( ) ;
86+
87+ // Assert
88+ var descriptor = Assert . Single ( descriptors ) ;
89+ Assert . Equal ( descriptor , expectedDescriptor , DefaultDescriptorComparer ) ;
90+ }
91+
92+ [ Fact ]
93+ public void DescriptorResolver_OnlyResolvesPropertiesWithGetAndSet ( )
94+ {
95+ // Arrange
96+ var resolver = new TagHelperDescriptorResolver (
97+ new CustomTagHelperTypeResolver (
98+ new Dictionary < string , IEnumerable < Type > > ( StringComparer . OrdinalIgnoreCase )
99+ {
100+ { "lookupText" , new Type [ ] { typeof ( TwoInvalidAttributeTagHelper ) } } ,
101+ } ) ) ;
102+ var validProp = typeof ( TwoInvalidAttributeTagHelper ) . GetProperty ( nameof ( TwoInvalidAttributeTagHelper . ValidAttribute ) ) ;
103+ var expectedDescriptor = new TagHelperDescriptor (
104+ "TwoInvalidAttribute" ,
105+ typeof ( TwoInvalidAttributeTagHelper ) . FullName ,
106+ ContentBehavior . None ,
107+ new [ ] {
108+ new TagHelperAttributeDescriptor ( nameof ( TwoInvalidAttributeTagHelper . ValidAttribute ) , validProp )
109+ } ) ;
110+
111+ // Act
112+ var descriptors = resolver . Resolve ( "lookupText" ) . ToArray ( ) ;
113+
114+ // Assert
115+ var descriptor = Assert . Single ( descriptors ) ;
116+ Assert . Equal ( descriptor , expectedDescriptor , DefaultDescriptorComparer ) ;
117+ }
118+
119+ [ Fact ]
120+ public void DescriptorResolver_DoesntResolveTypesForInvalidLookupText ( )
121+ {
122+ // Arrange
123+ var resolver = new TagHelperDescriptorResolver (
124+ new CustomTagHelperTypeResolver (
125+ new Dictionary < string , IEnumerable < Type > > ( StringComparer . OrdinalIgnoreCase )
126+ {
127+ { "lookupText1" , new Type [ ] { typeof ( string ) , typeof ( int ) } } ,
128+ { "lookupText2" , new Type [ ] { typeof ( object ) } }
129+ } ) ) ;
130+
131+ // Act
132+ var descriptors = resolver . Resolve ( "lookupText" ) . ToArray ( ) ;
133+
134+ // Assert
135+ Assert . Empty ( descriptors ) ;
136+ }
137+
138+ [ Fact ]
139+ public void DescriptorResolver_ThrowsWhenAttributesConflict ( )
140+ {
141+ // Arrange
142+ var resolver = new TagHelperDescriptorResolver (
143+ new CustomTagHelperTypeResolver (
144+ new Dictionary < string , IEnumerable < Type > > ( StringComparer . OrdinalIgnoreCase )
145+ {
146+ { "lookupText" , new Type [ ] { typeof ( SingleAttributeTagHelper ) ,
147+ typeof ( TestingNamespace . SingleAttributeTagHelper ) } } ,
148+ } ) ) ;
149+ var expectedError = string . Format (
150+ CultureInfo . InvariantCulture ,
151+ "You cannot have multiple TagHelpers that target the same HTML attribute name with " +
152+ "different types. TagHelper '{0}' targets the '{1}' HTML attribute with type '{2}' " +
153+ "which conflicts with TagHelper '{3}' that expects the '{1}' attribute to be of type '{4}'." ,
154+ "Microsoft.AspNet.Razor.Runtime.Test.TagHelpers.TestingNamespace.SingleAttributeTagHelper" ,
155+ "IntAttribute" ,
156+ "System.String" ,
157+ "Microsoft.AspNet.Razor.Runtime.Test.TagHelpers.TagHelperDescriptorResolverTest" +
158+ "+SingleAttributeTagHelper" ,
159+ "System.Int32" ) ;
160+
161+ // Act & Assert
162+ var ex = Assert . Throws < InvalidOperationException > ( ( ) =>
163+ {
164+ resolver . Resolve ( "lookupText" ) ;
165+ } ) ;
166+ Assert . Equal ( expectedError , ex . Message ) ;
167+ }
168+
169+ private class CustomTagHelperTypeResolver : ITagHelperTypeResolver
170+ {
171+ private Dictionary < string , IEnumerable < Type > > _lookupValues ;
172+
173+ public CustomTagHelperTypeResolver ( Dictionary < string , IEnumerable < Type > > lookupValues )
174+ {
175+ _lookupValues = lookupValues ;
176+ }
177+
178+ public IEnumerable < Type > Resolve ( string lookupText )
179+ {
180+ IEnumerable < Type > types ;
181+
182+ _lookupValues . TryGetValue ( lookupText , out types ) ;
183+
184+ return types ?? Enumerable . Empty < Type > ( ) ;
185+ }
186+ }
187+
188+ private class SingleAttributeTagHelper
189+ {
190+ public int IntAttribute { get ; set ; }
191+ }
192+
193+ private class TwoInvalidAttributeTagHelper
194+ {
195+ public string ValidAttribute { get ; set ; }
196+ public string InvalidNoGetAttribute { set { } }
197+ public string InvalidNoSetAttribute { get { return string . Empty ; } }
198+ }
199+
200+ private class CompleteTagHelperDescriptorComparer : TagHelperDescriptorComparer
201+ {
202+ public new bool Equals ( TagHelperDescriptor descriptorX , TagHelperDescriptor descriptorY )
203+ {
204+ return base . Equals ( descriptorX , descriptorY ) &&
205+ descriptorX . Attributes . SequenceEqual ( descriptorY . Attributes ,
206+ CompleteTagHelperAttributeDescriptorComparer . Default ) ;
207+ }
208+
209+ public new int GetHashCode ( TagHelperDescriptor descriptor )
210+ {
211+ return HashCodeCombiner . Start ( )
212+ . Add ( base . GetHashCode ( ) )
213+ . Add ( descriptor . Attributes )
214+ . CombinedHash ;
215+ }
216+ }
217+
218+ private class CompleteTagHelperAttributeDescriptorComparer : IEqualityComparer < TagHelperAttributeDescriptor >
219+ {
220+ public static readonly CompleteTagHelperAttributeDescriptorComparer Default =
221+ new CompleteTagHelperAttributeDescriptorComparer ( ) ;
222+
223+ public bool Equals ( TagHelperAttributeDescriptor descriptorX , TagHelperAttributeDescriptor descriptorY )
224+ {
225+ return descriptorX . AttributeName == descriptorY . AttributeName &&
226+ descriptorX . AttributePropertyName == descriptorY . AttributePropertyName ;
227+ }
228+
229+ public int GetHashCode ( TagHelperAttributeDescriptor descriptor )
230+ {
231+ return HashCodeCombiner . Start ( )
232+ . Add ( descriptor . AttributeName )
233+ . Add ( descriptor . AttributePropertyName )
234+ . CombinedHash ;
235+ }
236+ }
237+ }
238+
239+ namespace TestingNamespace
240+ {
241+ public class SingleAttributeTagHelper
242+ {
243+ // Conflicts with the SingleAttributeTagHelper in the namespace above.
244+ public string IntAttribute { get ; set ; }
245+ }
246+ }
247+ }
0 commit comments