diff --git a/Dappi.HeadlessCms.Tests/Controllers/ModelsControllerTests.cs b/Dappi.HeadlessCms.Tests/Controllers/ModelsControllerTests.cs index 85d557b3..93c2cb17 100644 --- a/Dappi.HeadlessCms.Tests/Controllers/ModelsControllerTests.cs +++ b/Dappi.HeadlessCms.Tests/Controllers/ModelsControllerTests.cs @@ -1,3 +1,4 @@ +using System.Net.Http; using System.Net.Http.Json; using System.Text.RegularExpressions; using Dappi.HeadlessCms.Models; @@ -436,6 +437,154 @@ public async Task AddField_Should_Add_ManyToMany_Relation_To_Models() await Verify(res, _verifySettings).UseFileName("response"); } + [Theory] + [ClassData(typeof(ValidMinMaxConstraints))] + public async Task AddField_Should_Accept_Valid_MinMax_Constraints( + string fieldType, + double? min, + double? max, + string testName) + { + var auth = await _client.Authorize(); + _client.DefaultRequestHeaders.Add("Authorization", $"Bearer {auth?.Token}"); + + var modelRequest = new ModelRequest { ModelName = $"MinMaxTest{testName}", IsAuditableEntity = false }; + await _client.PostAsJsonAsync(_baseUrl, modelRequest); + + var fieldRequest = new FieldRequest + { + FieldName = "TestField", + FieldType = fieldType, + IsRequired = false, + Min = min, + Max = max + }; + + var res = await _client.PutAsJsonAsync($"{_baseUrl}/{modelRequest.ModelName}", fieldRequest); + var filePath = Path.Combine(_entitiesPath, $"{modelRequest.ModelName}.cs"); + var actual = await File.ReadAllTextAsync(filePath); + + _verifySettings.UseDirectory( + $"{_snapshotPath}/{nameof(AddField_Should_Accept_Valid_MinMax_Constraints)}/{testName}"); + await Verify(actual, _verifySettings).UseFileName("model"); + await Verify(res, _verifySettings).UseFileName("response"); + } + + [Theory] + [ClassData(typeof(InvalidMinMaxConstraints))] + public async Task AddField_Should_Return_BadRequest_For_Invalid_MinMax_Constraints( + string fieldType, + double? min, + double? max, + string testName) + { + var auth = await _client.Authorize(); + _client.DefaultRequestHeaders.Add("Authorization", $"Bearer {auth?.Token}"); + + var modelRequest = new ModelRequest { ModelName = $"InvalidMinMax{testName}", IsAuditableEntity = false }; + await _client.PostAsJsonAsync(_baseUrl, modelRequest); + + var fieldRequest = new FieldRequest + { + FieldName = "TestField", + FieldType = fieldType, + IsRequired = false, + Min = min, + Max = max + }; + + var res = await _client.PutAsJsonAsync($"{_baseUrl}/{modelRequest.ModelName}", fieldRequest); + + _verifySettings.UseDirectory( + $"{_snapshotPath}/{nameof(AddField_Should_Return_BadRequest_For_Invalid_MinMax_Constraints)}/{testName}"); + await Verify(res, _verifySettings).UseFileName("response"); + } + + [Theory] + [ClassData(typeof(InvalidMinMaxConstraints))] + public async Task UpdateField_Should_Return_BadRequest_For_Invalid_MinMax_Update( + string fieldType, + double? min, + double? max, + string testName) + { + var auth = await _client.Authorize(); + _client.DefaultRequestHeaders.Add("Authorization", $"Bearer {auth?.Token}"); + + var modelRequest = new ModelRequest { ModelName = $"UpdateInvalidMinMax{testName}", IsAuditableEntity = false }; + await _client.PostAsJsonAsync(_baseUrl, modelRequest); + + var fieldRequest = new FieldRequest + { + FieldName = "TestField", + FieldType = fieldType, + IsRequired = false, + Min = 0, + Max = 100 + }; + await _client.PutAsJsonAsync($"{_baseUrl}/{modelRequest.ModelName}", fieldRequest); + + var updateRequest = new UpdateFieldRequest + { + OldFieldName = "TestField", + NewFieldName = "TestField", + FieldType = fieldType, + IsRequired = false, + Min = min, + Max = max + }; + + var res = await PatchAsJsonAsync(_client, $"{_baseUrl}/{modelRequest.ModelName}/fields", updateRequest); + + _verifySettings.UseDirectory( + $"{_snapshotPath}/{nameof(UpdateField_Should_Return_BadRequest_For_Invalid_MinMax_Update)}/{testName}"); + await Verify(res, _verifySettings).UseFileName("response"); + } + + [Theory] + [ClassData(typeof(ValidMinMaxConstraints))] + public async Task UpdateField_Should_Accept_Valid_MinMax_Update( + string fieldType, + double? min, + double? max, + string testName) + { + var auth = await _client.Authorize(); + _client.DefaultRequestHeaders.Add("Authorization", $"Bearer {auth?.Token}"); + + var modelRequest = new ModelRequest { ModelName = $"UpdateValidMinMax{testName}", IsAuditableEntity = false }; + await _client.PostAsJsonAsync(_baseUrl, modelRequest); + + var fieldRequest = new FieldRequest + { + FieldName = "TestField", + FieldType = fieldType, + IsRequired = false, + Min = 0, + Max = 10 + }; + await _client.PutAsJsonAsync($"{_baseUrl}/{modelRequest.ModelName}", fieldRequest); + + var updateRequest = new UpdateFieldRequest + { + OldFieldName = "TestField", + NewFieldName = "TestField", + FieldType = fieldType, + IsRequired = false, + Min = min, + Max = max + }; + + var res = await PatchAsJsonAsync(_client, $"{_baseUrl}/{modelRequest.ModelName}/fields", updateRequest); + var filePath = Path.Combine(_entitiesPath, $"{modelRequest.ModelName}.cs"); + var actual = await File.ReadAllTextAsync(filePath); + + _verifySettings.UseDirectory( + $"{_snapshotPath}/{nameof(UpdateField_Should_Accept_Valid_MinMax_Update)}/{testName}"); + await Verify(actual, _verifySettings).UseFileName("model"); + await Verify(res, _verifySettings).UseFileName("response"); + } + [Fact] public async Task DeleteModel_Should_Return_NotFound_If_Model_Does_Not_Exist() { @@ -560,6 +709,17 @@ public async Task Other_Relations_Should_Not_Be_Deleted() await Verify(deleteRes, _verifySettings).UseFileName("response"); } + private static Task PatchAsJsonAsync(HttpClient client, string requestUri, T value) + { + var content = JsonContent.Create(value); + var request = new HttpRequestMessage(HttpMethod.Patch, requestUri) + { + Content = content + }; + + return client.SendAsync(request); + } + public void Dispose() { if (Directory.Exists(_entitiesPath)) diff --git a/Dappi.HeadlessCms.Tests/Core/DomainModelEditorTests.cs b/Dappi.HeadlessCms.Tests/Core/DomainModelEditorTests.cs index f89eace8..0827bbd9 100644 --- a/Dappi.HeadlessCms.Tests/Core/DomainModelEditorTests.cs +++ b/Dappi.HeadlessCms.Tests/Core/DomainModelEditorTests.cs @@ -143,13 +143,13 @@ public class {{DomainModelName}} var actual = await File.ReadAllTextAsync(_filePath); Assert.Equal(expected.ReplaceLineEndings(), actual.ReplaceLineEndings()); } - + [Theory] [ClassData(typeof(ValidPropertyTypes))] public async Task DomainModelEditor_Should_Add_Optional_Property(string type) { - var expected = $$""" + var expected = $$""" using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; using Dappi.HeadlessCms.Models; @@ -169,18 +169,459 @@ public class {{DomainModelName}} } } """; - Property property = new() - { - DomainModel = DomainModelName, Name = TestPropertyName, Type = type, IsRequired = false, - }; - var modelRequest = new ModelRequest { ModelName = DomainModelName, IsAuditableEntity = false }; + Property property = new() + { + DomainModel = DomainModelName, + Name = TestPropertyName, + Type = type, + IsRequired = false, + }; + var modelRequest = new ModelRequest { ModelName = DomainModelName, IsAuditableEntity = false }; + _domainModelEditor.CreateEntityModel(modelRequest); + _domainModelEditor.AddProperty(property); + await _domainModelEditor.SaveAsync(); + var actual = await File.ReadAllTextAsync(_filePath); + Assert.Equal(expected.ReplaceLineEndings(), actual.ReplaceLineEndings()); + } + + [Fact] + public async Task DomainModelEditor_AddProperty_Should_Add_Length_Attribute_With_Both_Min_And_Max() + { + var modelRequest = new ModelRequest { ModelName = DomainModelName, IsAuditableEntity = false }; + _domainModelEditor.CreateEntityModel(modelRequest); + + var property = new Property + { + DomainModel = DomainModelName, + Name = "Description", + Type = "string", + IsRequired = false, + Min = "10", + Max = "100" + }; + + var expected = $$""" + using System.ComponentModel.DataAnnotations; + using System.ComponentModel.DataAnnotations.Schema; + using Dappi.HeadlessCms.Models; + using Dappi.Core.Attributes; + using Dappi.HeadlessCms.Core.Attributes; + using Dappi.Core.Enums; + + namespace {{_assemblyName}}.Entities + { + [{{CcControllerAttribute.ShortName}}] + public class {{DomainModelName}} + { + [Key] + [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + public Guid Id { get; set; } + + [Length(10, 100)] + public string? Description { get; set; } + } + } + """; + + _domainModelEditor.AddProperty(property); + await _domainModelEditor.SaveAsync(); + + var actual = await File.ReadAllTextAsync(_filePath); + Assert.Equal(expected.ReplaceLineEndings(), actual.ReplaceLineEndings()); + } + + [Fact] + public async Task DomainModelEditor_AddProperty_Should_Add_MinLength_Attribute_When_Only_Min_Specified() + { + var modelRequest = new ModelRequest { ModelName = DomainModelName, IsAuditableEntity = false }; + _domainModelEditor.CreateEntityModel(modelRequest); + + var property = new Property + { + DomainModel = DomainModelName, + Name = "Username", + Type = "string", + IsRequired = true, + Min = "5", + Max = null + }; + + var expected = $$""" + using System.ComponentModel.DataAnnotations; + using System.ComponentModel.DataAnnotations.Schema; + using Dappi.HeadlessCms.Models; + using Dappi.Core.Attributes; + using Dappi.HeadlessCms.Core.Attributes; + using Dappi.Core.Enums; + + namespace {{_assemblyName}}.Entities + { + [{{CcControllerAttribute.ShortName}}] + public class {{DomainModelName}} + { + [Key] + [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + public Guid Id { get; set; } + + [MinLength(5)] + public string Username { get; set; } + } + } + """; + + _domainModelEditor.AddProperty(property); + await _domainModelEditor.SaveAsync(); + + var actual = await File.ReadAllTextAsync(_filePath); + Assert.Equal(expected.ReplaceLineEndings(), actual.ReplaceLineEndings()); + } + + [Fact] + public async Task DomainModelEditor_AddProperty_Should_Add_MaxLength_Attribute_When_Only_Max_Specified() + { + var modelRequest = new ModelRequest { ModelName = DomainModelName, IsAuditableEntity = false }; + _domainModelEditor.CreateEntityModel(modelRequest); + + var property = new Property + { + DomainModel = DomainModelName, + Name = "ShortCode", + Type = "string", + IsRequired = false, + Min = null, + Max = "20" + }; + + var expected = $$""" + using System.ComponentModel.DataAnnotations; + using System.ComponentModel.DataAnnotations.Schema; + using Dappi.HeadlessCms.Models; + using Dappi.Core.Attributes; + using Dappi.HeadlessCms.Core.Attributes; + using Dappi.Core.Enums; + + namespace {{_assemblyName}}.Entities + { + [{{CcControllerAttribute.ShortName}}] + public class {{DomainModelName}} + { + [Key] + [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + public Guid Id { get; set; } + + [MaxLength(20)] + public string? ShortCode { get; set; } + } + } + """; + + _domainModelEditor.AddProperty(property); + await _domainModelEditor.SaveAsync(); + + var actual = await File.ReadAllTextAsync(_filePath); + Assert.Equal(expected.ReplaceLineEndings(), actual.ReplaceLineEndings()); + } + + [Fact] + public async Task DomainModelEditor_AddProperty_Should_Not_Add_Length_Attributes_When_Neither_Min_Nor_Max_Specified() + { + var modelRequest = new ModelRequest { ModelName = DomainModelName, IsAuditableEntity = false }; + _domainModelEditor.CreateEntityModel(modelRequest); + + var property = new Property + { + DomainModel = DomainModelName, + Name = "Title", + Type = "string", + IsRequired = false, + Min = null, + Max = null + }; + + var expected = $$""" + using System.ComponentModel.DataAnnotations; + using System.ComponentModel.DataAnnotations.Schema; + using Dappi.HeadlessCms.Models; + using Dappi.Core.Attributes; + using Dappi.HeadlessCms.Core.Attributes; + using Dappi.Core.Enums; + + namespace {{_assemblyName}}.Entities + { + [{{CcControllerAttribute.ShortName}}] + public class {{DomainModelName}} + { + [Key] + [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + public Guid Id { get; set; } + public string? Title { get; set; } + } + } + """; + + _domainModelEditor.AddProperty(property); + await _domainModelEditor.SaveAsync(); + + var actual = await File.ReadAllTextAsync(_filePath); + Assert.Equal(expected.ReplaceLineEndings(), actual.ReplaceLineEndings()); + } + + [Theory] + [InlineData("int", "1", "100")] + public async Task DomainModelEditor_AddProperty_Should_Add_Range_Attribute_For_Int_Types(string type, string min, string max) + { + var modelRequest = new ModelRequest { ModelName = DomainModelName, IsAuditableEntity = false }; + _domainModelEditor.CreateEntityModel(modelRequest); + + var property = new Property + { + DomainModel = DomainModelName, + Name = "Name", + Type = type, + IsRequired = false, + Min = min, + Max = max + }; + + _domainModelEditor.AddProperty(property); + await _domainModelEditor.SaveAsync(); + + var actual = await File.ReadAllTextAsync(_filePath); + Assert.Contains($"[Range({min}, {max})]", actual); + Assert.Contains($"public {type}? Name", actual); + } + + [Theory] + [InlineData("float", "-101.5", "142.5")] + [InlineData("double", "-123.92", "128.29")] + public async Task DomainModelEditor_AddProperty_Should_Add_Range_Attribute_For_Decimal_Types(string type, string min, string max) + { + var modelRequest = new ModelRequest { ModelName = DomainModelName, IsAuditableEntity = false }; _domainModelEditor.CreateEntityModel(modelRequest); + + var property = new Property + { + DomainModel = DomainModelName, + Name = "Name", + Type = type, + IsRequired = false, + Min = min, + Max = max + }; + _domainModelEditor.AddProperty(property); await _domainModelEditor.SaveAsync(); + + var actual = await File.ReadAllTextAsync(_filePath); + Assert.Contains($"[Range({min}, {max})]", actual); + Assert.Contains($"public {type}? Name", actual); + } + + [Fact] + public async Task DomainModelEditor_AddProperty_Should_Add_Range_With_Min_Only_For_Numeric_Types() + { + var modelRequest = new ModelRequest { ModelName = DomainModelName, IsAuditableEntity = false }; + _domainModelEditor.CreateEntityModel(modelRequest); + + var property = new Property + { + DomainModel = DomainModelName, + Name = "Name", + Type = "int", + IsRequired = false, + Min = "18", + Max = null + }; + + var expected = $$""" + using System.ComponentModel.DataAnnotations; + using System.ComponentModel.DataAnnotations.Schema; + using Dappi.HeadlessCms.Models; + using Dappi.Core.Attributes; + using Dappi.HeadlessCms.Core.Attributes; + using Dappi.Core.Enums; + + namespace {{_assemblyName}}.Entities + { + [{{CcControllerAttribute.ShortName}}] + public class {{DomainModelName}} + { + [Key] + [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + public Guid Id { get; set; } + + [Range(18, int.MaxValue)] + public int? Name { get; set; } + } + } + """; + + _domainModelEditor.AddProperty(property); + await _domainModelEditor.SaveAsync(); + var actual = await File.ReadAllTextAsync(_filePath); Assert.Equal(expected.ReplaceLineEndings(), actual.ReplaceLineEndings()); } - + + [Fact] + public async Task DomainModelEditor_AddProperty_Should_Add_Range_With_Max_Only_For_Numeric_Types() + { + var modelRequest = new ModelRequest { ModelName = DomainModelName, IsAuditableEntity = false }; + _domainModelEditor.CreateEntityModel(modelRequest); + + var property = new Property + { + DomainModel = DomainModelName, + Name = "Name", + Type = "int", + IsRequired = false, + Min = null, + Max = "100" + }; + + var expected = $$""" + using System.ComponentModel.DataAnnotations; + using System.ComponentModel.DataAnnotations.Schema; + using Dappi.HeadlessCms.Models; + using Dappi.Core.Attributes; + using Dappi.HeadlessCms.Core.Attributes; + using Dappi.Core.Enums; + + namespace {{_assemblyName}}.Entities + { + [{{CcControllerAttribute.ShortName}}] + public class {{DomainModelName}} + { + [Key] + [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + public Guid Id { get; set; } + + [Range(int.MinValue, 100)] + public int? Name { get; set; } + } + } + """; + + _domainModelEditor.AddProperty(property); + await _domainModelEditor.SaveAsync(); + + var actual = await File.ReadAllTextAsync(_filePath); + Assert.Equal(expected.ReplaceLineEndings(), actual.ReplaceLineEndings()); + } + + [Fact] + public async Task DomainModelEditor_AddProperty_Should_Not_Add_Range_Attribute_When_Neither_Min_Nor_Max_Specified() + { + var modelRequest = new ModelRequest { ModelName = DomainModelName, IsAuditableEntity = false }; + _domainModelEditor.CreateEntityModel(modelRequest); + + var property = new Property + { + DomainModel = DomainModelName, + Name = "Name", + Type = "int", + IsRequired = false, + Min = null, + Max = null + }; + + var expected = $$""" + using System.ComponentModel.DataAnnotations; + using System.ComponentModel.DataAnnotations.Schema; + using Dappi.HeadlessCms.Models; + using Dappi.Core.Attributes; + using Dappi.HeadlessCms.Core.Attributes; + using Dappi.Core.Enums; + + namespace {{_assemblyName}}.Entities + { + [{{CcControllerAttribute.ShortName}}] + public class {{DomainModelName}} + { + [Key] + [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + public Guid Id { get; set; } + public int? Name { get; set; } + } + } + """; + + _domainModelEditor.AddProperty(property); + await _domainModelEditor.SaveAsync(); + + var actual = await File.ReadAllTextAsync(_filePath); + Assert.Equal(expected.ReplaceLineEndings(), actual.ReplaceLineEndings()); + } + + [Fact] + public async Task DomainModelEditor_UpdateProperty_Should_Update_String_Length_To_Both_Properties() + { + var modelRequest = new ModelRequest { ModelName = DomainModelName, IsAuditableEntity = false }; + _domainModelEditor.CreateEntityModel(modelRequest); + + var originalProperty = new Property + { + DomainModel = DomainModelName, + Name = "Name", + Type = "string", + IsRequired = false, + }; + + _domainModelEditor.AddProperty(originalProperty); + await _domainModelEditor.SaveAsync(); + + var updatedProperty = new Property + { + DomainModel = DomainModelName, + Name = "Name", + Type = "string", + IsRequired = false, + Min = "3", + Max = "55" + }; + + _domainModelEditor.UpdateProperty(DomainModelName, "Name", updatedProperty); + await _domainModelEditor.SaveAsync(); + + var actual = await File.ReadAllTextAsync(_filePath); + Assert.Contains("[Length(3, 55)]", actual); + } + + [Fact] + public async Task DomainModelEditor_UpdateProperty_Should_Change_String_From_MinLength_To_Length() + { + var modelRequest = new ModelRequest { ModelName = DomainModelName, IsAuditableEntity = false }; + _domainModelEditor.CreateEntityModel(modelRequest); + + var originalProperty = new Property + { + DomainModel = DomainModelName, + Name = "Code", + Type = "string", + IsRequired = false, + Min = "1" + }; + _domainModelEditor.AddProperty(originalProperty); + await _domainModelEditor.SaveAsync(); + + var updatedProperty = new Property + { + DomainModel = DomainModelName, + Name = "Code", + Type = "string", + IsRequired = false, + Min = "5", + Max = "15" + }; + + _domainModelEditor.UpdateProperty(DomainModelName, "Code", updatedProperty); + await _domainModelEditor.SaveAsync(); + + var actual = await File.ReadAllTextAsync(_filePath); + Assert.Contains("[Length(5, 15)]", actual); + Assert.DoesNotContain("[MinLength", actual); + } + #pragma warning disable CA1816 public void Dispose() #pragma warning restore CA1816 diff --git a/Dappi.HeadlessCms.Tests/Dappi.HeadlessCms.Tests.csproj b/Dappi.HeadlessCms.Tests/Dappi.HeadlessCms.Tests.csproj index a1b2fa0a..34e3518b 100644 --- a/Dappi.HeadlessCms.Tests/Dappi.HeadlessCms.Tests.csproj +++ b/Dappi.HeadlessCms.Tests/Dappi.HeadlessCms.Tests.csproj @@ -10,6 +10,7 @@ + diff --git a/Dappi.HeadlessCms.Tests/TestData/PropertyAndClassNames.cs b/Dappi.HeadlessCms.Tests/TestData/PropertyAndClassNames.cs index f2838805..d3f9a995 100644 --- a/Dappi.HeadlessCms.Tests/TestData/PropertyAndClassNames.cs +++ b/Dappi.HeadlessCms.Tests/TestData/PropertyAndClassNames.cs @@ -49,4 +49,37 @@ public TestFieldTypeAndFieldName() } } + + public class ValidMinMaxConstraints : TheoryData + { + public ValidMinMaxConstraints() + { + Add("string", 0, 10, "StringMinMax"); + Add("string", 0, null, "StringMinOnly"); + Add("string", null, 50, "StringMaxOnly"); + + Add("int", -10, 10, "IntNegative"); + Add("int", 0, 100, "IntMinMax"); + Add("double", -99.5, 99.5, "DoubleMinMax"); + Add("float", 0.5, 100.5, "FloatMinMax"); + + Add("int", 5, 5, "IntEqual"); + } + } + + public class InvalidMinMaxConstraints : TheoryData + { + public InvalidMinMaxConstraints() + { + Add("string", -1, 10, "StringNegativeMin"); + Add("string", 5.5, 10, "StringDecimalMin"); + Add("string", 1, 10.5, "StringDecimalMax"); + Add("string", -5, -1, "StringBothNegative"); + + Add("int", 10, 5, "IntMinGreaterThanMax"); + Add("string", 50, 10, "StringMinGreaterThanMax"); + Add("double", 100.5, 50.5, "DoubleMinGreaterThanMax"); + Add("float", 100.5, 50.5, "FloatMinGreaterThanMax"); + } + } } \ No newline at end of file diff --git a/Dappi.HeadlessCms.Tests/Validators/FieldRequestValidatorTests.cs b/Dappi.HeadlessCms.Tests/Validators/FieldRequestValidatorTests.cs new file mode 100644 index 00000000..67a16574 --- /dev/null +++ b/Dappi.HeadlessCms.Tests/Validators/FieldRequestValidatorTests.cs @@ -0,0 +1,289 @@ +using System.Linq.Expressions; +using Dappi.HeadlessCms.Models; +using Dappi.HeadlessCms.Validators; +using FluentValidation.TestHelper; + +namespace Dappi.HeadlessCms.Tests.Validators; + +public class FieldRequestValidatorTests +{ + private readonly FieldRequestValidator _validator = new(); + + [Theory] + [MemberData(nameof(FieldRequestValidatorTestData.InvalidMinTestCases), MemberType = typeof(FieldRequestValidatorTestData))] + public void Should_have_error_for_invalid_Min_value(FieldRequest model, Expression> propertyExpression, string expectedErrorMessage) + { + var result = _validator.TestValidate(model); + + result.ShouldHaveValidationErrorFor(propertyExpression) + .WithErrorMessage(expectedErrorMessage); + } + + [Theory] + [MemberData(nameof(FieldRequestValidatorTestData.ValidMinTestCases), MemberType = typeof(FieldRequestValidatorTestData))] + public void Should_not_have_error_for_valid_Min_value(FieldRequest model, Expression> propertyExpression) + { + var result = _validator.TestValidate(model); + + result.ShouldNotHaveValidationErrorFor(propertyExpression); + } + + [Theory] + [MemberData(nameof(FieldRequestValidatorTestData.InvalidMaxTestCases), MemberType = typeof(FieldRequestValidatorTestData))] + public void Should_have_error_for_invalid_Max_value(FieldRequest model, Expression> propertyExpression, string expectedErrorMessage) + { + var result = _validator.TestValidate(model); + + result.ShouldHaveValidationErrorFor(propertyExpression) + .WithErrorMessage(expectedErrorMessage); + } + + [Theory] + [MemberData(nameof(FieldRequestValidatorTestData.ValidMaxTestCases), MemberType = typeof(FieldRequestValidatorTestData))] + public void Should_not_have_error_for_valid_Max_value( + FieldRequest model, + Expression> propertyExpression) + { + var result = _validator.TestValidate(model); + + result.ShouldNotHaveValidationErrorFor(propertyExpression); + } + + [Theory] + [MemberData(nameof(FieldRequestValidatorTestData.MinMaxComparisonTestCases), MemberType = typeof(FieldRequestValidatorTestData))] + public void Should_validate_Min_Max_comparison(FieldRequest model, bool shouldHaveError, string? expectedErrorMessage) + { + var result = _validator.TestValidate(model); + + if (shouldHaveError) + { + result.ShouldHaveValidationErrorFor(x => x) + .WithErrorMessage(expectedErrorMessage!); + } + else + { + result.ShouldNotHaveValidationErrorFor(x => x); + } + } +} + +public class FieldRequestValidatorTestData +{ + public static IEnumerable InvalidMinTestCases() + { + Expression> minExpression = x => x.Min; + const string errorMessage = "Min value is invalid for the field type."; + + yield return new object[] + { + new FieldRequest { FieldName = "TestField", FieldType = "string", Min = -1 }, + minExpression, + errorMessage + }; + + yield return new object[] + { + new FieldRequest { FieldName = "TestField", FieldType = "string", Min = 5.5 }, + minExpression, + errorMessage + }; + + yield return new object[] + { + new FieldRequest { FieldName = "TestField", FieldType = "int", Min = double.NaN }, + minExpression, + errorMessage + }; + } + + public static IEnumerable ValidMinTestCases() + { + Expression> minExpression = x => x.Min; + + yield return new object[] + { + new FieldRequest { FieldName = "TestField", FieldType = "string", Min = 0 }, + minExpression + }; + + yield return new object[] + { + new FieldRequest { FieldName = "TestField", FieldType = "string", Min = 5 }, + minExpression + }; + + yield return new object[] + { + new FieldRequest { FieldName = "TestField", FieldType = "string", Min = 100 }, + minExpression + }; + + yield return new object[] + { + new FieldRequest { FieldName = "TestField", FieldType = "int", Min = 0 }, + minExpression + }; + + yield return new object[] + { + new FieldRequest { FieldName = "TestField", FieldType = "int", Min = 5 }, + minExpression + }; + + yield return new object[] + { + new FieldRequest { FieldName = "TestField", FieldType = "int", Min = -5 }, + minExpression + }; + + yield return new object[] + { + new FieldRequest { FieldName = "TestField", FieldType = "int", Min = 100.5 }, + minExpression + }; + + yield return new object[] + { + new FieldRequest { FieldName = "TestField", FieldType = "int", Min = -100.5 }, + minExpression + }; + + yield return new object[] + { + new FieldRequest { FieldName = "TestField", FieldType = "string", Min = null }, + minExpression + }; + } + + public static IEnumerable InvalidMaxTestCases() + { + Expression> maxExpression = x => x.Max; + const string errorMessage = "Max value is invalid for the field type."; + + yield return new object[] + { + new FieldRequest { FieldName = "TestField", FieldType = "string", Max = -1 }, + maxExpression, + errorMessage + }; + + yield return new object[] + { + new FieldRequest { FieldName = "TestField", FieldType = "string", Max = 5.5 }, + maxExpression, + errorMessage + }; + + yield return new object[] + { + new FieldRequest { FieldName = "TestField", FieldType = "int", Max = double.NaN }, + maxExpression, + errorMessage + }; + } + + public static IEnumerable ValidMaxTestCases() + { + Expression> maxExpression = x => x.Max; + + yield return new object[] + { + new FieldRequest { FieldName = "TestField", FieldType = "string", Max = 0 }, + maxExpression + }; + + yield return new object[] + { + new FieldRequest { FieldName = "TestField", FieldType = "string", Max = 5 }, + maxExpression + }; + + yield return new object[] + { + new FieldRequest { FieldName = "TestField", FieldType = "string", Max = 100 }, + maxExpression + }; + + yield return new object[] + { + new FieldRequest { FieldName = "TestField", FieldType = "int", Max = 0 }, + maxExpression + }; + + yield return new object[] + { + new FieldRequest { FieldName = "TestField", FieldType = "int", Max = 5 }, + maxExpression + }; + + yield return new object[] + { + new FieldRequest { FieldName = "TestField", FieldType = "int", Max = -5 }, + maxExpression + }; + + yield return new object[] + { + new FieldRequest { FieldName = "TestField", FieldType = "int", Max = 100.5 }, + maxExpression + }; + + yield return new object[] + { + new FieldRequest { FieldName = "TestField", FieldType = "int", Max = -100.5 }, + maxExpression + }; + + yield return new object[] + { + new FieldRequest { FieldName = "TestField", FieldType = "string", Max = null }, + maxExpression + }; + } + + public static IEnumerable MinMaxComparisonTestCases() + { + yield return new object[] + { + new FieldRequest { FieldName = "TestField", FieldType = "int", Min = 10, Max = 5 }, + true, + "Min value cannot be greater than max value." + }; + + yield return new object[] + { + new FieldRequest { FieldName = "TestField", FieldType = "int", Min = 5, Max = 5 }, + false, + null! + }; + + yield return new object[] + { + new FieldRequest { FieldName = "TestField", FieldType = "int", Min = 5, Max = 10 }, + false, + null! + }; + + yield return new object[] + { + new FieldRequest { FieldName = "TestField", FieldType = "int", Min = 5, Max = null }, + false, + null! + }; + + yield return new object[] + { + new FieldRequest { FieldName = "TestField", FieldType = "int", Min = null, Max = 10 }, + false, + null! + }; + + yield return new object[] + { + new FieldRequest { FieldName = "TestField", FieldType = "int", Min = null, Max = null }, + false, + null! + }; + } +} + diff --git a/Dappi.HeadlessCms.Tests/Validators/UpdateFieldRequestValidatorTests.cs b/Dappi.HeadlessCms.Tests/Validators/UpdateFieldRequestValidatorTests.cs new file mode 100644 index 00000000..720f5748 --- /dev/null +++ b/Dappi.HeadlessCms.Tests/Validators/UpdateFieldRequestValidatorTests.cs @@ -0,0 +1,323 @@ +using System.Linq.Expressions; +using Dappi.HeadlessCms.Models; +using Dappi.HeadlessCms.Validators; +using FluentValidation.TestHelper; + +namespace Dappi.HeadlessCms.Tests.Validators; + +public class UpdateFieldRequestValidatorTests +{ + private readonly UpdateFieldRequestValidator _validator = new(); + + [Theory] + [MemberData(nameof(UpdateFieldValidationTestData.InvalidMinTestCases), MemberType = typeof(UpdateFieldValidationTestData))] + public void Should_have_error_for_invalid_Min_value( + UpdateFieldRequest model, + Expression> propertyExpression, + string expectedErrorMessage) + { + var result = _validator.TestValidate(model); + + result.ShouldHaveValidationErrorFor(propertyExpression) + .WithErrorMessage(expectedErrorMessage); + } + + [Theory] + [MemberData(nameof(UpdateFieldValidationTestData.ValidMinTestCases), MemberType = typeof(UpdateFieldValidationTestData))] + public void Should_not_have_error_for_valid_Min_value( + UpdateFieldRequest model, + Expression> propertyExpression) + { + var result = _validator.TestValidate(model); + + result.ShouldNotHaveValidationErrorFor(propertyExpression); + } + + [Theory] + [MemberData(nameof(UpdateFieldValidationTestData.InvalidMaxTestCases), MemberType = typeof(UpdateFieldValidationTestData))] + public void Should_have_error_for_invalid_Max_value( + UpdateFieldRequest model, + Expression> propertyExpression, + string expectedErrorMessage) + { + var result = _validator.TestValidate(model); + + result.ShouldHaveValidationErrorFor(propertyExpression) + .WithErrorMessage(expectedErrorMessage); + } + + [Theory] + [MemberData(nameof(UpdateFieldValidationTestData.ValidMaxTestCases), MemberType = typeof(UpdateFieldValidationTestData))] + public void Should_not_have_error_for_valid_Max_value( + UpdateFieldRequest model, + Expression> propertyExpression) + { + var result = _validator.TestValidate(model); + + result.ShouldNotHaveValidationErrorFor(propertyExpression); + } + + [Theory] + [MemberData(nameof(UpdateFieldValidationTestData.MinMaxComparisonTestCases), MemberType = typeof(UpdateFieldValidationTestData))] + public void Should_validate_Min_Max_comparison( + UpdateFieldRequest model, + bool shouldHaveError, + string? expectedErrorMessage) + { + var result = _validator.TestValidate(model); + + if (shouldHaveError) + { + result.ShouldHaveValidationErrorFor(x => x) + .WithErrorMessage(expectedErrorMessage!); + } + else + { + result.ShouldNotHaveValidationErrorFor(x => x); + } + } +} + +public class UpdateFieldValidationTestData +{ + public static IEnumerable InvalidMinTestCases() + { + Expression> minExpression = x => x.Min; + const string errorMessage = "Min value is invalid for the field type."; + + yield return new object[] + { + new UpdateFieldRequest { OldFieldName = "OldField", NewFieldName = "NewField", FieldType = "string", Min = -1 }, + minExpression, + errorMessage + }; + + yield return new object[] + { + new UpdateFieldRequest { OldFieldName = "OldField", NewFieldName = "NewField", FieldType = "string", Min = 5.5 }, + minExpression, + errorMessage + }; + + yield return new object[] + { + new UpdateFieldRequest { OldFieldName = "OldField", NewFieldName = "NewField", FieldType = "int", Min = double.NaN }, + minExpression, + errorMessage + }; + } + + public static IEnumerable ValidMinTestCases() + { + Expression> minExpression = x => x.Min; + + yield return new object[] + { + new UpdateFieldRequest { OldFieldName = "OldField", NewFieldName = "NewField", FieldType = "string", Min = 0 }, + minExpression + }; + + yield return new object[] + { + new UpdateFieldRequest { OldFieldName = "OldField", NewFieldName = "NewField", FieldType = "string", Min = 5 }, + minExpression + }; + + yield return new object[] + { + new UpdateFieldRequest { OldFieldName = "OldField", NewFieldName = "NewField", FieldType = "string", Min = 100 }, + minExpression + }; + + yield return new object[] + { + new UpdateFieldRequest { OldFieldName = "OldField", NewFieldName = "NewField", FieldType = "int", Min = 0 }, + minExpression + }; + + yield return new object[] + { + new UpdateFieldRequest { OldFieldName = "OldField", NewFieldName = "NewField", FieldType = "int", Min = 5 }, + minExpression + }; + + yield return new object[] + { + new UpdateFieldRequest { OldFieldName = "OldField", NewFieldName = "NewField", FieldType = "int", Min = -5 }, + minExpression + }; + + yield return new object[] + { + new UpdateFieldRequest { OldFieldName = "OldField", NewFieldName = "NewField", FieldType = "int", Min = 100.5 }, + minExpression + }; + + yield return new object[] + { + new UpdateFieldRequest { OldFieldName = "OldField", NewFieldName = "NewField", FieldType = "int", Min = -100.5 }, + minExpression + }; + + yield return new object[] + { + new UpdateFieldRequest { OldFieldName = "OldField", NewFieldName = "NewField", FieldType = "double", Min = 5.5 }, + minExpression + }; + + yield return new object[] + { + new UpdateFieldRequest { OldFieldName = "OldField", NewFieldName = "NewField", FieldType = "float", Min = 5.5 }, + minExpression + }; + + yield return new object[] + { + new UpdateFieldRequest { OldFieldName = "OldField", NewFieldName = "NewField", FieldType = "string", Min = null }, + minExpression + }; + } + + public static IEnumerable InvalidMaxTestCases() + { + Expression> maxExpression = x => x.Max; + const string errorMessage = "Max value is invalid for the field type."; + + yield return new object[] + { + new UpdateFieldRequest { OldFieldName = "OldField", NewFieldName = "NewField", FieldType = "string", Max = -1 }, + maxExpression, + errorMessage + }; + + yield return new object[] + { + new UpdateFieldRequest { OldFieldName = "OldField", NewFieldName = "NewField", FieldType = "string", Max = 5.5 }, + maxExpression, + errorMessage + }; + + yield return new object[] + { + new UpdateFieldRequest { OldFieldName = "OldField", NewFieldName = "NewField", FieldType = "int", Max = double.NaN }, + maxExpression, + errorMessage + }; + } + + public static IEnumerable ValidMaxTestCases() + { + Expression> maxExpression = x => x.Max; + + yield return new object[] + { + new UpdateFieldRequest { OldFieldName = "OldField", NewFieldName = "NewField", FieldType = "string", Max = 0 }, + maxExpression + }; + + yield return new object[] + { + new UpdateFieldRequest { OldFieldName = "OldField", NewFieldName = "NewField", FieldType = "string", Max = 5 }, + maxExpression + }; + + yield return new object[] + { + new UpdateFieldRequest { OldFieldName = "OldField", NewFieldName = "NewField", FieldType = "string", Max = 100 }, + maxExpression + }; + + yield return new object[] + { + new UpdateFieldRequest { OldFieldName = "OldField", NewFieldName = "NewField", FieldType = "int", Max = 0 }, + maxExpression + }; + + yield return new object[] + { + new UpdateFieldRequest { OldFieldName = "OldField", NewFieldName = "NewField", FieldType = "int", Max = 5 }, + maxExpression + }; + + yield return new object[] + { + new UpdateFieldRequest { OldFieldName = "OldField", NewFieldName = "NewField", FieldType = "int", Max = -5 }, + maxExpression + }; + + yield return new object[] + { + new UpdateFieldRequest { OldFieldName = "OldField", NewFieldName = "NewField", FieldType = "int", Max = 100.5 }, + maxExpression + }; + + yield return new object[] + { + new UpdateFieldRequest { OldFieldName = "OldField", NewFieldName = "NewField", FieldType = "int", Max = -100.5 }, + maxExpression + }; + + yield return new object[] + { + new UpdateFieldRequest { OldFieldName = "OldField", NewFieldName = "NewField", FieldType = "double", Max = 5.5 }, + maxExpression + }; + + yield return new object[] + { + new UpdateFieldRequest { OldFieldName = "OldField", NewFieldName = "NewField", FieldType = "float", Max = 5.5 }, + maxExpression + }; + + yield return new object[] + { + new UpdateFieldRequest { OldFieldName = "OldField", NewFieldName = "NewField", FieldType = "string", Max = null }, + maxExpression + }; + } + + public static IEnumerable MinMaxComparisonTestCases() + { + yield return new object[] + { + new UpdateFieldRequest { OldFieldName = "OldField", NewFieldName = "NewField", FieldType = "int", Min = 10, Max = 5 }, + true, + "Min value cannot be greater than max value." + }; + + yield return new object[] + { + new UpdateFieldRequest { OldFieldName = "OldField", NewFieldName = "NewField", FieldType = "int", Min = 5, Max = 5 }, + false, + null! + }; + + yield return new object[] + { + new UpdateFieldRequest { OldFieldName = "OldField", NewFieldName = "NewField", FieldType = "int", Min = 5, Max = 10 }, + false, + null! + }; + + yield return new object[] + { + new UpdateFieldRequest { OldFieldName = "OldField", NewFieldName = "NewField", FieldType = "int", Min = 5, Max = null }, + false, + null! + }; + + yield return new object[] + { + new UpdateFieldRequest { OldFieldName = "OldField", NewFieldName = "NewField", FieldType = "int", Min = null, Max = 10 }, + false, + null! + }; + + yield return new object[] + { + new UpdateFieldRequest { OldFieldName = "OldField", NewFieldName = "NewField", FieldType = "int", Min = null, Max = null }, + false, + null! + }; + } +} diff --git a/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/AddField_Should_Accept_Valid_MinMax_Constraints/DoubleMinMax/model.verified.txt b/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/AddField_Should_Accept_Valid_MinMax_Constraints/DoubleMinMax/model.verified.txt new file mode 100644 index 00000000..b3f37818 --- /dev/null +++ b/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/AddField_Should_Accept_Valid_MinMax_Constraints/DoubleMinMax/model.verified.txt @@ -0,0 +1,20 @@ +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using Dappi.HeadlessCms.Models; +using Dappi.Core.Attributes; +using Dappi.HeadlessCms.Core.Attributes; +using Dappi.Core.Enums; + +namespace Entities +{ + [CcController] + public class MinMaxTestDoubleMinMax + { + [Key] + [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + public Guid Id { get; set; } + + [Range(-99.5, 99.5)] + public double? TestField { get; set; } + } +} \ No newline at end of file diff --git a/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/AddField_Should_Accept_Valid_MinMax_Constraints/DoubleMinMax/response.verified.txt b/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/AddField_Should_Accept_Valid_MinMax_Constraints/DoubleMinMax/response.verified.txt new file mode 100644 index 00000000..9251f54f --- /dev/null +++ b/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/AddField_Should_Accept_Valid_MinMax_Constraints/DoubleMinMax/response.verified.txt @@ -0,0 +1,13 @@ +{ + Status: 200 OK, + Content: { + Headers: { + Content-Length: 150, + Content-Type: application/json; charset=utf-8 + }, + Value: { + Message: Field 'TestField' of type 'double' added successfully to 'MinMaxTestDoubleMinMax' model., + FilePath: Entities/MinMaxTestDoubleMinMax.cs + } + } +} \ No newline at end of file diff --git a/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/AddField_Should_Accept_Valid_MinMax_Constraints/FloatMinMax/model.verified.txt b/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/AddField_Should_Accept_Valid_MinMax_Constraints/FloatMinMax/model.verified.txt new file mode 100644 index 00000000..9282cec2 --- /dev/null +++ b/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/AddField_Should_Accept_Valid_MinMax_Constraints/FloatMinMax/model.verified.txt @@ -0,0 +1,20 @@ +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using Dappi.HeadlessCms.Models; +using Dappi.Core.Attributes; +using Dappi.HeadlessCms.Core.Attributes; +using Dappi.Core.Enums; + +namespace Entities +{ + [CcController] + public class MinMaxTestFloatMinMax + { + [Key] + [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + public Guid Id { get; set; } + + [Range(0.5, 100.5)] + public float? TestField { get; set; } + } +} \ No newline at end of file diff --git a/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/AddField_Should_Accept_Valid_MinMax_Constraints/FloatMinMax/response.verified.txt b/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/AddField_Should_Accept_Valid_MinMax_Constraints/FloatMinMax/response.verified.txt new file mode 100644 index 00000000..7bbf09be --- /dev/null +++ b/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/AddField_Should_Accept_Valid_MinMax_Constraints/FloatMinMax/response.verified.txt @@ -0,0 +1,13 @@ +{ + Status: 200 OK, + Content: { + Headers: { + Content-Length: 147, + Content-Type: application/json; charset=utf-8 + }, + Value: { + Message: Field 'TestField' of type 'float' added successfully to 'MinMaxTestFloatMinMax' model., + FilePath: Entities/MinMaxTestFloatMinMax.cs + } + } +} \ No newline at end of file diff --git a/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/AddField_Should_Accept_Valid_MinMax_Constraints/IntEqual/model.verified.txt b/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/AddField_Should_Accept_Valid_MinMax_Constraints/IntEqual/model.verified.txt new file mode 100644 index 00000000..026fc154 --- /dev/null +++ b/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/AddField_Should_Accept_Valid_MinMax_Constraints/IntEqual/model.verified.txt @@ -0,0 +1,20 @@ +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using Dappi.HeadlessCms.Models; +using Dappi.Core.Attributes; +using Dappi.HeadlessCms.Core.Attributes; +using Dappi.Core.Enums; + +namespace Entities +{ + [CcController] + public class MinMaxTestIntEqual + { + [Key] + [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + public Guid Id { get; set; } + + [Range(5, 5)] + public int? TestField { get; set; } + } +} \ No newline at end of file diff --git a/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/AddField_Should_Accept_Valid_MinMax_Constraints/IntEqual/response.verified.txt b/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/AddField_Should_Accept_Valid_MinMax_Constraints/IntEqual/response.verified.txt new file mode 100644 index 00000000..e44423ae --- /dev/null +++ b/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/AddField_Should_Accept_Valid_MinMax_Constraints/IntEqual/response.verified.txt @@ -0,0 +1,13 @@ +{ + Status: 200 OK, + Content: { + Headers: { + Content-Length: 139, + Content-Type: application/json; charset=utf-8 + }, + Value: { + Message: Field 'TestField' of type 'int' added successfully to 'MinMaxTestIntEqual' model., + FilePath: Entities/MinMaxTestIntEqual.cs + } + } +} \ No newline at end of file diff --git a/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/AddField_Should_Accept_Valid_MinMax_Constraints/IntMinMax/model.verified.txt b/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/AddField_Should_Accept_Valid_MinMax_Constraints/IntMinMax/model.verified.txt new file mode 100644 index 00000000..7502a5b2 --- /dev/null +++ b/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/AddField_Should_Accept_Valid_MinMax_Constraints/IntMinMax/model.verified.txt @@ -0,0 +1,20 @@ +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using Dappi.HeadlessCms.Models; +using Dappi.Core.Attributes; +using Dappi.HeadlessCms.Core.Attributes; +using Dappi.Core.Enums; + +namespace Entities +{ + [CcController] + public class MinMaxTestIntMinMax + { + [Key] + [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + public Guid Id { get; set; } + + [Range(0, 100)] + public int? TestField { get; set; } + } +} \ No newline at end of file diff --git a/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/AddField_Should_Accept_Valid_MinMax_Constraints/IntMinMax/response.verified.txt b/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/AddField_Should_Accept_Valid_MinMax_Constraints/IntMinMax/response.verified.txt new file mode 100644 index 00000000..658f7f32 --- /dev/null +++ b/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/AddField_Should_Accept_Valid_MinMax_Constraints/IntMinMax/response.verified.txt @@ -0,0 +1,13 @@ +{ + Status: 200 OK, + Content: { + Headers: { + Content-Length: 141, + Content-Type: application/json; charset=utf-8 + }, + Value: { + Message: Field 'TestField' of type 'int' added successfully to 'MinMaxTestIntMinMax' model., + FilePath: Entities/MinMaxTestIntMinMax.cs + } + } +} \ No newline at end of file diff --git a/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/AddField_Should_Accept_Valid_MinMax_Constraints/IntNegative/model.verified.txt b/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/AddField_Should_Accept_Valid_MinMax_Constraints/IntNegative/model.verified.txt new file mode 100644 index 00000000..1f87df2d --- /dev/null +++ b/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/AddField_Should_Accept_Valid_MinMax_Constraints/IntNegative/model.verified.txt @@ -0,0 +1,20 @@ +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using Dappi.HeadlessCms.Models; +using Dappi.Core.Attributes; +using Dappi.HeadlessCms.Core.Attributes; +using Dappi.Core.Enums; + +namespace Entities +{ + [CcController] + public class MinMaxTestIntNegative + { + [Key] + [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + public Guid Id { get; set; } + + [Range(-10, 10)] + public int? TestField { get; set; } + } +} \ No newline at end of file diff --git a/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/AddField_Should_Accept_Valid_MinMax_Constraints/IntNegative/response.verified.txt b/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/AddField_Should_Accept_Valid_MinMax_Constraints/IntNegative/response.verified.txt new file mode 100644 index 00000000..2bce1903 --- /dev/null +++ b/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/AddField_Should_Accept_Valid_MinMax_Constraints/IntNegative/response.verified.txt @@ -0,0 +1,13 @@ +{ + Status: 200 OK, + Content: { + Headers: { + Content-Length: 145, + Content-Type: application/json; charset=utf-8 + }, + Value: { + Message: Field 'TestField' of type 'int' added successfully to 'MinMaxTestIntNegative' model., + FilePath: Entities/MinMaxTestIntNegative.cs + } + } +} \ No newline at end of file diff --git a/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/AddField_Should_Accept_Valid_MinMax_Constraints/StringMaxOnly/model.verified.txt b/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/AddField_Should_Accept_Valid_MinMax_Constraints/StringMaxOnly/model.verified.txt new file mode 100644 index 00000000..086d2264 --- /dev/null +++ b/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/AddField_Should_Accept_Valid_MinMax_Constraints/StringMaxOnly/model.verified.txt @@ -0,0 +1,20 @@ +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using Dappi.HeadlessCms.Models; +using Dappi.Core.Attributes; +using Dappi.HeadlessCms.Core.Attributes; +using Dappi.Core.Enums; + +namespace Entities +{ + [CcController] + public class MinMaxTestStringMaxOnly + { + [Key] + [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + public Guid Id { get; set; } + + [MaxLength(50)] + public string? TestField { get; set; } + } +} \ No newline at end of file diff --git a/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/AddField_Should_Accept_Valid_MinMax_Constraints/StringMaxOnly/response.verified.txt b/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/AddField_Should_Accept_Valid_MinMax_Constraints/StringMaxOnly/response.verified.txt new file mode 100644 index 00000000..0d58d4a9 --- /dev/null +++ b/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/AddField_Should_Accept_Valid_MinMax_Constraints/StringMaxOnly/response.verified.txt @@ -0,0 +1,13 @@ +{ + Status: 200 OK, + Content: { + Headers: { + Content-Length: 152, + Content-Type: application/json; charset=utf-8 + }, + Value: { + Message: Field 'TestField' of type 'string' added successfully to 'MinMaxTestStringMaxOnly' model., + FilePath: Entities/MinMaxTestStringMaxOnly.cs + } + } +} \ No newline at end of file diff --git a/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/AddField_Should_Accept_Valid_MinMax_Constraints/StringMinMax/model.verified.txt b/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/AddField_Should_Accept_Valid_MinMax_Constraints/StringMinMax/model.verified.txt new file mode 100644 index 00000000..f29eb38f --- /dev/null +++ b/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/AddField_Should_Accept_Valid_MinMax_Constraints/StringMinMax/model.verified.txt @@ -0,0 +1,20 @@ +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using Dappi.HeadlessCms.Models; +using Dappi.Core.Attributes; +using Dappi.HeadlessCms.Core.Attributes; +using Dappi.Core.Enums; + +namespace Entities +{ + [CcController] + public class MinMaxTestStringMinMax + { + [Key] + [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + public Guid Id { get; set; } + + [Length(0, 10)] + public string? TestField { get; set; } + } +} \ No newline at end of file diff --git a/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/AddField_Should_Accept_Valid_MinMax_Constraints/StringMinMax/response.verified.txt b/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/AddField_Should_Accept_Valid_MinMax_Constraints/StringMinMax/response.verified.txt new file mode 100644 index 00000000..c6162ea7 --- /dev/null +++ b/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/AddField_Should_Accept_Valid_MinMax_Constraints/StringMinMax/response.verified.txt @@ -0,0 +1,13 @@ +{ + Status: 200 OK, + Content: { + Headers: { + Content-Length: 150, + Content-Type: application/json; charset=utf-8 + }, + Value: { + Message: Field 'TestField' of type 'string' added successfully to 'MinMaxTestStringMinMax' model., + FilePath: Entities/MinMaxTestStringMinMax.cs + } + } +} \ No newline at end of file diff --git a/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/AddField_Should_Accept_Valid_MinMax_Constraints/StringMinOnly/model.verified.txt b/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/AddField_Should_Accept_Valid_MinMax_Constraints/StringMinOnly/model.verified.txt new file mode 100644 index 00000000..70c53f4d --- /dev/null +++ b/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/AddField_Should_Accept_Valid_MinMax_Constraints/StringMinOnly/model.verified.txt @@ -0,0 +1,20 @@ +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using Dappi.HeadlessCms.Models; +using Dappi.Core.Attributes; +using Dappi.HeadlessCms.Core.Attributes; +using Dappi.Core.Enums; + +namespace Entities +{ + [CcController] + public class MinMaxTestStringMinOnly + { + [Key] + [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + public Guid Id { get; set; } + + [MinLength(0)] + public string? TestField { get; set; } + } +} \ No newline at end of file diff --git a/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/AddField_Should_Accept_Valid_MinMax_Constraints/StringMinOnly/response.verified.txt b/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/AddField_Should_Accept_Valid_MinMax_Constraints/StringMinOnly/response.verified.txt new file mode 100644 index 00000000..0ddc9c19 --- /dev/null +++ b/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/AddField_Should_Accept_Valid_MinMax_Constraints/StringMinOnly/response.verified.txt @@ -0,0 +1,13 @@ +{ + Status: 200 OK, + Content: { + Headers: { + Content-Length: 152, + Content-Type: application/json; charset=utf-8 + }, + Value: { + Message: Field 'TestField' of type 'string' added successfully to 'MinMaxTestStringMinOnly' model., + FilePath: Entities/MinMaxTestStringMinOnly.cs + } + } +} \ No newline at end of file diff --git a/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/AddField_Should_Add_ManyToMany_Relation_To_Models/response.verified.txt b/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/AddField_Should_Add_ManyToMany_Relation_To_Models/response.verified.txt index 5b4580d1..66ab6ad3 100644 --- a/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/AddField_Should_Add_ManyToMany_Relation_To_Models/response.verified.txt +++ b/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/AddField_Should_Add_ManyToMany_Relation_To_Models/response.verified.txt @@ -2,12 +2,12 @@ Status: 200 OK, Content: { Headers: { - Content-Length: 221, + Content-Length: 141, Content-Type: application/json; charset=utf-8 }, Value: { Message: Field 'TestRelation' of type 'ManyToMany' added successfully to 'TestClassSeven' model., - FilePath: {CurrentDirectory}Entities/TestClassSeven.cs + FilePath: Entities/TestClassSeven.cs } } } \ No newline at end of file diff --git a/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/AddField_Should_Add_ManyToOne_Relation_To_Models/response.verified.txt b/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/AddField_Should_Add_ManyToOne_Relation_To_Models/response.verified.txt index 8b0e2241..86ce4bd2 100644 --- a/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/AddField_Should_Add_ManyToOne_Relation_To_Models/response.verified.txt +++ b/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/AddField_Should_Add_ManyToOne_Relation_To_Models/response.verified.txt @@ -2,12 +2,12 @@ Status: 200 OK, Content: { Headers: { - Content-Length: 218, + Content-Length: 138, Content-Type: application/json; charset=utf-8 }, Value: { Message: Field 'TestRelation' of type 'ManyToOne' added successfully to 'TestClassFive' model., - FilePath: {CurrentDirectory}Entities/TestClassFive.cs + FilePath: Entities/TestClassFive.cs } } } \ No newline at end of file diff --git a/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/AddField_Should_Add_OneToMany_Relation_To_Models/response.verified.txt b/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/AddField_Should_Add_OneToMany_Relation_To_Models/response.verified.txt index 0cad769c..5c3a2bbb 100644 --- a/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/AddField_Should_Add_OneToMany_Relation_To_Models/response.verified.txt +++ b/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/AddField_Should_Add_OneToMany_Relation_To_Models/response.verified.txt @@ -2,12 +2,12 @@ Status: 200 OK, Content: { Headers: { - Content-Length: 220, + Content-Length: 140, Content-Type: application/json; charset=utf-8 }, Value: { Message: Field 'TestRelation' of type 'OneToMany' added successfully to 'TestClassThree' model., - FilePath: {CurrentDirectory}Entities/TestClassThree.cs + FilePath: Entities/TestClassThree.cs } } } \ No newline at end of file diff --git a/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/AddField_Should_Add_OneToOne_Relation_To_Models/response.verified.txt b/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/AddField_Should_Add_OneToOne_Relation_To_Models/response.verified.txt index 5a2daac0..95322bbe 100644 --- a/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/AddField_Should_Add_OneToOne_Relation_To_Models/response.verified.txt +++ b/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/AddField_Should_Add_OneToOne_Relation_To_Models/response.verified.txt @@ -2,12 +2,12 @@ Status: 200 OK, Content: { Headers: { - Content-Length: 215, + Content-Length: 135, Content-Type: application/json; charset=utf-8 }, Value: { Message: Field 'TestRelation' of type 'OneToOne' added successfully to 'TestClassOne' model., - FilePath: {CurrentDirectory}Entities/TestClassOne.cs + FilePath: Entities/TestClassOne.cs } } } \ No newline at end of file diff --git a/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/AddField_Should_Add_Optional_Field_To_Model/TestBoolType/response.verified.txt b/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/AddField_Should_Add_Optional_Field_To_Model/TestBoolType/response.verified.txt index 819dcbfd..6b4ab6ee 100644 --- a/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/AddField_Should_Add_Optional_Field_To_Model/TestBoolType/response.verified.txt +++ b/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/AddField_Should_Add_Optional_Field_To_Model/TestBoolType/response.verified.txt @@ -2,12 +2,12 @@ Status: 200 OK, Content: { Headers: { - Content-Length: 211, + Content-Length: 131, Content-Type: application/json; charset=utf-8 }, Value: { Message: Field 'TestBoolType' of type 'bool' added successfully to 'ProductThree' model., - FilePath: {CurrentDirectory}Entities/ProductThree.cs + FilePath: Entities/ProductThree.cs } } } \ No newline at end of file diff --git a/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/AddField_Should_Add_Optional_Field_To_Model/TestDateOnlyType/response.verified.txt b/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/AddField_Should_Add_Optional_Field_To_Model/TestDateOnlyType/response.verified.txt index f1b8c205..647d4993 100644 --- a/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/AddField_Should_Add_Optional_Field_To_Model/TestDateOnlyType/response.verified.txt +++ b/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/AddField_Should_Add_Optional_Field_To_Model/TestDateOnlyType/response.verified.txt @@ -2,12 +2,12 @@ Status: 200 OK, Content: { Headers: { - Content-Length: 219, + Content-Length: 139, Content-Type: application/json; charset=utf-8 }, Value: { Message: Field 'TestDateOnlyType' of type 'DateOnly' added successfully to 'ProductThree' model., - FilePath: {CurrentDirectory}Entities/ProductThree.cs + FilePath: Entities/ProductThree.cs } } } \ No newline at end of file diff --git a/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/AddField_Should_Add_Optional_Field_To_Model/TestDateTimeType/response.verified.txt b/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/AddField_Should_Add_Optional_Field_To_Model/TestDateTimeType/response.verified.txt index 1e81931f..e04c55e9 100644 --- a/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/AddField_Should_Add_Optional_Field_To_Model/TestDateTimeType/response.verified.txt +++ b/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/AddField_Should_Add_Optional_Field_To_Model/TestDateTimeType/response.verified.txt @@ -2,12 +2,12 @@ Status: 200 OK, Content: { Headers: { - Content-Length: 219, + Content-Length: 139, Content-Type: application/json; charset=utf-8 }, Value: { Message: Field 'TestDateTimeType' of type 'DateTime' added successfully to 'ProductThree' model., - FilePath: {CurrentDirectory}Entities/ProductThree.cs + FilePath: Entities/ProductThree.cs } } } \ No newline at end of file diff --git a/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/AddField_Should_Add_Optional_Field_To_Model/TestIntType/response.verified.txt b/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/AddField_Should_Add_Optional_Field_To_Model/TestIntType/response.verified.txt index bf280a30..31cf5890 100644 --- a/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/AddField_Should_Add_Optional_Field_To_Model/TestIntType/response.verified.txt +++ b/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/AddField_Should_Add_Optional_Field_To_Model/TestIntType/response.verified.txt @@ -2,12 +2,12 @@ Status: 200 OK, Content: { Headers: { - Content-Length: 209, + Content-Length: 129, Content-Type: application/json; charset=utf-8 }, Value: { Message: Field 'TestIntType' of type 'int' added successfully to 'ProductThree' model., - FilePath: {CurrentDirectory}Entities/ProductThree.cs + FilePath: Entities/ProductThree.cs } } } \ No newline at end of file diff --git a/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/AddField_Should_Add_Optional_Field_To_Model/TestStringType/response.verified.txt b/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/AddField_Should_Add_Optional_Field_To_Model/TestStringType/response.verified.txt index 96e68842..43d0af2a 100644 --- a/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/AddField_Should_Add_Optional_Field_To_Model/TestStringType/response.verified.txt +++ b/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/AddField_Should_Add_Optional_Field_To_Model/TestStringType/response.verified.txt @@ -2,12 +2,12 @@ Status: 200 OK, Content: { Headers: { - Content-Length: 215, + Content-Length: 135, Content-Type: application/json; charset=utf-8 }, Value: { Message: Field 'TestStringType' of type 'string' added successfully to 'ProductThree' model., - FilePath: {CurrentDirectory}Entities/ProductThree.cs + FilePath: Entities/ProductThree.cs } } } \ No newline at end of file diff --git a/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/AddField_Should_Add_Required_Field_To_Model/TestBoolType/response.verified.txt b/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/AddField_Should_Add_Required_Field_To_Model/TestBoolType/response.verified.txt index 140e20b5..cc37016b 100644 --- a/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/AddField_Should_Add_Required_Field_To_Model/TestBoolType/response.verified.txt +++ b/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/AddField_Should_Add_Required_Field_To_Model/TestBoolType/response.verified.txt @@ -2,12 +2,12 @@ Status: 200 OK, Content: { Headers: { - Content-Length: 207, + Content-Length: 127, Content-Type: application/json; charset=utf-8 }, Value: { Message: Field 'TestBoolType' of type 'bool' added successfully to 'ProductTwo' model., - FilePath: {CurrentDirectory}Entities/ProductTwo.cs + FilePath: Entities/ProductTwo.cs } } } \ No newline at end of file diff --git a/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/AddField_Should_Add_Required_Field_To_Model/TestDateOnlyType/response.verified.txt b/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/AddField_Should_Add_Required_Field_To_Model/TestDateOnlyType/response.verified.txt index 448474be..4d9a45c9 100644 --- a/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/AddField_Should_Add_Required_Field_To_Model/TestDateOnlyType/response.verified.txt +++ b/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/AddField_Should_Add_Required_Field_To_Model/TestDateOnlyType/response.verified.txt @@ -2,12 +2,12 @@ Status: 200 OK, Content: { Headers: { - Content-Length: 215, + Content-Length: 135, Content-Type: application/json; charset=utf-8 }, Value: { Message: Field 'TestDateOnlyType' of type 'DateOnly' added successfully to 'ProductTwo' model., - FilePath: {CurrentDirectory}Entities/ProductTwo.cs + FilePath: Entities/ProductTwo.cs } } } \ No newline at end of file diff --git a/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/AddField_Should_Add_Required_Field_To_Model/TestDateTimeType/response.verified.txt b/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/AddField_Should_Add_Required_Field_To_Model/TestDateTimeType/response.verified.txt index 74fa01ff..eec58100 100644 --- a/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/AddField_Should_Add_Required_Field_To_Model/TestDateTimeType/response.verified.txt +++ b/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/AddField_Should_Add_Required_Field_To_Model/TestDateTimeType/response.verified.txt @@ -2,12 +2,12 @@ Status: 200 OK, Content: { Headers: { - Content-Length: 215, + Content-Length: 135, Content-Type: application/json; charset=utf-8 }, Value: { Message: Field 'TestDateTimeType' of type 'DateTime' added successfully to 'ProductTwo' model., - FilePath: {CurrentDirectory}Entities/ProductTwo.cs + FilePath: Entities/ProductTwo.cs } } } \ No newline at end of file diff --git a/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/AddField_Should_Add_Required_Field_To_Model/TestIntType/response.verified.txt b/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/AddField_Should_Add_Required_Field_To_Model/TestIntType/response.verified.txt index b481ae1b..30f0c07e 100644 --- a/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/AddField_Should_Add_Required_Field_To_Model/TestIntType/response.verified.txt +++ b/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/AddField_Should_Add_Required_Field_To_Model/TestIntType/response.verified.txt @@ -2,12 +2,12 @@ Status: 200 OK, Content: { Headers: { - Content-Length: 205, + Content-Length: 125, Content-Type: application/json; charset=utf-8 }, Value: { Message: Field 'TestIntType' of type 'int' added successfully to 'ProductTwo' model., - FilePath: {CurrentDirectory}Entities/ProductTwo.cs + FilePath: Entities/ProductTwo.cs } } } \ No newline at end of file diff --git a/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/AddField_Should_Add_Required_Field_To_Model/TestStringType/response.verified.txt b/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/AddField_Should_Add_Required_Field_To_Model/TestStringType/response.verified.txt index 62f23ff5..3b8d10dc 100644 --- a/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/AddField_Should_Add_Required_Field_To_Model/TestStringType/response.verified.txt +++ b/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/AddField_Should_Add_Required_Field_To_Model/TestStringType/response.verified.txt @@ -2,12 +2,12 @@ Status: 200 OK, Content: { Headers: { - Content-Length: 211, + Content-Length: 131, Content-Type: application/json; charset=utf-8 }, Value: { Message: Field 'TestStringType' of type 'string' added successfully to 'ProductTwo' model., - FilePath: {CurrentDirectory}Entities/ProductTwo.cs + FilePath: Entities/ProductTwo.cs } } } \ No newline at end of file diff --git a/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/AddField_Should_Return_BadRequest_For_Invalid_MinMax_Constraints/DoubleMinGreaterThanMax/response.verified.txt b/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/AddField_Should_Return_BadRequest_For_Invalid_MinMax_Constraints/DoubleMinGreaterThanMax/response.verified.txt new file mode 100644 index 00000000..45238aeb --- /dev/null +++ b/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/AddField_Should_Return_BadRequest_For_Invalid_MinMax_Constraints/DoubleMinGreaterThanMax/response.verified.txt @@ -0,0 +1,20 @@ +{ + Status: 400 Bad Request, + Content: { + Headers: { + Content-Length: 254, + Content-Type: application/problem+json; charset=utf-8 + }, + Value: { + type: https://tools.ietf.org/html/rfc9110#section-15.5.1, + title: One or more validation errors occurred., + status: 400, + errors: { + : [ + Min value cannot be greater than max value. + ] + }, + traceId: {Scrubbed} + } + } +} \ No newline at end of file diff --git a/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/AddField_Should_Return_BadRequest_For_Invalid_MinMax_Constraints/FloatMinGreaterThanMax/response.verified.txt b/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/AddField_Should_Return_BadRequest_For_Invalid_MinMax_Constraints/FloatMinGreaterThanMax/response.verified.txt new file mode 100644 index 00000000..45238aeb --- /dev/null +++ b/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/AddField_Should_Return_BadRequest_For_Invalid_MinMax_Constraints/FloatMinGreaterThanMax/response.verified.txt @@ -0,0 +1,20 @@ +{ + Status: 400 Bad Request, + Content: { + Headers: { + Content-Length: 254, + Content-Type: application/problem+json; charset=utf-8 + }, + Value: { + type: https://tools.ietf.org/html/rfc9110#section-15.5.1, + title: One or more validation errors occurred., + status: 400, + errors: { + : [ + Min value cannot be greater than max value. + ] + }, + traceId: {Scrubbed} + } + } +} \ No newline at end of file diff --git a/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/AddField_Should_Return_BadRequest_For_Invalid_MinMax_Constraints/IntMinGreaterThanMax/response.verified.txt b/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/AddField_Should_Return_BadRequest_For_Invalid_MinMax_Constraints/IntMinGreaterThanMax/response.verified.txt new file mode 100644 index 00000000..45238aeb --- /dev/null +++ b/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/AddField_Should_Return_BadRequest_For_Invalid_MinMax_Constraints/IntMinGreaterThanMax/response.verified.txt @@ -0,0 +1,20 @@ +{ + Status: 400 Bad Request, + Content: { + Headers: { + Content-Length: 254, + Content-Type: application/problem+json; charset=utf-8 + }, + Value: { + type: https://tools.ietf.org/html/rfc9110#section-15.5.1, + title: One or more validation errors occurred., + status: 400, + errors: { + : [ + Min value cannot be greater than max value. + ] + }, + traceId: {Scrubbed} + } + } +} \ No newline at end of file diff --git a/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/AddField_Should_Return_BadRequest_For_Invalid_MinMax_Constraints/StringBothNegative/response.verified.txt b/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/AddField_Should_Return_BadRequest_For_Invalid_MinMax_Constraints/StringBothNegative/response.verified.txt new file mode 100644 index 00000000..b2e2e9e2 --- /dev/null +++ b/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/AddField_Should_Return_BadRequest_For_Invalid_MinMax_Constraints/StringBothNegative/response.verified.txt @@ -0,0 +1,23 @@ +{ + Status: 400 Bad Request, + Content: { + Headers: { + Content-Length: 305, + Content-Type: application/problem+json; charset=utf-8 + }, + Value: { + type: https://tools.ietf.org/html/rfc9110#section-15.5.1, + title: One or more validation errors occurred., + status: 400, + errors: { + Max: [ + Max value is invalid for the field type. + ], + Min: [ + Min value is invalid for the field type. + ] + }, + traceId: {Scrubbed} + } + } +} \ No newline at end of file diff --git a/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/AddField_Should_Return_BadRequest_For_Invalid_MinMax_Constraints/StringDecimalMax/response.verified.txt b/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/AddField_Should_Return_BadRequest_For_Invalid_MinMax_Constraints/StringDecimalMax/response.verified.txt new file mode 100644 index 00000000..4c02c845 --- /dev/null +++ b/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/AddField_Should_Return_BadRequest_For_Invalid_MinMax_Constraints/StringDecimalMax/response.verified.txt @@ -0,0 +1,20 @@ +{ + Status: 400 Bad Request, + Content: { + Headers: { + Content-Length: 254, + Content-Type: application/problem+json; charset=utf-8 + }, + Value: { + type: https://tools.ietf.org/html/rfc9110#section-15.5.1, + title: One or more validation errors occurred., + status: 400, + errors: { + Max: [ + Max value is invalid for the field type. + ] + }, + traceId: {Scrubbed} + } + } +} \ No newline at end of file diff --git a/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/AddField_Should_Return_BadRequest_For_Invalid_MinMax_Constraints/StringDecimalMin/response.verified.txt b/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/AddField_Should_Return_BadRequest_For_Invalid_MinMax_Constraints/StringDecimalMin/response.verified.txt new file mode 100644 index 00000000..1e495944 --- /dev/null +++ b/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/AddField_Should_Return_BadRequest_For_Invalid_MinMax_Constraints/StringDecimalMin/response.verified.txt @@ -0,0 +1,20 @@ +{ + Status: 400 Bad Request, + Content: { + Headers: { + Content-Length: 254, + Content-Type: application/problem+json; charset=utf-8 + }, + Value: { + type: https://tools.ietf.org/html/rfc9110#section-15.5.1, + title: One or more validation errors occurred., + status: 400, + errors: { + Min: [ + Min value is invalid for the field type. + ] + }, + traceId: {Scrubbed} + } + } +} \ No newline at end of file diff --git a/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/AddField_Should_Return_BadRequest_For_Invalid_MinMax_Constraints/StringMinGreaterThanMax/response.verified.txt b/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/AddField_Should_Return_BadRequest_For_Invalid_MinMax_Constraints/StringMinGreaterThanMax/response.verified.txt new file mode 100644 index 00000000..45238aeb --- /dev/null +++ b/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/AddField_Should_Return_BadRequest_For_Invalid_MinMax_Constraints/StringMinGreaterThanMax/response.verified.txt @@ -0,0 +1,20 @@ +{ + Status: 400 Bad Request, + Content: { + Headers: { + Content-Length: 254, + Content-Type: application/problem+json; charset=utf-8 + }, + Value: { + type: https://tools.ietf.org/html/rfc9110#section-15.5.1, + title: One or more validation errors occurred., + status: 400, + errors: { + : [ + Min value cannot be greater than max value. + ] + }, + traceId: {Scrubbed} + } + } +} \ No newline at end of file diff --git a/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/AddField_Should_Return_BadRequest_For_Invalid_MinMax_Constraints/StringNegativeMin/response.verified.txt b/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/AddField_Should_Return_BadRequest_For_Invalid_MinMax_Constraints/StringNegativeMin/response.verified.txt new file mode 100644 index 00000000..1e495944 --- /dev/null +++ b/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/AddField_Should_Return_BadRequest_For_Invalid_MinMax_Constraints/StringNegativeMin/response.verified.txt @@ -0,0 +1,20 @@ +{ + Status: 400 Bad Request, + Content: { + Headers: { + Content-Length: 254, + Content-Type: application/problem+json; charset=utf-8 + }, + Value: { + type: https://tools.ietf.org/html/rfc9110#section-15.5.1, + title: One or more validation errors occurred., + status: 400, + errors: { + Min: [ + Min value is invalid for the field type. + ] + }, + traceId: {Scrubbed} + } + } +} \ No newline at end of file diff --git a/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/DeleteModel_Should_Delete_Model_File/response.verified.txt b/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/DeleteModel_Should_Delete_Model_File/response.verified.txt index 656a5ecc..26676718 100644 --- a/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/DeleteModel_Should_Delete_Model_File/response.verified.txt +++ b/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/DeleteModel_Should_Delete_Model_File/response.verified.txt @@ -2,12 +2,12 @@ Status: 200 OK, Content: { Headers: { - Content-Length: 180, + Content-Length: 100, Content-Type: application/json; charset=utf-8 }, Value: { Message: Model 'TestDeleteModel' deleted successfully., - FilePath: {CurrentDirectory}Entities/TestDeleteModel.cs + FilePath: Entities/TestDeleteModel.cs } } } \ No newline at end of file diff --git a/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/DeleteModel_Should_Delete_Relations_And_References/response.verified.txt b/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/DeleteModel_Should_Delete_Relations_And_References/response.verified.txt index f85b2801..91ecf30a 100644 --- a/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/DeleteModel_Should_Delete_Relations_And_References/response.verified.txt +++ b/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/DeleteModel_Should_Delete_Relations_And_References/response.verified.txt @@ -2,12 +2,12 @@ Status: 200 OK, Content: { Headers: { - Content-Length: 158, + Content-Length: 78, Content-Type: application/json; charset=utf-8 }, Value: { Message: Model 'User' deleted successfully., - FilePath: {CurrentDirectory}Entities/User.cs + FilePath: Entities/User.cs } } } \ No newline at end of file diff --git a/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/Other_Relations_Should_Not_Be_Deleted/response.verified.txt b/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/Other_Relations_Should_Not_Be_Deleted/response.verified.txt index f85b2801..91ecf30a 100644 --- a/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/Other_Relations_Should_Not_Be_Deleted/response.verified.txt +++ b/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/Other_Relations_Should_Not_Be_Deleted/response.verified.txt @@ -2,12 +2,12 @@ Status: 200 OK, Content: { Headers: { - Content-Length: 158, + Content-Length: 78, Content-Type: application/json; charset=utf-8 }, Value: { Message: Model 'User' deleted successfully., - FilePath: {CurrentDirectory}Entities/User.cs + FilePath: Entities/User.cs } } } \ No newline at end of file diff --git a/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/UpdateField_Should_Accept_Valid_MinMax_Update/DoubleMinMax/model.verified.txt b/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/UpdateField_Should_Accept_Valid_MinMax_Update/DoubleMinMax/model.verified.txt new file mode 100644 index 00000000..06f2ba0f --- /dev/null +++ b/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/UpdateField_Should_Accept_Valid_MinMax_Update/DoubleMinMax/model.verified.txt @@ -0,0 +1,20 @@ +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using Dappi.HeadlessCms.Models; +using Dappi.Core.Attributes; +using Dappi.HeadlessCms.Core.Attributes; +using Dappi.Core.Enums; + +namespace Entities +{ + [CcController] + public class UpdateValidMinMaxDoubleMinMax + { + [Key] + [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + public Guid Id { get; set; } + + [Range(-99.5, 99.5)] + public double? TestField { get; set; } + } +} \ No newline at end of file diff --git a/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/UpdateField_Should_Accept_Valid_MinMax_Update/DoubleMinMax/response.verified.txt b/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/UpdateField_Should_Accept_Valid_MinMax_Update/DoubleMinMax/response.verified.txt new file mode 100644 index 00000000..eb9297b0 --- /dev/null +++ b/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/UpdateField_Should_Accept_Valid_MinMax_Update/DoubleMinMax/response.verified.txt @@ -0,0 +1,13 @@ +{ + Status: 200 OK, + Content: { + Headers: { + Content-Length: 155, + Content-Type: application/json; charset=utf-8 + }, + Value: { + Message: Field 'TestField' updated successfully to 'TestField' in 'UpdateValidMinMaxDoubleMinMax' model., + FilePath: UpdateValidMinMaxDoubleMinMax.cs + } + } +} \ No newline at end of file diff --git a/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/UpdateField_Should_Accept_Valid_MinMax_Update/FloatMinMax/model.verified.txt b/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/UpdateField_Should_Accept_Valid_MinMax_Update/FloatMinMax/model.verified.txt new file mode 100644 index 00000000..db1ce3e2 --- /dev/null +++ b/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/UpdateField_Should_Accept_Valid_MinMax_Update/FloatMinMax/model.verified.txt @@ -0,0 +1,20 @@ +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using Dappi.HeadlessCms.Models; +using Dappi.Core.Attributes; +using Dappi.HeadlessCms.Core.Attributes; +using Dappi.Core.Enums; + +namespace Entities +{ + [CcController] + public class UpdateValidMinMaxFloatMinMax + { + [Key] + [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + public Guid Id { get; set; } + + [Range(0.5, 100.5)] + public float? TestField { get; set; } + } +} \ No newline at end of file diff --git a/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/UpdateField_Should_Accept_Valid_MinMax_Update/FloatMinMax/response.verified.txt b/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/UpdateField_Should_Accept_Valid_MinMax_Update/FloatMinMax/response.verified.txt new file mode 100644 index 00000000..ef4a777c --- /dev/null +++ b/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/UpdateField_Should_Accept_Valid_MinMax_Update/FloatMinMax/response.verified.txt @@ -0,0 +1,13 @@ +{ + Status: 200 OK, + Content: { + Headers: { + Content-Length: 153, + Content-Type: application/json; charset=utf-8 + }, + Value: { + Message: Field 'TestField' updated successfully to 'TestField' in 'UpdateValidMinMaxFloatMinMax' model., + FilePath: UpdateValidMinMaxFloatMinMax.cs + } + } +} \ No newline at end of file diff --git a/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/UpdateField_Should_Accept_Valid_MinMax_Update/IntEqual/model.verified.txt b/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/UpdateField_Should_Accept_Valid_MinMax_Update/IntEqual/model.verified.txt new file mode 100644 index 00000000..90b8ea15 --- /dev/null +++ b/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/UpdateField_Should_Accept_Valid_MinMax_Update/IntEqual/model.verified.txt @@ -0,0 +1,20 @@ +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using Dappi.HeadlessCms.Models; +using Dappi.Core.Attributes; +using Dappi.HeadlessCms.Core.Attributes; +using Dappi.Core.Enums; + +namespace Entities +{ + [CcController] + public class UpdateValidMinMaxIntEqual + { + [Key] + [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + public Guid Id { get; set; } + + [Range(5, 5)] + public int? TestField { get; set; } + } +} \ No newline at end of file diff --git a/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/UpdateField_Should_Accept_Valid_MinMax_Update/IntEqual/response.verified.txt b/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/UpdateField_Should_Accept_Valid_MinMax_Update/IntEqual/response.verified.txt new file mode 100644 index 00000000..b0bd0e72 --- /dev/null +++ b/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/UpdateField_Should_Accept_Valid_MinMax_Update/IntEqual/response.verified.txt @@ -0,0 +1,13 @@ +{ + Status: 200 OK, + Content: { + Headers: { + Content-Length: 147, + Content-Type: application/json; charset=utf-8 + }, + Value: { + Message: Field 'TestField' updated successfully to 'TestField' in 'UpdateValidMinMaxIntEqual' model., + FilePath: UpdateValidMinMaxIntEqual.cs + } + } +} \ No newline at end of file diff --git a/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/UpdateField_Should_Accept_Valid_MinMax_Update/IntMinMax/model.verified.txt b/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/UpdateField_Should_Accept_Valid_MinMax_Update/IntMinMax/model.verified.txt new file mode 100644 index 00000000..e513fc6d --- /dev/null +++ b/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/UpdateField_Should_Accept_Valid_MinMax_Update/IntMinMax/model.verified.txt @@ -0,0 +1,20 @@ +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using Dappi.HeadlessCms.Models; +using Dappi.Core.Attributes; +using Dappi.HeadlessCms.Core.Attributes; +using Dappi.Core.Enums; + +namespace Entities +{ + [CcController] + public class UpdateValidMinMaxIntMinMax + { + [Key] + [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + public Guid Id { get; set; } + + [Range(0, 100)] + public int? TestField { get; set; } + } +} \ No newline at end of file diff --git a/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/UpdateField_Should_Accept_Valid_MinMax_Update/IntMinMax/response.verified.txt b/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/UpdateField_Should_Accept_Valid_MinMax_Update/IntMinMax/response.verified.txt new file mode 100644 index 00000000..e027422d --- /dev/null +++ b/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/UpdateField_Should_Accept_Valid_MinMax_Update/IntMinMax/response.verified.txt @@ -0,0 +1,13 @@ +{ + Status: 200 OK, + Content: { + Headers: { + Content-Length: 149, + Content-Type: application/json; charset=utf-8 + }, + Value: { + Message: Field 'TestField' updated successfully to 'TestField' in 'UpdateValidMinMaxIntMinMax' model., + FilePath: UpdateValidMinMaxIntMinMax.cs + } + } +} \ No newline at end of file diff --git a/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/UpdateField_Should_Accept_Valid_MinMax_Update/IntNegative/model.verified.txt b/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/UpdateField_Should_Accept_Valid_MinMax_Update/IntNegative/model.verified.txt new file mode 100644 index 00000000..40fa8bf5 --- /dev/null +++ b/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/UpdateField_Should_Accept_Valid_MinMax_Update/IntNegative/model.verified.txt @@ -0,0 +1,20 @@ +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using Dappi.HeadlessCms.Models; +using Dappi.Core.Attributes; +using Dappi.HeadlessCms.Core.Attributes; +using Dappi.Core.Enums; + +namespace Entities +{ + [CcController] + public class UpdateValidMinMaxIntNegative + { + [Key] + [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + public Guid Id { get; set; } + + [Range(-10, 10)] + public int? TestField { get; set; } + } +} \ No newline at end of file diff --git a/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/UpdateField_Should_Accept_Valid_MinMax_Update/IntNegative/response.verified.txt b/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/UpdateField_Should_Accept_Valid_MinMax_Update/IntNegative/response.verified.txt new file mode 100644 index 00000000..f6f62262 --- /dev/null +++ b/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/UpdateField_Should_Accept_Valid_MinMax_Update/IntNegative/response.verified.txt @@ -0,0 +1,13 @@ +{ + Status: 200 OK, + Content: { + Headers: { + Content-Length: 153, + Content-Type: application/json; charset=utf-8 + }, + Value: { + Message: Field 'TestField' updated successfully to 'TestField' in 'UpdateValidMinMaxIntNegative' model., + FilePath: UpdateValidMinMaxIntNegative.cs + } + } +} \ No newline at end of file diff --git a/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/UpdateField_Should_Accept_Valid_MinMax_Update/StringMaxOnly/model.verified.txt b/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/UpdateField_Should_Accept_Valid_MinMax_Update/StringMaxOnly/model.verified.txt new file mode 100644 index 00000000..a17673ba --- /dev/null +++ b/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/UpdateField_Should_Accept_Valid_MinMax_Update/StringMaxOnly/model.verified.txt @@ -0,0 +1,20 @@ +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using Dappi.HeadlessCms.Models; +using Dappi.Core.Attributes; +using Dappi.HeadlessCms.Core.Attributes; +using Dappi.Core.Enums; + +namespace Entities +{ + [CcController] + public class UpdateValidMinMaxStringMaxOnly + { + [Key] + [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + public Guid Id { get; set; } + + [MaxLength(50)] + public string? TestField { get; set; } + } +} \ No newline at end of file diff --git a/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/UpdateField_Should_Accept_Valid_MinMax_Update/StringMaxOnly/response.verified.txt b/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/UpdateField_Should_Accept_Valid_MinMax_Update/StringMaxOnly/response.verified.txt new file mode 100644 index 00000000..601ca9d8 --- /dev/null +++ b/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/UpdateField_Should_Accept_Valid_MinMax_Update/StringMaxOnly/response.verified.txt @@ -0,0 +1,13 @@ +{ + Status: 200 OK, + Content: { + Headers: { + Content-Length: 157, + Content-Type: application/json; charset=utf-8 + }, + Value: { + Message: Field 'TestField' updated successfully to 'TestField' in 'UpdateValidMinMaxStringMaxOnly' model., + FilePath: UpdateValidMinMaxStringMaxOnly.cs + } + } +} \ No newline at end of file diff --git a/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/UpdateField_Should_Accept_Valid_MinMax_Update/StringMinMax/model.verified.txt b/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/UpdateField_Should_Accept_Valid_MinMax_Update/StringMinMax/model.verified.txt new file mode 100644 index 00000000..58bf8b01 --- /dev/null +++ b/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/UpdateField_Should_Accept_Valid_MinMax_Update/StringMinMax/model.verified.txt @@ -0,0 +1,20 @@ +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using Dappi.HeadlessCms.Models; +using Dappi.Core.Attributes; +using Dappi.HeadlessCms.Core.Attributes; +using Dappi.Core.Enums; + +namespace Entities +{ + [CcController] + public class UpdateValidMinMaxStringMinMax + { + [Key] + [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + public Guid Id { get; set; } + + [Length(0, 10)] + public string? TestField { get; set; } + } +} \ No newline at end of file diff --git a/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/UpdateField_Should_Accept_Valid_MinMax_Update/StringMinMax/response.verified.txt b/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/UpdateField_Should_Accept_Valid_MinMax_Update/StringMinMax/response.verified.txt new file mode 100644 index 00000000..292ddbe3 --- /dev/null +++ b/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/UpdateField_Should_Accept_Valid_MinMax_Update/StringMinMax/response.verified.txt @@ -0,0 +1,13 @@ +{ + Status: 200 OK, + Content: { + Headers: { + Content-Length: 155, + Content-Type: application/json; charset=utf-8 + }, + Value: { + Message: Field 'TestField' updated successfully to 'TestField' in 'UpdateValidMinMaxStringMinMax' model., + FilePath: UpdateValidMinMaxStringMinMax.cs + } + } +} \ No newline at end of file diff --git a/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/UpdateField_Should_Accept_Valid_MinMax_Update/StringMinOnly/model.verified.txt b/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/UpdateField_Should_Accept_Valid_MinMax_Update/StringMinOnly/model.verified.txt new file mode 100644 index 00000000..b57a6a68 --- /dev/null +++ b/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/UpdateField_Should_Accept_Valid_MinMax_Update/StringMinOnly/model.verified.txt @@ -0,0 +1,20 @@ +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using Dappi.HeadlessCms.Models; +using Dappi.Core.Attributes; +using Dappi.HeadlessCms.Core.Attributes; +using Dappi.Core.Enums; + +namespace Entities +{ + [CcController] + public class UpdateValidMinMaxStringMinOnly + { + [Key] + [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + public Guid Id { get; set; } + + [MinLength(0)] + public string? TestField { get; set; } + } +} \ No newline at end of file diff --git a/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/UpdateField_Should_Accept_Valid_MinMax_Update/StringMinOnly/response.verified.txt b/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/UpdateField_Should_Accept_Valid_MinMax_Update/StringMinOnly/response.verified.txt new file mode 100644 index 00000000..48941e06 --- /dev/null +++ b/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/UpdateField_Should_Accept_Valid_MinMax_Update/StringMinOnly/response.verified.txt @@ -0,0 +1,13 @@ +{ + Status: 200 OK, + Content: { + Headers: { + Content-Length: 157, + Content-Type: application/json; charset=utf-8 + }, + Value: { + Message: Field 'TestField' updated successfully to 'TestField' in 'UpdateValidMinMaxStringMinOnly' model., + FilePath: UpdateValidMinMaxStringMinOnly.cs + } + } +} \ No newline at end of file diff --git a/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/UpdateField_Should_Return_BadRequest_For_Invalid_MinMax_Update/DoubleMinGreaterThanMax/response.verified.txt b/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/UpdateField_Should_Return_BadRequest_For_Invalid_MinMax_Update/DoubleMinGreaterThanMax/response.verified.txt new file mode 100644 index 00000000..45238aeb --- /dev/null +++ b/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/UpdateField_Should_Return_BadRequest_For_Invalid_MinMax_Update/DoubleMinGreaterThanMax/response.verified.txt @@ -0,0 +1,20 @@ +{ + Status: 400 Bad Request, + Content: { + Headers: { + Content-Length: 254, + Content-Type: application/problem+json; charset=utf-8 + }, + Value: { + type: https://tools.ietf.org/html/rfc9110#section-15.5.1, + title: One or more validation errors occurred., + status: 400, + errors: { + : [ + Min value cannot be greater than max value. + ] + }, + traceId: {Scrubbed} + } + } +} \ No newline at end of file diff --git a/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/UpdateField_Should_Return_BadRequest_For_Invalid_MinMax_Update/FloatMinGreaterThanMax/response.verified.txt b/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/UpdateField_Should_Return_BadRequest_For_Invalid_MinMax_Update/FloatMinGreaterThanMax/response.verified.txt new file mode 100644 index 00000000..45238aeb --- /dev/null +++ b/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/UpdateField_Should_Return_BadRequest_For_Invalid_MinMax_Update/FloatMinGreaterThanMax/response.verified.txt @@ -0,0 +1,20 @@ +{ + Status: 400 Bad Request, + Content: { + Headers: { + Content-Length: 254, + Content-Type: application/problem+json; charset=utf-8 + }, + Value: { + type: https://tools.ietf.org/html/rfc9110#section-15.5.1, + title: One or more validation errors occurred., + status: 400, + errors: { + : [ + Min value cannot be greater than max value. + ] + }, + traceId: {Scrubbed} + } + } +} \ No newline at end of file diff --git a/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/UpdateField_Should_Return_BadRequest_For_Invalid_MinMax_Update/IntMinGreaterThanMax/response.verified.txt b/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/UpdateField_Should_Return_BadRequest_For_Invalid_MinMax_Update/IntMinGreaterThanMax/response.verified.txt new file mode 100644 index 00000000..45238aeb --- /dev/null +++ b/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/UpdateField_Should_Return_BadRequest_For_Invalid_MinMax_Update/IntMinGreaterThanMax/response.verified.txt @@ -0,0 +1,20 @@ +{ + Status: 400 Bad Request, + Content: { + Headers: { + Content-Length: 254, + Content-Type: application/problem+json; charset=utf-8 + }, + Value: { + type: https://tools.ietf.org/html/rfc9110#section-15.5.1, + title: One or more validation errors occurred., + status: 400, + errors: { + : [ + Min value cannot be greater than max value. + ] + }, + traceId: {Scrubbed} + } + } +} \ No newline at end of file diff --git a/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/UpdateField_Should_Return_BadRequest_For_Invalid_MinMax_Update/StringBothNegative/response.verified.txt b/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/UpdateField_Should_Return_BadRequest_For_Invalid_MinMax_Update/StringBothNegative/response.verified.txt new file mode 100644 index 00000000..b2e2e9e2 --- /dev/null +++ b/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/UpdateField_Should_Return_BadRequest_For_Invalid_MinMax_Update/StringBothNegative/response.verified.txt @@ -0,0 +1,23 @@ +{ + Status: 400 Bad Request, + Content: { + Headers: { + Content-Length: 305, + Content-Type: application/problem+json; charset=utf-8 + }, + Value: { + type: https://tools.ietf.org/html/rfc9110#section-15.5.1, + title: One or more validation errors occurred., + status: 400, + errors: { + Max: [ + Max value is invalid for the field type. + ], + Min: [ + Min value is invalid for the field type. + ] + }, + traceId: {Scrubbed} + } + } +} \ No newline at end of file diff --git a/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/UpdateField_Should_Return_BadRequest_For_Invalid_MinMax_Update/StringDecimalMax/response.verified.txt b/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/UpdateField_Should_Return_BadRequest_For_Invalid_MinMax_Update/StringDecimalMax/response.verified.txt new file mode 100644 index 00000000..4c02c845 --- /dev/null +++ b/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/UpdateField_Should_Return_BadRequest_For_Invalid_MinMax_Update/StringDecimalMax/response.verified.txt @@ -0,0 +1,20 @@ +{ + Status: 400 Bad Request, + Content: { + Headers: { + Content-Length: 254, + Content-Type: application/problem+json; charset=utf-8 + }, + Value: { + type: https://tools.ietf.org/html/rfc9110#section-15.5.1, + title: One or more validation errors occurred., + status: 400, + errors: { + Max: [ + Max value is invalid for the field type. + ] + }, + traceId: {Scrubbed} + } + } +} \ No newline at end of file diff --git a/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/UpdateField_Should_Return_BadRequest_For_Invalid_MinMax_Update/StringDecimalMin/response.verified.txt b/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/UpdateField_Should_Return_BadRequest_For_Invalid_MinMax_Update/StringDecimalMin/response.verified.txt new file mode 100644 index 00000000..1e495944 --- /dev/null +++ b/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/UpdateField_Should_Return_BadRequest_For_Invalid_MinMax_Update/StringDecimalMin/response.verified.txt @@ -0,0 +1,20 @@ +{ + Status: 400 Bad Request, + Content: { + Headers: { + Content-Length: 254, + Content-Type: application/problem+json; charset=utf-8 + }, + Value: { + type: https://tools.ietf.org/html/rfc9110#section-15.5.1, + title: One or more validation errors occurred., + status: 400, + errors: { + Min: [ + Min value is invalid for the field type. + ] + }, + traceId: {Scrubbed} + } + } +} \ No newline at end of file diff --git a/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/UpdateField_Should_Return_BadRequest_For_Invalid_MinMax_Update/StringMinGreaterThanMax/response.verified.txt b/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/UpdateField_Should_Return_BadRequest_For_Invalid_MinMax_Update/StringMinGreaterThanMax/response.verified.txt new file mode 100644 index 00000000..45238aeb --- /dev/null +++ b/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/UpdateField_Should_Return_BadRequest_For_Invalid_MinMax_Update/StringMinGreaterThanMax/response.verified.txt @@ -0,0 +1,20 @@ +{ + Status: 400 Bad Request, + Content: { + Headers: { + Content-Length: 254, + Content-Type: application/problem+json; charset=utf-8 + }, + Value: { + type: https://tools.ietf.org/html/rfc9110#section-15.5.1, + title: One or more validation errors occurred., + status: 400, + errors: { + : [ + Min value cannot be greater than max value. + ] + }, + traceId: {Scrubbed} + } + } +} \ No newline at end of file diff --git a/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/UpdateField_Should_Return_BadRequest_For_Invalid_MinMax_Update/StringNegativeMin/response.verified.txt b/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/UpdateField_Should_Return_BadRequest_For_Invalid_MinMax_Update/StringNegativeMin/response.verified.txt new file mode 100644 index 00000000..1e495944 --- /dev/null +++ b/Dappi.HeadlessCms.Tests/snapshots/ModelsControllerTests/UpdateField_Should_Return_BadRequest_For_Invalid_MinMax_Update/StringNegativeMin/response.verified.txt @@ -0,0 +1,20 @@ +{ + Status: 400 Bad Request, + Content: { + Headers: { + Content-Length: 254, + Content-Type: application/problem+json; charset=utf-8 + }, + Value: { + type: https://tools.ietf.org/html/rfc9110#section-15.5.1, + title: One or more validation errors occurred., + status: 400, + errors: { + Min: [ + Min value is invalid for the field type. + ] + }, + traceId: {Scrubbed} + } + } +} \ No newline at end of file diff --git a/Dappi.HeadlessCms/Controllers/ModelsController.cs b/Dappi.HeadlessCms/Controllers/ModelsController.cs index e75e4f97..b661fa88 100644 --- a/Dappi.HeadlessCms/Controllers/ModelsController.cs +++ b/Dappi.HeadlessCms/Controllers/ModelsController.cs @@ -137,7 +137,11 @@ public async Task DeleteModel(string modelName) await _contentTypeChangesService.AddContentTypeChangeAsync(modelName, new Dictionary(), ContentTypeState.PendingDelete); - return Ok(new { Message = $"Model '{modelName}' deleted successfully.", FilePath = modelFilePath }); + return Ok(new + { + Message = $"Model '{modelName}' deleted successfully.", + FilePath = Path.GetRelativePath(Directory.GetCurrentDirectory(), modelFilePath) + }); } [HttpPut("{modelName}")] @@ -252,7 +256,7 @@ await _contentTypeChangesService.UpdateContentTypeChangeFieldsAsync(request.Rela { Message = $"Field '{request.FieldName}' of type '{request.FieldType}' added successfully to '{modelName}' model.", - FilePath = modelFilePath + FilePath = Path.GetRelativePath(Directory.GetCurrentDirectory(), modelFilePath) }); } @@ -370,7 +374,7 @@ public async Task UpdateField(string modelName, [FromBody] Update return Ok(new { Message = $"Field '{request.OldFieldName}' updated successfully to '{request.NewFieldName}' in '{modelName}' model.", - FilePath = modelFilePath + FilePath = Path.GetRelativePath(_entitiesFolderPath, modelFilePath) }); } @@ -419,7 +423,7 @@ public async Task DeleteField(string modelName, string fieldName) return Ok(new { Message = $"Field '{fieldName}' deleted successfully from '{modelName}' model.", - FilePath = modelFilePath + FilePath = Path.GetRelativePath(_entitiesFolderPath, modelFilePath) }); } diff --git a/Dappi.HeadlessCms/Core/Extensions/RoslynHelpers.cs b/Dappi.HeadlessCms/Core/Extensions/RoslynHelpers.cs index a039cbc9..68631a12 100644 --- a/Dappi.HeadlessCms/Core/Extensions/RoslynHelpers.cs +++ b/Dappi.HeadlessCms/Core/Extensions/RoslynHelpers.cs @@ -168,45 +168,48 @@ public static PropertyDeclarationSyntax WithRangeAttribute(this PropertyDeclarat } } - if (minDouble == null) + ExpressionSyntax CreateMinMaxExpression(string typeName, bool isMax) { - minDouble = propertyType.ToLower() switch + var keyword = typeName.ToLower() switch { - "int" => int.MinValue, - "float" => float.MinValue, - "double" => double.MinValue, - "decimal" => (double)decimal.MinValue, - "long" => long.MinValue, - "short" => short.MinValue, - "byte" => byte.MinValue, - _ => double.MinValue + "int" => SyntaxKind.IntKeyword, + "float" => SyntaxKind.FloatKeyword, + "double" => SyntaxKind.DoubleKeyword, + _ => SyntaxKind.DoubleKeyword }; + + return SyntaxFactory.MemberAccessExpression( + SyntaxKind.SimpleMemberAccessExpression, + SyntaxFactory.PredefinedType(SyntaxFactory.Token(keyword)), + SyntaxFactory.IdentifierName(isMax ? "MaxValue" : "MinValue")); + } + + ExpressionSyntax minExpression; + if (minDouble == null) + { + minExpression = CreateMinMaxExpression(propertyType, false); + } + else + { + minExpression = SyntaxFactory.LiteralExpression( + SyntaxKind.NumericLiteralExpression, + SyntaxFactory.Literal(minDouble.Value.ToString(System.Globalization.CultureInfo.InvariantCulture), minDouble.Value)); } + ExpressionSyntax maxExpression; if (maxDouble == null) { - maxDouble = propertyType.ToLower() switch - { - "int" => int.MaxValue, - "float" => float.MaxValue, - "double" => double.MaxValue, - "decimal" => (double)decimal.MaxValue, - "long" => long.MaxValue, - "short" => short.MaxValue, - "byte" => byte.MaxValue, - _ => double.MaxValue - }; + maxExpression = CreateMinMaxExpression(propertyType, true); + } + else + { + maxExpression = SyntaxFactory.LiteralExpression( + SyntaxKind.NumericLiteralExpression, + SyntaxFactory.Literal(maxDouble.Value.ToString(System.Globalization.CultureInfo.InvariantCulture), maxDouble.Value)); } - var minLiteral = SyntaxFactory.LiteralExpression( - SyntaxKind.NumericLiteralExpression, - SyntaxFactory.Literal(minDouble.Value.ToString(System.Globalization.CultureInfo.InvariantCulture), minDouble.Value)); - var maxLiteral = SyntaxFactory.LiteralExpression( - SyntaxKind.NumericLiteralExpression, - SyntaxFactory.Literal(maxDouble.Value.ToString(System.Globalization.CultureInfo.InvariantCulture), maxDouble.Value)); - - arguments.Add(SyntaxFactory.AttributeArgument(minLiteral)); - arguments.Add(SyntaxFactory.AttributeArgument(maxLiteral)); + arguments.Add(SyntaxFactory.AttributeArgument(minExpression)); + arguments.Add(SyntaxFactory.AttributeArgument(maxExpression)); attribute = attribute.WithArgumentList( SyntaxFactory.AttributeArgumentList(SyntaxFactory.SeparatedList(arguments)) diff --git a/Dappi.HeadlessCms/Dappi.HeadlessCms.csproj b/Dappi.HeadlessCms/Dappi.HeadlessCms.csproj index 2b8024c5..745a384c 100644 --- a/Dappi.HeadlessCms/Dappi.HeadlessCms.csproj +++ b/Dappi.HeadlessCms/Dappi.HeadlessCms.csproj @@ -11,6 +11,7 @@ + diff --git a/Dappi.HeadlessCms/Models/UpdateFieldRequest.cs b/Dappi.HeadlessCms/Models/UpdateFieldRequest.cs index 2d85cd03..3586fb86 100644 --- a/Dappi.HeadlessCms/Models/UpdateFieldRequest.cs +++ b/Dappi.HeadlessCms/Models/UpdateFieldRequest.cs @@ -10,6 +10,8 @@ public class UpdateFieldRequest [Required] public string NewFieldName { get; set; } = null!; + public required string FieldType { get; set; } + public bool IsRequired { get; set; } = false; public string? Regex { get; set; } diff --git a/Dappi.HeadlessCms/ServiceExtensions.cs b/Dappi.HeadlessCms/ServiceExtensions.cs index c6039512..397d605a 100644 --- a/Dappi.HeadlessCms/ServiceExtensions.cs +++ b/Dappi.HeadlessCms/ServiceExtensions.cs @@ -9,6 +9,9 @@ using Dappi.HeadlessCms.Services; using Dappi.HeadlessCms.Services.Identity; using Dappi.HeadlessCms.Core; +using Dappi.HeadlessCms.Validators; +using FluentValidation; +using FluentValidation.AspNetCore; using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; @@ -62,6 +65,9 @@ public static IServiceCollection AddDappi( services.AddScoped(); services.AddDappiSwaggerGen(); + services.AddFluentValidationAutoValidation(); + services.AddValidatorsFromAssemblyContaining(); + services.AddControllers() .AddJsonOptions(jsonOptions ?? (options => { diff --git a/Dappi.HeadlessCms/Validators/FieldRequestValidator.cs b/Dappi.HeadlessCms/Validators/FieldRequestValidator.cs new file mode 100644 index 00000000..ab199e1e --- /dev/null +++ b/Dappi.HeadlessCms/Validators/FieldRequestValidator.cs @@ -0,0 +1,47 @@ +using Dappi.HeadlessCms.Models; +using FluentValidation; + +namespace Dappi.HeadlessCms.Validators; + +public class FieldRequestValidator : AbstractValidator +{ + public FieldRequestValidator() + { + RuleFor(x => x.Min) + .Must((request, min) => FieldValidationHelper.ValidateMinValue(request.FieldType, min)) + .WithMessage("Min value is invalid for the field type.") + .When(x => x.Min.HasValue); + + RuleFor(x => x.Max) + .Must((request, max) => FieldValidationHelper.ValidateMaxValue(request.FieldType, max)) + .WithMessage("Max value is invalid for the field type.") + .When(x => x.Max.HasValue); + + RuleFor(x => x) + .Must(request => FieldValidationHelper.ValidateMinMaxRelationship(request.Min, request.Max)) + .WithMessage("Min value cannot be greater than max value.") + .When(x => x.Min.HasValue && x.Max.HasValue); + } +} + +public class UpdateFieldRequestValidator : AbstractValidator +{ + public UpdateFieldRequestValidator() + { + RuleFor(x => x.Min) + .Must((request, min) => FieldValidationHelper.ValidateMinValue(request.FieldType, min)) + .WithMessage("Min value is invalid for the field type.") + .When(x => x.Min.HasValue); + + RuleFor(x => x.Max) + .Must((request, max) => FieldValidationHelper.ValidateMaxValue(request.FieldType, max)) + .WithMessage("Max value is invalid for the field type.") + .When(x => x.Max.HasValue); + + RuleFor(x => x) + .Must(request => FieldValidationHelper.ValidateMinMaxRelationship(request.Min, request.Max)) + .WithMessage("Min value cannot be greater than max value.") + .When(x => x.Min.HasValue && x.Max.HasValue); + } +} + diff --git a/Dappi.HeadlessCms/Validators/FieldValidationHelper.cs b/Dappi.HeadlessCms/Validators/FieldValidationHelper.cs new file mode 100644 index 00000000..b4d84ae3 --- /dev/null +++ b/Dappi.HeadlessCms/Validators/FieldValidationHelper.cs @@ -0,0 +1,52 @@ +namespace Dappi.HeadlessCms.Validators; + +public static class FieldValidationHelper +{ + public static readonly string[] TextTypes = ["string"]; + public static readonly string[] NumericTypes = ["int", "double", "float"]; + + + public static bool ValidateMinValue(string fieldType, double? min) + { + if (!min.HasValue) + return true; + + if (TextTypes.Contains(fieldType)) + { + return min.Value >= 0 && Math.Floor(min.Value) == min.Value; + } + + if (NumericTypes.Contains(fieldType)) + { + return !double.IsNaN(min.Value); + } + + return true; + } + + public static bool ValidateMaxValue(string fieldType, double? max) + { + if (!max.HasValue) + return true; + + if (TextTypes.Contains(fieldType)) + { + return max.Value >= 0 && Math.Floor(max.Value) == max.Value; + } + + if (NumericTypes.Contains(fieldType)) + { + return !double.IsNaN(max.Value); + } + + return true; + } + + public static bool ValidateMinMaxRelationship(double? min, double? max) + { + if (!min.HasValue || !max.HasValue) + return true; + + return min.Value <= max.Value; + } +}