mirror of https://github.com/Squidex/squidex.git
10 changed files with 258 additions and 1 deletions
@ -0,0 +1,50 @@ |
|||
// ==========================================================================
|
|||
// TagsField.cs
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex Group
|
|||
// All rights reserved.
|
|||
// ==========================================================================
|
|||
|
|||
using System.Collections.Generic; |
|||
using System.Collections.Immutable; |
|||
using Newtonsoft.Json.Linq; |
|||
using Squidex.Domain.Apps.Core.Schemas.Validators; |
|||
|
|||
namespace Squidex.Domain.Apps.Core.Schemas |
|||
{ |
|||
public sealed class TagsField : Field<TagsFieldProperties> |
|||
{ |
|||
private static readonly ImmutableList<string> EmptyTags = ImmutableList<string>.Empty; |
|||
|
|||
public TagsField(long id, string name, Partitioning partitioning) |
|||
: this(id, name, partitioning, new TagsFieldProperties()) |
|||
{ |
|||
} |
|||
|
|||
public TagsField(long id, string name, Partitioning partitioning, TagsFieldProperties properties) |
|||
: base(id, name, partitioning, properties) |
|||
{ |
|||
} |
|||
|
|||
protected override IEnumerable<IValidator> CreateValidators() |
|||
{ |
|||
if (Properties.IsRequired || Properties.MinItems.HasValue || Properties.MaxItems.HasValue) |
|||
{ |
|||
yield return new CollectionValidator<string>(Properties.IsRequired, Properties.MinItems, Properties.MaxItems); |
|||
} |
|||
|
|||
yield return new CollectionItemValidator<string>(new RequiredStringValidator()); |
|||
} |
|||
|
|||
public override object ConvertValue(JToken value) |
|||
{ |
|||
return value.ToObject<List<string>>(); |
|||
} |
|||
|
|||
public override T Accept<T>(IFieldVisitor<T> visitor) |
|||
{ |
|||
return visitor.Visit(this); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,58 @@ |
|||
// ==========================================================================
|
|||
// TagsField.cs
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex Group
|
|||
// All rights reserved.
|
|||
// ==========================================================================
|
|||
|
|||
using Newtonsoft.Json.Linq; |
|||
using Squidex.Infrastructure; |
|||
|
|||
namespace Squidex.Domain.Apps.Core.Schemas |
|||
{ |
|||
[TypeName(nameof(TagsField))] |
|||
public sealed class TagsFieldProperties : FieldProperties |
|||
{ |
|||
private int? minItems; |
|||
private int? maxItems; |
|||
|
|||
public int? MinItems |
|||
{ |
|||
get |
|||
{ |
|||
return minItems; |
|||
} |
|||
set |
|||
{ |
|||
ThrowIfFrozen(); |
|||
|
|||
minItems = value; |
|||
} |
|||
} |
|||
|
|||
public int? MaxItems |
|||
{ |
|||
get |
|||
{ |
|||
return maxItems; |
|||
} |
|||
set |
|||
{ |
|||
ThrowIfFrozen(); |
|||
|
|||
maxItems = value; |
|||
} |
|||
} |
|||
|
|||
public override JToken GetDefaultValue() |
|||
{ |
|||
return new JArray(); |
|||
} |
|||
|
|||
public override T Accept<T>(IFieldPropertiesVisitor<T> visitor) |
|||
{ |
|||
return visitor.Visit(this); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,121 @@ |
|||
// ==========================================================================
|
|||
// TagsFieldTests.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 Xunit; |
|||
|
|||
namespace Squidex.Domain.Apps.Core.Schemas |
|||
{ |
|||
public class TagsFieldTests |
|||
{ |
|||
private readonly List<string> errors = new List<string>(); |
|||
|
|||
[Fact] |
|||
public void Should_instantiate_field() |
|||
{ |
|||
var sut = new TagsField(1, "my-tags", Partitioning.Invariant); |
|||
|
|||
Assert.Equal("my-tags", sut.Name); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Should_clone_object() |
|||
{ |
|||
var sut = new TagsField(1, "my-tags", Partitioning.Invariant); |
|||
|
|||
Assert.NotEqual(sut, sut.Enable()); |
|||
} |
|||
|
|||
[Fact] |
|||
public async Task Should_not_add_error_if_tags_are_valid() |
|||
{ |
|||
var referenceId = Guid.NewGuid(); |
|||
|
|||
var sut = new TagsField(1, "my-tags", Partitioning.Invariant); |
|||
|
|||
await sut.ValidateAsync(CreateValue(referenceId), errors, ValidationTestExtensions.ValidContext); |
|||
|
|||
Assert.Empty(errors); |
|||
} |
|||
|
|||
[Fact] |
|||
public async Task Should_not_add_error_if_tags_are_null_and_valid() |
|||
{ |
|||
var sut = new TagsField(1, "my-tags", Partitioning.Invariant); |
|||
|
|||
await sut.ValidateAsync(CreateValue(null), errors); |
|||
|
|||
Assert.Empty(errors); |
|||
} |
|||
|
|||
[Fact] |
|||
public async Task Should_add_errors_if_tags_are_required_and_null() |
|||
{ |
|||
var sut = new TagsField(1, "my-tags", Partitioning.Invariant, new TagsFieldProperties { IsRequired = true }); |
|||
|
|||
await sut.ValidateAsync(CreateValue(null), errors); |
|||
|
|||
errors.ShouldBeEquivalentTo( |
|||
new[] { "<FIELD> is required." }); |
|||
} |
|||
|
|||
[Fact] |
|||
public async Task Should_add_errors_if_tags_are_required_and_empty() |
|||
{ |
|||
var sut = new TagsField(1, "my-tags", Partitioning.Invariant, new TagsFieldProperties { 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 TagsField(1, "my-tags", Partitioning.Invariant); |
|||
|
|||
await sut.ValidateAsync("invalid", errors); |
|||
|
|||
errors.ShouldBeEquivalentTo( |
|||
new[] { "<FIELD> is not a valid value." }); |
|||
} |
|||
|
|||
[Fact] |
|||
public async Task Should_add_errors_if_value_has_not_enough_items() |
|||
{ |
|||
var sut = new TagsField(1, "my-tags", Partitioning.Invariant, new TagsFieldProperties { MinItems = 3 }); |
|||
|
|||
await sut.ValidateAsync(CreateValue(Guid.NewGuid(), Guid.NewGuid()), errors); |
|||
|
|||
errors.ShouldBeEquivalentTo( |
|||
new[] { "<FIELD> must have at least 3 item(s)." }); |
|||
} |
|||
|
|||
[Fact] |
|||
public async Task Should_add_errors_if_value_has_too_much_items() |
|||
{ |
|||
var sut = new TagsField(1, "my-tags", Partitioning.Invariant, new TagsFieldProperties { MaxItems = 1 }); |
|||
|
|||
await sut.ValidateAsync(CreateValue(Guid.NewGuid(), Guid.NewGuid()), errors); |
|||
|
|||
errors.ShouldBeEquivalentTo( |
|||
new[] { "<FIELD> must have not more than 1 item(s)." }); |
|||
} |
|||
|
|||
private static JToken CreateValue(params Guid[] ids) |
|||
{ |
|||
return ids == null ? JValue.CreateNull() : (JToken)new JArray(ids.OfType<object>().ToArray()); |
|||
} |
|||
} |
|||
} |
|||
Loading…
Reference in new issue