diff --git a/test/Microsoft.AspNet.Mvc.Core.Test/Rendering/DefaultDisplayTemplatesTests.cs b/test/Microsoft.AspNet.Mvc.Core.Test/Rendering/DefaultDisplayTemplatesTests.cs
index f9ab3f19d8..cb7155f3ce 100644
--- a/test/Microsoft.AspNet.Mvc.Core.Test/Rendering/DefaultDisplayTemplatesTests.cs
+++ b/test/Microsoft.AspNet.Mvc.Core.Test/Rendering/DefaultDisplayTemplatesTests.cs
@@ -97,6 +97,68 @@ namespace Microsoft.AspNet.Mvc.Core
Assert.Equal(expected, result);
}
+ [Fact]
+ public void ObjectTemplate_HonoursHideSurroundingHtml()
+ {
+ // Arrange
+ var expected =
+ "Model = p1, ModelType = System.String, PropertyName = Property1, SimpleDisplayText = p1" +
+ "
Property2
" + 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 = DefaultDisplayTemplates.ObjectTemplate(html);
+
+ // Assert
+ Assert.Equal(expected, result);
+ }
+
+ [Fact]
+ public void HiddenInputTemplate_ReturnsValue()
+ {
+ // Arrange
+ 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 = DefaultDisplayTemplates.HiddenInputTemplate(html);
+
+ // Assert
+ Assert.Equal("Formatted string", result);
+ }
+
+ [Fact]
+ public void HiddenInputTemplate_HonoursHideSurroundingHtml()
+ {
+ // Arrange
+ 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 = DefaultDisplayTemplates.HiddenInputTemplate(html);
+
+ // Assert
+ Assert.Empty(result);
+ }
+
[Fact]
public void Display_FindsViewDataMember()
{
diff --git a/test/Microsoft.AspNet.Mvc.Core.Test/Rendering/DefaultEditorTemplatesTests.cs b/test/Microsoft.AspNet.Mvc.Core.Test/Rendering/DefaultEditorTemplatesTests.cs
index 7996a4af89..e18f9012d3 100644
--- a/test/Microsoft.AspNet.Mvc.Core.Test/Rendering/DefaultEditorTemplatesTests.cs
+++ b/test/Microsoft.AspNet.Mvc.Core.Test/Rendering/DefaultEditorTemplatesTests.cs
@@ -111,6 +111,77 @@ Environment.NewLine;
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()
{
diff --git a/test/Microsoft.AspNet.Mvc.ModelBinding.Test/Metadata/CachedDataAnnotationsMetadataAttributesTest.cs b/test/Microsoft.AspNet.Mvc.ModelBinding.Test/Metadata/CachedDataAnnotationsMetadataAttributesTest.cs
index 571d99ef0e..9c65f93877 100644
--- a/test/Microsoft.AspNet.Mvc.ModelBinding.Test/Metadata/CachedDataAnnotationsMetadataAttributesTest.cs
+++ b/test/Microsoft.AspNet.Mvc.ModelBinding.Test/Metadata/CachedDataAnnotationsMetadataAttributesTest.cs
@@ -27,6 +27,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
Assert.Null(cache.DisplayColumn);
Assert.Null(cache.DisplayFormat);
Assert.Null(cache.Editable);
+ Assert.Null(cache.HiddenInput);
Assert.Null(cache.Required);
}
@@ -37,26 +38,12 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
{
return new TheoryData>
{
- {
- new DisplayAttribute(),
- (CachedDataAnnotationsMetadataAttributes cache) => cache.Display
- },
- {
- new DisplayColumnAttribute("Property"),
- (CachedDataAnnotationsMetadataAttributes cache) => cache.DisplayColumn
- },
- {
- new DisplayFormatAttribute(),
- (CachedDataAnnotationsMetadataAttributes cache) => cache.DisplayFormat
- },
- {
- new EditableAttribute(allowEdit: false),
- (CachedDataAnnotationsMetadataAttributes cache) => cache.Editable
- },
- {
- new RequiredAttribute(),
- (CachedDataAnnotationsMetadataAttributes cache) => cache.Required
- },
+ { new DisplayAttribute(), cache => cache.Display },
+ { new DisplayColumnAttribute("Property"), cache => cache.DisplayColumn },
+ { new DisplayFormatAttribute(), cache => cache.DisplayFormat },
+ { new EditableAttribute(allowEdit: false), cache => cache.Editable },
+ { new HiddenInputAttribute(), cache => cache.HiddenInput },
+ { new RequiredAttribute(), cache => cache.Required },
};
}
}
diff --git a/test/Microsoft.AspNet.Mvc.ModelBinding.Test/Metadata/CachedDataAnnotationsModelMetadataTest.cs b/test/Microsoft.AspNet.Mvc.ModelBinding.Test/Metadata/CachedDataAnnotationsModelMetadataTest.cs
index 3af0eefeec..df28e580e7 100644
--- a/test/Microsoft.AspNet.Mvc.ModelBinding.Test/Metadata/CachedDataAnnotationsModelMetadataTest.cs
+++ b/test/Microsoft.AspNet.Mvc.ModelBinding.Test/Metadata/CachedDataAnnotationsModelMetadataTest.cs
@@ -30,12 +30,23 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
// Assert
Assert.True(metadata.ConvertEmptyStringToNull);
+ Assert.False(metadata.HideSurroundingHtml);
+ Assert.True(metadata.IsComplexType);
Assert.False(metadata.IsReadOnly);
Assert.False(metadata.IsRequired);
+ Assert.True(metadata.ShowForDisplay);
+ Assert.True(metadata.ShowForEdit);
+ Assert.Null(metadata.DataTypeName);
Assert.Null(metadata.Description);
+ Assert.Null(metadata.DisplayFormatString);
Assert.Null(metadata.DisplayName);
+ Assert.Null(metadata.EditFormatString);
Assert.Null(metadata.NullDisplayText);
+ Assert.Null(metadata.SimpleDisplayText);
+ Assert.Null(metadata.TemplateHint);
+
+ Assert.Equal(ModelMetadata.DefaultOrder, metadata.Order);
}
public static TheoryData> ExpectedAttributeDataStrings
@@ -45,20 +56,16 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
return new TheoryData>
{
{
- new DisplayAttribute { Description = "value" },
- (ModelMetadata metadata) => metadata.Description
+ new DisplayAttribute { Description = "value" }, metadata => metadata.Description
},
{
- new DisplayAttribute { Name = "value" },
- (ModelMetadata metadata) => metadata.DisplayName
+ new DisplayAttribute { Name = "value" }, metadata => metadata.DisplayName
},
{
- new DisplayColumnAttribute("Property"),
- (ModelMetadata metadata) => metadata.SimpleDisplayText
+ new DisplayColumnAttribute("Property"), metadata => metadata.SimpleDisplayText
},
{
- new DisplayFormatAttribute { NullDisplayText = "value" },
- (ModelMetadata metadata) => metadata.NullDisplayText
+ new DisplayFormatAttribute { NullDisplayText = "value" }, metadata => metadata.NullDisplayText
},
};
}
@@ -71,8 +78,6 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
// Arrange
var attributes = new[] { attribute };
var provider = new DataAnnotationsModelMetadataProvider();
-
- // Act
var metadata = new CachedDataAnnotationsModelMetadata(
provider,
containerType: null,
@@ -82,6 +87,8 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
{
Model = new ClassWithDisplayableColumn { Property = "value" },
};
+
+ // Act
var result = accessor(metadata);
// Assert
@@ -96,27 +103,37 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
{
{
new DisplayFormatAttribute { ConvertEmptyStringToNull = false },
- (ModelMetadata metadata) => metadata.ConvertEmptyStringToNull,
+ metadata => metadata.ConvertEmptyStringToNull,
false
},
{
new DisplayFormatAttribute { ConvertEmptyStringToNull = true },
- (ModelMetadata metadata) => metadata.ConvertEmptyStringToNull,
+ metadata => metadata.ConvertEmptyStringToNull,
true
},
{
new EditableAttribute(allowEdit: false),
- (ModelMetadata metadata) => metadata.IsReadOnly,
+ metadata => metadata.IsReadOnly,
true
},
{
new EditableAttribute(allowEdit: true),
- (ModelMetadata metadata) => metadata.IsReadOnly,
+ metadata => metadata.IsReadOnly,
+ false
+ },
+ {
+ new HiddenInputAttribute { DisplayValue = false },
+ metadata => metadata.HideSurroundingHtml,
+ true
+ },
+ {
+ new HiddenInputAttribute { DisplayValue = true },
+ metadata => metadata.HideSurroundingHtml,
false
},
{
new RequiredAttribute(),
- (ModelMetadata metadata) => metadata.IsRequired,
+ metadata => metadata.IsRequired,
true
},
};
@@ -133,23 +150,67 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
// Arrange
var attributes = new[] { attribute };
var provider = new DataAnnotationsModelMetadataProvider();
-
- // Act
var metadata = new CachedDataAnnotationsModelMetadata(
provider,
containerType: null,
modelType: typeof(object),
propertyName: null,
attributes: attributes);
+
+ // Act
var result = accessor(metadata);
// Assert
Assert.Equal(expectedResult, result);
}
+ [Fact]
+ public void HiddenInputWorksOnProperty()
+ {
+ // Arrange
+ var provider = new DataAnnotationsModelMetadataProvider();
+ var metadata = provider.GetMetadataForType(modelAccessor: null, modelType: typeof(ClassWithHiddenProperties));
+ var property = metadata.Properties.First(m => string.Equals("DirectlyHidden", m.PropertyName));
+
+ // Act
+ var result = property.HideSurroundingHtml;
+
+ // Assert
+ Assert.True(result);
+ }
+
+ // TODO #1000; enable test once we detect attributes on the property's type
+ public void HiddenInputWorksOnPropertyType()
+ {
+ // Arrange
+ var provider = new DataAnnotationsModelMetadataProvider();
+ var metadata = provider.GetMetadataForType(modelAccessor: null, modelType: typeof(ClassWithHiddenProperties));
+ var property = metadata.Properties.First(m => string.Equals("OfHiddenType", m.PropertyName));
+
+ // Act
+ var result = property.HideSurroundingHtml;
+
+ // Assert
+ Assert.True(result);
+ }
+
private class ClassWithDisplayableColumn
{
public string Property { get; set; }
}
+
+ [HiddenInput(DisplayValue = false)]
+ private class HiddenClass
+ {
+ public string Property { get; set; }
+ }
+
+ private class ClassWithHiddenProperties
+ {
+ [HiddenInput(DisplayValue = false)]
+ public string DirectlyHidden { get; set; }
+
+ public HiddenClass OfHiddenType { get; set; }
+ }
}
}
\ No newline at end of file
diff --git a/test/Microsoft.AspNet.Mvc.ModelBinding.Test/Metadata/ModelMetadataTest.cs b/test/Microsoft.AspNet.Mvc.ModelBinding.Test/Metadata/ModelMetadataTest.cs
index 3daac32738..25ea719d90 100644
--- a/test/Microsoft.AspNet.Mvc.ModelBinding.Test/Metadata/ModelMetadataTest.cs
+++ b/test/Microsoft.AspNet.Mvc.ModelBinding.Test/Metadata/ModelMetadataTest.cs
@@ -13,6 +13,33 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
{
public class ModelMetadataTest
{
+ public static TheoryData, Func, object> MetadataModifierData
+ {
+ get
+ {
+ return new TheoryData, Func, object>
+ {
+ { m => m.ConvertEmptyStringToNull = false, m => m.ConvertEmptyStringToNull, false },
+ { m => m.HideSurroundingHtml = true, m => m.HideSurroundingHtml, true },
+ { m => m.IsReadOnly = true, m => m.IsReadOnly, true },
+ { m => m.IsRequired = true, m => m.IsRequired, true },
+ { m => m.ShowForDisplay = false, m => m.ShowForDisplay, false },
+ { m => m.ShowForEdit = false, m => m.ShowForEdit, false },
+
+ { m => m.DataTypeName = "New data type name", m => m.DataTypeName, "New data type name" },
+ { m => m.Description = "New description", m => m.Description, "New description" },
+ { m => m.DisplayFormatString = "New display format", m => m.DisplayFormatString, "New display format" },
+ { m => m.DisplayName = "New display name", m => m.DisplayName, "New display name" },
+ { m => m.EditFormatString = "New edit format", m => m.EditFormatString, "New edit format" },
+ { m => m.NullDisplayText = "New null display", m => m.NullDisplayText, "New null display" },
+ { m => m.SimpleDisplayText = "New simple display", m => m.SimpleDisplayText, "New simple display" },
+ { m => m.TemplateHint = "New template hint", m => m.TemplateHint, "New template hint" },
+
+ { m => m.Order = 23, m => m.Order, 23 },
+ };
+ }
+ }
+
#if NET45
// Constructor
@@ -27,11 +54,17 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
// Assert
Assert.Equal(typeof(Exception), metadata.ContainerType);
+
Assert.True(metadata.ConvertEmptyStringToNull);
+ Assert.False(metadata.HideSurroundingHtml);
Assert.False(metadata.IsComplexType);
+ Assert.False(metadata.IsNullableValueType);
Assert.False(metadata.IsReadOnly);
Assert.False(metadata.IsRequired);
+ Assert.True(metadata.ShowForDisplay);
+ Assert.True(metadata.ShowForEdit);
+ Assert.Null(metadata.DataTypeName);
Assert.Null(metadata.Description);
Assert.Null(metadata.DisplayFormatString);
Assert.Null(metadata.DisplayName);
@@ -41,8 +74,11 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
Assert.Equal("model", metadata.Model);
Assert.Equal("model", metadata.SimpleDisplayText);
+ Assert.Equal(typeof(string), metadata.RealModelType);
Assert.Equal(typeof(string), metadata.ModelType);
Assert.Equal("propertyName", metadata.PropertyName);
+
+ Assert.Equal(ModelMetadata.DefaultOrder, metadata.Order);
}
#endif
@@ -188,6 +224,78 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
Assert.Equal("Prop2", newProp.PropertyName);
}
+ [Fact]
+ public void PropertiesSetOnce()
+ {
+ // Arrange
+ var provider = new EmptyModelMetadataProvider();
+ var metadata = new ModelMetadata(
+ provider,
+ containerType: null,
+ modelAccessor: () => new Class1(),
+ modelType: typeof(Class1),
+ propertyName: null);
+
+ // Act
+ var firstPropertiesEvaluation = metadata.Properties;
+ var secondPropertiesEvaluation = metadata.Properties;
+
+ // Assert
+ // Same IEnumerable object.
+ Assert.Same(firstPropertiesEvaluation, secondPropertiesEvaluation);
+ }
+
+ [Fact]
+ public void PropertiesEnumerationEvaluatedOnce()
+ {
+ // Arrange
+ var provider = new EmptyModelMetadataProvider();
+ var metadata = new ModelMetadata(
+ provider,
+ containerType: null,
+ modelAccessor: () => new Class1(),
+ modelType: typeof(Class1),
+ propertyName: null);
+
+ // Act
+ var firstPropertiesEvaluation = metadata.Properties.ToList();
+ var secondPropertiesEvaluation = metadata.Properties.ToList();
+
+ // Assert
+ // Identical ModelMetadata objects every time we run through the Properties collection.
+ Assert.Equal(firstPropertiesEvaluation, secondPropertiesEvaluation);
+ }
+
+ [Theory]
+ [MemberData("MetadataModifierData")]
+ public void PropertiesPropertyChangesPersist(
+ Action setter,
+ Func getter,
+ object expected)
+ {
+ // Arrange
+ var provider = new EmptyModelMetadataProvider();
+ var metadata = new ModelMetadata(
+ provider,
+ containerType: null,
+ modelAccessor: () => new Class1(),
+ modelType: typeof(Class1),
+ propertyName: null);
+
+ // Act
+ foreach (var property in metadata.Properties)
+ {
+ setter(property);
+ }
+
+ // Assert
+ foreach (var property in metadata.Properties)
+ {
+ // Due to boxing of structs, can't Assert.Same().
+ Assert.Equal(expected, getter(property));
+ }
+ }
+
private class Class1
{
public string Prop1 { get; set; }
@@ -315,6 +423,31 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
public Class1 Prop1 { get; set; }
}
+ [Theory]
+ [MemberData("MetadataModifierData")]
+ public void PropertyChangesPersist(
+ Action setter,
+ Func getter,
+ object expected)
+ {
+ // Arrange
+ var provider = new EmptyModelMetadataProvider();
+ var metadata = new ModelMetadata(
+ provider,
+ containerType: null,
+ modelAccessor: () => new Class1(),
+ modelType: typeof(Class1),
+ propertyName: null);
+
+ // Act
+ setter(metadata);
+ var result = getter(metadata);
+
+ // Assert
+ // Due to boxing of structs, can't Assert.Same().
+ Assert.Equal(expected, result);
+ }
+
// Helpers
private class DummyContactModel