
OutputTest.pudu
Pudu60 lines4.5 KB
1/** @Test.Domain.Output.Suite — output templates and event identifiers */2module PuduLangLog.Domain.OutputTest34import Std.Io as Io5import Std.Test as Test6import PuduLangLog.Domain.Display as Display7import PuduLangLog.Domain.EventId as EventId8import PuduLangLog.Domain.Output as Output9import PuduLangLog.Domain.Parser as Parser10import PuduLangLog as Log111213fn text(held: Str) -> Log.Value { Log.Scalar(Log.Text(held)) }141516fn property(name: Str, held: Log.Value) -> Log.Property { Log.Property{name: name, value: held} }171819fn rendered(output: Str, event: &Log.Event) -> Str { Display.plain(&Output.render(&Parser.parse(output), event)) }202122fn main() -> Int {23 let event = Log.Event {24 timestamp: Log.Timestamp{millis: 1790604309123, offset: 120},25 level: Log.Warning,26 template: Parser.parse("Disk \{Disk\} is \{Percent\}% full"),27 properties: [property("Disk", text("C")), property("Percent", Log.Scalar(Log.Integer(93))), property("SourceContext", text("App.Disk")), property("Host", text("web-1"))],28 failure: None,29 traceId: Some("4bf92f3577b34da6a3ce929d0e0e4736"),30 spanId: Some("00f067aa0ba902b7")31 }32 let failed = Log.Event{..event, failure: Some(Log.Failure{kind: "IoError", message: "full", trace: ["Disk.write"], causes: []})}33 let checks = Test.suite("Domain.Output", &[34 Test.equals("the console layout", &rendered("[\{Timestamp:HH:mm:ss\} \{Level:u3\}] \{Message:lj\}\{NewLine\}\{Exception\}", &event), &"[16:05:09 WRN] Disk C is 93% full\n"),35 Test.equals("the file layout", &rendered("\{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz\} [\{Level:u3\}] \{Message:lj\}\{NewLine\}\{Exception\}", &event), &"2026-09-28 16:05:09.123 +02:00 [WRN] Disk C is 93% full\n"),36 Test.equals("a message without format quotes text", &rendered("\{Message\}", &event), &"Disk \"C\" is 93% full"),37 Test.equals("timestamps without a format", &(rendered("\{Timestamp\}", &event), rendered("\{UtcTimestamp:HH:mm\}", &event)), &("09/28/2026 16:05:09 +02:00", "14:05")),38 Test.equals("levels", &(rendered("\{Level\}", &event), rendered("\{Level:w3\}", &event), rendered("[\{Level,-9\}]", &event)), &("Warning", "wrn", "[Warning ]")),39 Test.equals("text properties render bare and cased", &(rendered("\{SourceContext\}", &event), rendered("\{Host:u\}", &event)), &("App.Disk", "WEB-1")),40 Test.equals("other properties render as values", &rendered("\{Percent:000\}", &event), &"093"),41 Test.equals("a missing property writes nothing", &rendered("[\{Missing,5\}]", &event), &"[ ]"),42 Test.equals("trace and span", &rendered("\{TraceId\}/\{SpanId\}", &event), &"4bf92f3577b34da6a3ce929d0e0e4736/00f067aa0ba902b7"),43 Test.equals("absent trace and span are empty", &rendered("[\{TraceId\}]", &Log.Event{..event, traceId: None}), &"[]"),44 Test.equals("the remaining properties", &rendered("\{Properties\}", &event), &"\{ SourceContext: \"App.Disk\", Host: \"web-1\" \}"),45 Test.equals("properties named by the output template are left out", &rendered("\{SourceContext\} \{Properties\}", &event), &"App.Disk \{ Host: \"web-1\" \}"),46 Test.equals("the remaining properties as JSON", &rendered("\{Properties:j\}", &event), &"\{\"SourceContext\":\"App.Disk\",\"Host\":\"web-1\"\}"),47 Test.equals("no remaining properties", &rendered("\{Properties\}", &Log.Event{..event, properties: []}), &"\{ \}"),48 Test.equals("a failure ends with a line break", &rendered("\{Message:l\}\{NewLine\}\{Exception\}", &failed), &"Disk C is 93% full\nIoError: full\n at Disk.write\n"),49 Test.equals("trace lines are secondary", &Output.render(&Parser.parse("\{Exception\}"), &failed).map(|piece: Display.Piece| piece.style), &[Display.Plain, Display.Secondary]),50 Test.equals("output styles", &Output.render(&Parser.parse("[\{Timestamp:HH\} \{Level:u3\}]"), &event).map(|piece: Display.Piece| piece.style), &[Display.Tertiary, Display.Secondary, Display.Tertiary, Display.LevelStyle(Log.Warning), Display.Tertiary]),51 Test.equals("event identifiers", &[EventId.hex(EventId.compute("Hello, \{Name\}!")), EventId.hex(EventId.compute("")), EventId.hex(EventId.compute("a"))], &["3872171f", "00000000", "ca2e9442"]),52 Test.equals("a long template's identifier", &EventId.hex(EventId.compute("HTTP \{RequestMethod\} \{RequestPath\} responded \{StatusCode\} in \{Elapsed:0.0000\} ms")), &"62d0885c")53 ])54 let ran = Test.run(&checks)55 for failure in Test.failuresOf(&ran) {56 let _reported = Io.writeErrorLine(failure)57 }58 Test.report(&ran)59}60