Browse Source

Validator fix for assets and references.

pull/596/head
Sebastian 5 years ago
parent
commit
a9693e6a01
  1. 2
      backend/extensions/Squidex.Extensions/Validation/CompositeUniqueValidatorFactory.cs
  2. 7
      backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/ContentValidator.cs
  3. 6
      backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/DefaultFieldValueValidatorsFactory.cs
  4. 4
      backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/DefaultValidatorsFactory.cs
  5. 8
      backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/IValidatorsFactory.cs
  6. 29
      backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/JsonValueConverter.cs
  7. 2
      backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/Validators/AggregateValidator.cs
  8. 13
      backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/Validators/CollectionItemValidator.cs
  9. 23
      backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/Validators/FieldValidator.cs
  10. 2
      backend/src/Squidex.Domain.Apps.Entities/Contents/Validation/DependencyValidatorsFactory.cs
  11. 112
      backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/AssetsFieldTests.cs
  12. 4
      backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/ContentValidationTests.cs
  13. 131
      backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/ReferencesFieldTests.cs
  14. 3
      backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/ValidationTestExtensions.cs
  15. 59
      backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/Validators/AssetsValidatorTests.cs
  16. 65
      backend/tests/Squidex.Domain.Apps.Core.Tests/TestHelpers/TestAssets.cs

2
backend/extensions/Squidex.Extensions/Validation/CompositeUniqueValidatorFactory.cs

@ -25,7 +25,7 @@ namespace Squidex.Extensions.Validation
this.contentRepository = contentRepository; this.contentRepository = contentRepository;
} }
public IEnumerable<IValidator> CreateContentValidators(ValidatorContext context, FieldValidatorFactory createFieldValidator) public IEnumerable<IValidator> CreateContentValidators(ValidatorContext context, ValidatorFactory createFieldValidator)
{ {
foreach (var validatorTag in ValidatorTags(context.Schema.Properties.Tags)) foreach (var validatorTag in ValidatorTags(context.Schema.Properties.Tags))
{ {

7
backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/ContentValidator.cs

@ -118,7 +118,12 @@ namespace Squidex.Domain.Apps.Core.ValidateContent
private IValidator CreateFieldValidator(IField field) private IValidator CreateFieldValidator(IField field)
{ {
return new FieldValidator(CreateValueValidators(field), field); return new FieldValidator(CreateValueValidator(field), field);
}
private IValidator CreateValueValidator(IField field)
{
return new AggregateValidator(CreateValueValidators(field), log);
} }
private IEnumerable<IValidator> CreateContentValidators() private IEnumerable<IValidator> CreateContentValidators()

6
backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/DefaultFieldValueValidatorsFactory.cs

@ -18,15 +18,15 @@ namespace Squidex.Domain.Apps.Core.ValidateContent
internal sealed class DefaultFieldValueValidatorsFactory : IFieldVisitor<IEnumerable<IValidator>> internal sealed class DefaultFieldValueValidatorsFactory : IFieldVisitor<IEnumerable<IValidator>>
{ {
private readonly ValidatorContext context; private readonly ValidatorContext context;
private readonly FieldValidatorFactory createFieldValidator; private readonly ValidatorFactory createFieldValidator;
private DefaultFieldValueValidatorsFactory(ValidatorContext context, FieldValidatorFactory createFieldValidator) private DefaultFieldValueValidatorsFactory(ValidatorContext context, ValidatorFactory createFieldValidator)
{ {
this.context = context; this.context = context;
this.createFieldValidator = createFieldValidator; this.createFieldValidator = createFieldValidator;
} }
public static IEnumerable<IValidator> CreateValidators(ValidatorContext context, IField field, FieldValidatorFactory createFieldValidator) public static IEnumerable<IValidator> CreateValidators(ValidatorContext context, IField field, ValidatorFactory createFieldValidator)
{ {
Guard.NotNull(context, nameof(context)); Guard.NotNull(context, nameof(context));
Guard.NotNull(field, nameof(field)); Guard.NotNull(field, nameof(field));

4
backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/DefaultValidatorsFactory.cs

@ -13,7 +13,7 @@ namespace Squidex.Domain.Apps.Core.ValidateContent
{ {
public sealed class DefaultValidatorsFactory : IValidatorsFactory public sealed class DefaultValidatorsFactory : IValidatorsFactory
{ {
public IEnumerable<IValidator> CreateFieldValidators(ValidatorContext context, IField field, FieldValidatorFactory createFieldValidator) public IEnumerable<IValidator> CreateFieldValidators(ValidatorContext context, IField field, ValidatorFactory createFieldValidator)
{ {
if (field is IField<UIFieldProperties>) if (field is IField<UIFieldProperties>)
{ {
@ -21,7 +21,7 @@ namespace Squidex.Domain.Apps.Core.ValidateContent
} }
} }
public IEnumerable<IValidator> CreateValueValidators(ValidatorContext context, IField field, FieldValidatorFactory createFieldValidator) public IEnumerable<IValidator> CreateValueValidators(ValidatorContext context, IField field, ValidatorFactory createFieldValidator)
{ {
return DefaultFieldValueValidatorsFactory.CreateValidators(context, field, createFieldValidator); return DefaultFieldValueValidatorsFactory.CreateValidators(context, field, createFieldValidator);
} }

8
backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/IValidatorsFactory.cs

@ -10,21 +10,21 @@ using Squidex.Domain.Apps.Core.Schemas;
namespace Squidex.Domain.Apps.Core.ValidateContent namespace Squidex.Domain.Apps.Core.ValidateContent
{ {
public delegate IValidator FieldValidatorFactory(IField field); public delegate IValidator ValidatorFactory(IField field);
public interface IValidatorsFactory public interface IValidatorsFactory
{ {
IEnumerable<IValidator> CreateFieldValidators(ValidatorContext context, IField field, FieldValidatorFactory createFieldValidator) IEnumerable<IValidator> CreateFieldValidators(ValidatorContext context, IField field, ValidatorFactory createFieldValidator)
{ {
yield break; yield break;
} }
IEnumerable<IValidator> CreateValueValidators(ValidatorContext context, IField field, FieldValidatorFactory createFieldValidator) IEnumerable<IValidator> CreateValueValidators(ValidatorContext context, IField field, ValidatorFactory createFieldValidator)
{ {
yield break; yield break;
} }
IEnumerable<IValidator> CreateContentValidators(ValidatorContext context, FieldValidatorFactory createFieldValidator) IEnumerable<IValidator> CreateContentValidators(ValidatorContext context, ValidatorFactory createFieldValidator)
{ {
yield break; yield break;
} }

29
backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/JsonValueConverter.cs

@ -9,6 +9,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using NodaTime.Text; using NodaTime.Text;
using Squidex.Domain.Apps.Core.Schemas; using Squidex.Domain.Apps.Core.Schemas;
using Squidex.Infrastructure;
using Squidex.Infrastructure.Json.Objects; using Squidex.Infrastructure.Json.Objects;
using Squidex.Infrastructure.Translations; using Squidex.Infrastructure.Translations;
using Squidex.Infrastructure.Validation; using Squidex.Infrastructure.Validation;
@ -36,12 +37,12 @@ namespace Squidex.Domain.Apps.Core.ValidateContent
public (object? Result, JsonError? Error) Visit(IField<AssetsFieldProperties> field) public (object? Result, JsonError? Error) Visit(IField<AssetsFieldProperties> field)
{ {
return ConvertToStringList(); return ConvertToIdList();
} }
public (object? Result, JsonError? Error) Visit(IField<ReferencesFieldProperties> field) public (object? Result, JsonError? Error) Visit(IField<ReferencesFieldProperties> field)
{ {
return ConvertToStringList(); return ConvertToIdList();
} }
public (object? Result, JsonError? Error) Visit(IField<TagsFieldProperties> field) public (object? Result, JsonError? Error) Visit(IField<TagsFieldProperties> field)
@ -153,6 +154,30 @@ namespace Squidex.Domain.Apps.Core.ValidateContent
return (value, null); return (value, null);
} }
private (object? Result, JsonError? Error) ConvertToIdList()
{
if (value is JsonArray array)
{
var result = new List<DomainId>(array.Count);
foreach (var item in array)
{
if (item is JsonString s && !string.IsNullOrWhiteSpace(s.Value))
{
result.Add(DomainId.Create(s.Value));
}
else
{
return (null, new JsonError("Invalid json type, expected array of strings."));
}
}
return (result, null);
}
return (null, new JsonError("Invalid json type, expected array of strings."));
}
private (object? Result, JsonError? Error) ConvertToStringList() private (object? Result, JsonError? Error) ConvertToStringList()
{ {
if (value is JsonArray array) if (value is JsonArray array)

2
backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/Validators/AggregateValidator.cs

@ -14,7 +14,7 @@ using Squidex.Infrastructure.Translations;
namespace Squidex.Domain.Apps.Core.ValidateContent.Validators namespace Squidex.Domain.Apps.Core.ValidateContent.Validators
{ {
internal sealed class AggregateValidator : IValidator public sealed class AggregateValidator : IValidator
{ {
private readonly IValidator[]? validators; private readonly IValidator[]? validators;
private readonly ISemanticLog log; private readonly ISemanticLog log;

13
backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/Validators/CollectionItemValidator.cs

@ -14,13 +14,13 @@ namespace Squidex.Domain.Apps.Core.ValidateContent.Validators
{ {
public sealed class CollectionItemValidator : IValidator public sealed class CollectionItemValidator : IValidator
{ {
private readonly IValidator[] itemValidators; private readonly IValidator itemValidator;
public CollectionItemValidator(params IValidator[] itemValidators) public CollectionItemValidator(IValidator itemValidator)
{ {
Guard.NotEmpty(itemValidators, nameof(itemValidators)); Guard.NotNull(itemValidator, nameof(itemValidator));
this.itemValidators = itemValidators; this.itemValidator = itemValidator;
} }
public async Task ValidateAsync(object? value, ValidationContext context, AddError addError) public async Task ValidateAsync(object? value, ValidationContext context, AddError addError)
@ -34,10 +34,7 @@ namespace Squidex.Domain.Apps.Core.ValidateContent.Validators
{ {
var innerContext = context.Nested($"[{index}]"); var innerContext = context.Nested($"[{index}]");
foreach (var itemValidator in itemValidators) await itemValidator.ValidateAsync(item, innerContext, addError);
{
innerTasks.Add(itemValidator.ValidateAsync(item, innerContext, addError));
}
index++; index++;
} }

23
backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/Validators/FieldValidator.cs

@ -5,9 +5,6 @@
// All rights reserved. Licensed under the MIT license. // All rights reserved. Licensed under the MIT license.
// ========================================================================== // ==========================================================================
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Squidex.Domain.Apps.Core.Schemas; using Squidex.Domain.Apps.Core.Schemas;
using Squidex.Infrastructure; using Squidex.Infrastructure;
@ -18,16 +15,16 @@ namespace Squidex.Domain.Apps.Core.ValidateContent.Validators
{ {
public sealed class FieldValidator : IValidator public sealed class FieldValidator : IValidator
{ {
private readonly IValidator[] validators; private readonly IValidator fieldValueValidator;
private readonly IField field; private readonly IField field;
public FieldValidator(IEnumerable<IValidator>? validators, IField field) public FieldValidator(IValidator fieldValueValidator, IField field)
{ {
Guard.NotNull(field, nameof(field)); Guard.NotNull(field, nameof(field));
Guard.NotNull(fieldValueValidator, nameof(fieldValueValidator));
this.validators = validators?.ToArray() ?? Array.Empty<IValidator>();
this.field = field; this.field = field;
this.fieldValueValidator = fieldValueValidator;
} }
public async Task ValidateAsync(object? value, ValidationContext context, AddError addError) public async Task ValidateAsync(object? value, ValidationContext context, AddError addError)
@ -63,17 +60,7 @@ namespace Squidex.Domain.Apps.Core.ValidateContent.Validators
return; return;
} }
if (validators.Length > 0) await fieldValueValidator.ValidateAsync(typedValue, context, addError);
{
var tasks = new List<Task>();
foreach (var validator in validators)
{
tasks.Add(validator.ValidateAsync(typedValue, context, addError));
}
await Task.WhenAll(tasks);
}
} }
} }
} }

2
backend/src/Squidex.Domain.Apps.Entities/Contents/Validation/DependencyValidatorsFactory.cs

@ -29,7 +29,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Validation
this.contentRepository = contentRepository; this.contentRepository = contentRepository;
} }
public IEnumerable<IValidator> CreateValueValidators(ValidatorContext context, IField field, FieldValidatorFactory createFieldValidator) public IEnumerable<IValidator> CreateValueValidators(ValidatorContext context, IField field, ValidatorFactory createFieldValidator)
{ {
if (context.Mode == ValidationMode.Optimized) if (context.Mode == ValidationMode.Optimized)
{ {

112
backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/AssetsFieldTests.cs

@ -5,10 +5,16 @@
// All rights reserved. Licensed under the MIT license. // All rights reserved. Licensed under the MIT license.
// ========================================================================== // ==========================================================================
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using FluentAssertions;
using Squidex.Domain.Apps.Core.Schemas; using Squidex.Domain.Apps.Core.Schemas;
using Squidex.Domain.Apps.Core.TestHelpers; using Squidex.Domain.Apps.Core.TestHelpers;
using Squidex.Domain.Apps.Core.ValidateContent;
using Squidex.Domain.Apps.Core.ValidateContent.Validators;
using Squidex.Infrastructure.Json.Objects;
using Xunit; using Xunit;
namespace Squidex.Domain.Apps.Core.Operations.ValidateContent namespace Squidex.Domain.Apps.Core.Operations.ValidateContent
@ -16,6 +22,28 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent
public class AssetsFieldTests : IClassFixture<TranslationsFixture> public class AssetsFieldTests : IClassFixture<TranslationsFixture>
{ {
private readonly List<string> errors = new List<string>(); private readonly List<string> errors = new List<string>();
private readonly IValidatorsFactory factory;
private class CustomFactory : IValidatorsFactory
{
public IEnumerable<IValidator> CreateValueValidators(ValidatorContext context, IField field, ValidatorFactory createFieldValidator)
{
if (field is IField<AssetsFieldProperties> assets)
{
yield return new AssetsValidator(assets.Properties.IsRequired, assets.Properties, ids =>
{
var result = ids.Select(TestAssets.Document).ToList();
return Task.FromResult<IReadOnlyList<IAssetInfo>>(result);
});
}
}
}
public AssetsFieldTests()
{
factory = new CustomFactory();
}
[Fact] [Fact]
public void Should_instantiate_field() public void Should_instantiate_field()
@ -30,11 +58,93 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent
{ {
var sut = Field(new AssetsFieldProperties()); var sut = Field(new AssetsFieldProperties());
await sut.ValidateAsync(null, errors); await sut.ValidateAsync(CreateValue(null), errors, factory: factory);
Assert.Empty(errors); Assert.Empty(errors);
} }
[Fact]
public async Task Should_not_add_error_if_number_of_assets_is_equal_to_min_and_max_items()
{
var sut = Field(new AssetsFieldProperties { MinItems = 2, MaxItems = 2 });
await sut.ValidateAsync(CreateValue(Guid.NewGuid(), Guid.NewGuid()), errors, factory: factory);
Assert.Empty(errors);
}
[Fact]
public async Task Should_not_add_error_if_duplicate_values_are_ignored()
{
var sut = Field(new AssetsFieldProperties { AllowDuplicates = true });
await sut.ValidateAsync(CreateValue(Guid.NewGuid(), Guid.NewGuid()), errors, factory: factory);
Assert.Empty(errors);
}
[Fact]
public async Task Should_add_error_if_assets_are_required_and_null()
{
var sut = Field(new AssetsFieldProperties { IsRequired = true });
await sut.ValidateAsync(CreateValue(null), errors, factory: factory);
errors.Should().BeEquivalentTo(
new[] { "Field is required." });
}
[Fact]
public async Task Should_add_error_if_assets_are_required_and_empty()
{
var sut = Field(new AssetsFieldProperties { IsRequired = true });
await sut.ValidateAsync(CreateValue(), errors, factory: factory);
errors.Should().BeEquivalentTo(
new[] { "Field is required." });
}
[Fact]
public async Task Should_add_error_if_value_has_not_enough_items()
{
var sut = Field(new AssetsFieldProperties { MinItems = 3 });
await sut.ValidateAsync(CreateValue(Guid.NewGuid(), Guid.NewGuid()), errors, factory: factory);
errors.Should().BeEquivalentTo(
new[] { "Must have at least 3 item(s)." });
}
[Fact]
public async Task Should_add_error_if_value_has_too_much_items()
{
var sut = Field(new AssetsFieldProperties { MaxItems = 1 });
await sut.ValidateAsync(CreateValue(Guid.NewGuid(), Guid.NewGuid()), errors, factory: factory);
errors.Should().BeEquivalentTo(
new[] { "Must not have more than 1 item(s)." });
}
[Fact]
public async Task Should_add_error_if_values_contains_duplicate()
{
var sut = Field(new AssetsFieldProperties());
var id = Guid.NewGuid();
await sut.ValidateAsync(CreateValue(id, id), errors, factory: factory);
errors.Should().BeEquivalentTo(
new[] { "Must not contain duplicate values." });
}
private static IJsonValue CreateValue(params Guid[]? ids)
{
return ids == null ? JsonValue.Null : JsonValue.Array(ids.Select(x => (object)x.ToString()).ToArray());
}
private static RootField<AssetsFieldProperties> Field(AssetsFieldProperties properties) private static RootField<AssetsFieldProperties> Field(AssetsFieldProperties properties)
{ {
return Fields.Assets(1, "my-assets", Partitioning.Invariant, properties); return Fields.Assets(1, "my-assets", Partitioning.Invariant, properties);

4
backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/ContentValidationTests.cs

@ -39,7 +39,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent
var validatorFactory = A.Fake<IValidatorsFactory>(); var validatorFactory = A.Fake<IValidatorsFactory>();
A.CallTo(() => validatorFactory.CreateValueValidators(A<ValidationContext>._, A<IField>._, A<FieldValidatorFactory>._)) A.CallTo(() => validatorFactory.CreateValueValidators(A<ValidationContext>._, A<IField>._, A<ValidatorFactory>._))
.Returns(Enumerable.Repeat(validator, 1)); .Returns(Enumerable.Repeat(validator, 1));
schema = schema.AddNumber(1, "my-field", Partitioning.Invariant, schema = schema.AddNumber(1, "my-field", Partitioning.Invariant,
@ -70,7 +70,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent
var validatorFactory = A.Fake<IValidatorsFactory>(); var validatorFactory = A.Fake<IValidatorsFactory>();
A.CallTo(() => validatorFactory.CreateFieldValidators(A<ValidationContext>._, A<IField>._, A<FieldValidatorFactory>._)) A.CallTo(() => validatorFactory.CreateFieldValidators(A<ValidationContext>._, A<IField>._, A<ValidatorFactory>._))
.Returns(Enumerable.Repeat(validator, 1)); .Returns(Enumerable.Repeat(validator, 1));
schema = schema.AddNumber(1, "my-field", Partitioning.Invariant, schema = schema.AddNumber(1, "my-field", Partitioning.Invariant,

131
backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/ReferencesFieldTests.cs

@ -6,9 +6,16 @@
// ========================================================================== // ==========================================================================
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using FluentAssertions;
using Squidex.Domain.Apps.Core.Contents;
using Squidex.Domain.Apps.Core.Schemas; using Squidex.Domain.Apps.Core.Schemas;
using Squidex.Domain.Apps.Core.TestHelpers; using Squidex.Domain.Apps.Core.TestHelpers;
using Squidex.Domain.Apps.Core.ValidateContent;
using Squidex.Domain.Apps.Core.ValidateContent.Validators;
using Squidex.Infrastructure;
using Squidex.Infrastructure.Json.Objects;
using Xunit; using Xunit;
namespace Squidex.Domain.Apps.Core.Operations.ValidateContent namespace Squidex.Domain.Apps.Core.Operations.ValidateContent
@ -16,6 +23,38 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent
public class ReferencesFieldTests : IClassFixture<TranslationsFixture> public class ReferencesFieldTests : IClassFixture<TranslationsFixture>
{ {
private readonly List<string> errors = new List<string>(); private readonly List<string> errors = new List<string>();
private readonly DomainId schemaId = DomainId.NewGuid();
private readonly DomainId ref1 = DomainId.NewGuid();
private readonly DomainId ref2 = DomainId.NewGuid();
private readonly IValidatorsFactory factory;
private class CustomFactory : IValidatorsFactory
{
private readonly DomainId schemaId;
public CustomFactory(DomainId schemaId)
{
this.schemaId = schemaId;
}
public IEnumerable<IValidator> CreateValueValidators(ValidatorContext context, IField field, ValidatorFactory createFieldValidator)
{
if (field is IField<ReferencesFieldProperties> references)
{
yield return new ReferencesValidator(references.Properties.IsRequired, references.Properties, ids =>
{
var result = ids.Select(x => (schemaId, x, Status.Published)).ToList();
return Task.FromResult<IReadOnlyList<(DomainId SchemaId, DomainId Id, Status Status)>>(result);
});
}
}
}
public ReferencesFieldTests()
{
factory = new CustomFactory(schemaId);
}
[Fact] [Fact]
public void Should_instantiate_field() public void Should_instantiate_field()
@ -25,16 +64,106 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent
Assert.Equal("my-refs", sut.Name); Assert.Equal("my-refs", sut.Name);
} }
[Fact]
public async Task Should_not_add_error_if_references_are_valid()
{
var sut = Field(new ReferencesFieldProperties());
await sut.ValidateAsync(CreateValue(ref1), errors, factory: factory);
Assert.Empty(errors);
}
[Fact] [Fact]
public async Task Should_not_add_error_if_references_are_null_and_valid() public async Task Should_not_add_error_if_references_are_null_and_valid()
{ {
var sut = Field(new ReferencesFieldProperties()); var sut = Field(new ReferencesFieldProperties());
await sut.ValidateAsync(null, errors); await sut.ValidateAsync(CreateValue(null), errors, factory: factory);
Assert.Empty(errors);
}
[Fact]
public async Task Should_not_add_error_if_number_of_references_is_equal_to_min_and_max_items()
{
var sut = Field(new ReferencesFieldProperties { MinItems = 2, MaxItems = 2 });
await sut.ValidateAsync(CreateValue(ref1, ref2), errors, factory: factory);
Assert.Empty(errors); Assert.Empty(errors);
} }
[Fact]
public async Task Should_not_add_error_if_duplicate_values_are_allowed()
{
var sut = Field(new ReferencesFieldProperties { MinItems = 2, MaxItems = 2, AllowDuplicates = true });
await sut.ValidateAsync(CreateValue(ref1, ref1), errors, factory: factory);
Assert.Empty(errors);
}
[Fact]
public async Task Should_add_error_if_references_are_required_and_null()
{
var sut = Field(new ReferencesFieldProperties { SchemaId = schemaId, IsRequired = true });
await sut.ValidateAsync(CreateValue(null), errors, factory: factory);
errors.Should().BeEquivalentTo(
new[] { "Field is required." });
}
[Fact]
public async Task Should_add_error_if_references_are_required_and_empty()
{
var sut = Field(new ReferencesFieldProperties { SchemaId = schemaId, IsRequired = true });
await sut.ValidateAsync(CreateValue(), errors, factory: factory);
errors.Should().BeEquivalentTo(
new[] { "Field is required." });
}
[Fact]
public async Task Should_add_error_if_value_has_not_enough_items()
{
var sut = Field(new ReferencesFieldProperties { SchemaId = schemaId, MinItems = 3 });
await sut.ValidateAsync(CreateValue(ref1, ref2), errors, factory: factory);
errors.Should().BeEquivalentTo(
new[] { "Must have at least 3 item(s)." });
}
[Fact]
public async Task Should_add_error_if_value_has_too_much_items()
{
var sut = Field(new ReferencesFieldProperties { SchemaId = schemaId, MaxItems = 1 });
await sut.ValidateAsync(CreateValue(ref1, ref2), errors, factory: factory);
errors.Should().BeEquivalentTo(
new[] { "Must not have more than 1 item(s)." });
}
[Fact]
public async Task Should_add_error_if_reference_contains_duplicate_values()
{
var sut = Field(new ReferencesFieldProperties { SchemaId = schemaId });
await sut.ValidateAsync(CreateValue(ref1, ref1), errors, factory: factory);
errors.Should().BeEquivalentTo(
new[] { "Must not contain duplicate values." });
}
private static IJsonValue CreateValue(params DomainId[]? ids)
{
return ids == null ? JsonValue.Null : JsonValue.Array(ids.Select(x => (object)x.ToString()).ToArray());
}
private static RootField<ReferencesFieldProperties> Field(ReferencesFieldProperties properties) private static RootField<ReferencesFieldProperties> Field(ReferencesFieldProperties properties)
{ {
return Fields.References(1, "my-refs", Partitioning.Invariant, properties); return Fields.References(1, "my-refs", Partitioning.Invariant, properties);

3
backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/ValidationTestExtensions.cs

@ -49,8 +49,9 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent
var context = CreateContext(schema, mode, updater, action); var context = CreateContext(schema, mode, updater, action);
var validators = Factories(factory).SelectMany(x => x.CreateValueValidators(context, field, null!)).ToArray(); var validators = Factories(factory).SelectMany(x => x.CreateValueValidators(context, field, null!)).ToArray();
var validator = new AggregateValidator(validators, Log);
return new FieldValidator(validators, field) return new FieldValidator(validator, field)
.ValidateAsync(value, context, CreateFormatter(errors)); .ValidateAsync(value, context, CreateFormatter(errors));
} }

59
backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/Validators/AssetsValidatorTests.cs

@ -9,7 +9,6 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using FluentAssertions; using FluentAssertions;
using Squidex.Domain.Apps.Core.Assets;
using Squidex.Domain.Apps.Core.Schemas; using Squidex.Domain.Apps.Core.Schemas;
using Squidex.Domain.Apps.Core.TestHelpers; using Squidex.Domain.Apps.Core.TestHelpers;
using Squidex.Domain.Apps.Core.ValidateContent; using Squidex.Domain.Apps.Core.ValidateContent;
@ -23,61 +22,9 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent.Validators
public class AssetsValidatorTests : IClassFixture<TranslationsFixture> public class AssetsValidatorTests : IClassFixture<TranslationsFixture>
{ {
private readonly List<string> errors = new List<string>(); private readonly List<string> errors = new List<string>();
private readonly IAssetInfo document = TestAssets.Document(DomainId.NewGuid());
public sealed class AssetInfo : IAssetInfo private readonly IAssetInfo image1 = TestAssets.Image(DomainId.NewGuid());
{ private readonly IAssetInfo image2 = TestAssets.Image(DomainId.NewGuid());
public DomainId AssetId { get; set; }
public string FileName { get; set; }
public string FileHash { get; set; }
public string Slug { get; set; }
public long FileSize { get; set; }
public bool IsImage { get; set; }
public int? PixelWidth { get; set; }
public int? PixelHeight { get; set; }
public AssetMetadata Metadata { get; set; }
public AssetType Type { get; set; }
}
private readonly AssetInfo document = new AssetInfo
{
AssetId = DomainId.NewGuid(),
FileName = "MyDocument.pdf",
FileSize = 1024 * 4,
Type = AssetType.Unknown
};
private readonly AssetInfo image1 = new AssetInfo
{
AssetId = DomainId.NewGuid(),
FileName = "MyImage.png",
FileSize = 1024 * 8,
Type = AssetType.Image,
Metadata =
new AssetMetadata()
.SetPixelWidth(800)
.SetPixelHeight(600)
};
private readonly AssetInfo image2 = new AssetInfo
{
AssetId = DomainId.NewGuid(),
FileName = "MyImage.png",
FileSize = 1024 * 8,
Type = AssetType.Image,
Metadata =
new AssetMetadata()
.SetPixelWidth(800)
.SetPixelHeight(600)
};
[Fact] [Fact]
public async Task Should_not_add_error_if_assets_are_valid() public async Task Should_not_add_error_if_assets_are_valid()

65
backend/tests/Squidex.Domain.Apps.Core.Tests/TestHelpers/TestAssets.cs

@ -0,0 +1,65 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using Squidex.Domain.Apps.Core.Assets;
using Squidex.Domain.Apps.Core.ValidateContent;
using Squidex.Infrastructure;
namespace Squidex.Domain.Apps.Core.TestHelpers
{
public static class TestAssets
{
public sealed class AssetInfo : IAssetInfo
{
public DomainId AssetId { get; set; }
public string FileName { get; set; }
public string FileHash { get; set; }
public string Slug { get; set; }
public long FileSize { get; set; }
public bool IsImage { get; set; }
public int? PixelWidth { get; set; }
public int? PixelHeight { get; set; }
public AssetMetadata Metadata { get; set; }
public AssetType Type { get; set; }
}
public static AssetInfo Document(DomainId id)
{
return new AssetInfo
{
AssetId = id,
FileName = "MyDocument.pdf",
FileSize = 1024 * 4,
Type = AssetType.Unknown
};
}
public static AssetInfo Image(DomainId id)
{
return new AssetInfo
{
AssetId = id,
FileName = "MyImage.png",
FileSize = 1024 * 8,
Type = AssetType.Image,
Metadata =
new AssetMetadata()
.SetPixelWidth(800)
.SetPixelHeight(600)
};
}
}
}
Loading…
Cancel
Save