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 . IO ;
7+ using System . Reflection ;
8+ using Microsoft . AspNet . Http ;
9+ using Microsoft . AspNet . Mvc . ModelBinding ;
10+ using Microsoft . AspNet . Mvc . Rendering ;
11+ using Microsoft . AspNet . Razor . Runtime . TagHelpers ;
12+ using Microsoft . AspNet . Routing ;
13+ using Moq ;
14+ using Xunit ;
15+
16+ namespace Microsoft . AspNet . Mvc . TagHelpers
17+ {
18+ public class FormTagHelperTest
19+ {
20+ [ Theory ]
21+ [ InlineData ( true , "<input />" ) ]
22+ [ InlineData ( false , "" ) ]
23+ [ InlineData ( null , "<input />" ) ]
24+ public void Process_GeneratesAntiForgeryCorrectly ( bool ? antiForgery , string expectedContent )
25+ {
26+ // Arrange
27+ var expectedViewContext = CreateViewContext ( ) ;
28+ var formTagHelper = new FormTagHelper
29+ {
30+ Action = "Index" ,
31+ AntiForgery = antiForgery
32+ } ;
33+ var context = new TagHelperContext (
34+ allAttributes : new Dictionary < string , object > ( ) ) ;
35+ var output = new TagHelperOutput (
36+ "form" ,
37+ attributes : new Dictionary < string , string > ( ) ,
38+ content : string . Empty ) ;
39+
40+ var generator = new Mock < IHtmlGenerator > ( ) ;
41+ generator . Setup ( mock =>
42+ mock . GenerateForm ( It . IsAny < ViewContext > ( ) ,
43+ It . IsAny < string > ( ) ,
44+ It . IsAny < string > ( ) ,
45+ It . IsAny < object > ( ) ,
46+ It . IsAny < string > ( ) ,
47+ It . IsAny < object > ( ) ) )
48+ . Returns ( new TagBuilder ( "form" ) ) ;
49+ generator . Setup ( mock => mock . GenerateAntiForgery ( It . IsAny < ViewContext > ( ) ) )
50+ . Returns ( new TagBuilder ( "input" ) ) ;
51+
52+ SetViewContextAndGenerator ( formTagHelper ,
53+ expectedViewContext ,
54+ generator . Object ) ;
55+
56+ // Act
57+ formTagHelper . Process ( context , output ) ;
58+
59+ // Assert
60+ Assert . Equal ( expectedContent , output . Content ) ;
61+ }
62+
63+ [ Fact ]
64+ public void Process_UnderstandsRouteValues ( )
65+ {
66+ // Arrange
67+ var testViewContext = CreateViewContext ( ) ;
68+ var formTagHelper = new FormTagHelper
69+ {
70+ Action = "Index" ,
71+ AntiForgery = false
72+ } ;
73+ var context = new TagHelperContext (
74+ allAttributes : new Dictionary < string , object > ( ) ) ;
75+ var output = new TagHelperOutput (
76+ "form" ,
77+ attributes : new Dictionary < string , string > ( )
78+ {
79+ { "route-val" , "hello" } ,
80+ { "roUte--Foo" , "bar" } ,
81+ { "ROUTEE-NotRoute" , "something" }
82+ } ,
83+ content : string . Empty ) ;
84+ var called = false ;
85+ var generator = new Mock < IHtmlGenerator > ( ) ;
86+ generator . Setup ( mock =>
87+ mock . GenerateForm ( It . IsAny < ViewContext > ( ) ,
88+ It . IsAny < string > ( ) ,
89+ It . IsAny < string > ( ) ,
90+ It . IsAny < object > ( ) ,
91+ It . IsAny < string > ( ) ,
92+ It . IsAny < object > ( ) ) )
93+ . Callback < ViewContext , string , string , object , string , object > (
94+ ( viewContext , actionName , controllerName , routeValues , method , htmlAttributes ) =>
95+ {
96+ called = true ;
97+
98+ var routeValueDictionary = ( Dictionary < string , object > ) routeValues ;
99+ var routeValue = Assert . Single ( routeValueDictionary , kvp => kvp . Key . Equals ( "val" ) ) ;
100+ Assert . Equal ( "hello" , routeValue . Value ) ;
101+ routeValue = Assert . Single ( routeValueDictionary , kvp => kvp . Key . Equals ( "-Foo" ) ) ;
102+ Assert . Equal ( "bar" , routeValue . Value ) ;
103+ } )
104+ . Returns ( new TagBuilder ( "form" ) ) ;
105+
106+ SetViewContextAndGenerator ( formTagHelper ,
107+ testViewContext ,
108+ generator . Object ) ;
109+
110+ // Act & Assert
111+ formTagHelper . Process ( context , output ) ;
112+
113+ var attribute = Assert . Single ( output . Attributes , kvp => kvp . Key . Equals ( "ROUTEE-NotRoute" ) ) ;
114+ Assert . Equal ( "something" , attribute . Value ) ;
115+ Assert . True ( called ) ;
116+ }
117+
118+ [ Fact ]
119+ public void Process_CallsIntoGenerateFormWithExpectedParameters ( )
120+ {
121+ // Arrange
122+ var expectedViewContext = CreateViewContext ( ) ;
123+ var formTagHelper = new FormTagHelper
124+ {
125+ Action = "Index" ,
126+ Controller = "Home" ,
127+ Method = "POST" ,
128+ AntiForgery = false
129+ } ;
130+ var called = false ;
131+ var context = new TagHelperContext (
132+ allAttributes : new Dictionary < string , object > ( ) ) ;
133+ var output = new TagHelperOutput (
134+ "form" ,
135+ attributes : new Dictionary < string , string > ( ) ,
136+ content : string . Empty ) ;
137+
138+ var generator = new Mock < IHtmlGenerator > ( ) ;
139+ generator . Setup ( mock =>
140+ mock . GenerateForm ( It . IsAny < ViewContext > ( ) ,
141+ It . IsAny < string > ( ) ,
142+ It . IsAny < string > ( ) ,
143+ It . IsAny < object > ( ) ,
144+ It . IsAny < string > ( ) ,
145+ It . IsAny < object > ( ) ) )
146+ . Callback < ViewContext , string , string , object , string , object > (
147+ ( viewContext , actionName , controllerName , routeValues , method , htmlAttributes ) =>
148+ {
149+ called = true ;
150+
151+ Assert . Same ( expectedViewContext , viewContext ) ;
152+ Assert . Equal ( "Index" , actionName ) ;
153+ Assert . Equal ( "Home" , controllerName ) ;
154+ Assert . Null ( routeValues ) ;
155+ Assert . Equal ( "POST" , method ) ;
156+ Assert . Null ( htmlAttributes ) ;
157+ } )
158+ . Returns ( new TagBuilder ( "form" ) ) ;
159+
160+ SetViewContextAndGenerator ( formTagHelper ,
161+ expectedViewContext ,
162+ generator . Object ) ;
163+
164+ // Act & Assert
165+ formTagHelper . Process ( context , output ) ;
166+
167+ Assert . True ( called ) ;
168+ }
169+
170+ [ Fact ]
171+ public void Process_RestoresBoundAttributesIfActionIsURL ( )
172+ {
173+ // Arrange
174+ var formTagHelper = new FormTagHelper
175+ {
176+ Action = "http://www.contoso.com" ,
177+ Method = "POST"
178+ } ;
179+ var output = new TagHelperOutput ( "form" ,
180+ attributes : new Dictionary < string , string > ( ) ,
181+ content : string . Empty ) ;
182+ var context = new TagHelperContext (
183+ allAttributes : new Dictionary < string , object > ( )
184+ {
185+ { "aCTiON" , "http://www.contoso.com" } ,
186+ { "METhod" , "POST" }
187+ } ) ;
188+
189+ // Act
190+ formTagHelper . Process ( context , output ) ;
191+
192+ // Assert
193+ var attribute = Assert . Single ( output . Attributes , kvp => kvp . Key . Equals ( "aCTiON" ) ) ;
194+ Assert . Equal ( "http://www.contoso.com" , attribute . Value ) ;
195+ attribute = Assert . Single ( output . Attributes , kvp => kvp . Key . Equals ( "METhod" ) ) ;
196+ Assert . Equal ( "POST" , attribute . Value ) ;
197+ }
198+
199+ [ Theory ]
200+ [ InlineData ( true , "<input />" ) ]
201+ [ InlineData ( false , "" ) ]
202+ [ InlineData ( null , "" ) ]
203+ public void Process_AllowsAntiForgeryIfActionIsURL ( bool ? antiForgery , string expectedContent )
204+ {
205+ // Arrange
206+ var expectedViewContext = CreateViewContext ( ) ;
207+ var generator = new Mock < IHtmlGenerator > ( ) ;
208+ generator . Setup ( mock => mock . GenerateAntiForgery ( It . IsAny < ViewContext > ( ) ) )
209+ . Returns ( new TagBuilder ( "input" ) ) ;
210+ var formTagHelper = new FormTagHelper
211+ {
212+ Action = "http://www.contoso.com" ,
213+ AntiForgery = antiForgery ,
214+ } ;
215+ SetViewContextAndGenerator ( formTagHelper ,
216+ expectedViewContext ,
217+ generator . Object ) ;
218+ var output = new TagHelperOutput ( "form" ,
219+ attributes : new Dictionary < string , string > ( ) ,
220+ content : string . Empty ) ;
221+ var context = new TagHelperContext (
222+ allAttributes : new Dictionary < string , object > ( )
223+ {
224+ { "aCTiON" , "http://www.contoso.com" }
225+ } ) ;
226+
227+ // Act
228+ formTagHelper . Process ( context , output ) ;
229+
230+ // Assert
231+ Assert . Equal ( expectedContent , output . Content ) ;
232+ }
233+
234+ [ Fact ]
235+ public void Process_ThrowsIfActionIsUrlWithSpecifiedController ( )
236+ {
237+ // Arrange
238+ var formTagHelper = new FormTagHelper
239+ {
240+ Action = "http://www.contoso.com" ,
241+ Controller = "Home" ,
242+ Method = "POST"
243+ } ;
244+ var expectedErrorMessage = "Cannot determine an Action for FormTagHelper. A FormTagHelper with a " +
245+ "speicified URL based Action must not have a Controller attribute." ;
246+
247+ // Act & Assert
248+ var ex = Assert . Throws < InvalidOperationException > ( ( ) =>
249+ {
250+ formTagHelper . Process ( context : null , output : null ) ;
251+ } ) ;
252+
253+ Assert . Equal ( expectedErrorMessage , ex . Message ) ;
254+ }
255+
256+ private ViewContext CreateViewContext ( )
257+ {
258+ var actionContext = new ActionContext (
259+ new Mock < HttpContext > ( ) . Object ,
260+ new RouteData ( ) ,
261+ new ActionDescriptor ( ) ) ;
262+
263+ return new ViewContext (
264+ actionContext ,
265+ Mock . Of < IView > ( ) ,
266+ new ViewDataDictionary (
267+ new DataAnnotationsModelMetadataProvider ( ) ) ,
268+ new StringWriter ( ) ) ;
269+ }
270+
271+ private void SetViewContextAndGenerator ( ITagHelper tagHelper ,
272+ ViewContext viewContext ,
273+ IHtmlGenerator generator )
274+ {
275+ var tagHelperType = tagHelper . GetType ( ) ;
276+
277+ tagHelperType . GetProperty ( "ViewContext" , BindingFlags . NonPublic | BindingFlags . Instance )
278+ . SetValue ( tagHelper , viewContext ) ;
279+ tagHelperType . GetProperty ( "Generator" , BindingFlags . NonPublic | BindingFlags . Instance )
280+ . SetValue ( tagHelper , generator ) ;
281+ }
282+ }
283+ }
0 commit comments