Browse Source

Field properties

pull/1/head
Sebastian 9 years ago
parent
commit
4af89a1eed
  1. 37
      src/Squidex.Core/Schemas/Field.cs
  2. 31
      src/Squidex.Core/Schemas/FieldProperties.cs
  3. 7
      src/Squidex.Core/Schemas/FieldRegistry.cs
  4. 23
      src/Squidex.Core/Schemas/Field_Generic.cs
  5. 42
      src/Squidex.Core/Schemas/NamedElementProperties.cs
  6. 2
      src/Squidex.Core/Schemas/NumberField.cs
  7. 57
      src/Squidex.Core/Schemas/NumberFieldProperties.cs
  8. 19
      src/Squidex.Core/Schemas/Schema.cs
  9. 50
      src/Squidex.Core/Schemas/StringField.cs
  10. 97
      src/Squidex.Core/Schemas/StringFieldProperties.cs
  11. 55
      src/Squidex.Core/Schemas/Validators/PatternValidator.cs
  12. 6
      src/Squidex.Core/Schemas/Validators/RangeValidator.cs
  13. 54
      src/Squidex.Core/Schemas/Validators/StringLengthValidator.cs
  14. 209
      src/Squidex.Infrastructure/UpdateProperties.cs
  15. 2
      src/Squidex.Write/Schemas/Commands/CreateSchema.cs
  16. 11
      tests/Squidex.Core.Tests/Properties/AssemblyInfo.cs
  17. 79
      tests/Squidex.Core.Tests/Schemas/FieldRegistryTests.cs
  18. 81
      tests/Squidex.Core.Tests/Schemas/NumberFieldPropertiesTests.cs
  19. 101
      tests/Squidex.Core.Tests/Schemas/NumberFieldTests.cs
  20. 280
      tests/Squidex.Core.Tests/Schemas/SchemaTests.cs
  21. 95
      tests/Squidex.Core.Tests/Schemas/StringFieldPropertiesTests.cs
  22. 100
      tests/Squidex.Core.Tests/Schemas/StringFieldTests.cs
  23. 63
      tests/Squidex.Core.Tests/Schemas/Validators/PatternValidatorTests.cs
  24. 32
      tests/Squidex.Core.Tests/Schemas/Validators/RangeValidatorTests.cs
  25. 6
      tests/Squidex.Core.Tests/Schemas/Validators/RequiredStringValidatorTests.cs
  26. 4
      tests/Squidex.Core.Tests/Schemas/Validators/RequiredValidatorTests.cs
  27. 89
      tests/Squidex.Core.Tests/Schemas/Validators/StringLengthValidatorTests.cs
  28. 18
      tests/Squidex.Write.Tests/Schemas/SchemaDomainObjectTests.cs

37
src/Squidex.Core/Schemas/Field.cs

@ -43,6 +43,8 @@ namespace Squidex.Core.Schemas
get { return isDisabled; }
}
public abstract FieldProperties RawProperties { get; }
protected Field(long id, string name)
{
Guard.ValidSlug(name, nameof(name));
@ -61,25 +63,32 @@ namespace Squidex.Core.Schemas
{
Guard.NotNull(property, nameof(property));
var value = ConvertValue(property);
var tempErrors = new List<string>();
var rawErrors = new List<string>();
try
{
var value = ConvertValue(property);
foreach (var validator in validators.Value)
foreach (var validator in validators.Value)
{
await validator.ValidateAsync(value, rawErrors);
}
}
catch (InvalidCastException)
{
await validator.ValidateAsync(value, tempErrors);
rawErrors.Add("<FIELD> is not a valid value");
}
foreach (var error in tempErrors)
if (rawErrors.Count > 0)
{
errors.Add(error.Replace("<FIELD>", name));
var displayName = !string.IsNullOrWhiteSpace(RawProperties.Label) ? RawProperties.Label : name;
foreach (var error in rawErrors)
{
errors.Add(error.Replace("<FIELD>", displayName));
}
}
}
protected abstract IEnumerable<IValidator> CreateValidators();
protected abstract object ConvertValue(PropertyValue property);
public Field Hide()
{
return Update<Field>(clone => clone.isHidden = true);
@ -121,8 +130,10 @@ namespace Squidex.Core.Schemas
return clone;
}
public abstract Field Clone();
protected abstract IEnumerable<IValidator> CreateValidators();
protected abstract object ConvertValue(PropertyValue property);
public abstract FieldProperties CloneProperties();
protected abstract Field Clone();
}
}

31
src/Squidex.Core/Schemas/FieldProperties.cs

@ -13,24 +13,39 @@ namespace Squidex.Core.Schemas
{
public abstract class FieldProperties : NamedElementProperties, IValidatable
{
public bool IsRequired { get; set; }
private bool isRequired;
private string placeholder;
public void Validate(IList<ValidationError> errors)
public bool IsRequired
{
foreach (var error in ValidateCore())
get { return isRequired; }
set
{
errors.Add(error);
ThrowIfFrozen();
isRequired = value;
}
}
protected virtual IEnumerable<ValidationError> ValidateCore()
public string Placeholder
{
yield break;
get { return placeholder; }
set
{
ThrowIfFrozen();
placeholder = value;
}
}
public FieldProperties Clone()
public void Validate(IList<ValidationError> errors)
{
return (FieldProperties) MemberwiseClone();
foreach (var error in ValidateCore())
{
errors.Add(error);
}
}
protected abstract IEnumerable<ValidationError> ValidateCore();
}
}

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

@ -66,7 +66,12 @@ namespace Squidex.Core.Schemas
public Field CreateField(long id, string name, FieldProperties properties)
{
var registered = fieldsByPropertyType[properties.GetType()];
var registered = fieldsByPropertyType.GetOrDefault(properties.GetType());
if (registered == null)
{
throw new InvalidOperationException($"The field property '{properties.GetType()}' is not supported.");
}
return registered.CreateField(id, name, properties);
}

23
src/Squidex.Core/Schemas/Field_Generic.cs

@ -20,19 +20,31 @@ namespace Squidex.Core.Schemas
get { return properties; }
}
public override FieldProperties RawProperties
{
get { return properties; }
}
protected Field(long id, string name, T properties)
: base(id, name)
{
Guard.NotNull(properties, nameof(properties));
this.properties = properties;
this.properties = ValidateProperties(properties);
}
public override Field Update(FieldProperties newProperties)
{
var typedProperties = ValidateProperties(newProperties);
return Update<Field<T>>(clone => clone.properties = typedProperties);
}
private T ValidateProperties(FieldProperties newProperties)
{
Guard.NotNull(newProperties, nameof(newProperties));
newProperties = newProperties.Clone();
newProperties.Freeze();
var typedProperties = newProperties as T;
@ -43,12 +55,7 @@ namespace Squidex.Core.Schemas
newProperties.Validate(() => $"Cannot update field with id '{Id}', because the settings are invalid.");
return Update<Field<T>>(clone => clone.properties = typedProperties);
}
public override FieldProperties CloneProperties()
{
return properties.Clone();
return typedProperties;
}
}
}

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

@ -6,12 +6,50 @@
// All rights reserved.
// ==========================================================================
using System;
namespace Squidex.Core.Schemas
{
public abstract class NamedElementProperties
{
public string Label { get; set; }
private string label;
private string hints;
public bool IsFrozen { get; private set; }
public string Label
{
get { return label; }
set
{
ThrowIfFrozen();
label = value;
}
}
public string Hints
{
get { return hints; }
set
{
ThrowIfFrozen();
hints = value;
}
}
protected void ThrowIfFrozen()
{
if (IsFrozen)
{
throw new InvalidOperationException("Object is frozen");
}
}
public string Hints { get; set; }
public void Freeze()
{
IsFrozen = true;
}
}
}

2
src/Squidex.Core/Schemas/NumberField.cs

@ -44,7 +44,7 @@ namespace Squidex.Core.Schemas
return property.ToNullableDouble(CultureInfo.InvariantCulture);
}
public override Field Clone()
protected override Field Clone()
{
return new NumberField(Id, Name, Properties);
}

57
src/Squidex.Core/Schemas/NumberFieldProperties.cs

@ -15,26 +15,65 @@ namespace Squidex.Core.Schemas
[TypeName("number")]
public sealed class NumberFieldProperties : FieldProperties
{
public string Placeholder { get; set; }
private double? maxValue;
private double? minValue;
private double? defaultValue;
private ImmutableList<double> allowedValues;
public double? MaxValue { get; set; }
public double? MaxValue
{
get { return maxValue; }
set
{
ThrowIfFrozen();
maxValue = value;
}
}
public double? MinValue
{
get { return minValue; }
set
{
ThrowIfFrozen();
minValue = value;
}
}
public double? MinValue { get; set; }
public double? DefaultValue
{
get { return defaultValue; }
set
{
ThrowIfFrozen();
defaultValue = value;
}
}
public double? DefaultValue { get; set; }
public ImmutableList<double> AllowedValues
{
get { return allowedValues; }
set
{
ThrowIfFrozen();
public ImmutableList<double> AllowedValues { get; set; }
allowedValues = value;
}
}
protected override IEnumerable<ValidationError> ValidateCore()
{
if (MaxValue.HasValue && MinValue.HasValue && MinValue.Value >= MaxValue.Value)
{
yield return new ValidationError("Max value must be greater than min value.", nameof(MinValue), nameof(MaxValue));
yield return new ValidationError("Max value must be greater than min value", nameof(MinValue), nameof(MaxValue));
}
if (AllowedValues != null && (MinValue.HasValue || MaxValue.HasValue))
{
yield return new ValidationError("Either or allowed values or range can be defined.",
yield return new ValidationError("Either or allowed values or range can be defined",
nameof(AllowedValues),
nameof(MinValue),
nameof(MaxValue));
@ -47,12 +86,12 @@ namespace Squidex.Core.Schemas
if (MinValue.HasValue && DefaultValue.Value < MinValue.Value)
{
yield return new ValidationError("Default value must be greater than min value.", nameof(DefaultValue));
yield return new ValidationError("Default value must be greater than min value", nameof(DefaultValue));
}
if (MaxValue.HasValue && DefaultValue.Value > MaxValue.Value)
{
yield return new ValidationError("Default value must be less than max value.", nameof(DefaultValue));
yield return new ValidationError("Default value must be less than max value", nameof(DefaultValue));
}
}
}

19
src/Squidex.Core/Schemas/Schema.cs

@ -51,6 +51,8 @@ namespace Squidex.Core.Schemas
fieldsById = fields;
fieldsByName = fields.Values.ToDictionary(x => x.Name, StringComparer.OrdinalIgnoreCase);
properties.Freeze();
}
public static Schema Create(string name, SchemaProperties newProperties)
@ -101,7 +103,7 @@ namespace Squidex.Core.Schemas
public Schema HideField(long fieldId)
{
return UpdateField(fieldId, field => field.Show());
return UpdateField(fieldId, field => field.Hide());
}
public Schema ShowField(long fieldId)
@ -152,10 +154,21 @@ namespace Squidex.Core.Schemas
}
else
{
fieldErrors.Add($"'{kvp.Key}' is not a known field");
fieldErrors.Add($"{kvp.Key} is not a known field");
}
fieldErrors.ForEach(error => errors.Add(new ValidationError(error, kvp.Key)));
foreach (var error in fieldErrors)
{
errors.Add(new ValidationError(error, kvp.Key));
}
}
foreach (var field in fieldsByName.Values)
{
if (field.RawProperties.IsRequired && !data.Contains(field.Name))
{
errors.Add(new ValidationError($"{field.Name} is required", field.Name));
}
}
}
}

50
src/Squidex.Core/Schemas/StringField.cs

@ -0,0 +1,50 @@
// ==========================================================================
// StringField.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
using System.Collections.Generic;
using Squidex.Core.Schemas.Validators;
using Squidex.Infrastructure;
namespace Squidex.Core.Schemas
{
public sealed class StringField : Field<StringFieldProperties>
{
public StringField(long id, string name, StringFieldProperties properties)
: base(id, name, properties)
{
}
protected override IEnumerable<IValidator> CreateValidators()
{
if (Properties.IsRequired)
{
yield return new RequiredStringValidator();
}
if (Properties.MinLength.HasValue || Properties.MaxLength.HasValue)
{
yield return new StringLengthValidator(Properties.MinLength, Properties.MaxLength);
}
if (!string.IsNullOrWhiteSpace(Properties.Pattern))
{
yield return new PatternValidator(Properties.Pattern, Properties.PatternMessage);
}
}
protected override object ConvertValue(PropertyValue property)
{
return property.ToString();
}
protected override Field Clone()
{
return new StringField(Id, Name, Properties);
}
}
}

97
src/Squidex.Core/Schemas/StringFieldProperties.cs

@ -0,0 +1,97 @@
// ==========================================================================
// StringFieldProperties.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using Squidex.Infrastructure;
// ReSharper disable ObjectCreationAsStatement
namespace Squidex.Core.Schemas
{
public sealed class StringFieldProperties : FieldProperties
{
private int? minLength;
private int? maxLength;
private string pattern;
private string patternMessage;
public int? MinLength
{
get { return minLength; }
set
{
ThrowIfFrozen();
minLength = value;
}
}
public int? MaxLength
{
get { return maxLength; }
set
{
ThrowIfFrozen();
maxLength = value;
}
}
public string Pattern
{
get { return pattern; }
set
{
ThrowIfFrozen();
pattern = value;
}
}
public string PatternMessage
{
get { return patternMessage; }
set
{
ThrowIfFrozen();
patternMessage = value;
}
}
protected override IEnumerable<ValidationError> ValidateCore()
{
if (MaxLength.HasValue && MinLength.HasValue && MinLength.Value >= MaxLength.Value)
{
yield return new ValidationError("Max length must be greater than min length", nameof(MinLength), nameof(MaxLength));
}
if (Pattern == null)
{
yield break;
}
var isValidPattern = true;
try
{
new Regex(Pattern);
}
catch (ArgumentException)
{
isValidPattern = false;
}
if (!isValidPattern)
{
yield return new ValidationError("Pattern is not a valid expression", nameof(Pattern));
}
}
}
}

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

@ -0,0 +1,55 @@
// ==========================================================================
// PatternValidator.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
using System.Collections.Generic;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using Squidex.Infrastructure.Tasks;
// ReSharper disable ConvertIfStatementToConditionalTernaryExpression
// ReSharper disable InvertIf
namespace Squidex.Core.Schemas.Validators
{
public class PatternValidator : IValidator
{
private readonly Regex regex;
private readonly string errorMessage;
public PatternValidator(string pattern, string errorMessage = null)
{
this.errorMessage = errorMessage;
regex = new Regex(pattern);
}
public Task ValidateAsync(object value, ICollection<string> errors)
{
var stringValue = value as string;
if (stringValue == null)
{
return TaskHelper.Done;
}
if (!regex.IsMatch(stringValue))
{
if (string.IsNullOrWhiteSpace(errorMessage))
{
errors.Add("<FIELD> is not valid");
}
else
{
errors.Add(errorMessage);
}
}
return TaskHelper.Done;
}
}
}

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

@ -22,7 +22,7 @@ namespace Squidex.Core.Schemas.Validators
{
if (min.HasValue && max.HasValue && min.Value.CompareTo(max.Value) >= 0)
{
throw new ArgumentException("MinValue must larger than max value");
throw new ArgumentException("Min value must be greater than max value", nameof(min));
}
this.min = min;
@ -40,12 +40,12 @@ namespace Squidex.Core.Schemas.Validators
if (min.HasValue && typedValue.CompareTo(min.Value) < 0)
{
errors.Add($"<FIELD> must be greater than {min}");
errors.Add($"<FIELD> must be greater than '{min}'");
}
if (max.HasValue && typedValue.CompareTo(max.Value) > 0)
{
errors.Add($"<FIELD> must be greater than {min}");
errors.Add($"<FIELD> must be less than '{max}'");
}
return TaskHelper.Done;

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

@ -0,0 +1,54 @@
// ==========================================================================
// StringLengthValidator.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Squidex.Infrastructure.Tasks;
namespace Squidex.Core.Schemas.Validators
{
public class StringLengthValidator : IValidator
{
private readonly int? minLength;
private readonly int? maxLength;
public StringLengthValidator(int? minLength, int? maxLength)
{
if (minLength.HasValue && maxLength.HasValue && minLength.Value >= maxLength.Value)
{
throw new ArgumentException("Min length must be greater than max length", nameof(minLength));
}
this.minLength = minLength;
this.maxLength = maxLength;
}
public Task ValidateAsync(object value, ICollection<string> errors)
{
var stringValue = value as string;
if (stringValue == null)
{
return TaskHelper.Done;
}
if (minLength.HasValue && stringValue.Length < minLength.Value)
{
errors.Add($"<FIELD> must have more than '{minLength}' characters");
}
if (maxLength.HasValue && stringValue.Length > maxLength.Value)
{
errors.Add($"<FIELD> must have less than '{maxLength}' characters");
}
return TaskHelper.Done;
}
}
}

209
src/Squidex.Infrastructure/UpdateProperties.cs

@ -0,0 +1,209 @@
// ==========================================================================
// Guard.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Runtime.CompilerServices;
// ReSharper disable InvertIf
namespace Squidex.Infrastructure
{
public static class UpdateProperties
{
[DebuggerStepThrough]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void ValidNumber(float target, string parameterName)
{
if (float.IsNaN(target) || float.IsPositiveInfinity(target) || float.IsNegativeInfinity(target))
{
throw new ArgumentException("Value must be a valid number.", parameterName);
}
}
[DebuggerStepThrough]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void ValidNumber(double target, string parameterName)
{
if (double.IsNaN(target) || double.IsPositiveInfinity(target) || double.IsNegativeInfinity(target))
{
throw new ArgumentException("Value must be a valid number.", parameterName);
}
}
[DebuggerStepThrough]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void ValidSlug(string target, string parameterName)
{
NotNullOrEmpty(target, parameterName);
if (!target.IsSlug())
{
throw new ArgumentException("Target is not a valid slug.", parameterName);
}
}
[DebuggerStepThrough]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void HasType<T>(object target, string parameterName)
{
if (target != null && target.GetType() != typeof(T))
{
throw new ArgumentException($"The parameter must be of type {typeof(T)}", parameterName);
}
}
[DebuggerStepThrough]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void HasType(object target, Type expectedType, string parameterName)
{
if (target != null && expectedType != null && target.GetType() != expectedType)
{
throw new ArgumentException($"The parameter must be of type {expectedType}", parameterName);
}
}
[DebuggerStepThrough]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Between<TValue>(TValue target, TValue lower, TValue upper, string parameterName) where TValue : IComparable
{
if (!target.IsBetween(lower, upper))
{
throw new ArgumentException($"Value must be between {lower} and {upper}", parameterName);
}
}
[DebuggerStepThrough]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Enum<TEnum>(TEnum target, string parameterName) where TEnum : struct
{
if (!target.IsEnumValue())
{
throw new ArgumentException($"Value must be a valid enum type {typeof(TEnum)}", parameterName);
}
}
[DebuggerStepThrough]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void GreaterThan<TValue>(TValue target, TValue lower, string parameterName) where TValue : IComparable
{
if (target.CompareTo(lower) <= 0)
{
throw new ArgumentException($"Value must be greater than {lower}", parameterName);
}
}
[DebuggerStepThrough]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void GreaterEquals<TValue>(TValue target, TValue lower, string parameterName) where TValue : IComparable
{
if (target.CompareTo(lower) < 0)
{
throw new ArgumentException($"Value must be greater or equals than {lower}", parameterName);
}
}
[DebuggerStepThrough]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void LessThan<TValue>(TValue target, TValue upper, string parameterName) where TValue : IComparable
{
if (target.CompareTo(upper) >= 0)
{
throw new ArgumentException($"Value must be less than {upper}", parameterName);
}
}
[DebuggerStepThrough]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void LessEquals<TValue>(TValue target, TValue upper, string parameterName) where TValue : IComparable
{
if (target.CompareTo(upper) > 0)
{
throw new ArgumentException($"Value must be less or equals than {upper}", parameterName);
}
}
[DebuggerStepThrough]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void NotEmpty<TType>(ICollection<TType> enumerable, string parameterName)
{
NotNull(enumerable, parameterName);
if (enumerable.Count == 0)
{
throw new ArgumentException("Collection does not contain an item", parameterName);
}
}
[DebuggerStepThrough]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void NotEmpty(Guid target, string parameterName)
{
if (target == Guid.Empty)
{
throw new ArgumentException("Value cannot be empty.", parameterName);
}
}
[DebuggerStepThrough]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void NotNull(object target, string parameterName)
{
if (target == null)
{
throw new ArgumentNullException(parameterName);
}
}
[DebuggerStepThrough]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void NotDefault<T>(T target, string parameterName)
{
if (Equals(target, default(T)))
{
throw new ArgumentException("Value cannot be an the default value", parameterName);
}
}
[DebuggerStepThrough]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void NotNullOrEmpty(string target, string parameterName)
{
NotNull(target, parameterName);
if (string.IsNullOrWhiteSpace(target))
{
throw new ArgumentException("String parameter cannot be null or empty and cannot contain only blanks.", parameterName);
}
}
[DebuggerStepThrough]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void ValidFileName(string target, string parameterName)
{
NotNullOrEmpty(target, parameterName);
if (target.Intersect(Path.GetInvalidFileNameChars()).Any())
{
throw new ArgumentException("Value contains an invalid character.", parameterName);
}
}
[DebuggerStepThrough]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Valid(IValidatable target, string parameterName, Func<string> message)
{
NotNull(target, parameterName);
target.Validate(message);
}
}
}

2
src/Squidex.Write/Schemas/Commands/CreateSchema.cs

@ -22,7 +22,7 @@ namespace Squidex.Write.Schemas.Commands
{
get
{
return properties ?? (properties = new SchemaProperties(null, null));
return properties ?? (properties = new SchemaProperties());
}
set { properties = value; }
}

11
tests/Squidex.Core.Tests/Properties/AssemblyInfo.cs

@ -1,5 +1,12 @@
using System.Reflection;
using System.Runtime.CompilerServices;
// ==========================================================================
// AssemblyInfo.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
using System.Reflection;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following

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

@ -0,0 +1,79 @@
// ==========================================================================
// FieldRegistryTests.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
using System;
using System.Collections.Generic;
using Squidex.Core.Schemas;
using Squidex.Infrastructure;
using Xunit;
namespace Squidex.Core.Tests.Schemas
{
public class FieldRegistryTests
{
private readonly FieldRegistry sut = new FieldRegistry();
public sealed class InvalidProperties : FieldProperties
{
protected override IEnumerable<ValidationError> ValidateCore()
{
yield break;
}
}
static FieldRegistryTests()
{
TypeNameRegistry.Map(typeof(NumberFieldProperties), "number");
TypeNameRegistry.Map(typeof(InvalidProperties), "invalid");
}
[Fact]
public void Should_throw_if_creating_field_and_field_is_not_registered()
{
Assert.Throws<InvalidOperationException>(() => sut.CreateField(1, "name", new InvalidProperties()));
}
[Fact]
public void Should_create_field_by_properties()
{
var properties = new NumberFieldProperties();
var field = sut.CreateField(1, "name", properties);
Assert.Equal(properties, field.RawProperties);
}
[Fact]
public void Should_throw_if_getting_by_type_and_field_is_not_registered()
{
Assert.Throws<InvalidOperationException>(() => sut.FindByPropertiesType(typeof(InvalidProperties)));
}
[Fact]
public void Should_find_registration_by_properties_type()
{
var registry = sut.FindByPropertiesType(typeof(NumberFieldProperties));
Assert.Equal(typeof(NumberFieldProperties), registry.PropertiesType);
}
[Fact]
public void Should_throw_if_getting_by_name_and_field_is_not_registered()
{
Assert.Throws<DomainException>(() => sut.FindByTypeName("invalid"));
}
[Fact]
public void Should_find_registration_by_name()
{
var registry = sut.FindByTypeName("number");
Assert.Equal(typeof(NumberFieldProperties), registry.PropertiesType);
}
}
}

81
tests/Squidex.Core.Tests/Schemas/NumberFieldPropertiesTests.cs

@ -6,12 +6,15 @@
// All rights reserved.
// ==========================================================================
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Reflection;
using Squidex.Core.Schemas;
using Squidex.Infrastructure;
using Xunit;
using FluentAssertions;
using System.Linq;
namespace Squidex.Core.Tests.Schemas
{
@ -20,16 +23,16 @@ namespace Squidex.Core.Tests.Schemas
private readonly List<ValidationError> errors = new List<ValidationError>();
[Fact]
public void Should_not_add_error_if_properties_are_valid()
public void Should_not_add_error_if_sut_are_valid()
{
var properties = new NumberFieldProperties
var sut = new NumberFieldProperties
{
MinValue = 0,
MaxValue = 100,
DefaultValue = 5
};
properties.Validate(errors);
sut.Validate(errors);
Assert.Equal(0, errors.Count);
}
@ -37,71 +40,113 @@ namespace Squidex.Core.Tests.Schemas
[Fact]
public void Should_add_error_if_default_value_is_less_than_min()
{
var properties = new NumberFieldProperties { MinValue = 10, DefaultValue = 5 };
var sut = new NumberFieldProperties { MinValue = 10, DefaultValue = 5 };
properties.Validate(errors);
sut.Validate(errors);
errors.ShouldBeEquivalentTo(
new List<ValidationError>
{
new ValidationError("Default value must be greater than min value.", "DefaultValue")
new ValidationError("Default value must be greater than min value", "DefaultValue")
});
}
[Fact]
public void Should_add_error_if_default_value_is_greater_than_min()
{
var properties = new NumberFieldProperties { MaxValue = 0, DefaultValue = 5 };
var sut = new NumberFieldProperties { MaxValue = 0, DefaultValue = 5 };
properties.Validate(errors);
sut.Validate(errors);
errors.ShouldBeEquivalentTo(
new List<ValidationError>
{
new ValidationError("Default value must be less than max value.", "DefaultValue")
new ValidationError("Default value must be less than max value", "DefaultValue")
});
}
[Fact]
public void Should_add_error_if_min_greater_than_max()
{
var properties = new NumberFieldProperties { MinValue = 10, MaxValue = 5 };
var sut = new NumberFieldProperties { MinValue = 10, MaxValue = 5 };
properties.Validate(errors);
sut.Validate(errors);
errors.ShouldBeEquivalentTo(
new List<ValidationError>
{
new ValidationError("Max value must be greater than min value.", "MinValue", "MaxValue")
new ValidationError("Max value must be greater than min value", "MinValue", "MaxValue")
});
}
[Fact]
public void Should_add_error_if_allowed_values_and_max_is_specified()
{
var properties = new NumberFieldProperties { MaxValue = 10, AllowedValues = ImmutableList.Create<double>(4) };
var sut = new NumberFieldProperties { MaxValue = 10, AllowedValues = ImmutableList.Create<double>(4) };
properties.Validate(errors);
sut.Validate(errors);
errors.ShouldBeEquivalentTo(
new List<ValidationError>
{
new ValidationError("Either or allowed values or range can be defined.", "AllowedValues", "MinValue", "MaxValue")
new ValidationError("Either or allowed values or range can be defined", "AllowedValues", "MinValue", "MaxValue")
});
}
[Fact]
public void Should_add_error_if_allowed_values_and_min_is_specified()
{
var properties = new NumberFieldProperties { MinValue = 10, AllowedValues = ImmutableList.Create<double>(4) };
var sut = new NumberFieldProperties { MinValue = 10, AllowedValues = ImmutableList.Create<double>(4) };
properties.Validate(errors);
sut.Validate(errors);
errors.ShouldBeEquivalentTo(
new List<ValidationError>
{
new ValidationError("Either or allowed values or range can be defined.", "AllowedValues", "MinValue", "MaxValue")
new ValidationError("Either or allowed values or range can be defined", "AllowedValues", "MinValue", "MaxValue")
});
}
[Fact]
public void Should_set_or_freeze_sut()
{
var sut = new NumberFieldProperties();
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 e)
{
throw e.InnerException;
}
});
}
}
}
}

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

@ -0,0 +1,101 @@
// ==========================================================================
// NumberFieldTests.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Threading.Tasks;
using Squidex.Core.Schemas;
using Squidex.Infrastructure;
using Xunit;
using FluentAssertions;
namespace Squidex.Core.Tests.Schemas
{
public class NumberFieldTests
{
private readonly List<string> errors = new List<string>();
[Fact]
public void Should_instantiate_field()
{
var sut = new NumberField(1, "name", new NumberFieldProperties());
Assert.Equal("name", sut.Name);
}
[Fact]
public void Should_clone_object()
{
var sut = new NumberField(1, "name", new NumberFieldProperties());
Assert.NotEqual(sut, sut.Enable());
}
[Fact]
public async Task Should_add_errors_if_number_is_required()
{
var sut = new NumberField(1, "name", new NumberFieldProperties { Label = "Name", IsRequired = true });
await sut.ValidateAsync(CreateValue(null), errors);
errors.ShouldBeEquivalentTo(
new [] { "Name is required" });
}
[Fact]
public async Task Should_add_errors_if_number_is_less_than_min()
{
var sut = new NumberField(1, "name", new NumberFieldProperties { Label = "Name", MinValue = 10 });
await sut.ValidateAsync(CreateValue(5), errors);
errors.ShouldBeEquivalentTo(
new[] { "Name must be greater than '10'" });
}
[Fact]
public async Task Should_add_errors_if_number_is_greater_than_max()
{
var sut = new NumberField(1, "name", new NumberFieldProperties { Label = "Name", MaxValue = 10 });
await sut.ValidateAsync(CreateValue(20), errors);
errors.ShouldBeEquivalentTo(
new[] { "Name must be less than '10'" });
}
[Fact]
public async Task Should_add_errors_if_number_is_not_allowed()
{
var sut = new NumberField(1, "name", new NumberFieldProperties { Label = "Name", AllowedValues = ImmutableList.Create(10d) });
await sut.ValidateAsync(CreateValue(20), errors);
errors.ShouldBeEquivalentTo(
new[] { "Name is not an allowed value" });
}
[Fact]
public async Task Should_add_errors_if_value_is_not_valid()
{
var sut = new NumberField(1, "name", new NumberFieldProperties { Label = "Name" });
await sut.ValidateAsync(CreateValue("Invalid"), errors);
errors.ShouldBeEquivalentTo(
new[] { "Name is not a valid value" });
}
private static PropertyValue CreateValue(object v)
{
var bag = new PropertiesBag().Set("value", v);
return bag["value"];
}
}
}

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

@ -0,0 +1,280 @@
// ==========================================================================
// SchemaTests.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Squidex.Core.Schemas;
using Squidex.Infrastructure;
using Xunit;
using FluentAssertions;
namespace Squidex.Core.Tests.Schemas
{
public class SchemaTests
{
private Schema sut = Schema.Create("my-name", new SchemaProperties());
private sealed class InvalidProperties : FieldProperties
{
protected override IEnumerable<ValidationError> ValidateCore()
{
yield break;
}
}
[Fact]
public void Should_instantiate_field()
{
var properties = new SchemaProperties { Hints = "my-hint", Label = "my-label" };
var schema = Schema.Create("my-name", properties);
Assert.Equal("my-name", schema.Name);
Assert.Equal(properties, schema.Properties);
Assert.True(properties.IsFrozen);
}
[Fact]
public void Should_throw_if_creating_schema_with_invalid_name()
{
Assert.Throws<ValidationException>(() => Schema.Create("Invalid Name", new SchemaProperties()));
}
[Fact]
public void Should_update_schema()
{
var properties = new SchemaProperties { Hints = "my-hint", Label = "my-label" };
sut = sut.Update(properties);
Assert.Equal(properties, sut.Properties);
Assert.True(properties.IsFrozen);
}
[Fact]
public void Should_add_field()
{
var field = AddField();
Assert.Equal(field, sut.Fields[1]);
}
[Fact]
public void Should_throw_if_adding_field_with_name_that_already_exists()
{
AddField();
Assert.Throws<ValidationException>(() => sut.AddOrUpdateField(new NumberField(2, "my-field", new NumberFieldProperties())));
}
[Fact]
public void Should_hide_field()
{
AddField();
sut = sut.HideField(1);
sut = sut.HideField(1);
Assert.True(sut.Fields[1].IsHidden);
}
[Fact]
public void Should_throw_if_field_to_hide_does_not_exist()
{
Assert.Throws<DomainObjectNotFoundException>(() => sut.HideField(1));
}
[Fact]
public void Should_show_field()
{
AddField();
sut = sut.HideField(1);
sut = sut.ShowField(1);
sut = sut.ShowField(1);
Assert.False(sut.Fields[1].IsHidden);
}
[Fact]
public void Should_throw_if_field_to_show_does_not_exist()
{
Assert.Throws<DomainObjectNotFoundException>(() => sut.ShowField(2));
}
[Fact]
public void Should_disable_field()
{
AddField();
sut = sut.DisableField(1);
sut = sut.DisableField(1);
Assert.True(sut.Fields[1].IsDisabled);
}
[Fact]
public void Should_throw_if_field_to_disable_does_not_exist()
{
Assert.Throws<DomainObjectNotFoundException>(() => sut.DisableField(1));
}
[Fact]
public void Should_enable_field()
{
AddField();
sut = sut.DisableField(1);
sut = sut.EnableField(1);
sut = sut.EnableField(1);
Assert.False(sut.Fields[1].IsDisabled);
}
[Fact]
public void Should_throw_if_field_to_enable_does_not_exist()
{
Assert.Throws<DomainObjectNotFoundException>(() => sut.EnableField(1));
}
[Fact]
public void Should_rename_field()
{
AddField();
sut = sut.RenameField(1, "new-name");
Assert.Equal("new-name", sut.Fields[1].Name);
}
[Fact]
public void Should_throw_if_new_field_already_exists()
{
AddField();
sut = sut.AddOrUpdateField(new NumberField(2, "other-field", new NumberFieldProperties()));
Assert.Throws<ValidationException>(() => sut.RenameField(2, "my-field"));
}
[Fact]
public void Should_throw_if_new_field_name_is_not_valid()
{
AddField();
Assert.Throws<ValidationException>(() => sut.RenameField(1, "new name"));
}
[Fact]
public void Should_throw_if_field_to_rename_does_not_exist()
{
Assert.Throws<DomainObjectNotFoundException>(() => sut.RenameField(1, "new-name"));
}
[Fact]
public void Should_delete_field()
{
AddField();
sut = sut.DeleteField(1);
Assert.Equal(0, sut.Fields.Count);
}
[Fact]
public void Should_not_throw_if_field_to_delete_does_not_exist()
{
sut.DeleteField(1);
}
[Fact]
public void Should_update_field()
{
AddField();
sut = sut.UpdateField(1, new NumberFieldProperties { Hints = "my-hints" });
Assert.Equal("my-hints", sut.Fields[1].RawProperties.Hints);
}
[Fact]
public void Should_throw_if_updating_field_with_invalid_property_type()
{
AddField();
Assert.Throws<ArgumentException>(() => sut.UpdateField(1, new InvalidProperties()));
}
[Fact]
public void Should_throw_if_field_to_update_does_not_exist()
{
Assert.Throws<DomainObjectNotFoundException>(() => sut.UpdateField(1, new NumberFieldProperties()));
}
[Fact]
public async Task Should_add_error_if_validating_bag_with_unknown_field()
{
var errors = new List<ValidationError>();
var bag = new PropertiesBag().Set("unknown", 123);
await sut.ValidateAsync(bag, errors);
errors.ShouldBeEquivalentTo(
new List<ValidationError>
{
new ValidationError("unknown is not a known field", "unknown")
});
}
[Fact]
public async Task Should_add_error_if_validating_bag_with_invalid_field()
{
sut = sut.AddOrUpdateField(new NumberField(1, "my-field", new NumberFieldProperties { MaxValue = 100 }));
var errors = new List<ValidationError>();
var bag = new PropertiesBag().Set("my-field", 123);
await sut.ValidateAsync(bag, errors);
errors.ShouldBeEquivalentTo(
new List<ValidationError>
{
new ValidationError("my-field must be less than '100'", "my-field")
});
}
[Fact]
public async Task Should_add_error_if_required_field_is_not_in_bag()
{
sut = sut.AddOrUpdateField(new NumberField(1, "my-field", new NumberFieldProperties { IsRequired = true }));
var errors = new List<ValidationError>();
var bag = new PropertiesBag();
await sut.ValidateAsync(bag, errors);
errors.ShouldBeEquivalentTo(
new List<ValidationError>
{
new ValidationError("my-field is required", "my-field")
});
}
private NumberField AddField()
{
var field = new NumberField(1, "my-field", new NumberFieldProperties());
sut = sut.AddOrUpdateField(field);
return field;
}
}
}

95
tests/Squidex.Core.Tests/Schemas/StringFieldPropertiesTests.cs

@ -0,0 +1,95 @@
// ==========================================================================
// StringFieldPropertiesTests.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using FluentAssertions;
using Squidex.Core.Schemas;
using Squidex.Core.Schemas.Validators;
using Squidex.Infrastructure;
using Xunit;
namespace Squidex.Core.Tests.Schemas
{
public class StringFieldPropertiesTests
{
private readonly List<ValidationError> errors = new List<ValidationError>();
[Fact]
public void Should_add_error_if_min_greater_than_max()
{
var sut = new StringFieldProperties { MinLength = 10, MaxLength = 5 };
sut.Validate(errors);
errors.ShouldBeEquivalentTo(
new List<ValidationError>
{
new ValidationError("Max length must be greater than min length", "MinLength", "MaxLength")
});
}
[Fact]
public void Should_add_error_if_pattern_is_not_valid_regex()
{
var sut = new StringFieldProperties { Pattern = "[0-9{1}"};
sut.Validate(errors);
errors.ShouldBeEquivalentTo(
new List<ValidationError>
{
new ValidationError("Pattern is not a valid expression", "Pattern")
});
}
[Fact]
public void Should_set_or_freeze_sut()
{
var sut = new StringFieldProperties();
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 e)
{
throw e.InnerException;
}
});
}
}
}
}

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

@ -0,0 +1,100 @@
// ==========================================================================
// StringFieldTests.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
using System.Collections.Generic;
using System.Threading.Tasks;
using Squidex.Core.Schemas;
using Squidex.Infrastructure;
using Xunit;
using FluentAssertions;
namespace Squidex.Core.Tests.Schemas
{
public class StringFieldTests
{
private readonly List<string> errors = new List<string>();
[Fact]
public void Should_instantiate_field()
{
var sut = new StringField(1, "name", new StringFieldProperties());
Assert.Equal("name", sut.Name);
}
[Fact]
public void Should_clone_object()
{
var sut = new StringField(1, "name", new StringFieldProperties());
Assert.NotEqual(sut, sut.Enable());
}
[Fact]
public async Task Should_add_errors_if_string_is_required()
{
var sut = new StringField(1, "name", new StringFieldProperties { Label = "Name", IsRequired = true });
await sut.ValidateAsync(CreateValue(null), errors);
errors.ShouldBeEquivalentTo(
new[] { "Name is required" });
}
[Fact]
public async Task Should_add_errors_if_string_shorter_than_max()
{
var sut = new StringField(1, "name", new StringFieldProperties { Label = "Name", MinLength = 10 });
await sut.ValidateAsync(CreateValue("123"), errors);
errors.ShouldBeEquivalentTo(
new[] { "Name must have more than '10' characters" });
}
[Fact]
public async Task Should_add_errors_if_number_is_greater_than_max()
{
var sut = new StringField(1, "name", new StringFieldProperties { Label = "Name", MaxLength = 5 });
await sut.ValidateAsync(CreateValue("12345678"), errors);
errors.ShouldBeEquivalentTo(
new[] { "Name must have less than '5' characters" });
}
[Fact]
public async Task Should_add_errors_if_number_is_not_valid_pattern()
{
var sut = new StringField(1, "name", new StringFieldProperties { Label = "Name", Pattern = "^[0-9]{3}$" });
await sut.ValidateAsync(CreateValue("abc"), errors);
errors.ShouldBeEquivalentTo(
new[] { "Name is not valid" });
}
[Fact]
public async Task Should_add_errors_if_number_is_not_valid_pattern_with_message()
{
var sut = new StringField(1, "name", new StringFieldProperties { Label = "Name", Pattern = "^[0-9]{3}$", PatternMessage = "Custom Error Message" });
await sut.ValidateAsync(CreateValue("abc"), errors);
errors.ShouldBeEquivalentTo(
new[] { "Custom Error Message" });
}
private static PropertyValue CreateValue(object v)
{
var bag = new PropertiesBag().Set("value", v);
return bag["value"];
}
}
}

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

@ -0,0 +1,63 @@
// ==========================================================================
// PatternValidatorTests.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
using System.Collections.Generic;
using System.Threading.Tasks;
using FluentAssertions;
using Squidex.Core.Schemas.Validators;
using Xunit;
namespace Squidex.Core.Tests.Schemas.Validators
{
public class PatternValidatorTests
{
private readonly List<string> errors = new List<string>();
[Fact]
public async Task Should_not_add_error_if_value_is_valid()
{
var sut = new PatternValidator("^[a-z]{3}:[0-9]{2}$");
await sut.ValidateAsync("abc:12", errors);
Assert.Equal(0, errors.Count);
}
[Fact]
public async Task Should_not_add_error_if_value_is_null()
{
var sut = new PatternValidator("^[a-z]{3}:[0-9]{2}$");
await sut.ValidateAsync(null, errors);
Assert.Equal(0, errors.Count);
}
[Fact]
public async Task Should_add_error_with_default_message_if_value_is_not_valid()
{
var sut = new PatternValidator("^[a-z]{3}:[0-9]{2}$");
await sut.ValidateAsync("foo", errors);
errors.ShouldBeEquivalentTo(
new[] { "<FIELD> is not valid" });
}
[Fact]
public async Task Should_add_error_with_custom_message_if_value_is_not_valid()
{
var sut = new PatternValidator("^[a-z]{3}:[0-9]{2}$", "Custom Error Message");
await sut.ValidateAsync("foo", errors);
errors.ShouldBeEquivalentTo(
new[] { "Custom Error Message" });
}
}
}

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

@ -19,12 +19,14 @@ namespace Squidex.Core.Tests.Schemas.Validators
{
private readonly List<string> errors = new List<string>();
[Theory]
[InlineData(20, 10)]
[InlineData(10, 10)]
public void Should_throw_error_if_min_greater_than_max(int? min, int? max)
[Fact]
public async Task Should_not_error_if_value_is_null()
{
Assert.Throws<ArgumentException>(() => new RangeValidator<int>(min, max));
var sut = new RangeValidator<int>(100, 200);
await sut.ValidateAsync(null, errors);
Assert.Equal(0, errors.Count);
}
[Theory]
@ -32,7 +34,7 @@ namespace Squidex.Core.Tests.Schemas.Validators
[InlineData(1000, null)]
[InlineData(1000, 2000)]
[InlineData(null, 2000)]
public async Task Should_not_error_if_value_is_within_range(int? min, int? max)
public async Task Should_not_add_error_if_value_is_within_range(int? min, int? max)
{
var sut = new RangeValidator<int>(min, max);
@ -41,17 +43,15 @@ namespace Squidex.Core.Tests.Schemas.Validators
Assert.Equal(0, errors.Count);
}
[Fact]
public async Task Should_not_error_if_value_null()
[Theory]
[InlineData(20, 10)]
[InlineData(10, 10)]
public void Should_throw_error_if_min_greater_than_max(int? min, int? max)
{
var sut = new RangeValidator<int>(100, 200);
await sut.ValidateAsync(null, errors);
Assert.Equal(0, errors.Count);
Assert.Throws<ArgumentException>(() => new RangeValidator<int>(min, max));
}
[Theory]
[Fact]
public async Task Should_add_error_if_value_is_smaller_than_min()
{
var sut = new RangeValidator<int>(2000, null);
@ -59,10 +59,10 @@ namespace Squidex.Core.Tests.Schemas.Validators
await sut.ValidateAsync(1500, errors);
errors.ShouldBeEquivalentTo(
new[] { "<FIELD> must be greater than '1500'" });
new[] { "<FIELD> must be greater than '2000'" });
}
[Theory]
[Fact]
public async Task Should_add_error_if_value_is_greater_than_max()
{
var sut = new RangeValidator<int>(null, 1000);

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

@ -23,7 +23,7 @@ namespace Squidex.Core.Tests.Schemas.Validators
[InlineData("")]
[InlineData(" ")]
[InlineData(" ")]
public async Task Should_not_add_error_if_object_is_valid(string value)
public async Task Should_not_add_error_if_value_is_valid(string value)
{
var sut = new RequiredStringValidator();
@ -33,7 +33,7 @@ namespace Squidex.Core.Tests.Schemas.Validators
}
[Fact]
public async Task Should_not_add_error_if_object_is_another_type()
public async Task Should_not_add_error_if_value_is_another_type()
{
var sut = new RequiredStringValidator();
@ -54,7 +54,7 @@ namespace Squidex.Core.Tests.Schemas.Validators
}
[Fact]
public async Task Should_add_error_if_object_is_null()
public async Task Should_add_error_if_value_is_null()
{
var sut = new RequiredStringValidator();

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

@ -19,7 +19,7 @@ namespace Squidex.Core.Tests.Schemas.Validators
private readonly List<string> errors = new List<string>();
[Fact]
public async Task Should_not_add_error_if_object_is_valid()
public async Task Should_not_add_error_if_value_is_valid()
{
var sut = new RequiredValidator();
@ -39,7 +39,7 @@ namespace Squidex.Core.Tests.Schemas.Validators
}
[Fact]
public async Task Should_add_error_if_object_is_null()
public async Task Should_add_error_if_value_is_null()
{
var sut = new RequiredValidator();

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

@ -0,0 +1,89 @@
// ==========================================================================
// MinMaxValidatorTests.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using FluentAssertions;
using Squidex.Core.Schemas.Validators;
using Xunit;
namespace Squidex.Core.Tests.Schemas.Validators
{
public class StringLengthValidatorTests
{
private readonly List<string> errors = new List<string>();
[Fact]
public async Task Should_not_error_if_value_is_null()
{
var sut = new StringLengthValidator(100, 200);
await sut.ValidateAsync(null, errors);
Assert.Equal(0, errors.Count);
}
[Theory]
[InlineData(null, null)]
[InlineData(1000, null)]
[InlineData(1000, 2000)]
[InlineData(null, 2000)]
public async Task Should_not_add_error_if_value_is_within_range(int? min, int? max)
{
var sut = new StringLengthValidator(min, max);
await sut.ValidateAsync(CreateString(1500), errors);
Assert.Equal(0, errors.Count);
}
[Theory]
[InlineData(20, 10)]
[InlineData(10, 10)]
public void Should_throw_error_if_min_greater_than_max(int? min, int? max)
{
Assert.Throws<ArgumentException>(() => new StringLengthValidator(min, max));
}
[Fact]
public async Task Should_add_error_if_value_is_smaller_than_min()
{
var sut = new StringLengthValidator(2000, null);
await sut.ValidateAsync(CreateString(1500), errors);
errors.ShouldBeEquivalentTo(
new[] { "<FIELD> must have more than '2000' characters" });
}
[Fact]
public async Task Should_add_error_if_value_is_greater_than_max()
{
var sut = new StringLengthValidator(null, 1000);
await sut.ValidateAsync(CreateString(1500), errors);
errors.ShouldBeEquivalentTo(
new[] { "<FIELD> must have less than '1000' characters" });
}
private static string CreateString(int size)
{
var sb = new StringBuilder();
for (var i = 0; i < size; i++)
{
sb.Append("x");
}
return sb.ToString();
}
}
}

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

@ -49,26 +49,24 @@ namespace Squidex.Write.Tests.Schemas
[Fact]
public void Create_should_create_schema()
{
var props = new SchemaProperties(null, null);
var properties = new SchemaProperties();
sut.Create(new CreateSchema { Name = TestName, AppId = appId, Properties = props });
sut.Create(new CreateSchema { Name = TestName, AppId = appId, Properties = properties });
Assert.Equal("schema", sut.Schema.Name);
Assert.Equal(props, sut.Schema.Properties);
Assert.Equal(appId, sut.AppId);
sut.GetUncomittedEvents().Select(x => x.Payload).ToArray()
.ShouldBeEquivalentTo(
new IEvent[]
{
new SchemaCreated { Name = TestName, AppId = appId, Properties = props }
new SchemaCreated { Name = TestName, AppId = appId, Properties = properties }
});
}
[Fact]
public void Update_should_throw_if_not_created()
{
Assert.Throws<DomainException>(() => sut.Update(new UpdateSchema { Properties = new SchemaProperties(null, null) }));
Assert.Throws<DomainException>(() => sut.Update(new UpdateSchema { Properties = new SchemaProperties() }));
}
[Fact]
@ -91,18 +89,18 @@ namespace Squidex.Write.Tests.Schemas
[Fact]
public void Update_should_refresh_properties()
{
var props = new SchemaProperties(null, null);
var properties = new SchemaProperties();
sut.Create(new CreateSchema { Name = TestName, AppId = appId });
sut.Update(new UpdateSchema { Properties = props });
sut.Update(new UpdateSchema { Properties = properties });
Assert.Equal(props, sut.Schema.Properties);
Assert.Equal(properties, sut.Schema.Properties);
sut.GetUncomittedEvents().Select(x => x.Payload).Skip(1).ToArray()
.ShouldBeEquivalentTo(
new IEvent[]
{
new SchemaUpdated { Properties = props }
new SchemaUpdated { Properties = properties }
});
}

Loading…
Cancel
Save