Browse Source

Refactored validators for nested schemas.

pull/297/head
Sebastian 8 years ago
parent
commit
2f747ec81d
  1. 4
      src/Squidex.Domain.Apps.Core.Model/Schemas/IArrayField.cs
  2. 2
      src/Squidex.Domain.Apps.Core.Operations/GenerateJsonSchema/JsonTypeVisitor.cs
  3. 98
      src/Squidex.Domain.Apps.Core.Operations/ValidateContent/ContentValidator.cs
  4. 57
      src/Squidex.Domain.Apps.Core.Operations/ValidateContent/FieldExtensions.cs
  5. 5
      src/Squidex.Domain.Apps.Core.Operations/ValidateContent/JsonValueConverter.cs
  6. 5
      src/Squidex.Domain.Apps.Core.Operations/ValidateContent/Validators/AllowedValuesValidator.cs
  7. 6
      src/Squidex.Domain.Apps.Core.Operations/ValidateContent/Validators/AssetsValidator.cs
  8. 13
      src/Squidex.Domain.Apps.Core.Operations/ValidateContent/Validators/CollectionItemValidator.cs
  9. 15
      src/Squidex.Domain.Apps.Core.Operations/ValidateContent/Validators/CollectionValidator.cs
  10. 5
      src/Squidex.Domain.Apps.Core.Operations/ValidateContent/Validators/FieldValidator.cs
  11. 27
      src/Squidex.Domain.Apps.Core.Operations/ValidateContent/Validators/Formatter.cs
  12. 5
      src/Squidex.Domain.Apps.Core.Operations/ValidateContent/Validators/IValidator.cs
  13. 70
      src/Squidex.Domain.Apps.Core.Operations/ValidateContent/Validators/ObjectValidator.cs
  14. 8
      src/Squidex.Domain.Apps.Core.Operations/ValidateContent/Validators/PatternValidator.cs
  15. 6
      src/Squidex.Domain.Apps.Core.Operations/ValidateContent/Validators/RangeValidator.cs
  16. 4
      src/Squidex.Domain.Apps.Core.Operations/ValidateContent/Validators/ReferencesValidator.cs
  17. 5
      src/Squidex.Domain.Apps.Core.Operations/ValidateContent/Validators/RequiredStringValidator.cs
  18. 5
      src/Squidex.Domain.Apps.Core.Operations/ValidateContent/Validators/RequiredValidator.cs
  19. 6
      src/Squidex.Domain.Apps.Core.Operations/ValidateContent/Validators/StringLengthValidator.cs
  20. 20
      src/Squidex.Domain.Apps.Core.Operations/ValidateContent/ValidatorsFactory.cs
  21. 32
      tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/AssetsFieldTests.cs
  22. 4
      tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/BooleanFieldTests.cs
  23. 34
      tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/ContentValidationTests.cs
  24. 10
      tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/DateTimeFieldTests.cs
  25. 8
      tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/GeolocationFieldTests.cs
  26. 2
      tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/JsonFieldTests.cs
  27. 10
      tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/NumberFieldTests.cs
  28. 12
      tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/ReferencesFieldTests.cs
  29. 10
      tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/StringFieldTests.cs
  30. 10
      tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/TagsFieldTests.cs
  31. 36
      tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/ValidationTestExtensions.cs
  32. 2
      tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/Validators/AllowedValuesValidatorTests.cs
  33. 10
      tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/Validators/CollectionItemValidatorTests.cs
  34. 16
      tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/Validators/CollectionValidatorTests.cs
  35. 4
      tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/Validators/PatternValidatorTests.cs
  36. 4
      tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/Validators/RangeValidatorTests.cs
  37. 4
      tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/Validators/RequiredStringValidatorTests.cs
  38. 2
      tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/Validators/RequiredValidatorTests.cs
  39. 4
      tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/Validators/StringLengthValidatorTests.cs

4
src/Squidex.Domain.Apps.Core.Model/Schemas/IArrayField.cs

@ -11,6 +11,8 @@ namespace Squidex.Domain.Apps.Core.Schemas
{
public interface IArrayField : IField<ArrayFieldProperties>
{
IReadOnlyCollection<IField> Fields { get; }
IReadOnlyDictionary<long, Field> FieldsById { get; }
IReadOnlyDictionary<string, Field> FieldsByName { get; }
}
}

2
src/Squidex.Domain.Apps.Core.Operations/GenerateJsonSchema/JsonTypeVisitor.cs

@ -30,7 +30,7 @@ namespace Squidex.Domain.Apps.Core.GenerateJsonSchema
Type = JsonObjectType.Object
};
foreach (var child in field.Fields)
foreach (var child in field.FieldsByName.Values)
{
var childProperty = field.Accept(this);

98
src/Squidex.Domain.Apps.Core.Operations/ValidateContent/ContentValidator.cs

@ -11,14 +11,17 @@ using System.Threading.Tasks;
using Newtonsoft.Json.Linq;
using Squidex.Domain.Apps.Core.Contents;
using Squidex.Domain.Apps.Core.Schemas;
using Squidex.Domain.Apps.Core.ValidateContent.Validators;
using Squidex.Infrastructure;
#pragma warning disable 168
#pragma warning disable SA1028, IDE0004 // Code must not contain trailing whitespace
namespace Squidex.Domain.Apps.Core.ValidateContent
{
public sealed class ContentValidator
{
private static readonly ContentFieldData DefaultFieldData = new ContentFieldData();
private static readonly JToken DefaultValue = JValue.CreateNull();
private readonly Schema schema;
private readonly PartitionResolver partitionResolver;
private readonly ValidationContext context;
@ -39,103 +42,56 @@ namespace Squidex.Domain.Apps.Core.ValidateContent
this.partitionResolver = partitionResolver;
}
public Task ValidatePartialAsync(NamedContentData data)
private void AddError(string field, string message)
{
Guard.NotNull(data, nameof(data));
var tasks = new List<Task>();
foreach (var fieldData in data)
{
var fieldName = fieldData.Key;
if (!schema.FieldsByName.TryGetValue(fieldData.Key, out var field))
{
errors.AddError("<FIELD> is not a known field.", fieldName);
}
else
{
tasks.Add(ValidateFieldPartialAsync(field, fieldData.Value));
}
}
return Task.WhenAll(tasks);
errors.Add(new ValidationError($"{field}: {message}", field));
}
private Task ValidateFieldPartialAsync(Field field, ContentFieldData fieldData)
public Task ValidatePartialAsync(NamedContentData data)
{
var partitioning = field.Partitioning;
var partition = partitionResolver(partitioning);
var tasks = new List<Task>();
Guard.NotNull(data, nameof(data));
foreach (var partitionValues in fieldData)
{
if (partition.TryGetItem(partitionValues.Key, out var item))
{
tasks.Add(field.ValidateAsync(partitionValues.Value, context.Optional(item.IsOptional), m => errors.AddError(m, field, item)));
}
else
{
errors.AddError($"<FIELD> has an unsupported {partitioning.Key} value '{partitionValues.Key}'.", field);
}
}
var validator = CreateSchemaValidator(true);
return Task.WhenAll(tasks);
return validator.ValidateAsync(data, context, AddError);
}
public Task ValidateAsync(NamedContentData data)
{
Guard.NotNull(data, nameof(data));
ValidateUnknownFields(data);
var tasks = new List<Task>();
foreach (var field in schema.FieldsByName.Values)
{
var fieldData = data.GetOrCreate(field.Name, k => new ContentFieldData());
tasks.Add(ValidateFieldAsync(field, fieldData));
}
var validator = CreateSchemaValidator(false);
return Task.WhenAll(tasks);
return validator.ValidateAsync(data, context, AddError);
}
private void ValidateUnknownFields(NamedContentData data)
private IValidator CreateSchemaValidator(bool isPartial)
{
foreach (var fieldData in data)
var fieldsValidators = new Dictionary<string, (bool IsOptional, IValidator Validator)>();
foreach (var field in schema.FieldsByName)
{
if (!schema.FieldsByName.ContainsKey(fieldData.Key))
{
errors.AddError("<FIELD> is not a known field.", fieldData.Key);
}
fieldsValidators[field.Key] = (!field.Value.RawProperties.IsRequired, CreateFieldValidator(field.Value, isPartial));
}
return new ObjectValidator<ContentFieldData>(fieldsValidators, isPartial, "field", DefaultFieldData);
}
private Task ValidateFieldAsync(Field field, ContentFieldData fieldData)
private IValidator CreateFieldValidator(Field field, bool isPartial)
{
var partitioning = field.Partitioning;
var partition = partitionResolver(partitioning);
var partitioning = partitionResolver(field.Partitioning);
var tasks = new List<Task>();
var fieldValidator = new FieldValidator(ValidatorsFactory.CreateValidators(field), field);
var fieldsValidators = new Dictionary<string, (bool IsOptional, IValidator Validator)>();
foreach (var partitionValues in fieldData)
foreach (var partition in partitioning)
{
if (!partition.TryGetItem(partitionValues.Key, out var _))
{
errors.AddError($"<FIELD> has an unsupported {partitioning.Key} value '{partitionValues.Key}'.", field);
}
fieldsValidators[partition.Key] = (partition.IsOptional, fieldValidator);
}
foreach (var item in partition)
{
var value = fieldData.GetOrCreate(item.Key, k => JValue.CreateNull());
tasks.Add(field.ValidateAsync(value, context.Optional(item.IsOptional), m => errors.AddError(m, field, item)));
}
var type = field.Partitioning.Equals(Partitioning.Language) ? "language" : "invariant value";
return Task.WhenAll(tasks);
return new ObjectValidator<JToken>(fieldsValidators, isPartial, type, DefaultValue);
}
}
}

57
src/Squidex.Domain.Apps.Core.Operations/ValidateContent/FieldExtensions.cs

@ -1,57 +0,0 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschränkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using System;
using System.Collections.Concurrent;
using System.Threading.Tasks;
using Newtonsoft.Json.Linq;
using Squidex.Domain.Apps.Core.Schemas;
using Squidex.Infrastructure;
using Squidex.Infrastructure.Json;
namespace Squidex.Domain.Apps.Core.ValidateContent
{
public static class FieldExtensions
{
public static void AddError(this ConcurrentBag<ValidationError> errors, string message, IField field, IFieldPartitionItem partitionItem = null)
{
AddError(errors, message, !string.IsNullOrWhiteSpace(field.RawProperties.Label) ? field.RawProperties.Label : field.Name, field.Name, partitionItem);
}
public static void AddError(this ConcurrentBag<ValidationError> errors, string message, string fieldName, IFieldPartitionItem partitionItem = null)
{
AddError(errors, message, fieldName, fieldName, partitionItem);
}
public static void AddError(this ConcurrentBag<ValidationError> errors, string message, string displayName, string fieldName, IFieldPartitionItem partitionItem = null)
{
if (partitionItem != null && partitionItem != InvariantPartitioning.Instance.Master)
{
displayName += $" ({partitionItem.Key})";
}
errors.Add(new ValidationError(message.Replace("<FIELD>", displayName), fieldName));
}
public static async Task ValidateAsync(this IField field, JToken value, ValidationContext context, Action<string> addError)
{
try
{
var typedValue = value.IsNull() ? null : JsonValueConverter.ConvertValue(field, value);
foreach (var validator in ValidatorsFactory.CreateValidators(field))
{
await validator.ValidateAsync(typedValue, context, addError);
}
}
catch
{
addError("<FIELD> is not a valid value.");
}
}
}
}

5
src/Squidex.Domain.Apps.Core.Operations/ValidateContent/JsonValueConverter.cs

@ -38,11 +38,6 @@ namespace Squidex.Domain.Apps.Core.ValidateContent
return Value.ToObject<List<Guid>>();
}
internal static object ConvertValue(IField field, object value)
{
throw new NotImplementedException();
}
public object Visit(IField<BooleanFieldProperties> field)
{
return (bool?)Value;

5
src/Squidex.Domain.Apps.Core.Operations/ValidateContent/Validators/AllowedValuesValidator.cs

@ -5,7 +5,6 @@
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using System;
using System.Linq;
using System.Threading.Tasks;
using Squidex.Infrastructure;
@ -24,7 +23,7 @@ namespace Squidex.Domain.Apps.Core.ValidateContent.Validators
this.allowedValues = allowedValues;
}
public Task ValidateAsync(object value, ValidationContext context, Action<string> addError)
public Task ValidateAsync(object value, ValidationContext context, ErrorFormatter addError)
{
if (value == null)
{
@ -35,7 +34,7 @@ namespace Squidex.Domain.Apps.Core.ValidateContent.Validators
if (!allowedValues.Contains(typedValue))
{
addError("<FIELD> is not an allowed value.");
addError(null, "Not an allowed value.");
}
return TaskHelper.Done;

6
src/Squidex.Domain.Apps.Core.Operations/ValidateContent/Validators/AssetsValidator.cs

@ -23,9 +23,9 @@ namespace Squidex.Domain.Apps.Core.ValidateContent.Validators
this.properties = properties;
}
public async Task ValidateAsync(object value, ValidationContext context, Action<string> addError)
public async Task ValidateAsync(object value, ValidationContext context, ErrorFormatter addError)
{
if (value is ICollection<Guid> assetIds)
if (value is ICollection<Guid> assetIds && assetIds.Count > 0)
{
var assets = await context.GetAssetInfosAsync(assetIds);
var i = 0;
@ -38,7 +38,7 @@ namespace Squidex.Domain.Apps.Core.ValidateContent.Validators
void Error(string message)
{
addError($"<FIELD> has invalid asset #{i}: {message}");
addError($"[{i}]", message);
}
if (asset == null)

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

@ -5,14 +5,14 @@
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using System;
using System.Collections;
using System.Collections.Generic;
using System.Threading.Tasks;
using Squidex.Infrastructure;
namespace Squidex.Domain.Apps.Core.ValidateContent.Validators
{
public sealed class CollectionItemValidator<T> : IValidator
public sealed class CollectionItemValidator : IValidator
{
private readonly IValidator[] itemValidators;
@ -24,10 +24,11 @@ namespace Squidex.Domain.Apps.Core.ValidateContent.Validators
this.itemValidators = itemValidators;
}
public async Task ValidateAsync(object value, ValidationContext context, Action<string> addError)
public async Task ValidateAsync(object value, ValidationContext context, ErrorFormatter addError)
{
if (value is ICollection<T> items)
if (value is ICollection items && items.Count > 0)
{
var innerTasks = new List<Task>();
var innerContext = context.Optional(false);
var index = 1;
@ -36,11 +37,13 @@ namespace Squidex.Domain.Apps.Core.ValidateContent.Validators
{
foreach (var itemValidator in itemValidators)
{
await itemValidator.ValidateAsync(item, innerContext, e => addError(e.Replace("<FIELD>", $"<FIELD> item #{index}")));
innerTasks.Add(itemValidator.ValidateAsync(item, innerContext, Formatter.Combine($"[{index}]", addError)));
}
index++;
}
await Task.WhenAll(innerTasks);
}
}
}

15
src/Squidex.Domain.Apps.Core.Operations/ValidateContent/Validators/CollectionValidator.cs

@ -5,14 +5,13 @@
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using System;
using System.Collections.Generic;
using System.Collections;
using System.Threading.Tasks;
using Squidex.Infrastructure.Tasks;
namespace Squidex.Domain.Apps.Core.ValidateContent.Validators
{
public sealed class CollectionValidator<T> : IValidator
public sealed class CollectionValidator : IValidator
{
private readonly bool isRequired;
private readonly int? minItems;
@ -25,13 +24,13 @@ namespace Squidex.Domain.Apps.Core.ValidateContent.Validators
this.maxItems = maxItems;
}
public Task ValidateAsync(object value, ValidationContext context, Action<string> addError)
public Task ValidateAsync(object value, ValidationContext context, ErrorFormatter addError)
{
if (!(value is ICollection<T> items) || items.Count == 0)
if (!(value is ICollection items) || items.Count == 0)
{
if (isRequired && !context.IsOptional)
{
addError("<FIELD> is required.");
addError(null, "Field is required.");
}
return TaskHelper.Done;
@ -39,12 +38,12 @@ namespace Squidex.Domain.Apps.Core.ValidateContent.Validators
if (minItems.HasValue && items.Count < minItems.Value)
{
addError($"<FIELD> must have at least {minItems} item(s).");
addError(null, $"Must have at least {minItems} item(s).");
}
if (maxItems.HasValue && items.Count > maxItems.Value)
{
addError($"<FIELD> must have not more than {maxItems} item(s).");
addError(null, $"Must have not more than {maxItems} item(s).");
}
return TaskHelper.Done;

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

@ -5,7 +5,6 @@
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Newtonsoft.Json.Linq;
@ -25,7 +24,7 @@ namespace Squidex.Domain.Apps.Core.ValidateContent.Validators
this.field = field;
}
public async Task ValidateAsync(object value, ValidationContext context, Action<string> addError)
public async Task ValidateAsync(object value, ValidationContext context, ErrorFormatter addError)
{
try
{
@ -43,7 +42,7 @@ namespace Squidex.Domain.Apps.Core.ValidateContent.Validators
}
catch
{
addError("<FIELD> is not a valid value.");
addError(null, "Not a valid value.");
}
}
}

27
src/Squidex.Domain.Apps.Core.Operations/ValidateContent/Validators/Formatter.cs

@ -0,0 +1,27 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
namespace Squidex.Domain.Apps.Core.ValidateContent.Validators
{
public static class Formatter
{
public static ErrorFormatter Combine(string field, ErrorFormatter formatter)
{
return (innerField, message) =>
{
if (!string.IsNullOrWhiteSpace(innerField))
{
formatter($"{field}.{innerField}", message);
}
else
{
formatter(field, message);
}
};
}
}
}

5
src/Squidex.Domain.Apps.Core.Operations/ValidateContent/Validators/IValidator.cs

@ -5,13 +5,14 @@
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using System;
using System.Threading.Tasks;
namespace Squidex.Domain.Apps.Core.ValidateContent.Validators
{
public delegate void ErrorFormatter(string field, string message);
public interface IValidator
{
Task ValidateAsync(object value, ValidationContext context, Action<string> addError);
Task ValidateAsync(object value, ValidationContext context, ErrorFormatter addError);
}
}

70
src/Squidex.Domain.Apps.Core.Operations/ValidateContent/Validators/ObjectValidator.cs

@ -0,0 +1,70 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using System.Collections.Generic;
using System.Threading.Tasks;
namespace Squidex.Domain.Apps.Core.ValidateContent.Validators
{
public sealed class ObjectValidator<TValue> : IValidator
{
private readonly IDictionary<string, (bool IsOptional, IValidator Validator)> schema;
private readonly bool isPartial;
private readonly string fieldType;
private readonly TValue fieldDefault;
public ObjectValidator(IDictionary<string, (bool IsOptional, IValidator Validator)> schema, bool isPartial, string fieldType, TValue fieldDefault)
{
this.schema = schema;
this.fieldDefault = fieldDefault;
this.fieldType = fieldType;
this.isPartial = isPartial;
}
public async Task ValidateAsync(object value, ValidationContext context, ErrorFormatter addError)
{
if (value is IReadOnlyDictionary<string, TValue> values)
{
foreach (var fieldData in values)
{
var name = fieldData.Key;
if (!schema.ContainsKey(name))
{
Formatter.Combine(name, addError)(null, $"Not a known {fieldType}.");
}
}
var tasks = new List<Task>();
foreach (var field in schema)
{
var name = field.Key;
if (!values.TryGetValue(name, out var fieldValue))
{
if (isPartial)
{
continue;
}
fieldValue = fieldDefault;
}
var (isOptional, validator) = field.Value;
var fieldContext = context.Optional(isOptional);
var fieldFormatter = Formatter.Combine(name, addError);
tasks.Add(validator.ValidateAsync(fieldValue, fieldContext, fieldFormatter));
}
await Task.WhenAll(tasks);
}
}
}
}

8
src/Squidex.Domain.Apps.Core.Operations/ValidateContent/Validators/PatternValidator.cs

@ -25,7 +25,7 @@ namespace Squidex.Domain.Apps.Core.ValidateContent.Validators
regex = new Regex("^" + pattern + "$", RegexOptions.None, Timeout);
}
public Task ValidateAsync(object value, ValidationContext context, Action<string> addError)
public Task ValidateAsync(object value, ValidationContext context, ErrorFormatter addError)
{
if (value is string stringValue)
{
@ -37,17 +37,17 @@ namespace Squidex.Domain.Apps.Core.ValidateContent.Validators
{
if (string.IsNullOrWhiteSpace(errorMessage))
{
addError("<FIELD> is not valid.");
addError(null, "Not valid.");
}
else
{
addError(errorMessage);
addError(null, errorMessage);
}
}
}
catch
{
addError("<FIELD> has a regex that is too slow.");
addError(null, "Regex is too slow.");
}
}
}

6
src/Squidex.Domain.Apps.Core.Operations/ValidateContent/Validators/RangeValidator.cs

@ -27,7 +27,7 @@ namespace Squidex.Domain.Apps.Core.ValidateContent.Validators
this.max = max;
}
public Task ValidateAsync(object value, ValidationContext context, Action<string> addError)
public Task ValidateAsync(object value, ValidationContext context, ErrorFormatter addError)
{
if (value == null)
{
@ -38,12 +38,12 @@ namespace Squidex.Domain.Apps.Core.ValidateContent.Validators
if (min.HasValue && typedValue.CompareTo(min.Value) < 0)
{
addError($"<FIELD> must be greater or equals than '{min}'.");
addError(null, $"Must be greater or equals than '{min}'.");
}
if (max.HasValue && typedValue.CompareTo(max.Value) > 0)
{
addError($"<FIELD> must be less or equals than '{max}'.");
addError(null, $"Must be less or equals than '{max}'.");
}
return TaskHelper.Done;

4
src/Squidex.Domain.Apps.Core.Operations/ValidateContent/Validators/ReferencesValidator.cs

@ -20,7 +20,7 @@ namespace Squidex.Domain.Apps.Core.ValidateContent.Validators
this.schemaId = schemaId;
}
public async Task ValidateAsync(object value, ValidationContext context, Action<string> addError)
public async Task ValidateAsync(object value, ValidationContext context, ErrorFormatter addError)
{
if (value is ICollection<Guid> contentIds)
{
@ -28,7 +28,7 @@ namespace Squidex.Domain.Apps.Core.ValidateContent.Validators
foreach (var invalidId in invalidIds)
{
addError($"<FIELD> contains invalid reference '{invalidId}'.");
addError(null, $"Contains invalid reference '{invalidId}'.");
}
}
}

5
src/Squidex.Domain.Apps.Core.Operations/ValidateContent/Validators/RequiredStringValidator.cs

@ -5,7 +5,6 @@
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using System;
using System.Threading.Tasks;
using Squidex.Infrastructure.Tasks;
@ -20,7 +19,7 @@ namespace Squidex.Domain.Apps.Core.ValidateContent.Validators
this.validateEmptyStrings = validateEmptyStrings;
}
public Task ValidateAsync(object value, ValidationContext context, Action<string> addError)
public Task ValidateAsync(object value, ValidationContext context, ErrorFormatter addError)
{
if (context.IsOptional || (value != null && !(value is string)))
{
@ -31,7 +30,7 @@ namespace Squidex.Domain.Apps.Core.ValidateContent.Validators
if (valueAsString == null || (validateEmptyStrings && string.IsNullOrWhiteSpace(valueAsString)))
{
addError("<FIELD> is required.");
addError(null, "Field is required.");
}
return TaskHelper.Done;

5
src/Squidex.Domain.Apps.Core.Operations/ValidateContent/Validators/RequiredValidator.cs

@ -5,7 +5,6 @@
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using System;
using System.Threading.Tasks;
using Squidex.Infrastructure.Tasks;
@ -13,11 +12,11 @@ namespace Squidex.Domain.Apps.Core.ValidateContent.Validators
{
public class RequiredValidator : IValidator
{
public Task ValidateAsync(object value, ValidationContext context, Action<string> addError)
public Task ValidateAsync(object value, ValidationContext context, ErrorFormatter addError)
{
if (value == null && !context.IsOptional)
{
addError("<FIELD> is required.");
addError(null, "Field is required.");
}
return TaskHelper.Done;

6
src/Squidex.Domain.Apps.Core.Operations/ValidateContent/Validators/StringLengthValidator.cs

@ -27,18 +27,18 @@ namespace Squidex.Domain.Apps.Core.ValidateContent.Validators
this.maxLength = maxLength;
}
public Task ValidateAsync(object value, ValidationContext context, Action<string> addError)
public Task ValidateAsync(object value, ValidationContext context, ErrorFormatter addError)
{
if (value is string stringValue && !string.IsNullOrEmpty(stringValue))
{
if (minLength.HasValue && stringValue.Length < minLength.Value)
{
addError($"<FIELD> must have more than '{minLength}' characters.");
addError(null, $"Must have more than '{minLength}' characters.");
}
if (maxLength.HasValue && stringValue.Length > maxLength.Value)
{
addError($"<FIELD> must have less than '{maxLength}' characters.");
addError(null, $"Must have less than '{maxLength}' characters.");
}
}

20
src/Squidex.Domain.Apps.Core.Operations/ValidateContent/ValidatorsFactory.cs

@ -8,6 +8,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Newtonsoft.Json.Linq;
using NodaTime;
using Squidex.Domain.Apps.Core.Schemas;
using Squidex.Domain.Apps.Core.ValidateContent.Validators;
@ -34,15 +35,24 @@ namespace Squidex.Domain.Apps.Core.ValidateContent
{
if (field.Properties.IsRequired || field.Properties.MinItems.HasValue || field.Properties.MaxItems.HasValue)
{
yield return new CollectionValidator<Guid>(field.Properties.IsRequired, field.Properties.MinItems, field.Properties.MaxItems);
yield return new CollectionValidator(field.Properties.IsRequired, field.Properties.MinItems, field.Properties.MaxItems);
}
var fieldsValidators = new Dictionary<string, (bool IsOptional, IValidator Validator)>();
foreach (var kvp in field.FieldsByName)
{
fieldsValidators[kvp.Key] = (false, new FieldValidator(kvp.Value.Accept(this), kvp.Value));
}
yield return new CollectionItemValidator(new ObjectValidator<JToken>(fieldsValidators, false, "field", JValue.CreateNull()));
}
public IEnumerable<IValidator> Visit(IField<AssetsFieldProperties> field)
{
if (field.Properties.IsRequired || field.Properties.MinItems.HasValue || field.Properties.MaxItems.HasValue)
{
yield return new CollectionValidator<Guid>(field.Properties.IsRequired, field.Properties.MinItems, field.Properties.MaxItems);
yield return new CollectionValidator(field.Properties.IsRequired, field.Properties.MinItems, field.Properties.MaxItems);
}
yield return new AssetsValidator(field.Properties);
@ -107,7 +117,7 @@ namespace Squidex.Domain.Apps.Core.ValidateContent
{
if (field.Properties.IsRequired || field.Properties.MinItems.HasValue || field.Properties.MaxItems.HasValue)
{
yield return new CollectionValidator<Guid>(field.Properties.IsRequired, field.Properties.MinItems, field.Properties.MaxItems);
yield return new CollectionValidator(field.Properties.IsRequired, field.Properties.MinItems, field.Properties.MaxItems);
}
if (field.Properties.SchemaId != Guid.Empty)
@ -143,10 +153,10 @@ namespace Squidex.Domain.Apps.Core.ValidateContent
{
if (field.Properties.IsRequired || field.Properties.MinItems.HasValue || field.Properties.MaxItems.HasValue)
{
yield return new CollectionValidator<string>(field.Properties.IsRequired, field.Properties.MinItems, field.Properties.MaxItems);
yield return new CollectionValidator(field.Properties.IsRequired, field.Properties.MinItems, field.Properties.MaxItems);
}
yield return new CollectionItemValidator<string>(new RequiredStringValidator());
yield return new CollectionItemValidator(new RequiredStringValidator());
}
}
}

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

@ -100,7 +100,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent
await sut.ValidateAsync(CreateValue(null), errors, ctx);
errors.ShouldBeEquivalentTo(
new[] { "<FIELD> is required." });
new[] { "Field is required." });
}
[Fact]
@ -111,7 +111,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent
await sut.ValidateAsync(CreateValue(), errors, ctx);
errors.ShouldBeEquivalentTo(
new[] { "<FIELD> is required." });
new[] { "Field is required." });
}
[Fact]
@ -122,7 +122,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent
await sut.ValidateAsync("invalid", errors);
errors.ShouldBeEquivalentTo(
new[] { "<FIELD> is not a valid value." });
new[] { "Not a valid value." });
}
[Fact]
@ -133,7 +133,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent
await sut.ValidateAsync(CreateValue(document.AssetId, document.AssetId), errors, ctx);
errors.ShouldBeEquivalentTo(
new[] { "<FIELD> must have at least 3 item(s)." });
new[] { "Must have at least 3 item(s)." });
}
[Fact]
@ -144,7 +144,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent
await sut.ValidateAsync(CreateValue(document.AssetId, document.AssetId), errors, ctx);
errors.ShouldBeEquivalentTo(
new[] { "<FIELD> must have not more than 1 item(s)." });
new[] { "Must have not more than 1 item(s)." });
}
[Fact]
@ -157,7 +157,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent
await sut.ValidateAsync(CreateValue(assetId), errors, ctx);
errors.ShouldBeEquivalentTo(
new[] { $"<FIELD> has invalid asset #1: Id '{assetId}' not found." });
new[] { $"[1]: Id '{assetId}' not found." });
}
[Fact]
@ -168,7 +168,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent
await sut.ValidateAsync(CreateValue(document.AssetId, image.AssetId), errors, ctx);
errors.ShouldBeEquivalentTo(
new[] { $"<FIELD> has invalid asset #1: '4 kB' less than minimum of '5 kB'." });
new[] { $"[1]: '4 kB' less than minimum of '5 kB'." });
}
[Fact]
@ -179,7 +179,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent
await sut.ValidateAsync(CreateValue(document.AssetId, image.AssetId), errors, ctx);
errors.ShouldBeEquivalentTo(
new[] { $"<FIELD> has invalid asset #2: '8 kB' greater than maximum of '5 kB'." });
new[] { $"[2]: '8 kB' greater than maximum of '5 kB'." });
}
[Fact]
@ -190,7 +190,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent
await sut.ValidateAsync(CreateValue(document.AssetId, image.AssetId), errors, ctx);
errors.ShouldBeEquivalentTo(
new[] { $"<FIELD> has invalid asset #1: Not an image." });
new[] { $"[1]: Not an image." });
}
[Fact]
@ -201,7 +201,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent
await sut.ValidateAsync(CreateValue(document.AssetId, image.AssetId), errors, ctx);
errors.ShouldBeEquivalentTo(
new[] { $"<FIELD> has invalid asset #2: Width '800px' less than minimum of '1000px'." });
new[] { $"[2]: Width '800px' less than minimum of '1000px'." });
}
[Fact]
@ -212,7 +212,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent
await sut.ValidateAsync(CreateValue(document.AssetId, image.AssetId), errors, ctx);
errors.ShouldBeEquivalentTo(
new[] { $"<FIELD> has invalid asset #2: Width '800px' greater than maximum of '700px'." });
new[] { $"[2]: Width '800px' greater than maximum of '700px'." });
}
[Fact]
@ -223,7 +223,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent
await sut.ValidateAsync(CreateValue(document.AssetId, image.AssetId), errors, ctx);
errors.ShouldBeEquivalentTo(
new[] { $"<FIELD> has invalid asset #2: Height '600px' less than minimum of '800px'." });
new[] { $"[2]: Height '600px' less than minimum of '800px'." });
}
[Fact]
@ -234,7 +234,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent
await sut.ValidateAsync(CreateValue(document.AssetId, image.AssetId), errors, ctx);
errors.ShouldBeEquivalentTo(
new[] { $"<FIELD> has invalid asset #2: Height '600px' greater than maximum of '500px'." });
new[] { $"[2]: Height '600px' greater than maximum of '500px'." });
}
[Fact]
@ -245,7 +245,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent
await sut.ValidateAsync(CreateValue(document.AssetId, image.AssetId), errors, ctx);
errors.ShouldBeEquivalentTo(
new[] { "<FIELD> has invalid asset #2: Aspect ratio not '1:1'." });
new[] { "[2]: Aspect ratio not '1:1'." });
}
[Fact]
@ -258,8 +258,8 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent
errors.ShouldBeEquivalentTo(
new[]
{
$"<FIELD> has invalid asset #1: Invalid file extension.",
$"<FIELD> has invalid asset #2: Invalid file extension."
$"[1]: Invalid file extension.",
$"[2]: Invalid file extension."
});
}

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

@ -54,7 +54,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent
await sut.ValidateAsync(CreateValue(null), errors);
errors.ShouldBeEquivalentTo(
new[] { "<FIELD> is required." });
new[] { "Field is required." });
}
[Fact]
@ -65,7 +65,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent
await sut.ValidateAsync(CreateValue("Invalid"), errors);
errors.ShouldBeEquivalentTo(
new[] { "<FIELD> is not a valid value." });
new[] { "Not a valid value." });
}
private static JValue CreateValue(object v)

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

@ -37,7 +37,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent
errors.ShouldBeEquivalentTo(
new List<ValidationError>
{
new ValidationError("unknown is not a known field.", "unknown")
new ValidationError("unknown: Not a known field.", "unknown")
});
}
@ -58,7 +58,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent
errors.ShouldBeEquivalentTo(
new List<ValidationError>
{
new ValidationError("my-field must be less or equals than '100'.", "my-field")
new ValidationError("my-field.iv: Must be less or equals than '100'.", "my-field.iv")
});
}
@ -79,8 +79,8 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent
errors.ShouldBeEquivalentTo(
new List<ValidationError>
{
new ValidationError("my-field has an unsupported invariant value 'es'.", "my-field"),
new ValidationError("my-field has an unsupported invariant value 'it'.", "my-field")
new ValidationError("my-field.es: Not a known invariant value.", "my-field.es"),
new ValidationError("my-field.it: Not a known invariant value.", "my-field.it")
});
}
@ -98,8 +98,8 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent
errors.ShouldBeEquivalentTo(
new List<ValidationError>
{
new ValidationError("my-field (de) is required.", "my-field"),
new ValidationError("my-field (en) is required.", "my-field")
new ValidationError("my-field.de: Field is required.", "my-field.de"),
new ValidationError("my-field.en: Field is required.", "my-field.en")
});
}
@ -117,7 +117,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent
errors.ShouldBeEquivalentTo(
new List<ValidationError>
{
new ValidationError("my-field is required.", "my-field")
new ValidationError("my-field.iv: Field is required.", "my-field.iv")
});
}
@ -138,7 +138,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent
errors.ShouldBeEquivalentTo(
new List<ValidationError>
{
new ValidationError("my-field has an unsupported language value 'xx'.", "my-field")
new ValidationError("my-field.xx: Not a known language.", "my-field.xx")
});
}
@ -181,8 +181,8 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent
errors.ShouldBeEquivalentTo(
new List<ValidationError>
{
new ValidationError("my-field has an unsupported language value 'es'.", "my-field"),
new ValidationError("my-field has an unsupported language value 'it'.", "my-field")
new ValidationError("my-field.es: Not a known language.", "my-field.es"),
new ValidationError("my-field.it: Not a known language.", "my-field.it")
});
}
@ -199,7 +199,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent
errors.ShouldBeEquivalentTo(
new List<ValidationError>
{
new ValidationError("unknown is not a known field.", "unknown")
new ValidationError("unknown: Not a known field.", "unknown")
});
}
@ -220,7 +220,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent
errors.ShouldBeEquivalentTo(
new List<ValidationError>
{
new ValidationError("my-field must be less or equals than '100'.", "my-field")
new ValidationError("my-field.iv: Must be less or equals than '100'.", "my-field.iv")
});
}
@ -241,8 +241,8 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent
errors.ShouldBeEquivalentTo(
new List<ValidationError>
{
new ValidationError("my-field has an unsupported invariant value 'es'.", "my-field"),
new ValidationError("my-field has an unsupported invariant value 'it'.", "my-field")
new ValidationError("my-field.es: Not a known invariant value.", "my-field.es"),
new ValidationError("my-field.it: Not a known invariant value.", "my-field.it")
});
}
@ -291,7 +291,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent
errors.ShouldBeEquivalentTo(
new List<ValidationError>
{
new ValidationError("my-field has an unsupported language value 'xx'.", "my-field")
new ValidationError("my-field.xx: Not a known language.", "my-field.xx")
});
}
@ -312,8 +312,8 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent
errors.ShouldBeEquivalentTo(
new List<ValidationError>
{
new ValidationError("my-field has an unsupported language value 'es'.", "my-field"),
new ValidationError("my-field has an unsupported language value 'it'.", "my-field")
new ValidationError("my-field.es: Not a known language.", "my-field.es"),
new ValidationError("my-field.it: Not a known language.", "my-field.it")
});
}
}

10
tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/DateTimeFieldTests.cs

@ -46,7 +46,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent
await sut.ValidateAsync(CreateValue(null), errors);
errors.ShouldBeEquivalentTo(
new[] { "<FIELD> is required." });
new[] { "Field is required." });
}
[Fact]
@ -57,7 +57,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent
await sut.ValidateAsync(CreateValue(FutureDays(0)), errors);
errors.ShouldBeEquivalentTo(
new[] { $"<FIELD> must be greater or equals than '{FutureDays(10)}'." });
new[] { $"Must be greater or equals than '{FutureDays(10)}'." });
}
[Fact]
@ -68,7 +68,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent
await sut.ValidateAsync(CreateValue(FutureDays(20)), errors);
errors.ShouldBeEquivalentTo(
new[] { $"<FIELD> must be less or equals than '{FutureDays(10)}'." });
new[] { $"Must be less or equals than '{FutureDays(10)}'." });
}
[Fact]
@ -79,7 +79,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent
await sut.ValidateAsync(CreateValue("Invalid"), errors);
errors.ShouldBeEquivalentTo(
new[] { "<FIELD> is not a valid value." });
new[] { "Not a valid value." });
}
[Fact]
@ -90,7 +90,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent
await sut.ValidateAsync(CreateValue(123), errors);
errors.ShouldBeEquivalentTo(
new[] { "<FIELD> is not a valid value." });
new[] { "Not a valid value." });
}
private static Instant FutureDays(int days)

8
tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/GeolocationFieldTests.cs

@ -62,7 +62,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent
await sut.ValidateAsync(CreateValue(geolocation), errors);
errors.ShouldBeEquivalentTo(
new[] { "<FIELD> is not a valid value." });
new[] { "Not a valid value." });
}
[Fact]
@ -77,7 +77,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent
await sut.ValidateAsync(CreateValue(geolocation), errors);
errors.ShouldBeEquivalentTo(
new[] { "<FIELD> is not a valid value." });
new[] { "Not a valid value." });
}
[Fact]
@ -93,7 +93,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent
await sut.ValidateAsync(CreateValue(geolocation), errors);
errors.ShouldBeEquivalentTo(
new[] { "<FIELD> is not a valid value." });
new[] { "Not a valid value." });
}
[Fact]
@ -104,7 +104,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent
await sut.ValidateAsync(CreateValue(JValue.CreateNull()), errors);
errors.ShouldBeEquivalentTo(
new[] { "<FIELD> is required." });
new[] { "Field is required." });
}
private static JToken CreateValue(JToken v)

2
tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/JsonFieldTests.cs

@ -44,7 +44,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent
await sut.ValidateAsync(CreateValue(JValue.CreateNull()), errors);
errors.ShouldBeEquivalentTo(
new[] { "<FIELD> is required." });
new[] { "Field is required." });
}
private static JValue CreateValue(JValue v)

10
tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/NumberFieldTests.cs

@ -45,7 +45,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent
await sut.ValidateAsync(CreateValue(null), errors);
errors.ShouldBeEquivalentTo(
new[] { "<FIELD> is required." });
new[] { "Field is required." });
}
[Fact]
@ -56,7 +56,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent
await sut.ValidateAsync(CreateValue(5), errors);
errors.ShouldBeEquivalentTo(
new[] { "<FIELD> must be greater or equals than '10'." });
new[] { "Must be greater or equals than '10'." });
}
[Fact]
@ -67,7 +67,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent
await sut.ValidateAsync(CreateValue(20), errors);
errors.ShouldBeEquivalentTo(
new[] { "<FIELD> must be less or equals than '10'." });
new[] { "Must be less or equals than '10'." });
}
[Fact]
@ -78,7 +78,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent
await sut.ValidateAsync(CreateValue(20), errors);
errors.ShouldBeEquivalentTo(
new[] { "<FIELD> is not an allowed value." });
new[] { "Not an allowed value." });
}
[Fact]
@ -89,7 +89,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent
await sut.ValidateAsync(CreateValue("Invalid"), errors);
errors.ShouldBeEquivalentTo(
new[] { "<FIELD> is not a valid value." });
new[] { "Not a valid value." });
}
private static JValue CreateValue(object v)

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

@ -59,7 +59,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent
await sut.ValidateAsync(CreateValue(null), errors);
errors.ShouldBeEquivalentTo(
new[] { "<FIELD> is required." });
new[] { "Field is required." });
}
[Fact]
@ -70,7 +70,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent
await sut.ValidateAsync(CreateValue(), errors);
errors.ShouldBeEquivalentTo(
new[] { "<FIELD> is required." });
new[] { "Field is required." });
}
[Fact]
@ -81,7 +81,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent
await sut.ValidateAsync("invalid", errors);
errors.ShouldBeEquivalentTo(
new[] { "<FIELD> is not a valid value." });
new[] { "Not a valid value." });
}
[Fact]
@ -92,7 +92,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent
await sut.ValidateAsync(CreateValue(Guid.NewGuid(), Guid.NewGuid()), errors);
errors.ShouldBeEquivalentTo(
new[] { "<FIELD> must have at least 3 item(s)." });
new[] { "Must have at least 3 item(s)." });
}
[Fact]
@ -103,7 +103,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent
await sut.ValidateAsync(CreateValue(Guid.NewGuid(), Guid.NewGuid()), errors);
errors.ShouldBeEquivalentTo(
new[] { "<FIELD> must have not more than 1 item(s)." });
new[] { "Must have not more than 1 item(s)." });
}
[Fact]
@ -116,7 +116,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent
await sut.ValidateAsync(CreateValue(referenceId), errors, ValidationTestExtensions.InvalidReferences(referenceId));
errors.ShouldBeEquivalentTo(
new[] { $"<FIELD> contains invalid reference '{referenceId}'." });
new[] { $"Contains invalid reference '{referenceId}'." });
}
private static JToken CreateValue(params Guid[] ids)

10
tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/StringFieldTests.cs

@ -45,7 +45,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent
await sut.ValidateAsync(CreateValue(null), errors);
errors.ShouldBeEquivalentTo(
new[] { "<FIELD> is required." });
new[] { "Field is required." });
}
[Fact]
@ -56,7 +56,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent
await sut.ValidateAsync(CreateValue("123"), errors);
errors.ShouldBeEquivalentTo(
new[] { "<FIELD> must have more than '10' characters." });
new[] { "Must have more than '10' characters." });
}
[Fact]
@ -67,7 +67,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent
await sut.ValidateAsync(CreateValue("12345678"), errors);
errors.ShouldBeEquivalentTo(
new[] { "<FIELD> must have less than '5' characters." });
new[] { "Must have less than '5' characters." });
}
[Fact]
@ -78,7 +78,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent
await sut.ValidateAsync(CreateValue("Bar"), errors);
errors.ShouldBeEquivalentTo(
new[] { "<FIELD> is not an allowed value." });
new[] { "Not an allowed value." });
}
[Fact]
@ -89,7 +89,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent
await sut.ValidateAsync(CreateValue("abc"), errors);
errors.ShouldBeEquivalentTo(
new[] { "<FIELD> is not valid." });
new[] { "Not valid." });
}
[Fact]

10
tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/TagsFieldTests.cs

@ -58,7 +58,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent
await sut.ValidateAsync(CreateValue(null), errors);
errors.ShouldBeEquivalentTo(
new[] { "<FIELD> is required." });
new[] { "Field is required." });
}
[Fact]
@ -69,7 +69,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent
await sut.ValidateAsync(CreateValue(), errors);
errors.ShouldBeEquivalentTo(
new[] { "<FIELD> is required." });
new[] { "Field is required." });
}
[Fact]
@ -80,7 +80,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent
await sut.ValidateAsync("invalid", errors);
errors.ShouldBeEquivalentTo(
new[] { "<FIELD> is not a valid value." });
new[] { "Not a valid value." });
}
[Fact]
@ -91,7 +91,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent
await sut.ValidateAsync(CreateValue(Guid.NewGuid(), Guid.NewGuid()), errors);
errors.ShouldBeEquivalentTo(
new[] { "<FIELD> must have at least 3 item(s)." });
new[] { "Must have at least 3 item(s)." });
}
[Fact]
@ -102,7 +102,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent
await sut.ValidateAsync(CreateValue(Guid.NewGuid(), Guid.NewGuid()), errors);
errors.ShouldBeEquivalentTo(
new[] { "<FIELD> must have not more than 1 item(s)." });
new[] { "Must have not more than 1 item(s)." });
}
private static JToken CreateValue(params Guid[] ids)

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

@ -25,22 +25,50 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent
public static Task ValidateAsync(this IValidator validator, object value, IList<string> errors, ValidationContext context = null)
{
return validator.ValidateAsync(value, context ?? ValidContext, errors.Add);
return validator.ValidateAsync(value,
CreateContext(context),
CreateFormatter(errors));
}
public static Task ValidateOptionalAsync(this IValidator validator, object value, IList<string> errors, ValidationContext context = null)
{
return validator.ValidateAsync(value, (context ?? ValidContext).Optional(true), errors.Add);
return validator.ValidateAsync(value,
CreateContext(context).Optional(true),
CreateFormatter(errors));
}
public static Task ValidateAsync(this IField field, JToken value, IList<string> errors, ValidationContext context = null)
{
return field.ValidateAsync(value, context ?? ValidContext, errors.Add);
return new FieldValidator(ValidatorsFactory.CreateValidators(field), field).ValidateAsync(value,
CreateContext(context),
CreateFormatter(errors));
}
public static Task ValidateOptionalAsync(this IField field, JToken value, IList<string> errors, ValidationContext context = null)
{
return field.ValidateAsync(value, (context ?? ValidContext).Optional(true), errors.Add);
return new FieldValidator(ValidatorsFactory.CreateValidators(field), field).ValidateAsync(value,
CreateContext(context).Optional(true),
CreateFormatter(errors));
}
private static ErrorFormatter CreateFormatter(IList<string> errors)
{
return (field, message) =>
{
if (field == null)
{
errors.Add(message);
}
else
{
errors.Add($"{field}: {message}");
}
};
}
private static ValidationContext CreateContext(ValidationContext context)
{
return context ?? ValidContext;
}
public static ValidationContext Assets(params IAssetInfo[] assets)

2
tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/Validators/AllowedValuesValidatorTests.cs

@ -45,7 +45,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent.Validators
await sut.ValidateAsync(50, errors);
errors.ShouldBeEquivalentTo(
new[] { "<FIELD> is not an allowed value." });
new[] { "Not an allowed value." });
}
}
}

10
tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/Validators/CollectionItemValidatorTests.cs

@ -20,7 +20,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent.Validators
[Fact]
public async Task Should_not_add_error_if_value_is_wrong_type()
{
var sut = new CollectionItemValidator<int>(new RangeValidator<int>(2, 4));
var sut = new CollectionItemValidator(new RangeValidator<int>(2, 4));
await sut.ValidateAsync(true, errors);
@ -30,7 +30,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent.Validators
[Fact]
public async Task Should_not_add_error_if_all_values_are_valid()
{
var sut = new CollectionItemValidator<int>(new RangeValidator<int>(2, 4));
var sut = new CollectionItemValidator(new RangeValidator<int>(2, 4));
await sut.ValidateAsync(new List<int> { 2, 3, 4 }, errors);
@ -40,15 +40,15 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent.Validators
[Fact]
public async Task Should_add_error_if_at_least_one_item_is_not_valid()
{
var sut = new CollectionItemValidator<int>(new RangeValidator<int>(2, 4));
var sut = new CollectionItemValidator(new RangeValidator<int>(2, 4));
await sut.ValidateAsync(new List<int> { 2, 1, 4, 5 }, errors);
errors.ShouldBeEquivalentTo(
new[]
{
"<FIELD> item #2 must be greater or equals than '2'.",
"<FIELD> item #4 must be less or equals than '4'."
"[2]: Must be greater or equals than '2'.",
"[4]: Must be less or equals than '4'."
});
}
}

16
tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/Validators/CollectionValidatorTests.cs

@ -20,7 +20,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent.Validators
[Fact]
public async Task Should_not_add_error_if_value_is_valid()
{
var sut = new CollectionValidator<int>(true, 1, 3);
var sut = new CollectionValidator(true, 1, 3);
await sut.ValidateAsync(new List<int> { 1, 2 }, errors);
@ -30,7 +30,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent.Validators
[Fact]
public async Task Should_not_add_error_if_optional()
{
var sut = new CollectionValidator<int>(true, 1, 3);
var sut = new CollectionValidator(true, 1, 3);
await sut.ValidateOptionalAsync(null, errors);
@ -40,34 +40,34 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent.Validators
[Fact]
public async Task Should_add_error_if_value_is_null()
{
var sut = new CollectionValidator<int>(true, 1, 3);
var sut = new CollectionValidator(true, 1, 3);
await sut.ValidateAsync(null, errors);
errors.ShouldBeEquivalentTo(
new[] { "<FIELD> is required." });
new[] { "Field is required." });
}
[Fact]
public async Task Should_add_error_if_collection_has_too_few_items()
{
var sut = new CollectionValidator<int>(true, 2, 3);
var sut = new CollectionValidator(true, 2, 3);
await sut.ValidateAsync(new List<int> { 1 }, errors);
errors.ShouldBeEquivalentTo(
new[] { "<FIELD> must have at least 2 item(s)." });
new[] { "Must have at least 2 item(s)." });
}
[Fact]
public async Task Should_add_error_if_collection_has_too_many_items()
{
var sut = new CollectionValidator<int>(true, 2, 3);
var sut = new CollectionValidator(true, 2, 3);
await sut.ValidateAsync(new List<int> { 1, 2, 3, 4 }, errors);
errors.ShouldBeEquivalentTo(
new[] { "<FIELD> must have not more than 3 item(s)." });
new[] { "Must have not more than 3 item(s)." });
}
}
}

4
tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/Validators/PatternValidatorTests.cs

@ -55,7 +55,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent.Validators
await sut.ValidateAsync("foo", errors);
errors.ShouldBeEquivalentTo(
new[] { "<FIELD> is not valid." });
new[] { "Not valid." });
}
[Fact]
@ -77,7 +77,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent.Validators
await sut.ValidateAsync("https://archiverbx.blob.core.windows.net/static/C:/Users/USR/Documents/Projects/PROJ/static/images/full/1234567890.jpg", errors);
errors.ShouldBeEquivalentTo(
new[] { "<FIELD> has a regex that is too slow." });
new[] { "Regex is too slow." });
}
}
}

4
tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/Validators/RangeValidatorTests.cs

@ -58,7 +58,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent.Validators
await sut.ValidateAsync(1500, errors);
errors.ShouldBeEquivalentTo(
new[] { "<FIELD> must be greater or equals than '2000'." });
new[] { "Must be greater or equals than '2000'." });
}
[Fact]
@ -69,7 +69,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent.Validators
await sut.ValidateAsync(1500, errors);
errors.ShouldBeEquivalentTo(
new[] { "<FIELD> must be less or equals than '1000'." });
new[] { "Must be less or equals than '1000'." });
}
}
}

4
tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/Validators/RequiredStringValidatorTests.cs

@ -59,7 +59,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent.Validators
await sut.ValidateAsync(string.Empty, errors);
errors.ShouldBeEquivalentTo(
new[] { "<FIELD> is required." });
new[] { "Field is required." });
}
[Fact]
@ -70,7 +70,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent.Validators
await sut.ValidateAsync(null, errors);
errors.ShouldBeEquivalentTo(
new[] { "<FIELD> is required." });
new[] { "Field is required." });
}
}
}

2
tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/Validators/RequiredValidatorTests.cs

@ -55,7 +55,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent.Validators
await sut.ValidateAsync(null, errors);
errors.ShouldBeEquivalentTo(
new[] { "<FIELD> is required." });
new[] { "Field is required." });
}
}
}

4
tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/Validators/StringLengthValidatorTests.cs

@ -69,7 +69,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent.Validators
await sut.ValidateAsync(CreateString(1500), errors);
errors.ShouldBeEquivalentTo(
new[] { "<FIELD> must have more than '2000' characters." });
new[] { "Must have more than '2000' characters." });
}
[Fact]
@ -80,7 +80,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent.Validators
await sut.ValidateAsync(CreateString(1500), errors);
errors.ShouldBeEquivalentTo(
new[] { "<FIELD> must have less than '1000' characters." });
new[] { "Must have less than '1000' characters." });
}
private static string CreateString(int size)

Loading…
Cancel
Save