diff --git a/test/Microsoft.AspNetCore.Mvc.ViewFeatures.Test/Rendering/HtmlHelperDisplayExtensionsTest.cs b/test/Microsoft.AspNetCore.Mvc.ViewFeatures.Test/Rendering/HtmlHelperDisplayExtensionsTest.cs new file mode 100644 index 0000000000..d1c294c1e8 --- /dev/null +++ b/test/Microsoft.AspNetCore.Mvc.ViewFeatures.Test/Rendering/HtmlHelperDisplayExtensionsTest.cs @@ -0,0 +1,360 @@ +// Copyright (c) .NET Foundation. 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.AspNetCore.Mvc.TestCommon; +using Microsoft.AspNetCore.Mvc.ViewEngines; +using Moq; +using Xunit; + +namespace Microsoft.AspNetCore.Mvc.Rendering +{ + public class HtmlHelperDisplayExtensionsTest + { + [Fact] + public void DisplayHelpers_FindsModel_WhenViewDataIsNotSet() + { + // Arrange + var expected = $"
HtmlEncode[[SomeProperty]]
{Environment.NewLine}" + + $"
HtmlEncode[[PropValue]]
{Environment.NewLine}"; + var model = new SomeModel + { + SomeProperty = "PropValue" + }; + var viewEngine = new Mock(MockBehavior.Strict); + viewEngine + .Setup(v => v.GetView(/*executingFilePath*/ null, It.IsAny(), /*isMainPage*/ false)) + .Returns(ViewEngineResult.NotFound(string.Empty, Enumerable.Empty())); + viewEngine + .Setup(v => v.FindView(It.IsAny(), It.IsAny(), /*isMainPage*/ false)) + .Returns(ViewEngineResult.NotFound(string.Empty, Enumerable.Empty())); + var helper = DefaultTemplatesUtilities.GetHtmlHelper(model, viewEngine.Object); + + // Act + var displayResult = helper.Display(expression: string.Empty); + var displayNullResult = helper.Display(expression: null); // null is another alias for current model + var displayForResult = helper.DisplayFor(m => m); + var displayForModelResult = helper.DisplayForModel(); + + // Assert + Assert.Equal(expected, HtmlContentUtilities.HtmlContentToString(displayResult)); + Assert.Equal(expected, HtmlContentUtilities.HtmlContentToString(displayNullResult)); + Assert.Equal(expected, HtmlContentUtilities.HtmlContentToString(displayForResult)); + Assert.Equal(expected, HtmlContentUtilities.HtmlContentToString(displayForModelResult)); + } + + [Fact] + public void Display_UsesAdditionalViewData() + { + // Arrange + var model = new SomeModel { SomeProperty = "ModelValue" }; + var view = new Mock(); + view.Setup(v => v.RenderAsync(It.IsAny())) + .Callback((ViewContext v) => v.Writer.WriteAsync(v.ViewData["SomeProperty"].ToString())) + .Returns(Task.FromResult(0)); + var viewEngine = new Mock(MockBehavior.Strict); + viewEngine + .Setup(v => v.GetView(/*executingFilePath*/ null, It.IsAny(), /*isMainPage*/ false)) + .Returns(ViewEngineResult.NotFound(string.Empty, Enumerable.Empty())); + viewEngine + .Setup(v => v.FindView(It.IsAny(), It.IsAny(), /*isMainPage*/ false)) + .Returns(ViewEngineResult.Found("SomeView", view.Object)); + var helper = DefaultTemplatesUtilities.GetHtmlHelper(model, viewEngine.Object); + + // Act + var displayResult = helper.Display(expression: "SomeProperty", additionalViewData: new { SomeProperty = "ViewDataValue" }); + + // Assert + Assert.Equal("ViewDataValue", HtmlContentUtilities.HtmlContentToString(displayResult)); + } + + [Fact] + public void Display_UsesTemplateName() + { + // Arrange + var model = new SomeModel { SomeProperty = "ModelValue" }; + var viewEngine = new Mock(MockBehavior.Strict); + viewEngine + .Setup(v => v.GetView(/*executingFilePath*/ null, It.IsAny(), /*isMainPage*/ false)) + .Returns(ViewEngineResult.NotFound(string.Empty, Enumerable.Empty())); + viewEngine + .Setup(v => v.FindView(It.IsAny(), "DisplayTemplates/SomeTemplate", /*isMainPage*/ false)) + .Returns(ViewEngineResult.Found("SomeView", Mock.Of())) + .Verifiable(); + var helper = DefaultTemplatesUtilities.GetHtmlHelper(model, viewEngine.Object); + + // Act + var displayResult = helper.Display(expression: "SomeProperty", templateName: "SomeTemplate"); + + // Assert + viewEngine.Verify(); + } + + [Fact] + public void Display_UsesTemplateNameAndAdditionalViewData() + { + // Arrange + var model = new SomeModel { SomeProperty = "ModelValue" }; + var view = new Mock(); + view.Setup(v => v.RenderAsync(It.IsAny())) + .Callback((ViewContext v) => v.Writer.WriteAsync(v.ViewData["SomeProperty"].ToString())) + .Returns(Task.FromResult(0)); + var viewEngine = new Mock(MockBehavior.Strict); + viewEngine + .Setup(v => v.GetView(/*executingFilePath*/ null, It.IsAny(), /*isMainPage*/ false)) + .Returns(ViewEngineResult.NotFound(string.Empty, Enumerable.Empty())); + viewEngine + .Setup(v => v.FindView(It.IsAny(), "DisplayTemplates/SomeTemplate", /*isMainPage*/ false)) + .Returns(ViewEngineResult.Found("SomeView", view.Object)); + var helper = DefaultTemplatesUtilities.GetHtmlHelper(model, viewEngine.Object); + + // Act + var displayResult = helper.Display( + expression: "SomeProperty", + templateName: "SomeTemplate", + additionalViewData: new { SomeProperty = "ViewDataValue" }); + + // Assert + Assert.Equal("ViewDataValue", HtmlContentUtilities.HtmlContentToString(displayResult)); + } + + [Fact] + public void Display_UsesTemplateNameAndHtmlFieldName() + { + // Arrange + var model = new SomeModel { SomeProperty = "ModelValue" }; + var view = new Mock(); + view.Setup(v => v.RenderAsync(It.IsAny())) + .Callback((ViewContext v) => v.Writer.WriteAsync(v.ViewData.TemplateInfo.HtmlFieldPrefix)) + .Returns(Task.FromResult(0)); + var viewEngine = new Mock(MockBehavior.Strict); + viewEngine + .Setup(v => v.GetView(/*executingFilePath*/ null, It.IsAny(), /*isMainPage*/ false)) + .Returns(ViewEngineResult.NotFound(string.Empty, Enumerable.Empty())); + viewEngine + .Setup(v => v.FindView(It.IsAny(), "DisplayTemplates/SomeTemplate", /*isMainPage*/ false)) + .Returns(ViewEngineResult.Found("SomeView", view.Object)); + var helper = DefaultTemplatesUtilities.GetHtmlHelper(model, viewEngine.Object); + + // Act + var displayResult = helper.Display( + expression: "SomeProperty", + templateName: "SomeTemplate", + htmlFieldName: "SomeField"); + + // Assert + Assert.Equal("SomeField", HtmlContentUtilities.HtmlContentToString(displayResult)); + } + + [Fact] + public void DisplayFor_UsesAdditionalViewData() + { + // Arrange + var model = new SomeModel { SomeProperty = "ModelValue" }; + var view = new Mock(); + view.Setup(v => v.RenderAsync(It.IsAny())) + .Callback((ViewContext v) => v.Writer.WriteAsync(v.ViewData["SomeProperty"].ToString())) + .Returns(Task.FromResult(0)); + var viewEngine = new Mock(MockBehavior.Strict); + viewEngine + .Setup(v => v.GetView(/*executingFilePath*/ null, It.IsAny(), /*isMainPage*/ false)) + .Returns(ViewEngineResult.NotFound(string.Empty, Enumerable.Empty())); + viewEngine + .Setup(v => v.FindView(It.IsAny(), It.IsAny(), /*isMainPage*/ false)) + .Returns(ViewEngineResult.Found("SomeView", view.Object)); + var helper = DefaultTemplatesUtilities.GetHtmlHelper(model, viewEngine.Object); + + // Act + var displayResult = helper.DisplayFor(expression: m => m.SomeProperty, additionalViewData: new { SomeProperty = "ViewDataValue" }); + + // Assert + Assert.Equal("ViewDataValue", HtmlContentUtilities.HtmlContentToString(displayResult)); + } + + [Fact] + public void DisplayFor_UsesTemplateName() + { + // Arrange + var model = new SomeModel { SomeProperty = "ModelValue" }; + var viewEngine = new Mock(MockBehavior.Strict); + viewEngine + .Setup(v => v.GetView(/*executingFilePath*/ null, It.IsAny(), /*isMainPage*/ false)) + .Returns(ViewEngineResult.NotFound(string.Empty, Enumerable.Empty())); + viewEngine + .Setup(v => v.FindView(It.IsAny(), "DisplayTemplates/SomeTemplate", /*isMainPage*/ false)) + .Returns(ViewEngineResult.Found("SomeView", Mock.Of())) + .Verifiable(); + var helper = DefaultTemplatesUtilities.GetHtmlHelper(model, viewEngine.Object); + + // Act + var displayResult = helper.DisplayFor(expression: m => m.SomeProperty, templateName: "SomeTemplate"); + + // Assert + viewEngine.Verify(); + } + + [Fact] + public void DisplayFor_UsesTemplateNameAndAdditionalViewData() + { + // Arrange + var model = new SomeModel { SomeProperty = "ModelValue" }; + var view = new Mock(); + view.Setup(v => v.RenderAsync(It.IsAny())) + .Callback((ViewContext v) => v.Writer.WriteAsync(v.ViewData["SomeProperty"].ToString())) + .Returns(Task.FromResult(0)); + var viewEngine = new Mock(MockBehavior.Strict); + viewEngine + .Setup(v => v.GetView(/*executingFilePath*/ null, It.IsAny(), /*isMainPage*/ false)) + .Returns(ViewEngineResult.NotFound(string.Empty, Enumerable.Empty())); + viewEngine + .Setup(v => v.FindView(It.IsAny(), "DisplayTemplates/SomeTemplate", /*isMainPage*/ false)) + .Returns(ViewEngineResult.Found("SomeView", view.Object)); + var helper = DefaultTemplatesUtilities.GetHtmlHelper(model, viewEngine.Object); + + // Act + var displayResult = helper.DisplayFor( + expression: m => m.SomeProperty, + templateName: "SomeTemplate", + additionalViewData: new { SomeProperty = "ViewDataValue" }); + + // Assert + Assert.Equal("ViewDataValue", HtmlContentUtilities.HtmlContentToString(displayResult)); + } + + [Fact] + public void DisplayFor_UsesTemplateNameAndHtmlFieldName() + { + // Arrange + var model = new SomeModel { SomeProperty = "ModelValue" }; + var view = new Mock(); + view.Setup(v => v.RenderAsync(It.IsAny())) + .Callback((ViewContext v) => v.Writer.WriteAsync(v.ViewData.TemplateInfo.HtmlFieldPrefix)) + .Returns(Task.FromResult(0)); + var viewEngine = new Mock(MockBehavior.Strict); + viewEngine + .Setup(v => v.GetView(/*executingFilePath*/ null, It.IsAny(), /*isMainPage*/ false)) + .Returns(ViewEngineResult.NotFound(string.Empty, Enumerable.Empty())); + viewEngine + .Setup(v => v.FindView(It.IsAny(), "DisplayTemplates/SomeTemplate", /*isMainPage*/ false)) + .Returns(ViewEngineResult.Found("SomeView", view.Object)); + var helper = DefaultTemplatesUtilities.GetHtmlHelper(model, viewEngine.Object); + + // Act + var displayResult = helper.DisplayFor( + expression: m => m.SomeProperty, + templateName: "SomeTemplate", + htmlFieldName: "SomeField"); + + // Assert + Assert.Equal("SomeField", HtmlContentUtilities.HtmlContentToString(displayResult)); + } + + [Fact] + public void DisplayForModel_UsesAdditionalViewData() + { + // Arrange + var model = new SomeModel { SomeProperty = "ModelValue" }; + var view = new Mock(); + view.Setup(v => v.RenderAsync(It.IsAny())) + .Callback((ViewContext v) => v.Writer.WriteAsync(v.ViewData["SomeProperty"].ToString())) + .Returns(Task.FromResult(0)); + var viewEngine = new Mock(MockBehavior.Strict); + viewEngine + .Setup(v => v.GetView(/*executingFilePath*/ null, It.IsAny(), /*isMainPage*/ false)) + .Returns(ViewEngineResult.NotFound(string.Empty, Enumerable.Empty())); + viewEngine + .Setup(v => v.FindView(It.IsAny(), It.IsAny(), /*isMainPage*/ false)) + .Returns(ViewEngineResult.Found("SomeView", view.Object)); + var helper = DefaultTemplatesUtilities.GetHtmlHelper(model, viewEngine.Object); + + // Act + var displayResult = helper.DisplayForModel(additionalViewData: new { SomeProperty = "ViewDataValue" }); + + // Assert + Assert.Equal("ViewDataValue", HtmlContentUtilities.HtmlContentToString(displayResult)); + } + + [Fact] + public void DisplayForModel_UsesTemplateName() + { + // Arrange + var model = new SomeModel { SomeProperty = "ModelValue" }; + var viewEngine = new Mock(MockBehavior.Strict); + viewEngine + .Setup(v => v.GetView(/*executingFilePath*/ null, It.IsAny(), /*isMainPage*/ false)) + .Returns(ViewEngineResult.NotFound(string.Empty, Enumerable.Empty())); + viewEngine + .Setup(v => v.FindView(It.IsAny(), "DisplayTemplates/SomeTemplate", /*isMainPage*/ false)) + .Returns(ViewEngineResult.Found("SomeView", Mock.Of())) + .Verifiable(); + var helper = DefaultTemplatesUtilities.GetHtmlHelper(model, viewEngine.Object); + + // Act + var displayResult = helper.DisplayForModel(templateName: "SomeTemplate"); + + // Assert + viewEngine.Verify(); + } + + [Fact] + public void DisplayForModel_UsesTemplateNameAndAdditionalViewData() + { + // Arrange + var model = new SomeModel { SomeProperty = "ModelValue" }; + var view = new Mock(); + view.Setup(v => v.RenderAsync(It.IsAny())) + .Callback((ViewContext v) => v.Writer.WriteAsync(v.ViewData["SomeProperty"].ToString())) + .Returns(Task.FromResult(0)); + var viewEngine = new Mock(MockBehavior.Strict); + viewEngine + .Setup(v => v.GetView(/*executingFilePath*/ null, It.IsAny(), /*isMainPage*/ false)) + .Returns(ViewEngineResult.NotFound(string.Empty, Enumerable.Empty())); + viewEngine + .Setup(v => v.FindView(It.IsAny(), "DisplayTemplates/SomeTemplate", /*isMainPage*/ false)) + .Returns(ViewEngineResult.Found("SomeView", view.Object)); + var helper = DefaultTemplatesUtilities.GetHtmlHelper(model, viewEngine.Object); + + // Act + var displayResult = helper.DisplayForModel( + templateName: "SomeTemplate", + additionalViewData: new { SomeProperty = "ViewDataValue" }); + + // Assert + Assert.Equal("ViewDataValue", HtmlContentUtilities.HtmlContentToString(displayResult)); + } + + [Fact] + public void DisplayForModel_UsesTemplateNameAndHtmlFieldName() + { + // Arrange + var model = new SomeModel { SomeProperty = "ModelValue" }; + var view = new Mock(); + view.Setup(v => v.RenderAsync(It.IsAny())) + .Callback((ViewContext v) => v.Writer.WriteAsync(v.ViewData.TemplateInfo.HtmlFieldPrefix)) + .Returns(Task.FromResult(0)); + var viewEngine = new Mock(MockBehavior.Strict); + viewEngine + .Setup(v => v.GetView(/*executingFilePath*/ null, It.IsAny(), /*isMainPage*/ false)) + .Returns(ViewEngineResult.NotFound(string.Empty, Enumerable.Empty())); + viewEngine + .Setup(v => v.FindView(It.IsAny(), "DisplayTemplates/SomeTemplate", /*isMainPage*/ false)) + .Returns(ViewEngineResult.Found("SomeView", view.Object)); + var helper = DefaultTemplatesUtilities.GetHtmlHelper(model, viewEngine.Object); + + // Act + var displayResult = helper.DisplayForModel( + templateName: "SomeTemplate", + htmlFieldName: "SomeField"); + + // Assert + Assert.Equal("SomeField", HtmlContentUtilities.HtmlContentToString(displayResult)); + } + + private class SomeModel + { + public string SomeProperty { get; set; } + } + } +} diff --git a/test/Microsoft.AspNetCore.Mvc.ViewFeatures.Test/Rendering/HtmlHelperPasswordTest.cs b/test/Microsoft.AspNetCore.Mvc.ViewFeatures.Test/Rendering/HtmlHelperPasswordTest.cs index 41a3a9654f..96a3e2edc9 100644 --- a/test/Microsoft.AspNetCore.Mvc.ViewFeatures.Test/Rendering/HtmlHelperPasswordTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.ViewFeatures.Test/Rendering/HtmlHelperPasswordTest.cs @@ -439,6 +439,61 @@ namespace Microsoft.AspNetCore.Mvc.Rendering return viewData; } + public static TheoryData PasswordFor_IgnoresExpressionValueForComplexExpressionsData + { + get + { + return new TheoryData>, string> + { + { + model => model.Property3["key"], + @"" + }, + { + model => model.Property4.Property5, + @"" + }, + { + model => model.Property4.Property6[0], + @"" + } + }; + } + } + + [Theory] + [MemberData(nameof(PasswordFor_IgnoresExpressionValueForComplexExpressionsData))] + public void PasswordFor_ComplexExpressions_IgnoresValueFromViewDataModelStateAndModel( + Expression> expression, + string expected) + { + // Arrange + var model = new PasswordModel(); + var helper = DefaultTemplatesUtilities.GetHtmlHelper(model); + helper.ViewData.TemplateInfo.HtmlFieldPrefix = "pre"; + + helper.ViewData.ModelState.SetModelValue("pre.Property3[key]", "MProp3Val", "MProp3Val"); + helper.ViewData.ModelState.SetModelValue("pre.Property4.Property5", "MProp5Val", "MProp5Val"); + helper.ViewData.ModelState.SetModelValue("pre.Property4.Property6[0]", "MProp6Val", "MProp6Val"); + + helper.ViewData["pre.Property3[key]"] = "VDProp3Val"; + helper.ViewData["pre.Property4.Property5"] = "VDProp5Val"; + helper.ViewData["pre.Property4.Property6"] = "VDProp6Val"; + + helper.ViewData.Model.Property3["key"] = "Prop3Val"; + helper.ViewData.Model.Property4.Property5 = "Prop5Val"; + helper.ViewData.Model.Property4.Property6.Add("Prop6Val"); + + // Act + var result = helper.PasswordFor(expression); + + // Assert + Assert.Equal(expected, HtmlContentUtilities.HtmlContentToString(result)); + } + public class PasswordModel { public string Property1 { get; set; } diff --git a/test/Microsoft.AspNetCore.Mvc.ViewFeatures.Test/Rendering/HtmlHelperTest.cs b/test/Microsoft.AspNetCore.Mvc.ViewFeatures.Test/Rendering/HtmlHelperTest.cs index 5b89516068..180dea3415 100644 --- a/test/Microsoft.AspNetCore.Mvc.ViewFeatures.Test/Rendering/HtmlHelperTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.ViewFeatures.Test/Rendering/HtmlHelperTest.cs @@ -286,6 +286,53 @@ namespace Microsoft.AspNetCore.Mvc.Rendering Assert.Equal(expectedString, result.ToString()); } + [Theory] + [InlineData("SomeName", "SomeName")] + [InlineData("Obj1.Prop1", "Obj1_Prop1")] + [InlineData("Obj1.Prop1[0]", "Obj1_Prop1_0_")] + [InlineData("Obj1.Prop1[0].Prop2", "Obj1_Prop1_0__Prop2")] + public void GenerateIdFromName_ReturnsExpectedValues(string fullname, string expected) + { + // Arrange + var helper = DefaultTemplatesUtilities.GetHtmlHelper(); + + // Act + var result = helper.GenerateIdFromName(fullname); + + // Assert + Assert.Equal(expected, result); + } + + [Theory] + [InlineData(FormMethod.Get, "get")] + [InlineData(FormMethod.Post, "post")] + [InlineData((FormMethod)42, "post")] + public void GetFormMethodString_ReturnsExpectedValues(FormMethod method, string expected) + { + // Act + var result = HtmlHelper.GetFormMethodString(method); + + // Assert + Assert.Equal(expected, result); + } + + [Theory] + [InlineData("-{0}-", "-boldFromObject-")] + [InlineData("-%{0}%-", "-%boldFromObject%-")] + [InlineData("-=={0}=={0}==-", "-==boldFromObject==boldFromObject==-")] + public void FormatValue_ReturnsExpectedValues(string format, string expected) + { + // Arrange + var value = new ObjectWithToStringOverride(); + var helper = DefaultTemplatesUtilities.GetHtmlHelper(); + + // Act + var result = helper.FormatValue(value, format); + + // Assert + Assert.Equal(expected, result); + } + private class ObjectWithToStringOverride { public override string ToString() diff --git a/test/Microsoft.AspNetCore.Mvc.ViewFeatures.Test/Rendering/HtmlHelperTextAreaTest.cs b/test/Microsoft.AspNetCore.Mvc.ViewFeatures.Test/Rendering/HtmlHelperTextAreaTest.cs index e9014ad9a8..a00633e372 100644 --- a/test/Microsoft.AspNetCore.Mvc.ViewFeatures.Test/Rendering/HtmlHelperTextAreaTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.ViewFeatures.Test/Rendering/HtmlHelperTextAreaTest.cs @@ -2,13 +2,15 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using System.Collections.Generic; using System.ComponentModel.DataAnnotations; +using System.Linq.Expressions; using Microsoft.AspNetCore.Mvc.TestCommon; using Xunit; namespace Microsoft.AspNetCore.Mvc.Rendering { - public class HtmlHelperTextBoxAreaTest + public class HtmlHelperTextAreaTest { [Fact] public void TextAreaFor_GeneratesPlaceholderAttribute_WhenDisplayAttributePromptIsSetAndTypeIsValid() @@ -40,6 +42,125 @@ namespace Microsoft.AspNetCore.Mvc.Rendering Assert.DoesNotContain(@"placeholder=""HtmlEncode[[placeholder]]""", result, StringComparison.Ordinal); } + public static TheoryData TextAreaFor_UsesModelValueForComplexExpressionsData + { + get + { + return new TheoryData>, string> + { + { + model => model.Property3["key"], + "" + }, + { + model => model.Property4.Property5, + "" + }, + { + model => model.Property4.Property6[0], + "" + } + }; + } + } + + [Theory] + [MemberData(nameof(TextAreaFor_UsesModelValueForComplexExpressionsData))] + public void TextAreaFor_ComplexExpressions_UsesModelValueForComplexExpressions( + Expression> expression, + string expected) + { + // Arrange + var model = new ComplexModel(); + var helper = DefaultTemplatesUtilities.GetHtmlHelper(model); + helper.ViewData.TemplateInfo.HtmlFieldPrefix = "pre"; + + helper.ViewData.Model.Property3["key"] = "Prop3Val"; + helper.ViewData.Model.Property4.Property5 = "Prop5Val"; + helper.ViewData.Model.Property4.Property6.Add("Prop6Val"); + + // Act + var result = helper.TextAreaFor(expression); + + // Assert + Assert.Equal(expected, HtmlContentUtilities.HtmlContentToString(result)); + } + + public static TheoryData TextAreaFor_UsesModelStateValueForComplexExpressionsData + { + get + { + return new TheoryData>, string> + { + { + model => model.Property3["key"], + "" + }, + { + model => model.Property4.Property5, + "" + }, + { + model => model.Property4.Property6[0], + "" + } + }; + } + } + + [Theory] + [MemberData(nameof(TextAreaFor_UsesModelStateValueForComplexExpressionsData))] + public void TextAreaFor_ComplexExpressions_UsesModelStateValueForComplexExpressions( + Expression> expression, + string expected) + { + // Arrange + var model = new ComplexModel(); + var helper = DefaultTemplatesUtilities.GetHtmlHelper(model); + helper.ViewData.TemplateInfo.HtmlFieldPrefix = "pre"; + + helper.ViewData.ModelState.SetModelValue("pre.Property3[key]", "MProp3Val", "MProp3Val"); + helper.ViewData.ModelState.SetModelValue("pre.Property4.Property5", "MProp5Val", "MProp5Val"); + helper.ViewData.ModelState.SetModelValue("pre.Property4.Property6[0]", "MProp6Val", "MProp6Val"); + + helper.ViewData.Model.Property3["key"] = "Prop3Val"; + helper.ViewData.Model.Property4.Property5 = "Prop5Val"; + helper.ViewData.Model.Property4.Property6.Add("Prop6Val"); + + // Act + var result = helper.TextAreaFor(expression); + + // Assert + Assert.Equal(expected, HtmlContentUtilities.HtmlContentToString(result)); + } + + public class ComplexModel + { + public string Property1 { get; set; } + + public byte[] Bytes { get; set; } + + [Required] + public string Property2 { get; set; } + + public Dictionary Property3 { get; } = new Dictionary(); + + public NestedClass Property4 { get; } = new NestedClass(); + } + + public class NestedClass + { + public string Property5 { get; set; } + + public List Property6 { get; } = new List(); + } + private class TextAreaModelWithAPlaceholder { [Display(Prompt = "placeholder")] diff --git a/test/Microsoft.AspNetCore.Mvc.ViewFeatures.Test/Rendering/HtmlHelperTextBoxTest.cs b/test/Microsoft.AspNetCore.Mvc.ViewFeatures.Test/Rendering/HtmlHelperTextBoxTest.cs index d2568dcbc1..e7dac3c03a 100644 --- a/test/Microsoft.AspNetCore.Mvc.ViewFeatures.Test/Rendering/HtmlHelperTextBoxTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.ViewFeatures.Test/Rendering/HtmlHelperTextBoxTest.cs @@ -2,7 +2,9 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using System.Collections.Generic; using System.ComponentModel.DataAnnotations; +using System.Linq.Expressions; using Microsoft.AspNetCore.Mvc.TestCommon; using Xunit; @@ -58,6 +60,125 @@ namespace Microsoft.AspNetCore.Mvc.Rendering Assert.DoesNotContain(@"placeholder=""HtmlEncode[[placeholder]]""", result, StringComparison.Ordinal); } + public static TheoryData TextBoxFor_UsesModelValueForComplexExpressionsData + { + get + { + return new TheoryData>, string> + { + { + model => model.Property3["key"], + @"" + }, + { + model => model.Property4.Property5, + @"" + }, + { + model => model.Property4.Property6[0], + @"" + } + }; + } + } + + [Theory] + [MemberData(nameof(TextBoxFor_UsesModelValueForComplexExpressionsData))] + public void TextBoxFor_ComplexExpressions_UsesModelValueForComplexExpressions( + Expression> expression, + string expected) + { + // Arrange + var model = new ComplexModel(); + var helper = DefaultTemplatesUtilities.GetHtmlHelper(model); + helper.ViewData.TemplateInfo.HtmlFieldPrefix = "pre"; + + helper.ViewData.Model.Property3["key"] = "Prop3Val"; + helper.ViewData.Model.Property4.Property5 = "Prop5Val"; + helper.ViewData.Model.Property4.Property6.Add("Prop6Val"); + + // Act + var result = helper.TextBoxFor(expression); + + // Assert + Assert.Equal(expected, HtmlContentUtilities.HtmlContentToString(result)); + } + + public static TheoryData TextBoxFor_UsesModelStateValueForComplexExpressionsData + { + get + { + return new TheoryData>, string> + { + { + model => model.Property3["key"], + @"" + }, + { + model => model.Property4.Property5, + @"" + }, + { + model => model.Property4.Property6[0], + @"" + } + }; + } + } + + [Theory] + [MemberData(nameof(TextBoxFor_UsesModelStateValueForComplexExpressionsData))] + public void TextBoxFor_ComplexExpressions_UsesModelStateValueForComplexExpressions( + Expression> expression, + string expected) + { + // Arrange + var model = new ComplexModel(); + var helper = DefaultTemplatesUtilities.GetHtmlHelper(model); + helper.ViewData.TemplateInfo.HtmlFieldPrefix = "pre"; + + helper.ViewData.ModelState.SetModelValue("pre.Property3[key]", "MProp3Val", "MProp3Val"); + helper.ViewData.ModelState.SetModelValue("pre.Property4.Property5", "MProp5Val", "MProp5Val"); + helper.ViewData.ModelState.SetModelValue("pre.Property4.Property6[0]", "MProp6Val", "MProp6Val"); + + helper.ViewData.Model.Property3["key"] = "Prop3Val"; + helper.ViewData.Model.Property4.Property5 = "Prop5Val"; + helper.ViewData.Model.Property4.Property6.Add("Prop6Val"); + + // Act + var result = helper.TextBoxFor(expression); + + // Assert + Assert.Equal(expected, HtmlContentUtilities.HtmlContentToString(result)); + } + + public class ComplexModel + { + public string Property1 { get; set; } + + public byte[] Bytes { get; set; } + + [Required] + public string Property2 { get; set; } + + public Dictionary Property3 { get; } = new Dictionary(); + + public NestedClass Property4 { get; } = new NestedClass(); + } + + public class NestedClass + { + public string Property5 { get; set; } + + public List Property6 { get; } = new List(); + } + private class TextBoxModel { [Display(Prompt = "placeholder")] diff --git a/test/Microsoft.AspNetCore.Mvc.ViewFeatures.Test/Rendering/HtmlHelperValueExtensionsTest.cs b/test/Microsoft.AspNetCore.Mvc.ViewFeatures.Test/Rendering/HtmlHelperValueExtensionsTest.cs new file mode 100644 index 0000000000..f1776922a9 --- /dev/null +++ b/test/Microsoft.AspNetCore.Mvc.ViewFeatures.Test/Rendering/HtmlHelperValueExtensionsTest.cs @@ -0,0 +1,77 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using Xunit; + +namespace Microsoft.AspNetCore.Mvc.Rendering +{ + public class HtmlHelperValueExtensionsTest + { + [Fact] + public void Value_ReturnsModelValue() + { + // Arrange + var model = new SomeModel { SomeProperty = "ModelValue" }; + var helper = DefaultTemplatesUtilities.GetHtmlHelper(model); + + // Act + var result = helper.Value("SomeProperty"); + + // Assert + Assert.Equal("ModelValue", result); + } + + [Fact] + public void ValueFor_ReturnsModelValue() + { + // Arrange + var model = new SomeModel { SomeProperty = "ModelValue" }; + var helper = DefaultTemplatesUtilities.GetHtmlHelper(model); + + // Act + var result = helper.ValueFor(m => m.SomeProperty); + + // Assert + Assert.Equal("ModelValue", result); + } + + [Fact] + public void ValueForModel_ReturnsModelValue() + { + // Arrange + var model = new SomeModel { SomeProperty = "ModelValue" }; + var helper = DefaultTemplatesUtilities.GetHtmlHelper(model); + + // Act + var result = helper.ValueForModel(); + + // Assert + Assert.Equal("{ SomeProperty = ModelValue }", result); + } + + [Fact] + public void ValueForModel_ReturnsModelValueWithSpecificFormat() + { + // Arrange + var model = new SomeModel { SomeProperty = "ModelValue" }; + var helper = DefaultTemplatesUtilities.GetHtmlHelper(model); + + // Act + var result = helper.ValueForModel(format: "-{0}-"); + + // Assert + Assert.Equal("-{ SomeProperty = ModelValue }-", result); + } + + private class SomeModel + { + public string SomeProperty { get; set; } + + public override string ToString() + { + return string.Format( + "{{ SomeProperty = {0} }}", SomeProperty ?? "(null)"); + } + } + } +}