Added tests and localization to radio button validation (#18512)

* Added tests and localization to radio button validation.

* Remove unnecessary ToString

* Add danish translations

---------

Co-authored-by: mole <nikolajlauridsen@protonmail.ch>
This commit is contained in:
Andy Butland
2025-03-03 13:23:55 +01:00
committed by GitHub
parent 33d83e1491
commit 865a2cd83a
7 changed files with 137 additions and 9 deletions

View File

@@ -121,6 +121,7 @@ Mange hilsner fra Umbraco robotten
<key alias="invalidStep">Værdien %0% passer ikke med den konfigureret trin værdi af %1% og mindste værdi af %2%.</key>
<key alias="unexpectedRange">Værdien %0% forventes ikke at indeholde et spænd.</key>
<key alias="invalidRange">Værdien %0% forventes at have en værdi der er større end fra værdien.</key>
<key alias="notOneOfOptions">"Værdien '%0%' er ikke en af de tilgængelige valgmuligheder.</key>
</area>
<area alias="recycleBin">
<key alias="contentTrashed">Slettet indhold med Id: {0} Relateret til original "parent" med id: {1}</key>

View File

@@ -395,6 +395,7 @@
<key alias="invalidMediaType">The chosen media type is invalid.</key>
<key alias="multipleMediaNotAllowed">Multiple selected media is not allowed.</key>
<key alias="invalidStartNode">The selected media is from the wrong folder.</key>
<key alias="notOneOfOptions">"The value '%0%' is not one of the available options.</key>
</area>
<area alias="healthcheck">
<!-- The following keys get these tokens passed in:

View File

@@ -396,6 +396,7 @@
<key alias="invalidMediaType">The chosen media type is invalid.</key>
<key alias="multipleMediaNotAllowed">Multiple selected media is not allowed.</key>
<key alias="invalidStartNode">The selected media is from the wrong folder.</key>
<key alias="notOneOfOptions">"The value '%0%' is not one of the available options.</key>
</area>
<area alias="healthcheck">
<!-- The following keys get these tokens passed in:

View File

@@ -1,4 +1,4 @@
using Umbraco.Cms.Core.IO;
using Umbraco.Cms.Core.IO;
using Umbraco.Cms.Core.PropertyEditors.Validators;
using Umbraco.Cms.Core.Serialization;
using Umbraco.Cms.Core.Services;
@@ -6,6 +6,7 @@ using Umbraco.Cms.Core.Strings;
namespace Umbraco.Cms.Core.PropertyEditors;
[Obsolete("This is no longer used and has been migrated to an internal class within RadioButtonsPropertyEditor. Scheduled for removal in Umbraco 17.")]
public class RadioValueEditor : DataValueEditor
{
public RadioValueEditor(

View File

@@ -1,9 +1,10 @@
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations;
using Umbraco.Cms.Core.Models.Validation;
using Umbraco.Extensions;
namespace Umbraco.Cms.Core.PropertyEditors.Validators;
[Obsolete("This is no longer used and has been migrated to an internal class within RadioButtonsPropertyEditor. Scheduled for removal in Umbraco 17.")]
public class RadioValueValidator : IValueValidator
{
public IEnumerable<ValidationResult> Validate(object? value, string? valueType, object? dataTypeConfiguration,

View File

@@ -1,9 +1,14 @@
// Copyright (c) Umbraco.
// See LICENSE for more details.
using System.ComponentModel.DataAnnotations;
using Umbraco.Cms.Core.IO;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Models.Validation;
using Umbraco.Cms.Core.Serialization;
using Umbraco.Cms.Core.Services;
using Umbraco.Cms.Core.Strings;
using Umbraco.Extensions;
namespace Umbraco.Cms.Core.PropertyEditors;
@@ -20,7 +25,7 @@ public class RadioButtonsPropertyEditor : DataEditor
private readonly IConfigurationEditorJsonSerializer _configurationEditorJsonSerializer;
/// <summary>
/// The constructor will setup the property editor based on the attribute if one is found
/// Initializes a new instance of the <see cref="RadioButtonsPropertyEditor"/> class.
/// </summary>
public RadioButtonsPropertyEditor(IDataValueEditorFactory dataValueEditorFactory, IIOHelper ioHelper, IConfigurationEditorJsonSerializer configurationEditorJsonSerializer)
: base(dataValueEditorFactory)
@@ -30,13 +35,71 @@ public class RadioButtonsPropertyEditor : DataEditor
SupportsReadOnly = true;
}
/// <summary>
/// Return a custom pre-value editor
/// </summary>
/// <returns></returns>
/// <inheritdoc/>
protected override IConfigurationEditor CreateConfigurationEditor() =>
new ValueListConfigurationEditor(_ioHelper, _configurationEditorJsonSerializer);
protected override IDataValueEditor CreateValueEditor() =>
DataValueEditorFactory.Create<RadioValueEditor>(Attribute!);
/// <inheritdoc/>
protected override IDataValueEditor CreateValueEditor()
=> DataValueEditorFactory.Create<RadioButtonsPropertyValueEditor>(Attribute!);
/// <summary>
/// Defines the value editor for the radio buttons property editor.
/// </summary>
internal class RadioButtonsPropertyValueEditor : DataValueEditor
{
/// <summary>
/// Initializes a new instance of the <see cref="RadioButtonsPropertyValueEditor"/> class.
/// </summary>
public RadioButtonsPropertyValueEditor(
IShortStringHelper shortStringHelper,
IJsonSerializer jsonSerializer,
IIOHelper ioHelper,
DataEditorAttribute attribute,
ILocalizedTextService localizedTextService)
: base(shortStringHelper, jsonSerializer, ioHelper, attribute)
=> Validators.AddRange([new RadioButtonValueValidator(localizedTextService)]);
}
/// <summary>
/// Validates the prevalue configuration for the radio buttons property editor.
/// </summary>
internal class RadioButtonValueValidator : IValueValidator
{
private readonly ILocalizedTextService _localizedTextService;
/// <summary>
/// Initializes a new instance of the <see cref="RadioButtonValueValidator"/> class.
/// </summary>
/// <param name="localizedTextService"></param>
public RadioButtonValueValidator(ILocalizedTextService localizedTextService) => _localizedTextService = localizedTextService;
/// <inheritdoc/>
public IEnumerable<ValidationResult> Validate(object? value, string? valueType, object? dataTypeConfiguration, PropertyValidationContext validationContext)
{
if (value == null || value.ToString().IsNullOrWhiteSpace())
{
yield break;
}
if (dataTypeConfiguration is not ValueListConfiguration valueListConfiguration)
{
yield break;
}
if (value is not string valueAsString)
{
yield break;
}
if (valueListConfiguration.Items.Contains(valueAsString) is false)
{
yield return new ValidationResult(
_localizedTextService.Localize("validation", "notOneOfOptions", [valueAsString]),
["value"]);
}
}
}
}

View File

@@ -0,0 +1,60 @@
using System.Globalization;
using Moq;
using NUnit.Framework;
using Umbraco.Cms.Core.IO;
using Umbraco.Cms.Core.Models.Validation;
using Umbraco.Cms.Core.PropertyEditors;
using Umbraco.Cms.Core.Serialization;
using Umbraco.Cms.Core.Services;
using Umbraco.Cms.Core.Strings;
namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Core.PropertyEditors;
[TestFixture]
public class RadioButtonsPropertyValueEditorTests
{
[TestCase("Red", true)]
[TestCase("Yellow", false)]
public void Validates_Is_One_Of_Options(object value, bool expectedSuccess)
{
var editor = CreateValueEditor();
var result = editor.Validate(value, false, null, PropertyValidationContext.Empty());
if (expectedSuccess)
{
Assert.IsEmpty(result);
}
else
{
Assert.AreEqual(1, result.Count());
var validationResult = result.First();
Assert.AreEqual(validationResult.ErrorMessage, "validation_notOneOfOptions");
}
}
private static RadioButtonsPropertyEditor.RadioButtonsPropertyValueEditor CreateValueEditor()
{
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 culture, IDictionary<string, string> args) => $"{key}_{alias}");
var configuration = new ValueListConfiguration
{
Items = ["Red", "Green", "Blue"],
};
return new RadioButtonsPropertyEditor.RadioButtonsPropertyValueEditor(
Mock.Of<IShortStringHelper>(),
Mock.Of<IJsonSerializer>(),
Mock.Of<IIOHelper>(),
new DataEditorAttribute("alias"),
localizedTextServiceMock.Object)
{
ConfigurationObject = configuration
};
}
}