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")); }
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()); } }
/// <summary> /// Adds validatiom rules for any DataAnnotations attributes on the validated type. /// </summary> /// <typeparam name="T"> The type to be validated. </typeparam> /// <param name="plan"> The validation plan to which to add DataAnnotations validation rules. </param> /// <returns> </returns> public static ValidationPlan <T> ConfigureFromAttributes <T>(this ValidationPlan <T> plan) { ValidationRule <T> rule = null; rule = Validate.That <T>(t => { var context = new ValidationContext(t, null, null); var results = new List <ValidationResult>(); var isValid = Validator.TryValidateObject(t, context, results, true); // add results to the validation scope results.ForEach(result => { result .MemberNames .ForEach(member => ValidationScope.Current.AddEvaluation( new FailedEvaluation( target: t, rule: rule) { Message = result.ErrorMessage, MemberPath = member })); }); return(isValid); }); var clone = (ValidationPlan <T>)plan.Clone(); clone.AddRule(rule); return(clone); }
/// <summary> /// Adds a dynamic property to a rule, which will be copied to any <see cref="FailedEvaluation" /> generated by the rule. /// </summary> /// <typeparam name="TTarget"> The <see cref="Type" /> of the target. </typeparam> /// <typeparam name="T"> The <see cref="Type" /> of the dynamic property. </typeparam> /// <param name="plan"> The validation plan. </param> /// <param name="value"> The value. </param> /// <returns> A clone of the source validation rule. </returns> public static ValidationPlan <TTarget> With <TTarget, T>(this ValidationPlan <TTarget> plan, T value) { var clone = (ValidationPlan <TTarget>)plan.Clone(); clone.Set(value); return(clone); }
private static void InitializeTwitterPlan() { isTwitterFreeUrl = new ValidationPlan <string>(); isTwitterFreeUrl.AddRule( s => { var client = new WebClient(); try { var response = client.DownloadString(s.As("url")); return(!response.ToLower().Contains("twitter")); } catch (WebException ex) { ex.Message.As("error"); return(false); } catch (Exception ex) { ex.As("error"); return(false); } }, only => only .When(isValidHttpUrl) .WithErrorMessage("Oh no! The page at {url} contains the word 'twitter'") .WithSuccessMessage("The page at {url} doesn't contain the word 'twitter'") ); }
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 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 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 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")); }
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()); }
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 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 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 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 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 void ConfigureFromAttributes_returns_a_new_instance_of_the_ValidationPlan() { var plan = new ValidationPlan <Account>(); var configuredPlan = plan.ConfigureFromAttributes(); Assert.That(plan != configuredPlan); }
public void SetUp() { thePlan = new ValidationPlan(typeof(string), new ValidationStep[0]); theDescription = Description.For(thePlan); theStepList = theDescription.BulletLists.Single(); }
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 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()); }
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 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 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 Continuation_rules_do_not_start_setup_tasks_when_precondition_fails() { // TODO: (Continuation_rules_do_not_start_setup_tasks_when_precondition_fails) var setupStarted = false; var hasAwesomeTag = Validate.Async <string>( setup: url => { setupStarted = true; return(Task <string> .Factory.StartNew(() => "<div>not awesome</div>")); }, validate: html => html.As("page").Contains("<awesome>")) .WithErrorMessage("{page} is missing the <awesome> tag!"); var plan = new ValidationPlan <string> { isValidHttpUrl, hasAwesomeTag.When(isValidHttpUrl) }; var task = plan.ExecuteAsync("hhttp://bing.com"); task.Wait(); Console.WriteLine(task.Result); Assert.That(setupStarted, Is.False); }
public void ValidationPlans_can_be_combined() { var plan1 = new ValidationPlan <Species>(); plan1.AddRule( Validate.That <Species>( s => s.Individuals.Every( i => Validate.That <Individual>( ind => ind.Species == s) .WithErrorCode("species mismatch") .Check(i)) ) ); var plan2 = new ValidationPlan <Species>(); plan2.AddRule( Validate.That <Species>( s => s.Individuals.Every( Validate.That <Individual>( ind => !string.IsNullOrEmpty(ind.Name)) .WithErrorCode("empty name") .Check) ) ); var species = new Species { Name = "Felis silvestris" }; var nameless = new Individual { Name = "", Species = species }; species.Individuals.Add(nameless); species.Individuals.Add(new Individual { Name = "Garfield", Species = species }); species.Individuals.Add(new Individual { Name = "Morris", Species = species }); var fido = new Individual { Name = "Fido" }; species.Individuals.Add(fido); var report = ValidationPlan <Species> .Merge( new KeyValuePair <string, ValidationPlan <Species> >("one", plan1), new KeyValuePair <string, ValidationPlan <Species> >("two", plan2) ).Execute(species); Assert.That(report.Failures.Count(f => f.ErrorCode == "one"), Is.EqualTo(2)); Assert.That(report.Failures.Count(f => f.ErrorCode == "two"), Is.EqualTo(2)); Assert.That(report.Failures.Count(f => f.Target == fido), Is.EqualTo(1)); Assert.That(report.Failures.Count(f => f.Target == nameless), Is.EqualTo(1)); }
public void Rules_within_ValidationPlan_can_be_iterated() { var plan = new ValidationPlan <string>(); Enumerable.Range(1, 10).ForEach(_AppDomain => plan.AddRule(Validate.That <string>(s => false))); Assert.AreEqual(10, plan.Count()); }
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 Null_rules_cannot_be_added_to_a_ValidationPlans() { var plan = new ValidationPlan <string>(); IValidationRule <string> nullRule = null; Action addNullRule = () => plan.Add(nullRule); addNullRule.ShouldThrow <ArgumentNullException>(); }
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 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); }
public void finds_the_rules_from_all_steps() { var r1 = new StubRule(); var r2 = new StubRule(); var r3 = new ClassFieldValidationRules(); var r4 = new ClassFieldValidationRules(); var src1 = new ConfiguredValidationSource(new IValidationRule[] { r1, r3 }); var src2 = new ConfiguredValidationSource(new IValidationRule[] { r2, r4 }); var step1 = ValidationStep.FromSource(typeof(object), src1); var step2 = ValidationStep.FromSource(typeof(object), src2); var plan = new ValidationPlan(typeof (object), new[] {step1, step2}); plan.FindRules<StubRule>().ShouldHaveTheSameElementsAs(r1, r2); }
public void SetUp() { theModel = new ContactModel(); theType = theModel.GetType(); r1 = MockRepository.GenerateStub<IValidationRule>(); r2 = MockRepository.GenerateStub<IValidationRule>(); r3 = MockRepository.GenerateStub<IValidationRule>(); theMatchingSource = ConfiguredValidationSource.For(type => type == theType, r1, r2); theOtherSource = ConfiguredValidationSource.For(type => type == typeof(int), r3); theGraph = ValidationGraph.BasicGraph(); theGraph.RegisterSource(theMatchingSource); theGraph.RegisterSource(theOtherSource); theContext = ValidationContext.For(theModel); thePlan = ValidationPlan.For(theType, theGraph); }