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 . Threading . Tasks ;
7
+ using Microsoft . AspNet . Mvc . ModelBinding ;
8
+ using Microsoft . AspNet . Mvc . Razor ;
9
+ using Microsoft . AspNet . Mvc . Rendering ;
10
+ using Microsoft . AspNet . Razor . Runtime . TagHelpers ;
11
+ using Xunit ;
12
+
13
+ namespace Microsoft . AspNet . Mvc . TagHelpers
14
+ {
15
+ public class LabelTagHelperTest
16
+ {
17
+ // Model (List<Model> or Model instance), container type (Model or NestModel), model accessor,
18
+ // property path, TagHelperOutput.Content values.
19
+ public static TheoryData < object , Type , Func < object > , string , TagHelperOutputContent > TestDataSet
20
+ {
21
+ get
22
+ {
23
+ var modelWithNull = new Model
24
+ {
25
+ NestedModel = new NestedModel
26
+ {
27
+ Text = null ,
28
+ } ,
29
+ Text = null ,
30
+ } ;
31
+ var modelWithText = new Model
32
+ {
33
+ NestedModel = new NestedModel
34
+ {
35
+ Text = "inner text" ,
36
+ } ,
37
+ Text = "outer text" ,
38
+ } ;
39
+ var models = new List < Model >
40
+ {
41
+ modelWithNull ,
42
+ modelWithText ,
43
+ } ;
44
+
45
+ return new TheoryData < object , Type , Func < object > , string , TagHelperOutputContent >
46
+ {
47
+ { null , typeof ( Model ) , ( ) => null , "Text" ,
48
+ new TagHelperOutputContent ( Environment . NewLine , "Text" ) } ,
49
+
50
+ { modelWithNull , typeof ( Model ) , ( ) => modelWithNull . Text , "Text" ,
51
+ new TagHelperOutputContent ( Environment . NewLine , "Text" ) } ,
52
+ { modelWithText , typeof ( Model ) , ( ) => modelWithText . Text , "Text" ,
53
+ new TagHelperOutputContent ( Environment . NewLine , "Text" ) } ,
54
+ { modelWithText , typeof ( Model ) , ( ) => modelWithNull . Text , "Text" ,
55
+ new TagHelperOutputContent ( "Hello World" , "Hello World" ) } ,
56
+ { modelWithText , typeof ( Model ) , ( ) => modelWithText . Text , "Text" ,
57
+ new TagHelperOutputContent ( "Hello World" , "Hello World" ) } ,
58
+
59
+ { modelWithNull , typeof ( NestedModel ) , ( ) => modelWithNull . NestedModel . Text , "NestedModel.Text" ,
60
+ new TagHelperOutputContent ( Environment . NewLine , "Text" ) } ,
61
+ { modelWithText , typeof ( NestedModel ) , ( ) => modelWithText . NestedModel . Text , "NestedModel.Text" ,
62
+ new TagHelperOutputContent ( Environment . NewLine , "Text" ) } ,
63
+ { modelWithNull , typeof ( NestedModel ) , ( ) => modelWithNull . NestedModel . Text , "NestedModel.Text" ,
64
+ new TagHelperOutputContent ( "Hello World" , "Hello World" ) } ,
65
+ { modelWithText , typeof ( NestedModel ) , ( ) => modelWithText . NestedModel . Text , "NestedModel.Text" ,
66
+ new TagHelperOutputContent ( "Hello World" , "Hello World" ) } ,
67
+
68
+ // Note: Tests cases below here will not work in practice due to current limitations on indexing
69
+ // into ModelExpressions. Will be fixed in https://github.com/aspnet/Mvc/issues/1345.
70
+ { models , typeof ( Model ) , ( ) => models [ 0 ] . Text , "[0].Text" ,
71
+ new TagHelperOutputContent ( Environment . NewLine , "Text" ) } ,
72
+ { models , typeof ( Model ) , ( ) => models [ 1 ] . Text , "[1].Text" ,
73
+ new TagHelperOutputContent ( Environment . NewLine , "Text" ) } ,
74
+ { models , typeof ( Model ) , ( ) => models [ 0 ] . Text , "[0].Text" ,
75
+ new TagHelperOutputContent ( "Hello World" , "Hello World" ) } ,
76
+ { models , typeof ( Model ) , ( ) => models [ 1 ] . Text , "[1].Text" ,
77
+ new TagHelperOutputContent ( "Hello World" , "Hello World" ) } ,
78
+
79
+ { models , typeof ( NestedModel ) , ( ) => models [ 0 ] . NestedModel . Text , "[0].NestedModel.Text" ,
80
+ new TagHelperOutputContent ( Environment . NewLine , "Text" ) } ,
81
+ { models , typeof ( NestedModel ) , ( ) => models [ 1 ] . NestedModel . Text , "[1].NestedModel.Text" ,
82
+ new TagHelperOutputContent ( Environment . NewLine , "Text" ) } ,
83
+ { models , typeof ( NestedModel ) , ( ) => models [ 0 ] . NestedModel . Text , "[0].NestedModel.Text" ,
84
+ new TagHelperOutputContent ( "Hello World" , "Hello World" ) } ,
85
+ { models , typeof ( NestedModel ) , ( ) => models [ 1 ] . NestedModel . Text , "[1].NestedModel.Text" ,
86
+ new TagHelperOutputContent ( "Hello World" , "Hello World" ) } ,
87
+ } ;
88
+ }
89
+ }
90
+
91
+ [ Theory ]
92
+ [ MemberData ( nameof ( TestDataSet ) ) ]
93
+ public async Task ProcessAsync_GeneratesExpectedOutput (
94
+ object model ,
95
+ Type containerType ,
96
+ Func < object > modelAccessor ,
97
+ string propertyPath ,
98
+ TagHelperOutputContent tagHelperOutputContent )
99
+ {
100
+ // Arrange
101
+ var expectedAttributes = new Dictionary < string , string >
102
+ {
103
+ { "class" , "form-control" } ,
104
+ { "for" , propertyPath }
105
+ } ;
106
+ var metadataProvider = new DataAnnotationsModelMetadataProvider ( ) ;
107
+
108
+ // Property name is either nameof(Model.Text) or nameof(NestedModel.Text).
109
+ var metadata = metadataProvider . GetMetadataForProperty ( modelAccessor , containerType , propertyName : "Text" ) ;
110
+ var modelExpression = new ModelExpression ( propertyPath , metadata ) ;
111
+ var tagHelper = new LabelTagHelper
112
+ {
113
+ For = modelExpression ,
114
+ } ;
115
+
116
+ var tagHelperContext = new TagHelperContext ( allAttributes : new Dictionary < string , object > ( ) ) ;
117
+ var htmlAttributes = new Dictionary < string , string >
118
+ {
119
+ { "class" , "form-control" } ,
120
+ } ;
121
+ var output = new TagHelperOutput ( "A random tag name" , htmlAttributes , tagHelperOutputContent . OriginalContent ) ;
122
+ var expectedTagName = "label" ;
123
+ var htmlGenerator = new TestableHtmlGenerator ( metadataProvider ) ;
124
+ var viewContext = TestableHtmlGenerator . GetViewContext ( model , htmlGenerator , metadataProvider ) ;
125
+ tagHelper . ViewContext = viewContext ;
126
+ tagHelper . Generator = htmlGenerator ;
127
+
128
+ // Act
129
+ await tagHelper . ProcessAsync ( tagHelperContext , output ) ;
130
+
131
+ // Assert
132
+ Assert . Equal ( expectedAttributes , output . Attributes ) ;
133
+ Assert . Equal ( tagHelperOutputContent . ExpectedContent , output . Content ) ;
134
+ Assert . False ( output . SelfClosing ) ;
135
+ Assert . Equal ( expectedTagName , output . TagName ) ;
136
+ }
137
+
138
+ [ Fact ]
139
+ public async Task TagHelper_LeavesOutputUnchanged_IfForNotBound2 ( )
140
+ {
141
+ // Arrange
142
+ var expectedAttributes = new Dictionary < string , string >
143
+ {
144
+ { "class" , "form-control" } ,
145
+ } ;
146
+ var expectedContent = "original content" ;
147
+ var expectedTagName = "original tag name" ;
148
+
149
+ var metadataProvider = new DataAnnotationsModelMetadataProvider ( ) ;
150
+ var metadata = metadataProvider . GetMetadataForProperty (
151
+ modelAccessor : ( ) => null ,
152
+ containerType : typeof ( Model ) ,
153
+ propertyName : nameof ( Model . Text ) ) ;
154
+ var modelExpression = new ModelExpression ( nameof ( Model . Text ) , metadata ) ;
155
+ var tagHelper = new LabelTagHelper ( ) ;
156
+
157
+ var tagHelperContext = new TagHelperContext ( allAttributes : new Dictionary < string , object > ( ) ) ;
158
+ var output = new TagHelperOutput ( expectedTagName , expectedAttributes , expectedContent ) ;
159
+
160
+ var htmlGenerator = new TestableHtmlGenerator ( metadataProvider ) ;
161
+ Model model = null ;
162
+ var viewContext = TestableHtmlGenerator . GetViewContext ( model , htmlGenerator , metadataProvider ) ;
163
+ var activator = new DefaultTagHelperActivator ( ) ;
164
+ activator . Activate ( tagHelper , viewContext ) ;
165
+
166
+ // Act
167
+ await tagHelper . ProcessAsync ( tagHelperContext , output ) ;
168
+
169
+ // Assert
170
+ Assert . Equal ( expectedAttributes , output . Attributes ) ;
171
+ Assert . Equal ( expectedContent , output . Content ) ;
172
+ Assert . Equal ( expectedTagName , output . TagName ) ;
173
+ }
174
+
175
+ public class TagHelperOutputContent
176
+ {
177
+ public TagHelperOutputContent ( string outputContent , string expectedContent )
178
+ {
179
+ OriginalContent = outputContent ;
180
+ ExpectedContent = expectedContent ;
181
+ }
182
+
183
+ public string OriginalContent { get ; set ; }
184
+ public string ExpectedContent { get ; set ; }
185
+ }
186
+
187
+ private class Model
188
+ {
189
+ public string Text { get ; set ; }
190
+
191
+ public NestedModel NestedModel { get ; set ; }
192
+ }
193
+
194
+ private class NestedModel
195
+ {
196
+ public string Text { get ; set ; }
197
+ }
198
+ }
199
+ }
0 commit comments