Skip to content

Commit 50e052a

Browse files
authored
BP-948: Add ValidationConfiguration support for fields when nullable is enabled (#49)
1 parent 4b6acb4 commit 50e052a

File tree

5 files changed

+52
-38
lines changed

5 files changed

+52
-38
lines changed

Enigmatry.Entry.CodeGeneration.Validation.Tests/Enigmatry.Entry.CodeGeneration.Validation.Tests.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
<PropertyGroup>
44
<TargetFramework>net8.0</TargetFramework>
5+
<Nullable>enable</Nullable>
56
<ImplicitUsings>enable</ImplicitUsings>
67
<IsPackable>false</IsPackable>
78
</PropertyGroup>

Enigmatry.Entry.CodeGeneration.Validation.Tests/ValidationConfigurationFixture.cs

Lines changed: 30 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
using System.Text.RegularExpressions;
1+
using Enigmatry.Entry.CodeGeneration.Validation.ValidationRules;
22
using FluentAssertions;
33
using Humanizer;
44
using NUnit.Framework;
@@ -11,7 +11,7 @@ public class ValidationConfigurationFixture
1111
[Test]
1212
public void ValidationConfiguration()
1313
{
14-
var validationConfiguration = new MockValidationModelConfiguration();
14+
var validationConfiguration = new ModelConfiguration();
1515

1616
validationConfiguration.ValidationRules
1717
.Where(x => x.PropertyName == nameof(ValidationMockModel.IntField).Camelize())
@@ -39,23 +39,23 @@ public void ValidationConfiguration()
3939
}
4040

4141
[TestCase(nameof(ValidationMockModel.IntField), "required", "", "validators.required")]
42-
[TestCase(nameof(ValidationMockModel.IntField), "min", MockValidationModelConfiguration.CustomMessage, "")]
43-
[TestCase(nameof(ValidationMockModel.IntField), "max", MockValidationModelConfiguration.CustomMessage, MockValidationModelConfiguration.CustomMessageTranlsationId)]
44-
[TestCase(nameof(ValidationMockModel.StringField), "required", MockValidationModelConfiguration.CustomMessage, MockValidationModelConfiguration.CustomMessageTranlsationId)]
45-
[TestCase(nameof(ValidationMockModel.StringField), "minLength", MockValidationModelConfiguration.CustomMessage, "")]
42+
[TestCase(nameof(ValidationMockModel.IntField), "min", ModelConfiguration.CustomMessage, "")]
43+
[TestCase(nameof(ValidationMockModel.IntField), "max", ModelConfiguration.CustomMessage, ModelConfiguration.CustomMessageTranslationId)]
44+
[TestCase(nameof(ValidationMockModel.StringField), "required", ModelConfiguration.CustomMessage, ModelConfiguration.CustomMessageTranslationId)]
45+
[TestCase(nameof(ValidationMockModel.StringField), "minLength", ModelConfiguration.CustomMessage, "")]
4646
[TestCase(nameof(ValidationMockModel.StringField), "maxLength", "", "validators.maxLength")]
4747
public void ValidationConfigurationPerValidationRule(
4848
string propertyName,
4949
string validationRuleName,
5050
string validationMessage,
5151
string validationMessageTranslationId)
5252
{
53-
var validationConfiguration = new MockValidationModelConfiguration();
53+
var validationConfiguration = new ModelConfiguration();
5454

5555
validationConfiguration.ValidationRules
5656
.Where(x => x.PropertyName == propertyName.Camelize())
5757
.Should().NotBeNullOrEmpty();
58-
var validationRule = validationConfiguration.ValidationRules
58+
IFormlyValidationRule? validationRule = validationConfiguration.ValidationRules
5959
.Where(x => x.PropertyName == propertyName.Camelize())
6060
.SingleOrDefault(rule => rule.FormlyRuleName == validationRuleName);
6161
validationRule.Should().NotBeNull();
@@ -66,7 +66,7 @@ public void ValidationConfigurationPerValidationRule(
6666
[Test]
6767
public void ValidationConfigurationForPatterns()
6868
{
69-
var validationConfiguration = new MockValidationModelWithPatternsConfiguration();
69+
var validationConfiguration = new PatternsConfiguration();
7070

7171
validationConfiguration.ValidationRules
7272
.Select(x => x.PropertyName.Pascalize())
@@ -96,18 +96,20 @@ public void ValidationConfigurationForPatterns()
9696
[Test]
9797
public void ValidationConfigurationForNullables()
9898
{
99-
var validationConfiguration = new MockValidationModelWithNullablesConfiguration();
99+
var validationConfiguration = new NullablesConfiguration();
100100

101101
validationConfiguration.ValidationRules
102102
.Select(x => x.PropertyName.Pascalize()).Distinct()
103103
.Should().BeEquivalentTo(
104104
nameof(ValidationMockModel.NullableIntField),
105105
nameof(ValidationMockModel.NullableDoubleField),
106-
nameof(ValidationMockModel.NullableByteField)
106+
nameof(ValidationMockModel.NullableByteField),
107+
nameof(ValidationMockModel.NullableStringField)
107108
);
109+
108110
validationConfiguration.ValidationRules
109111
.Select(x => x.FormlyRuleName).Distinct()
110-
.Should().BeEquivalentTo("required", "min", "max");
112+
.Should().BeEquivalentTo("required", "min", "max", "minLength", "maxLength", "pattern");
111113
validationConfiguration.ValidationRules
112114
.All(x => x.HasMessageTranslationId).Should().BeTrue();
113115
validationConfiguration.ValidationRules
@@ -117,55 +119,57 @@ public void ValidationConfigurationForNullables()
117119
.Should().BeEquivalentTo(
118120
"${field?.templateOptions?.label}:property-name: is required",
119121
"${field?.templateOptions?.label}:property-name: value should be more than ${field?.templateOptions?.min}:min-value:",
120-
"${field?.templateOptions?.label}:property-name: value should be less than ${field?.templateOptions?.max}:max-value:"
122+
"${field?.templateOptions?.label}:property-name: value should be less than ${field?.templateOptions?.max}:max-value:",
123+
"${field?.templateOptions?.label}:property-name: should have at least ${field?.templateOptions?.minLength}:min-value: characters",
124+
"${field?.templateOptions?.label}:property-name: value should be less than ${field?.templateOptions?.maxLength}:max-value: characters",
125+
"${field?.templateOptions?.label}:property-name: is not in valid format"
121126
);
122127
}
123128
}
124129

125130
#region Mocks
126131

127-
internal class MockValidationModelConfiguration : ValidationConfiguration<ValidationMockModel>
132+
internal class ModelConfiguration : ValidationConfiguration<ValidationMockModel>
128133
{
129134
public const string CustomMessage = "CUSTOM_VALIDATION_MESSAGE";
130-
public const string CustomMessageTranlsationId = "CUSTOM_VALIDATION_MESSAGE_TRANSLATION_ID";
135+
public const string CustomMessageTranslationId = "CUSTOM_VALIDATION_MESSAGE_TRANSLATION_ID";
131136

132-
public MockValidationModelConfiguration()
137+
public ModelConfiguration()
133138
{
134139
RuleFor(x => x.IntField)
135140
.IsRequired()
136141
.GreaterThen(0).WithMessage(CustomMessage)
137-
.LessThen(10).WithMessage(CustomMessage, CustomMessageTranlsationId);
142+
.LessThen(10).WithMessage(CustomMessage, CustomMessageTranslationId);
138143

139144
RuleFor(x => x.DoubleField)
140145
.IsRequired()
141146
.GreaterThen(0.5).WithMessage(CustomMessage)
142-
.LessThen(10).WithMessage(CustomMessage, CustomMessageTranlsationId);
147+
.LessThen(10).WithMessage(CustomMessage, CustomMessageTranslationId);
143148

144149
RuleFor(x => x.StringField)
145-
.IsRequired().WithMessage(CustomMessage, CustomMessageTranlsationId)
150+
.IsRequired().WithMessage(CustomMessage, CustomMessageTranslationId)
146151
.MinLength(0).WithMessage(CustomMessage)
147152
.MaxLength(10);
148153
}
149154
}
150155

151-
internal class MockValidationModelWithPatternsConfiguration : ValidationConfiguration<ValidationMockModel>
156+
internal class PatternsConfiguration : ValidationConfiguration<ValidationMockModel>
152157
{
153-
public MockValidationModelWithPatternsConfiguration()
158+
public PatternsConfiguration()
154159
{
155160
RuleFor(x => x.OtherStringField).EmailAddress();
156-
RuleFor(x => x.StringField).Match(new Regex("/[A-Z]/"));
157-
161+
RuleFor(x => x.StringField).Match(new("/[A-Z]/"));
158162
}
159163
}
160164

161-
internal class MockValidationModelWithNullablesConfiguration : ValidationConfiguration<ValidationMockModel>
165+
internal class NullablesConfiguration : ValidationConfiguration<ValidationMockModel>
162166
{
163-
public MockValidationModelWithNullablesConfiguration()
167+
public NullablesConfiguration()
164168
{
165169
RuleFor(x => x.NullableIntField).IsRequired().GreaterThen(1).LessThen(10);
166170
RuleFor(x => x.NullableDoubleField).IsRequired().GreaterThen(1.1).LessThen(10.1);
167171
RuleFor(x => x.NullableByteField).IsRequired().GreaterThen((byte)1).LessThen((byte)10);
168-
172+
RuleFor(x => x.NullableStringField).MinLength(0).MaxLength(100).Match(new("/[A-Z]/"));
169173
}
170174
}
171175

Enigmatry.Entry.CodeGeneration.Validation.Tests/ValidationMockModel.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,5 @@ internal class ValidationMockModel
1111
public DateTimeOffset DateTimeOffsetField { get; set; }
1212
public string StringField { get; set; } = String.Empty;
1313
public string OtherStringField { get; set; } = String.Empty;
14+
public string? NullableStringField { get; set; } = String.Empty;
1415
}

Enigmatry.Entry.CodeGeneration.Validation/InitialPropertyValidationBuilderExtensions.cs

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,16 +13,22 @@ public static IPropertyValidationBuilder<T, TProperty> IsRequired<T, TProperty>(
1313
var response = new PropertyValidationBuilder<T, TProperty>(builder.PropertyRule);
1414
response.SetValidationRule(new IsRequiredValidationRule(builder.PropertyRule.PropertyInfo, builder.PropertyRule.PropertyExpression));
1515
return response;
16-
}
17-
16+
}
17+
1818
#region STRINGS
19+
20+
// Disabling nullability for string extension methods below
21+
// It`s not possible to specify both nullable and non-nullable generic type parameter
22+
// https://github.com/dotnet/csharplang/blob/main/meetings/2019/LDM-2019-11-25.md
1923

24+
#nullable disable
25+
2026
public static IPropertyValidationBuilder<T, string> Match<T>(this IInitialPropertyValidationBuilder<T, string> builder, Regex rule)
2127
{
2228
var response = new PropertyValidationBuilder<T, string>(builder.PropertyRule);
2329
response.SetValidationRule(new PatternValidationRule(rule, builder.PropertyRule.PropertyInfo, builder.PropertyRule.PropertyExpression));
2430
return response;
25-
}
31+
}
2632

2733
public static IPropertyValidationBuilder<T, string> EmailAddress<T>(this IInitialPropertyValidationBuilder<T, string> builder)
2834
{
@@ -50,12 +56,14 @@ public static IPropertyValidationBuilder<T, string> Length<T>(this IInitialPrope
5056
var response = MinLength(builder, rule);
5157
MaxLength(response, rule);
5258
return response;
53-
}
59+
}
5460

61+
#nullable enable
62+
5563
#endregion STRINGS
56-
64+
5765
#region NUMBERS
58-
66+
5967
public static IPropertyValidationBuilder<T, TProperty> GreaterOrEqualTo<T, TProperty>(this IInitialPropertyValidationBuilder<T, TProperty> builder, TProperty rule)
6068
where TProperty : struct, IComparable, IComparable<TProperty>, IConvertible, IEquatable<TProperty>, IFormattable
6169
{
@@ -147,4 +155,4 @@ public static IPropertyValidationBuilder<T, TProperty> EqualTo<T, TProperty>(thi
147155
}
148156

149157
#endregion NUMBERS
150-
}
158+
}

Enigmatry.Entry.CodeGeneration.Validation/PropertyValidations/PropertyValidationBuilder.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,14 @@ namespace Enigmatry.Entry.CodeGeneration.Validation.PropertyValidations;
66

77
public interface IPropertyValidationBuilder<T, TProperty> : IInitialPropertyValidationBuilder<T, TProperty>
88
{
9-
public IPropertyValidationBuilder<T, TProperty> WithMessage(string message, string messageTranlsationId = "");
9+
public IPropertyValidationBuilder<T, TProperty> WithMessage(string message, string messageTranslationId = "");
1010
}
1111

1212
public class PropertyValidationBuilder<T, TProperty> : BasePropertyValidationBuilder<T, TProperty>, IPropertyValidationBuilder<T, TProperty>
1313
{
1414
public PropertyValidationBuilder(IPropertyValidation<T, TProperty> propertyRule) : base(propertyRule) { }
1515

16-
public IPropertyValidationBuilder<T, TProperty> WithMessage(string message, string messageTranlsationId = "")
16+
public IPropertyValidationBuilder<T, TProperty> WithMessage(string message, string messageTranslationId = "")
1717
{
1818
if (CurrentValidationRule == null)
1919
{
@@ -24,11 +24,11 @@ public IPropertyValidationBuilder<T, TProperty> WithMessage(string message, stri
2424

2525
CurrentValidationRule.SetCustomMessage(message);
2626

27-
if (!String.IsNullOrWhiteSpace(messageTranlsationId))
27+
if (!String.IsNullOrWhiteSpace(messageTranslationId))
2828
{
29-
CurrentValidationRule.SetMessageTranslationId(messageTranlsationId);
29+
CurrentValidationRule.SetMessageTranslationId(messageTranslationId);
3030
}
3131

3232
return this;
3333
}
34-
}
34+
}

0 commit comments

Comments
 (0)