From 8b5931d7585b74fa110e31d15f58ff539e2fcb90 Mon Sep 17 00:00:00 2001 From: Doug Bunting Date: Tue, 16 Jun 2015 18:48:07 -0700 Subject: [PATCH] Add `Encode()` and `Raw()` overrides to `IHtmlHelper` - #2392 - `dynamic` does not work correctly when inherited from a base `interface` --- .../Rendering/IHtmlHelperOfT.cs | 12 + .../Rendering/HtmlHelperTest.cs | 238 ++++++++++++++++++ 2 files changed, 250 insertions(+) diff --git a/src/Microsoft.AspNet.Mvc.Extensions/Rendering/IHtmlHelperOfT.cs b/src/Microsoft.AspNet.Mvc.Extensions/Rendering/IHtmlHelperOfT.cs index 8dae92c1bd..5640d13f50 100644 --- a/src/Microsoft.AspNet.Mvc.Extensions/Rendering/IHtmlHelperOfT.cs +++ b/src/Microsoft.AspNet.Mvc.Extensions/Rendering/IHtmlHelperOfT.cs @@ -171,6 +171,12 @@ HtmlString EditorFor( string htmlFieldName, object additionalViewData); + /// + new string Encode(object value); + + /// + new string Encode(string value); + /// /// Returns an <input> element of type "hidden" for the specified . /// @@ -333,6 +339,12 @@ HtmlString RadioButtonFor( [NotNull] object value, object htmlAttributes); + /// + new HtmlString Raw(object value); + + /// + new HtmlString Raw(string value); + /// /// Returns a <textarea> element for the specified . /// diff --git a/test/Microsoft.AspNet.Mvc.Extensions.Test/Rendering/HtmlHelperTest.cs b/test/Microsoft.AspNet.Mvc.Extensions.Test/Rendering/HtmlHelperTest.cs index c55e291ca1..f86e5ed154 100644 --- a/test/Microsoft.AspNet.Mvc.Extensions.Test/Rendering/HtmlHelperTest.cs +++ b/test/Microsoft.AspNet.Mvc.Extensions.Test/Rendering/HtmlHelperTest.cs @@ -42,6 +42,98 @@ public static TheoryData> IgnoreCaseTestDat } } + // value, expectedString + public static TheoryData EncodeDynamicTestData + { + get + { + var data = new TheoryData + { + { null, string.Empty }, + // Dynamic implementation calls the string overload when possible. + { string.Empty, string.Empty }, + { "<\">", "HtmlEncode[[<\">]]" }, + { "
", "HtmlEncode[[
]]" }, + { "bold", "HtmlEncode[[bold]]" }, + { new ObjectWithToStringOverride(), "HtmlEncode[[boldFromObject]]" }, + }; + + return data; + } + } + + // value, expectedString + public static TheoryData EncodeObjectTestData + { + get + { + var data = new TheoryData + { + { null, string.Empty }, + // Object overload does not special case the empty string. + { string.Empty, "HtmlEncode[[]]" }, + { "<\">", "HtmlEncode[[<\">]]" }, + { "
", "HtmlEncode[[
]]" }, + { "bold", "HtmlEncode[[bold]]" }, + { new ObjectWithToStringOverride(), "HtmlEncode[[boldFromObject]]" }, + }; + + return data; + } + } + + // value, expectedString + public static TheoryData EncodeStringTestData + { + get + { + return new TheoryData + { + { null, string.Empty }, + // String overload does not encode the empty string. + { string.Empty, string.Empty }, + { "<\">", "HtmlEncode[[<\">]]" }, + { "
", "HtmlEncode[[
]]" }, + { "bold", "HtmlEncode[[bold]]" }, + }; + } + } + + // value, expectedString + public static TheoryData RawObjectTestData + { + get + { + var data = new TheoryData + { + { new ObjectWithToStringOverride(), "boldFromObject" }, + }; + + foreach (var item in RawStringTestData) + { + data.Add(item[0], (string)item[1]); + } + + return data; + } + } + + // value, expectedString + public static TheoryData RawStringTestData + { + get + { + return new TheoryData + { + { null, null }, + { string.Empty, string.Empty }, + { "<\">", "<\">" }, + { "
", "
" }, + { "bold", "bold" }, + }; + } + } + [Theory] [MemberData(nameof(IgnoreCaseTestData))] public void AnonymousObjectToHtmlAttributes_IgnoresPropertyCase(object htmlAttributeObject, @@ -54,5 +146,151 @@ public void AnonymousObjectToHtmlAttributes_IgnoresPropertyCase(object htmlAttri var entry = Assert.Single(result); Assert.Equal(expectedEntry, entry); } + + [Theory] + [MemberData(nameof(EncodeDynamicTestData))] + public void EncodeDynamic_ReturnsExpectedString(object value, string expectedString) + { + // Arrange + // Important to preserve these particular variable types. Otherwise may end up testing different runtime + // (not compiler) behaviors. + dynamic dynamicValue = value; + IHtmlHelper helper = + DefaultTemplatesUtilities.GetHtmlHelper(); + + // Act + var result = helper.Encode(dynamicValue); + + // Assert + Assert.Equal(expectedString, result); + } + + [Theory] + [MemberData(nameof(EncodeDynamicTestData))] + public void EncodeDynamic_ReturnsExpectedString_WithBaseHelper(object value, string expectedString) + { + // Arrange + // Important to preserve these particular variable types. Otherwise may end up testing different runtime + // (not compiler) behaviors. + dynamic dynamicValue = value; + IHtmlHelper helper = DefaultTemplatesUtilities.GetHtmlHelper(); + + // Act + var result = helper.Encode(dynamicValue); + + // Assert + Assert.Equal(expectedString, result); + } + + [Theory] + [MemberData(nameof(EncodeObjectTestData))] + public void EncodeObject_ReturnsExpectedString(object value, string expectedString) + { + // Arrange + // Important to preserve this particular variable type and the (object) type of the value parameter. + // Otherwise may end up testing different runtime (not compiler) behaviors. + IHtmlHelper helper = + DefaultTemplatesUtilities.GetHtmlHelper(); + + // Act + var result = helper.Encode(value); + + // Assert + Assert.Equal(expectedString, result); + } + + [Theory] + [MemberData(nameof(EncodeStringTestData))] + public void EncodeString_ReturnsExpectedString(string value, string expectedString) + { + // Arrange + // Important to preserve this particular variable type and the (string) type of the value parameter. + // Otherwise may end up testing different runtime (not compiler) behaviors. + IHtmlHelper helper = + DefaultTemplatesUtilities.GetHtmlHelper(); + + // Act + var result = helper.Encode(value); + + // Assert + Assert.Equal(expectedString, result); + } + + [Theory] + [MemberData(nameof(RawObjectTestData))] + public void RawDynamic_ReturnsExpectedString(object value, string expectedString) + { + // Arrange + // Important to preserve these particular variable types. Otherwise may end up testing different runtime + // (not compiler) behaviors. + dynamic dynamicValue = value; + IHtmlHelper helper = + DefaultTemplatesUtilities.GetHtmlHelper(); + + // Act + var result = helper.Raw(dynamicValue); + + // Assert + Assert.Equal(expectedString, result.ToString()); + } + + [Theory] + [MemberData(nameof(RawObjectTestData))] + public void RawDynamic_ReturnsExpectedString_WithBaseHelper(object value, string expectedString) + { + // Arrange + // Important to preserve these particular variable types. Otherwise may end up testing different runtime + // (not compiler) behaviors. + dynamic dynamicValue = value; + IHtmlHelper helper = DefaultTemplatesUtilities.GetHtmlHelper(); + + // Act + var result = helper.Raw(dynamicValue); + + // Assert + Assert.Equal(expectedString, result.ToString()); + } + + [Theory] + [MemberData(nameof(RawObjectTestData))] + public void RawObject_ReturnsExpectedString(object value, string expectedString) + { + // Arrange + // Important to preserve this particular variable type and the (object) type of the value parameter. + // Otherwise may end up testing different runtime (not compiler) behaviors. + IHtmlHelper helper = + DefaultTemplatesUtilities.GetHtmlHelper(); + + // Act + var result = helper.Raw(value); + + // Assert + Assert.Equal(expectedString, result.ToString()); + } + + [Theory] + [MemberData(nameof(RawStringTestData))] + public void RawString_ReturnsExpectedString(string value, string expectedString) + { + // Arrange + // Important to preserve this particular variable type and the (string) type of the value parameter. + // Otherwise may end up testing different runtime (not compiler) behaviors. + IHtmlHelper helper = + DefaultTemplatesUtilities.GetHtmlHelper(); + + // Act + var result = helper.Raw(value); + + // Assert + Assert.Equal(expectedString, result.ToString()); + } + + private class ObjectWithToStringOverride + { + public override string ToString() + { + return "boldFromObject"; + } + } } }