
CollectionTest.pudu
Pudu57 lines2.8 KB
1/** @Test.Validation.Collection.Suite — checks element chains and indices */2module PuduLangValidator.CollectionTest34import Std.Test as Test5import PuduLangValidator.Result as Validation6import PuduLangValidator.Rules.Collection as Collection7import PuduLangValidator.Validator as Validator89type Basket = { lines: Array[Str] }1011fn elementValidator() -> Validator.Validator[Basket] {12 let first = Collection.withMessage(Collection.must(13 Collection.ruleForEach("lines", |basket: Basket| basket.lines),14 |line: Str| !line.isEmpty()15 ), "Line \{CollectionIndex\} is empty.")16 let second = Collection.withMessage(Collection.must(first,17 |line: Str| line.length() >= 3), "Line \{CollectionIndex\} is short.")18 Validator.add(Validator.create(), Collection.buildEach(Collection.stopOnFirst(second)))19}2021fn filteredValidator() -> Validator.Validator[Basket] {22 let base = Collection.ruleForEach("lines", |basket: Basket| basket.lines)23 let filtered = Collection.whereItems(base, |line: Str| line != "skip")24 let indexed = Collection.withIndex(filtered, |index: Int, _line: Str| "at-" + show(index))25 let checked = Collection.withMessage(Collection.must(indexed, |line: Str| line.length() > 3),26 "Bad line at \{CollectionIndex\}: \{PropertyPath\}.")27 Validator.add(Validator.create(), Collection.buildEach(checked))28}2930fn silentValidator() -> Validator.Validator[Basket] {31 let base = Collection.ruleForEach("lines", |basket: Basket| basket.lines)32 let none = Collection.whereItems(base, |_line: Str| false)33 let checked = Collection.withMessage(Collection.must(none, |_line: Str| false), "Never.")34 Validator.add(Validator.create(), Collection.buildEach(checked))35}3637fn main() -> Int {38 let elements = elementValidator()39 let filtered = filteredValidator()40 let failures = Validator.validate(&elements, Basket{lines: ["", "ok", "long"]})41 let filteredFailures = Validator.validate(&filtered, Basket{lines: ["skip", "bad", "skip", "x"]})42 let silent = Validator.validate(&silentValidator(), Basket{lines: ["a", "b"]})43 let checks = Test.suite("Collection", &[44 Test.equals("one failure per stopped element", &failures.errors.length(), &2),45 Test.equals("chain paths use source indices", &failures.errors.map(|error: Validation.Failure| error.propertyName),46 &["lines[0]", "lines[1]"]),47 Test.equals("collection placeholder uses source index", &failures.errors[1].errorMessage,48 &"Line 1 is short."),49 Test.equals("filter retains original indices", &filteredFailures.errors.map(|error: Validation.Failure| error.propertyName),50 &["lines[at-1]", "lines[at-3]"]),51 Test.equals("custom index and numeric placeholder differ", &filteredFailures.errors[0].errorMessage,52 &"Bad line at 1: lines[at-1]."),53 Test.equals("filtered-out chain elements stay silent", &silent.errors.length(), &0)54 ])55 Test.report(&Test.run(&checks))56}57