Add Switch.Microsoft.AspNetCore.Mvc.UseDateTimeTypeForDateTimeOffset quirks mode

- patch recipients can use switch to undo the #6648 fix
This commit is contained in:
Doug Bunting 2017-09-15 13:54:26 -07:00
parent 6041c6b966
commit fd9cb08790
5 changed files with 208 additions and 62 deletions

View File

@ -18,6 +18,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
[HtmlTargetElement("input", Attributes = ForAttributeName, TagStructure = TagStructure.WithoutEndTag)]
public class InputTagHelper : TagHelper
{
internal const string UseDateTimeLocalTypeForDateTimeOffsetSwitch = "Switch.Microsoft.AspNetCore.Mvc.UseDateTimeLocalTypeForDateTimeOffset";
private const string ForAttributeName = "asp-for";
private const string FormatAttributeName = "asp-format";
@ -63,6 +64,14 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
{ "time", "{0:HH:mm:ss.fff}" },
};
static InputTagHelper()
{
if (AppContext.TryGetSwitch(UseDateTimeLocalTypeForDateTimeOffsetSwitch, out var enabled) && enabled)
{
_defaultInputTypes.Remove(nameof(DateTimeOffset));
}
}
/// <summary>
/// Creates a new <see cref="InputTagHelper"/>.
/// </summary>
@ -393,8 +402,14 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
{
// Rfc3339 mode _may_ override EditFormatString in a limited number of cases. Happens only when
// EditFormatString has a default format i.e. came from a [DataType] attribute.
//
// First condition may occur when Switch.Microsoft.AspNetCore.Mvc.UseDateTimeLocalTypeForDateTimeOffset
// is true in extremely rare cases: The <input/> element for a DateTimeOffset expression must have
// type ="text". Checking the switch again to remove that case.
if (string.Equals("text", inputType) &&
string.Equals(nameof(DateTimeOffset), inputTypeHint, StringComparison.OrdinalIgnoreCase))
string.Equals(nameof(DateTimeOffset), inputTypeHint, StringComparison.OrdinalIgnoreCase) &&
!(AppContext.TryGetSwitch(UseDateTimeLocalTypeForDateTimeOffsetSwitch, out var enabled) &&
enabled))
{
// Auto-select a format that round-trips Offset and sub-Second values in a DateTimeOffset. Not
// done if user chose the "text" type in .cshtml file or with data annotations i.e. when

View File

@ -17,9 +17,10 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures.Internal
{
public class TemplateRenderer
{
public const string IEnumerableOfIFormFileName = "IEnumerable`" + nameof(IFormFile);
internal const string UseDateTimeLocalTypeForDateTimeOffsetSwitch = "Switch.Microsoft.AspNetCore.Mvc.UseDateTimeLocalTypeForDateTimeOffset";
private const string DisplayTemplateViewPath = "DisplayTemplates";
private const string EditorTemplateViewPath = "EditorTemplates";
public const string IEnumerableOfIFormFileName = "IEnumerable`" + nameof(IFormFile);
private static readonly Dictionary<string, Func<IHtmlHelper, IHtmlContent>> _defaultDisplayActions =
new Dictionary<string, Func<IHtmlHelper, IHtmlContent>>(StringComparer.OrdinalIgnoreCase)
@ -75,6 +76,14 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures.Internal
private readonly string _templateName;
private readonly bool _readOnly;
static TemplateRenderer()
{
if (AppContext.TryGetSwitch(UseDateTimeLocalTypeForDateTimeOffsetSwitch, out var enabled) && enabled)
{
_defaultEditorActions.Remove(nameof(DateTimeOffset));
}
}
public TemplateRenderer(
IViewEngine viewEngine,
IViewBufferScope bufferScope,

View File

@ -1,6 +1,7 @@
// 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.Net.Http;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Testing;
@ -10,6 +11,8 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests
{
public class HtmlHelperOptionsTest : IClassFixture<MvcTestFixture<RazorWebSite.Startup>>
{
private const string UseDateTimeLocalTypeForDateTimeOffsetSwitch = "Switch.Microsoft.AspNetCore.Mvc.UseDateTimeLocalTypeForDateTimeOffset";
public HtmlHelperOptionsTest(MvcTestFixture<RazorWebSite.Startup> fixture)
{
Client = fixture.Client;
@ -21,14 +24,17 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests
public async Task AppWideDefaultsInViewAndPartialView()
{
// Arrange
AppContext.TryGetSwitch(UseDateTimeLocalTypeForDateTimeOffsetSwitch, out var enabled);
var expectedType = enabled ? "datetime-local" : "text";
var expectedOffset = enabled ? string.Empty : "&#x2B;00:00";
var expected =
@"<div class=""validation-summary-errors""><validationSummaryElement>MySummary</validationSummaryElement>
$@"<div class=""validation-summary-errors""><validationSummaryElement>MySummary</validationSummaryElement>
<ul><li>A model error occurred.</li>
</ul></div>
<validationMessageElement class=""field-validation-error"">An error occurred.</validationMessageElement>
<input id=""Prefix!Property1"" name=""Prefix.Property1"" type=""text"" value="""" />
<div class=""editor-label""><label for=""MyDate"">MyDate</label></div>
<div class=""editor-field""><input class=""text-box single-line"" id=""MyDate"" name=""MyDate"" type=""text"" value=""2000-01-02T03:04:05.060&#x2B;00:00"" /> </div>
<div class=""editor-field""><input class=""text-box single-line"" id=""MyDate"" name=""MyDate"" type=""{expectedType}"" value=""2000-01-02T03:04:05.060{expectedOffset}"" /> </div>
<div class=""validation-summary-errors""><validationSummaryElement>MySummary</validationSummaryElement>
<ul><li>A model error occurred.</li>
@ -36,7 +42,7 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests
<validationMessageElement class=""field-validation-error"">An error occurred.</validationMessageElement>
<input id=""Prefix!Property1"" name=""Prefix.Property1"" type=""text"" value="""" />
<div class=""editor-label""><label for=""MyDate"">MyDate</label></div>
<div class=""editor-field""><input class=""text-box single-line"" id=""MyDate"" name=""MyDate"" type=""text"" value=""2000-01-02T03:04:05.060&#x2B;00:00"" /> </div>
<div class=""editor-field""><input class=""text-box single-line"" id=""MyDate"" name=""MyDate"" type=""{expectedType}"" value=""2000-01-02T03:04:05.060{expectedOffset}"" /> </div>
False";
@ -52,14 +58,16 @@ False";
public async Task OverrideAppWideDefaultsInViewAndPartialView()
{
// Arrange
AppContext.TryGetSwitch(UseDateTimeLocalTypeForDateTimeOffsetSwitch, out var enabled);
var expectedType = enabled ? "datetime-local" : "text";
var expected =
@"<div class=""validation-summary-errors""><ValidationSummaryInView>MySummary</ValidationSummaryInView>
$@"<div class=""validation-summary-errors""><ValidationSummaryInView>MySummary</ValidationSummaryInView>
<ul><li>A model error occurred.</li>
</ul></div>
<ValidationInView class=""field-validation-error"" data-valmsg-for=""Error"" data-valmsg-replace=""true"">An error occurred.</ValidationInView>
<input id=""Prefix!Property1"" name=""Prefix.Property1"" type=""text"" value="""" />
<div class=""editor-label""><label for=""MyDate"">MyDate</label></div>
<div class=""editor-field""><input class=""text-box single-line"" data-val=""true"" data-val-required=""The MyDate field is required."" id=""MyDate"" name=""MyDate"" type=""text"" value=""02/01/2000 03:04:05 &#x2B;00:00"" /> <ValidationInView class=""field-validation-valid"" data-valmsg-for=""MyDate"" data-valmsg-replace=""true""></ValidationInView></div>
<div class=""editor-field""><input class=""text-box single-line"" data-val=""true"" data-val-required=""The MyDate field is required."" id=""MyDate"" name=""MyDate"" type=""{expectedType}"" value=""02/01/2000 03:04:05 &#x2B;00:00"" /> <ValidationInView class=""field-validation-valid"" data-valmsg-for=""MyDate"" data-valmsg-replace=""true""></ValidationInView></div>
True
<div class=""validation-summary-errors""><ValidationSummaryInPartialView>MySummary</ValidationSummaryInPartialView>
@ -68,7 +76,7 @@ True
<ValidationInPartialView class=""field-validation-error"" data-valmsg-for=""Error"" data-valmsg-replace=""true"">An error occurred.</ValidationInPartialView>
<input id=""Prefix!Property1"" name=""Prefix.Property1"" type=""text"" value="""" />
<div class=""editor-label""><label for=""MyDate"">MyDate</label></div>
<div class=""editor-field""><input class=""text-box single-line"" id=""MyDate"" name=""MyDate"" type=""text"" value=""02/01/2000 03:04:05 &#x2B;00:00"" /> <ValidationInPartialView class=""field-validation-valid"" data-valmsg-for=""MyDate"" data-valmsg-replace=""true""></ValidationInPartialView></div>
<div class=""editor-field""><input class=""text-box single-line"" id=""MyDate"" name=""MyDate"" type=""{expectedType}"" value=""02/01/2000 03:04:05 &#x2B;00:00"" /> <ValidationInPartialView class=""field-validation-valid"" data-valmsg-for=""MyDate"" data-valmsg-replace=""true""></ValidationInPartialView></div>
True";

View File

@ -21,7 +21,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
{
public class InputTagHelperTest
{
public static TheoryData MultiAttributeCheckBoxData
public static TheoryData<TagHelperAttributeList, string> MultiAttributeCheckBoxData
{
get
{
@ -386,10 +386,22 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
Assert.Equal(expectedTagName, output.TagName);
}
public static TheoryData<string, string> Process_GeneratesFormattedOutputData
{
get
{
AppContext.TryGetSwitch(InputTagHelper.UseDateTimeLocalTypeForDateTimeOffsetSwitch, out var enabled);
return new TheoryData<string, string>
{
{ "datetime", "datetime" },
{ null, enabled ? "datetime-local" : "text" },
{ "hidden", "hidden" },
};
}
}
[Theory]
[InlineData("datetime", "datetime")]
[InlineData(null, "text")]
[InlineData("hidden", "hidden")]
[MemberData(nameof(Process_GeneratesFormattedOutputData))]
public void Process_GeneratesFormattedOutput(string specifiedType, string expectedType)
{
// Arrange
@ -1206,20 +1218,43 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
Assert.Equal(expectedTagName, output.TagName);
}
public static TheoryData<string, Html5DateRenderingMode, string, string> ProcessAsync_CallsGenerateTextBox_AddsExpectedAttributesForRfc3339Data
{
get
{
AppContext.TryGetSwitch(InputTagHelper.UseDateTimeLocalTypeForDateTimeOffsetSwitch, out var enabled);
var expectedK = enabled ? string.Empty : "K";
return new TheoryData<string, Html5DateRenderingMode, string, string>
{
{ "Date", Html5DateRenderingMode.CurrentCulture, "{0:d}", "date" }, // Format from [DataType].
{ "Date", Html5DateRenderingMode.Rfc3339, "{0:yyyy-MM-dd}", "date" },
{ "DateTime", Html5DateRenderingMode.CurrentCulture, null, "datetime-local" },
{ "DateTime", Html5DateRenderingMode.Rfc3339, "{0:yyyy-MM-ddTHH:mm:ss.fff}", "datetime-local" },
{ "DateTimeOffset", Html5DateRenderingMode.CurrentCulture, null, enabled ? "datetime-local" : "text" },
{
"DateTimeOffset",
Html5DateRenderingMode.Rfc3339,
$"{{0:yyyy-MM-ddTHH:mm:ss.fff{expectedK}}}",
enabled ? "datetime-local" : "text"
},
{ "DateTimeLocal", Html5DateRenderingMode.CurrentCulture, null, "datetime-local" },
{ "DateTimeLocal", Html5DateRenderingMode.Rfc3339, "{0:yyyy-MM-ddTHH:mm:ss.fff}", "datetime-local" },
{ "Time", Html5DateRenderingMode.CurrentCulture, "{0:t}", "time" }, // Format from [DataType].
{ "Time", Html5DateRenderingMode.Rfc3339, "{0:HH:mm:ss.fff}", "time" },
{ "NullableDate", Html5DateRenderingMode.Rfc3339, "{0:yyyy-MM-dd}", "date" },
{ "NullableDateTime", Html5DateRenderingMode.Rfc3339, "{0:yyyy-MM-ddTHH:mm:ss.fff}", "datetime-local" },
{
"NullableDateTimeOffset",
Html5DateRenderingMode.Rfc3339,
$"{{0:yyyy-MM-ddTHH:mm:ss.fff{expectedK}}}",
enabled ? "datetime-local" : "text"
},
};
}
}
[Theory]
[InlineData("Date", Html5DateRenderingMode.CurrentCulture, "{0:d}", "date")] // Format from [DataType].
[InlineData("Date", Html5DateRenderingMode.Rfc3339, "{0:yyyy-MM-dd}", "date")]
[InlineData("DateTime", Html5DateRenderingMode.CurrentCulture, null, "datetime-local")]
[InlineData("DateTime", Html5DateRenderingMode.Rfc3339, "{0:yyyy-MM-ddTHH:mm:ss.fff}", "datetime-local")]
[InlineData("DateTimeOffset", Html5DateRenderingMode.CurrentCulture, null, "text")]
[InlineData("DateTimeOffset", Html5DateRenderingMode.Rfc3339, "{0:yyyy-MM-ddTHH:mm:ss.fffK}", "text")]
[InlineData("DateTimeLocal", Html5DateRenderingMode.CurrentCulture, null, "datetime-local")]
[InlineData("DateTimeLocal", Html5DateRenderingMode.Rfc3339, "{0:yyyy-MM-ddTHH:mm:ss.fff}", "datetime-local")]
[InlineData("Time", Html5DateRenderingMode.CurrentCulture, "{0:t}", "time")] // Format from [DataType].
[InlineData("Time", Html5DateRenderingMode.Rfc3339, "{0:HH:mm:ss.fff}", "time")]
[InlineData("NullableDate", Html5DateRenderingMode.Rfc3339, "{0:yyyy-MM-dd}", "date")]
[InlineData("NullableDateTime", Html5DateRenderingMode.Rfc3339, "{0:yyyy-MM-ddTHH:mm:ss.fff}", "datetime-local")]
[InlineData("NullableDateTimeOffset", Html5DateRenderingMode.Rfc3339, "{0:yyyy-MM-ddTHH:mm:ss.fffK}", "text")]
[MemberData(nameof(ProcessAsync_CallsGenerateTextBox_AddsExpectedAttributesForRfc3339Data))]
public async Task ProcessAsync_CallsGenerateTextBox_AddsExpectedAttributesForRfc3339(
string propertyName,
Html5DateRenderingMode dateRenderingMode,

View File

@ -29,6 +29,10 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures.Internal
{
get
{
AppContext.TryGetSwitch(TemplateRenderer.UseDateTimeLocalTypeForDateTimeOffsetSwitch, out var enabled);
// Tests use string properties and fall back to text template (no type attribute) when quirk is enabled.
var dateTimeOffsetType = enabled ? string.Empty : " type='text'";
return new TheoryData<string, string>
{
{ null, "__TextBox__ class='text-box single-line'" },
@ -53,8 +57,8 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures.Internal
{ "datetime", "__TextBox__ class='text-box single-line' type='datetime-local'" },
{ "DateTime-local", "__TextBox__ class='text-box single-line' type='datetime-local'" },
{ "DATETIME-LOCAL", "__TextBox__ class='text-box single-line' type='datetime-local'" },
{ "datetimeoffset", "__TextBox__ class='text-box single-line' type='text'" },
{ "DateTimeOffset", "__TextBox__ class='text-box single-line' type='text'" },
{ "datetimeoffset", $"__TextBox__ class='text-box single-line'{dateTimeOffsetType}" },
{ "DateTimeOffset", $"__TextBox__ class='text-box single-line'{dateTimeOffsetType}" },
{ "Time", "__TextBox__ class='text-box single-line' type='time'" },
{ "time", "__TextBox__ class='text-box single-line' type='time'" },
{ "Byte", "__TextBox__ class='text-box single-line' type='number'" },
@ -774,9 +778,12 @@ Environment.NewLine;
{
// Arrange
var requiredMessage = ValidationAttributeUtil.GetRequiredErrorMessage("DateTimeOffset");
AppContext.TryGetSwitch(TemplateRenderer.UseDateTimeLocalTypeForDateTimeOffsetSwitch, out var enabled);
var expectedOffset = enabled ? string.Empty : "+00:00";
var expectedInput = "<input class=\"HtmlEncode[[text-box single-line]]\" data-val=\"HtmlEncode[[true]]\" " +
$"data-val-required=\"HtmlEncode[[{requiredMessage}]]\" id=\"HtmlEncode[[FieldPrefix]]\" " +
"name=\"HtmlEncode[[FieldPrefix]]\" type=\"HtmlEncode[[datetime]]\" value=\"HtmlEncode[[2000-01-02T03:04:05.060+00:00]]\" />";
"name=\"HtmlEncode[[FieldPrefix]]\" type=\"HtmlEncode[[datetime]]\" " +
$"value=\"HtmlEncode[[2000-01-02T03:04:05.060{expectedOffset}]]\" />";
var offset = TimeSpan.FromHours(0);
var model = new DateTimeOffset(
@ -814,14 +821,32 @@ Environment.NewLine;
Assert.Equal(expectedInput, HtmlContentUtilities.HtmlContentToString(result));
}
public static TheoryData<string, string, string, string> Editor_FindsCorrectDateOrTimeTemplateData
{
get
{
AppContext.TryGetSwitch(TemplateRenderer.UseDateTimeLocalTypeForDateTimeOffsetSwitch, out var enabled);
var expectedOffset = enabled ? string.Empty : "-05:00";
return new TheoryData<string, string, string, string>
{
{ null, null, $"2000-01-02T03:04:05.060{expectedOffset}", enabled ? "datetime-local" : "text" },
{ "date", "{0:d}", "2000-01-02", "date" },
{ "datetime", null, "2000-01-02T03:04:05.060", "datetime-local" },
{ "datetime-local", null, "2000-01-02T03:04:05.060", "datetime-local" },
{
"DateTimeOffset",
"{0:o}",
$"2000-01-02T03:04:05.060{expectedOffset}",
enabled ? "datetime-local" : "text"
},
{ "time", "{0:t}", "03:04:05.060", "time" },
};
}
}
// Html5DateRenderingMode.Rfc3339 is enabled by default.
[Theory]
[InlineData(null, null, "2000-01-02T03:04:05.060-05:00", "text")]
[InlineData("date", "{0:d}", "2000-01-02", "date")]
[InlineData("datetime", null, "2000-01-02T03:04:05.060", "datetime-local")]
[InlineData("datetime-local", null, "2000-01-02T03:04:05.060", "datetime-local")]
[InlineData("DateTimeOffset", "{0:o}", "2000-01-02T03:04:05.060-05:00", "text")]
[InlineData("time", "{0:t}", "03:04:05.060", "time")]
[MemberData(nameof(Editor_FindsCorrectDateOrTimeTemplateData))]
public void Editor_FindsCorrectDateOrTimeTemplate(
string dataTypeName,
string editFormatString,
@ -875,14 +900,26 @@ Environment.NewLine;
Assert.Equal(expectedInput, HtmlContentUtilities.HtmlContentToString(result));
}
public static TheoryData<string, string, string, string> Editor_FindsCorrectDateOrTimeTemplate_NotRfc3339Data
{
get
{
AppContext.TryGetSwitch(TemplateRenderer.UseDateTimeLocalTypeForDateTimeOffsetSwitch, out var enabled);
return new TheoryData<string, string, string, string>
{
{ null, null, "02/01/2000 03:04:05 -05:00", enabled ? "datetime-local" : "text" },
{ "date", "{0:d}", "02/01/2000", "date" },
{ "datetime", null, "02/01/2000 03:04:05 -05:00", "datetime-local" },
{ "datetime-local", null, "02/01/2000 03:04:05 -05:00", "datetime-local" },
{ "DateTimeOffset", "{0:o}", "2000-01-02T03:04:05.0600000-05:00", enabled ? "datetime-local" : "text" },
{ "time", "{0:t}", "03:04", "time" },
};
}
}
// Html5DateRenderingMode.Rfc3339 can be disabled.
[Theory]
[InlineData(null, null, "02/01/2000 03:04:05 -05:00", "text")]
[InlineData("date", "{0:d}", "02/01/2000", "date")]
[InlineData("datetime", null, "02/01/2000 03:04:05 -05:00", "datetime-local")]
[InlineData("datetime-local", null, "02/01/2000 03:04:05 -05:00", "datetime-local")]
[InlineData("DateTimeOffset", "{0:o}", "2000-01-02T03:04:05.0600000-05:00", "text")]
[InlineData("time", "{0:t}", "03:04", "time")]
[MemberData(nameof(Editor_FindsCorrectDateOrTimeTemplate_NotRfc3339Data))]
[ReplaceCulture]
public void Editor_FindsCorrectDateOrTimeTemplate_NotRfc3339(
string dataTypeName,
@ -939,14 +976,32 @@ Environment.NewLine;
Assert.Equal(expectedInput, HtmlContentUtilities.HtmlContentToString(result));
}
public static TheoryData<string, string, string, string> Editor_FindsCorrectDateOrTimeTemplate_ForDateTimeData
{
get
{
AppContext.TryGetSwitch(TemplateRenderer.UseDateTimeLocalTypeForDateTimeOffsetSwitch, out var enabled);
var expectedZ = enabled ? string.Empty : "Z";
return new TheoryData<string, string, string, string>
{
{ null, null, "2000-01-02T03:04:05.060", "datetime-local" },
{ "date", "{0:d}", "2000-01-02", "date" },
{ "datetime", null, "2000-01-02T03:04:05.060", "datetime-local" },
{ "datetime-local", null, "2000-01-02T03:04:05.060", "datetime-local" },
{
"DateTimeOffset",
"{0:o}",
$"2000-01-02T03:04:05.060{expectedZ}",
enabled ? "datetime-local" : "text"
},
{ "time", "{0:t}", "03:04:05.060", "time" },
};
}
}
// Html5DateRenderingMode.Rfc3339 is enabled by default.
[Theory]
[InlineData(null, null, "2000-01-02T03:04:05.060", "datetime-local")]
[InlineData("date", "{0:d}", "2000-01-02", "date")]
[InlineData("datetime", null, "2000-01-02T03:04:05.060", "datetime-local")]
[InlineData("datetime-local", null, "2000-01-02T03:04:05.060", "datetime-local")]
[InlineData("DateTimeOffset", "{0:o}", "2000-01-02T03:04:05.060Z", "text")]
[InlineData("time", "{0:t}", "03:04:05.060", "time")]
[MemberData(nameof(Editor_FindsCorrectDateOrTimeTemplate_ForDateTimeData))]
public void Editor_FindsCorrectDateOrTimeTemplate_ForDateTime(
string dataTypeName,
string editFormatString,
@ -999,14 +1054,26 @@ Environment.NewLine;
Assert.Equal(expectedInput, HtmlContentUtilities.HtmlContentToString(result));
}
public static TheoryData<string, string, string, string> Editor_FindsCorrectDateOrTimeTemplate_ForDateTimeNotRfc3339Data
{
get
{
AppContext.TryGetSwitch(TemplateRenderer.UseDateTimeLocalTypeForDateTimeOffsetSwitch, out var enabled);
return new TheoryData<string, string, string, string>
{
{ null, null, "02/01/2000 03:04:05", "datetime-local" },
{ "date", "{0:d}", "02/01/2000", "date" },
{ "datetime", null, "02/01/2000 03:04:05", "datetime-local" },
{ "datetime-local", null, "02/01/2000 03:04:05", "datetime-local" },
{ "DateTimeOffset", "{0:o}", "2000-01-02T03:04:05.0600000Z", enabled ? "datetime-local" : "text" },
{ "time", "{0:t}", "03:04", "time" },
};
}
}
// Html5DateRenderingMode.Rfc3339 can be disabled.
[Theory]
[InlineData(null, null, "02/01/2000 03:04:05", "datetime-local")]
[InlineData("date", "{0:d}", "02/01/2000", "date")]
[InlineData("datetime", null, "02/01/2000 03:04:05", "datetime-local")]
[InlineData("datetime-local", null, "02/01/2000 03:04:05", "datetime-local")]
[InlineData("DateTimeOffset", "{0:o}", "2000-01-02T03:04:05.0600000Z", "text")]
[InlineData("time", "{0:t}", "03:04", "time")]
[MemberData(nameof(Editor_FindsCorrectDateOrTimeTemplate_ForDateTimeNotRfc3339Data))]
[ReplaceCulture]
public void Editor_FindsCorrectDateOrTimeTemplate_ForDateTimeNotRfc3339(
string dataTypeName,
@ -1062,17 +1129,29 @@ Environment.NewLine;
Assert.Equal(expectedInput, HtmlContentUtilities.HtmlContentToString(result));
}
public static TheoryData<string, Html5DateRenderingMode, string> Editor_AppliesNonDefaultEditFormatData
{
get
{
AppContext.TryGetSwitch(TemplateRenderer.UseDateTimeLocalTypeForDateTimeOffsetSwitch, out var enabled);
return new TheoryData<string, Html5DateRenderingMode, string>
{
{ null, Html5DateRenderingMode.CurrentCulture, enabled ? "datetime-local" : "text" },
{ null, Html5DateRenderingMode.Rfc3339, enabled ? "datetime-local" : "text" },
{ "date", Html5DateRenderingMode.CurrentCulture, "date" },
{ "date", Html5DateRenderingMode.Rfc3339, "date" },
{ "datetime", Html5DateRenderingMode.CurrentCulture, "datetime-local" },
{ "datetime", Html5DateRenderingMode.Rfc3339, "datetime-local" },
{ "datetime-local", Html5DateRenderingMode.CurrentCulture, "datetime-local" },
{ "datetime-local", Html5DateRenderingMode.Rfc3339, "datetime-local" },
{ "time", Html5DateRenderingMode.CurrentCulture, "time" },
{ "time", Html5DateRenderingMode.Rfc3339, "time" },
};
}
}
[Theory]
[InlineData(null, Html5DateRenderingMode.CurrentCulture, "text")]
[InlineData(null, Html5DateRenderingMode.Rfc3339, "text")]
[InlineData("date", Html5DateRenderingMode.CurrentCulture, "date")]
[InlineData("date", Html5DateRenderingMode.Rfc3339, "date")]
[InlineData("datetime", Html5DateRenderingMode.CurrentCulture, "datetime-local")]
[InlineData("datetime", Html5DateRenderingMode.Rfc3339, "datetime-local")]
[InlineData("datetime-local", Html5DateRenderingMode.CurrentCulture, "datetime-local")]
[InlineData("datetime-local", Html5DateRenderingMode.Rfc3339, "datetime-local")]
[InlineData("time", Html5DateRenderingMode.CurrentCulture, "time")]
[InlineData("time", Html5DateRenderingMode.Rfc3339, "time")]
[MemberData(nameof(Editor_AppliesNonDefaultEditFormatData))]
public void Editor_AppliesNonDefaultEditFormat(string dataTypeName, Html5DateRenderingMode renderingMode, string expectedType)
{
// Arrange