Browse Source

References field and refactorings.

pull/65/head
Sebastian Stehle 9 years ago
parent
commit
0923a07bb2
  1. 8
      src/Squidex.Core/ContentExtensions.cs
  2. 21
      src/Squidex.Core/ContentValidator.cs
  3. 4
      src/Squidex.Core/FieldExtensions.cs
  4. 10
      src/Squidex.Core/Schemas/AssetsField.cs
  5. 9
      src/Squidex.Core/Schemas/FieldRegistry.cs
  6. 92
      src/Squidex.Core/Schemas/ReferencesField.cs
  7. 42
      src/Squidex.Core/Schemas/ReferencesFieldProperties.cs
  8. 15
      src/Squidex.Core/Schemas/ReferencesValue.cs
  9. 59
      src/Squidex.Core/Schemas/ValidationContext.cs
  10. 2
      src/Squidex.Core/Schemas/Validators/AllowedValuesValidator.cs
  11. 14
      src/Squidex.Core/Schemas/Validators/AssetsValidator.cs
  12. 2
      src/Squidex.Core/Schemas/Validators/IValidator.cs
  13. 2
      src/Squidex.Core/Schemas/Validators/PatternValidator.cs
  14. 2
      src/Squidex.Core/Schemas/Validators/RangeValidator.cs
  15. 57
      src/Squidex.Core/Schemas/Validators/ReferencesValidator.cs
  16. 4
      src/Squidex.Core/Schemas/Validators/RequiredStringValidator.cs
  17. 4
      src/Squidex.Core/Schemas/Validators/RequiredValidator.cs
  18. 2
      src/Squidex.Core/Schemas/Validators/StringLengthValidator.cs
  19. 7
      src/Squidex.Read.MongoDb/Assets/MongoAssetRepository.cs
  20. 12
      src/Squidex.Read.MongoDb/Contents/MongoContentRepository.cs
  21. 2
      src/Squidex.Read/Assets/Repositories/IAssetRepository.cs
  22. 2
      src/Squidex.Read/Contents/Repositories/IContentRepository.cs
  23. 21
      src/Squidex.Write/Contents/ContentCommandHandler.cs
  24. 2
      src/Squidex/Config/Domain/StoreMongoDbModule.cs
  25. 11
      src/Squidex/Controllers/Api/Schemas/Models/Converters/SchemaConverter.cs
  26. 1
      src/Squidex/Controllers/Api/Schemas/Models/FieldPropertiesDto.cs
  27. 29
      src/Squidex/Controllers/Api/Schemas/Models/ReferencesFieldPropertiesDto.cs
  28. 8
      tests/Squidex.Core.Tests/ContentEnrichmentTests.cs
  29. 32
      tests/Squidex.Core.Tests/ContentValidationTests.cs
  30. 5
      tests/Squidex.Core.Tests/Contents/ContentDataTests.cs
  31. 53
      tests/Squidex.Core.Tests/Schemas/AssetsFieldTests.cs
  32. 8
      tests/Squidex.Core.Tests/Schemas/BooleanFieldTests.cs
  33. 12
      tests/Squidex.Core.Tests/Schemas/DateTimeFieldTests.cs
  34. 3
      tests/Squidex.Core.Tests/Schemas/FieldRegistryTests.cs
  35. 10
      tests/Squidex.Core.Tests/Schemas/GeolocationFieldTests.cs
  36. 10
      tests/Squidex.Core.Tests/Schemas/Json/JsonSerializerTests.cs
  37. 4
      tests/Squidex.Core.Tests/Schemas/JsonFieldTests.cs
  38. 12
      tests/Squidex.Core.Tests/Schemas/NumberFieldTests.cs
  39. 60
      tests/Squidex.Core.Tests/Schemas/ReferencesFieldPropertiesTests.cs
  40. 208
      tests/Squidex.Core.Tests/Schemas/ReferencesFieldTests.cs
  41. 3
      tests/Squidex.Core.Tests/Schemas/SchemaTests.cs
  42. 14
      tests/Squidex.Core.Tests/Schemas/StringFieldTests.cs
  43. 23
      tests/Squidex.Core.Tests/Schemas/ValidationTestExtensions.cs
  44. 10
      tests/Squidex.Core.Tests/Schemas/Validators/AllowedValuesValidatorTests.cs
  45. 10
      tests/Squidex.Core.Tests/Schemas/Validators/PatternValidatorTests.cs
  46. 10
      tests/Squidex.Core.Tests/Schemas/Validators/RangeValidatorTests.cs
  47. 10
      tests/Squidex.Core.Tests/Schemas/Validators/RequiredStringValidatorTests.cs
  48. 8
      tests/Squidex.Core.Tests/Schemas/Validators/RequiredValidatorTests.cs
  49. 14
      tests/Squidex.Core.Tests/Schemas/Validators/StringLengthValidatorTests.cs
  50. 4
      tests/Squidex.Write.Tests/Contents/ContentCommandHandlerTests.cs
  51. 2
      tests/Squidex.Write.Tests/Schemas/SchemaCommandHandlerTests.cs
  52. 3
      tests/Squidex.Write.Tests/Schemas/SchemaDomainObjectTests.cs

8
src/Squidex.Core/ContentExtensions.cs

@ -25,9 +25,9 @@ namespace Squidex.Core
enricher.Enrich(data); enricher.Enrich(data);
} }
public static async Task ValidateAsync(this NamedContentData data, Schema schema, PartitionResolver partitionResolver, IList<ValidationError> errors) public static async Task ValidateAsync(this NamedContentData data, ValidationContext context, Schema schema, PartitionResolver partitionResolver, IList<ValidationError> errors)
{ {
var validator = new ContentValidator(schema, partitionResolver); var validator = new ContentValidator(schema, partitionResolver, context);
await validator.ValidateAsync(data); await validator.ValidateAsync(data);
@ -37,9 +37,9 @@ namespace Squidex.Core
} }
} }
public static async Task ValidatePartialAsync(this NamedContentData data, Schema schema, PartitionResolver partitionResolver, IList<ValidationError> errors) public static async Task ValidatePartialAsync(this NamedContentData data, ValidationContext context, Schema schema, PartitionResolver partitionResolver, IList<ValidationError> errors)
{ {
var validator = new ContentValidator(schema, partitionResolver); var validator = new ContentValidator(schema, partitionResolver, context);
await validator.ValidatePartialAsync(data); await validator.ValidatePartialAsync(data);

21
src/Squidex.Core/ContentValidator.cs

@ -21,6 +21,7 @@ namespace Squidex.Core
{ {
private readonly Schema schema; private readonly Schema schema;
private readonly PartitionResolver partitionResolver; private readonly PartitionResolver partitionResolver;
private readonly ValidationContext context;
private readonly List<ValidationError> errors = new List<ValidationError>(); private readonly List<ValidationError> errors = new List<ValidationError>();
public IReadOnlyList<ValidationError> Errors public IReadOnlyList<ValidationError> Errors
@ -28,13 +29,13 @@ namespace Squidex.Core
get { return errors; } get { return errors; }
} }
public ContentValidator(Schema schema, PartitionResolver partitionResolver) public ContentValidator(Schema schema, PartitionResolver partitionResolver, ValidationContext context)
{ {
Guard.NotNull(schema, nameof(schema)); Guard.NotNull(schema, nameof(schema));
Guard.NotNull(partitionResolver, nameof(partitionResolver)); Guard.NotNull(partitionResolver, nameof(partitionResolver));
this.schema = schema; this.schema = schema;
this.context = context;
this.partitionResolver = partitionResolver; this.partitionResolver = partitionResolver;
} }
@ -64,15 +65,13 @@ namespace Squidex.Core
foreach (var partitionValues in fieldData) foreach (var partitionValues in fieldData)
{ {
if (!partition.TryGetItem(partitionValues.Key, out var partitionItem)) if (partition.TryGetItem(partitionValues.Key, out var item))
{ {
errors.AddError($"<FIELD> has an unsupported {partitioning.Key} value '{partitionValues.Key}'", field); await field.ValidateAsync(partitionValues.Value, context.Optional(item.IsOptional), m => errors.AddError(m, field, item));
} }
else else
{ {
var item = partitionItem; errors.AddError($"<FIELD> has an unsupported {partitioning.Key} value '{partitionValues.Key}'", field);
await field.ValidateAsync(partitionValues.Value, item.IsOptional, m => errors.AddError(m, field, item));
} }
} }
} }
@ -115,11 +114,11 @@ namespace Squidex.Core
} }
} }
foreach (var partitionItem in partition) foreach (var item in partition)
{ {
var value = fieldData.GetOrCreate(partitionItem.Key, k => JValue.CreateNull()); var value = fieldData.GetOrCreate(item.Key, k => JValue.CreateNull());
await field.ValidateAsync(value, partitionItem.IsOptional, m => errors.AddError(m, field, partitionItem)); await field.ValidateAsync(value, context.Optional(item.IsOptional), m => errors.AddError(m, field, item));
} }
} }
} }

4
src/Squidex.Core/FieldExtensions.cs

@ -38,7 +38,7 @@ namespace Squidex.Core
errors.Add(new ValidationError(message.Replace("<FIELD>", displayName), fieldName)); errors.Add(new ValidationError(message.Replace("<FIELD>", displayName), fieldName));
} }
public static async Task ValidateAsync(this Field field, JToken value, bool isOptional, Action<string> addError) public static async Task ValidateAsync(this Field field, JToken value, ValidationContext context, Action<string> addError)
{ {
Guard.NotNull(value, nameof(value)); Guard.NotNull(value, nameof(value));
@ -48,7 +48,7 @@ namespace Squidex.Core
foreach (var validator in field.Validators) foreach (var validator in field.Validators)
{ {
await validator.ValidateAsync(typedValue, isOptional, addError); await validator.ValidateAsync(typedValue, context, addError);
} }
} }
catch catch

10
src/Squidex.Core/Schemas/AssetsField.cs

@ -19,22 +19,20 @@ namespace Squidex.Core.Schemas
public sealed class AssetsField : Field<AssetsFieldProperties>, IReferenceField public sealed class AssetsField : Field<AssetsFieldProperties>, IReferenceField
{ {
private static readonly Guid[] EmptyIds = new Guid[0]; private static readonly Guid[] EmptyIds = new Guid[0];
private readonly IAssetTester assetTester;
public AssetsField(long id, string name, Partitioning partitioning, IAssetTester assetTester) public AssetsField(long id, string name, Partitioning partitioning)
: this(id, name, partitioning, new AssetsFieldProperties(), assetTester) : this(id, name, partitioning, new AssetsFieldProperties())
{ {
} }
public AssetsField(long id, string name, Partitioning partitioning, AssetsFieldProperties properties, IAssetTester assetTester) public AssetsField(long id, string name, Partitioning partitioning, AssetsFieldProperties properties)
: base(id, name, partitioning, properties) : base(id, name, partitioning, properties)
{ {
this.assetTester = assetTester;
} }
protected override IEnumerable<IValidator> CreateValidators() protected override IEnumerable<IValidator> CreateValidators()
{ {
yield return new AssetsValidator(assetTester, Properties.IsRequired); yield return new AssetsValidator(Properties.IsRequired);
} }
public IEnumerable<Guid> GetReferencedIds(JToken value) public IEnumerable<Guid> GetReferencedIds(JToken value)

9
src/Squidex.Core/Schemas/FieldRegistry.cs

@ -41,10 +41,9 @@ namespace Squidex.Core.Schemas
} }
} }
public FieldRegistry(TypeNameRegistry typeNameRegistry, IAssetTester assetTester) public FieldRegistry(TypeNameRegistry typeNameRegistry)
{ {
Guard.NotNull(typeNameRegistry, nameof(typeNameRegistry)); Guard.NotNull(typeNameRegistry, nameof(typeNameRegistry));
Guard.NotNull(assetTester, nameof(assetTester));
this.typeNameRegistry = typeNameRegistry; this.typeNameRegistry = typeNameRegistry;
@ -70,7 +69,11 @@ namespace Squidex.Core.Schemas
Add<AssetsFieldProperties>( Add<AssetsFieldProperties>(
(id, name, partitioning, properties) => (id, name, partitioning, properties) =>
new AssetsField(id, name, partitioning, (AssetsFieldProperties)properties, assetTester)); new AssetsField(id, name, partitioning, (AssetsFieldProperties)properties));
Add<ReferencesFieldProperties>(
(id, name, partitioning, properties) =>
new ReferencesField(id, name, partitioning, (ReferencesFieldProperties)properties));
Add<GeolocationFieldProperties>( Add<GeolocationFieldProperties>(
(id, name, partitioning, properties) => (id, name, partitioning, properties) =>

92
src/Squidex.Core/Schemas/ReferencesField.cs

@ -0,0 +1,92 @@
// ==========================================================================
// ReferencesField.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.OData.Edm;
using Newtonsoft.Json.Linq;
using NJsonSchema;
using Squidex.Core.Schemas.Validators;
namespace Squidex.Core.Schemas
{
public sealed class ReferencesField : Field<ReferencesFieldProperties>, IReferenceField
{
private static readonly Guid[] EmptyIds = new Guid[0];
public ReferencesField(long id, string name, Partitioning partitioning)
: this(id, name, partitioning, new ReferencesFieldProperties())
{
}
public ReferencesField(long id, string name, Partitioning partitioning, ReferencesFieldProperties properties)
: base(id, name, partitioning, properties)
{
}
protected override IEnumerable<IValidator> CreateValidators()
{
if (Properties.SchemaId != Guid.Empty)
{
yield return new ReferencesValidator(Properties.IsRequired, Properties.SchemaId);
}
}
public IEnumerable<Guid> GetReferencedIds(JToken value)
{
Guid[] referenceIds;
try
{
referenceIds = value?.ToObject<Guid[]>() ?? EmptyIds;
}
catch
{
referenceIds = EmptyIds;
}
return referenceIds.Union(new [] { Properties.SchemaId });
}
public JToken RemoveDeletedReferences(JToken value, ISet<Guid> deletedReferencedIds)
{
if (value == null || value.Type == JTokenType.Null)
{
return null;
}
if (deletedReferencedIds.Contains(Properties.SchemaId))
{
return new JArray();
}
var oldReferenceIds = GetReferencedIds(value).TakeWhile(x => x != Properties.SchemaId).ToArray();
var newReferenceIds = oldReferenceIds.Where(x => !deletedReferencedIds.Contains(x)).ToList();
return newReferenceIds.Count != oldReferenceIds.Length ? JToken.FromObject(newReferenceIds) : value;
}
public override object ConvertValue(JToken value)
{
return new ReferencesValue(value.ToObject<Guid[]>());
}
protected override void PrepareJsonSchema(JsonProperty jsonProperty, Func<string, JsonSchema4, JsonSchema4> schemaResolver)
{
var itemSchema = schemaResolver("ReferenceItem", new JsonSchema4 { Type = JsonObjectType.String });
jsonProperty.Type = JsonObjectType.Array;
jsonProperty.Item = itemSchema;
}
protected override IEdmTypeReference CreateEdmType()
{
return null;
}
}
}

42
src/Squidex.Core/Schemas/ReferencesFieldProperties.cs

@ -0,0 +1,42 @@
// ==========================================================================
// ReferencesFieldProperties.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
using System;
using System.Collections.Generic;
using Newtonsoft.Json.Linq;
using Squidex.Infrastructure;
namespace Squidex.Core.Schemas
{
[TypeName("References")]
public sealed class ReferencesFieldProperties : FieldProperties
{
private Guid schemaId;
public Guid SchemaId
{
get { return schemaId; }
set
{
ThrowIfFrozen();
schemaId = value;
}
}
public override JToken GetDefaultValue()
{
return new JArray();
}
protected override IEnumerable<ValidationError> ValidateCore()
{
yield break;
}
}
}

15
src/Squidex.Core/Schemas/IAssetTester.cs → src/Squidex.Core/Schemas/ReferencesValue.cs

@ -1,5 +1,5 @@
// ========================================================================== // ==========================================================================
// IAssetTester.cs // ReferencesValue.cs
// Squidex Headless CMS // Squidex Headless CMS
// ========================================================================== // ==========================================================================
// Copyright (c) Squidex Group // Copyright (c) Squidex Group
@ -7,12 +7,19 @@
// ========================================================================== // ==========================================================================
using System; using System;
using System.Threading.Tasks; using System.Collections.Generic;
namespace Squidex.Core.Schemas namespace Squidex.Core.Schemas
{ {
public interface IAssetTester public sealed class ReferencesValue
{ {
Task<bool> IsValidAsync(Guid assetId); private readonly List<Guid> EmptyReferencedIds = new List<Guid>();
public IReadOnlyList<Guid> ContentIds { get; }
public ReferencesValue(IReadOnlyList<Guid> assetIds)
{
ContentIds = assetIds ?? EmptyReferencedIds;
}
} }
} }

59
src/Squidex.Core/Schemas/ValidationContext.cs

@ -0,0 +1,59 @@
// ==========================================================================
// ValidationContext.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
using System;
using System.Threading.Tasks;
using Squidex.Infrastructure;
namespace Squidex.Core.Schemas
{
public sealed class ValidationContext
{
private readonly Func<Guid, Guid, Task<bool>> checkContent;
private readonly Func<Guid, Task<bool>> checkAsset;
public bool IsOptional { get; }
public ValidationContext(
Func<Guid, Guid, Task<bool>> checkContent,
Func<Guid, Task<bool>> checkAsset)
: this(checkContent, checkAsset, false)
{
}
private ValidationContext(
Func<Guid, Guid, Task<bool>> checkContent,
Func<Guid, Task<bool>> checkAsset,
bool isOptional)
{
Guard.NotNull(checkAsset, nameof(checkAsset));
Guard.NotNull(checkContent, nameof(checkAsset));
this.checkContent = checkContent;
this.checkAsset = checkAsset;
IsOptional = isOptional;
}
public ValidationContext Optional(bool isOptional)
{
return isOptional == IsOptional ? this : new ValidationContext(checkContent, checkAsset, isOptional);
}
public async Task<bool> IsValidContentIdAsync(Guid schemaId, Guid contentId)
{
return contentId != Guid.Empty && schemaId != Guid.Empty && await checkContent(schemaId, contentId);
}
public async Task<bool> IsValidAssetIdAsync(Guid assetId)
{
return assetId != Guid.Empty && await checkAsset(assetId);
}
}
}

2
src/Squidex.Core/Schemas/Validators/AllowedValuesValidator.cs

@ -25,7 +25,7 @@ namespace Squidex.Core.Schemas.Validators
this.allowedValues = allowedValues; this.allowedValues = allowedValues;
} }
public Task ValidateAsync(object value, bool isOptional, Action<string> addError) public Task ValidateAsync(object value, ValidationContext context, Action<string> addError)
{ {
if (value == null) if (value == null)
{ {

14
src/Squidex.Core/Schemas/Validators/AssetsValidator.cs

@ -14,22 +14,20 @@ namespace Squidex.Core.Schemas.Validators
{ {
public sealed class AssetsValidator : IValidator public sealed class AssetsValidator : IValidator
{ {
private readonly IAssetTester assetTester;
private readonly bool isRequired; private readonly bool isRequired;
public AssetsValidator(IAssetTester assetTester, bool isRequired) public AssetsValidator(bool isRequired)
{ {
this.assetTester = assetTester;
this.isRequired = isRequired; this.isRequired = isRequired;
} }
public async Task ValidateAsync(object value, bool isOptional, Action<string> addError) public async Task ValidateAsync(object value, ValidationContext context, Action<string> addError)
{ {
var assets = value as AssetsValue; var assets = value as AssetsValue;
if (assets == null || assets.AssetIds.Count == 0) if (assets == null || assets.AssetIds.Count == 0)
{ {
if (isRequired && !isOptional) if (isRequired && !context.IsOptional)
{ {
addError("<FIELD> is required"); addError("<FIELD> is required");
} }
@ -37,7 +35,7 @@ namespace Squidex.Core.Schemas.Validators
return; return;
} }
var assetTasks = assets.AssetIds.Select(CheckAsset).ToArray(); var assetTasks = assets.AssetIds.Select(x => CheckAssetAsync(context, x)).ToArray();
await Task.WhenAll(assetTasks); await Task.WhenAll(assetTasks);
@ -47,9 +45,9 @@ namespace Squidex.Core.Schemas.Validators
} }
} }
private async Task<(Guid AssetId, bool IsFound)> CheckAsset(Guid id) private static async Task<(Guid AssetId, bool IsFound)> CheckAssetAsync(ValidationContext context, Guid id)
{ {
var isFound = await assetTester.IsValidAsync(id); var isFound = await context.IsValidAssetIdAsync(id);
return (id, isFound); return (id, isFound);
} }

2
src/Squidex.Core/Schemas/Validators/IValidator.cs

@ -13,6 +13,6 @@ namespace Squidex.Core.Schemas.Validators
{ {
public interface IValidator public interface IValidator
{ {
Task ValidateAsync(object value, bool isOptional, Action<string> addError); Task ValidateAsync(object value, ValidationContext context, Action<string> addError);
} }
} }

2
src/Squidex.Core/Schemas/Validators/PatternValidator.cs

@ -28,7 +28,7 @@ namespace Squidex.Core.Schemas.Validators
regex = new Regex("^" + pattern + "$"); regex = new Regex("^" + pattern + "$");
} }
public Task ValidateAsync(object value, bool isOptional, Action<string> addError) public Task ValidateAsync(object value, ValidationContext context, Action<string> addError)
{ {
if (value is string stringValue) if (value is string stringValue)
{ {

2
src/Squidex.Core/Schemas/Validators/RangeValidator.cs

@ -28,7 +28,7 @@ namespace Squidex.Core.Schemas.Validators
this.max = max; this.max = max;
} }
public Task ValidateAsync(object value, bool isOptional, Action<string> addError) public Task ValidateAsync(object value, ValidationContext context, Action<string> addError)
{ {
if (value == null) if (value == null)
{ {

57
src/Squidex.Core/Schemas/Validators/ReferencesValidator.cs

@ -0,0 +1,57 @@
// ==========================================================================
// ReferencesValidator.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
using System;
using System.Linq;
using System.Threading.Tasks;
namespace Squidex.Core.Schemas.Validators
{
public sealed class ReferencesValidator : IValidator
{
private readonly bool isRequired;
private readonly Guid schemaId;
public ReferencesValidator(bool isRequired, Guid schemaId)
{
this.isRequired = isRequired;
this.schemaId = schemaId;
}
public async Task ValidateAsync(object value, ValidationContext context, Action<string> addError)
{
var references = value as ReferencesValue;
if (references == null || references.ContentIds.Count == 0)
{
if (isRequired && !context.IsOptional)
{
addError("<FIELD> is required");
}
return;
}
var referenceTasks = references.ContentIds.Select(x => CheckReferenceAsync(context, x)).ToArray();
await Task.WhenAll(referenceTasks);
foreach (var notFoundId in referenceTasks.Where(x => !x.Result.IsFound).Select(x => x.Result.ReferenceId))
{
addError($"<FIELD> contains invalid reference '{notFoundId}'");
}
}
private async Task<(Guid ReferenceId, bool IsFound)> CheckReferenceAsync(ValidationContext context, Guid id)
{
var isFound = await context.IsValidContentIdAsync(schemaId, id);
return (id, isFound);
}
}
}

4
src/Squidex.Core/Schemas/Validators/RequiredStringValidator.cs

@ -21,9 +21,9 @@ namespace Squidex.Core.Schemas.Validators
this.validateEmptyStrings = validateEmptyStrings; this.validateEmptyStrings = validateEmptyStrings;
} }
public Task ValidateAsync(object value, bool isOptional, Action<string> addError) public Task ValidateAsync(object value, ValidationContext context, Action<string> addError)
{ {
if (isOptional || (value != null && !(value is string))) if (context.IsOptional || (value != null && !(value is string)))
{ {
return TaskHelper.Done; return TaskHelper.Done;
} }

4
src/Squidex.Core/Schemas/Validators/RequiredValidator.cs

@ -14,9 +14,9 @@ namespace Squidex.Core.Schemas.Validators
{ {
public class RequiredValidator : IValidator public class RequiredValidator : IValidator
{ {
public Task ValidateAsync(object value, bool isOptional, Action<string> addError) public Task ValidateAsync(object value, ValidationContext context, Action<string> addError)
{ {
if (value == null && !isOptional) if (value == null && !context.IsOptional)
{ {
addError("<FIELD> is required"); addError("<FIELD> is required");
} }

2
src/Squidex.Core/Schemas/Validators/StringLengthValidator.cs

@ -30,7 +30,7 @@ namespace Squidex.Core.Schemas.Validators
this.maxLength = maxLength; this.maxLength = maxLength;
} }
public Task ValidateAsync(object value, bool isOptional, Action<string> addError) public Task ValidateAsync(object value, ValidationContext context, Action<string> addError)
{ {
if (value is string stringValue && !string.IsNullOrEmpty(stringValue)) if (value is string stringValue && !string.IsNullOrEmpty(stringValue))
{ {

7
src/Squidex.Read.MongoDb/Assets/MongoAssetRepository.cs

@ -12,7 +12,6 @@ using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using MongoDB.Bson; using MongoDB.Bson;
using MongoDB.Driver; using MongoDB.Driver;
using Squidex.Core.Schemas;
using Squidex.Infrastructure.CQRS.Events; using Squidex.Infrastructure.CQRS.Events;
using Squidex.Infrastructure.MongoDb; using Squidex.Infrastructure.MongoDb;
using Squidex.Read.Assets; using Squidex.Read.Assets;
@ -20,7 +19,7 @@ using Squidex.Read.Assets.Repositories;
namespace Squidex.Read.MongoDb.Assets namespace Squidex.Read.MongoDb.Assets
{ {
public partial class MongoAssetRepository : MongoRepositoryBase<MongoAssetEntity>, IAssetRepository, IAssetTester, IEventConsumer public partial class MongoAssetRepository : MongoRepositoryBase<MongoAssetEntity>, IAssetRepository, IEventConsumer
{ {
public MongoAssetRepository(IMongoDatabase database) public MongoAssetRepository(IMongoDatabase database)
: base(database) : base(database)
@ -37,9 +36,9 @@ namespace Squidex.Read.MongoDb.Assets
return collection.Indexes.CreateOneAsync(IndexKeys.Ascending(x => x.AppId).Ascending(x => x.IsDeleted).Descending(x => x.LastModified).Ascending(x => x.FileName).Ascending(x => x.MimeType)); return collection.Indexes.CreateOneAsync(IndexKeys.Ascending(x => x.AppId).Ascending(x => x.IsDeleted).Descending(x => x.LastModified).Ascending(x => x.FileName).Ascending(x => x.MimeType));
} }
public async Task<bool> IsValidAsync(Guid assetId) public async Task<bool> ExistsAsync(Guid appId, Guid assetId)
{ {
return await Collection.Find(x => x.Id == assetId).CountAsync() == 1; return await Collection.Find(x => x.Id == assetId && x.AppId == appId).CountAsync() == 1;
} }
public async Task<IReadOnlyList<IAssetEntity>> QueryAsync(Guid appId, HashSet<string> mimeTypes = null, HashSet<Guid> ids = null, string query = null, int take = 10, int skip = 0) public async Task<IReadOnlyList<IAssetEntity>> QueryAsync(Guid appId, HashSet<string> mimeTypes = null, HashSet<Guid> ids = null, string query = null, int take = 10, int skip = 0)

12
src/Squidex.Read.MongoDb/Contents/MongoContentRepository.cs

@ -112,6 +112,18 @@ namespace Squidex.Read.MongoDb.Contents
return result; return result;
} }
public async Task<bool> ExistsAsync(Guid appId, Guid schemaId, Guid contentId)
{
var result = false;
await ForAppIdAsync(appId, async collection =>
{
result = await collection.Find(x => x.Id == contentId && x.SchemaId == schemaId).CountAsync() == 1;
});
return result;
}
public async Task<long> CountAsync(Guid schemaId, bool nonPublished, string odataQuery, IAppEntity appEntity) public async Task<long> CountAsync(Guid schemaId, bool nonPublished, string odataQuery, IAppEntity appEntity)
{ {
var result = 0L; var result = 0L;

2
src/Squidex.Read/Assets/Repositories/IAssetRepository.cs

@ -18,6 +18,8 @@ namespace Squidex.Read.Assets.Repositories
Task<long> CountAsync(Guid appId, HashSet<string> mimeTypes = null, HashSet<Guid> ids = null, string query = null); Task<long> CountAsync(Guid appId, HashSet<string> mimeTypes = null, HashSet<Guid> ids = null, string query = null);
Task<bool> ExistsAsync(Guid appId, Guid assetId);
Task<IAssetEntity> FindAssetAsync(Guid id); Task<IAssetEntity> FindAssetAsync(Guid id);
} }
} }

2
src/Squidex.Read/Contents/Repositories/IContentRepository.cs

@ -19,6 +19,8 @@ namespace Squidex.Read.Contents.Repositories
Task<long> CountAsync(Guid schemaId, bool nonPublished, string odataQuery, IAppEntity appEntity); Task<long> CountAsync(Guid schemaId, bool nonPublished, string odataQuery, IAppEntity appEntity);
Task<bool> ExistsAsync(Guid appId, Guid schemaId, Guid contentId);
Task<IContentEntity> FindContentAsync(Guid schemaId, Guid id, IAppEntity appEntity); Task<IContentEntity> FindContentAsync(Guid schemaId, Guid id, IAppEntity appEntity);
} }
} }

21
src/Squidex.Write/Contents/ContentCommandHandler.cs

@ -10,11 +10,14 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading.Tasks; using System.Threading.Tasks;
using Squidex.Core; using Squidex.Core;
using Squidex.Core.Schemas;
using Squidex.Infrastructure; using Squidex.Infrastructure;
using Squidex.Infrastructure.CQRS.Commands; using Squidex.Infrastructure.CQRS.Commands;
using Squidex.Infrastructure.Dispatching; using Squidex.Infrastructure.Dispatching;
using Squidex.Infrastructure.Tasks; using Squidex.Infrastructure.Tasks;
using Squidex.Read.Apps.Services; using Squidex.Read.Apps.Services;
using Squidex.Read.Assets.Repositories;
using Squidex.Read.Contents.Repositories;
using Squidex.Read.Schemas.Services; using Squidex.Read.Schemas.Services;
using Squidex.Write.Contents.Commands; using Squidex.Write.Contents.Commands;
@ -24,21 +27,29 @@ namespace Squidex.Write.Contents
{ {
private readonly IAggregateHandler handler; private readonly IAggregateHandler handler;
private readonly IAppProvider appProvider; private readonly IAppProvider appProvider;
private readonly IAssetRepository assetRepository;
private readonly IContentRepository contentRepository;
private readonly ISchemaProvider schemas; private readonly ISchemaProvider schemas;
public ContentCommandHandler( public ContentCommandHandler(
IAggregateHandler handler, IAggregateHandler handler,
IAppProvider appProvider, IAppProvider appProvider,
ISchemaProvider schemas) IAssetRepository assetRepository,
ISchemaProvider schemas,
IContentRepository contentRepository)
{ {
Guard.NotNull(handler, nameof(handler)); Guard.NotNull(handler, nameof(handler));
Guard.NotNull(schemas, nameof(schemas)); Guard.NotNull(schemas, nameof(schemas));
Guard.NotNull(handler, nameof(handler));
Guard.NotNull(appProvider, nameof(appProvider)); Guard.NotNull(appProvider, nameof(appProvider));
Guard.NotNull(assetRepository, nameof(assetRepository));
Guard.NotNull(contentRepository, nameof(contentRepository));
this.handler = handler; this.handler = handler;
this.schemas = schemas; this.schemas = schemas;
this.appProvider = appProvider; this.appProvider = appProvider;
this.assetRepository = assetRepository;
this.contentRepository = contentRepository;
} }
protected async Task On(CreateContent command, CommandContext context) protected async Task On(CreateContent command, CommandContext context)
@ -99,7 +110,11 @@ namespace Squidex.Write.Contents
var schemaObject = taskForSchema.Result.Schema; var schemaObject = taskForSchema.Result.Schema;
var schemaErrors = new List<ValidationError>(); var schemaErrors = new List<ValidationError>();
await command.Data.ValidateAsync(schemaObject, taskForApp.Result.PartitionResolver, schemaErrors); var appId = command.AppId.Id;
var validationContext = new ValidationContext((x, y) => contentRepository.ExistsAsync(appId, x, y), x => assetRepository.ExistsAsync(appId, x));
await command.Data.ValidateAsync(validationContext, schemaObject, taskForApp.Result.PartitionResolver, schemaErrors);
if (schemaErrors.Count > 0) if (schemaErrors.Count > 0)
{ {

2
src/Squidex/Config/Domain/StoreMongoDbModule.cs

@ -12,7 +12,6 @@ using IdentityServer4.Stores;
using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration;
using MongoDB.Driver; using MongoDB.Driver;
using Squidex.Core.Schemas;
using Squidex.Infrastructure; using Squidex.Infrastructure;
using Squidex.Infrastructure.CQRS.Events; using Squidex.Infrastructure.CQRS.Events;
using Squidex.Infrastructure.MongoDb; using Squidex.Infrastructure.MongoDb;
@ -139,7 +138,6 @@ namespace Squidex.Config.Domain
builder.RegisterType<MongoAssetRepository>() builder.RegisterType<MongoAssetRepository>()
.WithParameter(ResolvedParameter.ForNamed<IMongoDatabase>(MongoDatabaseRegistration)) .WithParameter(ResolvedParameter.ForNamed<IMongoDatabase>(MongoDatabaseRegistration))
.As<IAssetRepository>() .As<IAssetRepository>()
.As<IAssetTester>()
.As<IEventConsumer>() .As<IEventConsumer>()
.As<IExternalSystem>() .As<IExternalSystem>()
.AsSelf() .AsSelf()

11
src/Squidex/Controllers/Api/Schemas/Models/Converters/SchemaConverter.cs

@ -49,6 +49,10 @@ namespace Squidex.Controllers.Api.Schemas.Models.Converters
{ {
typeof(AssetsFieldProperties), typeof(AssetsFieldProperties),
p => Convert((AssetsFieldProperties)p) p => Convert((AssetsFieldProperties)p)
},
{
typeof(ReferencesFieldProperties),
p => Convert((ReferencesFieldProperties)p)
} }
}; };
@ -150,6 +154,13 @@ namespace Squidex.Controllers.Api.Schemas.Models.Converters
return result; return result;
} }
private static FieldPropertiesDto Convert(ReferencesFieldProperties source)
{
var result = SimpleMapper.Map(source, new ReferencesFieldPropertiesDto());
return result;
}
private static FieldPropertiesDto Convert(StringFieldProperties source) private static FieldPropertiesDto Convert(StringFieldProperties source)
{ {
var result = SimpleMapper.Map(source, new StringFieldPropertiesDto()); var result = SimpleMapper.Map(source, new StringFieldPropertiesDto());

1
src/Squidex/Controllers/Api/Schemas/Models/FieldPropertiesDto.cs

@ -21,6 +21,7 @@ namespace Squidex.Controllers.Api.Schemas.Models
[KnownType(typeof(GeolocationFieldPropertiesDto))] [KnownType(typeof(GeolocationFieldPropertiesDto))]
[KnownType(typeof(JsonFieldPropertiesDto))] [KnownType(typeof(JsonFieldPropertiesDto))]
[KnownType(typeof(NumberFieldPropertiesDto))] [KnownType(typeof(NumberFieldPropertiesDto))]
[KnownType(typeof(ReferencesFieldPropertiesDto))]
[KnownType(typeof(StringFieldPropertiesDto))] [KnownType(typeof(StringFieldPropertiesDto))]
public abstract class FieldPropertiesDto public abstract class FieldPropertiesDto
{ {

29
src/Squidex/Controllers/Api/Schemas/Models/ReferencesFieldPropertiesDto.cs

@ -0,0 +1,29 @@
// ==========================================================================
// ReferencesFieldPropertiesDto.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
using System;
using NJsonSchema.Annotations;
using Squidex.Core.Schemas;
using Squidex.Infrastructure.Reflection;
namespace Squidex.Controllers.Api.Schemas.Models
{
[JsonSchema("References")]
public sealed class ReferencesFieldPropertiesDto : FieldPropertiesDto
{
/// <summary>
/// The id of the referenced schema.
/// </summary>
public Guid SchemaId { get; set; }
public override FieldProperties ToProperties()
{
return SimpleMapper.Map(this, new ReferencesFieldProperties());
}
}
}

8
tests/Squidex.Core.Tests/ContentEnrichmentTests.cs

@ -6,7 +6,7 @@
// All rights reserved. // All rights reserved.
// ========================================================================== // ==========================================================================
using Moq; using System;
using NodaTime; using NodaTime;
using NodaTime.Text; using NodaTime.Text;
using Squidex.Core.Contents; using Squidex.Core.Contents;
@ -34,12 +34,14 @@ namespace Squidex.Core
.AddOrUpdateField(new NumberField(3, "my-number", Partitioning.Invariant, .AddOrUpdateField(new NumberField(3, "my-number", Partitioning.Invariant,
new NumberFieldProperties { DefaultValue = 123 })) new NumberFieldProperties { DefaultValue = 123 }))
.AddOrUpdateField(new AssetsField(4, "my-assets", Partitioning.Invariant, .AddOrUpdateField(new AssetsField(4, "my-assets", Partitioning.Invariant,
new AssetsFieldProperties(), new Mock<IAssetTester>().Object)) new AssetsFieldProperties()))
.AddOrUpdateField(new BooleanField(5, "my-boolean", Partitioning.Invariant, .AddOrUpdateField(new BooleanField(5, "my-boolean", Partitioning.Invariant,
new BooleanFieldProperties { DefaultValue = true })) new BooleanFieldProperties { DefaultValue = true }))
.AddOrUpdateField(new DateTimeField(6, "my-datetime", Partitioning.Invariant, .AddOrUpdateField(new DateTimeField(6, "my-datetime", Partitioning.Invariant,
new DateTimeFieldProperties { DefaultValue = now })) new DateTimeFieldProperties { DefaultValue = now }))
.AddOrUpdateField(new GeolocationField(7, "my-geolocation", Partitioning.Invariant, .AddOrUpdateField(new ReferencesField(7, "my-references", Partitioning.Invariant,
new ReferencesFieldProperties { SchemaId = Guid.NewGuid() }))
.AddOrUpdateField(new GeolocationField(8, "my-geolocation", Partitioning.Invariant,
new GeolocationFieldProperties())); new GeolocationFieldProperties()));
var data = var data =

32
tests/Squidex.Core.Tests/ContentValidationTests.cs

@ -12,6 +12,7 @@ using FluentAssertions;
using Squidex.Core.Contents; using Squidex.Core.Contents;
using Squidex.Core.Schemas; using Squidex.Core.Schemas;
using Squidex.Infrastructure; using Squidex.Infrastructure;
using Squidex.Infrastructure.Tasks;
using Xunit; using Xunit;
namespace Squidex.Core namespace Squidex.Core
@ -20,6 +21,7 @@ namespace Squidex.Core
{ {
private readonly LanguagesConfig languagesConfig = LanguagesConfig.Create(Language.DE, Language.EN); private readonly LanguagesConfig languagesConfig = LanguagesConfig.Create(Language.DE, Language.EN);
private readonly List<ValidationError> errors = new List<ValidationError>(); private readonly List<ValidationError> errors = new List<ValidationError>();
private readonly ValidationContext context = new ValidationContext((x, y) => TaskHelper.True, x => TaskHelper.True);
private Schema schema = Schema.Create("my-name", new SchemaProperties()); private Schema schema = Schema.Create("my-name", new SchemaProperties());
[Fact] [Fact]
@ -30,7 +32,7 @@ namespace Squidex.Core
.AddField("unknown", .AddField("unknown",
new ContentFieldData()); new ContentFieldData());
await data.ValidateAsync(schema, languagesConfig.ToResolver(), errors); await data.ValidateAsync(context, schema, languagesConfig.ToResolver(), errors);
errors.ShouldBeEquivalentTo( errors.ShouldBeEquivalentTo(
new List<ValidationError> new List<ValidationError>
@ -50,7 +52,7 @@ namespace Squidex.Core
new ContentFieldData() new ContentFieldData()
.SetValue(1000)); .SetValue(1000));
await data.ValidateAsync(schema, languagesConfig.ToResolver(), errors); await data.ValidateAsync(context, schema, languagesConfig.ToResolver(), errors);
errors.ShouldBeEquivalentTo( errors.ShouldBeEquivalentTo(
new List<ValidationError> new List<ValidationError>
@ -71,7 +73,7 @@ namespace Squidex.Core
.AddValue("es", 1) .AddValue("es", 1)
.AddValue("it", 1)); .AddValue("it", 1));
await data.ValidateAsync(schema, languagesConfig.ToResolver(), errors); await data.ValidateAsync(context, schema, languagesConfig.ToResolver(), errors);
errors.ShouldBeEquivalentTo( errors.ShouldBeEquivalentTo(
new List<ValidationError> new List<ValidationError>
@ -89,7 +91,7 @@ namespace Squidex.Core
var data = var data =
new NamedContentData(); new NamedContentData();
await data.ValidateAsync(schema, languagesConfig.ToResolver(), errors); await data.ValidateAsync(context, schema, languagesConfig.ToResolver(), errors);
errors.ShouldBeEquivalentTo( errors.ShouldBeEquivalentTo(
new List<ValidationError> new List<ValidationError>
@ -107,7 +109,7 @@ namespace Squidex.Core
var data = var data =
new NamedContentData(); new NamedContentData();
await data.ValidateAsync(schema, languagesConfig.ToResolver(), errors); await data.ValidateAsync(context, schema, languagesConfig.ToResolver(), errors);
errors.ShouldBeEquivalentTo( errors.ShouldBeEquivalentTo(
new List<ValidationError> new List<ValidationError>
@ -128,7 +130,7 @@ namespace Squidex.Core
.AddValue("de", 1) .AddValue("de", 1)
.AddValue("xx", 1)); .AddValue("xx", 1));
await data.ValidateAsync(schema, languagesConfig.ToResolver(), errors); await data.ValidateAsync(context, schema, languagesConfig.ToResolver(), errors);
errors.ShouldBeEquivalentTo( errors.ShouldBeEquivalentTo(
new List<ValidationError> new List<ValidationError>
@ -151,7 +153,7 @@ namespace Squidex.Core
new ContentFieldData() new ContentFieldData()
.AddValue("es", "value")); .AddValue("es", "value"));
await data.ValidateAsync(schema, optionalConfig.ToResolver(), errors); await data.ValidateAsync(context, schema, optionalConfig.ToResolver(), errors);
Assert.Equal(0, errors.Count); Assert.Equal(0, errors.Count);
} }
@ -168,7 +170,7 @@ namespace Squidex.Core
.AddValue("es", 1) .AddValue("es", 1)
.AddValue("it", 1)); .AddValue("it", 1));
await data.ValidateAsync(schema, languagesConfig.ToResolver(), errors); await data.ValidateAsync(context, schema, languagesConfig.ToResolver(), errors);
errors.ShouldBeEquivalentTo( errors.ShouldBeEquivalentTo(
new List<ValidationError> new List<ValidationError>
@ -186,7 +188,7 @@ namespace Squidex.Core
.AddField("unknown", .AddField("unknown",
new ContentFieldData()); new ContentFieldData());
await data.ValidatePartialAsync(schema, languagesConfig.ToResolver(), errors); await data.ValidatePartialAsync(context, schema, languagesConfig.ToResolver(), errors);
errors.ShouldBeEquivalentTo( errors.ShouldBeEquivalentTo(
new List<ValidationError> new List<ValidationError>
@ -206,7 +208,7 @@ namespace Squidex.Core
new ContentFieldData() new ContentFieldData()
.SetValue(1000)); .SetValue(1000));
await data.ValidatePartialAsync(schema, languagesConfig.ToResolver(), errors); await data.ValidatePartialAsync(context, schema, languagesConfig.ToResolver(), errors);
errors.ShouldBeEquivalentTo( errors.ShouldBeEquivalentTo(
new List<ValidationError> new List<ValidationError>
@ -227,7 +229,7 @@ namespace Squidex.Core
.AddValue("es", 1) .AddValue("es", 1)
.AddValue("it", 1)); .AddValue("it", 1));
await data.ValidatePartialAsync(schema, languagesConfig.ToResolver(), errors); await data.ValidatePartialAsync(context, schema, languagesConfig.ToResolver(), errors);
errors.ShouldBeEquivalentTo( errors.ShouldBeEquivalentTo(
new List<ValidationError> new List<ValidationError>
@ -245,7 +247,7 @@ namespace Squidex.Core
var data = var data =
new NamedContentData(); new NamedContentData();
await data.ValidatePartialAsync(schema, languagesConfig.ToResolver(), errors); await data.ValidatePartialAsync(context, schema, languagesConfig.ToResolver(), errors);
Assert.Equal(0, errors.Count); Assert.Equal(0, errors.Count);
} }
@ -258,7 +260,7 @@ namespace Squidex.Core
var data = var data =
new NamedContentData(); new NamedContentData();
await data.ValidatePartialAsync(schema, languagesConfig.ToResolver(), errors); await data.ValidatePartialAsync(context, schema, languagesConfig.ToResolver(), errors);
Assert.Equal(0, errors.Count); Assert.Equal(0, errors.Count);
} }
@ -275,7 +277,7 @@ namespace Squidex.Core
.AddValue("de", 1) .AddValue("de", 1)
.AddValue("xx", 1)); .AddValue("xx", 1));
await data.ValidatePartialAsync(schema, languagesConfig.ToResolver(), errors); await data.ValidatePartialAsync(context, schema, languagesConfig.ToResolver(), errors);
errors.ShouldBeEquivalentTo( errors.ShouldBeEquivalentTo(
new List<ValidationError> new List<ValidationError>
@ -296,7 +298,7 @@ namespace Squidex.Core
.AddValue("es", 1) .AddValue("es", 1)
.AddValue("it", 1)); .AddValue("it", 1));
await data.ValidatePartialAsync(schema, languagesConfig.ToResolver(), errors); await data.ValidatePartialAsync(context, schema, languagesConfig.ToResolver(), errors);
errors.ShouldBeEquivalentTo( errors.ShouldBeEquivalentTo(
new List<ValidationError> new List<ValidationError>

5
tests/Squidex.Core.Tests/Contents/ContentDataTests.cs

@ -9,7 +9,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using Moq;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
using Squidex.Core.Schemas; using Squidex.Core.Schemas;
using Squidex.Infrastructure; using Squidex.Infrastructure;
@ -24,8 +23,8 @@ namespace Squidex.Core.Contents
.AddOrUpdateField(new NumberField(1, "field1", Partitioning.Language)) .AddOrUpdateField(new NumberField(1, "field1", Partitioning.Language))
.AddOrUpdateField(new NumberField(2, "field2", Partitioning.Invariant)) .AddOrUpdateField(new NumberField(2, "field2", Partitioning.Invariant))
.AddOrUpdateField(new NumberField(3, "field3", Partitioning.Invariant).Hide()) .AddOrUpdateField(new NumberField(3, "field3", Partitioning.Invariant).Hide())
.AddOrUpdateField(new AssetsField(5, "assets1", Partitioning.Invariant, new Mock<IAssetTester>().Object)) .AddOrUpdateField(new AssetsField(5, "assets1", Partitioning.Invariant))
.AddOrUpdateField(new AssetsField(6, "assets2", Partitioning.Invariant, new Mock<IAssetTester>().Object)) .AddOrUpdateField(new AssetsField(6, "assets2", Partitioning.Invariant))
.AddOrUpdateField(new JsonField(4, "json", Partitioning.Language)); .AddOrUpdateField(new JsonField(4, "json", Partitioning.Language));
private readonly LanguagesConfig languagesConfig = LanguagesConfig.Create(Language.EN, Language.DE); private readonly LanguagesConfig languagesConfig = LanguagesConfig.Create(Language.EN, Language.DE);

53
tests/Squidex.Core.Tests/Schemas/AssetsFieldTests.cs

@ -11,7 +11,6 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using FluentAssertions; using FluentAssertions;
using Moq;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
using Squidex.Infrastructure.Tasks; using Squidex.Infrastructure.Tasks;
using Xunit; using Xunit;
@ -20,13 +19,13 @@ namespace Squidex.Core.Schemas
{ {
public class AssetsFieldTests public class AssetsFieldTests
{ {
private readonly Mock<IAssetTester> assetTester = new Mock<IAssetTester>();
private readonly List<string> errors = new List<string>(); private readonly List<string> errors = new List<string>();
private static readonly ValidationContext InvalidAssetContext = new ValidationContext((x, y) => TaskHelper.False, x => TaskHelper.False);
[Fact] [Fact]
public void Should_instantiate_field() public void Should_instantiate_field()
{ {
var sut = new AssetsField(1, "my-asset", Partitioning.Invariant, assetTester.Object); var sut = new AssetsField(1, "my-asset", Partitioning.Invariant);
Assert.Equal("my-asset", sut.Name); Assert.Equal("my-asset", sut.Name);
} }
@ -34,7 +33,7 @@ namespace Squidex.Core.Schemas
[Fact] [Fact]
public void Should_clone_object() public void Should_clone_object()
{ {
var sut = new AssetsField(1, "my-asset", Partitioning.Invariant, assetTester.Object); var sut = new AssetsField(1, "my-asset", Partitioning.Invariant);
Assert.NotEqual(sut, sut.Enable()); Assert.NotEqual(sut, sut.Enable());
} }
@ -44,11 +43,9 @@ namespace Squidex.Core.Schemas
{ {
var assetId = Guid.NewGuid(); var assetId = Guid.NewGuid();
assetTester.Setup(x => x.IsValidAsync(assetId)).Returns(TaskHelper.True); var sut = new AssetsField(1, "my-asset", Partitioning.Invariant);
var sut = new AssetsField(1, "my-asset", Partitioning.Invariant, assetTester.Object); await sut.ValidateAsync(CreateValue(assetId), errors);
await sut.ValidateAsync(CreateValue(assetId), false, errors);
Assert.Empty(errors); Assert.Empty(errors);
} }
@ -56,9 +53,9 @@ namespace Squidex.Core.Schemas
[Fact] [Fact]
public async Task Should_not_add_error_if_assets_are_null_and_valid() public async Task Should_not_add_error_if_assets_are_null_and_valid()
{ {
var sut = new AssetsField(1, "my-asset", Partitioning.Invariant, assetTester.Object); var sut = new AssetsField(1, "my-asset", Partitioning.Invariant);
await sut.ValidateAsync(CreateValue(null), false, errors); await sut.ValidateAsync(CreateValue(null), errors);
Assert.Empty(errors); Assert.Empty(errors);
} }
@ -66,9 +63,9 @@ namespace Squidex.Core.Schemas
[Fact] [Fact]
public async Task Should_add_errors_if_assets_are_required_and_null() public async Task Should_add_errors_if_assets_are_required_and_null()
{ {
var sut = new AssetsField(1, "my-asset", Partitioning.Invariant, new AssetsFieldProperties { IsRequired = true }, assetTester.Object); var sut = new AssetsField(1, "my-asset", Partitioning.Invariant, new AssetsFieldProperties { IsRequired = true });
await sut.ValidateAsync(CreateValue(null), false, errors); await sut.ValidateAsync(CreateValue(null), errors);
errors.ShouldBeEquivalentTo( errors.ShouldBeEquivalentTo(
new[] { "<FIELD> is required" }); new[] { "<FIELD> is required" });
@ -77,9 +74,9 @@ namespace Squidex.Core.Schemas
[Fact] [Fact]
public async Task Should_add_errors_if_assets_are_required_and_empty() public async Task Should_add_errors_if_assets_are_required_and_empty()
{ {
var sut = new AssetsField(1, "my-asset", Partitioning.Invariant, new AssetsFieldProperties { IsRequired = true }, assetTester.Object); var sut = new AssetsField(1, "my-asset", Partitioning.Invariant, new AssetsFieldProperties { IsRequired = true });
await sut.ValidateAsync(CreateValue(), false, errors); await sut.ValidateAsync(CreateValue(), errors);
errors.ShouldBeEquivalentTo( errors.ShouldBeEquivalentTo(
new[] { "<FIELD> is required" }); new[] { "<FIELD> is required" });
@ -88,9 +85,9 @@ namespace Squidex.Core.Schemas
[Fact] [Fact]
public async Task Should_add_errors_if_value_is_not_valid() public async Task Should_add_errors_if_value_is_not_valid()
{ {
var sut = new AssetsField(1, "my-asset", Partitioning.Invariant, assetTester.Object); var sut = new AssetsField(1, "my-asset", Partitioning.Invariant);
await sut.ValidateAsync("invalid", false, errors); await sut.ValidateAsync("invalid", errors);
errors.ShouldBeEquivalentTo( errors.ShouldBeEquivalentTo(
new[] { "<FIELD> is not a valid value" }); new[] { "<FIELD> is not a valid value" });
@ -100,12 +97,10 @@ namespace Squidex.Core.Schemas
public async Task Should_add_errors_if_asset_are_not_valid() public async Task Should_add_errors_if_asset_are_not_valid()
{ {
var assetId = Guid.NewGuid(); var assetId = Guid.NewGuid();
var sut = new AssetsField(1, "my-asset", Partitioning.Invariant);
assetTester.Setup(x => x.IsValidAsync(assetId)).Returns(TaskHelper.False); await sut.ValidateAsync(CreateValue(assetId), errors, InvalidAssetContext);
var sut = new AssetsField(1, "my-asset", Partitioning.Invariant, assetTester.Object);
await sut.ValidateAsync(CreateValue(assetId), false, errors);
errors.ShouldBeEquivalentTo( errors.ShouldBeEquivalentTo(
new[] { $"<FIELD> contains invalid asset '{assetId}'" }); new[] { $"<FIELD> contains invalid asset '{assetId}'" });
@ -117,7 +112,7 @@ namespace Squidex.Core.Schemas
var id1 = Guid.NewGuid(); var id1 = Guid.NewGuid();
var id2 = Guid.NewGuid(); var id2 = Guid.NewGuid();
var sut = new AssetsField(1, "my-asset", Partitioning.Invariant, assetTester.Object); var sut = new AssetsField(1, "my-asset", Partitioning.Invariant);
var result = sut.GetReferencedIds(CreateValue(id1, id2)).ToArray(); var result = sut.GetReferencedIds(CreateValue(id1, id2)).ToArray();
@ -127,7 +122,7 @@ namespace Squidex.Core.Schemas
[Fact] [Fact]
public void Should_empty_list_for_referenced_ids_when_null() public void Should_empty_list_for_referenced_ids_when_null()
{ {
var sut = new AssetsField(1, "my-asset", Partitioning.Invariant, assetTester.Object); var sut = new AssetsField(1, "my-asset", Partitioning.Invariant);
var result = sut.GetReferencedIds(null).ToArray(); var result = sut.GetReferencedIds(null).ToArray();
@ -137,7 +132,7 @@ namespace Squidex.Core.Schemas
[Fact] [Fact]
public void Should_empty_list_for_referenced_ids_when_other_type() public void Should_empty_list_for_referenced_ids_when_other_type()
{ {
var sut = new AssetsField(1, "my-asset", Partitioning.Invariant, assetTester.Object); var sut = new AssetsField(1, "my-asset", Partitioning.Invariant);
var result = sut.GetReferencedIds("invalid").ToArray(); var result = sut.GetReferencedIds("invalid").ToArray();
@ -147,7 +142,7 @@ namespace Squidex.Core.Schemas
[Fact] [Fact]
public void Should_return_null_when_removing_references_from_null_array() public void Should_return_null_when_removing_references_from_null_array()
{ {
var sut = new AssetsField(1, "my-asset", Partitioning.Invariant, assetTester.Object); var sut = new AssetsField(1, "my-asset", Partitioning.Invariant);
var result = sut.RemoveDeletedReferences(null, null); var result = sut.RemoveDeletedReferences(null, null);
@ -157,7 +152,7 @@ namespace Squidex.Core.Schemas
[Fact] [Fact]
public void Should_return_null_when_removing_references_from_null_json_array() public void Should_return_null_when_removing_references_from_null_json_array()
{ {
var sut = new AssetsField(1, "my-asset", Partitioning.Invariant, assetTester.Object); var sut = new AssetsField(1, "my-asset", Partitioning.Invariant);
var result = sut.RemoveDeletedReferences(JValue.CreateNull(), null); var result = sut.RemoveDeletedReferences(JValue.CreateNull(), null);
@ -170,7 +165,7 @@ namespace Squidex.Core.Schemas
var id1 = Guid.NewGuid(); var id1 = Guid.NewGuid();
var id2 = Guid.NewGuid(); var id2 = Guid.NewGuid();
var sut = new AssetsField(1, "my-asset", Partitioning.Invariant, assetTester.Object); var sut = new AssetsField(1, "my-asset", Partitioning.Invariant);
var result = sut.RemoveDeletedReferences(CreateValue(id1, id2), new HashSet<Guid>(new[] { id2 })); var result = sut.RemoveDeletedReferences(CreateValue(id1, id2), new HashSet<Guid>(new[] { id2 }));
@ -183,7 +178,7 @@ namespace Squidex.Core.Schemas
var id1 = Guid.NewGuid(); var id1 = Guid.NewGuid();
var id2 = Guid.NewGuid(); var id2 = Guid.NewGuid();
var sut = new AssetsField(1, "my-asset", Partitioning.Invariant, assetTester.Object); var sut = new AssetsField(1, "my-asset", Partitioning.Invariant);
var token = CreateValue(id1, id2); var token = CreateValue(id1, id2);
var result = sut.RemoveDeletedReferences(token, new HashSet<Guid>(new[] { Guid.NewGuid() })); var result = sut.RemoveDeletedReferences(token, new HashSet<Guid>(new[] { Guid.NewGuid() }));
@ -193,7 +188,7 @@ namespace Squidex.Core.Schemas
private static JToken CreateValue(params Guid[] ids) private static JToken CreateValue(params Guid[] ids)
{ {
return ids == null ? JValue.CreateNull() : (JToken)new JArray(ids); return ids == null ? JValue.CreateNull() : (JToken)new JArray(ids.OfType<object>().ToArray());
} }
} }
} }

8
tests/Squidex.Core.Tests/Schemas/BooleanFieldTests.cs

@ -39,7 +39,7 @@ namespace Squidex.Core.Schemas
{ {
var sut = new BooleanField(1, "my-bolean", Partitioning.Invariant); var sut = new BooleanField(1, "my-bolean", Partitioning.Invariant);
await sut.ValidateAsync(CreateValue(null), false, errors); await sut.ValidateAsync(CreateValue(null), errors);
Assert.Empty(errors); Assert.Empty(errors);
} }
@ -49,7 +49,7 @@ namespace Squidex.Core.Schemas
{ {
var sut = new BooleanField(1, "my-bolean", Partitioning.Invariant); var sut = new BooleanField(1, "my-bolean", Partitioning.Invariant);
await sut.ValidateAsync(CreateValue(true), false, errors); await sut.ValidateAsync(CreateValue(true), errors);
Assert.Empty(errors); Assert.Empty(errors);
} }
@ -59,7 +59,7 @@ namespace Squidex.Core.Schemas
{ {
var sut = new BooleanField(1, "my-bolean", Partitioning.Invariant, new BooleanFieldProperties { IsRequired = true }); var sut = new BooleanField(1, "my-bolean", Partitioning.Invariant, new BooleanFieldProperties { IsRequired = true });
await sut.ValidateAsync(CreateValue(null), false, errors); await sut.ValidateAsync(CreateValue(null), errors);
errors.ShouldBeEquivalentTo( errors.ShouldBeEquivalentTo(
new[] { "<FIELD> is required" }); new[] { "<FIELD> is required" });
@ -70,7 +70,7 @@ namespace Squidex.Core.Schemas
{ {
var sut = new BooleanField(1, "my-bolean", Partitioning.Invariant); var sut = new BooleanField(1, "my-bolean", Partitioning.Invariant);
await sut.ValidateAsync(CreateValue("Invalid"), false, errors); await sut.ValidateAsync(CreateValue("Invalid"), errors);
errors.ShouldBeEquivalentTo( errors.ShouldBeEquivalentTo(
new[] { "<FIELD> is not a valid value" }); new[] { "<FIELD> is not a valid value" });

12
tests/Squidex.Core.Tests/Schemas/DateTimeFieldTests.cs

@ -41,7 +41,7 @@ namespace Squidex.Core.Schemas
{ {
var sut = new DateTimeField(1, "my-datetime", Partitioning.Invariant); var sut = new DateTimeField(1, "my-datetime", Partitioning.Invariant);
await sut.ValidateAsync(CreateValue(null), false, errors); await sut.ValidateAsync(CreateValue(null), errors);
Assert.Empty(errors); Assert.Empty(errors);
} }
@ -51,7 +51,7 @@ namespace Squidex.Core.Schemas
{ {
var sut = new DateTimeField(1, "my-datetime", Partitioning.Invariant, new DateTimeFieldProperties { IsRequired = true }); var sut = new DateTimeField(1, "my-datetime", Partitioning.Invariant, new DateTimeFieldProperties { IsRequired = true });
await sut.ValidateAsync(CreateValue(null), false, errors); await sut.ValidateAsync(CreateValue(null), errors);
errors.ShouldBeEquivalentTo( errors.ShouldBeEquivalentTo(
new[] { "<FIELD> is required" }); new[] { "<FIELD> is required" });
@ -62,7 +62,7 @@ namespace Squidex.Core.Schemas
{ {
var sut = new DateTimeField(1, "my-datetime", Partitioning.Invariant, new DateTimeFieldProperties { MinValue = FutureDays(10) }); var sut = new DateTimeField(1, "my-datetime", Partitioning.Invariant, new DateTimeFieldProperties { MinValue = FutureDays(10) });
await sut.ValidateAsync(CreateValue(FutureDays(0)), false, errors); await sut.ValidateAsync(CreateValue(FutureDays(0)), errors);
errors.ShouldBeEquivalentTo( errors.ShouldBeEquivalentTo(
new[] { $"<FIELD> must be greater than '{FutureDays(10)}'" }); new[] { $"<FIELD> must be greater than '{FutureDays(10)}'" });
@ -73,7 +73,7 @@ namespace Squidex.Core.Schemas
{ {
var sut = new DateTimeField(1, "my-datetime", Partitioning.Invariant, new DateTimeFieldProperties { MaxValue = FutureDays(10) }); var sut = new DateTimeField(1, "my-datetime", Partitioning.Invariant, new DateTimeFieldProperties { MaxValue = FutureDays(10) });
await sut.ValidateAsync(CreateValue(FutureDays(20)), false, errors); await sut.ValidateAsync(CreateValue(FutureDays(20)), errors);
errors.ShouldBeEquivalentTo( errors.ShouldBeEquivalentTo(
new[] { $"<FIELD> must be less than '{FutureDays(10)}'" }); new[] { $"<FIELD> must be less than '{FutureDays(10)}'" });
@ -84,7 +84,7 @@ namespace Squidex.Core.Schemas
{ {
var sut = new DateTimeField(1, "my-datetime", Partitioning.Invariant); var sut = new DateTimeField(1, "my-datetime", Partitioning.Invariant);
await sut.ValidateAsync(CreateValue("Invalid"), false, errors); await sut.ValidateAsync(CreateValue("Invalid"), errors);
errors.ShouldBeEquivalentTo( errors.ShouldBeEquivalentTo(
new[] { "<FIELD> is not a valid value" }); new[] { "<FIELD> is not a valid value" });
@ -95,7 +95,7 @@ namespace Squidex.Core.Schemas
{ {
var sut = new DateTimeField(1, "my-datetime", Partitioning.Invariant); var sut = new DateTimeField(1, "my-datetime", Partitioning.Invariant);
await sut.ValidateAsync(CreateValue(123), false, errors); await sut.ValidateAsync(CreateValue(123), errors);
errors.ShouldBeEquivalentTo( errors.ShouldBeEquivalentTo(
new[] { "<FIELD> is not a valid value" }); new[] { "<FIELD> is not a valid value" });

3
tests/Squidex.Core.Tests/Schemas/FieldRegistryTests.cs

@ -8,7 +8,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using Moq;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
using Squidex.Infrastructure; using Squidex.Infrastructure;
using Xunit; using Xunit;
@ -17,7 +16,7 @@ namespace Squidex.Core.Schemas
{ {
public class FieldRegistryTests public class FieldRegistryTests
{ {
private readonly FieldRegistry sut = new FieldRegistry(new TypeNameRegistry(), new Mock<IAssetTester>().Object); private readonly FieldRegistry sut = new FieldRegistry(new TypeNameRegistry());
private sealed class InvalidProperties : FieldProperties private sealed class InvalidProperties : FieldProperties
{ {

10
tests/Squidex.Core.Tests/Schemas/GeolocationFieldTests.cs

@ -39,7 +39,7 @@ namespace Squidex.Core.Schemas
{ {
var sut = new GeolocationField(1, "my-geolocation", Partitioning.Invariant); var sut = new GeolocationField(1, "my-geolocation", Partitioning.Invariant);
await sut.ValidateAsync(CreateValue(JValue.CreateNull()), false, errors); await sut.ValidateAsync(CreateValue(JValue.CreateNull()), errors);
Assert.Empty(errors); Assert.Empty(errors);
} }
@ -53,7 +53,7 @@ namespace Squidex.Core.Schemas
new JProperty("latitude", 0), new JProperty("latitude", 0),
new JProperty("longitude", 0)); new JProperty("longitude", 0));
await sut.ValidateAsync(CreateValue(geolocation), false, errors); await sut.ValidateAsync(CreateValue(geolocation), errors);
Assert.Empty(errors); Assert.Empty(errors);
} }
@ -67,7 +67,7 @@ namespace Squidex.Core.Schemas
new JProperty("latitude", 200), new JProperty("latitude", 200),
new JProperty("longitude", 0)); new JProperty("longitude", 0));
await sut.ValidateAsync(CreateValue(geolocation), false, errors); await sut.ValidateAsync(CreateValue(geolocation), errors);
errors.ShouldBeEquivalentTo( errors.ShouldBeEquivalentTo(
new[] { "<FIELD> is not a valid value" }); new[] { "<FIELD> is not a valid value" });
@ -83,7 +83,7 @@ namespace Squidex.Core.Schemas
new JProperty("latitude", 0), new JProperty("latitude", 0),
new JProperty("longitude", 0)); new JProperty("longitude", 0));
await sut.ValidateAsync(CreateValue(geolocation), false, errors); await sut.ValidateAsync(CreateValue(geolocation), errors);
errors.ShouldBeEquivalentTo( errors.ShouldBeEquivalentTo(
new[] { "<FIELD> is not a valid value" }); new[] { "<FIELD> is not a valid value" });
@ -94,7 +94,7 @@ namespace Squidex.Core.Schemas
{ {
var sut = new GeolocationField(1, "my-geolocation", Partitioning.Invariant, new GeolocationFieldProperties { IsRequired = true }); var sut = new GeolocationField(1, "my-geolocation", Partitioning.Invariant, new GeolocationFieldProperties { IsRequired = true });
await sut.ValidateAsync(CreateValue(JValue.CreateNull()), false, errors); await sut.ValidateAsync(CreateValue(JValue.CreateNull()), errors);
errors.ShouldBeEquivalentTo( errors.ShouldBeEquivalentTo(
new[] { "<FIELD> is required" }); new[] { "<FIELD> is required" });

10
tests/Squidex.Core.Tests/Schemas/Json/JsonSerializerTests.cs

@ -6,9 +6,9 @@
// All rights reserved. // All rights reserved.
// ========================================================================== // ==========================================================================
using System;
using System.Collections.Immutable; using System.Collections.Immutable;
using FluentAssertions; using FluentAssertions;
using Moq;
using Newtonsoft.Json; using Newtonsoft.Json;
using Squidex.Infrastructure; using Squidex.Infrastructure;
using Squidex.Infrastructure.Json; using Squidex.Infrastructure.Json;
@ -27,7 +27,7 @@ namespace Squidex.Core.Schemas.Json
serializerSettings.TypeNameHandling = TypeNameHandling.Auto; serializerSettings.TypeNameHandling = TypeNameHandling.Auto;
serializerSettings.SerializationBinder = new TypeNameSerializationBinder(typeNameRegistry); serializerSettings.SerializationBinder = new TypeNameSerializationBinder(typeNameRegistry);
sut = new SchemaJsonSerializer(new FieldRegistry(typeNameRegistry, new Mock<IAssetTester>().Object), serializerSettings); sut = new SchemaJsonSerializer(new FieldRegistry(typeNameRegistry), serializerSettings);
} }
[Fact] [Fact]
@ -38,7 +38,7 @@ namespace Squidex.Core.Schemas.Json
.AddOrUpdateField(new JsonField(1, "my-json", Partitioning.Invariant, .AddOrUpdateField(new JsonField(1, "my-json", Partitioning.Invariant,
new JsonFieldProperties())) new JsonFieldProperties()))
.AddOrUpdateField(new AssetsField(2, "my-assets", Partitioning.Invariant, .AddOrUpdateField(new AssetsField(2, "my-assets", Partitioning.Invariant,
new AssetsFieldProperties(), new Mock<IAssetTester>().Object)) new AssetsFieldProperties()))
.AddOrUpdateField(new StringField(3, "my-string1", Partitioning.Language, .AddOrUpdateField(new StringField(3, "my-string1", Partitioning.Language,
new StringFieldProperties { Label = "My String1", IsRequired = true, AllowedValues = ImmutableList.Create("a", "b") })) new StringFieldProperties { Label = "My String1", IsRequired = true, AllowedValues = ImmutableList.Create("a", "b") }))
.AddOrUpdateField(new StringField(4, "my-string2", Partitioning.Invariant, .AddOrUpdateField(new StringField(4, "my-string2", Partitioning.Invariant,
@ -51,7 +51,9 @@ namespace Squidex.Core.Schemas.Json
new DateTimeFieldProperties { Editor = DateTimeFieldEditor.DateTime })) new DateTimeFieldProperties { Editor = DateTimeFieldEditor.DateTime }))
.AddOrUpdateField(new DateTimeField(8, "my-date", Partitioning.Invariant, .AddOrUpdateField(new DateTimeField(8, "my-date", Partitioning.Invariant,
new DateTimeFieldProperties { Editor = DateTimeFieldEditor.Date })) new DateTimeFieldProperties { Editor = DateTimeFieldEditor.Date }))
.AddOrUpdateField(new GeolocationField(9, "my-geolocation", Partitioning.Invariant, .AddOrUpdateField(new ReferencesField(9, "my-references", Partitioning.Invariant,
new ReferencesFieldProperties { SchemaId = Guid.NewGuid() }))
.AddOrUpdateField(new GeolocationField(10, "my-geolocation", Partitioning.Invariant,
new GeolocationFieldProperties())) new GeolocationFieldProperties()))
.Publish(); .Publish();

4
tests/Squidex.Core.Tests/Schemas/JsonFieldTests.cs

@ -39,7 +39,7 @@ namespace Squidex.Core.Schemas
{ {
var sut = new JsonField(1, "my-json", Partitioning.Invariant); var sut = new JsonField(1, "my-json", Partitioning.Invariant);
await sut.ValidateAsync(CreateValue(new JValue(1)), false, errors); await sut.ValidateAsync(CreateValue(new JValue(1)), errors);
Assert.Empty(errors); Assert.Empty(errors);
} }
@ -49,7 +49,7 @@ namespace Squidex.Core.Schemas
{ {
var sut = new JsonField(1, "my-json", Partitioning.Invariant, new JsonFieldProperties { IsRequired = true }); var sut = new JsonField(1, "my-json", Partitioning.Invariant, new JsonFieldProperties { IsRequired = true });
await sut.ValidateAsync(CreateValue(JValue.CreateNull()), false, errors); await sut.ValidateAsync(CreateValue(JValue.CreateNull()), errors);
errors.ShouldBeEquivalentTo( errors.ShouldBeEquivalentTo(
new[] { "<FIELD> is required" }); new[] { "<FIELD> is required" });

12
tests/Squidex.Core.Tests/Schemas/NumberFieldTests.cs

@ -40,7 +40,7 @@ namespace Squidex.Core.Schemas
{ {
var sut = new NumberField(1, "my-number", Partitioning.Invariant); var sut = new NumberField(1, "my-number", Partitioning.Invariant);
await sut.ValidateAsync(CreateValue(null), false, errors); await sut.ValidateAsync(CreateValue(null), errors);
Assert.Empty(errors); Assert.Empty(errors);
} }
@ -50,7 +50,7 @@ namespace Squidex.Core.Schemas
{ {
var sut = new NumberField(1, "my-number", Partitioning.Invariant, new NumberFieldProperties { IsRequired = true }); var sut = new NumberField(1, "my-number", Partitioning.Invariant, new NumberFieldProperties { IsRequired = true });
await sut.ValidateAsync(CreateValue(null), false, errors); await sut.ValidateAsync(CreateValue(null), errors);
errors.ShouldBeEquivalentTo( errors.ShouldBeEquivalentTo(
new[] { "<FIELD> is required" }); new[] { "<FIELD> is required" });
@ -61,7 +61,7 @@ namespace Squidex.Core.Schemas
{ {
var sut = new NumberField(1, "my-number", Partitioning.Invariant, new NumberFieldProperties { MinValue = 10 }); var sut = new NumberField(1, "my-number", Partitioning.Invariant, new NumberFieldProperties { MinValue = 10 });
await sut.ValidateAsync(CreateValue(5), false, errors); await sut.ValidateAsync(CreateValue(5), errors);
errors.ShouldBeEquivalentTo( errors.ShouldBeEquivalentTo(
new[] { "<FIELD> must be greater than '10'" }); new[] { "<FIELD> must be greater than '10'" });
@ -72,7 +72,7 @@ namespace Squidex.Core.Schemas
{ {
var sut = new NumberField(1, "my-number", Partitioning.Invariant, new NumberFieldProperties { MaxValue = 10 }); var sut = new NumberField(1, "my-number", Partitioning.Invariant, new NumberFieldProperties { MaxValue = 10 });
await sut.ValidateAsync(CreateValue(20), false, errors); await sut.ValidateAsync(CreateValue(20), errors);
errors.ShouldBeEquivalentTo( errors.ShouldBeEquivalentTo(
new[] { "<FIELD> must be less than '10'" }); new[] { "<FIELD> must be less than '10'" });
@ -83,7 +83,7 @@ namespace Squidex.Core.Schemas
{ {
var sut = new NumberField(1, "my-number", Partitioning.Invariant, new NumberFieldProperties { AllowedValues = ImmutableList.Create(10d) }); var sut = new NumberField(1, "my-number", Partitioning.Invariant, new NumberFieldProperties { AllowedValues = ImmutableList.Create(10d) });
await sut.ValidateAsync(CreateValue(20), false, errors); await sut.ValidateAsync(CreateValue(20), errors);
errors.ShouldBeEquivalentTo( errors.ShouldBeEquivalentTo(
new[] { "<FIELD> is not an allowed value" }); new[] { "<FIELD> is not an allowed value" });
@ -94,7 +94,7 @@ namespace Squidex.Core.Schemas
{ {
var sut = new NumberField(1, "my-number", Partitioning.Invariant); var sut = new NumberField(1, "my-number", Partitioning.Invariant);
await sut.ValidateAsync(CreateValue("Invalid"), false, errors); await sut.ValidateAsync(CreateValue("Invalid"), errors);
errors.ShouldBeEquivalentTo( errors.ShouldBeEquivalentTo(
new[] { "<FIELD> is not a valid value" }); new[] { "<FIELD> is not a valid value" });

60
tests/Squidex.Core.Tests/Schemas/ReferencesFieldPropertiesTests.cs

@ -0,0 +1,60 @@
// ==========================================================================
// ReferenceFieldPropertiesTests.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
using System;
using System.Linq;
using System.Reflection;
using Xunit;
namespace Squidex.Core.Schemas
{
public class ReferencesFieldPropertiesTests
{
[Fact]
public void Should_set_or_freeze_sut()
{
var sut = new ReferencesFieldProperties();
foreach (var property in sut.GetType().GetRuntimeProperties().Where(x => x.Name != "IsFrozen"))
{
var value =
property.PropertyType.GetTypeInfo().IsValueType ?
Activator.CreateInstance(property.PropertyType) :
null;
property.SetValue(sut, value);
var result = property.GetValue(sut);
Assert.Equal(value, result);
}
sut.Freeze();
foreach (var property in sut.GetType().GetRuntimeProperties().Where(x => x.Name != "IsFrozen"))
{
var value =
property.PropertyType.GetTypeInfo().IsValueType ?
Activator.CreateInstance(property.PropertyType) :
null;
Assert.Throws<InvalidOperationException>(() =>
{
try
{
property.SetValue(sut, value);
}
catch (Exception ex)
{
throw ex.InnerException;
}
});
}
}
}
}

208
tests/Squidex.Core.Tests/Schemas/ReferencesFieldTests.cs

@ -0,0 +1,208 @@
// ==========================================================================
// ReferenceFieldTests.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using FluentAssertions;
using Newtonsoft.Json.Linq;
using Squidex.Infrastructure.Tasks;
using Xunit;
namespace Squidex.Core.Schemas
{
public class ReferencesFieldTests
{
private readonly List<string> errors = new List<string>();
private readonly Guid schemaId = Guid.NewGuid();
private static readonly ValidationContext InvalidSchemaContext = new ValidationContext((x, y) => TaskHelper.False, x => TaskHelper.False);
[Fact]
public void Should_instantiate_field()
{
var sut = new ReferencesField(1, "my-refs", Partitioning.Invariant);
Assert.Equal("my-refs", sut.Name);
}
[Fact]
public void Should_clone_object()
{
var sut = new ReferencesField(1, "my-refs", Partitioning.Invariant);
Assert.NotEqual(sut, sut.Enable());
}
[Fact]
public async Task Should_not_add_error_if_references_are_valid()
{
var referenceId = Guid.NewGuid();
var sut = new ReferencesField(1, "my-refs", Partitioning.Invariant);
await sut.ValidateAsync(CreateValue(referenceId), errors, InvalidSchemaContext);
Assert.Empty(errors);
}
[Fact]
public async Task Should_not_add_error_if_references_are_null_and_valid()
{
var sut = new ReferencesField(1, "my-refs", Partitioning.Invariant);
await sut.ValidateAsync(CreateValue(null), errors);
Assert.Empty(errors);
}
[Fact]
public async Task Should_add_errors_if_references_are_required_and_null()
{
var sut = new ReferencesField(1, "my-refs", Partitioning.Invariant, new ReferencesFieldProperties { SchemaId = schemaId, IsRequired = true });
await sut.ValidateAsync(CreateValue(null), errors);
errors.ShouldBeEquivalentTo(
new[] { "<FIELD> is required" });
}
[Fact]
public async Task Should_add_errors_if_references_are_required_and_empty()
{
var sut = new ReferencesField(1, "my-refs", Partitioning.Invariant, new ReferencesFieldProperties { SchemaId = schemaId, IsRequired = true });
await sut.ValidateAsync(CreateValue(), errors);
errors.ShouldBeEquivalentTo(
new[] { "<FIELD> is required" });
}
[Fact]
public async Task Should_add_errors_if_value_is_not_valid()
{
var sut = new ReferencesField(1, "my-refs", Partitioning.Invariant);
await sut.ValidateAsync("invalid", errors);
errors.ShouldBeEquivalentTo(
new[] { "<FIELD> is not a valid value" });
}
[Fact]
public async Task Should_add_errors_if_reference_are_not_valid()
{
var referenceId = Guid.NewGuid();
var sut = new ReferencesField(1, "my-refs", Partitioning.Invariant, new ReferencesFieldProperties { SchemaId = schemaId });
await sut.ValidateAsync(CreateValue(referenceId), errors, InvalidSchemaContext);
errors.ShouldBeEquivalentTo(
new[] { $"<FIELD> contains invalid reference '{referenceId}'" });
}
[Fact]
public void Should_return_ids()
{
var id1 = Guid.NewGuid();
var id2 = Guid.NewGuid();
var sut = new ReferencesField(1, "my-refs", Partitioning.Invariant, new ReferencesFieldProperties { SchemaId = schemaId });
var result = sut.GetReferencedIds(CreateValue(id1, id2)).ToArray();
Assert.Equal(new[] { id1, id2, schemaId }, result);
}
[Fact]
public void Should_return_list_with_schema_idempty_list_for_referenced_ids_when_null()
{
var sut = new ReferencesField(1, "my-refs", Partitioning.Invariant, new ReferencesFieldProperties { SchemaId = schemaId });
var result = sut.GetReferencedIds(null).ToArray();
Assert.Equal(new[] { schemaId }, result);
}
[Fact]
public void Should_return_list_with_schema_id_for_referenced_ids_when_other_type()
{
var sut = new ReferencesField(1, "my-refs", Partitioning.Invariant, new ReferencesFieldProperties { SchemaId = schemaId });
var result = sut.GetReferencedIds("invalid").ToArray();
Assert.Equal(new[] { schemaId }, result);
}
[Fact]
public void Should_return_null_when_removing_references_from_null_array()
{
var sut = new ReferencesField(1, "my-refs", Partitioning.Invariant);
var result = sut.RemoveDeletedReferences(null, null);
Assert.Null(result);
}
[Fact]
public void Should_return_null_when_removing_references_from_null_json_array()
{
var sut = new ReferencesField(1, "my-refs", Partitioning.Invariant);
var result = sut.RemoveDeletedReferences(JValue.CreateNull(), null);
Assert.Null(result);
}
[Fact]
public void Should_remove_deleted_references()
{
var id1 = Guid.NewGuid();
var id2 = Guid.NewGuid();
var sut = new ReferencesField(1, "my-refs", Partitioning.Invariant);
var result = sut.RemoveDeletedReferences(CreateValue(id1, id2), new HashSet<Guid>(new[] { id2 }));
Assert.Equal(CreateValue(id1), result);
}
[Fact]
public void Should_remove_all_references_when_schema_is_removed()
{
var id1 = Guid.NewGuid();
var id2 = Guid.NewGuid();
var sut = new ReferencesField(1, "my-refs", Partitioning.Invariant, new ReferencesFieldProperties { SchemaId = schemaId });
var result = sut.RemoveDeletedReferences(CreateValue(id1, id2), new HashSet<Guid>(new[] { schemaId }));
Assert.Equal(CreateValue(), result);
}
[Fact]
public void Should_return_same_token_when_removing_references_and_nothing_to_remove()
{
var id1 = Guid.NewGuid();
var id2 = Guid.NewGuid();
var sut = new ReferencesField(1, "my-refs", Partitioning.Invariant);
var token = CreateValue(id1, id2);
var result = sut.RemoveDeletedReferences(token, new HashSet<Guid>(new[] { Guid.NewGuid() }));
Assert.Same(token, result);
}
private static JToken CreateValue(params Guid[] ids)
{
return ids == null ? JValue.CreateNull() : (JToken)new JArray(ids.OfType<object>().ToArray());
}
}
}

3
tests/Squidex.Core.Tests/Schemas/SchemaTests.cs

@ -10,7 +10,6 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.Immutable; using System.Collections.Immutable;
using System.Linq; using System.Linq;
using Moq;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
using NJsonSchema; using NJsonSchema;
using Squidex.Infrastructure; using Squidex.Infrastructure;
@ -319,7 +318,7 @@ namespace Squidex.Core.Schemas
.AddOrUpdateField(new JsonField(1, "my-json", Partitioning.Invariant, .AddOrUpdateField(new JsonField(1, "my-json", Partitioning.Invariant,
new JsonFieldProperties())) new JsonFieldProperties()))
.AddOrUpdateField(new AssetsField(2, "my-assets", Partitioning.Invariant, .AddOrUpdateField(new AssetsField(2, "my-assets", Partitioning.Invariant,
new AssetsFieldProperties(), new Mock<IAssetTester>().Object)) new AssetsFieldProperties()))
.AddOrUpdateField(new StringField(3, "my-string1", Partitioning.Language, .AddOrUpdateField(new StringField(3, "my-string1", Partitioning.Language,
new StringFieldProperties { Label = "My String1", IsRequired = true, AllowedValues = ImmutableList.Create("a", "b") })) new StringFieldProperties { Label = "My String1", IsRequired = true, AllowedValues = ImmutableList.Create("a", "b") }))
.AddOrUpdateField(new StringField(4, "my-string2", Partitioning.Invariant, .AddOrUpdateField(new StringField(4, "my-string2", Partitioning.Invariant,

14
tests/Squidex.Core.Tests/Schemas/StringFieldTests.cs

@ -40,7 +40,7 @@ namespace Squidex.Core.Schemas
{ {
var sut = new StringField(1, "my-string", Partitioning.Invariant, new StringFieldProperties { Label = "<FIELD>" }); var sut = new StringField(1, "my-string", Partitioning.Invariant, new StringFieldProperties { Label = "<FIELD>" });
await sut.ValidateAsync(CreateValue(null), false, errors); await sut.ValidateAsync(CreateValue(null), errors);
Assert.Empty(errors); Assert.Empty(errors);
} }
@ -50,7 +50,7 @@ namespace Squidex.Core.Schemas
{ {
var sut = new StringField(1, "my-string", Partitioning.Invariant, new StringFieldProperties { IsRequired = true }); var sut = new StringField(1, "my-string", Partitioning.Invariant, new StringFieldProperties { IsRequired = true });
await sut.ValidateAsync(CreateValue(null), false, errors); await sut.ValidateAsync(CreateValue(null), errors);
errors.ShouldBeEquivalentTo( errors.ShouldBeEquivalentTo(
new[] { "<FIELD> is required" }); new[] { "<FIELD> is required" });
@ -61,7 +61,7 @@ namespace Squidex.Core.Schemas
{ {
var sut = new StringField(1, "my-string", Partitioning.Invariant, new StringFieldProperties { MinLength = 10 }); var sut = new StringField(1, "my-string", Partitioning.Invariant, new StringFieldProperties { MinLength = 10 });
await sut.ValidateAsync(CreateValue("123"), false, errors); await sut.ValidateAsync(CreateValue("123"), errors);
errors.ShouldBeEquivalentTo( errors.ShouldBeEquivalentTo(
new[] { "<FIELD> must have more than '10' characters" }); new[] { "<FIELD> must have more than '10' characters" });
@ -72,7 +72,7 @@ namespace Squidex.Core.Schemas
{ {
var sut = new StringField(1, "my-string", Partitioning.Invariant, new StringFieldProperties { MaxLength = 5 }); var sut = new StringField(1, "my-string", Partitioning.Invariant, new StringFieldProperties { MaxLength = 5 });
await sut.ValidateAsync(CreateValue("12345678"), false, errors); await sut.ValidateAsync(CreateValue("12345678"), errors);
errors.ShouldBeEquivalentTo( errors.ShouldBeEquivalentTo(
new[] { "<FIELD> must have less than '5' characters" }); new[] { "<FIELD> must have less than '5' characters" });
@ -83,7 +83,7 @@ namespace Squidex.Core.Schemas
{ {
var sut = new StringField(1, "my-string", Partitioning.Invariant, new StringFieldProperties { AllowedValues = ImmutableList.Create("Foo") }); var sut = new StringField(1, "my-string", Partitioning.Invariant, new StringFieldProperties { AllowedValues = ImmutableList.Create("Foo") });
await sut.ValidateAsync(CreateValue("Bar"), false, errors); await sut.ValidateAsync(CreateValue("Bar"), errors);
errors.ShouldBeEquivalentTo( errors.ShouldBeEquivalentTo(
new[] { "<FIELD> is not an allowed value" }); new[] { "<FIELD> is not an allowed value" });
@ -94,7 +94,7 @@ namespace Squidex.Core.Schemas
{ {
var sut = new StringField(1, "my-string", Partitioning.Invariant, new StringFieldProperties { Pattern = "[0-9]{3}" }); var sut = new StringField(1, "my-string", Partitioning.Invariant, new StringFieldProperties { Pattern = "[0-9]{3}" });
await sut.ValidateAsync(CreateValue("abc"), false, errors); await sut.ValidateAsync(CreateValue("abc"), errors);
errors.ShouldBeEquivalentTo( errors.ShouldBeEquivalentTo(
new[] { "<FIELD> is not valid" }); new[] { "<FIELD> is not valid" });
@ -105,7 +105,7 @@ namespace Squidex.Core.Schemas
{ {
var sut = new StringField(1, "my-string", Partitioning.Invariant, new StringFieldProperties { Pattern = "[0-9]{3}", PatternMessage = "Custom Error Message" }); var sut = new StringField(1, "my-string", Partitioning.Invariant, new StringFieldProperties { Pattern = "[0-9]{3}", PatternMessage = "Custom Error Message" });
await sut.ValidateAsync(CreateValue("abc"), false, errors); await sut.ValidateAsync(CreateValue("abc"), errors);
errors.ShouldBeEquivalentTo( errors.ShouldBeEquivalentTo(
new[] { "Custom Error Message" }); new[] { "Custom Error Message" });

23
tests/Squidex.Core.Tests/Schemas/ValidationTestExtensions.cs

@ -9,14 +9,33 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading.Tasks; using System.Threading.Tasks;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
using Squidex.Core.Schemas.Validators;
using Squidex.Infrastructure.Tasks;
namespace Squidex.Core.Schemas namespace Squidex.Core.Schemas
{ {
public static class ValidationTestExtensions public static class ValidationTestExtensions
{ {
public static Task ValidateAsync(this Field field, JToken value, bool isOptional, IList<string> errors) private static readonly ValidationContext EverythingValidContext = new ValidationContext((x, y) => TaskHelper.True, x => TaskHelper.True);
public static Task ValidateAsync(this IValidator validator, object value, IList<string> errors, ValidationContext context = null)
{
return validator.ValidateAsync(value, context ?? EverythingValidContext, errors.Add);
}
public static Task ValidateOptionalAsync(this IValidator validator, object value, IList<string> errors, ValidationContext context = null)
{
return validator.ValidateAsync(value, (context ?? EverythingValidContext).Optional(true), errors.Add);
}
public static Task ValidateAsync(this Field field, JToken value, IList<string> errors, ValidationContext context = null)
{
return field.ValidateAsync(value, context ?? EverythingValidContext, errors.Add);
}
public static Task ValidateOptionalAsync(this Field field, JToken value, IList<string> errors, ValidationContext context = null)
{ {
return field.ValidateAsync(value, isOptional, errors.Add); return field.ValidateAsync(value, (context ?? EverythingValidContext).Optional(true), errors.Add);
} }
} }
} }

10
tests/Squidex.Core.Tests/Schemas/Validators/AllowedValuesValidatorTests.cs

@ -18,21 +18,21 @@ namespace Squidex.Core.Schemas.Validators
private readonly List<string> errors = new List<string>(); private readonly List<string> errors = new List<string>();
[Fact] [Fact]
public async Task Should_not_error_if_value_null() public async Task Should_not_add_error_if_value_null()
{ {
var sut = new AllowedValuesValidator<int>(100, 200); var sut = new AllowedValuesValidator<int>(100, 200);
await sut.ValidateAsync(null, false, errors.Add); await sut.ValidateAsync(null, errors);
Assert.Equal(0, errors.Count); Assert.Equal(0, errors.Count);
} }
[Fact] [Fact]
public async Task Should_not_error_if_value_is_allowed() public async Task Should_not_add_error_if_value_is_allowed()
{ {
var sut = new AllowedValuesValidator<int>(100, 200); var sut = new AllowedValuesValidator<int>(100, 200);
await sut.ValidateAsync(100, false, errors.Add); await sut.ValidateAsync(100, errors);
Assert.Equal(0, errors.Count); Assert.Equal(0, errors.Count);
} }
@ -42,7 +42,7 @@ namespace Squidex.Core.Schemas.Validators
{ {
var sut = new AllowedValuesValidator<int>(100, 200); var sut = new AllowedValuesValidator<int>(100, 200);
await sut.ValidateAsync(50, false, errors.Add); await sut.ValidateAsync(50, errors);
errors.ShouldBeEquivalentTo( errors.ShouldBeEquivalentTo(
new[] { "<FIELD> is not an allowed value" }); new[] { "<FIELD> is not an allowed value" });

10
tests/Squidex.Core.Tests/Schemas/Validators/PatternValidatorTests.cs

@ -22,7 +22,7 @@ namespace Squidex.Core.Schemas.Validators
{ {
var sut = new PatternValidator("[a-z]{3}:[0-9]{2}"); var sut = new PatternValidator("[a-z]{3}:[0-9]{2}");
await sut.ValidateAsync("abc:12", false, errors.Add); await sut.ValidateAsync("abc:12", errors);
Assert.Equal(0, errors.Count); Assert.Equal(0, errors.Count);
} }
@ -32,7 +32,7 @@ namespace Squidex.Core.Schemas.Validators
{ {
var sut = new PatternValidator("[a-z]{3}:[0-9]{2}"); var sut = new PatternValidator("[a-z]{3}:[0-9]{2}");
await sut.ValidateAsync(null, false, errors.Add); await sut.ValidateAsync(null, errors);
Assert.Equal(0, errors.Count); Assert.Equal(0, errors.Count);
} }
@ -42,7 +42,7 @@ namespace Squidex.Core.Schemas.Validators
{ {
var sut = new PatternValidator("[a-z]{3}:[0-9]{2}"); var sut = new PatternValidator("[a-z]{3}:[0-9]{2}");
await sut.ValidateAsync("", false, errors.Add); await sut.ValidateAsync(string.Empty, errors);
Assert.Equal(0, errors.Count); Assert.Equal(0, errors.Count);
} }
@ -52,7 +52,7 @@ namespace Squidex.Core.Schemas.Validators
{ {
var sut = new PatternValidator("[a-z]{3}:[0-9]{2}"); var sut = new PatternValidator("[a-z]{3}:[0-9]{2}");
await sut.ValidateAsync("foo", false, errors.Add); await sut.ValidateAsync("foo", errors);
errors.ShouldBeEquivalentTo( errors.ShouldBeEquivalentTo(
new[] { "<FIELD> is not valid" }); new[] { "<FIELD> is not valid" });
@ -63,7 +63,7 @@ namespace Squidex.Core.Schemas.Validators
{ {
var sut = new PatternValidator("[a-z]{3}:[0-9]{2}", "Custom Error Message"); var sut = new PatternValidator("[a-z]{3}:[0-9]{2}", "Custom Error Message");
await sut.ValidateAsync("foo", false, errors.Add); await sut.ValidateAsync("foo", errors);
errors.ShouldBeEquivalentTo( errors.ShouldBeEquivalentTo(
new[] { "Custom Error Message" }); new[] { "Custom Error Message" });

10
tests/Squidex.Core.Tests/Schemas/Validators/RangeValidatorTests.cs

@ -19,11 +19,11 @@ namespace Squidex.Core.Schemas.Validators
private readonly List<string> errors = new List<string>(); private readonly List<string> errors = new List<string>();
[Fact] [Fact]
public async Task Should_not_error_if_value_is_null() public async Task Should_not_add_error_if_value_is_null()
{ {
var sut = new RangeValidator<int>(100, 200); var sut = new RangeValidator<int>(100, 200);
await sut.ValidateAsync(null, false, errors.Add); await sut.ValidateAsync(null, errors);
Assert.Equal(0, errors.Count); Assert.Equal(0, errors.Count);
} }
@ -37,7 +37,7 @@ namespace Squidex.Core.Schemas.Validators
{ {
var sut = new RangeValidator<int>(min, max); var sut = new RangeValidator<int>(min, max);
await sut.ValidateAsync(1500, false, errors.Add); await sut.ValidateAsync(1500, errors);
Assert.Equal(0, errors.Count); Assert.Equal(0, errors.Count);
} }
@ -55,7 +55,7 @@ namespace Squidex.Core.Schemas.Validators
{ {
var sut = new RangeValidator<int>(2000, null); var sut = new RangeValidator<int>(2000, null);
await sut.ValidateAsync(1500, false, errors.Add); await sut.ValidateAsync(1500, errors);
errors.ShouldBeEquivalentTo( errors.ShouldBeEquivalentTo(
new[] { "<FIELD> must be greater than '2000'" }); new[] { "<FIELD> must be greater than '2000'" });
@ -66,7 +66,7 @@ namespace Squidex.Core.Schemas.Validators
{ {
var sut = new RangeValidator<int>(null, 1000); var sut = new RangeValidator<int>(null, 1000);
await sut.ValidateAsync(1500, false, errors.Add); await sut.ValidateAsync(1500, errors);
errors.ShouldBeEquivalentTo( errors.ShouldBeEquivalentTo(
new[] { "<FIELD> must be less than '1000'" }); new[] { "<FIELD> must be less than '1000'" });

10
tests/Squidex.Core.Tests/Schemas/Validators/RequiredStringValidatorTests.cs

@ -26,7 +26,7 @@ namespace Squidex.Core.Schemas.Validators
{ {
var sut = new RequiredStringValidator(); var sut = new RequiredStringValidator();
await sut.ValidateAsync(value, false, errors.Add); await sut.ValidateAsync(value, errors);
Assert.Equal(0, errors.Count); Assert.Equal(0, errors.Count);
} }
@ -36,7 +36,7 @@ namespace Squidex.Core.Schemas.Validators
{ {
var sut = new RequiredStringValidator(); var sut = new RequiredStringValidator();
await sut.ValidateAsync(string.Empty, true, errors.Add); await sut.ValidateOptionalAsync(string.Empty, errors);
Assert.Equal(0, errors.Count); Assert.Equal(0, errors.Count);
} }
@ -46,7 +46,7 @@ namespace Squidex.Core.Schemas.Validators
{ {
var sut = new RequiredStringValidator(); var sut = new RequiredStringValidator();
await sut.ValidateAsync(true, false, errors.Add); await sut.ValidateAsync(true, errors);
Assert.Equal(0, errors.Count); Assert.Equal(0, errors.Count);
} }
@ -56,7 +56,7 @@ namespace Squidex.Core.Schemas.Validators
{ {
var sut = new RequiredStringValidator(true); var sut = new RequiredStringValidator(true);
await sut.ValidateAsync(string.Empty, false, errors.Add); await sut.ValidateAsync(string.Empty, errors);
errors.ShouldBeEquivalentTo( errors.ShouldBeEquivalentTo(
new[] { "<FIELD> is required" }); new[] { "<FIELD> is required" });
@ -67,7 +67,7 @@ namespace Squidex.Core.Schemas.Validators
{ {
var sut = new RequiredStringValidator(); var sut = new RequiredStringValidator();
await sut.ValidateAsync(null, false, errors.Add); await sut.ValidateAsync(null, errors);
errors.ShouldBeEquivalentTo( errors.ShouldBeEquivalentTo(
new[] { "<FIELD> is required" }); new[] { "<FIELD> is required" });

8
tests/Squidex.Core.Tests/Schemas/Validators/RequiredValidatorTests.cs

@ -22,7 +22,7 @@ namespace Squidex.Core.Schemas.Validators
{ {
var sut = new RequiredValidator(); var sut = new RequiredValidator();
await sut.ValidateAsync(true, false, errors.Add); await sut.ValidateAsync(true, errors);
Assert.Equal(0, errors.Count); Assert.Equal(0, errors.Count);
} }
@ -32,7 +32,7 @@ namespace Squidex.Core.Schemas.Validators
{ {
var sut = new RequiredValidator(); var sut = new RequiredValidator();
await sut.ValidateAsync(string.Empty, false, errors.Add); await sut.ValidateAsync(string.Empty, errors);
Assert.Equal(0, errors.Count); Assert.Equal(0, errors.Count);
} }
@ -42,7 +42,7 @@ namespace Squidex.Core.Schemas.Validators
{ {
var sut = new RequiredValidator(); var sut = new RequiredValidator();
await sut.ValidateAsync(null, true, errors.Add); await sut.ValidateOptionalAsync(null, errors);
Assert.Equal(0, errors.Count); Assert.Equal(0, errors.Count);
} }
@ -52,7 +52,7 @@ namespace Squidex.Core.Schemas.Validators
{ {
var sut = new RequiredValidator(); var sut = new RequiredValidator();
await sut.ValidateAsync(null, false, errors.Add); await sut.ValidateAsync(null, errors);
errors.ShouldBeEquivalentTo( errors.ShouldBeEquivalentTo(
new[] { "<FIELD> is required" }); new[] { "<FIELD> is required" });

14
tests/Squidex.Core.Tests/Schemas/Validators/StringLengthValidatorTests.cs

@ -20,21 +20,21 @@ namespace Squidex.Core.Schemas.Validators
private readonly List<string> errors = new List<string>(); private readonly List<string> errors = new List<string>();
[Fact] [Fact]
public async Task Should_not_error_if_value_is_null() public async Task Should_not_add_error_if_value_is_null()
{ {
var sut = new StringLengthValidator(100, 200); var sut = new StringLengthValidator(100, 200);
await sut.ValidateAsync(null, false, errors.Add); await sut.ValidateAsync(null, errors);
Assert.Equal(0, errors.Count); Assert.Equal(0, errors.Count);
} }
[Fact] [Fact]
public async Task Should_not_error_if_value_is_empty() public async Task Should_not_add_error_if_value_is_empty()
{ {
var sut = new StringLengthValidator(100, 200); var sut = new StringLengthValidator(100, 200);
await sut.ValidateAsync(string.Empty, false, errors.Add); await sut.ValidateAsync(string.Empty, errors);
Assert.Equal(0, errors.Count); Assert.Equal(0, errors.Count);
} }
@ -48,7 +48,7 @@ namespace Squidex.Core.Schemas.Validators
{ {
var sut = new StringLengthValidator(min, max); var sut = new StringLengthValidator(min, max);
await sut.ValidateAsync(CreateString(1500), false, errors.Add); await sut.ValidateAsync(CreateString(1500), errors);
Assert.Equal(0, errors.Count); Assert.Equal(0, errors.Count);
} }
@ -66,7 +66,7 @@ namespace Squidex.Core.Schemas.Validators
{ {
var sut = new StringLengthValidator(2000, null); var sut = new StringLengthValidator(2000, null);
await sut.ValidateAsync(CreateString(1500), false, errors.Add); await sut.ValidateAsync(CreateString(1500), errors);
errors.ShouldBeEquivalentTo( errors.ShouldBeEquivalentTo(
new[] { "<FIELD> must have more than '2000' characters" }); new[] { "<FIELD> must have more than '2000' characters" });
@ -77,7 +77,7 @@ namespace Squidex.Core.Schemas.Validators
{ {
var sut = new StringLengthValidator(null, 1000); var sut = new StringLengthValidator(null, 1000);
await sut.ValidateAsync(CreateString(1500), false, errors.Add); await sut.ValidateAsync(CreateString(1500), errors);
errors.ShouldBeEquivalentTo( errors.ShouldBeEquivalentTo(
new[] { "<FIELD> must have less than '1000' characters" }); new[] { "<FIELD> must have less than '1000' characters" });

4
tests/Squidex.Write.Tests/Contents/ContentCommandHandlerTests.cs

@ -16,6 +16,8 @@ using Squidex.Infrastructure;
using Squidex.Infrastructure.CQRS.Commands; using Squidex.Infrastructure.CQRS.Commands;
using Squidex.Read.Apps; using Squidex.Read.Apps;
using Squidex.Read.Apps.Services; using Squidex.Read.Apps.Services;
using Squidex.Read.Assets.Repositories;
using Squidex.Read.Contents.Repositories;
using Squidex.Read.Schemas; using Squidex.Read.Schemas;
using Squidex.Read.Schemas.Services; using Squidex.Read.Schemas.Services;
using Squidex.Write.Contents.Commands; using Squidex.Write.Contents.Commands;
@ -47,7 +49,7 @@ namespace Squidex.Write.Contents
content = new ContentDomainObject(contentId, -1); content = new ContentDomainObject(contentId, -1);
sut = new ContentCommandHandler(Handler, appProvider.Object, schemaProvider.Object); sut = new ContentCommandHandler(Handler, appProvider.Object, new Mock<IAssetRepository>().Object, schemaProvider.Object, new Mock<IContentRepository>().Object);
appEntity.Setup(x => x.LanguagesConfig).Returns(languagesConfig); appEntity.Setup(x => x.LanguagesConfig).Returns(languagesConfig);
appEntity.Setup(x => x.PartitionResolver).Returns(languagesConfig.ToResolver()); appEntity.Setup(x => x.PartitionResolver).Returns(languagesConfig.ToResolver());

2
tests/Squidex.Write.Tests/Schemas/SchemaCommandHandlerTests.cs

@ -28,7 +28,7 @@ namespace Squidex.Write.Schemas
private readonly Mock<ISchemaProvider> schemaProvider = new Mock<ISchemaProvider>(); private readonly Mock<ISchemaProvider> schemaProvider = new Mock<ISchemaProvider>();
private readonly SchemaCommandHandler sut; private readonly SchemaCommandHandler sut;
private readonly SchemaDomainObject schema; private readonly SchemaDomainObject schema;
private readonly FieldRegistry registry = new FieldRegistry(new TypeNameRegistry(), new Mock<IAssetTester>().Object); private readonly FieldRegistry registry = new FieldRegistry(new TypeNameRegistry());
private readonly string fieldName = "age"; private readonly string fieldName = "age";
public SchemaCommandHandlerTests() public SchemaCommandHandlerTests()

3
tests/Squidex.Write.Tests/Schemas/SchemaDomainObjectTests.cs

@ -9,7 +9,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using Moq;
using Squidex.Core.Schemas; using Squidex.Core.Schemas;
using Squidex.Events.Schemas; using Squidex.Events.Schemas;
using Squidex.Infrastructure; using Squidex.Infrastructure;
@ -32,7 +31,7 @@ namespace Squidex.Write.Schemas
{ {
fieldId = new NamedId<long>(1, fieldName); fieldId = new NamedId<long>(1, fieldName);
var fieldRegistry = new FieldRegistry(new TypeNameRegistry(), new Mock<IAssetTester>().Object); var fieldRegistry = new FieldRegistry(new TypeNameRegistry());
sut = new SchemaDomainObject(SchemaId, 0, fieldRegistry); sut = new SchemaDomainObject(SchemaId, 0, fieldRegistry);
} }

Loading…
Cancel
Save