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}