aspnetcore/test/Microsoft.AspNetCore.Mvc.Vi.../DefaultDisplayTemplatesTest.cs

412 lines
18 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// 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.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.AspNetCore.Mvc.ViewEngines;
using Moq;
using Xunit;
namespace Microsoft.AspNetCore.Mvc.ViewFeatures
{
public class DefaultDisplayTemplatesTest
{
// Input value; HTML encode; expected value.
public static TheoryData<string, bool, string> HtmlEncodeData
{
get
{
return new TheoryData<string, bool, string>
{
{ "Simple Display Text", false, "Simple Display Text" },
{ "Simple Display Text", true, "HtmlEncode[[Simple Display Text]]" },
{ "<blink>text</blink>", false, "<blink>text</blink>" },
{ "<blink>text</blink>", true, "HtmlEncode[[<blink>text</blink>]]" },
{ "&'\"", false, "&'\"" },
{ "&'\"", true, "HtmlEncode[[&'\"]]" },
{ " ¡ÿĀ", false, " ¡ÿĀ" }, // high ASCII
{ " ¡ÿĀ", true, "HtmlEncode[[ ¡ÿĀ]]" },
{ "Chinese西雅图Chars", false, "Chinese西雅图Chars" },
{ "Chinese西雅图Chars", true, "HtmlEncode[[Chinese西雅图Chars]]" },
{ "Unicode؃Format؃Char", false, "Unicode؃Format؃Char" }, // class Cf
{ "Unicode؃Format؃Char", true, "HtmlEncode[[Unicode؃Format؃Char]]" },
{ "UnicodeῼTitlecaseῼChar", false, "UnicodeῼTitlecaseῼChar" }, // class Lt
{ "UnicodeῼTitlecaseῼChar", true, "HtmlEncode[[UnicodeῼTitlecaseῼChar]]" },
{ "UnicodeCombiningChar", false, "UnicodeCombiningChar" }, // class Mc
{ "UnicodeCombiningChar", true, "HtmlEncode[[UnicodeCombiningChar]]" },
};
}
}
[Fact]
public void ObjectTemplateDisplaysSimplePropertiesOnObjectByDefault()
{
var expected =
"<div class=\"HtmlEncode[[display-label]]\">HtmlEncode[[Property1]]</div>" + Environment.NewLine
+ "<div class=\"HtmlEncode[[display-field]]\">Model = p1, ModelType = System.String, PropertyName = Property1," +
" SimpleDisplayText = p1</div>" + Environment.NewLine
+ "<div class=\"HtmlEncode[[display-label]]\">HtmlEncode[[Prop2]]</div>" + Environment.NewLine
+ "<div class=\"HtmlEncode[[display-field]]\">Model = (null), ModelType = System.String, PropertyName = Property2," +
" SimpleDisplayText = (null)</div>" + Environment.NewLine;
// Arrange
var model = new DefaultTemplatesUtilities.ObjectTemplateModel { Property1 = "p1", Property2 = null };
var html = DefaultTemplatesUtilities.GetHtmlHelper(model);
// Act
var result = DefaultDisplayTemplates.ObjectTemplate(html);
// Assert
Assert.Equal(expected, HtmlContentUtilities.HtmlContentToString(result));
}
[Fact]
public void ObjectTemplateDisplaysNullDisplayTextWhenObjectIsNull()
{
// Arrange
var provider = new TestModelMetadataProvider();
provider.ForType<DefaultTemplatesUtilities.ObjectTemplateModel>().DisplayDetails(dd =>
{
dd.NullDisplayText = "(null value)";
});
var html = DefaultTemplatesUtilities.GetHtmlHelper(provider: provider);
// Act
var result = DefaultDisplayTemplates.ObjectTemplate(html);
// Assert
Assert.Equal("(null value)", HtmlContentUtilities.HtmlContentToString(result));
}
[Theory]
[MemberData(nameof(HtmlEncodeData))]
public void ObjectTemplateDisplaysSimpleDisplayTextWhenTemplateDepthGreaterThanOne(
string simpleDisplayText,
bool htmlEncode,
string expectedResult)
{
// Arrange
var model = new DefaultTemplatesUtilities.ObjectTemplateModel();
model.Property1 = simpleDisplayText;
var provider = new TestModelMetadataProvider();
provider.ForType<DefaultTemplatesUtilities.ObjectTemplateModel>().DisplayDetails(dd =>
{
dd.HtmlEncode = htmlEncode;
dd.SimpleDisplayProperty = "Property1";
});
var html = DefaultTemplatesUtilities.GetHtmlHelper(model, provider);
html.ViewData.TemplateInfo.AddVisited("foo");
html.ViewData.TemplateInfo.AddVisited("bar");
// Act
var result = DefaultDisplayTemplates.ObjectTemplate(html);
// Assert
Assert.Equal(expectedResult, HtmlContentUtilities.HtmlContentToString(result));
}
[Fact]
public void ObjectTemplate_IgnoresPropertiesWith_ScaffoldColumnFalse()
{
// Arrange
var expected = "<div class=\"HtmlEncode[[display-label]]\">HtmlEncode[[Property1]]</div>" + Environment.NewLine +
"<div class=\"HtmlEncode[[display-field]]\"></div>" + Environment.NewLine +
"<div class=\"HtmlEncode[[display-label]]\">HtmlEncode[[Property3]]</div>" + Environment.NewLine +
"<div class=\"HtmlEncode[[display-field]]\"></div>" + Environment.NewLine;
var model = new DefaultTemplatesUtilities.ObjectWithScaffoldColumn();
var viewEngine = new Mock<ICompositeViewEngine>(MockBehavior.Strict);
viewEngine
.Setup(v => v.GetView(/*executingFilePath*/ null, It.IsAny<string>(), /*isMainPage*/ false))
.Returns(ViewEngineResult.NotFound(string.Empty, Enumerable.Empty<string>()));
viewEngine
.Setup(v => v.FindView(It.IsAny<ActionContext>(), It.IsAny<string>(), /*isMainPage*/ false))
.Returns(ViewEngineResult.NotFound(string.Empty, Enumerable.Empty<string>()));
var htmlHelper = DefaultTemplatesUtilities.GetHtmlHelper(model, viewEngine.Object);
// Act
var result = DefaultDisplayTemplates.ObjectTemplate(htmlHelper);
// Assert
Assert.Equal(expected, HtmlContentUtilities.HtmlContentToString(result));
}
[Fact]
public void ObjectTemplate_HonorsHideSurroundingHtml()
{
// Arrange
var expected =
"Model = p1, ModelType = System.String, PropertyName = Property1, SimpleDisplayText = p1" +
"<div class=\"HtmlEncode[[display-label]]\">HtmlEncode[[Prop2]]</div>" + Environment.NewLine +
"<div class=\"HtmlEncode[[display-field]]\">Model = (null), ModelType = System.String, PropertyName = Property2," +
" SimpleDisplayText = (null)</div>" + Environment.NewLine;
var model = new DefaultTemplatesUtilities.ObjectTemplateModel { Property1 = "p1", Property2 = null };
var provider = new TestModelMetadataProvider();
provider.ForProperty<DefaultTemplatesUtilities.ObjectTemplateModel>("Property1").DisplayDetails(dd =>
{
dd.HideSurroundingHtml = true;
});
var html = DefaultTemplatesUtilities.GetHtmlHelper(model, provider);
// Act
var result = DefaultDisplayTemplates.ObjectTemplate(html);
// Assert
Assert.Equal(expected, HtmlContentUtilities.HtmlContentToString(result));
}
[Fact]
public void ObjectTemplate_OrdersProperties_AsExpected()
{
// Arrange
var model = new OrderedModel();
var html = DefaultTemplatesUtilities.GetHtmlHelper(model);
var expectedProperties = new List<string>
{
"OrderedProperty3",
"OrderedProperty2",
"OrderedProperty1",
"Property3",
"Property1",
"Property2",
"LastProperty",
};
var stringBuilder = new StringBuilder();
foreach (var property in expectedProperties)
{
var label = string.Format(
CultureInfo.InvariantCulture,
"<div class=\"HtmlEncode[[display-label]]\">HtmlEncode[[{0}]]</div>",
property);
stringBuilder.AppendLine(label);
var value = string.Format(
CultureInfo.InvariantCulture,
"<div class=\"HtmlEncode[[display-field]]\">Model = (null), ModelType = System.String, PropertyName = {0}, " +
"SimpleDisplayText = (null)</div>",
property);
stringBuilder.AppendLine(value);
}
var expected = stringBuilder.ToString();
// Act
var result = DefaultDisplayTemplates.ObjectTemplate(html);
// Assert
Assert.Equal(expected, HtmlContentUtilities.HtmlContentToString(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("HtmlEncode[[Formatted string]]", HtmlContentUtilities.HtmlContentToString(result));
}
[Fact]
public void HiddenInputTemplate_HonorsHideSurroundingHtml()
{
// Arrange
var model = "Model string";
var provider = new TestModelMetadataProvider();
provider.ForType<string>().DisplayDetails(dd =>
{
dd.HideSurroundingHtml = true;
});
var html = DefaultTemplatesUtilities.GetHtmlHelper(model, provider: provider);
var viewData = html.ViewData;
var templateInfo = viewData.TemplateInfo;
templateInfo.HtmlFieldPrefix = "FieldPrefix";
templateInfo.FormattedModelValue = "Formatted string";
// Act
var result = DefaultDisplayTemplates.HiddenInputTemplate(html);
// Assert
Assert.Empty(HtmlContentUtilities.HtmlContentToString(result));
}
[Fact]
public void Display_FindsViewDataMember()
{
// Arrange
var model = new DefaultTemplatesUtilities.ObjectTemplateModel { Property1 = "Model string" };
var viewEngine = new Mock<ICompositeViewEngine>(MockBehavior.Strict);
viewEngine
.Setup(v => v.GetView(/*executingFilePath*/ null, It.IsAny<string>(), /*isMainPage*/ false))
.Returns(ViewEngineResult.NotFound(string.Empty, Enumerable.Empty<string>()));
viewEngine
.Setup(v => v.FindView(It.IsAny<ActionContext>(), It.IsAny<string>(), /*isMainPage*/ false))
.Returns(ViewEngineResult.NotFound(string.Empty, Enumerable.Empty<string>()));
var helper = DefaultTemplatesUtilities.GetHtmlHelper(model, viewEngine.Object);
helper.ViewData["Property1"] = "ViewData string";
// Act
var result = helper.Display("Property1");
// Assert
Assert.Equal("HtmlEncode[[ViewData string]]", HtmlContentUtilities.HtmlContentToString(result));
}
[Fact]
public void DisplayFor_FindsModel()
{
// Arrange
var model = new DefaultTemplatesUtilities.ObjectTemplateModel { Property1 = "Model string" };
var viewEngine = new Mock<ICompositeViewEngine>(MockBehavior.Strict);
viewEngine
.Setup(v => v.GetView(/*executingFilePath*/ null, It.IsAny<string>(), /*isMainPage*/ false))
.Returns(ViewEngineResult.NotFound(string.Empty, Enumerable.Empty<string>()));
viewEngine
.Setup(v => v.FindView(It.IsAny<ActionContext>(), It.IsAny<string>(), /*isMainPage*/ false))
.Returns(ViewEngineResult.NotFound(string.Empty, Enumerable.Empty<string>()));
var helper = DefaultTemplatesUtilities.GetHtmlHelper(model, viewEngine.Object);
helper.ViewData["Property1"] = "ViewData string";
// Act
var result = helper.DisplayFor(m => m.Property1);
// Assert
Assert.Equal("HtmlEncode[[Model string]]", HtmlContentUtilities.HtmlContentToString(result));
}
[Fact]
public void Display_FindsModel_IfNoViewDataMember()
{
// Arrange
var model = new DefaultTemplatesUtilities.ObjectTemplateModel { Property1 = "Model string" };
var viewEngine = new Mock<ICompositeViewEngine>(MockBehavior.Strict);
viewEngine
.Setup(v => v.GetView(/*executingFilePath*/ null, It.IsAny<string>(), /*isMainPage*/ false))
.Returns(ViewEngineResult.NotFound(string.Empty, Enumerable.Empty<string>()));
viewEngine
.Setup(v => v.FindView(It.IsAny<ActionContext>(), It.IsAny<string>(), /*isMainPage*/ false))
.Returns(ViewEngineResult.NotFound(string.Empty, Enumerable.Empty<string>()));
var helper = DefaultTemplatesUtilities.GetHtmlHelper(model, viewEngine.Object);
// Act
var result = helper.Display("Property1");
// Assert
Assert.Equal("HtmlEncode[[Model string]]", HtmlContentUtilities.HtmlContentToString(result));
}
[Theory]
[InlineData(null)]
[InlineData("")]
public void DisplayFor_FindsModel_EvenIfNullOrEmpty(string propertyValue)
{
// Arrange
var model = new DefaultTemplatesUtilities.ObjectTemplateModel { Property1 = propertyValue, };
var viewEngine = new Mock<ICompositeViewEngine>(MockBehavior.Strict);
viewEngine
.Setup(v => v.GetView(/*executingFilePath*/ null, It.IsAny<string>(), /*isMainPage*/ false))
.Returns(ViewEngineResult.NotFound(string.Empty, Enumerable.Empty<string>()));
viewEngine
.Setup(v => v.FindView(It.IsAny<ActionContext>(), It.IsAny<string>(), /*isMainPage*/ false))
.Returns(ViewEngineResult.NotFound(string.Empty, Enumerable.Empty<string>()));
var helper = DefaultTemplatesUtilities.GetHtmlHelper(model, viewEngine.Object);
helper.ViewData["Property1"] = "ViewData string";
// Act
var result = helper.DisplayFor(m => m.Property1);
// Assert
Assert.Equal(string.Empty, HtmlContentUtilities.HtmlContentToString(result));
}
[Fact]
public void DisplayFor_DoesNotWrapExceptionThrowsDuringViewRendering()
{
// Arrange
var expectedMessage = "my exception message";
var model = new DefaultTemplatesUtilities.ObjectTemplateModel { Property1 = "Test string", };
var view = new Mock<IView>();
view.Setup(v => v.RenderAsync(It.IsAny<ViewContext>()))
.Returns(Task.Run(() =>
{
throw new ArgumentException(expectedMessage);
}));
var viewEngine = new Mock<ICompositeViewEngine>(MockBehavior.Strict);
viewEngine
.Setup(v => v.GetView(/*executingFilePath*/ null, It.IsAny<string>(), /*isMainPage*/ false))
.Returns(ViewEngineResult.NotFound(string.Empty, Enumerable.Empty<string>()));
viewEngine
.Setup(v => v.FindView(It.IsAny<ActionContext>(), It.IsAny<string>(), /*isMainPage*/ false))
.Returns(ViewEngineResult.Found("test-view", view.Object));
var helper = DefaultTemplatesUtilities.GetHtmlHelper(model, viewEngine.Object);
helper.ViewData["Property1"] = "ViewData string";
// Act and Assert
var ex = Assert.Throws<ArgumentException>(() => helper.DisplayFor(m => m.Property1));
Assert.Equal(expectedMessage, ex.Message);
}
[Fact]
public void Display_CallsFindView_WithExpectedPath()
{
// Arrange
var viewEngine = new Mock<ICompositeViewEngine>(MockBehavior.Strict);
viewEngine
.Setup(v => v.GetView(/*executingFilePath*/ null, It.IsAny<string>(), /*isMainPage*/ false))
.Returns(ViewEngineResult.NotFound(string.Empty, Enumerable.Empty<string>()));
viewEngine
.Setup(v => v.FindView(It.IsAny<ActionContext>(), "DisplayTemplates/String", /*isMainPage*/ false))
.Returns(ViewEngineResult.Found(string.Empty, new Mock<IView>().Object))
.Verifiable();
var html = DefaultTemplatesUtilities.GetHtmlHelper(new object(), viewEngine: viewEngine.Object);
// Act & Assert
html.Display(expression: string.Empty, templateName: null, htmlFieldName: null, additionalViewData: null);
viewEngine.Verify();
}
private class OrderedModel
{
[Display(Order = 10001)]
public string LastProperty { get; set; }
public string Property3 { get; set; }
public string Property1 { get; set; }
public string Property2 { get; set; }
[Display(Order = 23)]
public string OrderedProperty3 { get; set; }
[Display(Order = 23)]
public string OrderedProperty2 { get; set; }
[Display(Order = 23)]
public string OrderedProperty1 { get; set; }
}
}
}