PageRenderTime 25ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/test/System.Web.Mvc.Test/Html/Test/DefaultEditorTemplatesTest.cs

https://bitbucket.org/mdavid/aspnetwebstack
C# | 693 lines | 492 code | 127 blank | 74 comment | 4 complexity | 442568c777d9d38bc8f28c939722a17f MD5 | raw file
  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using System.Data.Linq;
  4. using System.Data.Objects.DataClasses;
  5. using System.IO;
  6. using System.Web.UI.WebControls;
  7. using Microsoft.Web.UnitTestUtil;
  8. using Moq;
  9. using Xunit;
  10. using Assert = Microsoft.TestCommon.AssertEx;
  11. namespace System.Web.Mvc.Html.Test
  12. {
  13. public class DefaultEditorTemplatesTest
  14. {
  15. // BooleanTemplate
  16. [Fact]
  17. public void BooleanTemplateTests()
  18. {
  19. // Boolean values
  20. Assert.Equal(
  21. @"<input checked=""checked"" class=""check-box"" id=""FieldPrefix"" name=""FieldPrefix"" type=""checkbox"" value=""true"" /><input name=""FieldPrefix"" type=""hidden"" value=""false"" />",
  22. DefaultEditorTemplates.BooleanTemplate(MakeHtmlHelper<bool>(true)));
  23. Assert.Equal(
  24. @"<input class=""check-box"" id=""FieldPrefix"" name=""FieldPrefix"" type=""checkbox"" value=""true"" /><input name=""FieldPrefix"" type=""hidden"" value=""false"" />",
  25. DefaultEditorTemplates.BooleanTemplate(MakeHtmlHelper<bool>(false)));
  26. Assert.Equal(
  27. @"<input class=""check-box"" id=""FieldPrefix"" name=""FieldPrefix"" type=""checkbox"" value=""true"" /><input name=""FieldPrefix"" type=""hidden"" value=""false"" />",
  28. DefaultEditorTemplates.BooleanTemplate(MakeHtmlHelper<bool>(null)));
  29. // Nullable<Boolean> values
  30. Assert.Equal(
  31. @"<select class=""list-box tri-state"" id=""FieldPrefix"" name=""FieldPrefix""><option value="""">Not Set</option>
  32. <option selected=""selected"" value=""true"">True</option>
  33. <option value=""false"">False</option>
  34. </select>",
  35. DefaultEditorTemplates.BooleanTemplate(MakeHtmlHelper<Nullable<bool>>(true)));
  36. Assert.Equal(
  37. @"<select class=""list-box tri-state"" id=""FieldPrefix"" name=""FieldPrefix""><option value="""">Not Set</option>
  38. <option value=""true"">True</option>
  39. <option selected=""selected"" value=""false"">False</option>
  40. </select>",
  41. DefaultEditorTemplates.BooleanTemplate(MakeHtmlHelper<Nullable<bool>>(false)));
  42. Assert.Equal(
  43. @"<select class=""list-box tri-state"" id=""FieldPrefix"" name=""FieldPrefix""><option selected=""selected"" value="""">Not Set</option>
  44. <option value=""true"">True</option>
  45. <option value=""false"">False</option>
  46. </select>",
  47. DefaultEditorTemplates.BooleanTemplate(MakeHtmlHelper<Nullable<bool>>(null)));
  48. }
  49. // CollectionTemplate
  50. private static string CollectionSpyCallback(HtmlHelper html, ModelMetadata metadata, string htmlFieldName, string templateName, DataBoundControlMode mode, object additionalViewData)
  51. {
  52. return String.Format(Environment.NewLine + "Model = {0}, ModelType = {1}, PropertyName = {2}, HtmlFieldName = {3}, TemplateName = {4}, Mode = {5}, TemplateInfo.HtmlFieldPrefix = {6}, AdditionalViewData = {7}",
  53. metadata.Model ?? "(null)",
  54. metadata.ModelType == null ? "(null)" : metadata.ModelType.FullName,
  55. metadata.PropertyName ?? "(null)",
  56. htmlFieldName == String.Empty ? "(empty)" : htmlFieldName ?? "(null)",
  57. templateName ?? "(null)",
  58. mode,
  59. html.ViewContext.ViewData.TemplateInfo.HtmlFieldPrefix,
  60. AnonymousObject.Inspect(additionalViewData));
  61. }
  62. [Fact]
  63. public void CollectionTemplateWithNullModel()
  64. {
  65. // Arrange
  66. HtmlHelper html = MakeHtmlHelper<object>(null);
  67. // Act
  68. string result = DefaultEditorTemplates.CollectionTemplate(html, CollectionSpyCallback);
  69. // Assert
  70. Assert.Equal(String.Empty, result);
  71. }
  72. [Fact]
  73. public void CollectionTemplateNonEnumerableModelThrows()
  74. {
  75. // Arrange
  76. HtmlHelper html = MakeHtmlHelper<object>(new object());
  77. // Act & Assert
  78. Assert.Throws<InvalidOperationException>(
  79. () => DefaultEditorTemplates.CollectionTemplate(html, CollectionSpyCallback),
  80. "The Collection template was used with an object of type 'System.Object', which does not implement System.IEnumerable."
  81. );
  82. }
  83. [Fact]
  84. public void CollectionTemplateWithSingleItemCollectionWithoutPrefix()
  85. {
  86. // Arrange
  87. HtmlHelper html = MakeHtmlHelper<List<string>>(new List<string> { "foo" });
  88. html.ViewContext.ViewData.TemplateInfo.HtmlFieldPrefix = null;
  89. // Act
  90. string result = DefaultEditorTemplates.CollectionTemplate(html, CollectionSpyCallback);
  91. // Assert
  92. Assert.Equal(@"
  93. Model = foo, ModelType = System.String, PropertyName = (null), HtmlFieldName = [0], TemplateName = (null), Mode = Edit, TemplateInfo.HtmlFieldPrefix = , AdditionalViewData = (null)",
  94. result);
  95. }
  96. [Fact]
  97. public void CollectionTemplateWithSingleItemCollectionWithPrefix()
  98. {
  99. // Arrange
  100. HtmlHelper html = MakeHtmlHelper<List<string>>(new List<string> { "foo" });
  101. html.ViewContext.ViewData.TemplateInfo.HtmlFieldPrefix = "ModelProperty";
  102. // Act
  103. string result = DefaultEditorTemplates.CollectionTemplate(html, CollectionSpyCallback);
  104. // Assert
  105. Assert.Equal(@"
  106. Model = foo, ModelType = System.String, PropertyName = (null), HtmlFieldName = ModelProperty[0], TemplateName = (null), Mode = Edit, TemplateInfo.HtmlFieldPrefix = , AdditionalViewData = (null)",
  107. result);
  108. }
  109. [Fact]
  110. public void CollectionTemplateWithMultiItemCollection()
  111. {
  112. // Arrange
  113. HtmlHelper html = MakeHtmlHelper<List<string>>(new List<string> { "foo", "bar", "baz" });
  114. html.ViewContext.ViewData.TemplateInfo.HtmlFieldPrefix = null;
  115. // Act
  116. string result = DefaultEditorTemplates.CollectionTemplate(html, CollectionSpyCallback);
  117. // Assert
  118. Assert.Equal(@"
  119. Model = foo, ModelType = System.String, PropertyName = (null), HtmlFieldName = [0], TemplateName = (null), Mode = Edit, TemplateInfo.HtmlFieldPrefix = , AdditionalViewData = (null)
  120. Model = bar, ModelType = System.String, PropertyName = (null), HtmlFieldName = [1], TemplateName = (null), Mode = Edit, TemplateInfo.HtmlFieldPrefix = , AdditionalViewData = (null)
  121. Model = baz, ModelType = System.String, PropertyName = (null), HtmlFieldName = [2], TemplateName = (null), Mode = Edit, TemplateInfo.HtmlFieldPrefix = , AdditionalViewData = (null)",
  122. result);
  123. }
  124. [Fact]
  125. public void CollectionTemplateNullITemInWeaklyTypedCollectionUsesModelTypeOfString()
  126. {
  127. // Arrange
  128. HtmlHelper html = MakeHtmlHelper<ArrayList>(new ArrayList { null });
  129. html.ViewContext.ViewData.TemplateInfo.HtmlFieldPrefix = null;
  130. // Act
  131. string result = DefaultEditorTemplates.CollectionTemplate(html, CollectionSpyCallback);
  132. // Assert
  133. Assert.Equal(@"
  134. Model = (null), ModelType = System.String, PropertyName = (null), HtmlFieldName = [0], TemplateName = (null), Mode = Edit, TemplateInfo.HtmlFieldPrefix = , AdditionalViewData = (null)",
  135. result);
  136. }
  137. [Fact]
  138. public void CollectionTemplateNullItemInStronglyTypedCollectionUsesModelTypeFromIEnumerable()
  139. {
  140. // Arrange
  141. HtmlHelper html = MakeHtmlHelper<List<IHttpHandler>>(new List<IHttpHandler> { null });
  142. html.ViewContext.ViewData.TemplateInfo.HtmlFieldPrefix = null;
  143. // Act
  144. string result = DefaultEditorTemplates.CollectionTemplate(html, CollectionSpyCallback);
  145. // Assert
  146. Assert.Equal(@"
  147. Model = (null), ModelType = System.Web.IHttpHandler, PropertyName = (null), HtmlFieldName = [0], TemplateName = (null), Mode = Edit, TemplateInfo.HtmlFieldPrefix = , AdditionalViewData = (null)",
  148. result);
  149. }
  150. [Fact]
  151. public void CollectionTemplateUsesRealObjectTypes()
  152. {
  153. // Arrange
  154. HtmlHelper html = MakeHtmlHelper<List<Object>>(new List<Object> { 1, 2.3, "Hello World" });
  155. html.ViewContext.ViewData.TemplateInfo.HtmlFieldPrefix = null;
  156. // Act
  157. string result = DefaultEditorTemplates.CollectionTemplate(html, CollectionSpyCallback);
  158. // Assert
  159. Assert.Equal(@"
  160. Model = 1, ModelType = System.Int32, PropertyName = (null), HtmlFieldName = [0], TemplateName = (null), Mode = Edit, TemplateInfo.HtmlFieldPrefix = , AdditionalViewData = (null)
  161. Model = 2.3, ModelType = System.Double, PropertyName = (null), HtmlFieldName = [1], TemplateName = (null), Mode = Edit, TemplateInfo.HtmlFieldPrefix = , AdditionalViewData = (null)
  162. Model = Hello World, ModelType = System.String, PropertyName = (null), HtmlFieldName = [2], TemplateName = (null), Mode = Edit, TemplateInfo.HtmlFieldPrefix = , AdditionalViewData = (null)",
  163. result);
  164. }
  165. [Fact]
  166. public void CollectionTemplateNullItemInCollectionOfNullableValueTypesDoesNotDiscardNullable()
  167. {
  168. // Arrange
  169. HtmlHelper html = MakeHtmlHelper<List<int?>>(new List<int?> { 1, null, 2 });
  170. html.ViewContext.ViewData.TemplateInfo.HtmlFieldPrefix = null;
  171. // Act
  172. string result = DefaultEditorTemplates.CollectionTemplate(html, CollectionSpyCallback);
  173. // Assert
  174. Assert.Equal(@"
  175. Model = 1, ModelType = System.Nullable`1[[System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]], PropertyName = (null), HtmlFieldName = [0], TemplateName = (null), Mode = Edit, TemplateInfo.HtmlFieldPrefix = , AdditionalViewData = (null)
  176. Model = (null), ModelType = System.Nullable`1[[System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]], PropertyName = (null), HtmlFieldName = [1], TemplateName = (null), Mode = Edit, TemplateInfo.HtmlFieldPrefix = , AdditionalViewData = (null)
  177. Model = 2, ModelType = System.Nullable`1[[System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]], PropertyName = (null), HtmlFieldName = [2], TemplateName = (null), Mode = Edit, TemplateInfo.HtmlFieldPrefix = , AdditionalViewData = (null)",
  178. result);
  179. }
  180. // DecimalTemplate
  181. [Fact]
  182. public void DecimalTemplateTests()
  183. {
  184. Assert.Equal(
  185. @"<input class=""text-box single-line"" id=""FieldPrefix"" name=""FieldPrefix"" type=""text"" value=""12.35"" />",
  186. DefaultEditorTemplates.DecimalTemplate(MakeHtmlHelper<decimal>(12.3456M)));
  187. Assert.Equal(
  188. @"<input class=""text-box single-line"" id=""FieldPrefix"" name=""FieldPrefix"" type=""text"" value=""Formatted Value"" />",
  189. DefaultEditorTemplates.DecimalTemplate(MakeHtmlHelper<decimal>(12.3456M, "Formatted Value")));
  190. Assert.Equal(
  191. @"<input class=""text-box single-line"" id=""FieldPrefix"" name=""FieldPrefix"" type=""text"" value=""&lt;script>alert(&#39;XSS!&#39;)&lt;/script>"" />",
  192. DefaultEditorTemplates.DecimalTemplate(MakeHtmlHelper<decimal>(12.3456M, "<script>alert('XSS!')</script>")));
  193. }
  194. // HiddenInputTemplate
  195. [Fact]
  196. public void HiddenInputTemplateTests()
  197. {
  198. Assert.Equal(
  199. @"Hidden Value<input id=""FieldPrefix"" name=""FieldPrefix"" type=""hidden"" value=""Hidden Value"" />",
  200. DefaultEditorTemplates.HiddenInputTemplate(MakeHtmlHelper<string>("Hidden Value")));
  201. Assert.Equal(
  202. @"&lt;script&gt;alert(&#39;XSS!&#39;)&lt;/script&gt;<input id=""FieldPrefix"" name=""FieldPrefix"" type=""hidden"" value=""&lt;script>alert(&#39;XSS!&#39;)&lt;/script>"" />",
  203. DefaultEditorTemplates.HiddenInputTemplate(MakeHtmlHelper<string>("<script>alert('XSS!')</script>")));
  204. var helperWithInvisibleHtml = MakeHtmlHelper<string>("<script>alert('XSS!')</script>", "<b>Encode me!</b>");
  205. helperWithInvisibleHtml.ViewData.ModelMetadata.HideSurroundingHtml = true;
  206. Assert.Equal(
  207. @"<input id=""FieldPrefix"" name=""FieldPrefix"" type=""hidden"" value=""&lt;script>alert(&#39;XSS!&#39;)&lt;/script>"" />",
  208. DefaultEditorTemplates.HiddenInputTemplate(helperWithInvisibleHtml));
  209. byte[] byteValues = { 1, 2, 3, 4, 5 };
  210. Assert.Equal(
  211. @"&quot;AQIDBAU=&quot;<input id=""FieldPrefix"" name=""FieldPrefix"" type=""hidden"" value=""AQIDBAU="" />",
  212. DefaultEditorTemplates.HiddenInputTemplate(MakeHtmlHelper<Binary>(new Binary(byteValues))));
  213. Assert.Equal(
  214. @"System.Byte[]<input id=""FieldPrefix"" name=""FieldPrefix"" type=""hidden"" value=""AQIDBAU="" />",
  215. DefaultEditorTemplates.HiddenInputTemplate(MakeHtmlHelper<byte[]>(byteValues)));
  216. }
  217. // MultilineText
  218. [Fact]
  219. public void MultilineTextTemplateTests()
  220. {
  221. Assert.Equal(
  222. @"<textarea class=""text-box multi-line"" id=""FieldPrefix"" name=""FieldPrefix"">
  223. Multiple
  224. Line
  225. Value!</textarea>",
  226. DefaultEditorTemplates.MultilineTextTemplate(MakeHtmlHelper<string>("", @"Multiple
  227. Line
  228. Value!")));
  229. Assert.Equal(
  230. @"<textarea class=""text-box multi-line"" id=""FieldPrefix"" name=""FieldPrefix"">
  231. &lt;script&gt;alert(&#39;XSS!&#39;)&lt;/script&gt;</textarea>",
  232. DefaultEditorTemplates.MultilineTextTemplate(MakeHtmlHelper<string>("", "<script>alert('XSS!')</script>")));
  233. }
  234. // ObjectTemplate
  235. private static string SpyCallback(HtmlHelper html, ModelMetadata metadata, string htmlFieldName, string templateName, DataBoundControlMode mode, object additionalViewData)
  236. {
  237. return String.Format("Model = {0}, ModelType = {1}, PropertyName = {2}, HtmlFieldName = {3}, TemplateName = {4}, Mode = {5}, AdditionalViewData = {6}",
  238. metadata.Model ?? "(null)",
  239. metadata.ModelType == null ? "(null)" : metadata.ModelType.FullName,
  240. metadata.PropertyName ?? "(null)",
  241. htmlFieldName == String.Empty ? "(empty)" : htmlFieldName ?? "(null)",
  242. templateName ?? "(null)",
  243. mode,
  244. AnonymousObject.Inspect(additionalViewData));
  245. }
  246. class ObjectTemplateModel
  247. {
  248. public ObjectTemplateModel()
  249. {
  250. ComplexInnerModel = new object();
  251. }
  252. public string Property1 { get; set; }
  253. public string Property2 { get; set; }
  254. public object ComplexInnerModel { get; set; }
  255. }
  256. [Fact]
  257. public void ObjectTemplateEditsSimplePropertiesOnObjectByDefault()
  258. {
  259. string expected = @"<div class=""editor-label""><label for=""FieldPrefix_Property1"">Property1</label></div>
  260. <div class=""editor-field"">Model = p1, ModelType = System.String, PropertyName = Property1, HtmlFieldName = Property1, TemplateName = (null), Mode = Edit, AdditionalViewData = (null) </div>
  261. <div class=""editor-label""><label for=""FieldPrefix_Property2"">Property2</label></div>
  262. <div class=""editor-field"">Model = (null), ModelType = System.String, PropertyName = Property2, HtmlFieldName = Property2, TemplateName = (null), Mode = Edit, AdditionalViewData = (null) </div>
  263. ";
  264. // Arrange
  265. ObjectTemplateModel model = new ObjectTemplateModel { Property1 = "p1", Property2 = null };
  266. HtmlHelper html = MakeHtmlHelper<ObjectTemplateModel>(model);
  267. // Act
  268. string result = DefaultEditorTemplates.ObjectTemplate(html, SpyCallback);
  269. // Assert
  270. Assert.Equal(expected, result);
  271. }
  272. [Fact]
  273. public void ObjectTemplateWithModelError()
  274. {
  275. string expected = @"<div class=""editor-label""><label for=""FieldPrefix_Property1"">Property1</label></div>
  276. <div class=""editor-field"">Model = p1, ModelType = System.String, PropertyName = Property1, HtmlFieldName = Property1, TemplateName = (null), Mode = Edit, AdditionalViewData = (null) <span class=""field-validation-error"">Error Message</span></div>
  277. <div class=""editor-label""><label for=""FieldPrefix_Property2"">Property2</label></div>
  278. <div class=""editor-field"">Model = (null), ModelType = System.String, PropertyName = Property2, HtmlFieldName = Property2, TemplateName = (null), Mode = Edit, AdditionalViewData = (null) </div>
  279. ";
  280. // Arrange
  281. ObjectTemplateModel model = new ObjectTemplateModel { Property1 = "p1", Property2 = null };
  282. HtmlHelper html = MakeHtmlHelper<ObjectTemplateModel>(model);
  283. html.ViewData.ModelState.AddModelError("FieldPrefix.Property1", "Error Message");
  284. // Act
  285. string result = DefaultEditorTemplates.ObjectTemplate(html, SpyCallback);
  286. // Assert
  287. Assert.Equal(expected, result);
  288. }
  289. [Fact]
  290. public void ObjectTemplateWithDisplayNameMetadata()
  291. {
  292. string expected = @"<div class=""editor-field"">Model = (null), ModelType = System.String, PropertyName = Property1, HtmlFieldName = Property1, TemplateName = (null), Mode = Edit, AdditionalViewData = (null) </div>
  293. <div class=""editor-label""><label for=""FieldPrefix_Property2"">Custom display name</label></div>
  294. <div class=""editor-field"">Model = (null), ModelType = System.String, PropertyName = Property2, HtmlFieldName = Property2, TemplateName = (null), Mode = Edit, AdditionalViewData = (null) </div>
  295. ";
  296. // Arrange
  297. ObjectTemplateModel model = new ObjectTemplateModel();
  298. HtmlHelper html = MakeHtmlHelper<ObjectTemplateModel>(model);
  299. Mock<ModelMetadataProvider> provider = new Mock<ModelMetadataProvider>();
  300. Func<object> accessor = () => model;
  301. Mock<ModelMetadata> metadata = new Mock<ModelMetadata>(provider.Object, null, accessor, typeof(ObjectTemplateModel), null);
  302. ModelMetadata prop1Metadata = new ModelMetadata(provider.Object, typeof(ObjectTemplateModel), null, typeof(string), "Property1") { DisplayName = String.Empty };
  303. ModelMetadata prop2Metadata = new ModelMetadata(provider.Object, typeof(ObjectTemplateModel), null, typeof(string), "Property2") { DisplayName = "Custom display name" };
  304. html.ViewData.ModelMetadata = metadata.Object;
  305. metadata.Setup(p => p.Properties).Returns(() => new[] { prop1Metadata, prop2Metadata });
  306. // Act
  307. string result = DefaultEditorTemplates.ObjectTemplate(html, SpyCallback);
  308. // Assert
  309. Assert.Equal(expected, result);
  310. }
  311. [Fact]
  312. public void ObjectTemplateWithShowForEditorMetadata()
  313. {
  314. string expected = @"<div class=""editor-label""><label for=""FieldPrefix_Property1"">Property1</label></div>
  315. <div class=""editor-field"">Model = (null), ModelType = System.String, PropertyName = Property1, HtmlFieldName = Property1, TemplateName = (null), Mode = Edit, AdditionalViewData = (null) </div>
  316. ";
  317. // Arrange
  318. ObjectTemplateModel model = new ObjectTemplateModel();
  319. HtmlHelper html = MakeHtmlHelper<ObjectTemplateModel>(model);
  320. Mock<ModelMetadataProvider> provider = new Mock<ModelMetadataProvider>();
  321. Func<object> accessor = () => model;
  322. Mock<ModelMetadata> metadata = new Mock<ModelMetadata>(provider.Object, null, accessor, typeof(ObjectTemplateModel), null);
  323. ModelMetadata prop1Metadata = new ModelMetadata(provider.Object, typeof(ObjectTemplateModel), null, typeof(string), "Property1") { ShowForEdit = true };
  324. ModelMetadata prop2Metadata = new ModelMetadata(provider.Object, typeof(ObjectTemplateModel), null, typeof(string), "Property2") { ShowForEdit = false };
  325. html.ViewData.ModelMetadata = metadata.Object;
  326. metadata.Setup(p => p.Properties).Returns(() => new[] { prop1Metadata, prop2Metadata });
  327. // Act
  328. string result = DefaultEditorTemplates.ObjectTemplate(html, SpyCallback);
  329. // Assert
  330. Assert.Equal(expected, result);
  331. }
  332. [Fact]
  333. public void ObjectTemplatePreventsRecursionOnModelValue()
  334. {
  335. string expected = @"<div class=""editor-label""><label for=""FieldPrefix_Property2"">Property2</label></div>
  336. <div class=""editor-field"">Model = propValue2, ModelType = System.String, PropertyName = Property2, HtmlFieldName = Property2, TemplateName = (null), Mode = Edit, AdditionalViewData = (null) </div>
  337. ";
  338. // Arrange
  339. ObjectTemplateModel model = new ObjectTemplateModel();
  340. HtmlHelper html = MakeHtmlHelper<ObjectTemplateModel>(model);
  341. Mock<ModelMetadataProvider> provider = new Mock<ModelMetadataProvider>();
  342. Func<object> accessor = () => model;
  343. Mock<ModelMetadata> metadata = new Mock<ModelMetadata>(provider.Object, null, accessor, typeof(ObjectTemplateModel), null);
  344. ModelMetadata prop1Metadata = new ModelMetadata(provider.Object, typeof(ObjectTemplateModel), () => "propValue1", typeof(string), "Property1");
  345. ModelMetadata prop2Metadata = new ModelMetadata(provider.Object, typeof(ObjectTemplateModel), () => "propValue2", typeof(string), "Property2");
  346. html.ViewData.ModelMetadata = metadata.Object;
  347. metadata.Setup(p => p.Properties).Returns(() => new[] { prop1Metadata, prop2Metadata });
  348. html.ViewData.TemplateInfo.VisitedObjects.Add("propValue1");
  349. // Act
  350. string result = DefaultEditorTemplates.ObjectTemplate(html, SpyCallback);
  351. // Assert
  352. Assert.Equal(expected, result);
  353. }
  354. [Fact]
  355. public void ObjectTemplatePreventsRecursionOnModelTypeForNullModelValues()
  356. {
  357. string expected = @"<div class=""editor-label""><label for=""FieldPrefix_Property2"">Property2</label></div>
  358. <div class=""editor-field"">Model = propValue2, ModelType = System.String, PropertyName = Property2, HtmlFieldName = Property2, TemplateName = (null), Mode = Edit, AdditionalViewData = (null) </div>
  359. ";
  360. // Arrange
  361. ObjectTemplateModel model = new ObjectTemplateModel();
  362. HtmlHelper html = MakeHtmlHelper<ObjectTemplateModel>(model);
  363. Mock<ModelMetadataProvider> provider = new Mock<ModelMetadataProvider>();
  364. Func<object> accessor = () => model;
  365. Mock<ModelMetadata> metadata = new Mock<ModelMetadata>(provider.Object, null, accessor, typeof(ObjectTemplateModel), null);
  366. ModelMetadata prop1Metadata = new ModelMetadata(provider.Object, typeof(ObjectTemplateModel), null, typeof(string), "Property1");
  367. ModelMetadata prop2Metadata = new ModelMetadata(provider.Object, typeof(ObjectTemplateModel), () => "propValue2", typeof(string), "Property2");
  368. html.ViewData.ModelMetadata = metadata.Object;
  369. metadata.Setup(p => p.Properties).Returns(() => new[] { prop1Metadata, prop2Metadata });
  370. html.ViewData.TemplateInfo.VisitedObjects.Add(typeof(string));
  371. // Act
  372. string result = DefaultEditorTemplates.ObjectTemplate(html, SpyCallback);
  373. // Assert
  374. Assert.Equal(expected, result);
  375. }
  376. [Fact]
  377. public void ObjectTemplateDisplaysNullDisplayTextWithNullModelAndTemplateDepthGreaterThanOne()
  378. {
  379. // Arrange
  380. HtmlHelper html = MakeHtmlHelper<ObjectTemplateModel>(null);
  381. ModelMetadata metadata = ModelMetadataProviders.Current.GetMetadataForType(null, typeof(ObjectTemplateModel));
  382. metadata.NullDisplayText = "Null Display Text";
  383. metadata.SimpleDisplayText = "Simple Display Text";
  384. html.ViewData.ModelMetadata = metadata;
  385. html.ViewData.TemplateInfo.VisitedObjects.Add("foo");
  386. html.ViewData.TemplateInfo.VisitedObjects.Add("bar");
  387. // Act
  388. string result = DefaultEditorTemplates.ObjectTemplate(html, SpyCallback);
  389. // Assert
  390. Assert.Equal(metadata.NullDisplayText, result);
  391. }
  392. [Fact]
  393. public void ObjectTemplateDisplaysSimpleDisplayTextWithNonNullModelTemplateDepthGreaterThanOne()
  394. {
  395. // Arrange
  396. ObjectTemplateModel model = new ObjectTemplateModel();
  397. HtmlHelper html = MakeHtmlHelper<ObjectTemplateModel>(model);
  398. ModelMetadata metadata = ModelMetadataProviders.Current.GetMetadataForType(() => model, typeof(ObjectTemplateModel));
  399. html.ViewData.ModelMetadata = metadata;
  400. metadata.NullDisplayText = "Null Display Text";
  401. metadata.SimpleDisplayText = "Simple Display Text";
  402. html.ViewData.TemplateInfo.VisitedObjects.Add("foo");
  403. html.ViewData.TemplateInfo.VisitedObjects.Add("bar");
  404. // Act
  405. string result = DefaultEditorTemplates.ObjectTemplate(html, SpyCallback);
  406. // Assert
  407. Assert.Equal(metadata.SimpleDisplayText, result);
  408. }
  409. // PasswordTemplate
  410. [Fact]
  411. public void PasswordTemplateTests()
  412. {
  413. Assert.Equal(
  414. @"<input class=""text-box single-line password"" id=""FieldPrefix"" name=""FieldPrefix"" type=""password"" value=""Value"" />",
  415. DefaultEditorTemplates.PasswordTemplate(MakeHtmlHelper<string>("Value")));
  416. Assert.Equal(
  417. @"<input class=""text-box single-line password"" id=""FieldPrefix"" name=""FieldPrefix"" type=""password"" value=""&lt;script>alert(&#39;XSS!&#39;)&lt;/script>"" />",
  418. DefaultEditorTemplates.PasswordTemplate(MakeHtmlHelper<string>("<script>alert('XSS!')</script>")));
  419. }
  420. [Fact]
  421. public void ObjectTemplateWithHiddenHtml()
  422. {
  423. string expected = @"Model = propValue1, ModelType = System.String, PropertyName = Property1, HtmlFieldName = Property1, TemplateName = (null), Mode = Edit, AdditionalViewData = (null)";
  424. // Arrange
  425. ObjectTemplateModel model = new ObjectTemplateModel();
  426. HtmlHelper html = MakeHtmlHelper<ObjectTemplateModel>(model);
  427. Mock<ModelMetadataProvider> provider = new Mock<ModelMetadataProvider>();
  428. Func<object> accessor = () => model;
  429. Mock<ModelMetadata> metadata = new Mock<ModelMetadata>(provider.Object, null, accessor, typeof(ObjectTemplateModel), null);
  430. ModelMetadata prop1Metadata = new ModelMetadata(provider.Object, typeof(ObjectTemplateModel), () => "propValue1", typeof(string), "Property1") { HideSurroundingHtml = true };
  431. html.ViewData.ModelMetadata = metadata.Object;
  432. metadata.Setup(p => p.Properties).Returns(() => new[] { prop1Metadata });
  433. // Act
  434. string result = DefaultEditorTemplates.ObjectTemplate(html, SpyCallback);
  435. // Assert
  436. Assert.Equal(expected, result);
  437. }
  438. [Fact]
  439. public void ObjectTemplateAllPropertiesFromEntityObjectAreHidden()
  440. {
  441. // Arrange
  442. HtmlHelper html = MakeHtmlHelper<ObjectTemplateModel>(new MyEntityObject());
  443. // Act
  444. string result = DefaultEditorTemplates.ObjectTemplate(html, SpyCallback);
  445. // Assert
  446. Assert.Equal(String.Empty, result);
  447. }
  448. private class MyEntityObject : EntityObject
  449. {
  450. }
  451. // StringTemplate
  452. [Fact]
  453. public void StringTemplateTests()
  454. {
  455. Assert.Equal(
  456. @"<input class=""text-box single-line"" id=""FieldPrefix"" name=""FieldPrefix"" type=""text"" value=""Value"" />",
  457. DefaultEditorTemplates.StringTemplate(MakeHtmlHelper<string>("Value")));
  458. Assert.Equal(
  459. @"<input class=""text-box single-line"" id=""FieldPrefix"" name=""FieldPrefix"" type=""text"" value=""&lt;script>alert(&#39;XSS!&#39;)&lt;/script>"" />",
  460. DefaultEditorTemplates.StringTemplate(MakeHtmlHelper<string>("<script>alert('XSS!')</script>")));
  461. }
  462. // PhoneNumberInputTemplate
  463. [Fact]
  464. public void PhoneNumberInputTemplateTests()
  465. {
  466. Assert.Equal(
  467. @"<input class=""text-box single-line"" id=""FieldPrefix"" name=""FieldPrefix"" type=""tel"" value=""Value"" />",
  468. DefaultEditorTemplates.PhoneNumberInputTemplate(MakeHtmlHelper<string>("Value")));
  469. Assert.Equal(
  470. @"<input class=""text-box single-line"" id=""FieldPrefix"" name=""FieldPrefix"" type=""tel"" value=""&lt;script>alert(&#39;XSS!&#39;)&lt;/script>"" />",
  471. DefaultEditorTemplates.PhoneNumberInputTemplate(MakeHtmlHelper<string>("<script>alert('XSS!')</script>")));
  472. }
  473. // UrlInputTemplate
  474. [Fact]
  475. public void UrlInputTemplateTests()
  476. {
  477. Assert.Equal(
  478. @"<input class=""text-box single-line"" id=""FieldPrefix"" name=""FieldPrefix"" type=""url"" value=""Value"" />",
  479. DefaultEditorTemplates.UrlInputTemplate(MakeHtmlHelper<string>("Value")));
  480. Assert.Equal(
  481. @"<input class=""text-box single-line"" id=""FieldPrefix"" name=""FieldPrefix"" type=""url"" value=""&lt;script>alert(&#39;XSS!&#39;)&lt;/script>"" />",
  482. DefaultEditorTemplates.UrlInputTemplate(MakeHtmlHelper<string>("<script>alert('XSS!')</script>")));
  483. }
  484. // EmailAddressInputTemplate
  485. [Fact]
  486. public void EmailAddressTemplateTests()
  487. {
  488. Assert.Equal(
  489. @"<input class=""text-box single-line"" id=""FieldPrefix"" name=""FieldPrefix"" type=""email"" value=""Value"" />",
  490. DefaultEditorTemplates.EmailAddressInputTemplate(MakeHtmlHelper<string>("Value")));
  491. Assert.Equal(
  492. @"<input class=""text-box single-line"" id=""FieldPrefix"" name=""FieldPrefix"" type=""email"" value=""&lt;script>alert(&#39;XSS!&#39;)&lt;/script>"" />",
  493. DefaultEditorTemplates.EmailAddressInputTemplate(MakeHtmlHelper<string>("<script>alert('XSS!')</script>")));
  494. }
  495. // DateTimeInputTemplate
  496. [Fact]
  497. public void DateTimeInputTemplateTests()
  498. {
  499. Assert.Equal(
  500. @"<input class=""text-box single-line"" id=""FieldPrefix"" name=""FieldPrefix"" type=""datetime"" value=""Value"" />",
  501. DefaultEditorTemplates.DateTimeInputTemplate(MakeHtmlHelper<string>("Value")));
  502. Assert.Equal(
  503. @"<input class=""text-box single-line"" id=""FieldPrefix"" name=""FieldPrefix"" type=""datetime"" value=""&lt;script>alert(&#39;XSS!&#39;)&lt;/script>"" />",
  504. DefaultEditorTemplates.DateTimeInputTemplate(MakeHtmlHelper<string>("<script>alert('XSS!')</script>")));
  505. }
  506. // DateInputTemplate
  507. [Fact]
  508. public void DateInputTemplateTests()
  509. {
  510. Assert.Equal(
  511. @"<input class=""text-box single-line"" id=""FieldPrefix"" name=""FieldPrefix"" type=""date"" value=""Value"" />",
  512. DefaultEditorTemplates.DateInputTemplate(MakeHtmlHelper<string>("Value")));
  513. Assert.Equal(
  514. @"<input class=""text-box single-line"" id=""FieldPrefix"" name=""FieldPrefix"" type=""date"" value=""&lt;script>alert(&#39;XSS!&#39;)&lt;/script>"" />",
  515. DefaultEditorTemplates.DateInputTemplate(MakeHtmlHelper<string>("<script>alert('XSS!')</script>")));
  516. }
  517. // TimeInputTemplate
  518. [Fact]
  519. public void TimeInputTemplateTests()
  520. {
  521. Assert.Equal(
  522. @"<input class=""text-box single-line"" id=""FieldPrefix"" name=""FieldPrefix"" type=""time"" value=""Value"" />",
  523. DefaultEditorTemplates.TimeInputTemplate(MakeHtmlHelper<string>("Value")));
  524. Assert.Equal(
  525. @"<input class=""text-box single-line"" id=""FieldPrefix"" name=""FieldPrefix"" type=""time"" value=""&lt;script>alert(&#39;XSS!&#39;)&lt;/script>"" />",
  526. DefaultEditorTemplates.TimeInputTemplate(MakeHtmlHelper<string>("<script>alert('XSS!')</script>")));
  527. }
  528. // NumberInputTemplate
  529. [Fact]
  530. public void NumberInputTemplateTests()
  531. {
  532. Assert.Equal(
  533. @"<input class=""text-box single-line"" id=""FieldPrefix"" name=""FieldPrefix"" type=""number"" value=""Value"" />",
  534. DefaultEditorTemplates.NumberInputTemplate(MakeHtmlHelper<string>("Value")));
  535. Assert.Equal(
  536. @"<input class=""text-box single-line"" id=""FieldPrefix"" name=""FieldPrefix"" type=""number"" value=""&lt;script>alert(&#39;XSS!&#39;)&lt;/script>"" />",
  537. DefaultEditorTemplates.NumberInputTemplate(MakeHtmlHelper<string>("<script>alert('XSS!')</script>")));
  538. }
  539. // Helpers
  540. private HtmlHelper MakeHtmlHelper<TModel>(object model)
  541. {
  542. return MakeHtmlHelper<TModel>(model, model);
  543. }
  544. private HtmlHelper MakeHtmlHelper<TModel>(object model, object formattedModelValue)
  545. {
  546. ViewDataDictionary viewData = new ViewDataDictionary(model);
  547. viewData.TemplateInfo.HtmlFieldPrefix = "FieldPrefix";
  548. viewData.TemplateInfo.FormattedModelValue = formattedModelValue;
  549. viewData.ModelMetadata = new EmptyModelMetadataProvider().GetMetadataForType(() => model, typeof(TModel));
  550. Mock<HttpContextBase> mockHttpContext = new Mock<HttpContextBase>();
  551. mockHttpContext.Setup(o => o.Items).Returns(new Hashtable());
  552. ViewContext viewContext = new ViewContext(new ControllerContext(), new DummyView(), viewData, new TempDataDictionary(), new StringWriter())
  553. {
  554. HttpContext = mockHttpContext.Object
  555. };
  556. return new HtmlHelper(viewContext, new SimpleViewDataContainer(viewData));
  557. }
  558. private class DummyView : IView
  559. {
  560. public void Render(ViewContext viewContext, TextWriter writer)
  561. {
  562. throw new NotImplementedException();
  563. }
  564. }
  565. }
  566. }