73 / 73 lines covered (100.0%)
1unit module BDD::Behave::Matcher::Type;23use BDD::Behave::Matcher;4use BDD::Behave::TypeName;56class BeAMatcher does Matcher is export {7 has Mu $.type is required;89 method matches($actual --> Bool) {10 ?($actual ~~ $!type);11 }1213 method type-name(--> Str) {14 short-type-name($!type);15 }1617 method failure-message($actual --> Str) {18 "expected " ~ $actual.raku ~ " to be a " ~ self.type-name;19 }2021 method failure-message-negated($actual --> Str) {22 "expected " ~ $actual.raku ~ " not to be a " ~ self.type-name;23 }2425 method expected-value(--> Mu) { $!type }2627 method description(--> Str) { 'be a ' ~ self.type-name }28}2930class BeAnInstanceOfMatcher does Matcher is export {31 has Mu $.type is required;3233 method matches($actual --> Bool) {34 ?($actual.defined && $actual.WHAT === $!type);35 }3637 method type-name(--> Str) {38 short-type-name($!type);39 }4041 method failure-message($actual --> Str) {42 "expected " ~ $actual.raku ~ " to be an instance of " ~ self.type-name;43 }4445 method failure-message-negated($actual --> Str) {46 "expected " ~ $actual.raku ~ " not to be an instance of " ~ self.type-name;47 }4849 method expected-value(--> Mu) { $!type }5051 method description(--> Str) { 'be an instance of ' ~ self.type-name }52}5354class RespondToMatcher does Matcher is export {55 has $.expected;5657 method !missing($actual) {58 $!expected.list.grep({ !$actual.^can($_.Str) });59 }6061 method matches($actual --> Bool) {62 ?(self!missing($actual).elems == 0);63 }6465 method format-expected(--> Str) {66 $!expected.list.map(*.raku).join(', ');67 }6869 method failure-message($actual --> Str) {70 my @missing = self!missing($actual);71 my $head = "expected " ~ $actual.raku ~ " to respond to "72 ~ self.format-expected;73 @missing.elems74 ?? $head ~ " (missing: " ~ @missing.map(*.raku).join(', ') ~ ")"75 !! $head;76 }7778 method failure-message-negated($actual --> Str) {79 "expected " ~ $actual.raku ~ " not to respond to " ~ self.format-expected;80 }8182 method expected-value(--> Mu) { $!expected }8384 method description(--> Str) { 'respond to ' ~ self.format-expected }85}8687class HaveAttributesMatcher does Matcher is export {88 has %.expected;8990 method !sorted-names() {91 %!expected.keys.sort;92 }9394 method !missing($actual) {95 self!sorted-names.grep({ !$actual.^can($_) });96 }9798 method !mismatches($actual) {99 my @result;100 for self!sorted-names -> $name {101 next unless $actual.^can($name);102 my $expected-value = %!expected{$name};103 my $actual-value = $actual."$name"();104105 my $passed = $expected-value ~~ Matcher106 ?? $expected-value.matches($actual-value)107 !! ($actual-value eqv $expected-value);108109 unless $passed {110 @result.push: %(111 :name($name),112 :actual($actual-value),113 :expected($expected-value),114 );115 }116 }117 @result;118 }119120 method matches($actual --> Bool) {121 return False unless $actual.defined;122 return False if self!missing($actual).elems;123 self!mismatches($actual).elems == 0;124 }125126 method format-expected(--> Str) {127 self!sorted-names.map({128 my $v = %!expected{$_};129 my $rendered = $v ~~ Matcher ?? $v.description !! $v.raku;130 "$_ => $rendered";131 }).join(', ');132 }133134 method failure-message($actual --> Str) {135 my $head = "expected " ~ $actual.raku ~ " to have attributes "136 ~ self.format-expected;137 my @parts;138139 my @missing = self!missing($actual);140 if @missing.elems {141 @parts.push: "missing: " ~ @missing.map(*.raku).join(', ');142 }143144 my @mismatched = self!mismatches($actual);145 if @mismatched.elems {146 my $detail = @mismatched.map({147 my $exp = $_<expected>;148 my $rendered = $exp ~~ Matcher ?? $exp.description !! $exp.raku;149 $_<name> ~ ": got " ~ $_<actual>.raku ~ ", wanted " ~ $rendered;150 }).join('; ');151 @parts.push: "mismatched: " ~ $detail;152 }153154 @parts.elems155 ?? $head ~ " (" ~ @parts.join('; ') ~ ")"156 !! $head;157 }158159 method failure-message-negated($actual --> Str) {160 "expected " ~ $actual.raku ~ " not to have attributes "161 ~ self.format-expected;162 }163164 method expected-value(--> Mu) { %!expected }165166 method description(--> Str) {167 'have attributes ' ~ self.format-expected;168 }169}