mirror of https://github.com/Squidex/squidex.git
66 changed files with 782 additions and 371 deletions
@ -0,0 +1,29 @@ |
|||
// ==========================================================================
|
|||
// IFieldPropertiesVisitor.cs
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex Group
|
|||
// All rights reserved.
|
|||
// ==========================================================================
|
|||
|
|||
namespace Squidex.Domain.Apps.Core.Schemas |
|||
{ |
|||
public interface IFieldPropertiesVisitor<T> |
|||
{ |
|||
T Visit(AssetsFieldProperties properties); |
|||
|
|||
T Visit(BooleanFieldProperties properties); |
|||
|
|||
T Visit(DateTimeFieldProperties properties); |
|||
|
|||
T Visit(GeolocationFieldProperties properties); |
|||
|
|||
T Visit(JsonFieldProperties properties); |
|||
|
|||
T Visit(NumberFieldProperties properties); |
|||
|
|||
T Visit(ReferencesFieldProperties properties); |
|||
|
|||
T Visit(StringFieldProperties properties); |
|||
} |
|||
} |
|||
@ -0,0 +1,193 @@ |
|||
// ==========================================================================
|
|||
// FieldPropertiesValidator.cs
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex Group
|
|||
// All rights reserved.
|
|||
// ==========================================================================
|
|||
|
|||
using System.Collections.Generic; |
|||
using Squidex.Domain.Apps.Core.Schemas; |
|||
using Squidex.Infrastructure; |
|||
|
|||
namespace Squidex.Domain.Apps.Write.Schemas.Guards |
|||
{ |
|||
public sealed class FieldPropertiesValidator : IFieldPropertiesVisitor<IEnumerable<ValidationError>> |
|||
{ |
|||
private static readonly FieldPropertiesValidator Instance = new FieldPropertiesValidator(); |
|||
|
|||
private FieldPropertiesValidator() |
|||
{ |
|||
} |
|||
|
|||
public static IEnumerable<ValidationError> Validate(FieldProperties properties) |
|||
{ |
|||
return properties.Visit(Instance); |
|||
} |
|||
|
|||
public IEnumerable<ValidationError> Visit(AssetsFieldProperties properties) |
|||
{ |
|||
if (properties.MaxItems.HasValue && properties.MinItems.HasValue && properties.MinItems.Value >= properties.MaxItems.Value) |
|||
{ |
|||
yield return new ValidationError("Max items must be greater than min items.", |
|||
nameof(properties.MinItems), |
|||
nameof(properties.MaxItems)); |
|||
} |
|||
} |
|||
|
|||
public IEnumerable<ValidationError> Visit(BooleanFieldProperties properties) |
|||
{ |
|||
if (!properties.Editor.IsEnumValue()) |
|||
{ |
|||
yield return new ValidationError("Editor is not a valid value.", |
|||
nameof(properties.Editor)); |
|||
} |
|||
} |
|||
|
|||
public IEnumerable<ValidationError> Visit(DateTimeFieldProperties properties) |
|||
{ |
|||
if (!properties.Editor.IsEnumValue()) |
|||
{ |
|||
yield return new ValidationError("Editor is not a valid value.", |
|||
nameof(properties.Editor)); |
|||
} |
|||
|
|||
if (properties.DefaultValue.HasValue && properties.MinValue.HasValue && properties.DefaultValue.Value < properties.MinValue.Value) |
|||
{ |
|||
yield return new ValidationError("Default value must be greater than min value.", |
|||
nameof(properties.DefaultValue)); |
|||
} |
|||
|
|||
if (properties.DefaultValue.HasValue && properties.MaxValue.HasValue && properties.DefaultValue.Value > properties.MaxValue.Value) |
|||
{ |
|||
yield return new ValidationError("Default value must be less than max value.", |
|||
nameof(properties.DefaultValue)); |
|||
} |
|||
|
|||
if (properties.MaxValue.HasValue && properties.MinValue.HasValue && properties.MinValue.Value >= properties.MaxValue.Value) |
|||
{ |
|||
yield return new ValidationError("Max value must be greater than min value.", |
|||
nameof(properties.MinValue), |
|||
nameof(properties.MaxValue)); |
|||
} |
|||
|
|||
if (properties.CalculatedDefaultValue.HasValue) |
|||
{ |
|||
if (!properties.CalculatedDefaultValue.Value.IsEnumValue()) |
|||
{ |
|||
yield return new ValidationError("Calculated default value is not valid.", |
|||
nameof(properties.CalculatedDefaultValue)); |
|||
} |
|||
|
|||
if (properties.DefaultValue.HasValue) |
|||
{ |
|||
yield return new ValidationError("Calculated default value and default value cannot be used together.", |
|||
nameof(properties.CalculatedDefaultValue), |
|||
nameof(properties.DefaultValue)); |
|||
} |
|||
} |
|||
} |
|||
|
|||
public IEnumerable<ValidationError> Visit(GeolocationFieldProperties properties) |
|||
{ |
|||
if (!properties.Editor.IsEnumValue()) |
|||
{ |
|||
yield return new ValidationError("Editor is not a valid value.", |
|||
nameof(properties.Editor)); |
|||
} |
|||
} |
|||
|
|||
public IEnumerable<ValidationError> Visit(JsonFieldProperties properties) |
|||
{ |
|||
yield break; |
|||
} |
|||
|
|||
public IEnumerable<ValidationError> Visit(NumberFieldProperties properties) |
|||
{ |
|||
if (!properties.Editor.IsEnumValue()) |
|||
{ |
|||
yield return new ValidationError("Editor is not a valid value.", |
|||
nameof(properties.Editor)); |
|||
} |
|||
|
|||
if ((properties.Editor == NumberFieldEditor.Radio || properties.Editor == NumberFieldEditor.Dropdown) && (properties.AllowedValues == null || properties.AllowedValues.Count == 0)) |
|||
{ |
|||
yield return new ValidationError("Radio buttons or dropdown list need allowed values.", |
|||
nameof(properties.AllowedValues)); |
|||
} |
|||
|
|||
if (properties.DefaultValue.HasValue && properties.MinValue.HasValue && properties.DefaultValue.Value < properties.MinValue.Value) |
|||
{ |
|||
yield return new ValidationError("Default value must be greater than min value.", |
|||
nameof(properties.DefaultValue)); |
|||
} |
|||
|
|||
if (properties.DefaultValue.HasValue && properties.MaxValue.HasValue && properties.DefaultValue.Value > properties.MaxValue.Value) |
|||
{ |
|||
yield return new ValidationError("Default value must be less than max value.", |
|||
nameof(properties.DefaultValue)); |
|||
} |
|||
|
|||
if (properties.MaxValue.HasValue && properties.MinValue.HasValue && properties.MinValue.Value >= properties.MaxValue.Value) |
|||
{ |
|||
yield return new ValidationError("Max value must be greater than min value.", |
|||
nameof(properties.MinValue), |
|||
nameof(properties.MaxValue)); |
|||
} |
|||
|
|||
if (properties.AllowedValues != null && properties.AllowedValues.Count > 0 && (properties.MinValue.HasValue || properties.MaxValue.HasValue)) |
|||
{ |
|||
yield return new ValidationError("Either allowed values or min and max value can be defined.", |
|||
nameof(properties.AllowedValues), |
|||
nameof(properties.MinValue), |
|||
nameof(properties.MaxValue)); |
|||
} |
|||
} |
|||
|
|||
public IEnumerable<ValidationError> Visit(ReferencesFieldProperties properties) |
|||
{ |
|||
if (properties.MaxItems.HasValue && properties.MinItems.HasValue && properties.MinItems.Value >= properties.MaxItems.Value) |
|||
{ |
|||
yield return new ValidationError("Max items must be greater than min items.", |
|||
nameof(properties.MinItems), |
|||
nameof(properties.MaxItems)); |
|||
} |
|||
} |
|||
|
|||
public IEnumerable<ValidationError> Visit(StringFieldProperties properties) |
|||
{ |
|||
if (!properties.Editor.IsEnumValue()) |
|||
{ |
|||
yield return new ValidationError("Editor is not a valid value.", |
|||
nameof(properties.Editor)); |
|||
} |
|||
|
|||
if ((properties.Editor == StringFieldEditor.Radio || properties.Editor == StringFieldEditor.Dropdown) && (properties.AllowedValues == null || properties.AllowedValues.Count == 0)) |
|||
{ |
|||
yield return new ValidationError("Radio buttons or dropdown list need allowed values.", |
|||
nameof(properties.AllowedValues)); |
|||
} |
|||
|
|||
if (properties.Pattern != null && !properties.Pattern.IsValidRegex()) |
|||
{ |
|||
yield return new ValidationError("Pattern is not a valid expression.", |
|||
nameof(properties.Pattern)); |
|||
} |
|||
|
|||
if (properties.MaxLength.HasValue && properties.MinLength.HasValue && properties.MinLength.Value >= properties.MaxLength.Value) |
|||
{ |
|||
yield return new ValidationError("Max length must be greater than min length.", |
|||
nameof(properties.MinLength), |
|||
nameof(properties.MaxLength)); |
|||
} |
|||
|
|||
if (properties.AllowedValues != null && properties.AllowedValues.Count > 0 && (properties.MinLength.HasValue || properties.MaxLength.HasValue)) |
|||
{ |
|||
yield return new ValidationError("Either allowed values or min and max length can be defined.", |
|||
nameof(properties.AllowedValues), |
|||
nameof(properties.MinLength), |
|||
nameof(properties.MaxLength)); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,169 @@ |
|||
// ==========================================================================
|
|||
// SchemaFieldGuardTests.cs
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex Group
|
|||
// All rights reserved.
|
|||
// ==========================================================================
|
|||
|
|||
using Squidex.Domain.Apps.Core; |
|||
using Squidex.Domain.Apps.Core.Schemas; |
|||
using Squidex.Infrastructure; |
|||
using Xunit; |
|||
|
|||
namespace Squidex.Domain.Apps.Write.Schemas.Guards |
|||
{ |
|||
public class SchemaFieldGuardTests |
|||
{ |
|||
private Schema schema = |
|||
Schema.Create("my-schema", new SchemaProperties()) |
|||
.AddField(new StringField(1, "field1", Partitioning.Invariant)) |
|||
.AddField(new StringField(2, "field2", Partitioning.Invariant)); |
|||
|
|||
[Fact] |
|||
public void Should_throw_exception_if_field_to_hide_already_hidden() |
|||
{ |
|||
schema = schema.HideField(1); |
|||
|
|||
Assert.Throws<DomainException>(() => SchemaFieldGuard.GuardCanHide(schema, 1)); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Should_throw_exception_if_field_to_hide_not_found() |
|||
{ |
|||
Assert.Throws<DomainObjectNotFoundException>(() => SchemaFieldGuard.GuardCanHide(schema, 3)); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Should_not_throw_exception_if_field_to_hide_shown() |
|||
{ |
|||
SchemaFieldGuard.GuardCanHide(schema, 1); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Should_throw_exception_if_field_to_disable_not_found() |
|||
{ |
|||
Assert.Throws<DomainObjectNotFoundException>(() => SchemaFieldGuard.GuardCanDisable(schema, 3)); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Should_throw_exception_if_field_to_disable_already_disabled() |
|||
{ |
|||
schema = schema.DisableField(1); |
|||
|
|||
Assert.Throws<DomainException>(() => SchemaFieldGuard.GuardCanDisable(schema, 1)); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Should_not_throw_exception_if_field_to_disable_shown() |
|||
{ |
|||
SchemaFieldGuard.GuardCanDisable(schema, 1); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Should_throw_exception_if_field_to_show_already_shown() |
|||
{ |
|||
Assert.Throws<DomainException>(() => SchemaFieldGuard.GuardCanShow(schema, 1)); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Should_throw_exception_if_field_to_show_not_found() |
|||
{ |
|||
Assert.Throws<DomainObjectNotFoundException>(() => SchemaFieldGuard.GuardCanShow(schema, 3)); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Should_not_throw_exception_if_field_to_show_hidden() |
|||
{ |
|||
schema = schema.HideField(1); |
|||
|
|||
SchemaFieldGuard.GuardCanShow(schema, 1); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Should_throw_exception_if_field_to_enable_already_enabled() |
|||
{ |
|||
Assert.Throws<DomainException>(() => SchemaFieldGuard.GuardCanEnable(schema, 1)); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Should_throw_exception_if_field_to_enable_not_found() |
|||
{ |
|||
Assert.Throws<DomainObjectNotFoundException>(() => SchemaFieldGuard.GuardCanEnable(schema, 3)); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Should_not_throw_exception_if_field_to_enable_disabled() |
|||
{ |
|||
schema = schema.DisableField(1); |
|||
|
|||
SchemaFieldGuard.GuardCanEnable(schema, 1); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Should_throw_exception_if_field_to_lock_already_locked() |
|||
{ |
|||
schema = schema.LockField(1); |
|||
|
|||
Assert.Throws<DomainException>(() => SchemaFieldGuard.GuardCanLock(schema, 1)); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Should_throw_exception_if_field_to_lock_not_found() |
|||
{ |
|||
Assert.Throws<DomainObjectNotFoundException>(() => SchemaFieldGuard.GuardCanLock(schema, 3)); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Should_not_throw_exception_if_field_to_lock_not_locked() |
|||
{ |
|||
SchemaFieldGuard.GuardCanLock(schema, 1); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Should_throw_exception_if_field_to_delete_not_found() |
|||
{ |
|||
Assert.Throws<DomainObjectNotFoundException>(() => SchemaFieldGuard.GuardCanDelete(schema, 3)); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Should_throw_exception_if_field_to_delete_is_locked() |
|||
{ |
|||
schema = schema.LockField(1); |
|||
|
|||
Assert.Throws<DomainException>(() => SchemaFieldGuard.GuardCanDelete(schema, 1)); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Should_throw_exception_if_field_to_update_not_locked() |
|||
{ |
|||
SchemaFieldGuard.GuardCanUpdate(schema, 1); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Should_throw_exception_if_field_to_update_is_locked() |
|||
{ |
|||
schema = schema.LockField(1); |
|||
|
|||
Assert.Throws<DomainException>(() => SchemaFieldGuard.GuardCanUpdate(schema, 1)); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Should_throw_exception_if_field_to_delete_not_locked() |
|||
{ |
|||
SchemaFieldGuard.GuardCanDelete(schema, 1); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Should_throw_exception_if_field_to_add_already_exists() |
|||
{ |
|||
Assert.Throws<ValidationException>(() => SchemaFieldGuard.GuardCanAdd(schema, "field1")); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Should_not_throw_exception_if_field_to_add_not_exists() |
|||
{ |
|||
SchemaFieldGuard.GuardCanAdd(schema, "field3"); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,65 @@ |
|||
// ==========================================================================
|
|||
// SchemaGuardTests.cs
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex Group
|
|||
// All rights reserved.
|
|||
// ==========================================================================
|
|||
|
|||
using System.Collections.Generic; |
|||
using Squidex.Domain.Apps.Core; |
|||
using Squidex.Domain.Apps.Core.Schemas; |
|||
using Squidex.Infrastructure; |
|||
using Xunit; |
|||
|
|||
namespace Squidex.Domain.Apps.Write.Schemas.Guards |
|||
{ |
|||
public class SchemaGuardTests |
|||
{ |
|||
private Schema schema = |
|||
Schema.Create("my-schema", new SchemaProperties()) |
|||
.AddField(new StringField(1, "field1", Partitioning.Invariant)) |
|||
.AddField(new StringField(2, "field2", Partitioning.Invariant)); |
|||
|
|||
[Fact] |
|||
public void Should_throw_exception_if_schema_to_publish_already_published() |
|||
{ |
|||
schema = schema.Publish(); |
|||
|
|||
Assert.Throws<DomainException>(() => SchemaGuard.GuardCanPublish(schema)); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Should_not_throw_exception_if_schema_to_publish_not_published() |
|||
{ |
|||
SchemaGuard.GuardCanPublish(schema); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Should_throw_exception_if_schema_to_unpublish_already_unpublished() |
|||
{ |
|||
Assert.Throws<DomainException>(() => SchemaGuard.GuardCanUnpublish(schema)); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Should_not_throw_exception_if_schema_to_unpublish_published() |
|||
{ |
|||
schema = schema.Publish(); |
|||
|
|||
SchemaGuard.GuardCanUnpublish(schema); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Should_throw_excepotion_if_schema_fields_to_reorder_not_valid() |
|||
{ |
|||
Assert.Throws<ValidationException>(() => SchemaGuard.GuardCanReorder(schema, new List<long> { 1 })); |
|||
Assert.Throws<ValidationException>(() => SchemaGuard.GuardCanReorder(schema, new List<long> { 1, 3 })); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Should_not_throw_excepotion_if_schema_fields_to_reorder_are_valid() |
|||
{ |
|||
SchemaGuard.GuardCanReorder(schema, new List<long> { 1, 2 }); |
|||
} |
|||
} |
|||
} |
|||
Loading…
Reference in new issue