public async Task ValidateAsyncShouldReturnFailureResultForSingleFailedRule([IntegrationTesting] IGetsValidator validatorFactory) { var validator = validatorFactory.GetValidator <Person>(typeof(PersonValidatorBuilder)); var person = new Person { Name = null, Birthday = new DateTime(2000, 1, 1), Pets = new[] { new Pet { Name = "Miffles", NumberOfLegs = 4, Type = "Cat" }, }, }; var result = await validator.ValidateAsync(person).ConfigureAwait(false); Assert.Multiple(() => { Assert.That(result.Passed, Is.False, "Overall result"); Assert.That(result.RuleResults, Has.One.Matches <ValidationRuleResult>(r => r.Identifier.MemberName == "Name" && r.Outcome == RuleOutcome.Failed), "Correct failing rule"); }); }
public void ValidatingACircularReferenceShouldNotThrowOrTimeOut([IntegrationTesting] IGetsValidator validatorFactory) { var manifest = new ValidationManifest { ValidatedType = typeof(Node), RootValue = new ManifestValue { ValidatedType = typeof(Node), IdentityAccessor = obj => ((Node)obj).Identity, Children = new[] { new ManifestValue { ValidatedType = typeof(NodeChild), IdentityAccessor = obj => ((NodeChild)obj).Identity, AccessorFromParent = obj => ((Node)obj).Child, }, new ManifestValue { ValidatedType = typeof(string), AccessorFromParent = obj => ((Node)obj).Name, } } } }; var nameValue = manifest.RootValue.Children.Single(x => x.ValidatedType == typeof(string)); var nameRule = new ManifestRule(nameValue, new ManifestRuleIdentifier(nameValue, typeof(MatchesRegex))) { RuleConfiguration = obj => ((MatchesRegex)obj).Pattern = "^Foo", }; nameValue.Rules.Add(nameRule); var childValue = manifest.RootValue.Children.Single(x => x.ValidatedType == typeof(NodeChild)); var recursiveValue = new RecursiveManifestValue(manifest.RootValue) { AccessorFromParent = obj => ((NodeChild)obj).Node, }; childValue.Children.Add(recursiveValue); var validatedObject = new Node { Child = new NodeChild { Node = new Node { Child = new NodeChild { Node = new Node { Name = "Invalid" } } } } }; validatedObject.Child.Node.Child.Node.Child = validatedObject.Child; var sut = validatorFactory.GetValidator <Node>(manifest); Assert.That(() => sut.ValidateAsync(validatedObject).Wait(300), Is.True, "Validation completes within 300ms"); }
/// <summary> /// Gets a validator instance for a specified generic type, using a specified manifest model. /// The model must describe a validator which is able to validate the object type <typeparamref name="TValidated"/>. /// </summary> /// <typeparam name="TValidated">The type of object to validate.</typeparam> /// <param name="factory">The validator factory.</param> /// <param name="manifestModel">The validation manifest model.</param> /// <returns>A strongly-typed validator implementation.</returns> /// <exception cref="ArgumentNullException">If either <paramref name="factory"/> or <paramref name="manifestModel"/> are <see langword="null"/>.</exception> public static IValidator <TValidated> GetValidator <TValidated>(this IGetsValidator factory, ManifestModel.Value manifestModel) { if (factory is null) { throw new ArgumentNullException(nameof(factory)); } return((IValidator <TValidated>)factory.GetValidator(manifestModel, typeof(TValidated))); }
public void GetValidatorShouldReturnCorrectGenericValidatorForBuilder(IGetsValidator factory, StubValidator validator) { Mock.Get(factory) .Setup(x => x.GetValidator(typeof(ValidatedObjectBuilder))) .Returns(validator); Assert.That(() => factory.GetValidator <ValidatedObject>(typeof(ValidatedObjectBuilder)), Is.SameAs(validator)); }
public void GetValidatorShouldReturnCorrectGenericValidatorForModel(IGetsValidator factory, StubValidator validator, [ManifestModel] Value model) { Mock.Get(factory) .Setup(x => x.GetValidator(model, typeof(ValidatedObject))) .Returns(validator); Assert.That(() => factory.GetValidator <ValidatedObject>(model), Is.SameAs(validator)); }
/// <summary> /// Gets a validator instance for a specified generic type, using a specified validation manifest. /// The manifest must describe a validator which is able to validate the object type <typeparamref name="TValidated"/>. /// </summary> /// <typeparam name="TValidated">The type of object to validate.</typeparam> /// <param name="factory">The validator factory.</param> /// <param name="manifest">The validation manifest.</param> /// <returns>A strongly-typed validator implementation.</returns> /// <exception cref="ArgumentNullException">If either <paramref name="factory"/> or <paramref name="manifest"/> are <see langword="null"/>.</exception> /// <exception cref="ArgumentException">If <paramref name="manifest"/> does not describe a validator for <typeparamref name="TValidated"/>.</exception> public static IValidator <TValidated> GetValidator <TValidated>(this IGetsValidator factory, Manifest.ValidationManifest manifest) { if (factory is null) { throw new ArgumentNullException(nameof(factory)); } if (!IsCorrectValidatedType <TValidated>(manifest.ValidatedType)) { throw new ArgumentException(String.Format(GetExceptionMessage("ValidatedTypeMustBeSelectedValidatedType"), typeof(TValidated).Name), nameof(manifest)); } return((IValidator <TValidated>)factory.GetValidator(manifest)); }
/// <summary> /// Gets a validator instance for a specified generic type, using a specified builder type. /// The builder type must implement <see cref="IBuildsValidator{TValidated}"/> for the generic /// type <typeparamref name="TValidated"/>. /// </summary> /// <typeparam name="TValidated">The type of object to validate.</typeparam> /// <param name="factory">The validator factory.</param> /// <param name="builderType">A type indicating the type of validator-builder service to use.</param> /// <returns>A strongly-typed validator implementation.</returns> /// <exception cref="ArgumentNullException">If either <paramref name="factory"/> or <paramref name="builderType"/> are <see langword="null"/>.</exception> /// <exception cref="ArgumentException">If <paramref name="builderType"/> is not of a type appropriate to validate <typeparamref name="TValidated"/>.</exception> public static IValidator <TValidated> GetValidator <TValidated>(this IGetsValidator factory, Type builderType) { if (factory is null) { throw new ArgumentNullException(nameof(factory)); } if (!IsCorrectBuilderType <TValidated>(builderType)) { throw new ArgumentException(String.Format(GetExceptionMessage("BuilderTypeMustBeForSelectedValidatedType"), GetBuilderType <TValidated>()), nameof(builderType)); } return((IValidator <TValidated>)factory.GetValidator(builderType)); }
public async Task ValidateAsyncShouldReturnPassResultForValidObject([IntegrationTesting] IGetsValidator validatorFactory) { var validator = validatorFactory.GetValidator <Person>(typeof(PersonValidatorBuilder)); var person = new Person { Name = "Bobby", Birthday = new DateTime(2000, 1, 1), Pets = new[] { new Pet { Name = "Miffles", NumberOfLegs = 4, Type = "Cat" }, }, }; var result = await validator.ValidateAsync(person).ConfigureAwait(false); Assert.That(result.Passed, Is.True); }
public async Task ForMatchingMemberItemCanFindRulesForTheCorrectItem([IntegrationTesting] IGetsValidator validatorFactory) { var validator = validatorFactory.GetValidator <Customer>(typeof(CustomerValidatorBuilder)); var customer = new Customer { Person = new Person { Name = "John Smith", Birthday = new DateTime(2000, 1, 1), Pets = new[] { new Pet { Name = "Pet1" }, new Pet { Name = "Pet2" }, new Pet { Name = "Pet3" }, new Pet { Name = "Pet4" }, new Pet { Name = "Pet5" }, new Pet { Name = "Pet6" }, } } }; var result = await validator.ValidateAsync(customer, new ValidationOptions { EnableMessageGeneration = true }).ConfigureAwait(false); var expectedPet = customer.Person.Pets.Skip(1).First(); Assert.That(result.ForMember(x => x.Person).ForMatchingMemberItem(x => x.Pets, expectedPet).ForOnlyThisValue().First().ValidatedValue, Is.SameAs(expectedPet)); }
public async Task PolymorphicAsShouldThrowIfUsedTwiceInSuccessionFromAResult([IntegrationTesting] IGetsValidator validatorFactory) { var validator = validatorFactory.GetValidator <Customer>(typeof(CustomerValidatorBuilder)); var customer = new FrequentShopper { Person = new Employee { Name = "John Smith", Birthday = new DateTime(2000, 1, 1), Pets = new[] { new Pet { Name = "Pet1" }, new Pet { Name = "Pet2" }, new Pet { Name = "Pet3" }, new Pet { Name = "Pet4" }, new Pet { Name = "Pet5" }, new Pet { Name = "Pet6" }, }, PayrollNumber = -5, }, LoyaltyPoints = -100, }; var result = await validator.ValidateAsync(customer).ConfigureAwait(false); Assert.That(() => result.ForMember(x => x.Person).PolymorphicAs <Employee>().PolymorphicAs <Employee>(), Throws.ArgumentException.And.Message.StartWith("The validation manifest value for the current context must implement IHasPolymorphicTypes")); }
public async Task ValidateAsyncShouldReturnPassResultForARulewithADependency([IntegrationTesting] IGetsValidator validatorFactory) { var validator = validatorFactory.GetValidator <Customer>(typeof(CustomerValidatorBuilder)); var customer = new Customer { Person = new Person { Name = "John Smith", Birthday = new DateTime(2000, 1, 1), Pets = new[] { new Pet { Name = "Miffles", NumberOfLegs = 4, Type = "Cat" }, }, } }; var result = await validator.ValidateAsync(customer).ConfigureAwait(false); Assert.That(result.Passed, Is.True); }
public async Task ValidateAsyncShouldTakeApproximatelyTheCorrectTimeToRunAParallelRuleset([IntegrationTesting] IGetsValidator validatorFactory, [NoAutoProperties] Person person) { var validator = validatorFactory.GetValidator <Person>(typeof(ParallelValidatorBuilder)); stopwatch.Start(); await validator.ValidateAsync(person, new ValidationOptions { EnableRuleParallelization = true }).ConfigureAwait(false); stopwatch.Stop(); // Best case time : [largest of (300, 300, 200, 200)] + 200 + 150 = 650 (represents perfect parallelisation with no overhead) // Worst case time: 300 + 300 + 200 + 200 + 200 + 150 = 1350 (represents serial execution, although still no overhead) // // The total time for validation should be a little over "the best case time". // We allow a short grace period because that best case is totally hypothetical and impossible to actually achieve. // Even with the grace period, the target time is well below the worst case (representing totally non-parallel execution). var bestCaseMilliseconds = 650; Assert.That(stopwatch.ElapsedMilliseconds, Is.GreaterThan(bestCaseMilliseconds).And.LessThan(bestCaseMilliseconds + millisecondsGrace), "The validator is expected to take between 650 and 800 milliseconds to complete validation."); }
public async Task ValidateAsyncShouldReturnFailureResultForARulewithAFailedDependency([IntegrationTesting] IGetsValidator validatorFactory) { var validator = validatorFactory.GetValidator <Customer>(typeof(CustomerValidatorBuilder)); var customer = new Customer { Person = new Person { Name = "John Smith", Birthday = new DateTime(2000, 1, 1), Pets = null, } }; var result = await validator.ValidateAsync(customer).ConfigureAwait(false); Assert.Multiple(() => { Assert.That(result.Passed, Is.False, "Result is false"); var dependencyFailures = result.RuleResults .Where(x => !x.IsPass && x.Outcome == RuleOutcome.DependencyFailed) .Select(x => x.Identifier.RuleType) .ToList(); var failures = result.RuleResults .Where(x => !x.IsPass && x.Outcome == RuleOutcome.Failed) .Select(x => x.Identifier.RuleType) .ToList(); Assert.That(failures, Is.EqualTo(new[] { typeof(NotNull) }), "One normal failure and it's the right type"); }); }
public async Task ValidateAsyncWithMessageSupportShouldReturnMessagesForAFailingRule([IntegrationTesting] IGetsValidator validatorFactory) { var validator = validatorFactory.GetValidator <Person>(typeof(PersonValidatorBuilder)); var person = new Person { Name = "John Smith", Birthday = new DateTime(1750, 1, 1), Pets = Array.Empty <Pet>(), }; var result = await validator.ValidateAsync(person, new ValidationOptions { EnableMessageGeneration = true }).ConfigureAwait(false); Assert.That(result.RuleResults.Single(x => !x.IsPass).Message, Is.EqualTo("The date 1750-01-01 is invalid. It must equal-to or later than 1900-01-01.")); }
public async Task RecursiveValidationShouldReturnaResultFromADescendentObjectValidatedUsingTheSameManifestAsAnAncestor([IntegrationTesting] IGetsValidator validatorFactory) { var manifest = new ValidationManifest { ValidatedType = typeof(Node), RootValue = new ManifestValue { ValidatedType = typeof(Node), IdentityAccessor = obj => ((Node)obj).Identity, Children = new[] { new ManifestValue { ValidatedType = typeof(NodeChild), IdentityAccessor = obj => ((NodeChild)obj).Identity, AccessorFromParent = obj => ((Node)obj).Child, }, new ManifestValue { ValidatedType = typeof(string), AccessorFromParent = obj => ((Node)obj).Name, } } } }; var nameValue = manifest.RootValue.Children.Single(x => x.ValidatedType == typeof(string)); var nameRule = new ManifestRule(nameValue, new ManifestRuleIdentifier(nameValue, typeof(MatchesRegex))) { RuleConfiguration = obj => ((MatchesRegex)obj).Pattern = "^Foo", }; nameValue.Rules.Add(nameRule); var childValue = manifest.RootValue.Children.Single(x => x.ValidatedType == typeof(NodeChild)); var recursiveValue = new RecursiveManifestValue(manifest.RootValue) { AccessorFromParent = obj => ((NodeChild)obj).Node, }; childValue.Children.Add(recursiveValue); var validatedObject = new Node { Child = new NodeChild { Node = new Node { Child = new NodeChild { Node = new Node { Name = "Invalid" } } } } }; var sut = validatorFactory.GetValidator <Node>(manifest); var result = await sut.ValidateAsync(validatedObject); Assert.That(result, Has.One.Matches <ValidationRuleResult>(r => r.Outcome == RuleOutcome.Failed && Equals(r.ValidatedValue, "Invalid"))); }
public async Task ValidateAsyncWithMessageSupportShouldReturnAMessageFromARuleThatHasAMessage([IntegrationTesting] IGetsValidator validatorFactory) { var validator = validatorFactory.GetValidator <Customer>(typeof(CustomerValidatorBuilder)); var customer = new Customer { Person = new Person { Name = "John Smith", Birthday = new DateTime(2000, 1, 1), Pets = new[] { new Pet { Name = "Pet1" }, new Pet { Name = "Pet2" }, new Pet { Name = "Pet3" }, new Pet { Name = "Pet4" }, new Pet { Name = "Pet5" }, new Pet { Name = "Pet6" }, } } }; var result = await validator.ValidateAsync(customer, new ValidationOptions { EnableMessageGeneration = true }).ConfigureAwait(false); Assert.That(result.RuleResults.Single(x => !x.IsPass).Message, Is.EqualTo("Nobody may have more than 5 pets.")); }
public async Task ForMemberAndWithoutSuccessesShouldBeUsableToTraverseToASingleResult([IntegrationTesting] IGetsValidator validatorFactory) { var validator = validatorFactory.GetValidator <Customer>(typeof(CustomerValidatorBuilder)); var customer = new Customer { Person = new Person { Name = "John Smith", Birthday = new DateTime(2000, 1, 1), Pets = new[] { new Pet { Name = "Pet1" }, new Pet { Name = "Pet2" }, new Pet { Name = "Pet3" }, new Pet { Name = "Pet4" }, new Pet { Name = "Pet5" }, new Pet { Name = "Pet6" }, } } }; var result = await validator.ValidateAsync(customer, new ValidationOptions { EnableMessageGeneration = true }).ConfigureAwait(false); Assert.That(result.ForMember(x => x.Person).WithoutSuccesses().Single().Message, Is.EqualTo("Nobody may have more than 5 pets.")); }
public void GetValidatorShouldThrowIfBuilderTypeIsNotCorrectForValidatedType(IGetsValidator factory) { Assert.That(() => factory.GetValidator <ValidatedObject>(typeof(DifferentObjectBuilder)), Throws.ArgumentException); }
public async Task ToSerializableResultShouldReturnSameNumberOfRuleResultsAsOriginalResult([IntegrationTesting] IGetsValidator validatorFactory) { var validator = validatorFactory.GetValidator <Person>(typeof(PersonValidatorBuilder)); var person = new Person { Name = "Bobby", Birthday = new DateTime(2000, 1, 1), Pets = new[] { new Pet { Name = "Miffles", NumberOfLegs = 4, Type = "Cat" }, }, }; var result = await validator.ValidateAsync(person).ConfigureAwait(false); Assert.That(result.ToSerializableResult().RuleResults.Length, Is.EqualTo(result.RuleResults.Count)); }
public void GetValidatorShouldThrowIfManifestTypeIsNotCorrectForValidatedType(IGetsValidator factory, [ManifestModel] ValidationManifest manifest) { manifest.ValidatedType = typeof(string); Assert.That(() => factory.GetValidator <ValidatedObject>(manifest), Throws.ArgumentException); }
public async Task PolymorphicValidationShouldBeAbleToCreateAnErrorResultForADerivedClass([IntegrationTesting] IGetsValidator validatorFactory) { var validator = validatorFactory.GetValidator <Customer>(typeof(CustomerValidatorBuilder)); var customer = new FrequentShopper { Person = new Employee { Name = "John Smith", Birthday = new DateTime(2000, 1, 1), Pets = new[] { new Pet { Name = "Pet1" }, new Pet { Name = "Pet2" }, new Pet { Name = "Pet3" }, new Pet { Name = "Pet4" }, new Pet { Name = "Pet5" }, new Pet { Name = "Pet6" }, }, PayrollNumber = -5, }, LoyaltyPoints = -100, }; var result = await validator.ValidateAsync(customer).ConfigureAwait(false); Assert.That(result.ForMember(x => x.Person).PolymorphicAs <Employee>().ForMember(x => x.PayrollNumber), Has.One.Matches <ValidationRuleResult>(r => r.Identifier.RuleType == typeof(IntegerInRange) && r.IsPass == false && Equals(r.ValidatedValue, -5))); }