Pudu programming language
Menu
Package

@chrismichaelps / pudu-lang-validator

Typed fluent validation rules for Pudu

0.1.1Apache-2.01

InstallClose

DynamicMetadataTest.pudu

Pudu81 lines4.6 KB

GitHub ↗
1/** @Test.Validation.DynamicMetadata.Suite — checks source-derived failure fields */2module PuduLangValidator.DynamicMetadataTest34import Std.Test as Test5import PuduLangValidator.Async as Async6import PuduLangValidator.Result as Validation7import PuduLangValidator.Rule as Rule8import PuduLangValidator.Validator as Validator910type Model = { name: Str, priority: Int }1112fn syncRule() -> Rule.RuleBuilder[Model, Str] {13  let checked = Rule.must(Rule.ruleFor("name", |model: Model| model.name),14    |value: Str| value == "ok")15  let severity = Rule.withSeverityFrom(checked, fn(root: Model, _value: Str) -> Validation.Severity {16      if root.priority > 1 { Validation.Warning } else { Validation.Info }17    })18  Rule.withStateFrom(severity, fn(root: Model, value: Str) -> Str {19      value + ":" + show(root.priority)20    })21}2223async fn matches(_root: Model, value: Str) -> Bool { value == "ok" }2425fn asyncRule() -> Async.AsyncRule[Model] {26  let checked = Async.mustAsync("name", |model: Model| model.name, matches,27    "Name failed.", "Name")28  let severity = Async.withSeverityFrom(checked, fn(root: Model) -> Validation.Severity {29      if root.priority > 1 { Validation.Warning } else { Validation.Info }30    })31  Async.withStateFrom(severity, fn(root: Model) -> Str { root.name + ":" + show(root.priority) })32}3334async fn main() -> Int {35  let bad = Model{name: "bad", priority: 2}36  let good = Model{name: "ok", priority: 2}37  let sync = Validator.add(Validator.create(), Rule.build(syncRule()))38  let syncBad = Validator.validate(&sync, bad)39  let syncGood = Validator.validate(&sync, good)40  let staticLast = Rule.withState(Rule.withSeverity(syncRule(), Validation.Error), "fixed")41  let staticResult = Validator.validate(&Validator.add(Validator.create(), Rule.build(staticLast)), bad)42  let dynamicLast = Rule.withStateFrom(Rule.withSeverityFrom(43      Rule.withState(Rule.withSeverity(Rule.must(Rule.ruleFor("name", |model: Model| model.name),44            |_value: Str| false), Validation.Error), "fixed"),45      fn(_root: Model, _value: Str) -> Validation.Severity { Validation.Info }),46    fn(root: Model, _value: Str) -> Str { show(root.priority) })47  let dynamicResult = Validator.validate(&Validator.add(Validator.create(), Rule.build(dynamicLast)), bad)48  let awaited = Async.add(Async.create(), asyncRule())49  let asyncBad = Async.validateAsync(&awaited, bad).await50  let asyncGood = Async.validateAsync(&awaited, good).await51  let asyncStatic = Async.add(Async.create(),52    Async.withState(Async.withSeverity(asyncRule(), Validation.Error), "fixed"))53  let asyncStaticResult = Async.validateAsync(&asyncStatic, bad).await54  let overridden = Async.withState(Async.withSeverity(55      Async.withStateFrom(Async.withSeverityFrom(asyncRule(),56          fn(_root: Model) -> Validation.Severity { panic("overridden severity ran") }),57        fn(_root: Model) -> Str { panic("overridden state ran") }),58      Validation.Error), "fixed")59  let overriddenResult = Async.validateAsync(&Async.add(Async.create(), overridden), bad).await60  let skippedFactory = Async.withSeverityFrom(asyncRule(),61    fn(_root: Model) -> Validation.Severity { panic("successful rule computed severity") })62  let skippedResult = Async.validateAsync(&Async.add(Async.create(), skippedFactory), good).await63  let checks = Test.suite("DynamicMetadata", &[64      Test.equals("sync severity comes from root", &syncBad.errors[0].severity, &Validation.Warning),65      Test.equals("sync state sees root and property", &syncBad.errors[0].customState, &"bad:2"),66      Test.equals("successful sync check has no failure", &syncGood.errors.length(), &0),67      Test.equals("later static severity wins", &staticResult.errors[0].severity, &Validation.Error),68      Test.equals("later static state wins", &staticResult.errors[0].customState, &"fixed"),69      Test.equals("later computed severity wins", &dynamicResult.errors[0].severity, &Validation.Info),70      Test.equals("later computed state wins", &dynamicResult.errors[0].customState, &"2"),71      Test.equals("async severity comes from root", &asyncBad.errors[0].severity, &Validation.Warning),72      Test.equals("async state comes from root", &asyncBad.errors[0].customState, &"bad:2"),73      Test.equals("successful async check has no failure", &asyncGood.errors.length(), &0),74      Test.equals("outer static async severity wins", &asyncStaticResult.errors[0].severity, &Validation.Error),75      Test.equals("outer static async state wins", &asyncStaticResult.errors[0].customState, &"fixed"),76      Test.equals("overridden async callbacks are not run", &overriddenResult.errors[0].customState, &"fixed"),77      Test.equals("successful async rules skip metadata callbacks", &skippedResult.errors.length(), &0)78    ])79  Test.report(&Test.run(&checks))80}81