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, expected content.
19
+ public static TheoryData < object , Type , Func < object > , string , ContentAssertion > 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 , ContentAssertion >
46
+ {
47
+ { null , typeof ( Model ) , ( ) => null , "Text" ,
48
+ new ContentAssertion ( Environment . NewLine , "Text" ) } ,
49
+
50
+ { modelWithNull , typeof ( Model ) , ( ) => modelWithNull . Text , "Text" ,
51
+ new ContentAssertion ( Environment . NewLine , "Text" ) } ,
52
+ { modelWithText , typeof ( Model ) , ( ) => modelWithText . Text , "Text" ,
53
+ new ContentAssertion ( Environment . NewLine , "Text" ) } ,
54
+ { modelWithText , typeof ( Model ) , ( ) => modelWithNull . Text , "Text" ,
55
+ new ContentAssertion ( "Hello World" , "Hello World" ) } ,
56
+ { modelWithText , typeof ( Model ) , ( ) => modelWithText . Text , "Text" ,
57
+ new ContentAssertion ( "Hello World" , "Hello World" ) } ,
58
+
59
+ { modelWithNull , typeof ( NestedModel ) , ( ) => modelWithNull . NestedModel . Text , "NestedModel.Text" ,
60
+ new ContentAssertion ( Environment . NewLine , "Text" ) } ,
61
+ { modelWithText , typeof ( NestedModel ) , ( ) => modelWithText . NestedModel . Text , "NestedModel.Text" ,
62
+ new ContentAssertion ( Environment . NewLine , "Text" ) } ,
63
+ { modelWithNull , typeof ( NestedModel ) , ( ) => modelWithNull . NestedModel . Text , "NestedModel.Text" ,
64
+ new ContentAssertion ( "Hello World" , "Hello World" ) } ,
65
+ { modelWithText , typeof ( NestedModel ) , ( ) => modelWithText . NestedModel . Text , "NestedModel.Text" ,
66
+ new ContentAssertion ( "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 ContentAssertion ( Environment . NewLine , "Text" ) } ,
72
+ { models , typeof ( Model ) , ( ) => models [ 1 ] . Text , "[1].Text" ,
73
+ new ContentAssertion ( Environment . NewLine , "Text" ) } ,
74
+ { models , typeof ( Model ) , ( ) => models [ 0 ] . Text , "[0].Text" ,
75
+ new ContentAssertion ( "Hello World" , "Hello World" ) } ,
76
+ { models , typeof ( Model ) , ( ) => models [ 1 ] . Text , "[1].Text" ,
77
+ new ContentAssertion ( "Hello World" , "Hello World" ) } ,
78
+
79
+ { models , typeof ( NestedModel ) , ( ) => models [ 0 ] . NestedModel . Text , "[0].NestedModel.Text" ,
80
+ new ContentAssertion ( Environment . NewLine , "Text" ) } ,
81
+ { models , typeof ( NestedModel ) , ( ) => models [ 1 ] . NestedModel . Text , "[1].NestedModel.Text" ,
82
+ new ContentAssertion ( Environment . NewLine , "Text" ) } ,
83
+ { models , typeof ( NestedModel ) , ( ) => models [ 0 ] . NestedModel . Text , "[0].NestedModel.Text" ,
84
+ new ContentAssertion ( "Hello World" , "Hello World" ) } ,
85
+ { models , typeof ( NestedModel ) , ( ) => models [ 1 ] . NestedModel . Text , "[1].NestedModel.Text" ,
86
+ new ContentAssertion ( "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
+ ContentAssertion contentAssertion )
99
+ {
100
+ // Arrange
101
+ var expectedAttributes = new Dictionary < string , string >
102
+ {
103
+ { "class" , "form-control" } ,
104
+ { "for" , propertyPath }
105
+ } ;
106
+ var expectedTagName = "label" ;
107
+
108
+ var metadataProvider = new DataAnnotationsModelMetadataProvider ( ) ;
109
+
110
+ // Property name is either nameof(Model.Text) or nameof(NestedModel.Text).
111
+ var metadata = metadataProvider . GetMetadataForProperty ( modelAccessor , containerType , propertyName : "Text" ) ;
112
+ var modelExpression = new ModelExpression ( propertyPath , metadata ) ;
113
+ var tagHelper = new LabelTagHelper
114
+ {
115
+ For = modelExpression ,
116
+ } ;
117
+
118
+ var tagHelperContext = new TagHelperContext ( allAttributes : new Dictionary < string , object > ( ) ) ;
119
+ var htmlAttributes = new Dictionary < string , string >
120
+ {
121
+ { "class" , "form-control" } ,
122
+ } ;
123
+ var output = new TagHelperOutput ( expectedTagName , htmlAttributes , contentAssertion . OutputContent ) ;
124
+
125
+ var htmlGenerator = new TestableHtmlGenerator ( metadataProvider ) ;
126
+ var viewContext = TestableHtmlGenerator . GetViewContext ( model , htmlGenerator , metadataProvider ) ;
127
+ var activator = new DefaultTagHelperActivator ( ) ;
128
+ activator . Activate ( tagHelper , viewContext ) ;
129
+
130
+ // Act
131
+ await tagHelper . ProcessAsync ( tagHelperContext , output ) ;
132
+
133
+ // Assert
134
+ Assert . Equal ( expectedAttributes , output . Attributes ) ;
135
+ Assert . Equal ( contentAssertion . ExpectedContent , output . Content ) ;
136
+ Assert . False ( output . SelfClosing ) ;
137
+ Assert . Equal ( expectedTagName , output . TagName ) ;
138
+ }
139
+
140
+ [ Fact ]
141
+ public async Task TagHelper_LeavesOutputUnchanged_IfForNotBound2 ( )
142
+ {
143
+ // Arrange
144
+ var expectedAttributes = new Dictionary < string , string >
145
+ {
146
+ { "class" , "form-control" } ,
147
+ } ;
148
+ var expectedContent = "original content" ;
149
+ var expectedTagName = "original tag name" ;
150
+
151
+ var metadataProvider = new DataAnnotationsModelMetadataProvider ( ) ;
152
+ var metadata = metadataProvider . GetMetadataForProperty (
153
+ modelAccessor : ( ) => null ,
154
+ containerType : typeof ( Model ) ,
155
+ propertyName : nameof ( Model . Text ) ) ;
156
+ var modelExpression = new ModelExpression ( nameof ( Model . Text ) , metadata ) ;
157
+ var tagHelper = new LabelTagHelper ( ) ;
158
+
159
+ var tagHelperContext = new TagHelperContext ( allAttributes : new Dictionary < string , object > ( ) ) ;
160
+ var output = new TagHelperOutput ( expectedTagName , expectedAttributes , expectedContent ) ;
161
+
162
+ var htmlGenerator = new TestableHtmlGenerator ( metadataProvider ) ;
163
+ Model model = null ;
164
+ var viewContext = TestableHtmlGenerator . GetViewContext ( model , htmlGenerator , metadataProvider ) ;
165
+ var activator = new DefaultTagHelperActivator ( ) ;
166
+ activator . Activate ( tagHelper , viewContext ) ;
167
+
168
+ // Act
169
+ await tagHelper . ProcessAsync ( tagHelperContext , output ) ;
170
+
171
+ // Assert
172
+ Assert . Equal ( expectedAttributes , output . Attributes ) ;
173
+ Assert . Equal ( expectedContent , output . Content ) ;
174
+ Assert . Equal ( expectedTagName , output . TagName ) ;
175
+ }
176
+
177
+ public class ContentAssertion
178
+ {
179
+ public ContentAssertion ( string outputContent , string expectedContent )
180
+ {
181
+ OutputContent = outputContent ;
182
+ ExpectedContent = expectedContent ;
183
+ }
184
+
185
+ public string OutputContent { get ; set ; }
186
+ public string ExpectedContent { get ; set ; }
187
+ }
188
+
189
+ private class Model
190
+ {
191
+ public string Text { get ; set ; }
192
+
193
+ public NestedModel NestedModel { get ; set ; }
194
+ }
195
+
196
+ private class NestedModel
197
+ {
198
+ public string Text { get ; set ; }
199
+ }
200
+ }
201
+ }
0 commit comments