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);
}
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);
@ -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);

21
src/Squidex.Core/ContentValidator.cs

@ -21,6 +21,7 @@ namespace Squidex.Core
{
private readonly Schema schema;
private readonly PartitionResolver partitionResolver;
private readonly ValidationContext context;
private readonly List<ValidationError> errors = new List<ValidationError>();
public IReadOnlyList<ValidationError> Errors
@ -28,13 +29,13 @@ namespace Squidex.Core
get { return errors; }
}
public ContentValidator(Schema schema, PartitionResolver partitionResolver)
public ContentValidator(Schema schema, PartitionResolver partitionResolver, ValidationContext context)
{
Guard.NotNull(schema, nameof(schema));
Guard.NotNull(partitionResolver, nameof(partitionResolver));
this.schema = schema;
this.context = context;
this.partitionResolver = partitionResolver;
}
@ -64,15 +65,13 @@ namespace Squidex.Core
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
{
var item = partitionItem;
await field.ValidateAsync(partitionValues.Value, item.IsOptional, m => errors.AddError(m, field, item));
errors.AddError($"<FIELD> has an unsupported {partitioning.Key} value '{partitionValues.Key}'", field);
}
}
}
@ -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));
}
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));
@ -48,7 +48,7 @@ namespace Squidex.Core
foreach (var validator in field.Validators)
{
await validator.ValidateAsync(typedValue, isOptional, addError);
await validator.ValidateAsync(typedValue, context, addError);
}
}
catch

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

@ -19,22 +19,20 @@ namespace Squidex.Core.Schemas
public sealed class AssetsField : Field<AssetsFieldProperties>, IReferenceField
{
private static readonly Guid[] EmptyIds = new Guid[0];
private readonly IAssetTester assetTester;
public AssetsField(long id, string name, Partitioning partitioning, IAssetTester assetTester)
: this(id, name, partitioning, new AssetsFieldProperties(), assetTester)
public AssetsField(long id, string name, Partitioning partitioning)
: 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)
{
this.assetTester = assetTester;
}
protected override IEnumerable<IValidator> CreateValidators()
{
yield return new AssetsValidator(assetTester, Properties.IsRequired);
yield return new AssetsValidator(Properties.IsRequired);
}
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(assetTester, nameof(assetTester));
this.typeNameRegistry = typeNameRegistry;
@ -70,7 +69,11 @@ namespace Squidex.Core.Schemas
Add<AssetsFieldProperties>(
(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>(
(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
// ==========================================================================
// Copyright (c) Squidex Group
@ -7,12 +7,19 @@
// ==========================================================================
using System;
using System.Threading.Tasks;
using System.Collections.Generic;
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;
}
public Task ValidateAsync(object value, bool isOptional, Action<string> addError)
public Task ValidateAsync(object value, ValidationContext context, Action<string> addError)
{
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
{
private readonly IAssetTester assetTester;
private readonly bool isRequired;
public AssetsValidator(IAssetTester assetTester, bool isRequired)
public AssetsValidator(bool isRequired)
{
this.assetTester = assetTester;
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;
if (assets == null || assets.AssetIds.Count == 0)
{
if (isRequired && !isOptional)
if (isRequired && !context.IsOptional)
{
addError("<FIELD> is required");
}
@ -37,7 +35,7 @@ namespace Squidex.Core.Schemas.Validators
return;
}
var assetTasks = assets.AssetIds.Select(CheckAsset).ToArray();
var assetTasks = assets.AssetIds.Select(x => CheckAssetAsync(context, x)).ToArray();
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);
}

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

@ -13,6 +13,6 @@ namespace Squidex.Core.Schemas.Validators
{
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 + "$");
}
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)
{

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

@ -28,7 +28,7 @@ namespace Squidex.Core.Schemas.Validators
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)
{

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;
}
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;
}

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

@ -14,9 +14,9 @@ namespace Squidex.Core.Schemas.Validators
{
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");
}

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

@ -30,7 +30,7 @@ namespace Squidex.Core.Schemas.Validators
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))
{

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

@ -12,7 +12,6 @@ using System.Linq;
using System.Threading.Tasks;
using MongoDB.Bson;
using MongoDB.Driver;
using Squidex.Core.Schemas;
using Squidex.Infrastructure.CQRS.Events;
using Squidex.Infrastructure.MongoDb;
using Squidex.Read.Assets;
@ -20,7 +19,7 @@ using Squidex.Read.Assets.Repositories;
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)
: 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));
}
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)

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

@ -112,6 +112,18 @@ namespace Squidex.Read.MongoDb.Contents
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)
{
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<bool> ExistsAsync(Guid appId, Guid assetId);
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<bool> ExistsAsync(Guid appId, Guid schemaId, Guid contentId);
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.Threading.Tasks;
using Squidex.Core;
using Squidex.Core.Schemas;
using Squidex.Infrastructure;
using Squidex.Infrastructure.CQRS.Commands;
using Squidex.Infrastructure.Dispatching;
using Squidex.Infrastructure.Tasks;
using Squidex.Read.Apps.Services;
using Squidex.Read.Assets.Repositories;
using Squidex.Read.Contents.Repositories;
using Squidex.Read.Schemas.Services;
using Squidex.Write.Contents.Commands;
@ -24,21 +27,29 @@ namespace Squidex.Write.Contents
{
private readonly IAggregateHandler handler;
private readonly IAppProvider appProvider;
private readonly IAssetRepository assetRepository;
private readonly IContentRepository contentRepository;
private readonly ISchemaProvider schemas;
public ContentCommandHandler(
IAggregateHandler handler,
IAppProvider appProvider,
ISchemaProvider schemas)
IAssetRepository assetRepository,
ISchemaProvider schemas,
IContentRepository contentRepository)
{
Guard.NotNull(handler, nameof(handler));
Guard.NotNull(schemas, nameof(schemas));
Guard.NotNull(handler, nameof(handler));
Guard.NotNull(appProvider, nameof(appProvider));
Guard.NotNull(assetRepository, nameof(assetRepository));
Guard.NotNull(contentRepository, nameof(contentRepository));
this.handler = handler;
this.schemas = schemas;
this.appProvider = appProvider;
this.assetRepository = assetRepository;
this.contentRepository = contentRepository;
}
protected async Task On(CreateContent command, CommandContext context)
@ -99,7 +110,11 @@ namespace Squidex.Write.Contents
var schemaObject = taskForSchema.Result.Schema;
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)
{

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

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

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

@ -49,6 +49,10 @@ namespace Squidex.Controllers.Api.Schemas.Models.Converters
{
typeof(AssetsFieldProperties),
p => Convert((AssetsFieldProperties)p)
},
{
typeof(ReferencesFieldProperties),
p => Convert((ReferencesFieldProperties)p)
}
};
@ -150,6 +154,13 @@ namespace Squidex.Controllers.Api.Schemas.Models.Converters
return result;
}
private static FieldPropertiesDto Convert(ReferencesFieldProperties source)
{
var result = SimpleMapper.Map(source, new ReferencesFieldPropertiesDto());
return result;
}
private static FieldPropertiesDto Convert(StringFieldProperties source)
{
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(JsonFieldPropertiesDto))]
[KnownType(typeof(NumberFieldPropertiesDto))]
[KnownType(typeof(ReferencesFieldPropertiesDto))]
[KnownType(typeof(StringFieldPropertiesDto))]
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.
// ==========================================================================
using Moq;
using System;
using NodaTime;
using NodaTime.Text;
using Squidex.Core.Contents;
@ -34,12 +34,14 @@ namespace Squidex.Core
.AddOrUpdateField(new NumberField(3, "my-number", Partitioning.Invariant,
new NumberFieldProperties { DefaultValue = 123 }))
.AddOrUpdateField(new AssetsField(4, "my-assets", Partitioning.Invariant,
new AssetsFieldProperties(), new Mock<IAssetTester>().Object))
new AssetsFieldProperties()))
.AddOrUpdateField(new BooleanField(5, "my-boolean", Partitioning.Invariant,
new BooleanFieldProperties { DefaultValue = true }))
.AddOrUpdateField(new DateTimeField(6, "my-datetime", Partitioning.Invariant,
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()));
var data =

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

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

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

@ -9,7 +9,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Moq;
using Newtonsoft.Json.Linq;
using Squidex.Core.Schemas;
using Squidex.Infrastructure;
@ -24,8 +23,8 @@ namespace Squidex.Core.Contents
.AddOrUpdateField(new NumberField(1, "field1", Partitioning.Language))
.AddOrUpdateField(new NumberField(2, "field2", Partitioning.Invariant))
.AddOrUpdateField(new NumberField(3, "field3", Partitioning.Invariant).Hide())
.AddOrUpdateField(new AssetsField(5, "assets1", Partitioning.Invariant, new Mock<IAssetTester>().Object))
.AddOrUpdateField(new AssetsField(6, "assets2", Partitioning.Invariant, new Mock<IAssetTester>().Object))
.AddOrUpdateField(new AssetsField(5, "assets1", Partitioning.Invariant))
.AddOrUpdateField(new AssetsField(6, "assets2", Partitioning.Invariant))
.AddOrUpdateField(new JsonField(4, "json", Partitioning.Language));
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.Threading.Tasks;
using FluentAssertions;
using Moq;
using Newtonsoft.Json.Linq;
using Squidex.Infrastructure.Tasks;
using Xunit;
@ -20,13 +19,13 @@ namespace Squidex.Core.Schemas
{
public class AssetsFieldTests
{
private readonly Mock<IAssetTester> assetTester = new Mock<IAssetTester>();
private readonly List<string> errors = new List<string>();
private static readonly ValidationContext InvalidAssetContext = new ValidationContext((x, y) => TaskHelper.False, x => TaskHelper.False);
[Fact]
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);
}
@ -34,7 +33,7 @@ namespace Squidex.Core.Schemas
[Fact]
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());
}
@ -44,11 +43,9 @@ namespace Squidex.Core.Schemas
{
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), false, errors);
await sut.ValidateAsync(CreateValue(assetId), errors);
Assert.Empty(errors);
}
@ -56,9 +53,9 @@ namespace Squidex.Core.Schemas
[Fact]
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);
}
@ -66,9 +63,9 @@ namespace Squidex.Core.Schemas
[Fact]
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(
new[] { "<FIELD> is required" });
@ -77,9 +74,9 @@ namespace Squidex.Core.Schemas
[Fact]
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(
new[] { "<FIELD> is required" });
@ -88,9 +85,9 @@ namespace Squidex.Core.Schemas
[Fact]
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(
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()
{
var assetId = Guid.NewGuid();
var sut = new AssetsField(1, "my-asset", Partitioning.Invariant);
assetTester.Setup(x => x.IsValidAsync(assetId)).Returns(TaskHelper.False);
var sut = new AssetsField(1, "my-asset", Partitioning.Invariant, assetTester.Object);
await sut.ValidateAsync(CreateValue(assetId), false, errors);
await sut.ValidateAsync(CreateValue(assetId), errors, InvalidAssetContext);
errors.ShouldBeEquivalentTo(
new[] { $"<FIELD> contains invalid asset '{assetId}'" });
@ -117,7 +112,7 @@ namespace Squidex.Core.Schemas
var id1 = 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();
@ -127,7 +122,7 @@ namespace Squidex.Core.Schemas
[Fact]
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();
@ -137,7 +132,7 @@ namespace Squidex.Core.Schemas
[Fact]
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();
@ -147,7 +142,7 @@ namespace Squidex.Core.Schemas
[Fact]
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);
@ -157,7 +152,7 @@ namespace Squidex.Core.Schemas
[Fact]
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);
@ -170,7 +165,7 @@ namespace Squidex.Core.Schemas
var id1 = 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 }));
@ -183,7 +178,7 @@ namespace Squidex.Core.Schemas
var id1 = 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 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)
{
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);
await sut.ValidateAsync(CreateValue(null), false, errors);
await sut.ValidateAsync(CreateValue(null), errors);
Assert.Empty(errors);
}
@ -49,7 +49,7 @@ namespace Squidex.Core.Schemas
{
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);
}
@ -59,7 +59,7 @@ namespace Squidex.Core.Schemas
{
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(
new[] { "<FIELD> is required" });
@ -70,7 +70,7 @@ namespace Squidex.Core.Schemas
{
var sut = new BooleanField(1, "my-bolean", Partitioning.Invariant);
await sut.ValidateAsync(CreateValue("Invalid"), false, errors);
await sut.ValidateAsync(CreateValue("Invalid"), errors);
errors.ShouldBeEquivalentTo(
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);
await sut.ValidateAsync(CreateValue(null), false, errors);
await sut.ValidateAsync(CreateValue(null), 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 });
await sut.ValidateAsync(CreateValue(null), false, errors);
await sut.ValidateAsync(CreateValue(null), errors);
errors.ShouldBeEquivalentTo(
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) });
await sut.ValidateAsync(CreateValue(FutureDays(0)), false, errors);
await sut.ValidateAsync(CreateValue(FutureDays(0)), errors);
errors.ShouldBeEquivalentTo(
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) });
await sut.ValidateAsync(CreateValue(FutureDays(20)), false, errors);
await sut.ValidateAsync(CreateValue(FutureDays(20)), errors);
errors.ShouldBeEquivalentTo(
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);
await sut.ValidateAsync(CreateValue("Invalid"), false, errors);
await sut.ValidateAsync(CreateValue("Invalid"), errors);
errors.ShouldBeEquivalentTo(
new[] { "<FIELD> is not a valid value" });
@ -95,7 +95,7 @@ namespace Squidex.Core.Schemas
{
var sut = new DateTimeField(1, "my-datetime", Partitioning.Invariant);
await sut.ValidateAsync(CreateValue(123), false, errors);
await sut.ValidateAsync(CreateValue(123), errors);
errors.ShouldBeEquivalentTo(
new[] { "<FIELD> is not a valid value" });

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

@ -8,7 +8,6 @@
using System;
using System.Collections.Generic;
using Moq;
using Newtonsoft.Json.Linq;
using Squidex.Infrastructure;
using Xunit;
@ -17,7 +16,7 @@ namespace Squidex.Core.Schemas
{
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
{

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);
await sut.ValidateAsync(CreateValue(JValue.CreateNull()), false, errors);
await sut.ValidateAsync(CreateValue(JValue.CreateNull()), errors);
Assert.Empty(errors);
}
@ -53,7 +53,7 @@ namespace Squidex.Core.Schemas
new JProperty("latitude", 0),
new JProperty("longitude", 0));
await sut.ValidateAsync(CreateValue(geolocation), false, errors);
await sut.ValidateAsync(CreateValue(geolocation), errors);
Assert.Empty(errors);
}
@ -67,7 +67,7 @@ namespace Squidex.Core.Schemas
new JProperty("latitude", 200),
new JProperty("longitude", 0));
await sut.ValidateAsync(CreateValue(geolocation), false, errors);
await sut.ValidateAsync(CreateValue(geolocation), errors);
errors.ShouldBeEquivalentTo(
new[] { "<FIELD> is not a valid value" });
@ -83,7 +83,7 @@ namespace Squidex.Core.Schemas
new JProperty("latitude", 0),
new JProperty("longitude", 0));
await sut.ValidateAsync(CreateValue(geolocation), false, errors);
await sut.ValidateAsync(CreateValue(geolocation), errors);
errors.ShouldBeEquivalentTo(
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 });
await sut.ValidateAsync(CreateValue(JValue.CreateNull()), false, errors);
await sut.ValidateAsync(CreateValue(JValue.CreateNull()), errors);
errors.ShouldBeEquivalentTo(
new[] { "<FIELD> is required" });

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

@ -6,9 +6,9 @@
// All rights reserved.
// ==========================================================================
using System;
using System.Collections.Immutable;
using FluentAssertions;
using Moq;
using Newtonsoft.Json;
using Squidex.Infrastructure;
using Squidex.Infrastructure.Json;
@ -27,7 +27,7 @@ namespace Squidex.Core.Schemas.Json
serializerSettings.TypeNameHandling = TypeNameHandling.Auto;
serializerSettings.SerializationBinder = new TypeNameSerializationBinder(typeNameRegistry);
sut = new SchemaJsonSerializer(new FieldRegistry(typeNameRegistry, new Mock<IAssetTester>().Object), serializerSettings);
sut = new SchemaJsonSerializer(new FieldRegistry(typeNameRegistry), serializerSettings);
}
[Fact]
@ -38,7 +38,7 @@ namespace Squidex.Core.Schemas.Json
.AddOrUpdateField(new JsonField(1, "my-json", Partitioning.Invariant,
new JsonFieldProperties()))
.AddOrUpdateField(new AssetsField(2, "my-assets", Partitioning.Invariant,
new AssetsFieldProperties(), new Mock<IAssetTester>().Object))
new AssetsFieldProperties()))
.AddOrUpdateField(new StringField(3, "my-string1", Partitioning.Language,
new StringFieldProperties { Label = "My String1", IsRequired = true, AllowedValues = ImmutableList.Create("a", "b") }))
.AddOrUpdateField(new StringField(4, "my-string2", Partitioning.Invariant,
@ -51,7 +51,9 @@ namespace Squidex.Core.Schemas.Json
new DateTimeFieldProperties { Editor = DateTimeFieldEditor.DateTime }))
.AddOrUpdateField(new DateTimeField(8, "my-date", Partitioning.Invariant,
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()))
.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);
await sut.ValidateAsync(CreateValue(new JValue(1)), false, errors);
await sut.ValidateAsync(CreateValue(new JValue(1)), 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 });
await sut.ValidateAsync(CreateValue(JValue.CreateNull()), false, errors);
await sut.ValidateAsync(CreateValue(JValue.CreateNull()), errors);
errors.ShouldBeEquivalentTo(
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);
await sut.ValidateAsync(CreateValue(null), false, errors);
await sut.ValidateAsync(CreateValue(null), 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 });
await sut.ValidateAsync(CreateValue(null), false, errors);
await sut.ValidateAsync(CreateValue(null), errors);
errors.ShouldBeEquivalentTo(
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 });
await sut.ValidateAsync(CreateValue(5), false, errors);
await sut.ValidateAsync(CreateValue(5), errors);
errors.ShouldBeEquivalentTo(
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 });
await sut.ValidateAsync(CreateValue(20), false, errors);
await sut.ValidateAsync(CreateValue(20), errors);
errors.ShouldBeEquivalentTo(
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) });
await sut.ValidateAsync(CreateValue(20), false, errors);
await sut.ValidateAsync(CreateValue(20), errors);
errors.ShouldBeEquivalentTo(
new[] { "<FIELD> is not an allowed value" });
@ -94,7 +94,7 @@ namespace Squidex.Core.Schemas
{
var sut = new NumberField(1, "my-number", Partitioning.Invariant);
await sut.ValidateAsync(CreateValue("Invalid"), false, errors);
await sut.ValidateAsync(CreateValue("Invalid"), errors);
errors.ShouldBeEquivalentTo(
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.Immutable;
using System.Linq;
using Moq;
using Newtonsoft.Json.Linq;
using NJsonSchema;
using Squidex.Infrastructure;
@ -319,7 +318,7 @@ namespace Squidex.Core.Schemas
.AddOrUpdateField(new JsonField(1, "my-json", Partitioning.Invariant,
new JsonFieldProperties()))
.AddOrUpdateField(new AssetsField(2, "my-assets", Partitioning.Invariant,
new AssetsFieldProperties(), new Mock<IAssetTester>().Object))
new AssetsFieldProperties()))
.AddOrUpdateField(new StringField(3, "my-string1", Partitioning.Language,
new StringFieldProperties { Label = "My String1", IsRequired = true, AllowedValues = ImmutableList.Create("a", "b") }))
.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>" });
await sut.ValidateAsync(CreateValue(null), false, errors);
await sut.ValidateAsync(CreateValue(null), 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 });
await sut.ValidateAsync(CreateValue(null), false, errors);
await sut.ValidateAsync(CreateValue(null), errors);
errors.ShouldBeEquivalentTo(
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 });
await sut.ValidateAsync(CreateValue("123"), false, errors);
await sut.ValidateAsync(CreateValue("123"), errors);
errors.ShouldBeEquivalentTo(
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 });
await sut.ValidateAsync(CreateValue("12345678"), false, errors);
await sut.ValidateAsync(CreateValue("12345678"), errors);
errors.ShouldBeEquivalentTo(
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") });
await sut.ValidateAsync(CreateValue("Bar"), false, errors);
await sut.ValidateAsync(CreateValue("Bar"), errors);
errors.ShouldBeEquivalentTo(
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}" });
await sut.ValidateAsync(CreateValue("abc"), false, errors);
await sut.ValidateAsync(CreateValue("abc"), errors);
errors.ShouldBeEquivalentTo(
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" });
await sut.ValidateAsync(CreateValue("abc"), false, errors);
await sut.ValidateAsync(CreateValue("abc"), errors);
errors.ShouldBeEquivalentTo(
new[] { "Custom Error Message" });

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

@ -9,14 +9,33 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using Newtonsoft.Json.Linq;
using Squidex.Core.Schemas.Validators;
using Squidex.Infrastructure.Tasks;
namespace Squidex.Core.Schemas
{
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>();
[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);
await sut.ValidateAsync(null, false, errors.Add);
await sut.ValidateAsync(null, errors);
Assert.Equal(0, errors.Count);
}
[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);
await sut.ValidateAsync(100, false, errors.Add);
await sut.ValidateAsync(100, errors);
Assert.Equal(0, errors.Count);
}
@ -42,7 +42,7 @@ namespace Squidex.Core.Schemas.Validators
{
var sut = new AllowedValuesValidator<int>(100, 200);
await sut.ValidateAsync(50, false, errors.Add);
await sut.ValidateAsync(50, errors);
errors.ShouldBeEquivalentTo(
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}");
await sut.ValidateAsync("abc:12", false, errors.Add);
await sut.ValidateAsync("abc:12", errors);
Assert.Equal(0, errors.Count);
}
@ -32,7 +32,7 @@ namespace Squidex.Core.Schemas.Validators
{
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);
}
@ -42,7 +42,7 @@ namespace Squidex.Core.Schemas.Validators
{
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);
}
@ -52,7 +52,7 @@ namespace Squidex.Core.Schemas.Validators
{
var sut = new PatternValidator("[a-z]{3}:[0-9]{2}");
await sut.ValidateAsync("foo", false, errors.Add);
await sut.ValidateAsync("foo", errors);
errors.ShouldBeEquivalentTo(
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");
await sut.ValidateAsync("foo", false, errors.Add);
await sut.ValidateAsync("foo", errors);
errors.ShouldBeEquivalentTo(
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>();
[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);
await sut.ValidateAsync(null, false, errors.Add);
await sut.ValidateAsync(null, errors);
Assert.Equal(0, errors.Count);
}
@ -37,7 +37,7 @@ namespace Squidex.Core.Schemas.Validators
{
var sut = new RangeValidator<int>(min, max);
await sut.ValidateAsync(1500, false, errors.Add);
await sut.ValidateAsync(1500, errors);
Assert.Equal(0, errors.Count);
}
@ -55,7 +55,7 @@ namespace Squidex.Core.Schemas.Validators
{
var sut = new RangeValidator<int>(2000, null);
await sut.ValidateAsync(1500, false, errors.Add);
await sut.ValidateAsync(1500, errors);
errors.ShouldBeEquivalentTo(
new[] { "<FIELD> must be greater than '2000'" });
@ -66,7 +66,7 @@ namespace Squidex.Core.Schemas.Validators
{
var sut = new RangeValidator<int>(null, 1000);
await sut.ValidateAsync(1500, false, errors.Add);
await sut.ValidateAsync(1500, errors);
errors.ShouldBeEquivalentTo(
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();
await sut.ValidateAsync(value, false, errors.Add);
await sut.ValidateAsync(value, errors);
Assert.Equal(0, errors.Count);
}
@ -36,7 +36,7 @@ namespace Squidex.Core.Schemas.Validators
{
var sut = new RequiredStringValidator();
await sut.ValidateAsync(string.Empty, true, errors.Add);
await sut.ValidateOptionalAsync(string.Empty, errors);
Assert.Equal(0, errors.Count);
}
@ -46,7 +46,7 @@ namespace Squidex.Core.Schemas.Validators
{
var sut = new RequiredStringValidator();
await sut.ValidateAsync(true, false, errors.Add);
await sut.ValidateAsync(true, errors);
Assert.Equal(0, errors.Count);
}
@ -56,7 +56,7 @@ namespace Squidex.Core.Schemas.Validators
{
var sut = new RequiredStringValidator(true);
await sut.ValidateAsync(string.Empty, false, errors.Add);
await sut.ValidateAsync(string.Empty, errors);
errors.ShouldBeEquivalentTo(
new[] { "<FIELD> is required" });
@ -67,7 +67,7 @@ namespace Squidex.Core.Schemas.Validators
{
var sut = new RequiredStringValidator();
await sut.ValidateAsync(null, false, errors.Add);
await sut.ValidateAsync(null, errors);
errors.ShouldBeEquivalentTo(
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();
await sut.ValidateAsync(true, false, errors.Add);
await sut.ValidateAsync(true, errors);
Assert.Equal(0, errors.Count);
}
@ -32,7 +32,7 @@ namespace Squidex.Core.Schemas.Validators
{
var sut = new RequiredValidator();
await sut.ValidateAsync(string.Empty, false, errors.Add);
await sut.ValidateAsync(string.Empty, errors);
Assert.Equal(0, errors.Count);
}
@ -42,7 +42,7 @@ namespace Squidex.Core.Schemas.Validators
{
var sut = new RequiredValidator();
await sut.ValidateAsync(null, true, errors.Add);
await sut.ValidateOptionalAsync(null, errors);
Assert.Equal(0, errors.Count);
}
@ -52,7 +52,7 @@ namespace Squidex.Core.Schemas.Validators
{
var sut = new RequiredValidator();
await sut.ValidateAsync(null, false, errors.Add);
await sut.ValidateAsync(null, errors);
errors.ShouldBeEquivalentTo(
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>();
[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);
await sut.ValidateAsync(null, false, errors.Add);
await sut.ValidateAsync(null, errors);
Assert.Equal(0, errors.Count);
}
[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);
await sut.ValidateAsync(string.Empty, false, errors.Add);
await sut.ValidateAsync(string.Empty, errors);
Assert.Equal(0, errors.Count);
}
@ -48,7 +48,7 @@ namespace Squidex.Core.Schemas.Validators
{
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);
}
@ -66,7 +66,7 @@ namespace Squidex.Core.Schemas.Validators
{
var sut = new StringLengthValidator(2000, null);
await sut.ValidateAsync(CreateString(1500), false, errors.Add);
await sut.ValidateAsync(CreateString(1500), errors);
errors.ShouldBeEquivalentTo(
new[] { "<FIELD> must have more than '2000' characters" });
@ -77,7 +77,7 @@ namespace Squidex.Core.Schemas.Validators
{
var sut = new StringLengthValidator(null, 1000);
await sut.ValidateAsync(CreateString(1500), false, errors.Add);
await sut.ValidateAsync(CreateString(1500), errors);
errors.ShouldBeEquivalentTo(
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.Read.Apps;
using Squidex.Read.Apps.Services;
using Squidex.Read.Assets.Repositories;
using Squidex.Read.Contents.Repositories;
using Squidex.Read.Schemas;
using Squidex.Read.Schemas.Services;
using Squidex.Write.Contents.Commands;
@ -47,7 +49,7 @@ namespace Squidex.Write.Contents
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.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 SchemaCommandHandler sut;
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";
public SchemaCommandHandlerTests()

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

@ -9,7 +9,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Moq;
using Squidex.Core.Schemas;
using Squidex.Events.Schemas;
using Squidex.Infrastructure;
@ -32,7 +31,7 @@ namespace Squidex.Write.Schemas
{
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);
}

Loading…
Cancel
Save