Demonstrate #1485, #1487, #2662, #2664 in functional and unit tests

- test additional cases _close_ to these bugs as well

for #1485
- show odd `@Html.CheckBox()`, `@Html.Hidden()` behaviour in unit tests
- show odd `@Html.TextBox()` behaviour in functional tests (templates)

for #1487
- show odd `@Html.Value()` behaviour in unit tests
- show odd `@Html.RadioButton()`, `@Html.TextArea()` behaviour in functional tests
- show lack of validation attributes for `@Html.RadioButton()`, `<select>` tag helper

for #2662
- show odd `@Html.RadioButton(string.Empty)` behaviour in functional tests

for #2664
- show failures with `@Html.ListBox()` in unit tests

nits:
- test `IHtmlHelper` methods, not extensions
- use `ViewData`, not `ViewBag` in `HtmlGeneration_FormController`
- name test methods a bit more consistently
- rename `HtmlHelperValueExtensionsTest` to `HtmlHelperValueTest`
This commit is contained in:
Doug Bunting 2015-06-07 22:45:53 -07:00
parent 37d1881dad
commit afd5b4f2a6
10 changed files with 953 additions and 72 deletions

View File

@ -85,11 +85,11 @@ namespace Microsoft.AspNet.Mvc.Rendering
}
[Fact]
public void CheckBoxCheckedWithOnlyName()
public void CheckBoxCheckedWithOnlyName_GeneratesExpectedValue()
{
// Arrange
var expected =
@"<input checked=""HtmlEncode[[checked]]"" data-val=""HtmlEncode[[true]]"" " +
@"<input checked=""HtmlEncode[[checked]]"" data-val=""HtmlEncode[[true]]"" " +
@"data-val-required=""HtmlEncode[[The Boolean field is required.]]"" id=""HtmlEncode[[Property1]]"" " +
@"name=""HtmlEncode[[Property1]]"" type=""HtmlEncode[[checkbox]]"" " +
@"value=""HtmlEncode[[true]]"" /><input name=""HtmlEncode[[Property1]]"" type=""HtmlEncode[[hidden]]"" value=""HtmlEncode[[false]]"" />";
@ -121,6 +121,170 @@ namespace Microsoft.AspNet.Mvc.Rendering
Assert.Equal(expected, html.ToString());
}
[Fact]
public void CheckBoxNotInTemplate_GetsValueFromViewDataDictionary()
{
// Arrange
var expected =
@"<input checked=""HtmlEncode[[checked]]"" id=""HtmlEncode[[Property1]]"" " +
@"name=""HtmlEncode[[Property1]]"" type=""HtmlEncode[[checkbox]]"" value=""HtmlEncode[[true]]"" />" +
@"<input name=""HtmlEncode[[Property1]]"" type=""HtmlEncode[[hidden]]"" value=""HtmlEncode[[false]]"" />";
var helper = DefaultTemplatesUtilities.GetHtmlHelper(GetTestModelViewData());
helper.ViewContext.ClientValidationEnabled = false;
helper.ViewData.Model = new TestModel();
// Act
var html = helper.CheckBox("Property1", isChecked: null, htmlAttributes: null);
// Assert
Assert.Equal(expected, html.ToString());
}
[Fact]
public void CheckBoxInTemplate_GetsValueFromViewDataDictionary()
{
// Arrange
var expected =
@"<input checked=""HtmlEncode[[checked]]"" id=""HtmlEncode[[Prefix_Property1]]"" " +
@"name=""HtmlEncode[[Prefix.Property1]]"" type=""HtmlEncode[[checkbox]]"" value=""HtmlEncode[[true]]"" />" +
@"<input name=""HtmlEncode[[Prefix.Property1]]"" type=""HtmlEncode[[hidden]]"" value=""HtmlEncode[[false]]"" />";
var helper = DefaultTemplatesUtilities.GetHtmlHelper(GetTestModelViewData());
helper.ViewContext.ClientValidationEnabled = false;
helper.ViewData.Remove(nameof(TestModel.Property1));
helper.ViewData["Prefix.Property1"] = true;
helper.ViewData.Model = new TestModel();
helper.ViewData.TemplateInfo.HtmlFieldPrefix = "Prefix";
// Act
var html = helper.CheckBox("Property1", isChecked: null, htmlAttributes: null);
// Assert
Assert.Equal(expected, html.ToString());
}
[Fact]
public void CheckBoxNotInTemplate_GetsValueFromPropertyOfViewDataEntry()
{
// Arrange
var expected =
@"<input checked=""HtmlEncode[[checked]]"" id=""HtmlEncode[[Prefix_Property1]]"" " +
@"name=""HtmlEncode[[Prefix.Property1]]"" type=""HtmlEncode[[checkbox]]"" value=""HtmlEncode[[true]]"" />" +
@"<input name=""HtmlEncode[[Prefix.Property1]]"" type=""HtmlEncode[[hidden]]"" value=""HtmlEncode[[false]]"" />";
var helper = DefaultTemplatesUtilities.GetHtmlHelper(GetTestModelViewData());
helper.ViewContext.ClientValidationEnabled = false;
helper.ViewData.Remove(nameof(TestModel.Property1));
helper.ViewData["Prefix"] = new TestModel { Property1 = true };
helper.ViewData.Model = new TestModel();
// Act
var html = helper.CheckBox("Prefix.Property1", isChecked: null, htmlAttributes: null);
// Assert
Assert.Equal(expected, html.ToString());
}
[Fact]
public void CheckBoxInTemplate_GetsValueFromPropertyOfViewDataEntry()
{
// Arrange
var expected =
@"<input checked=""HtmlEncode[[checked]]"" id=""HtmlEncode[[Prefix_Property1]]"" " +
@"name=""HtmlEncode[[Prefix.Property1]]"" type=""HtmlEncode[[checkbox]]"" value=""HtmlEncode[[true]]"" />" +
@"<input name=""HtmlEncode[[Prefix.Property1]]"" type=""HtmlEncode[[hidden]]"" value=""HtmlEncode[[false]]"" />";
var helper = DefaultTemplatesUtilities.GetHtmlHelper(GetTestModelViewData());
helper.ViewContext.ClientValidationEnabled = false;
helper.ViewData.Remove(nameof(TestModel.Property1));
helper.ViewData["Prefix"] = new TestModel { Property1 = true };
helper.ViewData.Model = new TestModel();
helper.ViewData.TemplateInfo.HtmlFieldPrefix = "Prefix";
// Act
var html = helper.CheckBox("Property1", isChecked: null, htmlAttributes: null);
// Assert
Assert.Equal(expected, html.ToString());
}
[Fact]
public void CheckBoxNotInTemplate_GetsModelValue_IfModelStateAndViewDataEmpty()
{
// Arrange
var expected =
@"<input checked=""HtmlEncode[[checked]]"" id=""HtmlEncode[[Property1]]"" " +
@"name=""HtmlEncode[[Property1]]"" type=""HtmlEncode[[checkbox]]"" value=""HtmlEncode[[true]]"" />" +
@"<input name=""HtmlEncode[[Property1]]"" type=""HtmlEncode[[hidden]]"" value=""HtmlEncode[[false]]"" />";
var metadataProvider = new EmptyModelMetadataProvider();
var helper = DefaultTemplatesUtilities.GetHtmlHelper(new ViewDataDictionary<TestModel>(metadataProvider));
helper.ViewContext.ClientValidationEnabled = false;
helper.ViewData.Model = new TestModel { Property1 = true };
// Act
var html = helper.CheckBox("Property1", isChecked: null, htmlAttributes: null);
// Assert
Assert.Equal(expected, html.ToString());
}
[Fact(Skip = "#1485, unable to get Model value.")]
public void CheckBoxInTemplate_GetsModelValue_IfModelStateAndViewDataEmpty()
{
// Arrange
var expected =
@"<input checked=""HtmlEncode[[checked]]"" id=""HtmlEncode[[Prefix_Property1]]"" " +
@"name=""HtmlEncode[[Prefix.Property1]]"" type=""HtmlEncode[[checkbox]]"" value=""HtmlEncode[[true]]"" />" +
@"<input name=""HtmlEncode[[Prefix.Property1]]"" type=""HtmlEncode[[hidden]]"" value=""HtmlEncode[[false]]"" />";
var metadataProvider = new EmptyModelMetadataProvider();
var helper = DefaultTemplatesUtilities.GetHtmlHelper(new ViewDataDictionary<TestModel>(metadataProvider));
helper.ViewContext.ClientValidationEnabled = false;
helper.ViewData.Model = new TestModel { Property1 = true };
helper.ViewData.TemplateInfo.HtmlFieldPrefix = "Prefix";
// Act
var html = helper.CheckBox("Property1", isChecked: null, htmlAttributes: null);
// Assert
Assert.Equal(expected, html.ToString());
}
[Fact]
public void CheckBoxNotInTemplate_NotChecked_IfPropertyIsNotFound()
{
// Arrange
var expected =
@"<input id=""HtmlEncode[[Property1]]"" " +
@"name=""HtmlEncode[[Property1]]"" type=""HtmlEncode[[checkbox]]"" value=""HtmlEncode[[true]]"" />" +
@"<input name=""HtmlEncode[[Property1]]"" type=""HtmlEncode[[hidden]]"" value=""HtmlEncode[[false]]"" />";
var metadataProvider = new EmptyModelMetadataProvider();
var helper = DefaultTemplatesUtilities.GetHtmlHelper(new ViewDataDictionary<TestModel>(metadataProvider));
helper.ViewContext.ClientValidationEnabled = false;
// Act
var html = helper.CheckBox("Property1", isChecked: null, htmlAttributes: null);
// Assert
Assert.Equal(expected, html.ToString());
}
[Fact]
public void CheckBoxInTemplate_NotChecked_IfPropertyIsNotFound()
{
// Arrange
var expected =
@"<input id=""HtmlEncode[[Prefix_Property1]]"" " +
@"name=""HtmlEncode[[Prefix.Property1]]"" type=""HtmlEncode[[checkbox]]"" value=""HtmlEncode[[true]]"" />" +
@"<input name=""HtmlEncode[[Prefix.Property1]]"" type=""HtmlEncode[[hidden]]"" value=""HtmlEncode[[false]]"" />";
var metadataProvider = new EmptyModelMetadataProvider();
var helper = DefaultTemplatesUtilities.GetHtmlHelper(new ViewDataDictionary<TestModel>(metadataProvider));
helper.ViewContext.ClientValidationEnabled = false;
helper.ViewData.TemplateInfo.HtmlFieldPrefix = "Prefix";
// Act
var html = helper.CheckBox("Property1", isChecked: null, htmlAttributes: null);
// Assert
Assert.Equal(expected, html.ToString());
}
[Fact]
public void CheckBoxGeneratesUnobtrusiveValidationAttributes()
{
@ -142,9 +306,9 @@ namespace Microsoft.AspNet.Mvc.Rendering
{
// Arrange
var expected =
@"<input checked=""HtmlEncode[[checked]]"" data-val=""HtmlEncode[[true]]"" " +
@"<input checked=""HtmlEncode[[checked]]"" data-val=""HtmlEncode[[true]]"" " +
@"data-val-required=""HtmlEncode[[The Boolean field is required.]]"" id=""HtmlEncode[[Property1]]"" " +
@"name=""HtmlEncode[[Property1]]"" Property1-Property3=""HtmlEncode[[Property3ObjValue]]"" " +
@"name=""HtmlEncode[[Property1]]"" Property1-Property3=""HtmlEncode[[Property3ObjValue]]"" " +
@"type=""HtmlEncode[[checkbox]]"" value=""HtmlEncode[[true]]"" /><input " +
@"name=""HtmlEncode[[Property1]]"" type=""HtmlEncode[[hidden]]"" value=""HtmlEncode[[false]]"" />";
var helper = DefaultTemplatesUtilities.GetHtmlHelper(GetTestModelViewData());
@ -158,7 +322,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
}
[Fact]
public void CheckBoxWithPrefix_ReplaceDotsInIdByDefaultWithUnderscores()
public void CheckBoxInTemplate_ReplaceDotsInIdByDefaultWithUnderscores()
{
// Arrange
var expected = @"<input id=""HtmlEncode[[MyPrefix_Property1]]"" name=""HtmlEncode[[MyPrefix.Property1]]"" " +
@ -176,7 +340,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
}
[Fact]
public void CheckBoxWithPrefix_ReplacesDotsInIdWithIdDotReplacement()
public void CheckBoxInTemplate_ReplacesDotsInIdWithIdDotReplacement()
{
// Arrange
var expected = @"<input id=""HtmlEncode[[MyPrefix!!!Property1]]"" name=""HtmlEncode[[MyPrefix.Property1]]"" " +
@ -196,7 +360,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
}
[Fact]
public void CheckBoxWithPrefixAndEmptyName()
public void CheckBoxInTemplate_WithEmptyExpression_GeneratesExpectedValue()
{
// Arrange
var expected =
@ -219,7 +383,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
public void CheckBoxWithComplexExpressionsEvaluatesValuesInViewDataDictionary()
{
// Arrange
var expected =
var expected =
@"<input checked=""HtmlEncode[[checked]]"" data-val=""HtmlEncode[[true]]"" " +
@"data-val-required=""HtmlEncode[[The Boolean field is required.]]"" id=""HtmlEncode[[ComplexProperty_Property1]]"" " +
@"name=""HtmlEncode[[ComplexProperty." +
@ -248,7 +412,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
viewData.ModelState.SetModelValue("Property1", valueProviderResult);
// Act
var html = helper.CheckBoxFor(m => m.Property1);
var html = helper.CheckBoxFor(m => m.Property1, htmlAttributes: null);
// Assert
Assert.Equal(expected, html.ToString());
@ -275,7 +439,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
var helper = DefaultTemplatesUtilities.GetHtmlHelper(viewData);
// Act
var html = helper.CheckBoxFor(m => m.Property1);
var html = helper.CheckBoxFor(m => m.Property1, htmlAttributes: null);
// Assert
Assert.Equal(expected, html.ToString());
@ -286,7 +450,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
{
// Arrange
var expected =
@"<input checked=""HtmlEncode[[checked]]"" data-val=""HtmlEncode[[true]]"" " +
@"<input checked=""HtmlEncode[[checked]]"" data-val=""HtmlEncode[[true]]"" " +
@"data-val-required=""HtmlEncode[[The Property3 field is required.]]"" " +
@"id=""HtmlEncode[[Property3]]"" name=""HtmlEncode[[Property3]]"" type=""HtmlEncode[[checkbox]]"" " +
@"value=""HtmlEncode[[false]]"" /><input name=""HtmlEncode[[Property3]]"" type=""HtmlEncode[[hidden]]"" value=""HtmlEncode[[false]]"" />";
@ -326,7 +490,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
public void CheckBoxFor_UsesModelStateAttemptedValue(string attemptedValue, string expectedChecked)
{
// Arrange
var expected =
var expected =
@"<input {0}data-val=""HtmlEncode[[true]]"" data-val-required=""HtmlEncode[[The Property1 field is required.]]"" " +
@"id=""HtmlEncode[[Property1]]"" name=""HtmlEncode[[Property1]]"" type=""HtmlEncode[[checkbox]]"" value=""HtmlEncode[[true]]"" />" +
@"<input name=""HtmlEncode[[Property1]]"" type=""HtmlEncode[[hidden]]"" value=""HtmlEncode[[false]]"" />";
@ -339,7 +503,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
viewData.ModelState.SetModelValue("Property1", valueProviderResult);
// Act
var html = helper.CheckBoxFor(m => m.Property1);
var html = helper.CheckBoxFor(m => m.Property1, htmlAttributes: null);
// Assert
Assert.Equal(expected, html.ToString());
@ -365,10 +529,10 @@ namespace Microsoft.AspNet.Mvc.Rendering
}
[Fact]
public void CheckBoxForWith_AttributeDictionary_GeneratesExpectedAttributes()
public void CheckBoxFor_WithAttributeDictionary_GeneratesExpectedAttributes()
{
// Arrange
var expected =
var expected =
@"<input data-val=""HtmlEncode[[true]]"" data-val-required=""HtmlEncode[[The Property1 field is required.]]"" " +
@"id=""HtmlEncode[[Property1]]"" name=""HtmlEncode[[Property1]]"" " +
@"Property3=""HtmlEncode[[Property3Value]]"" type=""HtmlEncode[[checkbox]]"" value=""HtmlEncode[[true]]"" /><input " +
@ -384,7 +548,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
}
[Fact]
public void CheckBoxForWithPrefix()
public void CheckBoxForInTemplate_GeneratesExpectedValue()
{
// Arrange
var expected =
@ -407,7 +571,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
public void CheckBoxFor_WithComplexExpressions_DoesNotUseValuesFromViewDataDictionary()
{
// Arrange
var expected =
var expected =
@"<input data-val=""HtmlEncode[[true]]"" data-val-required=""HtmlEncode[[The Property1 field is required.]]"" " +
@"id=""HtmlEncode[[ComplexProperty_Property1]]"" name=""HtmlEncode[[ComplexProperty." +
@"Property1]]"" type=""HtmlEncode[[checkbox]]"" value=""HtmlEncode[[true]]"" /><input name=""HtmlEncode[[ComplexProperty.Property1]]"" " +

View File

@ -59,6 +59,76 @@ namespace Microsoft.AspNet.Mvc.Rendering
Assert.Equal(expected, result.ToString());
}
[Fact]
public void HiddenNotInTemplate_GetsValueFromPropertyOfViewDataEntry()
{
// Arrange
var expected = @"<input id=""HtmlEncode[[Prefix_Property1]]"" name=""HtmlEncode[[Prefix.Property1]]"" " +
@"type=""HtmlEncode[[hidden]]"" value=""HtmlEncode[[contained-view-data-value]]"" />";
var helper = DefaultTemplatesUtilities.GetHtmlHelper(GetViewDataWithNonNullModel());
helper.ViewData.Model.Property1 = "model-property1-value";
helper.ViewData["Prefix"] = new HiddenModel { Property1 = "contained-view-data-value" };
// Act
var html = helper.Hidden("Prefix.Property1", value: null, htmlAttributes: null);
// Assert
Assert.Equal(expected, html.ToString());
}
[Fact]
public void HiddenInTemplate_GetsValueFromPropertyOfViewDataEntry()
{
// Arrange
var expected = @"<input id=""HtmlEncode[[Prefix_Property1]]"" name=""HtmlEncode[[Prefix.Property1]]"" " +
@"type=""HtmlEncode[[hidden]]"" value=""HtmlEncode[[contained-view-data-value]]"" />";
var helper = DefaultTemplatesUtilities.GetHtmlHelper(GetViewDataWithNonNullModel());
helper.ViewData.TemplateInfo.HtmlFieldPrefix = "Prefix";
helper.ViewData.Model.Property1 = "model-property1-value";
helper.ViewData["Prefix"] = new HiddenModel { Property1 = "contained-view-data-value" };
// Act
var html = helper.Hidden("Property1", value: null, htmlAttributes: null);
// Assert
Assert.Equal(expected, html.ToString());
}
[Fact]
public void HiddenNotInTemplate_GetsValueFromViewDataEntry_EvenIfNull()
{
// Arrange
var expected = @"<input id=""HtmlEncode[[Property1]]"" name=""HtmlEncode[[Property1]]"" " +
@"type=""HtmlEncode[[hidden]]"" value="""" />";
var helper = DefaultTemplatesUtilities.GetHtmlHelper(GetViewDataWithNonNullModel());
helper.ViewData.Model.Property1 = "model-property1-value";
helper.ViewData["Property1"] = null;
// Act
var html = helper.Hidden("Property1", value: null, htmlAttributes: null);
// Assert
Assert.Equal(expected, html.ToString());
}
[Fact]
public void HiddenInTemplate_GetsValueFromViewDataEntry_EvenIfNull()
{
// Arrange
var expected = @"<input id=""HtmlEncode[[Prefix_Property1]]"" name=""HtmlEncode[[Prefix.Property1]]"" " +
@"type=""HtmlEncode[[hidden]]"" value="""" />";
var helper = DefaultTemplatesUtilities.GetHtmlHelper(GetViewDataWithNonNullModel());
helper.ViewData.TemplateInfo.HtmlFieldPrefix = "Prefix";
helper.ViewData.Model.Property1 = "model-property1-value";
helper.ViewData["Prefix.Property1"] = null;
// Act
var html = helper.Hidden("Property1", value: null, htmlAttributes: null);
// Assert
Assert.Equal(expected, html.ToString());
}
[Fact]
public void HiddenOverridesValueFromAttributesWithArgumentValue()
{
@ -92,7 +162,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
}
[Fact]
public void HiddenWithNullValueAndNullModel_GeneratesExpectedValue()
public void HiddenWithNonNullValue_GeneratesExpectedValue()
{
// Arrange
var expected = @"<input data-key=""HtmlEncode[[value]]"" id=""HtmlEncode[[Property1]]"" name=""HtmlEncode[[Property1]]"" type=""HtmlEncode[[hidden]]"" " +
@ -155,13 +225,11 @@ namespace Microsoft.AspNet.Mvc.Rendering
}
[Fact]
public void HiddenUsesPropertyValue_IfModelStateAndViewDataDoNotHavePropertyAndExplicitValueIsNull()
public void HiddenNotInTemplate_GetsModelValue_IfModelStateAndViewDataEmpty()
{
// Arrange
var expected = @"<input id=""HtmlEncode[[Property1]]"" name=""HtmlEncode[[Property1]]"" type=""HtmlEncode[[hidden]]"" value=""HtmlEncode[[property-value]]"" />";
var helper = DefaultTemplatesUtilities.GetHtmlHelper(GetViewDataWithModelStateAndModelAndViewDataValues());
helper.ViewData.ModelState.Clear();
helper.ViewData.Clear();
var helper = DefaultTemplatesUtilities.GetHtmlHelper(GetViewDataWithNonNullModel());
helper.ViewData.Model.Property1 = "property-value";
// Act
@ -171,15 +239,29 @@ namespace Microsoft.AspNet.Mvc.Rendering
Assert.Equal(expected, result.ToString());
}
[Fact(Skip = "#1485, unable to get Model value.")]
public void HiddenInTemplate_GetsModelValue_IfModelStateAndViewDataEmpty()
{
// Arrange
var expected = @"<input id=""HtmlEncode[[Prefix_Property1]]"" name=""HtmlEncode[[Prefix.Property1]]"" " +
@"type=""HtmlEncode[[hidden]]"" value=""HtmlEncode[[property-value]]"" />";
var helper = DefaultTemplatesUtilities.GetHtmlHelper(GetViewDataWithNonNullModel());
helper.ViewData.TemplateInfo.HtmlFieldPrefix = "Prefix";
helper.ViewData.Model.Property1 = "property-value";
// Act
var html = helper.Hidden("Property1", value: null, htmlAttributes: new { value = "attribute-value" });
// Assert
Assert.Equal(expected, html.ToString());
}
[Fact]
public void HiddenDoesNotUsesAttributeValue()
public void HiddenNotInTemplate_DoesNotUseAttributeValue()
{
// Arrange
var expected = @"<input id=""HtmlEncode[[Property1]]"" name=""HtmlEncode[[Property1]]"" type=""HtmlEncode[[hidden]]"" value="""" />";
var helper = DefaultTemplatesUtilities.GetHtmlHelper(GetViewDataWithModelStateAndModelAndViewDataValues());
helper.ViewData.ModelState.Clear();
helper.ViewData.Clear();
helper.ViewData.Model.Property1 = null;
var helper = DefaultTemplatesUtilities.GetHtmlHelper(GetViewDataWithNonNullModel());
// Act
var result = helper.Hidden("Property1", value: null, htmlAttributes: new { value = "attribute-value" });
@ -189,7 +271,23 @@ namespace Microsoft.AspNet.Mvc.Rendering
}
[Fact]
public void HiddenReturnsEmptyValue_IfPropertyIsNotFound()
public void HiddenInTemplate_DoesNotUseAttributeValue()
{
// Arrange
var expected = @"<input id=""HtmlEncode[[Prefix_Property1]]"" name=""HtmlEncode[[Prefix.Property1]]"" " +
@"type=""HtmlEncode[[hidden]]"" value="""" />";
var helper = DefaultTemplatesUtilities.GetHtmlHelper(GetViewDataWithNonNullModel());
helper.ViewData.TemplateInfo.HtmlFieldPrefix = "Prefix";
// Act
var html = helper.Hidden("Property1", value: null, htmlAttributes: new { value = "attribute-value" });
// Assert
Assert.Equal(expected, html.ToString());
}
[Fact]
public void HiddenNotInTemplate_GetsEmptyValue_IfPropertyIsNotFound()
{
// Arrange
var expected = @"<input baz=""HtmlEncode[[BazValue]]"" id=""HtmlEncode[[keyNotFound]]"" name=""HtmlEncode[[keyNotFound]]"" type=""HtmlEncode[[hidden]]"" " +
@ -205,7 +303,23 @@ namespace Microsoft.AspNet.Mvc.Rendering
}
[Fact]
public void HiddenWithPrefix_GeneratesExpectedValue()
public void HiddenInTemplate_GetsEmptyValue_IfPropertyIsNotFound()
{
// Arrange
var expected = @"<input id=""HtmlEncode[[Prefix_keyNotFound]]"" name=""HtmlEncode[[Prefix.keyNotFound]]"" " +
@"type=""HtmlEncode[[hidden]]"" value="""" />";
var helper = DefaultTemplatesUtilities.GetHtmlHelper(GetViewDataWithModelStateAndModelAndViewDataValues());
helper.ViewData.TemplateInfo.HtmlFieldPrefix = "Prefix";
// Act
var html = helper.Hidden("keyNotFound", value: null, htmlAttributes: null);
// Assert
Assert.Equal(expected, html.ToString());
}
[Fact]
public void HiddenInTemplate_WithExplicitValue_GeneratesExpectedValue()
{
// Arrange
var expected = @"<input id=""HtmlEncode[[MyPrefix_Property1]]"" name=""HtmlEncode[[MyPrefix.Property1]]"" type=""HtmlEncode[[hidden]]"" " +
@ -221,7 +335,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
}
[Fact]
public void HiddenWithPrefixAndEmptyName_GeneratesExpectedValue()
public void HiddenInTemplate_WithExplicitValueAndEmptyName_GeneratesExpectedValue()
{
// Arrange
var expected = @"<input id=""HtmlEncode[[MyPrefix]]"" name=""HtmlEncode[[MyPrefix]]"" type=""HtmlEncode[[hidden]]"" value=""HtmlEncode[[fooValue]]"" />";
@ -236,7 +350,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
}
[Fact]
public void HiddenUsesPrefixName_ToLookupPropertyValueInModelState()
public void HiddenInTemplate_UsesPrefixName_ToLookupPropertyValueInModelState()
{
// Arrange
var expected = @"<input id=""HtmlEncode[[MyPrefix$Property1]]"" name=""HtmlEncode[[MyPrefix.Property1]]"" type=""HtmlEncode[[hidden]]"" " +
@ -258,7 +372,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
}
[Fact]
public void HiddenUsesPrefixName_ToLookupPropertyValueInViewData()
public void HiddenInTemplate_UsesPrefixNameToLookupPropertyValueInViewData()
{
// Arrange
var expected = @"<input id=""HtmlEncode[[MyPrefix$Property1]]"" name=""HtmlEncode[[MyPrefix.Property1]]"" type=""HtmlEncode[[hidden]]"" " +
@ -509,7 +623,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
// This test ensures that specifying a the prefix does not affect the expression result.
[Fact]
public void HiddenForWithPrefix_GeneratesExpectedValue()
public void HiddenForInTemplate_GeneratesExpectedValue()
{
// Arrange
var expected = @"<input id=""HtmlEncode[[MyPrefix_Property1]]"" name=""HtmlEncode[[MyPrefix.Property1]]"" type=""HtmlEncode[[hidden]]"" " +
@ -519,14 +633,14 @@ namespace Microsoft.AspNet.Mvc.Rendering
helper.ViewContext.ViewData.TemplateInfo.HtmlFieldPrefix = "MyPrefix";
// Act
var result = helper.HiddenFor(m => m.Property1);
var result = helper.HiddenFor(m => m.Property1, htmlAttributes: null);
// Assert
Assert.Equal(expected, result.ToString());
}
[Fact]
public void HiddenForWithPrefix_UsesPrefixWhenLookingUpModelStateValues()
public void HiddenForInTemplate_UsesPrefixWhenLookingUpModelStateValues()
{
// Arrange
var expected = @"<input id=""HtmlEncode[[MyPrefix$Property1]]"" name=""HtmlEncode[[MyPrefix.Property1]]"" type=""HtmlEncode[[hidden]]"" " +
@ -542,7 +656,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
helper.ViewData.ModelState.Add("MyPrefix$Property1", GetModelState("modelstate-with-iddotreplacement"));
// Act
var result = helper.HiddenFor(m => m.Property1);
var result = helper.HiddenFor(m => m.Property1, htmlAttributes: null);
// Assert
Assert.Equal(expected, result.ToString());
@ -671,7 +785,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
[Theory]
[MemberData(nameof(HiddenFor_UsesModelStateValueForComplexExpressionsData))]
public void HiddenFor_UsesModelStateValueForComplexExpressions(
public void HiddenForInTemplate_UsesModelStateValueForComplexExpressions(
Expression<Func<HiddenModel, string>> expression,
string expected)
{
@ -718,13 +832,20 @@ namespace Microsoft.AspNet.Mvc.Rendering
};
}
private static ViewDataDictionary<HiddenModel> GetViewDataWithModelStateAndModelAndViewDataValues()
private static ViewDataDictionary<HiddenModel> GetViewDataWithNonNullModel()
{
var viewData = new ViewDataDictionary<HiddenModel>(new EmptyModelMetadataProvider())
{
Model = new HiddenModel(),
["Property1"] = "view-data-val",
};
return viewData;
}
private static ViewDataDictionary<HiddenModel> GetViewDataWithModelStateAndModelAndViewDataValues()
{
var viewData = GetViewDataWithNonNullModel();
viewData["Property1"] = "view-data-val";
viewData.ModelState.Add("Property1", GetModelState("ModelStateValue"));
return viewData;

View File

@ -59,6 +59,17 @@ namespace Microsoft.AspNet.Mvc.Rendering
new SelectListItem { Group = DisabledGroup, Selected = true, Text = "Two", Value = "2"},
new SelectListItem { Group = DisabledGroup, Selected = true, Text = "Three", Value = "3"},
};
private static readonly List<SelectListItem> SourcesSelectList = new List<SelectListItem>
{
new SelectListItem { Text = SelectSources.ModelStateEntry.ToString() },
new SelectListItem { Text = SelectSources.ModelStateEntryWithPrefix.ToString() },
new SelectListItem { Text = SelectSources.ViewDataEntry.ToString() },
new SelectListItem { Text = SelectSources.PropertyOfViewDataEntry.ToString() },
new SelectListItem { Text = SelectSources.ViewDataEntryWithPrefix.ToString() },
new SelectListItem { Text = SelectSources.PropertyOfViewDataEntryWithPrefix.ToString() },
new SelectListItem { Text = SelectSources.ModelValue.ToString() },
new SelectListItem { Text = SelectSources.PropertyOfModel.ToString() },
};
// Select list -> expected HTML with null model, expected HTML with model containing "2".
public static TheoryData<IEnumerable<SelectListItem>, string, string> DropDownListDataSet
@ -371,6 +382,200 @@ namespace Microsoft.AspNet.Mvc.Rendering
Assert.Equal(savedSelected, selectList.Select(item => item.Selected));
}
[Fact]
public void DropDownListNotInTemplate_GetsModelStateEntry()
{
// Arrange
var expectedHtml = GetExpectedSelectElement(SelectSources.ModelStateEntry, allowMultiple: false);
var entryResult = new ValueProviderResult(
SelectSources.ModelStateEntry,
SelectSources.ModelStateEntry.ToString(),
culture: null);
var entryResultWithPrefix = new ValueProviderResult(
SelectSources.ModelStateEntryWithPrefix,
SelectSources.ModelStateEntryWithPrefix.ToString(),
culture: null);
var modelState = new ModelStateDictionary
{
["Property1"] = new ModelState { Value = entryResult },
["Prefix.Property1"] = new ModelState { Value = entryResultWithPrefix },
};
var provider = TestModelMetadataProvider.CreateDefaultProvider();
var viewData = new ViewDataDictionary<ModelContainingSources>(provider, modelState)
{
["Property1"] = SelectSources.ViewDataEntry,
["Prefix.Property1"] = SelectSources.ViewDataEntryWithPrefix,
["Prefix"] = new ModelContainingSources { Property1 = SelectSources.PropertyOfViewDataEntry },
};
viewData.Model = new ModelContainingSources { Property1 = SelectSources.PropertyOfModel };
var helper = DefaultTemplatesUtilities.GetHtmlHelper(viewData);
helper.ViewContext.ClientValidationEnabled = false;
// Act
var html = helper.DropDownList("Property1", SourcesSelectList, optionLabel: null, htmlAttributes: null);
// Assert
Assert.Equal(expectedHtml, html.ToString());
}
[Fact]
public void DropDownListInTemplate_GetsModelStateEntry()
{
// Arrange
var expectedHtml = GetExpectedSelectElementWithPrefix(
SelectSources.ModelStateEntryWithPrefix,
allowMultiple: false);
var entryResult = new ValueProviderResult(
SelectSources.ModelStateEntry,
SelectSources.ModelStateEntry.ToString(),
culture: null);
var entryResultWithPrefix = new ValueProviderResult(
SelectSources.ModelStateEntryWithPrefix,
SelectSources.ModelStateEntryWithPrefix.ToString(),
culture: null);
var modelState = new ModelStateDictionary
{
["Property1"] = new ModelState { Value = entryResult },
["Prefix.Property1"] = new ModelState { Value = entryResultWithPrefix },
};
var provider = TestModelMetadataProvider.CreateDefaultProvider();
var viewData = new ViewDataDictionary<ModelContainingSources>(provider, modelState)
{
["Property1"] = SelectSources.ViewDataEntry,
["Prefix.Property1"] = SelectSources.ViewDataEntryWithPrefix,
["Prefix"] = new ModelContainingSources { Property1 = SelectSources.PropertyOfViewDataEntry },
};
viewData.Model = new ModelContainingSources { Property1 = SelectSources.PropertyOfModel };
viewData.TemplateInfo.HtmlFieldPrefix = "Prefix";
var helper = DefaultTemplatesUtilities.GetHtmlHelper(viewData);
helper.ViewContext.ClientValidationEnabled = false;
// Act
var html = helper.DropDownList("Property1", SourcesSelectList, optionLabel: null, htmlAttributes: null);
// Assert
Assert.Equal(expectedHtml, html.ToString());
}
[Fact]
public void DropDownListNotInTemplate_GetsViewDataEntry_IfModelStateEmpty()
{
// Arrange
var expectedHtml = GetExpectedSelectElement(SelectSources.ViewDataEntry, allowMultiple: false);
var provider = TestModelMetadataProvider.CreateDefaultProvider();
var viewData = new ViewDataDictionary<ModelContainingSources>(provider)
{
["Property1"] = SelectSources.ViewDataEntry,
["Prefix.Property1"] = SelectSources.ViewDataEntryWithPrefix,
["Prefix"] = new ModelContainingSources { Property1 = SelectSources.PropertyOfViewDataEntry },
};
viewData.Model = new ModelContainingSources { Property1 = SelectSources.PropertyOfModel };
var helper = DefaultTemplatesUtilities.GetHtmlHelper(viewData);
helper.ViewContext.ClientValidationEnabled = false;
// Act
var html = helper.DropDownList("Property1", SourcesSelectList, optionLabel: null, htmlAttributes: null);
// Assert
Assert.Equal(expectedHtml, html.ToString());
}
[Fact(Skip = "#1487, incorrectly matches Property1 entry (without prefix) in ViewData.")]
public void DropDownListInTemplate_GetsViewDataEntry_IfModelStateEmpty()
{
// Arrange
var expectedHtml = GetExpectedSelectElementWithPrefix(
SelectSources.ViewDataEntryWithPrefix,
allowMultiple: false);
var provider = TestModelMetadataProvider.CreateDefaultProvider();
var viewData = new ViewDataDictionary<ModelContainingSources>(provider)
{
["Property1"] = SelectSources.ViewDataEntry,
["Prefix.Property1"] = SelectSources.ViewDataEntryWithPrefix,
["Prefix"] = new ModelContainingSources { Property1 = SelectSources.PropertyOfViewDataEntry },
};
viewData.Model = new ModelContainingSources { Property1 = SelectSources.PropertyOfModel };
viewData.TemplateInfo.HtmlFieldPrefix = "Prefix";
var helper = DefaultTemplatesUtilities.GetHtmlHelper(viewData);
helper.ViewContext.ClientValidationEnabled = false;
// Act
var html = helper.DropDownList("Property1", SourcesSelectList, optionLabel: null, htmlAttributes: null);
// Assert
Assert.Equal(expectedHtml, html.ToString());
}
[Fact(Skip = "#1487, incorrectly matches Property1 entry (without prefix) in ViewData.")]
public void DropDownListInTemplate_GetsPropertyOfViewDataEntry_IfModelStateEmptyAndNoViewDataEntryWithPrefix()
{
// Arrange
var expectedHtml = GetExpectedSelectElementWithPrefix(
SelectSources.PropertyOfViewDataEntry,
allowMultiple: false);
var provider = TestModelMetadataProvider.CreateDefaultProvider();
var viewData = new ViewDataDictionary<ModelContainingSources>(provider)
{
["Property1"] = SelectSources.ViewDataEntry,
["Prefix"] = new ModelContainingSources { Property1 = SelectSources.PropertyOfViewDataEntry },
};
viewData.Model = new ModelContainingSources { Property1 = SelectSources.PropertyOfModel };
viewData.TemplateInfo.HtmlFieldPrefix = "Prefix";
var helper = DefaultTemplatesUtilities.GetHtmlHelper(viewData);
helper.ViewContext.ClientValidationEnabled = false;
// Act
var html = helper.DropDownList("Property1", SourcesSelectList, optionLabel: null, htmlAttributes: null);
// Assert
Assert.Equal(expectedHtml, html.ToString());
}
[Fact]
public void DropDownListNotInTemplate_GetsPropertyOfModel_IfModelStateAndViewDataEmpty()
{
// Arrange
var expectedHtml = GetExpectedSelectElement(SelectSources.PropertyOfModel, allowMultiple: false);
var model = new ModelContainingSources { Property1 = SelectSources.PropertyOfModel };
var helper = DefaultTemplatesUtilities.GetHtmlHelper(model);
helper.ViewContext.ClientValidationEnabled = false;
// Act
var html = helper.DropDownList("Property1", SourcesSelectList, optionLabel: null, htmlAttributes: null);
// Assert
Assert.Equal(expectedHtml, html.ToString());
}
[Fact]
public void DropDownListInTemplate_GetsPropertyOfModel_IfModelStateAndViewDataEmpty()
{
// Arrange
var expectedHtml = GetExpectedSelectElementWithPrefix(SelectSources.PropertyOfModel, allowMultiple: false);
var model = new ModelContainingSources { Property1 = SelectSources.PropertyOfModel };
var helper = DefaultTemplatesUtilities.GetHtmlHelper(model);
helper.ViewContext.ClientValidationEnabled = false;
helper.ViewData.TemplateInfo.HtmlFieldPrefix = "Prefix";
// Act
var html = helper.DropDownList("Property1", SourcesSelectList, optionLabel: null, htmlAttributes: null);
// Assert
Assert.Equal(expectedHtml, html.ToString());
}
[Theory]
[MemberData(nameof(DropDownListDataSet))]
public void DropDownListFor_WithNullModel_GeneratesExpectedValue(
@ -588,6 +793,200 @@ namespace Microsoft.AspNet.Mvc.Rendering
Assert.Equal(savedSelected, selectList.Select(item => item.Selected));
}
[Fact]
public void ListBoxNotInTemplate_GetsModelStateEntry()
{
// Arrange
var expectedHtml = GetExpectedSelectElement(SelectSources.ModelStateEntry, allowMultiple: true);
var entryResult = new ValueProviderResult(
SelectSources.ModelStateEntry,
SelectSources.ModelStateEntry.ToString(),
culture: null);
var entryResultWithPrefix = new ValueProviderResult(
SelectSources.ModelStateEntryWithPrefix,
SelectSources.ModelStateEntryWithPrefix.ToString(),
culture: null);
var modelState = new ModelStateDictionary
{
["Property1"] = new ModelState { Value = entryResult },
["Prefix.Property1"] = new ModelState { Value = entryResultWithPrefix },
};
var provider = TestModelMetadataProvider.CreateDefaultProvider();
var viewData = new ViewDataDictionary<ModelContainingListOfSources>(provider, modelState)
{
["Property1"] = new[] { SelectSources.ViewDataEntry },
["Prefix.Property1"] = new[] { SelectSources.ViewDataEntryWithPrefix },
["Prefix"] = new ModelContainingListOfSources { Property1 = { SelectSources.PropertyOfViewDataEntry } },
};
viewData.Model = new ModelContainingListOfSources { Property1 = { SelectSources.PropertyOfModel } };
var helper = DefaultTemplatesUtilities.GetHtmlHelper(viewData);
helper.ViewContext.ClientValidationEnabled = false;
// Act
var html = helper.ListBox("Property1", SourcesSelectList, htmlAttributes: null);
// Assert
Assert.Equal(expectedHtml, html.ToString());
}
[Fact]
public void ListBoxInTemplate_GetsModelStateEntry()
{
// Arrange
var expectedHtml = GetExpectedSelectElementWithPrefix(
SelectSources.ModelStateEntryWithPrefix,
allowMultiple: true);
var entryResult = new ValueProviderResult(
SelectSources.ModelStateEntry,
SelectSources.ModelStateEntry.ToString(),
culture: null);
var entryResultWithPrefix = new ValueProviderResult(
SelectSources.ModelStateEntryWithPrefix,
SelectSources.ModelStateEntryWithPrefix.ToString(),
culture: null);
var modelState = new ModelStateDictionary
{
["Property1"] = new ModelState { Value = entryResult },
["Prefix.Property1"] = new ModelState { Value = entryResultWithPrefix },
};
var provider = TestModelMetadataProvider.CreateDefaultProvider();
var viewData = new ViewDataDictionary<ModelContainingListOfSources>(provider, modelState)
{
["Property1"] = new[] { SelectSources.ViewDataEntry },
["Prefix.Property1"] = new[] { SelectSources.ViewDataEntryWithPrefix },
["Prefix"] = new ModelContainingListOfSources { Property1 = { SelectSources.PropertyOfViewDataEntry } },
};
viewData.Model = new ModelContainingListOfSources { Property1 = { SelectSources.PropertyOfModel } };
viewData.TemplateInfo.HtmlFieldPrefix = "Prefix";
var helper = DefaultTemplatesUtilities.GetHtmlHelper(viewData);
helper.ViewContext.ClientValidationEnabled = false;
// Act
var html = helper.ListBox("Property1", SourcesSelectList, htmlAttributes: null);
// Assert
Assert.Equal(expectedHtml, html.ToString());
}
[Fact(Skip = "#2664, throws ArgumentNullException")]
public void ListBoxNotInTemplate_GetsViewDataEntry_IfModelStateEmpty()
{
// Arrange
var expectedHtml = GetExpectedSelectElement(SelectSources.ViewDataEntry, allowMultiple: true);
var provider = TestModelMetadataProvider.CreateDefaultProvider();
var viewData = new ViewDataDictionary<ModelContainingListOfSources>(provider)
{
["Property1"] = new[] { SelectSources.ViewDataEntry },
["Prefix.Property1"] = new[] { SelectSources.ViewDataEntryWithPrefix },
["Prefix"] = new ModelContainingListOfSources { Property1 = { SelectSources.PropertyOfViewDataEntry } },
};
viewData.Model = new ModelContainingListOfSources { Property1 = { SelectSources.PropertyOfModel } };
var helper = DefaultTemplatesUtilities.GetHtmlHelper(viewData);
helper.ViewContext.ClientValidationEnabled = false;
// Act
var html = helper.ListBox("Property1", SourcesSelectList, htmlAttributes: null);
// Assert
Assert.Equal(expectedHtml, html.ToString());
}
[Fact(Skip = "#2664, throws ArgumentNullException")]
public void ListBoxInTemplate_GetsViewDataEntry_IfModelStateEmpty()
{
// Arrange
var expectedHtml = GetExpectedSelectElementWithPrefix(
SelectSources.ViewDataEntryWithPrefix,
allowMultiple: true);
var provider = TestModelMetadataProvider.CreateDefaultProvider();
var viewData = new ViewDataDictionary<ModelContainingListOfSources>(provider)
{
["Property1"] = new[] { SelectSources.ViewDataEntry },
["Prefix.Property1"] = new[] { SelectSources.ViewDataEntryWithPrefix },
["Prefix"] = new ModelContainingListOfSources { Property1 = { SelectSources.PropertyOfViewDataEntry } },
};
viewData.Model = new ModelContainingListOfSources { Property1 = { SelectSources.PropertyOfModel } };
viewData.TemplateInfo.HtmlFieldPrefix = "Prefix";
var helper = DefaultTemplatesUtilities.GetHtmlHelper(viewData);
helper.ViewContext.ClientValidationEnabled = false;
// Act
var html = helper.ListBox("Property1", SourcesSelectList, htmlAttributes: null);
// Assert
Assert.Equal(expectedHtml, html.ToString());
}
[Fact(Skip = "#2664, throws ArgumentNullException")]
public void ListBoxInTemplate_GetsPropertyOfViewDataEntry_IfModelStateEmptyAndNoViewDataEntryWithPrefix()
{
// Arrange
var expectedHtml = GetExpectedSelectElementWithPrefix(
SelectSources.PropertyOfViewDataEntry,
allowMultiple: true);
var provider = TestModelMetadataProvider.CreateDefaultProvider();
var viewData = new ViewDataDictionary<ModelContainingListOfSources>(provider)
{
["Property1"] = new[] { SelectSources.ViewDataEntry },
["Prefix"] = new ModelContainingListOfSources { Property1 = { SelectSources.PropertyOfViewDataEntry } },
};
viewData.Model = new ModelContainingListOfSources { Property1 = { SelectSources.PropertyOfModel } };
viewData.TemplateInfo.HtmlFieldPrefix = "Prefix";
var helper = DefaultTemplatesUtilities.GetHtmlHelper(viewData);
helper.ViewContext.ClientValidationEnabled = false;
// Act
var html = helper.ListBox("Property1", SourcesSelectList, htmlAttributes: null);
// Assert
Assert.Equal(expectedHtml, html.ToString());
}
[Fact(Skip = "#2664, throws ArgumentNullException")]
public void ListBoxNotInTemplate_GetsPropertyOfModel_IfModelStateAndViewDataEmpty()
{
// Arrange
var expectedHtml = GetExpectedSelectElement(SelectSources.PropertyOfModel, allowMultiple: true);
var model = new ModelContainingListOfSources { Property1 = { SelectSources.PropertyOfModel } };
var helper = DefaultTemplatesUtilities.GetHtmlHelper(model);
helper.ViewContext.ClientValidationEnabled = false;
// Act
var html = helper.ListBox("Property1", SourcesSelectList, htmlAttributes: null);
// Assert
Assert.Equal(expectedHtml, html.ToString());
}
[Fact(Skip = "#2664, throws ArgumentNullException")]
public void ListBoxInTemplate_GetsPropertyOfModel_IfModelStateAndViewDataEmpty()
{
// Arrange
var expectedHtml = GetExpectedSelectElementWithPrefix(SelectSources.PropertyOfModel, allowMultiple: true);
var model = new ModelContainingListOfSources { Property1 = { SelectSources.PropertyOfModel } };
var helper = DefaultTemplatesUtilities.GetHtmlHelper(model);
helper.ViewContext.ClientValidationEnabled = false;
helper.ViewData.TemplateInfo.HtmlFieldPrefix = "Prefix";
// Act
var html = helper.ListBox("Property1", SourcesSelectList, htmlAttributes: null);
// Assert
Assert.Equal(expectedHtml, html.ToString());
}
[Theory]
[MemberData(nameof(ListBoxDataSet))]
public void ListBoxFor_WithNullModel_GeneratesExpectedValue(
@ -1072,6 +1471,51 @@ namespace Microsoft.AspNet.Mvc.Rendering
VerifySelectList(expected, result);
}
private static string GetExpectedSelectElement(SelectSources source, bool allowMultiple)
{
return $"<select id=\"HtmlEncode[[Property1]]\"{ GetMultiple(allowMultiple) } " +
"name=\"HtmlEncode[[Property1]]\">" +
$"{ GetOption(SelectSources.ModelStateEntry, source) }{ Environment.NewLine }" +
$"{ GetOption(SelectSources.ModelStateEntryWithPrefix, source) }{ Environment.NewLine }" +
$"{ GetOption(SelectSources.ViewDataEntry, source) }{ Environment.NewLine }" +
$"{ GetOption(SelectSources.PropertyOfViewDataEntry, source) }{ Environment.NewLine }" +
$"{ GetOption(SelectSources.ViewDataEntryWithPrefix, source) }{ Environment.NewLine }" +
$"{ GetOption(SelectSources.PropertyOfViewDataEntryWithPrefix, source) }{ Environment.NewLine }" +
$"{ GetOption(SelectSources.ModelValue, source) }{ Environment.NewLine }" +
$"{ GetOption(SelectSources.PropertyOfModel, source) }{ Environment.NewLine }" +
"</select>";
}
private static string GetExpectedSelectElementWithPrefix(SelectSources source, bool allowMultiple)
{
return $"<select id=\"HtmlEncode[[Prefix_Property1]]\"{ GetMultiple(allowMultiple) } " +
"name=\"HtmlEncode[[Prefix.Property1]]\">" +
$"{ GetOption(SelectSources.ModelStateEntry, source) }{ Environment.NewLine }" +
$"{ GetOption(SelectSources.ModelStateEntryWithPrefix, source) }{ Environment.NewLine }" +
$"{ GetOption(SelectSources.ViewDataEntry, source) }{ Environment.NewLine }" +
$"{ GetOption(SelectSources.PropertyOfViewDataEntry, source) }{ Environment.NewLine }" +
$"{ GetOption(SelectSources.ViewDataEntryWithPrefix, source) }{ Environment.NewLine }" +
$"{ GetOption(SelectSources.PropertyOfViewDataEntryWithPrefix, source) }{ Environment.NewLine }" +
$"{ GetOption(SelectSources.ModelValue, source) }{ Environment.NewLine }" +
$"{ GetOption(SelectSources.PropertyOfModel, source) }{ Environment.NewLine }" +
"</select>";
}
private static string GetMultiple(bool allowMultiple)
{
return allowMultiple ? " multiple=\"HtmlEncode[[multiple]]\"" : string.Empty;
}
private static string GetOption(SelectSources optionSource, SelectSources source)
{
return $"<option{ GetSelected(optionSource, source) }>HtmlEncode[[{ optionSource.ToString() }]]</option>";
}
private static string GetSelected(SelectSources optionSource, SelectSources source)
{
return optionSource == source ? " selected=\"HtmlEncode[[selected]]\"" : string.Empty;
}
// Confirm methods that wrap GetEnumSelectList(ModelMetadata) are not changing anything in returned collection.
private void VerifySelectList(IEnumerable<SelectListItem> expected, IEnumerable<SelectListItem> actual)
{
@ -1137,6 +1581,28 @@ namespace Microsoft.AspNet.Mvc.Rendering
}
}
private enum SelectSources
{
ModelStateEntry,
ModelStateEntryWithPrefix,
ViewDataEntry,
PropertyOfViewDataEntry,
ViewDataEntryWithPrefix,
PropertyOfViewDataEntryWithPrefix,
ModelValue,
PropertyOfModel,
};
private class ModelContainingSources
{
public SelectSources Property1 { get; set; }
}
private class ModelContainingListOfSources
{
public List<SelectSources> Property1 { get; } = new List<SelectSources>();
}
private class ClassWithFields
{
public const int Zero = 0;

View File

@ -11,25 +11,127 @@ using Xunit;
namespace Microsoft.AspNet.Mvc.Core
{
/// <summary>
/// Test the <see cref="HtmlHelperValueExtensions" /> class.
/// Test the <see cref="IHtmlHelper.Value" /> and <see cref="IHtmlHelper{TModel}.ValueFor"/> methods.
/// </summary>
public class HtmlHelperValueExtensionsTest
public class HtmlHelperValueTest
{
// Value
[Fact]
public void ValueGetsValueFromViewData()
public void ValueNotInTemplate_GetsValueFromViewData()
{
// Arrange
var helper = GetHtmlHelper();
// Act
var html = helper.Value("StringProperty");
var html = helper.Value("StringProperty", format: null);
// Assert
Assert.Equal("ViewDataValue", html);
}
[Fact(Skip = "$1487, finds 'StringProperty' entry (without prefix) instead.")]
public void ValueInTemplate_GetsValueFromPrefixedViewDataEntry()
{
// Arrange
var helper = GetHtmlHelper();
helper.ViewData["Prefix.StringProperty"] = "PrefixedViewDataValue";
helper.ViewData.TemplateInfo.HtmlFieldPrefix = "Prefix";
// Act
var html = helper.Value("StringProperty", format: null);
// Assert
Assert.Equal("PrefixedViewDataValue", html);
}
[Fact]
public void ValueNotInTemplate_GetsValueFromPropertyOfViewDataEntry()
{
// Arrange
var helper = GetHtmlHelper();
helper.ViewData["Prefix"] = new { StringProperty = "ContainedViewDataValue" };
// Act
var html = helper.Value("Prefix.StringProperty", format: null);
// Assert
Assert.Equal("ContainedViewDataValue", html);
}
[Fact(Skip = "$1487, finds 'StringProperty' entry (without prefix) instead.")]
public void ValueInTemplate_GetsValueFromPropertyOfViewDataEntry()
{
// Arrange
var helper = GetHtmlHelper();
helper.ViewData["Prefix"] = new { StringProperty = "ContainedViewDataValue" };
helper.ViewData.TemplateInfo.HtmlFieldPrefix = "Prefix";
// Act
var html = helper.Value("StringProperty", format: null);
// Assert
Assert.Equal("ContainedViewDataValue", html);
}
[Fact]
public void ValueNotInTemplate_GetsValueFromModel_IfNoViewDataEntry()
{
// Arrange
var helper = GetHtmlHelper();
helper.ViewData.Clear();
// Act
var html = helper.Value("StringProperty", format: null);
// Assert
Assert.Equal("ModelStringPropertyValue", html);
}
[Fact]
public void ValueInTemplate_GetsValueFromModel_IfNoViewDataEntry()
{
// Arrange
var helper = GetHtmlHelper();
helper.ViewData.Clear();
helper.ViewData.TemplateInfo.HtmlFieldPrefix = "Prefix";
// Act
var html = helper.Value("StringProperty", format: null);
// Assert
Assert.Equal("ModelStringPropertyValue", html);
}
[Fact]
public void ValueNotInTemplate_GetsValueFromViewData_EvenIfNull()
{
// Arrange
var helper = GetHtmlHelper();
helper.ViewData["StringProperty"] = null;
// Act
var html = helper.Value("StringProperty", format: null);
// Assert
Assert.Empty(html);
}
[Fact(Skip = "$1487, finds 'StringProperty' entry (without prefix) instead.")]
public void ValueInTemplate_GetsValueFromViewData_EvenIfNull()
{
// Arrange
var helper = GetHtmlHelper();
helper.ViewData["Prefix.StringProperty"] = null;
helper.ViewData.TemplateInfo.HtmlFieldPrefix = "Prefix";
// Act
var html = helper.Value("StringProperty", format: null);
// Assert
Assert.Empty(html);
}
// ValueFor
[Fact]
@ -39,7 +141,7 @@ namespace Microsoft.AspNet.Mvc.Core
var helper = GetHtmlHelper();
// Act
var html = helper.ValueFor(m => m.StringProperty);
var html = helper.ValueFor(m => m.StringProperty, format: null);
// Assert
Assert.Equal("ModelStringPropertyValue", html);
@ -76,9 +178,9 @@ namespace Microsoft.AspNet.Mvc.Core
viewData.ModelState["FieldPrefix"] = modelState;
// Act & Assert
Assert.Equal("StringPropertyRawValue", helper.Value("StringProperty"));
Assert.Equal("StringPropertyRawValue", helper.ValueFor(m => m.StringProperty));
Assert.Equal("ModelRawValue", helper.ValueForModel());
Assert.Equal("StringPropertyRawValue", helper.Value("StringProperty", format: null));
Assert.Equal("StringPropertyRawValue", helper.ValueFor(m => m.StringProperty, format: null));
Assert.Equal("ModelRawValue", helper.ValueForModel(format: null));
}
[Fact]
@ -91,10 +193,10 @@ namespace Microsoft.AspNet.Mvc.Core
"{ StringProperty = ModelStringPropertyValue, ObjectProperty = 01/01/1900 00:00:00 }";
// Act & Assert
Assert.Equal(expectedModelValue, helper.Value(expression: string.Empty));
Assert.Equal(expectedModelValue, helper.Value(expression: null)); // null is another alias for current model
Assert.Equal(expectedModelValue, helper.ValueFor(m => m));
Assert.Equal(expectedModelValue, helper.ValueForModel());
Assert.Equal(expectedModelValue, helper.Value(expression: string.Empty, format: null));
Assert.Equal(expectedModelValue, helper.Value(expression: null, format: null)); // null is another alias for current model
Assert.Equal(expectedModelValue, helper.ValueFor(m => m, format: null));
Assert.Equal(expectedModelValue, helper.ValueForModel(format: null));
}
[Fact]
@ -135,7 +237,7 @@ namespace Microsoft.AspNet.Mvc.Core
helper.ValueForModel("<{0}>"));
Assert.Equal("<ViewDataValue <\"\">>", helper.Value("StringProperty", "<{0}>"));
Assert.Equal("<ModelStringPropertyValue <\"\">>", helper.ValueFor(m => m.StringProperty, "<{0}>"));
Assert.Equal("ObjectPropertyRawValue <\"\">", helper.ValueFor(m => m.ObjectProperty));
Assert.Equal("ObjectPropertyRawValue <\"\">", helper.ValueFor(m => m.ObjectProperty, format: null));
}
private sealed class TestModel

View File

@ -3,13 +3,15 @@
<form action="/HtmlGeneration_Home/EmployeeList" method="post">
<div>
<label for="z0__Number">Number</label>
<input data-val="true" data-val-range="The field Number must be between 1 and 100." data-val-range-max="100" data-val-range-min="1" data-val-required="The Number field is required." disabled="disabled" id="z0__Number" name="[0].Number" readonly="readonly" type="text" value="0" />
<input data-val="true" data-val-range="The field Number must be between 1 and 100." data-val-range-max="100" data-val-range-min="1" data-val-required="The Number field is required." disabled="disabled" id="z0__Number" name="[0].Number" readonly="readonly" type="text" value="" />
<input class="form-control" type="number" id="z0__Number" name="[0].Number" value="0" />
</div>
<div>
<label class="employee" for="z0__Name">Name</label>
<textarea id="z0__Name" name="[0].Name">
EmployeeName_0</textarea>
Name value that should not be seen.</textarea>
</div>
<div>
<label class="employee" for="z0__PhoneNumber">PhoneNumber</label>
@ -18,7 +20,10 @@ EmployeeName_0</textarea>
<div>
<label class="employee" for="z0__Gender">Gender</label>
<select data-val="true" data-val-required="The Gender field is required." id="z0__Gender" name="[0].Gender"><option selected="selected">Male</option>
<input disabled="disabled" id="z0__Gender" name="[0].Gender" readonly="readonly" type="radio" value="Female" />
<select id="z0__Gender" name="[0].Gender"><option selected="selected">Male</option>
<option>Female</option>
</select>
</div>
@ -35,13 +40,15 @@ EmployeeName_0</textarea>
</div>
<div>
<label for="z1__Number">Number</label>
<input data-val="true" data-val-range="The field Number must be between 1 and 100." data-val-range-max="100" data-val-range-min="1" data-val-required="The Number field is required." disabled="disabled" id="z1__Number" name="[1].Number" readonly="readonly" type="text" value="1" />
<input data-val="true" data-val-range="The field Number must be between 1 and 100." data-val-range-max="100" data-val-range-min="1" data-val-required="The Number field is required." disabled="disabled" id="z1__Number" name="[1].Number" readonly="readonly" type="text" value="" />
<input class="form-control" type="number" id="z1__Number" name="[1].Number" value="1" />
</div>
<div>
<label class="employee" for="z1__Name">Name</label>
<textarea id="z1__Name" name="[1].Name">
EmployeeName_1</textarea>
Name value that should not be seen.</textarea>
</div>
<div>
<label class="employee" for="z1__PhoneNumber">PhoneNumber</label>
@ -50,7 +57,10 @@ EmployeeName_1</textarea>
<div>
<label class="employee" for="z1__Gender">Gender</label>
<select data-val="true" data-val-required="The Gender field is required." id="z1__Gender" name="[1].Gender"><option>Male</option>
<input disabled="disabled" id="z1__Gender" name="[1].Gender" readonly="readonly" type="radio" value="Female" />
<select id="z1__Gender" name="[1].Gender"><option>Male</option>
<option selected="selected">Female</option>
</select>
</div>
@ -67,13 +77,15 @@ EmployeeName_1</textarea>
</div>
<div>
<label for="z2__Number">Number</label>
<input data-val="true" data-val-range="The field Number must be between 1 and 100." data-val-range-max="100" data-val-range-min="1" data-val-required="The Number field is required." disabled="disabled" id="z2__Number" name="[2].Number" readonly="readonly" type="text" value="2" />
<input data-val="true" data-val-range="The field Number must be between 1 and 100." data-val-range-max="100" data-val-range-min="1" data-val-required="The Number field is required." disabled="disabled" id="z2__Number" name="[2].Number" readonly="readonly" type="text" value="" />
<input class="form-control" type="number" id="z2__Number" name="[2].Number" value="2" />
</div>
<div>
<label class="employee" for="z2__Name">Name</label>
<textarea id="z2__Name" name="[2].Name">
EmployeeName_2</textarea>
Name value that should not be seen.</textarea>
</div>
<div>
<label class="employee" for="z2__PhoneNumber">PhoneNumber</label>
@ -82,7 +94,10 @@ EmployeeName_2</textarea>
<div>
<label class="employee" for="z2__Gender">Gender</label>
<select data-val="true" data-val-required="The Gender field is required." id="z2__Gender" name="[2].Gender"><option selected="selected">Male</option>
<input disabled="disabled" id="z2__Gender" name="[2].Gender" readonly="readonly" type="radio" value="Female" />
<select id="z2__Gender" name="[2].Gender"><option selected="selected">Male</option>
<option>Female</option>
</select>
</div>

View File

@ -1,4 +1,4 @@
<html>
<html>
<head>
<meta charset="utf-8" />
<title></title>
@ -69,7 +69,8 @@
<div>
<label class="HtmlEncode[[order]]" for="HtmlEncode[[Customer_Gender]]">HtmlEncode[[Gender]]</label>
<input data-val="HtmlEncode[[true]]" data-val-required="HtmlEncode[[The Gender field is required.]]" id="HtmlEncode[[Customer_Gender]]" name="HtmlEncode[[Customer.Gender]]" type="HtmlEncode[[radio]]" value="HtmlEncode[[Male]]" /> Male
<input checked="HtmlEncode[[checked]]" id="HtmlEncode[[Customer_Gender]]" name="HtmlEncode[[Customer.Gender]]" type="HtmlEncode[[radio]]" value="HtmlEncode[[Female]]" /> Female
<input id="HtmlEncode[[Customer_Gender]]" name="HtmlEncode[[Customer.Gender]]" type="HtmlEncode[[radio]]" value="HtmlEncode[[Female]]" /> Female
<span class="HtmlEncode[[field-validation-valid]]" data-valmsg-for="HtmlEncode[[Customer.Gender]]" data-valmsg-replace="HtmlEncode[[true]]"></span>
</div>
<div class="HtmlEncode[[validation-summary-valid order]]" data-valmsg-summary="HtmlEncode[[true]]"><ul><li style="display:none"></li>

View File

@ -1,4 +1,4 @@
<html>
<html>
<head>
<meta charset="utf-8" />
<title></title>
@ -69,7 +69,8 @@
<div>
<label class="order" for="Customer_Gender">Gender</label>
<input data-val="true" data-val-required="The Gender field is required." id="Customer_Gender" name="Customer.Gender" type="radio" value="Male" /> Male
<input checked="checked" id="Customer_Gender" name="Customer.Gender" type="radio" value="Female" /> Female
<input id="Customer_Gender" name="Customer.Gender" type="radio" value="Female" /> Female
<span class="field-validation-valid" data-valmsg-for="Customer.Gender" data-valmsg-replace="true"></span>
</div>
<div class="validation-summary-valid order" data-valmsg-summary="true"><ul><li style="display:none"></li>

View File

@ -56,14 +56,14 @@ namespace HtmlGenerationWebSite.Controllers
public IActionResult Order()
{
ViewBag.Items = _productsListWithSelection;
ViewData["Items"] = _productsListWithSelection;
return View(_order);
}
public IActionResult OrderUsingHtmlHelpers()
{
ViewBag.Items = _productsListWithSelection;
ViewData["Items"] = _productsListWithSelection;
return View(_order);
}
@ -124,12 +124,17 @@ namespace HtmlGenerationWebSite.Controllers
},
};
// Extra data that should be ignored within a template. But #1487 currently affects RadioButton and
// TextArea as well as ModelMetadata for <select> tag helper.
ViewData[nameof(Employee.Gender)] = "Gender value that will not match.";
ViewData[nameof(Employee.Name)] = "Name value that should not be seen.";
return View(employees);
}
public IActionResult CreateWarehouse()
{
ViewBag.Items = _productsList;
ViewData["Items"] = _productsList;
return View();
}

View File

@ -4,12 +4,14 @@
<div>
@Html.LabelFor(m => m.Number)
@Html.TextBoxFor(m => m.Number, htmlAttributes: new { disabled = "disabled", @readonly= "readonly" })
@* Due to #1485, text box will be empty though all employees have Number values. *@
@Html.TextBox(nameof(Model.Number), value: null, htmlAttributes: new { disabled = "disabled", @readonly = "readonly" })
<input asp-for="Number" type="number" class="form-control" />
</div>
<div>
<label asp-for="Name" class="employee"></label>
@Html.TextAreaFor(m => m.Name)
@* Due to #1487, text area will contain incorrect "Value that should not be seen." *@
@Html.TextArea(nameof(Model.Name))
</div>
<div>
<label asp-for="PhoneNumber" class="employee"></label>
@ -20,11 +22,14 @@
var genders = new SelectList(new string[] { "Male", "Female" });
}
<label asp-for="Gender" class="employee"></label>
@* Due to #1487, radio button will not be checked. Employee is Female but incorrect information does not match. *@
@Html.RadioButton(nameof(Model.Gender), "Female", htmlAttributes: new { disabled = "disabled", @readonly = "readonly" })
@* Due to #1487, <select> tag helper will not generate expected validation attributes. *@
<select asp-for="Gender" asp-items="genders"></select>
</div>
<div>
<label asp-for="Remote" class="employee"></label>
@Html.CheckBoxFor(m=>m.Remote)
@Html.CheckBoxFor(m => m.Remote)
</div>
<div>
<label asp-for="OfficeNumber" class="employee"></label>

View File

@ -1,4 +1,5 @@
@using HtmlGenerationWebSite.Models
@model Gender
@Html.RadioButtonFor(m => m, value: "Male") Male
@Html.RadioButtonFor(m => m, value: "Female") Female
@* Due to #2662 radio button will not be checked because help ignores this expression." *@
@Html.RadioButton(expression: string.Empty, value: "Female") Female