// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; using System.Linq; using System.Threading.Tasks; using Microsoft.AspNet.Mvc.ModelBinding; using Microsoft.AspNet.Mvc.Rendering; using Microsoft.AspNet.Testing; using Moq; using Xunit; namespace Microsoft.AspNet.Mvc.Core { public class DefaultEditorTemplatesTests { [Fact] public void ObjectTemplateEditsSimplePropertiesOnObjectByDefault() { var expected = "
" + Environment.NewLine + "
Model = p1, ModelType = System.String, PropertyName = Property1," + " SimpleDisplayText = p1 " + "" + "
" + Environment.NewLine + "
" + Environment.NewLine + "
Model = (null), ModelType = System.String, PropertyName = Property2," + " SimpleDisplayText = (null) " + "" + "
" + Environment.NewLine; // Arrange var model = new DefaultTemplatesUtilities.ObjectTemplateModel { Property1 = "p1", Property2 = null }; var html = DefaultTemplatesUtilities.GetHtmlHelper(model); // Act var result = DefaultEditorTemplates.ObjectTemplate(html); // Assert Assert.Equal(expected, result); } [Fact] public void ObjectTemplateDisplaysNullDisplayTextWithNullModelAndTemplateDepthGreaterThanOne() { // Arrange var html = DefaultTemplatesUtilities.GetHtmlHelper(); var metadata = new EmptyModelMetadataProvider() .GetMetadataForType(null, typeof(DefaultTemplatesUtilities.ObjectTemplateModel)); metadata.NullDisplayText = "Null Display Text"; metadata.SimpleDisplayText = "Simple Display Text"; html.ViewData.ModelMetadata = metadata; html.ViewData.TemplateInfo.AddVisited("foo"); html.ViewData.TemplateInfo.AddVisited("bar"); // Act var result = DefaultEditorTemplates.ObjectTemplate(html); // Assert Assert.Equal(metadata.NullDisplayText, result); } [Fact] public void ObjectTemplateDisplaysSimpleDisplayTextWithNonNullModelTemplateDepthGreaterThanOne() { // Arrange var model = new DefaultTemplatesUtilities.ObjectTemplateModel(); var html = DefaultTemplatesUtilities.GetHtmlHelper(model); var metadata = new EmptyModelMetadataProvider() .GetMetadataForType(() => model, typeof(DefaultTemplatesUtilities.ObjectTemplateModel)); html.ViewData.ModelMetadata = metadata; metadata.NullDisplayText = "Null Display Text"; metadata.SimpleDisplayText = "Simple Display Text"; html.ViewData.TemplateInfo.AddVisited("foo"); html.ViewData.TemplateInfo.AddVisited("bar"); // Act var result = DefaultEditorTemplates.ObjectTemplate(html); // Assert Assert.Equal(metadata.SimpleDisplayText, result); } [Fact] public void ObjectTemplate_IgnoresPropertiesWith_ScaffoldColumnFalse() { // Arrange var expected = @"
" + Environment.NewLine + @"
" + @"
" + Environment.NewLine + @"
" + Environment.NewLine + @"
" + @"
" + Environment.NewLine; var model = new DefaultTemplatesUtilities.ObjectWithScaffoldColumn(); var viewEngine = new Mock(); viewEngine.Setup(v => v.FindPartialView(It.IsAny(), It.IsAny())) .Returns(ViewEngineResult.NotFound("", Enumerable.Empty())); var htmlHelper = DefaultTemplatesUtilities.GetHtmlHelper(model, viewEngine.Object); // Act var result = DefaultEditorTemplates.ObjectTemplate(htmlHelper); // Assert Assert.Equal(expected, result); } [Fact] public void ObjectTemplate_HonoursHideSurroundingHtml() { // Arrange var expected = "Model = p1, ModelType = System.String, PropertyName = Property1, SimpleDisplayText = p1" + "
" + Environment.NewLine + "
" + "Model = (null), ModelType = System.String, PropertyName = Property2, SimpleDisplayText = (null) " + "" + "
" + Environment.NewLine; var model = new DefaultTemplatesUtilities.ObjectTemplateModel { Property1 = "p1", Property2 = null }; var html = DefaultTemplatesUtilities.GetHtmlHelper(model); var metadata = html.ViewData.ModelMetadata.Properties.First(m => string.Equals(m.PropertyName, "Property1")); metadata.HideSurroundingHtml = true; // Act var result = DefaultEditorTemplates.ObjectTemplate(html); // Assert Assert.Equal(expected, result); } [Fact] public void HiddenInputTemplate_ReturnsValueAndHiddenInput() { // Arrange var expected = "Formatted string"; var model = "Model string"; var html = DefaultTemplatesUtilities.GetHtmlHelper(model); var templateInfo = html.ViewData.TemplateInfo; templateInfo.HtmlFieldPrefix = "FieldPrefix"; // TemplateBuilder sets FormattedModelValue before calling TemplateRenderer and it's used below. templateInfo.FormattedModelValue = "Formatted string"; // Act var result = DefaultEditorTemplates.HiddenInputTemplate(html); // Assert Assert.Equal(expected, result); } [Fact] public void HiddenInputTemplate_HonoursHideSurroundingHtml() { // Arrange var expected = ""; var model = "Model string"; var html = DefaultTemplatesUtilities.GetHtmlHelper(model); var viewData = html.ViewData; viewData.ModelMetadata.HideSurroundingHtml = true; var templateInfo = viewData.TemplateInfo; templateInfo.HtmlFieldPrefix = "FieldPrefix"; templateInfo.FormattedModelValue = "Formatted string"; // Act var result = DefaultEditorTemplates.HiddenInputTemplate(html); // Assert Assert.Equal(expected, result); } [Fact] public void Editor_FindsViewDataMember() { // Arrange var model = new DefaultTemplatesUtilities.ObjectTemplateModel { Property1 = "Model string" }; var viewEngine = new Mock(); viewEngine .Setup(v => v.FindPartialView(It.IsAny(), It.IsAny())) .Returns(ViewEngineResult.NotFound("", Enumerable.Empty())); var helper = DefaultTemplatesUtilities.GetHtmlHelper(model, viewEngine.Object); helper.ViewData["Property1"] = "ViewData string"; // Act var result = helper.Editor("Property1"); // Assert Assert.Equal( "", result.ToString()); } // DateTime-local is not special-cased unless using Html5DateRenderingMode.Rfc3339. [Theory] [InlineData("date", "{0:d}", "02/01/2000")] [InlineData("datetime", null, "02/01/2000 03:04:05 +00:00")] [InlineData("datetime-local", null, "02/01/2000 03:04:05 +00:00")] [InlineData("time", "{0:t}", "03:04")] [ReplaceCulture] public void Editor_FindsCorrectDateOrTimeTemplate(string dataTypeName, string editFormatString, string expected) { // Arrange var expectedInput = ""; var offset = TimeSpan.FromHours(0); var model = new DateTimeOffset( year: 2000, month: 1, day: 2, hour: 3, minute: 4, second: 5, millisecond: 6, offset: offset); var viewEngine = new Mock(); viewEngine .Setup(v => v.FindPartialView(It.IsAny(), It.IsAny())) .Returns(ViewEngineResult.NotFound("", Enumerable.Empty())); var helper = DefaultTemplatesUtilities.GetHtmlHelper(model, viewEngine.Object); helper.ViewData.ModelMetadata.DataTypeName = dataTypeName; helper.ViewData.ModelMetadata.EditFormatString = editFormatString; // What [DataType] does for given type. helper.ViewData.TemplateInfo.HtmlFieldPrefix = "FieldPrefix"; // Act var result = helper.Editor(""); // Assert Assert.Equal(expectedInput, result.ToString()); } [Theory] [InlineData("date", "{0:d}", "2000-01-02")] [InlineData("datetime", null, "2000-01-02T03:04:05.060+00:00")] [InlineData("datetime-local", null, "2000-01-02T03:04:05.060")] [InlineData("time", "{0:t}", "03:04:05.060")] [ReplaceCulture] public void Editor_AppliesRfc3339(string dataTypeName, string editFormatString, string expected) { // Arrange var expectedInput = ""; // Place DateTime-local value in current timezone. var offset = string.Equals("", dataTypeName) ? DateTimeOffset.Now.Offset : TimeSpan.FromHours(0); var model = new DateTimeOffset( year: 2000, month: 1, day: 2, hour: 3, minute: 4, second: 5, millisecond: 60, offset: offset); var viewEngine = new Mock(); viewEngine .Setup(v => v.FindPartialView(It.IsAny(), It.IsAny())) .Returns(ViewEngineResult.NotFound("", Enumerable.Empty())); var helper = DefaultTemplatesUtilities.GetHtmlHelper(model, viewEngine.Object); helper.Html5DateRenderingMode = Html5DateRenderingMode.Rfc3339; helper.ViewData.ModelMetadata.DataTypeName = dataTypeName; helper.ViewData.ModelMetadata.EditFormatString = editFormatString; // What [DataType] does for given type. helper.ViewData.TemplateInfo.HtmlFieldPrefix = "FieldPrefix"; // Act var result = helper.Editor(""); // Assert Assert.Equal(expectedInput, result.ToString()); } [Theory] [InlineData("date", Html5DateRenderingMode.CurrentCulture)] [InlineData("date", Html5DateRenderingMode.Rfc3339)] [InlineData("datetime", Html5DateRenderingMode.CurrentCulture)] [InlineData("datetime", Html5DateRenderingMode.Rfc3339)] [InlineData("datetime-local", Html5DateRenderingMode.CurrentCulture)] [InlineData("datetime-local", Html5DateRenderingMode.Rfc3339)] [InlineData("time", Html5DateRenderingMode.CurrentCulture)] [InlineData("time", Html5DateRenderingMode.Rfc3339)] public void Editor_AppliesNonDefaultEditFormat(string dataTypeName, Html5DateRenderingMode renderingMode) { // Arrange var expectedInput = ""; var offset = TimeSpan.FromHours(0); var model = new DateTimeOffset( year: 2000, month: 1, day: 2, hour: 3, minute: 4, second: 5, millisecond: 60, offset: offset); var viewEngine = new Mock(); viewEngine .Setup(v => v.FindPartialView(It.IsAny(), It.IsAny())) .Returns(ViewEngineResult.NotFound("", Enumerable.Empty())); var helper = DefaultTemplatesUtilities.GetHtmlHelper(model, viewEngine.Object); helper.Html5DateRenderingMode = renderingMode; // Ignored due to HasNonDefaultEditFormat. helper.ViewData.ModelMetadata.DataTypeName = dataTypeName; helper.ViewData.ModelMetadata.EditFormatString = "Formatted as {0:O}"; helper.ViewData.ModelMetadata.HasNonDefaultEditFormat = true; helper.ViewData.TemplateInfo.HtmlFieldPrefix = "FieldPrefix"; // Act var result = helper.Editor(""); // Assert Assert.Equal(expectedInput, result.ToString()); } [Fact] public void EditorFor_FindsModel() { // Arrange var model = new DefaultTemplatesUtilities.ObjectTemplateModel { Property1 = "Model string" }; var viewEngine = new Mock(); viewEngine .Setup(v => v.FindPartialView(It.IsAny(), It.IsAny())) .Returns(ViewEngineResult.NotFound("", Enumerable.Empty())); var helper = DefaultTemplatesUtilities.GetHtmlHelper(model, viewEngine.Object); helper.ViewData["Property1"] = "ViewData string"; // Act var result = helper.EditorFor(m => m.Property1); // Assert Assert.Equal( "", result.ToString()); } [Fact] public void Editor_FindsModel_IfNoViewDataMember() { // Arrange var model = new DefaultTemplatesUtilities.ObjectTemplateModel { Property1 = "Model string" }; var viewEngine = new Mock(); viewEngine .Setup(v => v.FindPartialView(It.IsAny(), It.IsAny())) .Returns(ViewEngineResult.NotFound("", Enumerable.Empty())); var helper = DefaultTemplatesUtilities.GetHtmlHelper(model, viewEngine.Object); // Act var result = helper.Editor("Property1"); // Assert Assert.Equal( "", result.ToString()); } [Theory] [InlineData(null)] [InlineData("")] public void EditorFor_FindsModel_EvenIfNullOrEmpty(string propertyValue) { // Arrange var model = new DefaultTemplatesUtilities.ObjectTemplateModel { Property1 = propertyValue, }; var viewEngine = new Mock(); viewEngine .Setup(v => v.FindPartialView(It.IsAny(), It.IsAny())) .Returns(ViewEngineResult.NotFound("", Enumerable.Empty())); var helper = DefaultTemplatesUtilities.GetHtmlHelper(model, viewEngine.Object); helper.ViewData["Property1"] = "ViewData string"; // Act var result = helper.EditorFor(m => m.Property1); // Assert Assert.Equal( "", result.ToString()); } [Fact] public void EditorFor_DoesNotWrapExceptionThrowsDuringViewRendering() { // Arrange var expectedMessage = "my exception message"; var model = new DefaultTemplatesUtilities.ObjectTemplateModel { Property1 = "Test string", }; var view = new Mock(); view.Setup(v => v.RenderAsync(It.IsAny())) .Returns(Task.Run(() => { throw new FormatException(expectedMessage); })); var viewEngine = new Mock(); viewEngine .Setup(v => v.FindPartialView(It.IsAny(), It.IsAny())) .Returns(ViewEngineResult.Found("test-view", view.Object)); var helper = DefaultTemplatesUtilities.GetHtmlHelper(model, viewEngine.Object); helper.ViewData["Property1"] = "ViewData string"; // Act and Assert var ex = Assert.Throws(() => helper.EditorFor(m => m.Property1)); Assert.Equal(expectedMessage, ex.Message); } } }