← Back to index

lib/BDD/Behave/Mock/Double.rakumod

41 / 44 lines covered (93.2%)

1unit module BDD::Behave::Mock::Double;23use BDD::Behave::Mock::ArgMatcher;4use BDD::Behave::TypeName;56class Double is export {7  has Str $.double-name;8  has Mu   $.double-class;9  has %!stubs;10  has Call @!calls;1112  submethod BUILD(:$!double-name, Mu :$double-class is raw = Mu, :%stubs) {13    $!double-class := $double-class;14    %!stubs = %stubs;15  }1617  method add-stub(*%pairs) {18    if $!double-class !=== Mu {19      for %pairs.keys -> $name {20        unless $!double-class.^can($name) {21          die "Double for '{$!double-name}': cannot stub '$name'; "22              ~ "{$!double-class.^name} has no such method";23        }24      }25    }26    for %pairs.kv -> $name, $value {27      %!stubs{$name} = $value;28    }29    self;30  }3132  method stubs() { %!stubs.clone }3334  method raw-stubs() is rw { %!stubs }3536  method calls() { @!calls.List }3738  method calls-of(Str:D $method) {39    @!calls.grep({ .method eq $method }).List;40  }4142  method received(Str:D $method --> Bool) {43    @!calls.first({ .method eq $method }).defined;44  }4546  method call-count(Str:D $method --> Int) {47    +@!calls.grep({ .method eq $method });48  }4950  method reset() {51    @!calls = ();52    self;53  }5455  method FALLBACK(Str $name, |c) {56    if $!double-class !=== Mu && !$!double-class.^can($name) {57      die "Double for '{$!double-name}': "58          ~ "{$!double-class.^name} has no method '$name'";59    }6061    my $caller = user-callframe();62    @!calls.push: Call.new(63      :method($name),64      :args(c.list),65      :named(c.hash),66      :file($caller.defined ?? $caller.file.IO !! IO::Path),67      :line($caller.defined ?? $caller.line.Int !! 0),68    );6970    return %!stubs{$name} unless %!stubs{$name} ~~ Callable;71    %!stubs{$name}(|c);72  }73}7475our sub double(|args) is export {76  my @pos   = args.list;77  my %named = args.hash;7879  my Str $double-name;80  my Mu  $double-class = Mu;8182  if @pos.elems == 0 {83    $double-name = 'anonymous';84  } elsif @pos.elems == 1 {85    if @pos[0] ~~ Str {86      $double-name = @pos[0];87    } else {88      $double-class = @pos[0];89      $double-name  = short-type-name($double-class);90    }91  } else {92    die "double() takes at most one positional argument (a name string or a class)";93  }9495  if $double-class !=== Mu {96    for %named.keys -> $name {97      unless $double-class.^can($name) {98        die "Double for '$double-name': cannot stub '$name'; "99            ~ "{$double-class.^name} has no such method";100      }101    }102  }103104  Double.new(:$double-name, :$double-class, :stubs(%named));105}