Files
Umbraco-CMS/tests/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Services/PropertyValidationServiceTests.cs

190 lines
11 KiB
C#
Raw Normal View History

// Copyright (c) Umbraco.
// See LICENSE for more details.
using System.Threading;
using Moq;
using NUnit.Framework;
using Umbraco.Cms.Core;
2021-08-24 11:02:51 +02:00
using Umbraco.Cms.Core.Cache;
using Umbraco.Cms.Core.Hosting;
using Umbraco.Cms.Core.IO;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.PropertyEditors;
using Umbraco.Cms.Core.PropertyEditors.Validators;
using Umbraco.Cms.Core.Serialization;
using Umbraco.Cms.Core.Services;
using Umbraco.Cms.Core.Services.Implement;
using Umbraco.Cms.Core.Strings;
using Umbraco.Cms.Infrastructure.Serialization;
namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Infrastructure.Services
{
[TestFixture]
2020-10-05 11:32:03 +02:00
public class PropertyValidationServiceTests
{
2020-10-05 11:32:03 +02:00
private IShortStringHelper ShortStringHelper => new DefaultShortStringHelper(new DefaultShortStringHelperConfig());
private void MockObjects(out PropertyValidationService validationService, out IDataType dt)
{
var textService = new Mock<ILocalizedTextService>();
Merge remote-tracking branch 'origin/v8/dev' into v9/feature/merge-v8-05072021 # Conflicts: # build/NuSpecs/UmbracoCms.Web.nuspec # src/SolutionInfo.cs # src/Umbraco.Core/Compose/RelateOnTrashComponent.cs # src/Umbraco.Core/Composing/Current.cs # src/Umbraco.Core/Constants-AppSettings.cs # src/Umbraco.Core/Constants-SqlTemplates.cs # src/Umbraco.Core/Dashboards/ContentDashboardSettings.cs # src/Umbraco.Core/Dashboards/IContentDashboardSettings.cs # src/Umbraco.Core/Extensions/PublishedPropertyExtension.cs # src/Umbraco.Core/HealthChecks/Checks/Services/SmtpCheck.cs # src/Umbraco.Core/Models/IReadOnlyContentBase.cs # src/Umbraco.Core/Models/Mapping/MemberTabsAndPropertiesMapper.cs # src/Umbraco.Core/Models/Mapping/UserMapDefinition.cs # src/Umbraco.Core/Models/ReadOnlyContentBaseAdapter.cs # src/Umbraco.Core/Persistence/NPocoDatabaseExtensions-Bulk.cs # src/Umbraco.Core/PropertyEditors/IPropertyCacheCompression.cs # src/Umbraco.Core/PropertyEditors/IPropertyCacheCompressionOptions.cs # src/Umbraco.Core/PropertyEditors/MediaPicker3Configuration.cs # src/Umbraco.Core/PropertyEditors/NoopPropertyCacheCompressionOptions.cs # src/Umbraco.Core/PropertyEditors/PropertyCacheCompression.cs # src/Umbraco.Core/Routing/UrlProviderExtensions.cs # src/Umbraco.Core/Runtime/CoreRuntime.cs # src/Umbraco.Core/Services/ILocalizedTextService.cs # src/Umbraco.Core/Services/LocalizedTextServiceExtensions.cs # src/Umbraco.Examine.Lucene/BackOfficeExamineSearcher.cs # src/Umbraco.Examine/UmbracoContentIndex.cs # src/Umbraco.Infrastructure/Examine/GenericIndexDiagnostics.cs # src/Umbraco.Infrastructure/IPublishedContentQuery.cs # src/Umbraco.Infrastructure/Migrations/Upgrade/UmbracoPlan.cs # src/Umbraco.Infrastructure/Models/MediaWithCrops.cs # src/Umbraco.Infrastructure/Persistence/NPocoDatabaseExtensions.cs # src/Umbraco.Infrastructure/Persistence/UmbracoDatabase.cs # src/Umbraco.Infrastructure/PropertyEditors/ImageCropperConfiguration.cs # src/Umbraco.Infrastructure/PropertyEditors/MediaPicker3PropertyEditor.cs # src/Umbraco.Infrastructure/PropertyEditors/NestedContentPropertyEditor.cs # src/Umbraco.Infrastructure/PropertyEditors/UploadFileTypeValidator.cs # src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/ImageCropperValue.cs # src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/MediaPickerWithCropsValueConverter.cs # src/Umbraco.Infrastructure/PublishedContentQuery.cs # src/Umbraco.Infrastructure/Search/UmbracoTreeSearcherFields.cs # src/Umbraco.Infrastructure/Services/Implement/LocalizedTextService.cs # src/Umbraco.Persistence.SqlCe/SqlCeSyntaxProvider.cs # src/Umbraco.PublishedCache.NuCache/DataSource/BTree.DictionaryOfPropertyDataSerializer.cs # src/Umbraco.PublishedCache.NuCache/DataSource/BTree.cs # src/Umbraco.PublishedCache.NuCache/DataSource/ContentData.cs # src/Umbraco.PublishedCache.NuCache/DataSource/ContentSourceDto.cs # src/Umbraco.PublishedCache.NuCache/DataSource/PropertyData.cs # src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/ContentTypeServiceVariantsTests.cs # src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/ImageCropperTest.cs # src/Umbraco.Tests/App.config # src/Umbraco.Tests/Models/Mapping/ContentWebModelMappingTests.cs # src/Umbraco.Tests/PublishedContent/NuCacheChildrenTests.cs # src/Umbraco.Tests/PublishedContent/NuCacheTests.cs # src/Umbraco.Tests/Scoping/ScopedNuCacheTests.cs # src/Umbraco.Web.BackOffice/Controllers/CodeFileController.cs # src/Umbraco.Web.BackOffice/Controllers/ContentController.cs # src/Umbraco.Web.BackOffice/Controllers/ContentTypeControllerBase.cs # src/Umbraco.Web.BackOffice/Controllers/DashboardController.cs # src/Umbraco.Web.BackOffice/Controllers/DataTypeController.cs # src/Umbraco.Web.BackOffice/Controllers/MediaController.cs # src/Umbraco.Web.BackOffice/Controllers/PackageInstallController.cs # src/Umbraco.Web.BackOffice/Controllers/TemplateQueryController.cs # src/Umbraco.Web.BackOffice/Mapping/ContentMapDefinition.cs # src/Umbraco.Web.BackOffice/Trees/ContentTreeControllerBase.cs # src/Umbraco.Web.BackOffice/Trees/DataTypeTreeController.cs # src/Umbraco.Web.BackOffice/Trees/MediaTypeTreeController.cs # src/Umbraco.Web.Common/Extensions/FriendlyImageCropperTemplateExtensions.cs # src/Umbraco.Web.Common/Extensions/ImageCropperTemplateCoreExtensions.cs # src/Umbraco.Web.Common/Macros/MacroRenderer.cs # src/Umbraco.Web.UI.NetCore/umbraco/config/lang/da.xml # src/Umbraco.Web.UI/Umbraco/config/lang/it.xml # src/Umbraco.Web.UI/web.Template.Debug.config # src/Umbraco.Web.UI/web.Template.config # src/Umbraco.Web/Compose/NotificationsComponent.cs # src/Umbraco.Web/Composing/ModuleInjector.cs # src/Umbraco.Web/Editors/AuthenticationController.cs # src/Umbraco.Web/Editors/BackOfficeController.cs # src/Umbraco.Web/Editors/ContentTypeController.cs # src/Umbraco.Web/Editors/CurrentUserController.cs # src/Umbraco.Web/Editors/DictionaryController.cs # src/Umbraco.Web/Editors/MediaTypeController.cs # src/Umbraco.Web/Editors/MemberController.cs # src/Umbraco.Web/Editors/MemberGroupController.cs # src/Umbraco.Web/Editors/MemberTypeController.cs # src/Umbraco.Web/Editors/NuCacheStatusController.cs # src/Umbraco.Web/Editors/UserGroupsController.cs # src/Umbraco.Web/Editors/UsersController.cs # src/Umbraco.Web/HealthCheck/Checks/Config/AbstractConfigCheck.cs # src/Umbraco.Web/HealthCheck/Checks/Config/CompilationDebugCheck.cs # src/Umbraco.Web/HealthCheck/Checks/Config/ConfigurationService.cs # src/Umbraco.Web/HealthCheck/Checks/Config/CustomErrorsCheck.cs # src/Umbraco.Web/HealthCheck/Checks/Config/MacroErrorsCheck.cs # src/Umbraco.Web/HealthCheck/Checks/Config/NotificationEmailCheck.cs # src/Umbraco.Web/HealthCheck/Checks/Config/TraceCheck.cs # src/Umbraco.Web/HealthCheck/Checks/Config/TrySkipIisCustomErrorsCheck.cs # src/Umbraco.Web/HealthCheck/Checks/Permissions/FolderAndFilePermissionsCheck.cs # src/Umbraco.Web/HealthCheck/Checks/Security/BaseHttpHeaderCheck.cs # src/Umbraco.Web/HealthCheck/Checks/Security/ExcessiveHeadersCheck.cs # src/Umbraco.Web/HealthCheck/Checks/Security/HttpsCheck.cs # src/Umbraco.Web/HealthCheck/NotificationMethods/EmailNotificationMethod.cs # src/Umbraco.Web/Models/Trees/MenuItemList.cs # src/Umbraco.Web/PublishedCache/NuCache/DataSource/ContentCacheDataModel.cs # src/Umbraco.Web/PublishedCache/NuCache/DataSource/DatabaseDataSource.cs # src/Umbraco.Web/PublishedCache/NuCache/DataSource/SerializerBase.cs # src/Umbraco.Web/PublishedCache/NuCache/NuCacheComposer.cs # src/Umbraco.Web/Runtime/WebRuntime.cs # src/Umbraco.Web/Search/ExamineComponent.cs # src/Umbraco.Web/Trees/ApplicationTreeController.cs # src/Umbraco.Web/Trees/MemberTreeController.cs # src/Umbraco.Web/UrlHelperRenderExtensions.cs
2021-07-05 20:58:04 +02:00
textService.Setup(x => x.Localize(It.IsAny<string>(),It.IsAny<string>(), Thread.CurrentThread.CurrentCulture, null)).Returns("Localized text");
var dataTypeService = new Mock<IDataTypeService>();
IDataType dataType = Mock.Of<IDataType>(
x => x.Configuration == (object)string.Empty // irrelevant but needs a value
&& x.DatabaseType == ValueStorageType.Nvarchar
&& x.EditorAlias == Constants.PropertyEditors.Aliases.TextBox);
dataTypeService.Setup(x => x.GetDataType(It.IsAny<int>())).Returns(() => dataType);
dt = dataType;
// new data editor that returns a TextOnlyValueEditor which will do the validation for the properties
IDataEditor dataEditor = Mock.Of<IDataEditor>(
x => x.Type == EditorType.PropertyValue
&& x.Alias == Constants.PropertyEditors.Aliases.TextBox);
Mock.Get(dataEditor).Setup(x => x.GetValueEditor(It.IsAny<object>()))
.Returns(new CustomTextOnlyValueEditor(new DataEditorAttribute(Constants.PropertyEditors.Aliases.TextBox, "Test Textbox", "textbox"), textService.Object, Mock.Of<IShortStringHelper>(), new JsonNetSerializer(), Mock.Of<IIOHelper>()));
var propEditors = new PropertyEditorCollection(new DataEditorCollection(() => new[] { dataEditor }));
2021-08-24 11:02:51 +02:00
validationService = new PropertyValidationService(propEditors, dataTypeService.Object, Mock.Of<ILocalizedTextService>(), new ValueEditorCache());
}
[Test]
public void Validate_Invariant_Properties_On_Variant_Default_Culture()
{
MockObjects(out PropertyValidationService validationService, out IDataType dataType);
var p1 = new Property(new PropertyType(ShortStringHelper, dataType, "test1") { Mandatory = true, Variations = ContentVariation.Culture });
p1.SetValue("Hello", "en-US");
var p2 = new Property(new PropertyType(ShortStringHelper, dataType, "test2") { Mandatory = true, Variations = ContentVariation.Nothing });
p2.SetValue("Hello", null);
var p3 = new Property(new PropertyType(ShortStringHelper, dataType, "test3") { Mandatory = true, Variations = ContentVariation.Culture });
p3.SetValue(null, "en-US"); // invalid
var p4 = new Property(new PropertyType(ShortStringHelper, dataType, "test4") { Mandatory = true, Variations = ContentVariation.Nothing });
p4.SetValue(null, null); // invalid
IContent content = Mock.Of<IContent>(
x => x.Published == true // set to published, the default culture will validate invariant anyways
&& x.Properties == new PropertyCollection(new[] { p1, p2, p3, p4 }));
bool result = validationService.IsPropertyDataValid(content, out IProperty[] invalid, CultureImpact.Explicit("en-US", true));
Assert.IsFalse(result);
Assert.AreEqual(2, invalid.Length);
}
[Test]
public void Validate_Invariant_Properties_On_Variant_Non_Default_Culture()
{
MockObjects(out PropertyValidationService validationService, out IDataType dataType);
var p1 = new Property(new PropertyType(ShortStringHelper, dataType, "test1") { Mandatory = true, Variations = ContentVariation.Culture });
p1.SetValue("Hello", "en-US");
var p2 = new Property(new PropertyType(ShortStringHelper, dataType, "test2") { Mandatory = true, Variations = ContentVariation.Nothing });
p2.SetValue("Hello", null);
var p3 = new Property(new PropertyType(ShortStringHelper, dataType, "test3") { Mandatory = true, Variations = ContentVariation.Culture });
p3.SetValue(null, "en-US"); // invalid
var p4 = new Property(new PropertyType(ShortStringHelper, dataType, "test4") { Mandatory = true, Variations = ContentVariation.Nothing });
p4.SetValue(null, null); // invalid
IContent content = Mock.Of<IContent>(
x => x.Published == false // set to not published, the non default culture will need to validate invariant too
&& x.Properties == new PropertyCollection(new[] { p1, p2, p3, p4 }));
bool result = validationService.IsPropertyDataValid(content, out IProperty[] invalid, CultureImpact.Explicit("en-US", false));
Assert.IsFalse(result);
Assert.AreEqual(2, invalid.Length);
}
[Test]
public void Validate_Variant_Properties_On_Variant()
{
MockObjects(out PropertyValidationService validationService, out IDataType dataType);
var p1 = new Property(new PropertyType(ShortStringHelper, dataType, "test1") { Mandatory = true, Variations = ContentVariation.Culture });
p1.SetValue(null, "en-US"); // invalid
var p2 = new Property(new PropertyType(ShortStringHelper, dataType, "test2") { Mandatory = true, Variations = ContentVariation.Nothing });
p2.SetValue(null, null); // invalid
var p3 = new Property(new PropertyType(ShortStringHelper, dataType, "test3") { Mandatory = true, Variations = ContentVariation.Culture });
p3.SetValue(null, "en-US"); // ignored because the impact isn't the default lang + the content is published
var p4 = new Property(new PropertyType(ShortStringHelper, dataType, "test4") { Mandatory = true, Variations = ContentVariation.Nothing });
p4.SetValue(null, null); // ignored because the impact isn't the default lang + the content is published
IContent content = Mock.Of<IContent>(
x => x.Published == true // set to published
&& x.Properties == new PropertyCollection(new[] { p1, p2, p3, p4 }));
bool result = validationService.IsPropertyDataValid(content, out IProperty[] invalid, CultureImpact.Explicit("en-US", false));
Assert.IsFalse(result);
Assert.AreEqual(2, invalid.Length);
}
[Test]
public void Validate_Invariant_Properties_On_Invariant()
{
MockObjects(out PropertyValidationService validationService, out IDataType dataType);
var p1 = new Property(new PropertyType(ShortStringHelper, dataType, "test1") { Mandatory = true, Variations = ContentVariation.Culture });
p1.SetValue(null, "en-US"); // ignored since this is variant
var p2 = new Property(new PropertyType(ShortStringHelper, dataType, "test2") { Mandatory = true, Variations = ContentVariation.Nothing });
p2.SetValue(null, null); // invalid
var p3 = new Property(new PropertyType(ShortStringHelper, dataType, "test3") { Mandatory = true, Variations = ContentVariation.Culture });
p3.SetValue("Hello", "en-US"); // ignored since this is variant
var p4 = new Property(new PropertyType(ShortStringHelper, dataType, "test4") { Mandatory = true, Variations = ContentVariation.Nothing });
p4.SetValue(null, null); // invalid
2019-11-05 13:45:42 +01:00
IContent content = Mock.Of<IContent>(
x => x.Properties == new PropertyCollection(new[] { p1, p2, p3, p4 }));
bool result = validationService.IsPropertyDataValid(content, out IProperty[] invalid, CultureImpact.Invariant);
Assert.IsFalse(result);
Assert.AreEqual(2, invalid.Length);
}
[Test]
public void Validate_Properties_On_All()
{
MockObjects(out PropertyValidationService validationService, out IDataType dataType);
var p1 = new Property(new PropertyType(ShortStringHelper, dataType, "test1") { Mandatory = true, Variations = ContentVariation.Culture });
p1.SetValue(null, "en-US"); // invalid
var p2 = new Property(new PropertyType(ShortStringHelper, dataType, "test2") { Mandatory = true, Variations = ContentVariation.Nothing });
p2.SetValue(null, null); // invalid
var p3 = new Property(new PropertyType(ShortStringHelper, dataType, "test3") { Mandatory = true, Variations = ContentVariation.Culture });
p3.SetValue(null, "en-US"); // invalid
var p4 = new Property(new PropertyType(ShortStringHelper, dataType, "test4") { Mandatory = true, Variations = ContentVariation.Nothing });
p4.SetValue(null, null); // invalid
IContent content = Mock.Of<IContent>(
x => x.Properties == new PropertyCollection(new[] { p1, p2, p3, p4 }));
bool result = validationService.IsPropertyDataValid(content, out IProperty[] invalid, CultureImpact.All);
Assert.IsFalse(result);
Assert.AreEqual(4, invalid.Length);
}
// used so we can inject a mock - we should fix the base class DataValueEditor to be able to have the ILocalizedTextField passed
// in to create the Requried and Regex validators so we aren't using singletons
private class CustomTextOnlyValueEditor : TextOnlyValueEditor
{
private readonly ILocalizedTextService _textService;
public CustomTextOnlyValueEditor(
DataEditorAttribute attribute,
ILocalizedTextService textService,
IShortStringHelper shortStringHelper,
IJsonSerializer jsonSerializer,
IIOHelper ioHelper)
: base(attribute, textService, shortStringHelper, jsonSerializer, ioHelper) => _textService = textService;
public override IValueRequiredValidator RequiredValidator => new RequiredValidator(_textService);
public override IValueFormatValidator FormatValidator => new RegexValidator(_textService, null);
}
}
}