
VariablesTest.pudu
Pudu67 lines5.6 KB
1/** @Test.Variables.Suite — the settled view and its typed reads */2module PuduLangEnvironment.VariablesTest34import Std.App.Secret as Secret5import Std.Decimal as Decimal6import Std.Io as Io7import Std.Map as Map8import Std.Process as Process9import Std.Result as Result10import Std.Test as Test11import PuduLangEnvironment as Environment12import PuduLangEnvironment.Variables as Variables131415const SECRET: Str = "hunter2-very-secret"161718fn main() -> Int {19 let loaded = Map.fromPairs(&[("PORT", "8080"), ("RATIO", "0.25"), ("PRICE", "9.99"), ("DEBUG", "TRUE"), ("TOKEN", SECRET), ("HOST", "file"), ("EMPTY", ""), ("WORD", "fast")])20 let process = Map.fromPairs(&[("HOST", "shell"), ("SHELL_ONLY", "kept"), ("EMPTY", "")])21 let skipped = [Environment.MissingFile(".env.local")]22 let view = Variables.settled(&loaded, &process, false, [".env"], skipped)23 let launch = Variables.apply(&view, &Process.launch("tool", &[]).isolated())24 let checks = Test.suite("Variables", &[25 Test.equals("a loaded value is found", &Variables.find(&view, "PORT"), &Some("8080")),26 Test.equals("a process value the load left alone is found", &Variables.find(&view, "SHELL_ONLY"), &Some("kept")),27 Test.equals("without overwriting the process value wins", &Variables.find(&view, "HOST"), &Some("shell")),28 Test.equals("with overwriting the loaded value wins", &Variables.find(&Variables.settled(&loaded, &process, true, [], []), "HOST"), &Some("file")),29 Test.equals("an empty value is absent", &(Variables.find(&view, "EMPTY"), Variables.has(&view, "EMPTY")), &(None, false)),30 Test.equals("an unset key is absent", &(Variables.find(&view, "NOPE"), Variables.has(&view, "NOPE")), &(None, false)),31 Test.that("a set key is present", Variables.has(&view, "PORT")),32 Test.equals("text answers the value", &Variables.text(&view, "PORT"), &Ok("8080")),33 Test.equals("text names a missing key", &Variables.text(&view, "NOPE"), &Err(Environment.Missing(["NOPE"]))),34 Test.equals("a whole number is read", &(Variables.int(&view, "PORT"), Variables.findInt(&view, "PORT")), &(Ok(8080), Some(8080))),35 Test.equals("a float is read", &(Variables.float(&view, "RATIO"), Variables.findFloat(&view, "RATIO")), &(Ok(0.25), Some(0.25))),36 Test.equals("a decimal is read", &(Result.ok(Variables.decimal(&view, "PRICE")), Variables.findDecimal(&view, "PRICE")), &(Decimal.parse("9.99"), Decimal.parse("9.99"))),37 Test.equals("a truth value is read", &(Variables.bool(&view, "DEBUG"), Variables.findBool(&view, "DEBUG")), &(Ok(true), Some(true))),38 Test.equals("a malformed value names its key and kind", &[Result.map(Variables.int(&view, "WORD"), |_n: Int| ()), Result.map(Variables.float(&view, "WORD"), |_f: Float64| ()), Result.map(Variables.decimal(&view, "WORD"), |_d: Decimal| ()), Result.map(Variables.bool(&view, "WORD"), |_b: Bool| ())], &[39 Err(Environment.Malformed("WORD", "a whole number")),40 Err(Environment.Malformed("WORD", "a floating-point number")),41 Err(Environment.Malformed("WORD", "a decimal number")),42 Err(Environment.Malformed("WORD", "true or false"))43 ]),44 Test.equals("a missing value is missing for every kind", &(Variables.int(&view, "NOPE"), Variables.bool(&view, "NOPE")), &(Err(Environment.Missing(["NOPE"])), Err(Environment.Missing(["NOPE"])))),45 Test.equals("find answers nothing for malformed and missing values", &(Variables.findInt(&view, "WORD"), Variables.findFloat(&view, "NOPE"), Variables.findDecimal(&view, "WORD"), Variables.findBool(&view, "PORT")), &(None, None, None, None)),46 Test.equals("a secret reveals its value", &Result.map(Variables.secret(&view, "TOKEN"), |held: Secret.Secret| Secret.reveal(&held)), &Ok(SECRET)),47 Test.equals("a secret redacts its value", &Result.map(Variables.secret(&view, "TOKEN"), |held: Secret.Secret| Secret.redact(&held)), &Ok("[REDACTED]")),48 Test.equals("a missing secret is missing", &Result.map(Variables.secret(&view, "NOPE"), |held: Secret.Secret| Secret.redact(&held)), &Err(Environment.Missing(["NOPE"]))),49 Test.equals("require accepts present keys", &Variables.require(&view, &["PORT", "SHELL_ONLY"]), &Ok(())),50 Test.equals("require names every absent key in order", &Variables.require(&view, &["Z", "PORT", "EMPTY", "A"]), &Err(Environment.Missing(["Z", "EMPTY", "A"]))),51 Test.equals("only applied keys are listed", &view.applied, &["DEBUG", "EMPTY", "PORT", "PRICE", "RATIO", "TOKEN", "WORD"]),52 Test.equals("sources and skipped problems are kept", &(view.sources, view.skipped), &([".env"], skipped)),53 Test.equals("a launch is given the applied keys", &launch.variables, &[("DEBUG", "TRUE"), ("EMPTY", ""), ("PORT", "8080"), ("PRICE", "9.99"), ("RATIO", "0.25"), ("TOKEN", SECRET), ("WORD", "fast")]),54 Test.that("a launch keeps its own choices", !launch.inherits && launch.program == "tool"),55 Test.equals("a description hides values", &Variables.describe(&view), &"7 variables applied from .env; values are hidden."),56 Test.equals("a view from no source says so", &Variables.describe(&Variables.settled(&Map.empty(), &Map.empty(), true, [], [])), &"0 variables applied from no source; values are hidden."),57 Test.that("rendering the view shows no value", !show(view).contains(SECRET) && !show(view).contains("8080")),58 Test.that("the process view reads the process", Variables.has(&Variables.process(), "PATH")),59 Test.equals("the process view applies nothing and reads no source", &(Variables.process().applied, Variables.process().sources), &([], []))60 ])61 let ran = Test.run(&checks)62 for failure in Test.failuresOf(&ran) {63 let _reported = Io.writeErrorLine(failure)64 }65 Test.report(&ran)66}67