public void Rules_can_be_aggregated_from_function_calls() { var plan = new ValidationPlan <Species>(); plan.AddRule(Validate.That <Species>(IndividualsAreAllOfSpecies().Check)); var cat = new Species("Felis silvestris"); var fluffy = new Individual { Name = "Fluffy", Species = cat }; var boots = new Individual { Name = "Boots", Species = cat }; cat.Individuals.AddRange(new[] { fluffy, boots }); Assert.IsFalse(plan.Execute(cat).HasFailures); // adding an individual without a name causes the plan to evaluate to false var fido = new Individual { Name = "Fido", Species = new Species("Canis familiaris") }; cat.Individuals.Add(fido); var report = plan.Execute(cat); Assert.IsTrue(report.HasFailures); Console.WriteLine(report); Assert.AreEqual(3, report.Failures.Count()); Assert.That(report.Failures.Any(failure => failure.Target == fido)); Assert.That(report.Failures.Any(failure => failure.Target == cat)); }
public void One_rule_can_be_evaluated_inside_another_without_framework_being_aware_of_it() { var individualNameRule = Validate.That <Individual>(i => !string.IsNullOrEmpty(i.Name)) .WithErrorCode("Name"); var speciesNameRule = Validate .That <Species>(s => !string.IsNullOrEmpty(s.Name)) .WithErrorCode("Name"); var speciesIndividualsRule = Validate.That <Species>(s => s.Individuals.All(individualNameRule.Check)); var plan = new ValidationPlan <Species>(); plan.AddRule(speciesNameRule); plan.AddRule(speciesIndividualsRule); var cat = new Species("Felis silvestris"); var fluffy = new Individual { Name = "Fluffy", Species = cat }; var boots = new Individual { Name = "Boots", Species = cat }; cat.Individuals.AddRange(new[] { fluffy, boots }); Assert.IsFalse(plan.Execute(cat).HasFailures); // adding an individual without a name causes the plan to evaluate to false cat.Individuals.Add(new Individual { Species = cat }); var report = plan.Execute(cat); Console.WriteLine(report); Assert.IsTrue(report.HasFailures); }
public virtual void Outer_validation_scope_aggregates_rules_from_inner_scopes() { var plan = new ValidationPlan <string> { Validate.That <string>(s => true) }; using (var scope = new ValidationScope()) { using (new ValidationScope()) { plan.Execute(""); } using (new ValidationScope()) { plan.Execute(""); } using (new ValidationScope()) { plan.Execute(""); } Assert.AreEqual(3, scope.Evaluations.Count()); } }
public void Success_and_failure_messages_can_be_configured_separately() { var plan = new ValidationPlan <string> { Validate.That <string>(s => s.As("value").Length.As("length") > 3.As("min")) .WithErrorMessage("Fail! Your string {value} is only {length} characters.") .WithSuccessMessage("Win! '{value}' is more than {min} characters.") }; var failure = plan.Execute("hi").Evaluations.Single(); var success = plan.Execute("hello").Evaluations.Single(); StringAssert.Contains("Fail!", failure.Message); StringAssert.Contains("Win!", success.Message); }
public void When_the_same_plan_is_run_on_multiple_threads_simultaneously_they_each_report_parameters_correctly() { var barrier = new Barrier(20); var plan = new ValidationPlan <string>(new DebugMessageGenerator()) { Validate.That <string>(s => { DescribeThread(); // report input parameter s.As("s"); barrier.SignalAndWait(); return(false); }).WithErrorMessage("the parameter was {s}") }; var tasks = new ConcurrentBag <Task <ValidationReport> >( Enumerable.Range(1, 20).Select( i => Task <ValidationReport> .Factory.StartNew(() => { var report = plan.Execute(i.ToString()); Console.WriteLine(report); return(report); }))); Task.WaitAll(tasks.ToArray()); Enumerable.Range(1, 20).ForEach(i => tasks.Any( t => t.Result.Failures.Any(f => f.Parameters["s"].Equals(i.ToString())))); }
public void Nested_plan_evaluates_all_rules() { var rule1Evaluated = false; var rule2Evaluated = false; var rule3Evaluated = false; var plan = new ValidationPlan <string>() .AddRule(s => true) .AddRule(new ValidationPlan <string>() .AddRule(_ => { rule1Evaluated = true; return(false); }, fail => fail.WithErrorMessage("1")) .AddRule(_ => { rule2Evaluated = true; return(false); }, fail => fail.WithErrorMessage("2")) .AddRule(_ => { rule3Evaluated = true; return(false); }, fail => fail.WithErrorMessage("3"))); var report = plan.Execute(null); Assert.That(rule1Evaluated); Assert.That(rule2Evaluated); Assert.That(rule3Evaluated); Assert.That(report.Evaluations.Count(), Is.EqualTo(5)); }
public void MemberPath_can_be_set_differently_for_the_same_rule_in_different_contexts() { var nameNotEmpty = Validate.That <Species>(s => !string.IsNullOrEmpty(s.Name)); var plan = new ValidationPlan <Species>(); plan.AddRule(nameNotEmpty.ForMember("species")); plan.AddRule( s => s.Individuals.Every( i => nameNotEmpty.ForMember("subspecies").Check(i.Species))); var cat = new Species(); var fluffy = new Individual { Species = cat }; cat.Individuals.Add(fluffy); var report = plan.Execute(cat); Console.WriteLine(report); Assert.AreEqual(3, report.Failures.Count()); Assert.AreEqual(1, report.Failures.Where(f => f.MemberPath == "species").Count()); Assert.AreEqual(1, report.Failures.Where(f => f.MemberPath == "subspecies").Count()); }
public void ValidationPlan_collection_initializer_can_be_used_to_combine_plans() { var plan1 = new ValidationPlan <string> { Validate.That <string>(s => s != "a").WithErrorCode("RULE 1") }; var plan2 = new ValidationPlan <string> { Validate.That <string>(s => s.Length > 1).WithErrorCode("RULE 2") }; plan1.WithErrorCode("PLAN 1"); plan2.WithErrorCode("PLAN 2"); var combinedPlan = new ValidationPlan <string> { plan1, plan2 }; var report = combinedPlan.Execute("a"); Console.WriteLine(report); Assert.AreEqual(4, report.Failures.Count()); }
Intermediate_preconditions_that_return_true_prevent_later_rules_from_being_evaluated_using_actual_validation_rule () { var speciesNotNull = Validate.That <Species>(t => t != null); var validSpeciesName = Validate.That <Species>(t => !string.IsNullOrEmpty(t.Name)); var notTooManyIndividuals = Validate .That <Species>(t => t.Individuals.Count() <= 45) .When(s => s.Individuals != null); var noDuplicates = Validate.That <Species>(t => t.Individuals.Distinct().Count() == t.Individuals.Count()); var plan = new ValidationPlan <Species> { speciesNotNull, new ValidationPlan <Species> { validSpeciesName, notTooManyIndividuals, noDuplicates.When(notTooManyIndividuals), }.When(speciesNotNull) }; var report = plan.Execute(new Species { Name = "cat", Individuals = null }); Assert.AreEqual(0, report.Failures.Count()); }
public void When_precondition_is_first_class_rule_in_plan_precondition_is_only_evaluated_once() { var callCount = 0; var precondition = Validate.That <Species>(_ => { callCount++; return(false); }); var plan = new ValidationPlan <Species> { precondition, // these rules will throw if the precondition does not short circuit them Validate.That <Species>(species => species.Name.Length > 0) .When(precondition), Validate.That <Species>(species => !species.Name.Contains("!")) .When(precondition) }; var nameless = new Species { Name = null }; plan.Execute(nameless); callCount.Should().Be(1); }
public void executes_each_step() { thePlan.Execute(theContext); r1.AssertWasCalled(x => x.Validate(theContext)); r2.AssertWasCalled(x => x.Validate(theContext)); }
public void Same_rule_in_different_plans_can_have_different_error_codes() { var rule = Validate.That <string>( s => !s.Contains("A") & !s.Contains("B")); var planA = new ValidationPlan <string> { rule.WithErrorCode("string contains A") }; var planB = new ValidationPlan <string> { rule.WithErrorCode("string contains B") }; var report = planA.Execute("A"); Console.WriteLine(report); Assert.IsTrue(report.Failures.Any(f => f.ErrorCode == "string contains A"), "The error code for the rule changed"); report = planB.Execute("B"); Console.WriteLine(report); Assert.IsTrue(report.Failures.Any(f => f.ErrorCode == "string contains B")); }
public virtual void When_precondition_is_not_in_plan_and_precondition_fails_precondition_is_only_evaluated_once () { var count = 0; Func <Species, bool> counter = s => { count++; return(false); }; var precondition = Validate.That <Species>(s => counter(s)); var plan = new ValidationPlan <Species> { // these rules will throw if the precondition does not short circuit them Validate.That <Species>(species => true) .When(precondition), Validate.That <Species>(species => true) .When(precondition) }; plan.Execute(null); // we only want the precondition called once. the value should be stored. Assert.AreEqual(1, count); }
When_specifying_multiple_preconditions_and_one_precondition_fails_subsequent_preconditions_are_not_evaluated () { var falsePreconditionCallCount = 0; var truePreconditionCallCount = 0; var falsePrecondition = Validate.That <string>(_ => { falsePreconditionCallCount++; return(false); }); var truePrecondition = Validate.That <string>(_ => { truePreconditionCallCount++; return(true); }); // this rule will fail but should be short circuited var rule = Validate.That <string>(s => false) .When(falsePrecondition) .When(truePrecondition); var plan = new ValidationPlan <string> { rule }; var report = plan.Execute(""); falsePreconditionCallCount.Should().Be(1); truePreconditionCallCount.Should().Be(0); Assert.True(!report.Failures.Any(f => f.Rule == rule)); }
public virtual void When_precondition_is_used_in_nested_plans_it_is_not_reevaluated() { var count = 0; Func <string, bool> counter = s => { count++; return(true); }; var precondition = Validate.That(counter).WithMessage("precondition"); var plan = new ValidationPlan <string> { Validate.That <string>(s => s.Length > 0).When(precondition), new ValidationPlan <string> { Validate.That <string>(s => s.Contains("a")).When(precondition), Validate.That <string>(s => s.Contains("b")).When(precondition), } }; plan.Execute("ab"); Assert.AreEqual(1, count); }
public void ErrorCode_can_be_set_differently_for_the_same_rule_in_different_contexts() { var nameNotEmpty = Validate .That <Species>(s => !string.IsNullOrEmpty(s.Name)) .WithErrorCode("NameCannotBeEmpty"); var plan = new ValidationPlan <Species>(); plan.AddRule( s => s.Individuals.Every( i => nameNotEmpty .WithErrorCode("IndividualsSpeciesNameCannotBeEmpty") .Check(i.Species))); plan.AddRule(nameNotEmpty.WithErrorCode("SpeciesNameCannotBeEmpty")); var cat = new Species(); var fluffy = new Individual { Species = cat }; cat.Individuals.Add(fluffy); var report = plan.Execute(cat); Console.WriteLine(report); Assert.AreEqual(3, report.Failures.Count()); Assert.AreEqual(1, report.Failures.Count(f => f.ErrorCode == "SpeciesNameCannotBeEmpty")); Assert.AreEqual(1, report.Failures.Count(f => f.ErrorCode == "IndividualsSpeciesNameCannotBeEmpty")); }
When_precondition_is_first_class_rule_in_plan_and_has_different_error_code_assigned_precondition_is_only_evaluated_once () { var count = 0; Func <Species, bool> counter = s => { count++; return(false); }; var precondition = Validate.That <Species>(s => counter(s)); var plan = new ValidationPlan <Species> { precondition.WithErrorCode("some code"), // these rules will throw if the precondition does not short circuit them Validate.That <Species>(species => species.Name.Length > 0) .When(precondition), Validate.That <Species>(species => !species.Name.Contains("!")) .When(precondition) }; var nameless = new Species { Name = null }; Assert.DoesNotThrow(() => plan.Execute(nameless)); Assert.AreEqual(1, count); }
public void When_items_are_validated_in_parallel_the_rule_evaluations_are_reported_correctly() { DescribeThread(); var plan = new ValidationPlan <IEnumerable <string> >(); plan.AddRule(urls => urls.Parallel(url => { if (string.IsNullOrWhiteSpace(Thread.CurrentThread.Name)) { Thread.CurrentThread.Name = url; } Console.WriteLine( "checking {0} in scope {2} on thread {1} ", url, Thread.CurrentThread.ManagedThreadId, ValidationScope.Current); return(isReachableUrl.Check(url)); })); var report = plan.Execute(Urls()); Console.WriteLine(report); Assert.That(report.Evaluations.Count(), Is.GreaterThan(Urls().Count())); }
public void Rules_within_a_ValidationPlan_can_use_APM_signatures_and_run_synchronously() { var hasAwesomeTag = Validate.Async <string>( setup: url => { var request = new ApmOperation <string, string>(s => Task <string> .Factory.StartNew(() => "<div>" + s + "</div>")); var tcs = new TaskCompletionSource <string>(); Task <string> .Factory .FromAsync(request.BeginInvoke, request.EndInvoke, url, state: null) .ContinueWith( t => tcs.Complete(t, () => t.Result)); return(tcs.Task); }, validate: html => html.As("page").Contains("<awesome>")) .WithErrorMessage("{page} is missing the <awesome> tag!"); var plan = new ValidationPlan <string> { isValidHttpUrl, hasAwesomeTag.When(isValidHttpUrl) }; var result = plan.Execute("http://microsoft.com"); Console.WriteLine(result); // TODO: (Rules_within_a_ValidationPlan_can_use_APM_signatures_and_run_synchronously) Assert.Fail("Test not written"); }
public void Dependencies_can_be_declared_within_expression_using_Validate_That() { var plan = new ValidationPlan <IEnumerable <Species> >(); plan .AddRule(list => list.Every(species => Validate .That <Species>(s => s.Name.Length < 20) .WithErrorCode("name too long") .When( Validate .That <Species>(s => s.Name != null) .WithErrorCode("name null")) .Check(species))); var listToValidate = new[] { new Species { Name = null }, new Species { Name = "this name is way too " } }; var report = plan.Execute(listToValidate); Console.WriteLine(report); Assert.AreEqual(2, report.Failures.Count()); Assert.AreEqual(1, report.Failures.Count(f => f.ErrorCode == "name too long")); }
public virtual void When_precondition_and_cloned_precondition_are_both_used_they_are_evaluated_as_equivalent() { var notEmptyRule = Validate.That <string>(s => !string.IsNullOrEmpty(s)); var tooLongRule = Validate.That <string>(s => s.Length < 10); var plan = new ValidationPlan <string> { notEmptyRule.WithErrorCode("empty!"), tooLongRule.When(notEmptyRule).WithErrorCode("too long!"), }; var report = plan.Execute(""); Assert.AreEqual(1, report.Failures.Count(f => f.ErrorCode == "empty!")); report = plan.Execute("sdff3'4otj;4kth;kdfjsekfjpf4"); Assert.AreEqual(1, report.Failures.Count(f => f.ErrorCode == "too long!")); }
public void FailedEvaluation_Message_is_set_from_data_annotation_ErrorMessage() { ValidationPlan <Account> plan = new ValidationPlan <Account>() .ConfigureFromAttributes(); ValidationReport report = plan.Execute(new Account()); Assert.That(report.Failures.Any(f => f.Message == "What's your name?")); }
public void FailedEvaluation_target_is_set_to_the_instance_that_was_evaluated() { ValidationPlan <Account> plan = new ValidationPlan <Account>() .ConfigureFromAttributes(); var account = new Account(); ValidationReport report = plan.Execute(account); Assert.That(report.Failures.Any(f => f.Target == account)); }
public void Dependencies_can_be_declared_using_optional_parameter_on_AddRule() { var plan = new ValidationPlan <Species>(); plan.AddRule(s => s.Name.Length < 20, only => only.When(s => s.Name != null)); var speciesWithNullName = new Species { Name = null }; var speciesWithLongName = new Species { Name = "this name is way too long" }; var reportOnSpeciesWithNullName = plan.Execute(speciesWithNullName); var reportOnSpeciesWithLongName = plan.Execute(speciesWithLongName); Assert.AreEqual(0, reportOnSpeciesWithNullName.Failures.Count()); Assert.AreEqual(1, reportOnSpeciesWithLongName.Failures.Count()); }
public void ForMember_using_func_returns_expected_member_name_for_chained_property() { var rule = new ValidationPlan <Phylum> { Validate.That <Phylum>(s => false).ForMember(p => p.Kingdom.Name) }; var report = rule.Execute(new Phylum()); Assert.AreEqual("Kingdom.Name", report.Failures.Single().MemberPath); }
ValidationPlan_collection_initializer_can_be_used_to_combine_rules_with_error_code_assignments() { var rule1 = Validate.That <string>(s => s != null); var rule2 = Validate.That <string>(s => s.Length > 0); var plan = new ValidationPlan <string> { rule1.WithErrorCode("null check"), rule2.When(rule1).WithErrorCode("length check") }; var report = plan.Execute(null); Assert.AreEqual(1, report.Failures.Count(), report.ToString()); Assert.AreEqual("null check", report.Failures.First().ErrorCode); report = plan.Execute(string.Empty); Assert.AreEqual(1, report.Failures.Count()); Assert.AreEqual("length check", report.Failures.First().ErrorCode); }
public void ForMember_using_func_returns_expected_member_name_for_immediate_property() { var rule = new ValidationPlan <Species> { Validate.That <Species>(s => false).ForMember(s => s.Individuals) }; var report = rule.Execute(new Species()); Assert.AreEqual("Individuals", report.Failures.Single().MemberPath); }
public void Parameters_are_flushed_after_rule_evaluation_when_rule_passes() { var plan = new ValidationPlan <string> { Validate.That <string>(s => true.As("pass")), Validate.That <string>(s => false.As("fail")) }; var report = plan.Execute(""); Assert.IsFalse(report.Failures.First().Parameters.ContainsKey("pass")); }
public void IValidationRule_when_check_passes_no_failures_are_added_to_report() { var rule = Validate.That <string>(_ => true); var plan = new ValidationPlan <string> { rule }; var report = plan.Execute(""); Assert.AreEqual(0, report.Failures.Count()); }
public void Multiple_validation_parameters_can_be_written_to_error_message_with_params_in_order() { var rule = Validate .That <int>(i => i > 0.As("start") & i < 365.As("end")) .WithMessage("must be between {start} and {end}"); var plan = new ValidationPlan <int> { rule }; var report = plan.Execute(9785); Assert.AreEqual("must be between 0 and 365", report.Failures.First().Message); }