Property Editors: New Date Time property editors (#19915)
* Started the implementation of the new date time property editor * Display picked time in local and UTC * Adjustments to the way the timezones are displayed and the picker is configured * Filter out `Etc/` (offset) timezones from the list * Additional adjustments * Introduced date format and time zone options (all, local or custom) * Adjustments to the property editor configuration and value converter * Use UUICombobox instead of UUISelect for displaying time zone options. Display UTC offset instead of short offset name in label. * Allow searching by offset * Ignore case when searching for time zone * Store dates consistently (always same format) * Add custom PropertyIndexValueFactory for the new property editor * Adjustments when switching between time zone modes * Small fixes and cleanup * Started improving time zone config selection * Small adjustments * Remove selected time zones from the list + display label instead of value * Localizing labels * Remove unwanted character * Fix incorrect order of custom time zones list * Small fixes (mostly validation) * Rename input time zone component * Small adjustments * Using model for stored value * Save examine value as ISO format * Adjusting class names for consistency * Small fixes * Add default data type configuration * Rename `TimeZone` to `UmbTimeZone` * Fix failing tests * Started adding unit tests for DateWithTimeZonePropertyEditor * Additional tests * Additional tests * Additional tests * Fixed searches with regex special characters throwing errors * Remove offset from generic UmbTimeZone type and added new type specific for the property editor * Adjust property editor to show error when selected time zone is no longer available, instead of pre-selecting another one * Do not preselect a time zone if a date is stored without time zone This most likely means that the configuration of the editor changed to add time zone support. In this case we want to force the editor to select the applicable time zone. * Fix failing backoffice build * Added tests for DateTimeWithTimeZonePropertyIndexValueFactory * Improved picker validation * Remove unused code * Move models to their corresponding places * Renaming `DateTimeWithTimeZone` to `DateTime2` * Fix data type count tests * Simplifying code + adjusting value converter to support old picker value * Adjustments to property editor unit tests * Fix validation issue * Fix default configuration for 'Date Time (Unspecified)' * Rename validator * Fix comment * Adjust database creator default DateTime2 data types * Update tests after adjusting default data types * Add integration test for DateTime2 returned value type * Apply suggestions from code review Co-authored-by: Andy Butland <abutland73@gmail.com> * Aligning DateTime2Validator with other JSON validators. Added new model for API. * Removed unused code and updated tests * Fix validation error message * Apply suggestions from code review Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Splitting the new date time editor into multiple (per output type) * Adjust tests in DateTime2PropertyIndexValueFactoryTest * Update value converter tests * Group the new date time tests * Adjust new property editor tests * Adjust property editor integration tests * Update data editor count tests * Naming adjustments * Small fixes * Cleanup - Remove unused files - Remove 'None' option from configuration and update all the tests * Update luxon depedencies * Move GetValueFromSource to the value converter * Add new property editor examples to mock data * Re-organizing the code * Adjustments from code review * Place the date time property index value factories in their own files * Small adjustments for code consistency * Small adjustments * Minor adjustment * Small fix from copilot review * Completed the set of XML header comments. * use already existing query property * fail is form control element is null or undefined * using lit ref for querying and form control registration * state for timeZonePickerValue and remove _disableAddButton * Adjustments to form control registration * Remove unused declaration --------- Co-authored-by: Andy Butland <abutland73@gmail.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: Niels Lyngsø <nsl@umbraco.dk> Co-authored-by: Niels Lyngsø <niels.lyngso@gmail.com>
This commit is contained in:
@@ -132,7 +132,7 @@ public class TypeLoaderTests
|
||||
public void GetDataEditors()
|
||||
{
|
||||
var types = _typeLoader.GetDataEditors();
|
||||
Assert.AreEqual(37, types.Count());
|
||||
Assert.AreEqual(41, types.Count());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -0,0 +1,164 @@
|
||||
using System.Globalization;
|
||||
using System.Text.Json.Nodes;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Core.IO;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Models.Editors;
|
||||
using Umbraco.Cms.Core.Models.Validation;
|
||||
using Umbraco.Cms.Core.PropertyEditors;
|
||||
using Umbraco.Cms.Core.PropertyEditors.ValueConverters;
|
||||
using Umbraco.Cms.Core.Serialization;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
using Umbraco.Cms.Core.Strings;
|
||||
using Umbraco.Cms.Infrastructure.Models;
|
||||
using Umbraco.Cms.Infrastructure.Serialization;
|
||||
|
||||
namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Core.PropertyEditors;
|
||||
|
||||
[TestFixture]
|
||||
public class DateOnlyPropertyEditorTests
|
||||
{
|
||||
private static readonly IJsonSerializer _jsonSerializer =
|
||||
new SystemTextJsonSerializer(new DefaultJsonSerializerEncoderFactory());
|
||||
|
||||
private static readonly object[] _validateDateReceivedTestCases =
|
||||
[
|
||||
new object[] { null, true },
|
||||
new object[] { JsonNode.Parse("{}"), false },
|
||||
new object[] { JsonNode.Parse("{\"test\": \"\"}"), false },
|
||||
new object[] { JsonNode.Parse("{\"date\": \"\"}"), false },
|
||||
new object[] { JsonNode.Parse("{\"date\": \"INVALID\"}"), false },
|
||||
new object[] { JsonNode.Parse("{\"date\": \"2025-08-20T14:30:00\"}"), true }
|
||||
];
|
||||
|
||||
[TestCaseSource(nameof(_validateDateReceivedTestCases))]
|
||||
public void Validates_Date_Received(object? value, bool expectedSuccess)
|
||||
{
|
||||
var editor = CreateValueEditor();
|
||||
var result = editor.Validate(value, false, null, PropertyValidationContext.Empty()).ToList();
|
||||
if (expectedSuccess)
|
||||
{
|
||||
Assert.IsEmpty(result);
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert.AreEqual(1, result.Count);
|
||||
|
||||
var validationResult = result.First();
|
||||
Assert.AreEqual("validation_invalidDate", validationResult.ErrorMessage);
|
||||
}
|
||||
}
|
||||
|
||||
private static readonly object[] _dateOnlyParseValuesFromEditorTestCases =
|
||||
[
|
||||
new object[] { null, null, null },
|
||||
new object[] { JsonNode.Parse("{\"date\": \"2025-08-20\"}"), new DateTimeOffset(2025, 8, 20, 0, 0, 0, TimeSpan.Zero), null },
|
||||
];
|
||||
|
||||
[TestCaseSource(nameof(_dateOnlyParseValuesFromEditorTestCases))]
|
||||
public void Can_Parse_Values_From_Editor(
|
||||
object? value,
|
||||
DateTimeOffset? expectedDateTimeOffset,
|
||||
string? expectedTimeZone)
|
||||
{
|
||||
var expectedJson = expectedDateTimeOffset is null ? null : _jsonSerializer.Serialize(
|
||||
new DateTimeValueConverterBase.DateTimeDto
|
||||
{
|
||||
Date = expectedDateTimeOffset.Value,
|
||||
TimeZone = expectedTimeZone,
|
||||
});
|
||||
var result = CreateValueEditor().FromEditor(
|
||||
new ContentPropertyData(
|
||||
value,
|
||||
new DateTimeConfiguration
|
||||
{
|
||||
TimeZones = null,
|
||||
}),
|
||||
null);
|
||||
Assert.AreEqual(expectedJson, result);
|
||||
}
|
||||
|
||||
private static readonly object[][] _dateOnlyParseValuesToEditorTestCases =
|
||||
[
|
||||
[null, null, null],
|
||||
[0, null, new DateTimeEditorValue { Date = "2025-08-20", TimeZone = null }],
|
||||
];
|
||||
|
||||
[TestCaseSource(nameof(_dateOnlyParseValuesToEditorTestCases))]
|
||||
public void Can_Parse_Values_To_Editor(
|
||||
int? offset,
|
||||
string? timeZone,
|
||||
object? expectedResult)
|
||||
{
|
||||
var storedValue = offset is null
|
||||
? null
|
||||
: new DateTimeValueConverterBase.DateTimeDto
|
||||
{
|
||||
Date = new DateTimeOffset(2025, 8, 20, 16, 30, 00, TimeSpan.FromHours(offset.Value)),
|
||||
TimeZone = timeZone,
|
||||
};
|
||||
var valueEditor = CreateValueEditor(timeZoneMode: null);
|
||||
var storedValueJson = storedValue is null ? null : _jsonSerializer.Serialize(storedValue);
|
||||
var result = valueEditor.ToEditor(
|
||||
new Property(new PropertyType(Mock.Of<IShortStringHelper>(), "dataType", ValueStorageType.Ntext))
|
||||
{
|
||||
Values =
|
||||
[
|
||||
new Property.PropertyValue
|
||||
{
|
||||
EditedValue = storedValueJson,
|
||||
PublishedValue = storedValueJson,
|
||||
}
|
||||
],
|
||||
});
|
||||
|
||||
if (expectedResult is null)
|
||||
{
|
||||
Assert.IsNull(result);
|
||||
return;
|
||||
}
|
||||
|
||||
Assert.IsNotNull(result);
|
||||
Assert.IsInstanceOf<DateTimeEditorValue>(result);
|
||||
var apiModel = (DateTimeEditorValue)result;
|
||||
Assert.AreEqual(((DateTimeEditorValue)expectedResult).Date, apiModel.Date);
|
||||
Assert.AreEqual(((DateTimeEditorValue)expectedResult).TimeZone, apiModel.TimeZone);
|
||||
}
|
||||
|
||||
private DateTimePropertyEditorBase.DateTimeDataValueEditor CreateValueEditor(
|
||||
DateTimeConfiguration.TimeZoneMode? timeZoneMode = null,
|
||||
string[]? timeZones = null)
|
||||
{
|
||||
var localizedTextServiceMock = new Mock<ILocalizedTextService>();
|
||||
localizedTextServiceMock.Setup(x => x.Localize(
|
||||
It.IsAny<string>(),
|
||||
It.IsAny<string>(),
|
||||
It.IsAny<CultureInfo>(),
|
||||
It.IsAny<IDictionary<string, string>>()))
|
||||
.Returns((string key, string alias, CultureInfo _, IDictionary<string, string> _) => $"{key}_{alias}");
|
||||
var valueEditor = new DateTimePropertyEditorBase.DateTimeDataValueEditor(
|
||||
Mock.Of<IShortStringHelper>(),
|
||||
_jsonSerializer,
|
||||
Mock.Of<IIOHelper>(),
|
||||
new DataEditorAttribute(Constants.PropertyEditors.Aliases.DateOnly),
|
||||
localizedTextServiceMock.Object,
|
||||
Mock.Of<ILogger<DateTimePropertyEditorBase.DateTimeDataValueEditor>>(),
|
||||
dt => dt.Date.ToString("yyyy-MM-dd"))
|
||||
{
|
||||
ConfigurationObject = new DateTimeConfiguration
|
||||
{
|
||||
TimeZones = timeZoneMode is null
|
||||
? null
|
||||
: new DateTimeConfiguration.TimeZonesConfiguration
|
||||
{
|
||||
Mode = timeZoneMode.Value,
|
||||
TimeZones = timeZones?.ToList() ?? [],
|
||||
},
|
||||
},
|
||||
};
|
||||
return valueEditor;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,167 @@
|
||||
using System.Globalization;
|
||||
using System.Text.Json.Nodes;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Core.IO;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Models.Editors;
|
||||
using Umbraco.Cms.Core.Models.Validation;
|
||||
using Umbraco.Cms.Core.PropertyEditors;
|
||||
using Umbraco.Cms.Core.PropertyEditors.ValueConverters;
|
||||
using Umbraco.Cms.Core.Serialization;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
using Umbraco.Cms.Core.Strings;
|
||||
using Umbraco.Cms.Infrastructure.Models;
|
||||
using Umbraco.Cms.Infrastructure.Serialization;
|
||||
|
||||
namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Core.PropertyEditors;
|
||||
|
||||
[TestFixture]
|
||||
public class DateTimeUnspecifiedPropertyEditorTests
|
||||
{
|
||||
private static readonly IJsonSerializer _jsonSerializer =
|
||||
new SystemTextJsonSerializer(new DefaultJsonSerializerEncoderFactory());
|
||||
|
||||
private static readonly object[] _validateDateReceivedTestCases =
|
||||
[
|
||||
new object[] { null, true },
|
||||
new object[] { JsonNode.Parse("{}"), false },
|
||||
new object[] { JsonNode.Parse("{\"test\": \"\"}"), false },
|
||||
new object[] { JsonNode.Parse("{\"date\": \"\"}"), false },
|
||||
new object[] { JsonNode.Parse("{\"date\": \"INVALID\"}"), false },
|
||||
new object[] { JsonNode.Parse("{\"date\": \"2025-08-20T14:30:00\"}"), true }
|
||||
];
|
||||
|
||||
[TestCaseSource(nameof(_validateDateReceivedTestCases))]
|
||||
public void Validates_Date_Received(object? value, bool expectedSuccess)
|
||||
{
|
||||
var editor = CreateValueEditor();
|
||||
var result = editor.Validate(value, false, null, PropertyValidationContext.Empty()).ToList();
|
||||
if (expectedSuccess)
|
||||
{
|
||||
Assert.IsEmpty(result);
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert.AreEqual(1, result.Count);
|
||||
|
||||
var validationResult = result.First();
|
||||
Assert.AreEqual("validation_invalidDate", validationResult.ErrorMessage);
|
||||
}
|
||||
}
|
||||
|
||||
private static readonly object[] _dateTimeUnspecifiedParseValuesFromEditorTestCases =
|
||||
[
|
||||
new object[] { null, null, null },
|
||||
new object[] { JsonNode.Parse("{}"), null, null },
|
||||
new object[] { JsonNode.Parse("{\"INVALID\": \"\"}"), null, null },
|
||||
new object[] { JsonNode.Parse("{\"date\": \"2025-08-20T18:30:01\"}"), new DateTimeOffset(2025, 8, 20, 18, 30, 1, TimeSpan.Zero), null },
|
||||
new object[] { JsonNode.Parse("{\"date\": \"2025-08-20T18:30:01Z\"}"), new DateTimeOffset(2025, 8, 20, 18, 30, 1, TimeSpan.Zero), null },
|
||||
new object[] { JsonNode.Parse("{\"date\": \"2025-08-20T18:30:01-05:00\"}"), new DateTimeOffset(2025, 8, 20, 18, 30, 1, TimeSpan.FromHours(-5)), null },
|
||||
];
|
||||
|
||||
[TestCaseSource(nameof(_dateTimeUnspecifiedParseValuesFromEditorTestCases))]
|
||||
public void Can_Parse_Values_From_Editor(
|
||||
object? value,
|
||||
DateTimeOffset? expectedDateTimeOffset,
|
||||
string? expectedTimeZone)
|
||||
{
|
||||
var expectedJson = expectedDateTimeOffset is null ? null : _jsonSerializer.Serialize(
|
||||
new DateTimeValueConverterBase.DateTimeDto
|
||||
{
|
||||
Date = expectedDateTimeOffset.Value,
|
||||
TimeZone = expectedTimeZone,
|
||||
});
|
||||
var result = CreateValueEditor().FromEditor(
|
||||
new ContentPropertyData(
|
||||
value,
|
||||
new DateTimeConfiguration
|
||||
{
|
||||
TimeZones = null,
|
||||
}),
|
||||
null);
|
||||
Assert.AreEqual(expectedJson, result);
|
||||
}
|
||||
|
||||
private static readonly object[][] _dateTimeUnspecifiedParseValuesToEditorTestCases =
|
||||
[
|
||||
[null, null],
|
||||
[0, new DateTimeEditorValue { Date = "2025-08-20T16:30:00", TimeZone = null }],
|
||||
[2, new DateTimeEditorValue { Date = "2025-08-20T16:30:00", TimeZone = null }],
|
||||
];
|
||||
|
||||
[TestCaseSource(nameof(_dateTimeUnspecifiedParseValuesToEditorTestCases))]
|
||||
public void Can_Parse_Values_To_Editor(
|
||||
int? offset,
|
||||
object? expectedResult)
|
||||
{
|
||||
var storedValue = offset is null
|
||||
? null
|
||||
: new DateTimeValueConverterBase.DateTimeDto
|
||||
{
|
||||
Date = new DateTimeOffset(2025, 8, 20, 16, 30, 00, TimeSpan.FromHours(offset.Value)),
|
||||
};
|
||||
var valueEditor = CreateValueEditor(timeZoneMode: null);
|
||||
var storedValueJson = storedValue is null ? null : _jsonSerializer.Serialize(storedValue);
|
||||
var result = valueEditor.ToEditor(
|
||||
new Property(new PropertyType(Mock.Of<IShortStringHelper>(), "dataType", ValueStorageType.Ntext))
|
||||
{
|
||||
Values =
|
||||
[
|
||||
new Property.PropertyValue
|
||||
{
|
||||
EditedValue = storedValueJson,
|
||||
PublishedValue = storedValueJson,
|
||||
}
|
||||
],
|
||||
});
|
||||
|
||||
if (expectedResult is null)
|
||||
{
|
||||
Assert.IsNull(result);
|
||||
return;
|
||||
}
|
||||
|
||||
Assert.IsNotNull(result);
|
||||
Assert.IsInstanceOf<DateTimeEditorValue>(result);
|
||||
var apiModel = (DateTimeEditorValue)result;
|
||||
Assert.AreEqual(((DateTimeEditorValue)expectedResult).Date, apiModel.Date);
|
||||
Assert.AreEqual(((DateTimeEditorValue)expectedResult).TimeZone, apiModel.TimeZone);
|
||||
}
|
||||
|
||||
private DateTimePropertyEditorBase.DateTimeDataValueEditor CreateValueEditor(
|
||||
DateTimeConfiguration.TimeZoneMode? timeZoneMode = null,
|
||||
string[]? timeZones = null)
|
||||
{
|
||||
var localizedTextServiceMock = new Mock<ILocalizedTextService>();
|
||||
localizedTextServiceMock.Setup(x => x.Localize(
|
||||
It.IsAny<string>(),
|
||||
It.IsAny<string>(),
|
||||
It.IsAny<CultureInfo>(),
|
||||
It.IsAny<IDictionary<string, string>>()))
|
||||
.Returns((string key, string alias, CultureInfo _, IDictionary<string, string> _) => $"{key}_{alias}");
|
||||
var valueEditor = new DateTimePropertyEditorBase.DateTimeDataValueEditor(
|
||||
Mock.Of<IShortStringHelper>(),
|
||||
_jsonSerializer,
|
||||
Mock.Of<IIOHelper>(),
|
||||
new DataEditorAttribute(Constants.PropertyEditors.Aliases.DateTimeUnspecified),
|
||||
localizedTextServiceMock.Object,
|
||||
Mock.Of<ILogger<DateTimePropertyEditorBase.DateTimeDataValueEditor>>(),
|
||||
dt => dt.Date.ToString("yyyy-MM-ddTHH:mm:ss"))
|
||||
{
|
||||
ConfigurationObject = new DateTimeConfiguration
|
||||
{
|
||||
TimeZones = timeZoneMode is null
|
||||
? null
|
||||
: new DateTimeConfiguration.TimeZonesConfiguration
|
||||
{
|
||||
Mode = timeZoneMode.Value,
|
||||
TimeZones = timeZones?.ToList() ?? [],
|
||||
},
|
||||
},
|
||||
};
|
||||
return valueEditor;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,205 @@
|
||||
using System.Globalization;
|
||||
using System.Text.Json.Nodes;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Core.IO;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Models.Editors;
|
||||
using Umbraco.Cms.Core.Models.Validation;
|
||||
using Umbraco.Cms.Core.PropertyEditors;
|
||||
using Umbraco.Cms.Core.PropertyEditors.ValueConverters;
|
||||
using Umbraco.Cms.Core.Serialization;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
using Umbraco.Cms.Core.Strings;
|
||||
using Umbraco.Cms.Infrastructure.Models;
|
||||
using Umbraco.Cms.Infrastructure.Serialization;
|
||||
|
||||
namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Core.PropertyEditors;
|
||||
|
||||
[TestFixture]
|
||||
public class DateTimeWithTimeZonePropertyEditorTests
|
||||
{
|
||||
private static readonly IJsonSerializer _jsonSerializer =
|
||||
new SystemTextJsonSerializer(new DefaultJsonSerializerEncoderFactory());
|
||||
|
||||
private static readonly object[] _validateDateReceivedTestCases =
|
||||
[
|
||||
new object[] { null, true },
|
||||
new object[] { JsonNode.Parse("{}"), false },
|
||||
new object[] { JsonNode.Parse("{\"test\": \"\"}"), false },
|
||||
new object[] { JsonNode.Parse("{\"date\": \"\"}"), false },
|
||||
new object[] { JsonNode.Parse("{\"date\": \"INVALID\"}"), false },
|
||||
new object[] { JsonNode.Parse("{\"date\": \"2025-08-20T14:30:00\"}"), true }
|
||||
];
|
||||
|
||||
private static readonly object[] _sourceList2 =
|
||||
[
|
||||
new object[] { JsonNode.Parse("{\"date\": \"2025-08-20T14:30:00\"}"), DateTimeConfiguration.TimeZoneMode.All, Array.Empty<string>(), true },
|
||||
new object[] { JsonNode.Parse("{\"date\": \"2025-08-20T14:30:00\"}"), DateTimeConfiguration.TimeZoneMode.Local, Array.Empty<string>(), true },
|
||||
new object[] { JsonNode.Parse("{\"date\": \"2025-08-20T14:30:00\"}"), DateTimeConfiguration.TimeZoneMode.Custom, new[] { "Europe/Copenhagen" }, false },
|
||||
new object[] { JsonNode.Parse("{\"date\": \"2025-08-20T14:30:00\", \"timeZone\": \"Europe/Copenhagen\"}"), DateTimeConfiguration.TimeZoneMode.All, Array.Empty<string>(), true },
|
||||
new object[] { JsonNode.Parse("{\"date\": \"2025-08-20T14:30:00\", \"timeZone\": \"Europe/Copenhagen\"}"), DateTimeConfiguration.TimeZoneMode.Local, Array.Empty<string>(), true },
|
||||
new object[] { JsonNode.Parse("{\"date\": \"2025-08-20T14:30:00\", \"timeZone\": \"Europe/Copenhagen\"}"), DateTimeConfiguration.TimeZoneMode.Custom, Array.Empty<string>(), false },
|
||||
new object[] { JsonNode.Parse("{\"date\": \"2025-08-20T14:30:00\", \"timeZone\": \"Europe/Copenhagen\"}"), DateTimeConfiguration.TimeZoneMode.Custom, new[] { "Europe/Copenhagen" }, true },
|
||||
new object[] { JsonNode.Parse("{\"date\": \"2025-08-20T14:30:00\", \"timeZone\": \"Europe/Copenhagen\"}"), DateTimeConfiguration.TimeZoneMode.Custom, new[] { "Europe/Amsterdam", "Europe/Copenhagen" }, true },
|
||||
new object[] { JsonNode.Parse("{\"date\": \"2025-08-20T14:30:00\", \"timeZone\": \"Europe/Copenhagen\"}"), DateTimeConfiguration.TimeZoneMode.Custom, new[] { "Europe/Amsterdam" }, false },
|
||||
];
|
||||
|
||||
[TestCaseSource(nameof(_sourceList2))]
|
||||
public void Validates_TimeZone_Received(
|
||||
object value,
|
||||
DateTimeConfiguration.TimeZoneMode timeZoneMode,
|
||||
string[] timeZones,
|
||||
bool expectedSuccess)
|
||||
{
|
||||
var editor = CreateValueEditor(timeZoneMode: timeZoneMode, timeZones: timeZones);
|
||||
var result = editor.Validate(value, false, null, PropertyValidationContext.Empty()).ToList();
|
||||
if (expectedSuccess)
|
||||
{
|
||||
Assert.IsEmpty(result);
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert.AreEqual(1, result.Count);
|
||||
|
||||
var validationResult = result.First();
|
||||
Assert.AreEqual("validation_notOneOfOptions", validationResult.ErrorMessage);
|
||||
}
|
||||
}
|
||||
|
||||
[TestCaseSource(nameof(_validateDateReceivedTestCases))]
|
||||
public void Validates_Date_Received(object? value, bool expectedSuccess)
|
||||
{
|
||||
var editor = CreateValueEditor();
|
||||
var result = editor.Validate(value, false, null, PropertyValidationContext.Empty()).ToList();
|
||||
if (expectedSuccess)
|
||||
{
|
||||
Assert.IsEmpty(result);
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert.AreEqual(1, result.Count);
|
||||
|
||||
var validationResult = result.First();
|
||||
Assert.AreEqual("validation_invalidDate", validationResult.ErrorMessage);
|
||||
}
|
||||
}
|
||||
|
||||
private static readonly object[] _dateTimeWithTimeZoneParseValuesFromEditorTestCases =
|
||||
[
|
||||
new object[] { null, null, null },
|
||||
new object[] { JsonNode.Parse("{}"), null, null },
|
||||
new object[] { JsonNode.Parse("{\"INVALID\": \"\"}"), null, null },
|
||||
new object[] { JsonNode.Parse("{\"date\": \"2025-08-20T18:30:01\"}"), new DateTimeOffset(2025, 8, 20, 18, 30, 1, TimeSpan.Zero), null },
|
||||
new object[] { JsonNode.Parse("{\"date\": \"2025-08-20T18:30:01Z\"}"), new DateTimeOffset(2025, 8, 20, 18, 30, 1, TimeSpan.Zero), null },
|
||||
new object[] { JsonNode.Parse("{\"date\": \"2025-08-20T18:30:01-05:00\"}"), new DateTimeOffset(2025, 8, 20, 18, 30, 1, TimeSpan.FromHours(-5)), null },
|
||||
];
|
||||
|
||||
[TestCaseSource(nameof(_dateTimeWithTimeZoneParseValuesFromEditorTestCases))]
|
||||
public void Can_Parse_Values_From_Editor(
|
||||
object? value,
|
||||
DateTimeOffset? expectedDateTimeOffset,
|
||||
string? expectedTimeZone)
|
||||
{
|
||||
var expectedJson = expectedDateTimeOffset is null ? null : _jsonSerializer.Serialize(
|
||||
new DateTimeValueConverterBase.DateTimeDto
|
||||
{
|
||||
Date = expectedDateTimeOffset.Value,
|
||||
TimeZone = expectedTimeZone,
|
||||
});
|
||||
var result = CreateValueEditor().FromEditor(
|
||||
new ContentPropertyData(
|
||||
value,
|
||||
new DateTimeConfiguration
|
||||
{
|
||||
TimeZones = null,
|
||||
}),
|
||||
null);
|
||||
Assert.AreEqual(expectedJson, result);
|
||||
}
|
||||
|
||||
private static readonly object[][] _dateTimeWithTimeZoneParseValuesToEditorTestCases =
|
||||
[
|
||||
[null, null, DateTimeConfiguration.TimeZoneMode.All, null],
|
||||
[0, null, DateTimeConfiguration.TimeZoneMode.All, new DateTimeEditorValue { Date = "2025-08-20T16:30:00+00:00", TimeZone = null }],
|
||||
[0, null, DateTimeConfiguration.TimeZoneMode.Local, new DateTimeEditorValue { Date = "2025-08-20T16:30:00+00:00", TimeZone = null }],
|
||||
[0, null, DateTimeConfiguration.TimeZoneMode.Custom, new DateTimeEditorValue { Date = "2025-08-20T16:30:00+00:00", TimeZone = null }],
|
||||
[-5, "Europe/Copenhagen", DateTimeConfiguration.TimeZoneMode.All, new DateTimeEditorValue { Date = "2025-08-20T16:30:00-05:00", TimeZone = "Europe/Copenhagen" }],
|
||||
];
|
||||
|
||||
[TestCaseSource(nameof(_dateTimeWithTimeZoneParseValuesToEditorTestCases))]
|
||||
public void Can_Parse_Values_To_Editor(
|
||||
int? offset,
|
||||
string? timeZone,
|
||||
DateTimeConfiguration.TimeZoneMode timeZoneMode,
|
||||
object? expectedResult)
|
||||
{
|
||||
var storedValue = offset is null
|
||||
? null
|
||||
: new DateTimeValueConverterBase.DateTimeDto
|
||||
{
|
||||
Date = new DateTimeOffset(2025, 8, 20, 16, 30, 00, TimeSpan.FromHours(offset.Value)),
|
||||
TimeZone = timeZone,
|
||||
};
|
||||
var valueEditor = CreateValueEditor(timeZoneMode: timeZoneMode);
|
||||
var storedValueJson = storedValue is null ? null : _jsonSerializer.Serialize(storedValue);
|
||||
var result = valueEditor.ToEditor(
|
||||
new Property(new PropertyType(Mock.Of<IShortStringHelper>(), "dataType", ValueStorageType.Ntext))
|
||||
{
|
||||
Values =
|
||||
[
|
||||
new Property.PropertyValue
|
||||
{
|
||||
EditedValue = storedValueJson,
|
||||
PublishedValue = storedValueJson,
|
||||
}
|
||||
],
|
||||
});
|
||||
|
||||
if (expectedResult is null)
|
||||
{
|
||||
Assert.IsNull(result);
|
||||
return;
|
||||
}
|
||||
|
||||
Assert.IsNotNull(result);
|
||||
Assert.IsInstanceOf<DateTimeEditorValue>(result);
|
||||
var apiModel = (DateTimeEditorValue)result;
|
||||
Assert.AreEqual(((DateTimeEditorValue)expectedResult).Date, apiModel.Date);
|
||||
Assert.AreEqual(((DateTimeEditorValue)expectedResult).TimeZone, apiModel.TimeZone);
|
||||
}
|
||||
|
||||
private DateTimePropertyEditorBase.DateTimeDataValueEditor CreateValueEditor(
|
||||
DateTimeConfiguration.TimeZoneMode timeZoneMode = DateTimeConfiguration.TimeZoneMode.All,
|
||||
string[]? timeZones = null)
|
||||
{
|
||||
var localizedTextServiceMock = new Mock<ILocalizedTextService>();
|
||||
localizedTextServiceMock.Setup(x => x.Localize(
|
||||
It.IsAny<string>(),
|
||||
It.IsAny<string>(),
|
||||
It.IsAny<CultureInfo>(),
|
||||
It.IsAny<IDictionary<string, string>>()))
|
||||
.Returns((string key, string alias, CultureInfo _, IDictionary<string, string> _) => $"{key}_{alias}");
|
||||
var valueEditor = new DateTimePropertyEditorBase.DateTimeDataValueEditor(
|
||||
Mock.Of<IShortStringHelper>(),
|
||||
_jsonSerializer,
|
||||
Mock.Of<IIOHelper>(),
|
||||
new DataEditorAttribute(Constants.PropertyEditors.Aliases.DateTimeWithTimeZone),
|
||||
localizedTextServiceMock.Object,
|
||||
Mock.Of<ILogger<DateTimePropertyEditorBase.DateTimeDataValueEditor>>(),
|
||||
dt => dt.Date.ToString("yyyy-MM-ddTHH:mm:sszzz"))
|
||||
{
|
||||
ConfigurationObject = new DateTimeConfiguration
|
||||
{
|
||||
TimeZones = new DateTimeConfiguration.TimeZonesConfiguration
|
||||
{
|
||||
Mode = timeZoneMode,
|
||||
TimeZones = timeZones?.ToList() ?? [],
|
||||
},
|
||||
},
|
||||
};
|
||||
return valueEditor;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,164 @@
|
||||
using System.Globalization;
|
||||
using System.Text.Json.Nodes;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Core.IO;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Models.Editors;
|
||||
using Umbraco.Cms.Core.Models.Validation;
|
||||
using Umbraco.Cms.Core.PropertyEditors;
|
||||
using Umbraco.Cms.Core.PropertyEditors.ValueConverters;
|
||||
using Umbraco.Cms.Core.Serialization;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
using Umbraco.Cms.Core.Strings;
|
||||
using Umbraco.Cms.Infrastructure.Models;
|
||||
using Umbraco.Cms.Infrastructure.Serialization;
|
||||
|
||||
namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Core.PropertyEditors;
|
||||
|
||||
[TestFixture]
|
||||
public class TimeOnlyPropertyEditorTests
|
||||
{
|
||||
private static readonly IJsonSerializer _jsonSerializer =
|
||||
new SystemTextJsonSerializer(new DefaultJsonSerializerEncoderFactory());
|
||||
|
||||
private static readonly object[] _validateDateReceivedTestCases =
|
||||
[
|
||||
new object[] { null, true },
|
||||
new object[] { JsonNode.Parse("{}"), false },
|
||||
new object[] { JsonNode.Parse("{\"test\": \"\"}"), false },
|
||||
new object[] { JsonNode.Parse("{\"date\": \"\"}"), false },
|
||||
new object[] { JsonNode.Parse("{\"date\": \"INVALID\"}"), false },
|
||||
new object[] { JsonNode.Parse("{\"date\": \"2025-08-20T14:30:00\"}"), true }
|
||||
];
|
||||
|
||||
[TestCaseSource(nameof(_validateDateReceivedTestCases))]
|
||||
public void Validates_Date_Received(object? value, bool expectedSuccess)
|
||||
{
|
||||
var editor = CreateValueEditor();
|
||||
var result = editor.Validate(value, false, null, PropertyValidationContext.Empty()).ToList();
|
||||
if (expectedSuccess)
|
||||
{
|
||||
Assert.IsEmpty(result);
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert.AreEqual(1, result.Count);
|
||||
|
||||
var validationResult = result.First();
|
||||
Assert.AreEqual("validation_invalidDate", validationResult.ErrorMessage);
|
||||
}
|
||||
}
|
||||
|
||||
private static readonly object[] _timeOnlyParseValuesFromEditorTestCases =
|
||||
[
|
||||
new object[] { null, null, null },
|
||||
new object[] { JsonNode.Parse("{\"date\": \"16:34\"}"), new DateTimeOffset(1, 1, 1, 16, 34, 0, TimeSpan.Zero), null },
|
||||
];
|
||||
|
||||
[TestCaseSource(nameof(_timeOnlyParseValuesFromEditorTestCases))]
|
||||
public void Can_Parse_Values_From_Editor(
|
||||
object? value,
|
||||
DateTimeOffset? expectedDateTimeOffset,
|
||||
string? expectedTimeZone)
|
||||
{
|
||||
var expectedJson = expectedDateTimeOffset is null ? null : _jsonSerializer.Serialize(
|
||||
new DateTimeValueConverterBase.DateTimeDto
|
||||
{
|
||||
Date = expectedDateTimeOffset.Value,
|
||||
TimeZone = expectedTimeZone,
|
||||
});
|
||||
var result = CreateValueEditor().FromEditor(
|
||||
new ContentPropertyData(
|
||||
value,
|
||||
new DateTimeConfiguration
|
||||
{
|
||||
TimeZones = null,
|
||||
}),
|
||||
null);
|
||||
Assert.AreEqual(expectedJson, result);
|
||||
}
|
||||
|
||||
private static readonly object[][] _timeOnlyParseValuesToEditorTestCases =
|
||||
[
|
||||
[null, null, null],
|
||||
[0, null, new DateTimeEditorValue { Date = "16:30:00", TimeZone = null }],
|
||||
];
|
||||
|
||||
[TestCaseSource(nameof(_timeOnlyParseValuesToEditorTestCases))]
|
||||
public void Can_Parse_Values_To_Editor(
|
||||
int? offset,
|
||||
string? timeZone,
|
||||
object? expectedResult)
|
||||
{
|
||||
var storedValue = offset is null
|
||||
? null
|
||||
: new DateTimeValueConverterBase.DateTimeDto
|
||||
{
|
||||
Date = new DateTimeOffset(2025, 8, 20, 16, 30, 00, TimeSpan.FromHours(offset.Value)),
|
||||
TimeZone = timeZone,
|
||||
};
|
||||
var valueEditor = CreateValueEditor(timeZoneMode: null);
|
||||
var storedValueJson = storedValue is null ? null : _jsonSerializer.Serialize(storedValue);
|
||||
var result = valueEditor.ToEditor(
|
||||
new Property(new PropertyType(Mock.Of<IShortStringHelper>(), "dataType", ValueStorageType.Ntext))
|
||||
{
|
||||
Values =
|
||||
[
|
||||
new Property.PropertyValue
|
||||
{
|
||||
EditedValue = storedValueJson,
|
||||
PublishedValue = storedValueJson,
|
||||
}
|
||||
],
|
||||
});
|
||||
|
||||
if (expectedResult is null)
|
||||
{
|
||||
Assert.IsNull(result);
|
||||
return;
|
||||
}
|
||||
|
||||
Assert.IsNotNull(result);
|
||||
Assert.IsInstanceOf<DateTimeEditorValue>(result);
|
||||
var apiModel = (DateTimeEditorValue)result;
|
||||
Assert.AreEqual(((DateTimeEditorValue)expectedResult).Date, apiModel.Date);
|
||||
Assert.AreEqual(((DateTimeEditorValue)expectedResult).TimeZone, apiModel.TimeZone);
|
||||
}
|
||||
|
||||
private DateTimePropertyEditorBase.DateTimeDataValueEditor CreateValueEditor(
|
||||
DateTimeConfiguration.TimeZoneMode? timeZoneMode = null,
|
||||
string[]? timeZones = null)
|
||||
{
|
||||
var localizedTextServiceMock = new Mock<ILocalizedTextService>();
|
||||
localizedTextServiceMock.Setup(x => x.Localize(
|
||||
It.IsAny<string>(),
|
||||
It.IsAny<string>(),
|
||||
It.IsAny<CultureInfo>(),
|
||||
It.IsAny<IDictionary<string, string>>()))
|
||||
.Returns((string key, string alias, CultureInfo _, IDictionary<string, string> _) => $"{key}_{alias}");
|
||||
var valueEditor = new DateTimePropertyEditorBase.DateTimeDataValueEditor(
|
||||
Mock.Of<IShortStringHelper>(),
|
||||
_jsonSerializer,
|
||||
Mock.Of<IIOHelper>(),
|
||||
new DataEditorAttribute(Constants.PropertyEditors.Aliases.TimeOnly),
|
||||
localizedTextServiceMock.Object,
|
||||
Mock.Of<ILogger<DateTimePropertyEditorBase.DateTimeDataValueEditor>>(),
|
||||
dt => dt.Date.ToString("HH:mm:ss"))
|
||||
{
|
||||
ConfigurationObject = new DateTimeConfiguration
|
||||
{
|
||||
TimeZones = timeZoneMode is null
|
||||
? null
|
||||
: new DateTimeConfiguration.TimeZonesConfiguration
|
||||
{
|
||||
Mode = timeZoneMode.Value,
|
||||
TimeZones = timeZones?.ToList() ?? [],
|
||||
},
|
||||
},
|
||||
};
|
||||
return valueEditor;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Core.Models.PublishedContent;
|
||||
using Umbraco.Cms.Core.PropertyEditors;
|
||||
using Umbraco.Cms.Core.PropertyEditors.ValueConverters;
|
||||
using Umbraco.Cms.Core.Serialization;
|
||||
using Umbraco.Cms.Infrastructure.Serialization;
|
||||
|
||||
namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Core.PropertyEditors.ValueConverters;
|
||||
|
||||
[TestFixture]
|
||||
public class DateOnlyValueConverterTests
|
||||
{
|
||||
private readonly IJsonSerializer _jsonSerializer =
|
||||
new SystemTextJsonSerializer(new DefaultJsonSerializerEncoderFactory());
|
||||
|
||||
private static readonly DateTimeValueConverterBase.DateTimeDto _convertToObjectInputDate = new()
|
||||
{
|
||||
Date = new DateTimeOffset(2025, 08, 20, 16, 30, 0, TimeSpan.FromHours(-1)),
|
||||
TimeZone = "Europe/Copenhagen",
|
||||
};
|
||||
|
||||
[TestCase(Constants.PropertyEditors.Aliases.DateOnly, true)]
|
||||
[TestCase(Constants.PropertyEditors.Aliases.DateTimeUnspecified, false)]
|
||||
[TestCase(Constants.PropertyEditors.Aliases.DateTimeWithTimeZone, false)]
|
||||
[TestCase(Constants.PropertyEditors.Aliases.TimeOnly, false)]
|
||||
[TestCase(Constants.PropertyEditors.Aliases.DateTime, false)]
|
||||
public void IsConverter_For(string propertyEditorAlias, bool expected)
|
||||
{
|
||||
var propertyType = Mock.Of<IPublishedPropertyType>(x => x.EditorAlias == propertyEditorAlias);
|
||||
var converter = new DateOnlyValueConverter(Mock.Of<IJsonSerializer>(MockBehavior.Strict), Mock.Of<ILogger<DateOnlyValueConverter>>());
|
||||
|
||||
var result = converter.IsConverter(propertyType);
|
||||
|
||||
Assert.AreEqual(expected, result);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetPropertyValueType_ReturnsExpectedType()
|
||||
{
|
||||
var converter = new DateOnlyValueConverter(Mock.Of<IJsonSerializer>(MockBehavior.Strict), Mock.Of<ILogger<DateOnlyValueConverter>>());
|
||||
var dataType = new PublishedDataType(
|
||||
0,
|
||||
"test",
|
||||
"test",
|
||||
new Lazy<object?>(() =>
|
||||
new DateTimeConfiguration
|
||||
{
|
||||
TimeZones = null,
|
||||
}));
|
||||
var propertyType = Mock.Of<IPublishedPropertyType>(x => x.DataType == dataType);
|
||||
|
||||
var result = converter.GetPropertyValueType(propertyType);
|
||||
|
||||
Assert.AreEqual(typeof(DateOnly?), result);
|
||||
}
|
||||
|
||||
private static readonly object[] _convertToIntermediateCases =
|
||||
[
|
||||
new object[] { null, null },
|
||||
new object[] { """{"date":"2025-08-20T16:30:00.0000000Z","timeZone":null}""", new DateTimeValueConverterBase.DateTimeDto { Date = new DateTimeOffset(2025, 08, 20, 16, 30, 0, TimeSpan.Zero), TimeZone = null } },
|
||||
new object[] { """{"date":"2025-08-20T16:30:00.0000000Z","timeZone":"Europe/Copenhagen"}""", new DateTimeValueConverterBase.DateTimeDto { Date = new DateTimeOffset(2025, 08, 20, 16, 30, 0, TimeSpan.Zero), TimeZone = "Europe/Copenhagen" } },
|
||||
new object[] { """{"date":"2025-08-20T16:30:00.0000000-05:00","timeZone":"Europe/Copenhagen"}""", new DateTimeValueConverterBase.DateTimeDto { Date = new DateTimeOffset(2025, 08, 20, 16, 30, 0, TimeSpan.FromHours(-5)), TimeZone = "Europe/Copenhagen" } },
|
||||
];
|
||||
|
||||
[TestCaseSource(nameof(_convertToIntermediateCases))]
|
||||
public void Can_Convert_To_Intermediate_Value(string? input, object? expected)
|
||||
{
|
||||
var result = new DateOnlyValueConverter(_jsonSerializer, Mock.Of<ILogger<DateOnlyValueConverter>>()).ConvertSourceToIntermediate(null!, null!, input, false);
|
||||
if (expected is null)
|
||||
{
|
||||
Assert.IsNull(result);
|
||||
return;
|
||||
}
|
||||
|
||||
Assert.IsNotNull(result);
|
||||
Assert.IsInstanceOf<DateTimeValueConverterBase.DateTimeDto>(result);
|
||||
var dateTime = (DateTimeValueConverterBase.DateTimeDto)result;
|
||||
Assert.IsInstanceOf<DateTimeValueConverterBase.DateTimeDto>(dateTime);
|
||||
Assert.AreEqual(((DateTimeValueConverterBase.DateTimeDto)expected).Date, dateTime.Date);
|
||||
Assert.AreEqual(((DateTimeValueConverterBase.DateTimeDto)expected).TimeZone, dateTime.TimeZone);
|
||||
}
|
||||
|
||||
private static object[] _dateOnlyConvertToObjectCases =
|
||||
[
|
||||
new object[] { null, null },
|
||||
new object[] { _convertToObjectInputDate, DateOnly.Parse("2025-08-20") },
|
||||
];
|
||||
|
||||
[TestCaseSource(nameof(_dateOnlyConvertToObjectCases))]
|
||||
public void Can_Convert_To_Object(
|
||||
object? input,
|
||||
object? expected)
|
||||
{
|
||||
var dataType = new PublishedDataType(
|
||||
0,
|
||||
"test",
|
||||
"test",
|
||||
new Lazy<object?>(() =>
|
||||
new DateTimeConfiguration
|
||||
{
|
||||
TimeZones = null,
|
||||
}));
|
||||
|
||||
var propertyType = new Mock<IPublishedPropertyType>(MockBehavior.Strict);
|
||||
propertyType.SetupGet(x => x.DataType)
|
||||
.Returns(dataType);
|
||||
|
||||
var result = new DateOnlyValueConverter(_jsonSerializer, Mock.Of<ILogger<DateOnlyValueConverter>>())
|
||||
.ConvertIntermediateToObject(null!, propertyType.Object, PropertyCacheLevel.Unknown, input, false);
|
||||
if (expected is null)
|
||||
{
|
||||
Assert.IsNull(result);
|
||||
return;
|
||||
}
|
||||
|
||||
Assert.IsNotNull(result);
|
||||
Assert.AreEqual(expected, result);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Core.Models.PublishedContent;
|
||||
using Umbraco.Cms.Core.PropertyEditors;
|
||||
using Umbraco.Cms.Core.PropertyEditors.ValueConverters;
|
||||
using Umbraco.Cms.Core.Serialization;
|
||||
using Umbraco.Cms.Infrastructure.Serialization;
|
||||
|
||||
namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Core.PropertyEditors.ValueConverters;
|
||||
|
||||
[TestFixture]
|
||||
public class DateTimeUnspecifiedValueConverterTests
|
||||
{
|
||||
private readonly IJsonSerializer _jsonSerializer =
|
||||
new SystemTextJsonSerializer(new DefaultJsonSerializerEncoderFactory());
|
||||
|
||||
private static readonly DateTimeValueConverterBase.DateTimeDto _convertToObjectInputDate = new()
|
||||
{
|
||||
Date = new DateTimeOffset(2025, 08, 20, 16, 30, 0, TimeSpan.FromHours(-1)),
|
||||
TimeZone = "Europe/Copenhagen",
|
||||
};
|
||||
|
||||
[TestCase(Constants.PropertyEditors.Aliases.DateTimeUnspecified, true)]
|
||||
[TestCase(Constants.PropertyEditors.Aliases.DateTimeWithTimeZone, false)]
|
||||
[TestCase(Constants.PropertyEditors.Aliases.DateOnly, false)]
|
||||
[TestCase(Constants.PropertyEditors.Aliases.TimeOnly, false)]
|
||||
[TestCase(Constants.PropertyEditors.Aliases.DateTime, false)]
|
||||
public void IsConverter_For(string propertyEditorAlias, bool expected)
|
||||
{
|
||||
var propertyType = Mock.Of<IPublishedPropertyType>(x => x.EditorAlias == propertyEditorAlias);
|
||||
var converter = new DateTimeUnspecifiedValueConverter(Mock.Of<IJsonSerializer>(MockBehavior.Strict), Mock.Of<ILogger<DateTimeUnspecifiedValueConverter>>());
|
||||
|
||||
var result = converter.IsConverter(propertyType);
|
||||
|
||||
Assert.AreEqual(expected, result);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetPropertyValueType_ReturnsExpectedType()
|
||||
{
|
||||
var converter = new DateTimeUnspecifiedValueConverter(Mock.Of<IJsonSerializer>(MockBehavior.Strict), Mock.Of<ILogger<DateTimeUnspecifiedValueConverter>>());
|
||||
var dataType = new PublishedDataType(
|
||||
0,
|
||||
"test",
|
||||
"test",
|
||||
new Lazy<object?>(() =>
|
||||
new DateTimeConfiguration
|
||||
{
|
||||
TimeZones = null,
|
||||
}));
|
||||
var propertyType = Mock.Of<IPublishedPropertyType>(x => x.DataType == dataType);
|
||||
|
||||
var result = converter.GetPropertyValueType(propertyType);
|
||||
|
||||
Assert.AreEqual(typeof(DateTime?), result);
|
||||
}
|
||||
|
||||
private static readonly object[] _convertToIntermediateCases =
|
||||
[
|
||||
new object[] { null, null },
|
||||
new object[] { """{"date":"2025-08-20T16:30:00.0000000Z","timeZone":null}""", new DateTimeValueConverterBase.DateTimeDto { Date = new DateTimeOffset(2025, 08, 20, 16, 30, 0, TimeSpan.Zero), TimeZone = null } },
|
||||
new object[] { """{"date":"2025-08-20T16:30:00.0000000Z","timeZone":"Europe/Copenhagen"}""", new DateTimeValueConverterBase.DateTimeDto { Date = new DateTimeOffset(2025, 08, 20, 16, 30, 0, TimeSpan.Zero), TimeZone = "Europe/Copenhagen" } },
|
||||
new object[] { """{"date":"2025-08-20T16:30:00.0000000-05:00","timeZone":"Europe/Copenhagen"}""", new DateTimeValueConverterBase.DateTimeDto { Date = new DateTimeOffset(2025, 08, 20, 16, 30, 0, TimeSpan.FromHours(-5)), TimeZone = "Europe/Copenhagen" } },
|
||||
];
|
||||
|
||||
[TestCaseSource(nameof(_convertToIntermediateCases))]
|
||||
public void Can_Convert_To_Intermediate_Value(string? input, object? expected)
|
||||
{
|
||||
var result = new DateTimeUnspecifiedValueConverter(_jsonSerializer, Mock.Of<ILogger<DateTimeUnspecifiedValueConverter>>()).ConvertSourceToIntermediate(null!, null!, input, false);
|
||||
if (expected is null)
|
||||
{
|
||||
Assert.IsNull(result);
|
||||
return;
|
||||
}
|
||||
|
||||
Assert.IsNotNull(result);
|
||||
Assert.IsInstanceOf<DateTimeValueConverterBase.DateTimeDto>(result);
|
||||
var dateTime = (DateTimeValueConverterBase.DateTimeDto)result;
|
||||
Assert.IsInstanceOf<DateTimeValueConverterBase.DateTimeDto>(dateTime);
|
||||
Assert.AreEqual(((DateTimeValueConverterBase.DateTimeDto)expected).Date, dateTime.Date);
|
||||
Assert.AreEqual(((DateTimeValueConverterBase.DateTimeDto)expected).TimeZone, dateTime.TimeZone);
|
||||
}
|
||||
|
||||
private static object[] _dateTimeUnspecifiedConvertToObjectCases =
|
||||
[
|
||||
new object[] { null, null },
|
||||
new object[] { _convertToObjectInputDate, DateTime.Parse("2025-08-20T17:30:00") },
|
||||
];
|
||||
|
||||
[TestCaseSource(nameof(_dateTimeUnspecifiedConvertToObjectCases))]
|
||||
public void Can_Convert_To_Object(
|
||||
object? input,
|
||||
object? expected)
|
||||
{
|
||||
var dataType = new PublishedDataType(
|
||||
0,
|
||||
"test",
|
||||
"test",
|
||||
new Lazy<object?>(() =>
|
||||
new DateTimeConfiguration
|
||||
{
|
||||
TimeZones = null,
|
||||
}));
|
||||
|
||||
var propertyType = new Mock<IPublishedPropertyType>(MockBehavior.Strict);
|
||||
propertyType.SetupGet(x => x.DataType)
|
||||
.Returns(dataType);
|
||||
|
||||
var result = new DateTimeUnspecifiedValueConverter(_jsonSerializer, Mock.Of<ILogger<DateTimeUnspecifiedValueConverter>>())
|
||||
.ConvertIntermediateToObject(null!, propertyType.Object, PropertyCacheLevel.Unknown, input, false);
|
||||
if (expected is null)
|
||||
{
|
||||
Assert.IsNull(result);
|
||||
return;
|
||||
}
|
||||
|
||||
Assert.IsNotNull(result);
|
||||
Assert.AreEqual(expected, result);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Core.Models.PublishedContent;
|
||||
using Umbraco.Cms.Core.PropertyEditors;
|
||||
using Umbraco.Cms.Core.PropertyEditors.ValueConverters;
|
||||
using Umbraco.Cms.Core.Serialization;
|
||||
using Umbraco.Cms.Infrastructure.Serialization;
|
||||
|
||||
namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Core.PropertyEditors.ValueConverters;
|
||||
|
||||
[TestFixture]
|
||||
public class DateTimeWithTimeZoneValueConverterTests
|
||||
{
|
||||
private readonly IJsonSerializer _jsonSerializer =
|
||||
new SystemTextJsonSerializer(new DefaultJsonSerializerEncoderFactory());
|
||||
|
||||
private static readonly DateTimeValueConverterBase.DateTimeDto _convertToObjectInputDate = new()
|
||||
{
|
||||
Date = new DateTimeOffset(2025, 08, 20, 16, 30, 0, TimeSpan.FromHours(-1)),
|
||||
TimeZone = "Europe/Copenhagen",
|
||||
};
|
||||
|
||||
[TestCase(Constants.PropertyEditors.Aliases.DateTimeWithTimeZone, true)]
|
||||
[TestCase(Constants.PropertyEditors.Aliases.DateTimeUnspecified, false)]
|
||||
[TestCase(Constants.PropertyEditors.Aliases.DateOnly, false)]
|
||||
[TestCase(Constants.PropertyEditors.Aliases.TimeOnly, false)]
|
||||
[TestCase(Constants.PropertyEditors.Aliases.DateTime, false)]
|
||||
public void IsConverter_For(string propertyEditorAlias, bool expected)
|
||||
{
|
||||
var propertyType = Mock.Of<IPublishedPropertyType>(x => x.EditorAlias == propertyEditorAlias);
|
||||
var converter = new DateTimeWithTimeZoneValueConverter(Mock.Of<IJsonSerializer>(MockBehavior.Strict), Mock.Of<ILogger<DateTimeWithTimeZoneValueConverter>>());
|
||||
|
||||
var result = converter.IsConverter(propertyType);
|
||||
|
||||
Assert.AreEqual(expected, result);
|
||||
}
|
||||
|
||||
[TestCase(DateTimeConfiguration.TimeZoneMode.All)]
|
||||
[TestCase(DateTimeConfiguration.TimeZoneMode.Custom)]
|
||||
[TestCase(DateTimeConfiguration.TimeZoneMode.Local)]
|
||||
public void GetPropertyValueType_ReturnsExpectedType(DateTimeConfiguration.TimeZoneMode timeZoneMode)
|
||||
{
|
||||
var converter = new DateTimeWithTimeZoneValueConverter(Mock.Of<IJsonSerializer>(MockBehavior.Strict), Mock.Of<ILogger<DateTimeWithTimeZoneValueConverter>>());
|
||||
var dataType = new PublishedDataType(
|
||||
0,
|
||||
"test",
|
||||
"test",
|
||||
new Lazy<object?>(() =>
|
||||
new DateTimeConfiguration
|
||||
{
|
||||
TimeZones = new DateTimeConfiguration.TimeZonesConfiguration { Mode = timeZoneMode },
|
||||
}));
|
||||
var propertyType = Mock.Of<IPublishedPropertyType>(x => x.DataType == dataType);
|
||||
|
||||
var result = converter.GetPropertyValueType(propertyType);
|
||||
|
||||
Assert.AreEqual(typeof(DateTimeOffset?), result);
|
||||
}
|
||||
|
||||
private static readonly object[] _convertToIntermediateCases =
|
||||
[
|
||||
new object[] { null, null },
|
||||
new object[] { """{"date":"2025-08-20T16:30:00.0000000Z","timeZone":null}""", new DateTimeValueConverterBase.DateTimeDto { Date = new DateTimeOffset(2025, 08, 20, 16, 30, 0, TimeSpan.Zero), TimeZone = null } },
|
||||
new object[] { """{"date":"2025-08-20T16:30:00.0000000Z","timeZone":"Europe/Copenhagen"}""", new DateTimeValueConverterBase.DateTimeDto { Date = new DateTimeOffset(2025, 08, 20, 16, 30, 0, TimeSpan.Zero), TimeZone = "Europe/Copenhagen" } },
|
||||
new object[] { """{"date":"2025-08-20T16:30:00.0000000-05:00","timeZone":"Europe/Copenhagen"}""", new DateTimeValueConverterBase.DateTimeDto { Date = new DateTimeOffset(2025, 08, 20, 16, 30, 0, TimeSpan.FromHours(-5)), TimeZone = "Europe/Copenhagen" } },
|
||||
];
|
||||
|
||||
[TestCaseSource(nameof(_convertToIntermediateCases))]
|
||||
public void Can_Convert_To_Intermediate_Value(string? input, object? expected)
|
||||
{
|
||||
var result = new DateTimeWithTimeZoneValueConverter(_jsonSerializer, Mock.Of<ILogger<DateTimeWithTimeZoneValueConverter>>()).ConvertSourceToIntermediate(null!, null!, input, false);
|
||||
if (expected is null)
|
||||
{
|
||||
Assert.IsNull(result);
|
||||
return;
|
||||
}
|
||||
|
||||
Assert.IsNotNull(result);
|
||||
Assert.IsInstanceOf<DateTimeValueConverterBase.DateTimeDto>(result);
|
||||
var dateTime = (DateTimeValueConverterBase.DateTimeDto)result;
|
||||
Assert.IsInstanceOf<DateTimeValueConverterBase.DateTimeDto>(dateTime);
|
||||
Assert.AreEqual(((DateTimeValueConverterBase.DateTimeDto)expected).Date, dateTime.Date);
|
||||
Assert.AreEqual(((DateTimeValueConverterBase.DateTimeDto)expected).TimeZone, dateTime.TimeZone);
|
||||
}
|
||||
|
||||
private static object[] _dateTimeWithTimeZoneConvertToObjectCases =
|
||||
[
|
||||
new object[] { null, DateTimeConfiguration.TimeZoneMode.All, null },
|
||||
new object[] { _convertToObjectInputDate, DateTimeConfiguration.TimeZoneMode.All, _convertToObjectInputDate.Date },
|
||||
new object[] { _convertToObjectInputDate, DateTimeConfiguration.TimeZoneMode.Local, _convertToObjectInputDate.Date },
|
||||
new object[] { _convertToObjectInputDate, DateTimeConfiguration.TimeZoneMode.Custom, _convertToObjectInputDate.Date },
|
||||
];
|
||||
|
||||
[TestCaseSource(nameof(_dateTimeWithTimeZoneConvertToObjectCases))]
|
||||
public void Can_Convert_To_Object(
|
||||
object? input,
|
||||
DateTimeConfiguration.TimeZoneMode timeZoneMode,
|
||||
object? expected)
|
||||
{
|
||||
var dataType = new PublishedDataType(
|
||||
0,
|
||||
"test",
|
||||
"test",
|
||||
new Lazy<object?>(() =>
|
||||
new DateTimeConfiguration
|
||||
{
|
||||
TimeZones = new DateTimeConfiguration.TimeZonesConfiguration { Mode = timeZoneMode },
|
||||
}));
|
||||
|
||||
var propertyType = new Mock<IPublishedPropertyType>(MockBehavior.Strict);
|
||||
propertyType.SetupGet(x => x.DataType)
|
||||
.Returns(dataType);
|
||||
|
||||
var result = new DateTimeWithTimeZoneValueConverter(_jsonSerializer, Mock.Of<ILogger<DateTimeWithTimeZoneValueConverter>>())
|
||||
.ConvertIntermediateToObject(null!, propertyType.Object, PropertyCacheLevel.Unknown, input, false);
|
||||
if (expected is null)
|
||||
{
|
||||
Assert.IsNull(result);
|
||||
return;
|
||||
}
|
||||
|
||||
Assert.IsNotNull(result);
|
||||
Assert.AreEqual(expected, result);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Core.Models.PublishedContent;
|
||||
using Umbraco.Cms.Core.PropertyEditors;
|
||||
using Umbraco.Cms.Core.PropertyEditors.ValueConverters;
|
||||
using Umbraco.Cms.Core.Serialization;
|
||||
using Umbraco.Cms.Infrastructure.Serialization;
|
||||
|
||||
namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Core.PropertyEditors.ValueConverters;
|
||||
|
||||
[TestFixture]
|
||||
public class TimeOnlyValueConverterTests
|
||||
{
|
||||
private readonly IJsonSerializer _jsonSerializer =
|
||||
new SystemTextJsonSerializer(new DefaultJsonSerializerEncoderFactory());
|
||||
|
||||
private static readonly DateTimeValueConverterBase.DateTimeDto _convertToObjectInputDate = new()
|
||||
{
|
||||
Date = new DateTimeOffset(2025, 08, 20, 16, 30, 0, TimeSpan.FromHours(-1)),
|
||||
TimeZone = "Europe/Copenhagen",
|
||||
};
|
||||
|
||||
[TestCase(Constants.PropertyEditors.Aliases.TimeOnly, true)]
|
||||
[TestCase(Constants.PropertyEditors.Aliases.DateTimeUnspecified, false)]
|
||||
[TestCase(Constants.PropertyEditors.Aliases.DateTimeWithTimeZone, false)]
|
||||
[TestCase(Constants.PropertyEditors.Aliases.DateOnly, false)]
|
||||
[TestCase(Constants.PropertyEditors.Aliases.DateTime, false)]
|
||||
public void IsConverter_For(string propertyEditorAlias, bool expected)
|
||||
{
|
||||
var propertyType = Mock.Of<IPublishedPropertyType>(x => x.EditorAlias == propertyEditorAlias);
|
||||
var converter = new TimeOnlyValueConverter(Mock.Of<IJsonSerializer>(MockBehavior.Strict), Mock.Of<ILogger<TimeOnlyValueConverter>>());
|
||||
|
||||
var result = converter.IsConverter(propertyType);
|
||||
|
||||
Assert.AreEqual(expected, result);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetPropertyValueType_ReturnsExpectedType()
|
||||
{
|
||||
var converter = new TimeOnlyValueConverter(Mock.Of<IJsonSerializer>(MockBehavior.Strict), Mock.Of<ILogger<TimeOnlyValueConverter>>());
|
||||
var dataType = new PublishedDataType(
|
||||
0,
|
||||
"test",
|
||||
"test",
|
||||
new Lazy<object?>(() =>
|
||||
new DateTimeConfiguration
|
||||
{
|
||||
TimeZones = null,
|
||||
}));
|
||||
var propertyType = Mock.Of<IPublishedPropertyType>(x => x.DataType == dataType);
|
||||
|
||||
var result = converter.GetPropertyValueType(propertyType);
|
||||
|
||||
Assert.AreEqual(typeof(TimeOnly?), result);
|
||||
}
|
||||
|
||||
private static readonly object[] _convertToIntermediateCases =
|
||||
[
|
||||
new object[] { null, null },
|
||||
new object[] { """{"date":"2025-08-20T16:30:00.0000000Z","timeZone":null}""", new DateTimeValueConverterBase.DateTimeDto { Date = new DateTimeOffset(2025, 08, 20, 16, 30, 0, TimeSpan.Zero), TimeZone = null } },
|
||||
new object[] { """{"date":"2025-08-20T16:30:00.0000000Z","timeZone":"Europe/Copenhagen"}""", new DateTimeValueConverterBase.DateTimeDto { Date = new DateTimeOffset(2025, 08, 20, 16, 30, 0, TimeSpan.Zero), TimeZone = "Europe/Copenhagen" } },
|
||||
new object[] { """{"date":"2025-08-20T16:30:00.0000000-05:00","timeZone":"Europe/Copenhagen"}""", new DateTimeValueConverterBase.DateTimeDto { Date = new DateTimeOffset(2025, 08, 20, 16, 30, 0, TimeSpan.FromHours(-5)), TimeZone = "Europe/Copenhagen" } },
|
||||
];
|
||||
|
||||
[TestCaseSource(nameof(_convertToIntermediateCases))]
|
||||
public void Can_Convert_To_Intermediate_Value(string? input, object? expected)
|
||||
{
|
||||
var result = new TimeOnlyValueConverter(_jsonSerializer, Mock.Of<ILogger<TimeOnlyValueConverter>>()).ConvertSourceToIntermediate(null!, null!, input, false);
|
||||
if (expected is null)
|
||||
{
|
||||
Assert.IsNull(result);
|
||||
return;
|
||||
}
|
||||
|
||||
Assert.IsNotNull(result);
|
||||
Assert.IsInstanceOf<DateTimeValueConverterBase.DateTimeDto>(result);
|
||||
var dateTime = (DateTimeValueConverterBase.DateTimeDto)result;
|
||||
Assert.IsInstanceOf<DateTimeValueConverterBase.DateTimeDto>(dateTime);
|
||||
Assert.AreEqual(((DateTimeValueConverterBase.DateTimeDto)expected).Date, dateTime.Date);
|
||||
Assert.AreEqual(((DateTimeValueConverterBase.DateTimeDto)expected).TimeZone, dateTime.TimeZone);
|
||||
}
|
||||
|
||||
private static object[] _timeOnlyConvertToObjectCases =
|
||||
[
|
||||
new object[] { null, null },
|
||||
new object[] { _convertToObjectInputDate, TimeOnly.Parse("17:30") },
|
||||
];
|
||||
|
||||
[TestCaseSource(nameof(_timeOnlyConvertToObjectCases))]
|
||||
public void Can_Convert_To_Object(
|
||||
object? input,
|
||||
object? expected)
|
||||
{
|
||||
var dataType = new PublishedDataType(
|
||||
0,
|
||||
"test",
|
||||
"test",
|
||||
new Lazy<object?>(() =>
|
||||
new DateTimeConfiguration
|
||||
{
|
||||
TimeZones = null,
|
||||
}));
|
||||
|
||||
var propertyType = new Mock<IPublishedPropertyType>(MockBehavior.Strict);
|
||||
propertyType.SetupGet(x => x.DataType)
|
||||
.Returns(dataType);
|
||||
|
||||
var result = new TimeOnlyValueConverter(_jsonSerializer, Mock.Of<ILogger<TimeOnlyValueConverter>>())
|
||||
.ConvertIntermediateToObject(null!, propertyType.Object, PropertyCacheLevel.Unknown, input, false);
|
||||
if (expected is null)
|
||||
{
|
||||
Assert.IsNull(result);
|
||||
return;
|
||||
}
|
||||
|
||||
Assert.IsNotNull(result);
|
||||
Assert.AreEqual(expected, result);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.PropertyEditors;
|
||||
using Umbraco.Cms.Core.Serialization;
|
||||
using Umbraco.Cms.Infrastructure.Serialization;
|
||||
|
||||
namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Infrastructure.PropertyEditors;
|
||||
|
||||
[TestFixture]
|
||||
[TestOf(typeof(DateOnlyPropertyIndexValueFactory))]
|
||||
public class DateOnlyPropertyIndexValueFactoryTests
|
||||
{
|
||||
private static readonly IJsonSerializer _jsonSerializer = new SystemTextJsonSerializer(new DefaultJsonSerializerEncoderFactory());
|
||||
|
||||
[Test]
|
||||
public void GetIndexValues_ReturnsEmptyValues_ForNullPropertyValue()
|
||||
{
|
||||
var propertyMock = new Mock<IProperty>(MockBehavior.Strict);
|
||||
propertyMock.SetupGet(x => x.Alias)
|
||||
.Returns("testAlias");
|
||||
propertyMock.Setup(x => x.GetValue("en-US", null, true))
|
||||
.Returns(null);
|
||||
var factory = new DateOnlyPropertyIndexValueFactory(_jsonSerializer, Mock.Of<ILogger<DateOnlyPropertyIndexValueFactory>>());
|
||||
|
||||
var result = factory.GetIndexValues(
|
||||
propertyMock.Object,
|
||||
"en-US",
|
||||
null,
|
||||
true,
|
||||
[],
|
||||
new Dictionary<Guid, IContentType>())
|
||||
.ToList();
|
||||
|
||||
Assert.AreEqual(1, result.Count);
|
||||
var indexValue = result.First();
|
||||
Assert.AreEqual(indexValue.FieldName, "testAlias");
|
||||
Assert.IsEmpty(indexValue.Values);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetIndexValues_ReturnsFormattedDateTime()
|
||||
{
|
||||
var propertyMock = new Mock<IProperty>(MockBehavior.Strict);
|
||||
propertyMock.SetupGet(x => x.Alias)
|
||||
.Returns("testAlias");
|
||||
propertyMock.Setup(x => x.GetValue("en-US", null, true))
|
||||
.Returns("{\"date\":\"2023-01-18T12:00:00+01:00\",\"timeZone\":\"Europe/Copenhagen\"}");
|
||||
|
||||
var factory = new DateOnlyPropertyIndexValueFactory(_jsonSerializer, Mock.Of<ILogger<DateOnlyPropertyIndexValueFactory>>());
|
||||
|
||||
var result = factory.GetIndexValues(
|
||||
propertyMock.Object,
|
||||
"en-US",
|
||||
null,
|
||||
true,
|
||||
[],
|
||||
new Dictionary<Guid, IContentType>())
|
||||
.ToList();
|
||||
|
||||
Assert.AreEqual(1, result.Count);
|
||||
var indexValue = result.First();
|
||||
Assert.AreEqual(indexValue.FieldName, "testAlias");
|
||||
Assert.AreEqual(1, indexValue.Values.Count());
|
||||
var value = indexValue.Values.First();
|
||||
Assert.AreEqual("2023-01-18", value);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.PropertyEditors;
|
||||
using Umbraco.Cms.Core.Serialization;
|
||||
using Umbraco.Cms.Infrastructure.Serialization;
|
||||
|
||||
namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Infrastructure.PropertyEditors;
|
||||
|
||||
[TestFixture]
|
||||
[TestOf(typeof(DateTimeUnspecifiedPropertyIndexValueFactory))]
|
||||
public class DateTimeUnspecifiedPropertyIndexValueFactoryTests
|
||||
{
|
||||
private static readonly IJsonSerializer _jsonSerializer = new SystemTextJsonSerializer(new DefaultJsonSerializerEncoderFactory());
|
||||
|
||||
[Test]
|
||||
public void GetIndexValues_ReturnsEmptyValues_ForNullPropertyValue()
|
||||
{
|
||||
var propertyMock = new Mock<IProperty>(MockBehavior.Strict);
|
||||
propertyMock.SetupGet(x => x.Alias)
|
||||
.Returns("testAlias");
|
||||
propertyMock.Setup(x => x.GetValue("en-US", null, true))
|
||||
.Returns(null);
|
||||
var factory = new DateTimeUnspecifiedPropertyIndexValueFactory(_jsonSerializer, Mock.Of<ILogger<DateTimeUnspecifiedPropertyIndexValueFactory>>());
|
||||
|
||||
var result = factory.GetIndexValues(
|
||||
propertyMock.Object,
|
||||
"en-US",
|
||||
null,
|
||||
true,
|
||||
[],
|
||||
new Dictionary<Guid, IContentType>())
|
||||
.ToList();
|
||||
|
||||
Assert.AreEqual(1, result.Count);
|
||||
var indexValue = result.First();
|
||||
Assert.AreEqual(indexValue.FieldName, "testAlias");
|
||||
Assert.IsEmpty(indexValue.Values);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetIndexValues_ReturnsFormattedDateTime()
|
||||
{
|
||||
var propertyMock = new Mock<IProperty>(MockBehavior.Strict);
|
||||
propertyMock.SetupGet(x => x.Alias)
|
||||
.Returns("testAlias");
|
||||
propertyMock.Setup(x => x.GetValue("en-US", null, true))
|
||||
.Returns("{\"date\":\"2023-01-18T12:00:00+01:00\",\"timeZone\":\"Europe/Copenhagen\"}");
|
||||
|
||||
var factory = new DateTimeUnspecifiedPropertyIndexValueFactory(_jsonSerializer, Mock.Of<ILogger<DateTimeUnspecifiedPropertyIndexValueFactory>>());
|
||||
|
||||
var result = factory.GetIndexValues(
|
||||
propertyMock.Object,
|
||||
"en-US",
|
||||
null,
|
||||
true,
|
||||
[],
|
||||
new Dictionary<Guid, IContentType>())
|
||||
.ToList();
|
||||
|
||||
Assert.AreEqual(1, result.Count);
|
||||
var indexValue = result.First();
|
||||
Assert.AreEqual(indexValue.FieldName, "testAlias");
|
||||
Assert.AreEqual(1, indexValue.Values.Count());
|
||||
var value = indexValue.Values.First();
|
||||
Assert.AreEqual("2023-01-18T11:00:00", value);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.PropertyEditors;
|
||||
using Umbraco.Cms.Core.Serialization;
|
||||
using Umbraco.Cms.Infrastructure.Serialization;
|
||||
|
||||
namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Infrastructure.PropertyEditors;
|
||||
|
||||
[TestFixture]
|
||||
[TestOf(typeof(DateTimeWithTimeZonePropertyIndexValueFactory))]
|
||||
public class DateTimeWithTimeZonePropertyIndexValueFactoryTests
|
||||
{
|
||||
private static readonly IJsonSerializer _jsonSerializer = new SystemTextJsonSerializer(new DefaultJsonSerializerEncoderFactory());
|
||||
|
||||
[Test]
|
||||
public void GetIndexValues_ReturnsEmptyValues_ForNullPropertyValue()
|
||||
{
|
||||
var propertyMock = new Mock<IProperty>(MockBehavior.Strict);
|
||||
propertyMock.SetupGet(x => x.Alias)
|
||||
.Returns("testAlias");
|
||||
propertyMock.Setup(x => x.GetValue("en-US", null, true))
|
||||
.Returns(null);
|
||||
var factory = new DateTimeWithTimeZonePropertyIndexValueFactory(_jsonSerializer, Mock.Of<ILogger<DateTimeWithTimeZonePropertyIndexValueFactory>>());
|
||||
|
||||
var result = factory.GetIndexValues(
|
||||
propertyMock.Object,
|
||||
"en-US",
|
||||
null,
|
||||
true,
|
||||
[],
|
||||
new Dictionary<Guid, IContentType>())
|
||||
.ToList();
|
||||
|
||||
Assert.AreEqual(1, result.Count);
|
||||
var indexValue = result.First();
|
||||
Assert.AreEqual(indexValue.FieldName, "testAlias");
|
||||
Assert.IsEmpty(indexValue.Values);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetIndexValues_ReturnsFormattedDateTime()
|
||||
{
|
||||
var propertyMock = new Mock<IProperty>(MockBehavior.Strict);
|
||||
propertyMock.SetupGet(x => x.Alias)
|
||||
.Returns("testAlias");
|
||||
propertyMock.Setup(x => x.GetValue("en-US", null, true))
|
||||
.Returns("{\"date\":\"2023-01-18T12:00:00+01:00\",\"timeZone\":\"Europe/Copenhagen\"}");
|
||||
|
||||
var factory = new DateTimeWithTimeZonePropertyIndexValueFactory(_jsonSerializer, Mock.Of<ILogger<DateTimeWithTimeZonePropertyIndexValueFactory>>());
|
||||
|
||||
var result = factory.GetIndexValues(
|
||||
propertyMock.Object,
|
||||
"en-US",
|
||||
null,
|
||||
true,
|
||||
[],
|
||||
new Dictionary<Guid, IContentType>())
|
||||
.ToList();
|
||||
|
||||
Assert.AreEqual(1, result.Count);
|
||||
var indexValue = result.First();
|
||||
Assert.AreEqual(indexValue.FieldName, "testAlias");
|
||||
Assert.AreEqual(1, indexValue.Values.Count());
|
||||
var value = indexValue.Values.First();
|
||||
Assert.AreEqual("2023-01-18T11:00:00Z", value);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.PropertyEditors;
|
||||
using Umbraco.Cms.Core.Serialization;
|
||||
using Umbraco.Cms.Infrastructure.Serialization;
|
||||
|
||||
namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Infrastructure.PropertyEditors;
|
||||
|
||||
[TestFixture]
|
||||
[TestOf(typeof(TimeOnlyPropertyIndexValueFactory))]
|
||||
public class TimeOnlyPropertyIndexValueFactoryTests
|
||||
{
|
||||
private static readonly IJsonSerializer _jsonSerializer = new SystemTextJsonSerializer(new DefaultJsonSerializerEncoderFactory());
|
||||
|
||||
[Test]
|
||||
public void GetIndexValues_ReturnsEmptyValues_ForNullPropertyValue()
|
||||
{
|
||||
var propertyMock = new Mock<IProperty>(MockBehavior.Strict);
|
||||
propertyMock.SetupGet(x => x.Alias)
|
||||
.Returns("testAlias");
|
||||
propertyMock.Setup(x => x.GetValue("en-US", null, true))
|
||||
.Returns(null);
|
||||
var factory = new TimeOnlyPropertyIndexValueFactory(_jsonSerializer, Mock.Of<ILogger<TimeOnlyPropertyIndexValueFactory>>());
|
||||
|
||||
var result = factory.GetIndexValues(
|
||||
propertyMock.Object,
|
||||
"en-US",
|
||||
null,
|
||||
true,
|
||||
[],
|
||||
new Dictionary<Guid, IContentType>())
|
||||
.ToList();
|
||||
|
||||
Assert.AreEqual(1, result.Count);
|
||||
var indexValue = result.First();
|
||||
Assert.AreEqual(indexValue.FieldName, "testAlias");
|
||||
Assert.IsEmpty(indexValue.Values);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetIndexValues_ReturnsFormattedDateTime()
|
||||
{
|
||||
var propertyMock = new Mock<IProperty>(MockBehavior.Strict);
|
||||
propertyMock.SetupGet(x => x.Alias)
|
||||
.Returns("testAlias");
|
||||
propertyMock.Setup(x => x.GetValue("en-US", null, true))
|
||||
.Returns("{\"date\":\"2023-01-18T12:00:00+01:00\",\"timeZone\":\"Europe/Copenhagen\"}");
|
||||
|
||||
var factory = new TimeOnlyPropertyIndexValueFactory(_jsonSerializer, Mock.Of<ILogger<TimeOnlyPropertyIndexValueFactory>>());
|
||||
|
||||
var result = factory.GetIndexValues(
|
||||
propertyMock.Object,
|
||||
"en-US",
|
||||
null,
|
||||
true,
|
||||
[],
|
||||
new Dictionary<Guid, IContentType>())
|
||||
.ToList();
|
||||
|
||||
Assert.AreEqual(1, result.Count);
|
||||
var indexValue = result.First();
|
||||
Assert.AreEqual(indexValue.FieldName, "testAlias");
|
||||
Assert.AreEqual(1, indexValue.Values.Count());
|
||||
var value = indexValue.Values.First();
|
||||
Assert.AreEqual("11:00:00", value);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user