60 / 61 lines covered (98.4%)
1unit module BDD::Behave::Benchmark::Format;23sub json-string(Str $s --> Str) {4 my $body = $s;5 $body = $body.subst('\\', '\\\\', :g);6 $body = $body.subst('"', '\\"', :g);7 $body = $body.subst("\b", '\\b', :g);8 $body = $body.subst("\f", '\\f', :g);9 $body = $body.subst("\n", '\\n', :g);10 $body = $body.subst("\r", '\\r', :g);11 $body = $body.subst("\t", '\\t', :g);12 '"' ~ $body ~ '"';13}1415sub json-number($n --> Str) {16 return 'null' unless $n.defined;17 $n.Real.Str;18}1920our sub to-json($value --> Str) {21 given $value {22 when Bool { $value ?? 'true' !! 'false' }23 when Numeric { json-number($value) }24 when Str { json-string($value) }25 when Positional { '[' ~ $value.list.map(&to-json).join(',') ~ ']' }26 when Associative {27 my @keys = $value.keys.sort;28 '{' ~ @keys.map(-> $k {29 json-string($k.Str) ~ ':' ~ to-json($value{$k})30 }).join(',') ~ '}';31 }32 default {33 return 'null' unless $value.defined;34 json-string($value.Str);35 }36 }37}3839our sub format-bench-summary(@summaries --> Hash) {40 my @rows;41 for @summaries -> %s {42 my $ex = %s<example>;43 @rows.push: {44 description => %s<description>,45 key => %s<key>,46 label => (%s<label> // Str),47 position => (%s<position> // Int),48 iterations => %s<iterations>,49 runs => (%s<runs> // 1),50 min => %s<min>.Real,51 max => %s<max>.Real,52 mean => %s<mean>.Real,53 median => %s<median>.Real,54 total => %s<total>.Real,55 file => ($ex.defined ?? $ex.file.Str !! Str),56 line => ($ex.defined ?? $ex.line !! Int),57 };58 }59 %( benchmarks => @rows );60}6162our sub format-bench-regressions(@regressions --> Hash) {63 my @rows;64 for @regressions -> %r {65 @rows.push: {66 description => %r<description>,67 key => %r<key>,68 current-median => %r<median>.Real,69 baseline-median => %r<baseline-median>.Real,70 delta-pct => %r<delta-pct>.Real,71 regression => %r<regression>.so,72 };73 }74 %( regressions => @rows );75}7677our sub to-json-document(@summaries, @regressions, Real $threshold --> Str) {78 my %summary = format-bench-summary(@summaries);79 my %regression = format-bench-regressions(@regressions);80 my %doc = (81 version => 1,82 threshold => $threshold.Real,83 benchmarks => %summary<benchmarks>,84 regressions => %regression<regressions>,85 );86 to-json(%doc);87}8889sub strip-ansi(Str $s --> Str) {90 $s.subst(/\e '[' \d+ 'm'/, '', :g);91}9293our sub visible-width(Str $s --> Int) {94 strip-ansi($s).chars;95}9697our sub pad-right(Str $s, Int $width --> Str) {98 my $pad = $width - visible-width($s);99 $pad > 0 ?? $s ~ (' ' x $pad) !! $s;100}101102our sub pad-left(Str $s, Int $width --> Str) {103 my $pad = $width - visible-width($s);104 $pad > 0 ?? (' ' x $pad) ~ $s !! $s;105}106107our sub render-table(@headers, @rows, @widths, @aligns --> Str) {108 my @lines;109110 my @header-cells;111 for ^@headers.elems -> $i {112 @header-cells.push: @aligns[$i] eq 'right'113 ?? pad-left(@headers[$i], @widths[$i])114 !! pad-right(@headers[$i], @widths[$i]);115 }116 @lines.push: ' ' ~ @header-cells.join(' ');117118 my @rule-cells = @widths.map({ '─' x $_ });119 @lines.push: ' ' ~ @rule-cells.join(' ');120121 for @rows -> @row {122 my @cells;123 for ^@row.elems -> $i {124 @cells.push: @aligns[$i] eq 'right'125 ?? pad-left(@row[$i], @widths[$i])126 !! pad-right(@row[$i], @widths[$i]);127 }128 @lines.push: ' ' ~ @cells.join(' ');129 }130 @lines.join("\n");131}132133our sub column-widths(@headers, @rows --> List) {134 my @widths = @headers.map(&visible-width);135 for @rows -> @row {136 for ^@row.elems -> $i {137 my $w = visible-width(@row[$i]);138 @widths[$i] = $w if $w > @widths[$i];139 }140 }141 @widths.List;142}