← Back to index

lib/BDD/Behave/Formatter/JSON.rakumod

71 / 79 lines covered (89.9%)

1use BDD::Behave::Benchmark::Format;2use BDD::Behave::Formatter;34unit class BDD::Behave::Formatter::JSON does BDD::Behave::Formatter;56has @!description-stack;7has @!examples;8has Str $!pending-auto-description;9has Bool $!multi-file = False;10has Int $!seed;11has Str $!order = 'defined';12has Bool $!emitted = False;13has Real $!start-time;14has @!load-errors;1516method name(--> Str) { 'json' }1718method !full-description(Str $description --> Str) {19  my @parts = @!description-stack.clone;20  @parts.push: $description;21  @parts.grep(*.defined).join(' ');22}2324method !ex-record($example, Str $status, %extras = %()) {25  my $description = $!pending-auto-description // $example.description;26  my %record = (27    description      => $description,28    full_description => self!full-description($description),29    status           => $status,30    file             => $example.file.Str,31    line             => $example.line,32    duration         => $example.duration.defined ?? $example.duration.Real !! Real,33    tags             => $example.effective-tags.List,34  );35  for %extras.kv -> $k, $v { %record{$k} = $v }36  %record;37}3839method suite-loading(Str :$file) { }4041method suite-start($suite, Bool :$multi-file = False) {42  $!multi-file = $multi-file;43  $!start-time //= now.Real;44}4546method suite-end($suite) { }4748method group-start($group) {49  @!description-stack.push: $group.description;50}5152method group-end($group) {53  @!description-stack.pop;54}5556method group-around-skipped($group) { }5758method example-start($example, Bool :$auto = False) {59  $!pending-auto-description = Str;60}6162method example-auto-description($example, Str :$description) {63  $!pending-auto-description = $description;64}6566method example-pass($example) {67  @!examples.push: self!ex-record($example, 'passed');68  $!pending-auto-description = Str;69}7071method example-fail($example, :$failure-info) {72  my %fail = ();7374  if $failure-info.defined {75    if $failure-info<exception>.defined {76      %fail<type>    = 'exception';77      %fail<message> = $failure-info<exception>.message;78    }79    elsif $failure-info<message>.defined {80      %fail<type>    = 'exception';81      %fail<message> = $failure-info<message>;82    }83    elsif $failure-info<exception-message>.defined {84      %fail<type>    = 'exception';85      %fail<message> = $failure-info<exception-message>;86    }8788    if $failure-info<file>.defined { %fail<file> = $failure-info<file>.Str }89    if $failure-info<line>.defined { %fail<line> = $failure-info<line> }9091    if $failure-info<expectations>.defined && $failure-info<expectations>.elems {92      %fail<expectations> = $failure-info<expectations>.List;93    }94  }9596  @!examples.push: self!ex-record($example, 'failed', %( failure => %fail ));97  $!pending-auto-description = Str;98}99100method example-pending($example) {101  my %extras = ();102  my $reason = $example.get-metadata('pending-reason');103  %extras<pending_reason> = $reason if $reason.defined;104  @!examples.push: self!ex-record($example, 'pending', %extras);105}106107method example-skipped($example) {108  @!examples.push: self!ex-record($example, 'skipped');109}110111method example-around-skipped($example) {112  @!examples.push: self!ex-record(113    $example, 'skipped',114    %( skip_reason => 'around-each did not invoke continuation' ),115  );116}117118method example-slow($example, Real :$threshold) { }119120method run-summary(121  $result,122  Bool :$aborted   = False,123  Int  :$fail-fast = 0,124  Str  :$order     = 'defined',125  Int  :$seed,126) {127  $!seed  = $seed  if $seed.defined;128  $!order = $order if $order.defined;129  return if $!multi-file;130  self!emit($result, :$aborted, :$fail-fast);131}132133method profile-summary(@records, Int :$limit)        { }134135method benchmark-summary-section(136  @summaries, @regressions,137  Real     :$threshold,138  Str      :$format,139  IO::Path :$output,140  :$runner,141) { }142143method multi-file-overall(144  $result,145  Str :$order = 'defined',146  Int :$seed,147) {148  $!seed  = $seed  if $seed.defined;149  $!order = $order;150  self!emit($result);151}152153method multi-file-profile($runner, @records, Int :$limit)        { }154method multi-file-benchmark(155  $runner,156  @summaries, @regressions,157  Real     :$threshold,158  Str      :$format,159  IO::Path :$output,160) { }161162method load-errors(@errors) {163  for @errors -> $err {164    @!load-errors.push: %(165      file    => $err<file>.Str,166      message => $err<message>.Str,167    );168  }169}170171method !emit($result, Bool :$aborted = False, Int :$fail-fast = 0) {172  return if $!emitted;173  $!emitted = True;174175  my %summary = (176    total    => $result.total,177    passed   => $result.passed,178    failed   => $result.failed,179    pending  => $result.pending,180    skipped  => $result.skipped,181    duration => ($!start-time.defined ?? (now.Real - $!start-time) !! Real),182  );183184  my %doc = (185    version       => 1,186    summary       => %summary,187    summary_line  => self!summary-line($result),188    seed          => $!seed,189    order         => $!order,190    aborted       => $aborted,191    examples      => @!examples.List,192    load_errors   => @!load-errors.List,193  );194195  say BDD::Behave::Benchmark::Format::to-json(%doc);196}197198method !summary-line($result --> Str) {199  my @parts;200  @parts.push: "{$result.total} example" ~ ($result.total == 1 ?? '' !! 's');201  @parts.push: "{$result.failed} failed"   if $result.failed  > 0;202  @parts.push: "{$result.pending} pending" if $result.pending > 0;203  @parts.push: "{$result.skipped} skipped" if $result.skipped > 0;204  @parts.push: "{$result.passed} passed"   if $result.passed  > 0;205  @parts.join(', ');206}