← Back to index

lib/BDD/Behave/Matcher/Collection.rakumod

121 / 122 lines covered (99.2%)

1unit module BDD::Behave::Matcher::Collection;23use BDD::Behave::Matcher;45class IncludeMatcher does Matcher is export {6  has $.expected;78  method matches($actual --> Bool) {9    return False unless $actual.defined;1011    given $actual {12      when Str {13        for $!expected.list -> $item {14          return False unless $actual.contains($item.Str);15        }16        return True;17      }18      when Setty | Baggy {19        for $!expected.list -> $item {20          return False unless $actual{$item};21        }22        return True;23      }24      when Associative {25        for $!expected.list -> $item {26          if $item ~~ Pair {27            return False unless $actual{$item.key}:exists;28            return False unless $actual{$item.key} eqv $item.value;29          } else {30            return False unless $actual{$item}:exists;31          }32        }33        return True;34      }35      when Positional | Iterable {36        my @arr = $actual.list;37        for $!expected.list -> $item {38          return False unless @arr.first({ $_ eqv $item }).defined;39        }40        return True;41      }42      default {43        return False;44      }45    }46  }4748  method format-expected(--> Str) {49    $!expected.list.map(*.raku).join(', ');50  }5152  method failure-message($actual --> Str) {53    "expected " ~ $actual.raku ~ " to include " ~ self.format-expected;54  }5556  method failure-message-negated($actual --> Str) {57    "expected " ~ $actual.raku ~ " not to include " ~ self.format-expected;58  }5960  method expected-value(--> Mu) { $!expected }6162  method description(--> Str) { 'include ' ~ self.format-expected }63}6465class ContainExactlyMatcher does Matcher is export {66  has $.expected;6768  method matches($actual --> Bool) {69    return False unless $actual.defined;70    return False unless $actual ~~ Positional | Iterable;7172    my @remaining = $actual.list;7374    for $!expected.list -> $item {75      my $idx = @remaining.first({ $_ eqv $item }, :k);76      if $idx.defined {77        @remaining.splice($idx, 1);78      } else {79        return False;80      }81    }8283    @remaining.elems == 0;84  }8586  method format-expected(--> Str) {87    $!expected.list.map(*.raku).join(', ');88  }8990  method failure-message($actual --> Str) {91    "expected " ~ $actual.raku ~ " to contain exactly " ~ self.format-expected;92  }9394  method failure-message-negated($actual --> Str) {95    "expected " ~ $actual.raku ~ " not to contain exactly " ~ self.format-expected;96  }9798  method expected-value(--> Mu) { $!expected }99100  method description(--> Str) { 'contain exactly ' ~ self.format-expected }101}102103class StartWithMatcher does Matcher is export {104  has $.expected;105106  method matches($actual --> Bool) {107    return False unless $actual.defined;108109    given $actual {110      when Str {111        for $!expected.list -> $item {112          return False unless $actual.starts-with($item.Str);113        }114        return True;115      }116      when Positional | Iterable {117        my @arr = $actual.list;118        my @items = $!expected.list;119        return False if @items.elems > @arr.elems;120        for @items.kv -> $i, $item {121          return False unless @arr[$i] eqv $item;122        }123        return True;124      }125      default {126        return False;127      }128    }129  }130131  method format-expected(--> Str) {132    $!expected.list.map(*.raku).join(', ');133  }134135  method failure-message($actual --> Str) {136    "expected " ~ $actual.raku ~ " to start with " ~ self.format-expected;137  }138139  method failure-message-negated($actual --> Str) {140    "expected " ~ $actual.raku ~ " not to start with " ~ self.format-expected;141  }142143  method expected-value(--> Mu) { $!expected }144145  method description(--> Str) { 'start with ' ~ self.format-expected }146}147148class EndWithMatcher does Matcher is export {149  has $.expected;150151  method matches($actual --> Bool) {152    return False unless $actual.defined;153154    given $actual {155      when Str {156        for $!expected.list -> $item {157          return False unless $actual.ends-with($item.Str);158        }159        return True;160      }161      when Positional | Iterable {162        my @arr = $actual.list;163        my @items = $!expected.list;164        return False if @items.elems > @arr.elems;165        my $offset = @arr.elems - @items.elems;166        for @items.kv -> $i, $item {167          return False unless @arr[$offset + $i] eqv $item;168        }169        return True;170      }171      default {172        return False;173      }174    }175  }176177  method format-expected(--> Str) {178    $!expected.list.map(*.raku).join(', ');179  }180181  method failure-message($actual --> Str) {182    "expected " ~ $actual.raku ~ " to end with " ~ self.format-expected;183  }184185  method failure-message-negated($actual --> Str) {186    "expected " ~ $actual.raku ~ " not to end with " ~ self.format-expected;187  }188189  method expected-value(--> Mu) { $!expected }190191  method description(--> Str) { 'end with ' ~ self.format-expected }192}193194class AllMatcher does Matcher is export {195  has Matcher $.inner;196197  method matches($actual --> Bool) {198    return False unless $actual.defined;199    return False unless $actual ~~ Positional | Iterable;200201    for $actual.list -> $item {202      return False unless $!inner.matches($item);203    }204    return True;205  }206207  method !find-failing-index($actual) {208    for $actual.list.kv -> $i, $item {209      return $i unless $!inner.matches($item);210    }211    return Int;212  }213214  method failure-message($actual --> Str) {215    unless $actual.defined && $actual ~~ Positional | Iterable {216      return "expected " ~ $actual.raku ~ " to be a collection that all "217           ~ $!inner.description;218    }219220    my $idx = self!find-failing-index($actual);221    if $idx.defined {222      my $item = $actual.list[$idx];223      return "expected " ~ $actual.raku ~ " to all " ~ $!inner.description224           ~ " (element at index " ~ $idx ~ ": " ~ $item.raku ~ " did not match)";225    }226    "expected " ~ $actual.raku ~ " to all " ~ $!inner.description;227  }228229  method failure-message-negated($actual --> Str) {230    "expected " ~ $actual.raku ~ " not to all " ~ $!inner.description;231  }232233  method expected-value(--> Mu) { $!inner }234235  method description(--> Str) { 'all ' ~ $!inner.description }236}