Skip to content

Commit

Permalink
Merge pull request #14 from /issues/10
Browse files Browse the repository at this point in the history
issues-10 Update contracts and unit tests
  • Loading branch information
mr5z authored Dec 23, 2023
2 parents 07dc9bd + cedfa4f commit 688040e
Show file tree
Hide file tree
Showing 4 changed files with 76 additions and 13 deletions.
8 changes: 4 additions & 4 deletions src/Models/IRuleCollection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,23 +9,23 @@ public interface IRuleCollection<TModel>
{
IRuleCollection<TModel> AddRule<TProperty>(
Expression<Func<TModel, TProperty>> expression,
params ValidationRule<TProperty>[] rules);
params IValidationRule[] rules);

IRuleCollection<TModel> AddRule<TProperty>(
[NotNull]
string propertyName,
params ValidationRule<TProperty>[] rules);
params IValidationRule[] rules);

IRuleCollection<TModel> AddRule<TProperty>(
Expression<Func<TModel, TProperty>> expression,
string? errorMessageOverride,
params ValidationRule<TProperty>[] rules);
params IValidationRule[] rules);

IRuleCollection<TModel> AddRule<TProperty>(
[NotNull]
string propertyName,
string? errorMessageOverride,
params ValidationRule<TProperty>[] rules);
params IValidationRule[] rules);

IReadOnlyDictionary<string, IEnumerable<IValidationRule>> GetRules();
}
16 changes: 8 additions & 8 deletions src/Models/RuleCollection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,26 +36,26 @@ private void TargetInstance_PropertyChanged(object sender, PropertyChangedEventA

public IRuleCollection<TModel> AddRule<TProperty>(
Expression<Func<TModel, TProperty>> expression,
params ValidationRule<TProperty>[] rules)
params IValidationRule[] rules)
{
return AddRule(expression, null, rules);
}

public IRuleCollection<TModel> AddRule<TProperty>(
[NotNull] string propertyName,
params ValidationRule<TProperty>[] rules)
params IValidationRule[] rules)
{
return AddRule(propertyName, null, rules);
return AddRule<TProperty>(propertyName, null, rules);
}

public IRuleCollection<TModel> AddRule<TProperty>(
Expression<Func<TModel, TProperty>> expression,
string? errorMessageOverride,
params ValidationRule<TProperty>[] rules)
params IValidationRule[] rules)
{
var propertyName = expression.GetMemberName();
var propInfo = expression.GetPropertyInfo();
var result = AddRule(propertyName, errorMessageOverride, rules);
var result = AddRule<TProperty>(propertyName, errorMessageOverride, rules);
var value = propInfo.GetValue(this.target, null);
if (value is INotifyPropertyChanged notifiableObject)
{
Expand All @@ -68,13 +68,13 @@ public IRuleCollection<TModel> AddRule<TProperty>(
public IRuleCollection<TModel> AddRule<TProperty>(
[NotNull] string propertyName,
string? errorMessageOverride,
params ValidationRule<TProperty>[] rules)
params IValidationRule[] rules)
{
RegisterRuleFor(propertyName, errorMessageOverride, rules);
RegisterRuleFor<TProperty>(propertyName, errorMessageOverride, rules);
return this;
}

private void RegisterRuleFor<TProperty>(string propertyName, string? errorMessageOverride, params ValidationRule<TProperty>[] rules)
private void RegisterRuleFor<TProperty>(string propertyName, string? errorMessageOverride, params IValidationRule[] rules)
{
Array.ForEach(rules, rule => {
rule.PropertyName = propertyName;
Expand Down
1 change: 1 addition & 0 deletions src/Services/ValidationService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ private async Task ValidateByProperty<TValue>(string propertyName, TValue? value
throw new InvalidOperationException($"'{propertyName}' is not registered to validation rules.");

var resultArgs = GetValidationResultArgs(propertyName, value, propertyRules);

this.recentErrors[propertyName] = null;

UpdateRecentErrors(resultArgs);
Expand Down
64 changes: 63 additions & 1 deletion test/PropertyValidator.Test/ValidationService.test.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using PropertyValidator.Exceptions;
using PropertyValidator.Models;
using PropertyValidator.Services;
using PropertyValidator.ValidationPack;
Expand All @@ -8,7 +9,7 @@ public class Tests
{
public class DummyViewModel : INotifiableModel, System.ComponentModel.INotifyPropertyChanged
{
public void NotifyErrorPropertyChanged() => throw new NotImplementedException();
public void NotifyErrorPropertyChanged() { }
public event System.ComponentModel.PropertyChangedEventHandler? PropertyChanged;

Check warning on line 13 in test/PropertyValidator.Test/ValidationService.test.cs

View workflow job for this annotation

GitHub Actions / build

The event 'Tests.DummyViewModel.PropertyChanged' is never used

Check warning on line 13 in test/PropertyValidator.Test/ValidationService.test.cs

View workflow job for this annotation

GitHub Actions / build

The event 'Tests.DummyViewModel.PropertyChanged' is never used
public string? Value { get; set; }
}
Expand Down Expand Up @@ -107,6 +108,56 @@ public void MustValidateRangeLengthRule(DummyViewModel vm, RangeLengthRule rule)
Assert.That(result, Is.EqualTo(true), $"Didn't succeed because vb.Value: '{vm.Value}', length: {vm.Value?.Length}");
}

[Test, Description("ValidationService.PropertyInvalid must be invoked upon violation of property rules.")]
public async Task MustInvokePropertyInvalidEvent()
{
var vm = new DummyViewModel { Value = "something" };

validationService
.For(vm)
.AddRule(e => e.Value, new StringRequiredRule());

var cts = new CancellationTokenSource(TimeSpan.FromSeconds(1));
var tcs = new TaskCompletionSource<bool>();
cts.Token.Register(() => tcs.TrySetCanceled(), useSynchronizationContext: false);

validationService.PropertyInvalid += PropertyInvalid;

vm.Value = null;

var result = await tcs.Task;

void PropertyInvalid(object? sender, ValidationResultArgs e)
{
tcs.SetResult(e.HasError);
}

Assert.That(result, Is.EqualTo(true), $"Didn't succeed because result from PropertyInvalid is not expected.");
}

[Test, Description("ValidationService.EnsurePropertiesAreValid() must throw Exception.")]
[TestCaseSource(nameof(DummyViewModelFixturesXRule))]
public void MustEnsurePropertiesAreInvalid(DummyViewModel vm, IValidationRule rule)
{
validationService
.For(vm)
.AddRule(e => e.Value, rule);

bool result;

try
{
validationService.EnsurePropertiesAreValid();
result = false;
}
catch (Exception e)
{
result = e is PropertyException;
}

Assert.That(result, Is.EqualTo(true), $"Didn't succeed because EnsurePropertiesAreValid() didn't throw.");
}

private static IEnumerable<TestCaseData> DummyViewModelFixturesStringRequiredRule
{
get
Expand All @@ -126,4 +177,15 @@ private static IEnumerable<TestCaseData> DummyViewModelFixturesRangeLengthRule
yield return new TestCaseData(new DummyViewModel { Value = "1234567890+2" }, new RangeLengthRule(10, 20));
}
}

private static IEnumerable<TestCaseData> DummyViewModelFixturesXRule
{
get
{
yield return new TestCaseData(new DummyViewModel { Value = null }, new StringRequiredRule());
yield return new TestCaseData(new DummyViewModel { Value = "1234" }, new RangeLengthRule(5, 10));
yield return new TestCaseData(new DummyViewModel { Value = "12345+1" }, new MaxLengthRule(5));
yield return new TestCaseData(new DummyViewModel { Value = "123" }, new MinLengthRule(5));
}
}
}

0 comments on commit 688040e

Please sign in to comment.