Pudu programming language
Menu
Package

@chrismichaelps / pudu-lang-validator

Typed fluent validation rules for Pudu

0.1.1Apache-2.01

InstallClose

CollectionTest.pudu

Pudu57 lines2.8 KB

GitHub ↗
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