Pudu programming language
Menu
Package

@chrismichaelps / pudu-lang-mediator

In-process messaging for Pudu: requests, notifications, streams, pipeline behaviors, processors, and exception handling

0.1.0Apache-2.01

InstallClose

ValidationTest.pudu

Pudu73 lines3.6 KB

GitHub ↗
1/** @Test.Behaviors.Validation.Suite — requests and streams refused by their rules */2module PuduLangMediator.Behaviors.ValidationTest34import Std.Io as Io5import Std.Test as Test6import PuduLangMediator.Behaviors.Validation as Validation7import PuduLangMediator.Context as Context8import PuduLangMediator.Mediator as Mediator9import PuduLangMediator as Messaging10import PuduLangMediator.Registration as Registration11import PuduLangMediator.Request as Request12import PuduLangMediator.Stream as Stream13import PuduLangMediator.Utils.Shared as Shared14import PuduLangValidator.Rule as Rule15import PuduLangValidator.Rules.Number as NumberRule16import PuduLangValidator.Rules.Text as TextRule17import PuduLangValidator.Validator as Validator1819/** @Test.Behaviors.Validation.SignUp — a request with rules */20type SignUp = { name: Str, age: Int }2122/// The rules a sign-up must keep.23fn rules() -> Validator.Validator[SignUp] {24  let name = Rule.build(TextRule.notEmpty(Rule.ruleFor("name", |request: SignUp| request.name)))25  let age = Rule.build(NumberRule.greaterThanOrEqualTo(Rule.ruleFor("age", |request: SignUp| request.age), 18))26  Validator.add(Validator.add(Validator.create(), name), age)27}2829/// Runs the suite.30fn main() -> Int {31  let signUp: Request.Kind[SignUp, Int, Str] = Request.kind("users.signUp")32  let roster: Stream.Kind[SignUp, Str, Str] = Stream.kind("users.roster")33  let handled = Shared.shared(0)34  let mediator = match Mediator.build([35      Validation.register(&signUp, rules()),36      Registration.handler(&signUp, fn(request: SignUp, _context: Context.Context) -> Messaging.Outcome[Int, Str] {37          Shared.update(&handled, |count: Int| count + 1)38          Ok(request.age)39        }),40      Validation.registerStream(&roster, rules()),41      Registration.streamHandler(&roster, fn(request: SignUp, _context: Context.Context, sink: Stream.Sink[Str]) -> Messaging.Outcome[(), Str] {42          Stream.each(&[request.name, request.name], sink)43        })44    ]) {45    case Ok(found) => found46    case Err(invalid) => panic(Mediator.explain(&invalid))47  }48  let accepted = Mediator.send(&mediator, &signUp, SignUp{name: "ada", age: 36})49  let rejected = Mediator.send(&mediator, &signUp, SignUp{name: "", age: 12})50  let violations = match rejected {51    case Err(failure) => Messaging.violations(&failure)52    case Ok(_) => []53  }54  let checks = Test.suite("Behaviors.Validation", &[55      Test.equals("a valid request reaches its handler", &accepted, &Ok(36)),56      Test.equals("an invalid request names every property it broke", &violations.map(|one: Messaging.Violation| one.property), &["name", "age"]),57      Test.that("each violation carries its rule's code", violations.length() == 2 && !violations[0].code.isEmpty()),58      Test.equals("an invalid request never reaches its handler", &Shared.current(&handled), &1),59      Test.that("the failure describes what was wrong", match rejected {60          case Err(failure) => Messaging.describe(&failure).startsWith("The message is invalid: name: ")61          case Ok(_) => false62        }),63      Test.equals("a valid stream emits", &Mediator.collect(&mediator, &roster, SignUp{name: "grace", age: 40}), &Ok(["grace", "grace"])),64      Test.equals("an invalid stream emits nothing", &(match Mediator.collect(&mediator, &roster, SignUp{name: "", age: 40}) { case Ok(items) => items.length() case Err(failure) => 0 - Messaging.violations(&failure).length() }), &(0 - 1)),65      Test.equals("an empty result has no violations", &Validation.violationsOf(&Validator.validate(&rules(), SignUp{name: "x", age: 20})), &[])66    ])67  let ran = Test.run(&checks)68  for failure in Test.failuresOf(&ran) {69    let _reported = Io.writeErrorLine(failure)70  }71  Test.report(&ran)72}73