
BoundaryTest.pudu
Pudu71 lines8.2 KB
1/** @Test.Validation.Boundary.Suite — pins inclusive bounds and boundary verdicts */2module PuduLangValidator.BoundaryTest34import Std.Test as Test5import PuduLangValidator.Result as Validation6import PuduLangValidator.Rule as Rule7import PuduLangValidator.Rules.Child as ChildRule8import PuduLangValidator.Rules.Collection as CollectionRule9import PuduLangValidator.Rules.Comparison as ComparisonRule10import PuduLangValidator.Rules.Decimal as DecimalRule11import PuduLangValidator.Rules.Number as NumberRule12import PuduLangValidator.Rules.Ordering as OrderingRule13import PuduLangValidator.Rules.Presence as PresenceRule14import PuduLangValidator.Validator as Validator1516type Child = { code: Str }1718type Sample = {19 score: Int, nickname: Option[Str], tags: Array[Str], amount: Decimal,20 level: Int, other: Int, child: Child, items: Array[Child]21}2223fn numberRule(check: fn(Rule.RuleBuilder[Sample, Int]) -> Rule.RuleBuilder[Sample, Int]) -> Validator.Validator[Sample] {24 Validator.add(Validator.create(), Rule.build(check(Rule.ruleFor("score", |sample: Sample| sample.score))))25}2627fn main() -> Int {28 let sample = Sample{score: 5, nickname: Some("Ada"), tags: ["a", "b"], amount: 5d,29 level: 5, other: 6, child: Child{code: "ok"}, items: [Child{code: "ok"}, Child{code: ""}] }30 let below = Sample{..sample, score: 4, level: 4, other: 4, tags: [], nickname: None, amount: 5d}31 let above = Sample{..sample, score: 6, level: 6, other: 6}32 let codeRule = Rule.build(Rule.must(Rule.ruleFor("code", |child: Child| child.code),33 |code: Str| !code.isEmpty()))34 let childValidator = Validator.add(Validator.create(), codeRule)35 let checks = Test.suite("Boundary", &[36 Test.that("greaterThan rejects the bound", !Validator.validate(&numberRule(|base: Rule.RuleBuilder[Sample, Int]| NumberRule.greaterThan(base, 5)), sample).isValid),37 Test.that("greaterThanOrEqualTo accepts the bound", Validator.validate(&numberRule(|base: Rule.RuleBuilder[Sample, Int]| NumberRule.greaterThanOrEqualTo(base, 5)), sample).isValid),38 Test.that("lessThan rejects the bound", !Validator.validate(&numberRule(|base: Rule.RuleBuilder[Sample, Int]| NumberRule.lessThan(base, 5)), sample).isValid),39 Test.that("lessThanOrEqualTo accepts the bound", Validator.validate(&numberRule(|base: Rule.RuleBuilder[Sample, Int]| NumberRule.lessThanOrEqualTo(base, 5)), sample).isValid),40 Test.that("inclusiveBetween accepts the low bound", Validator.validate(&numberRule(|base: Rule.RuleBuilder[Sample, Int]| NumberRule.inclusiveBetween(base, 5, 6)), sample).isValid),41 Test.that("inclusiveBetween accepts the high bound", Validator.validate(&numberRule(|base: Rule.RuleBuilder[Sample, Int]| NumberRule.inclusiveBetween(base, 5, 6)), above).isValid),42 Test.that("exclusiveBetween rejects the low bound", !Validator.validate(&numberRule(|base: Rule.RuleBuilder[Sample, Int]| NumberRule.exclusiveBetween(base, 5, 6)), sample).isValid),43 Test.that("exclusiveBetween rejects below the bounds", !Validator.validate(&numberRule(|base: Rule.RuleBuilder[Sample, Int]| NumberRule.exclusiveBetween(base, 5, 6)), below).isValid),44 Test.that("exclusiveBetween rejects the high bound", !Validator.validate(&numberRule(|base: Rule.RuleBuilder[Sample, Int]| NumberRule.exclusiveBetween(base, 5, 6)), above).isValid),45 Test.that("equal accepts the expected value", Validator.validate(&numberRule(|base: Rule.RuleBuilder[Sample, Int]| NumberRule.equal(base, 5)), sample).isValid),46 Test.that("notEqual rejects the excluded value", !Validator.validate(&numberRule(|base: Rule.RuleBuilder[Sample, Int]| NumberRule.notEqual(base, 5)), sample).isValid),47 Test.that("integer notEmpty accepts nonzero", Validator.validate(&numberRule(|base: Rule.RuleBuilder[Sample, Int]| NumberRule.notEmpty(base)), sample).isValid),48 Test.that("integer empty accepts zero", Validator.validate(&numberRule(|base: Rule.RuleBuilder[Sample, Int]| NumberRule.empty(base)), Sample{..sample, score: 0}).isValid),49 Test.that("notNull accepts a value", Validator.validate(&Validator.add(Validator.create(), Rule.build(PresenceRule.notNull(Rule.ruleFor("nickname", |sample: Sample| sample.nickname)))), sample).isValid),50 Test.that("notNull rejects absence", !Validator.validate(&Validator.add(Validator.create(), Rule.build(PresenceRule.notNull(Rule.ruleFor("nickname", |sample: Sample| sample.nickname)))), below).isValid),51 Test.that("isNull rejects a value", !Validator.validate(&Validator.add(Validator.create(), Rule.build(PresenceRule.isNull(Rule.ruleFor("nickname", |sample: Sample| sample.nickname)))), sample).isValid),52 Test.that("isNull accepts absence", Validator.validate(&Validator.add(Validator.create(), Rule.build(PresenceRule.isNull(Rule.ruleFor("nickname", |sample: Sample| sample.nickname)))), below).isValid),53 Test.that("collection notEmpty accepts items", Validator.validate(&Validator.add(Validator.create(), Rule.build(CollectionRule.notEmpty(Rule.ruleFor("tags", |sample: Sample| sample.tags)))), sample).isValid),54 Test.that("collection notEmpty rejects emptiness", !Validator.validate(&Validator.add(Validator.create(), Rule.build(CollectionRule.notEmpty(Rule.ruleFor("tags", |sample: Sample| sample.tags)))), below).isValid),55 Test.that("countBetween accepts the low bound", Validator.validate(&Validator.add(Validator.create(), Rule.build(CollectionRule.countBetween(Rule.ruleFor("tags", |sample: Sample| sample.tags), 2, 3))), sample).isValid),56 Test.that("countBetween accepts the high bound", Validator.validate(&Validator.add(Validator.create(), Rule.build(CollectionRule.countBetween(Rule.ruleFor("tags", |sample: Sample| sample.tags), 1, 2))), sample).isValid),57 Test.that("countBetween rejects below the low bound", !Validator.validate(&Validator.add(Validator.create(), Rule.build(CollectionRule.countBetween(Rule.ruleFor("tags", |sample: Sample| sample.tags), 3, 4))), sample).isValid),58 Test.that("filtered elements stay silent", Validator.validate(&Validator.add(Validator.create(), CollectionRule.forEachWhere("tags", |sample: Sample| sample.tags, |_tag: Str| false, |_tag: Str| false, "Never.")), sample).isValid),59 Test.that("decimal precision one accepts a digit", Validator.validate(&Validator.add(Validator.create(), Rule.build(DecimalRule.precisionScale(Rule.ruleFor("amount", |sample: Sample| sample.amount), 1, 0, false))), sample).isValid),60 Test.that("ordered greaterThanOrEqualTo accepts the bound", Validator.validate(&Validator.add(Validator.create(), Rule.build(OrderingRule.greaterThanOrEqualTo(Rule.ruleFor("level", |sample: Sample| sample.level), 5))), sample).isValid),61 Test.that("ordered lessThanOrEqualTo accepts the bound", Validator.validate(&Validator.add(Validator.create(), Rule.build(OrderingRule.lessThanOrEqualTo(Rule.ruleFor("level", |sample: Sample| sample.level), 5))), sample).isValid),62 Test.that("ordered inclusiveBetween accepts the low bound", Validator.validate(&Validator.add(Validator.create(), Rule.build(OrderingRule.inclusiveBetween(Rule.ruleFor("level", |sample: Sample| sample.level), 5, 6))), sample).isValid),63 Test.that("ordered inclusiveBetween accepts the high bound", Validator.validate(&Validator.add(Validator.create(), Rule.build(OrderingRule.inclusiveBetween(Rule.ruleFor("level", |sample: Sample| sample.level), 5, 6))), above).isValid),64 Test.that("ordered inclusiveBetween rejects outside", !Validator.validate(&Validator.add(Validator.create(), Rule.build(OrderingRule.inclusiveBetween(Rule.ruleFor("level", |sample: Sample| sample.level), 5, 6))), below).isValid),65 Test.that("typed notEqual accepts a different value", Validator.validate(&Validator.add(Validator.create(), Rule.build(ComparisonRule.notEqual(Rule.ruleFor("level", |sample: Sample| sample.level), 4))), sample).isValid),66 Test.that("typed notEqual rejects the excluded value", !Validator.validate(&Validator.add(Validator.create(), Rule.build(ComparisonRule.notEqual(Rule.ruleFor("level", |sample: Sample| sample.level), 5))), sample).isValid),67 Test.equals("default selection reaches failing elements", &Validator.validate(&Validator.add(Validator.create(), ChildRule.forEachValidator("items", |sample: Sample| sample.items, childValidator)), sample).errors.map(|failure: Validation.Failure| failure.propertyName), &["items[1].code"])68 ])69 Test.report(&Test.run(&checks))70}71