File Coverage

lib/Test/Chai/Core/Assertions/Keys.pm
Criterion Covered Total %
statement 63 63 100.0
branch 30 32 93.7
condition 8 10 80.0
subroutine 11 11 100.0
pod 0 1 0.0
total 112 117 95.7


line stmt bran cond sub pod time code
1             package Test::Chai::Core::Assertions::Keys;
2 2     2   10 use strict;
  2         3  
  2         55  
3 2     2   10 use warnings;
  2         3  
  2         48  
4 2     2   10 use utf8;
  2         3  
  2         12  
5              
6 2     2   48 use Exporter qw/import/;
  2         6  
  2         109  
7             our @EXPORT_OK = qw/assert_keys/;
8              
9 2     2   11 use List::MoreUtils qw/all any/;
  2         9  
  2         17  
10              
11 2     2   1126 use Test::Chai::Util::Flag qw/flag/;
  2         4  
  2         106  
12 2     2   11 use Test::Chai::Util::Inspect qw/inspect/;
  2         4  
  2         1542  
13              
14             sub assert_keys {
15 47     47 0 80 my $self = shift;
16              
17 47         64 my @keys;
18             my $str;
19 47         126 my $obj = flag($self, 'object');
20 47         98 my $ok = 1;
21 47         71 my $mixed_args_msg =
22             'keys must be given single argument of ArrayRef|HashRef|String, or multiple String arguments';
23              
24 47 100       169 if (ref $_[0] eq 'ARRAY') {
    100          
25 15 100       48 return $self->_fail($mixed_args_msg) if @_ > 1;
26 14         20 @keys = @{ $_[0] };
  14         43  
27             }
28              
29             elsif (ref $_[0] eq 'HASH') {
30 11 100       36 return $self->_fail($mixed_args_msg) if @_ > 1;
31 10         14 @keys = keys %{ $_[0] };
  10         48  
32             }
33              
34             else {
35 21         75 @keys = @_;
36             }
37              
38 45 100       139 return $self->_fail('keys required') unless @keys;
39              
40 41         146 my @actual = keys $obj;
41 41         99 my @expected = @keys;
42 41         67 my $len = @keys;
43 41   100     109 my $any = flag($self, 'any') // 0;
44 41   100     112 my $all = flag($self, 'all') // 0;
45              
46 41 50 66     168 $all = 1 if !$any && !$all;
47              
48             # Has any
49 41 100       107 if ($any) {
50 8         19 my @intersection = grep { _index_of(\@actual, $_) } @expected;
  12         31  
51 8         20 $ok = @intersection > 0;
52             }
53              
54             # Has all
55 41 100       113 if ($all) {
56 33     49   218 $ok = all { _index_of(\@actual, $_) } @keys;
  49         156  
57              
58 33 100 66     193 if (!flag($self, 'negate') && !flag($self, 'contains')) {
59 10 100       32 $ok = 0 unless @keys == @actual;
60             }
61             }
62              
63             # Key string
64 41 100       89 if ($len > 1) {
65 24         51 @keys = map { inspect($_) } @keys;
  50         33669  
66 24         29327 my $last = pop @keys;
67 24 100       95 $str = join(', ', @keys) . ', and ' . $last if $all;
68 24 100       59 $str = join(', ', @keys) . ', or ' . $last if $any;
69             }
70              
71             else {
72 17 50       70 $str = defined $keys[0] ? inspect($keys[0]) : '';
73             }
74              
75             # Form
76 41 100       22018 $str = ($len > 1 ? 'keys ' : 'key ') . $str;
77              
78             # Have / include
79 41 100       124 $str = (flag($self, 'contains') ? 'contain ' : 'have ') . $str;
80              
81 41         335 return $self->assert(
82             $ok,
83             'expected #{this} to ' . $str,
84             'expected #{this} to not ' . $str,
85             [ sort @expected ],
86             [ sort @actual ],
87             1
88             );
89             }
90              
91             sub _index_of {
92 61     61   110 my ($array, $val) = @_;
93 61     106   282 return any { $_ eq $val } @$array;
  106         305  
94             }
95              
96             1;