File Coverage

blib/lib/Test/Stream/Compare.pm
Criterion Covered Total %
statement 89 91 97.8
branch 44 50 88.0
condition 20 26 76.9
subroutine 27 27 100.0
pod 8 12 66.6
total 188 206 91.2


line stmt bran cond sub pod time code
1             package Test::Stream::Compare;
2 100     100   619 use strict;
  100         94  
  100         2252  
3 100     100   306 use warnings;
  100         93  
  100         2029  
4              
5 100     100   306 use Test::Stream::Util qw/try sub_info/;
  100         100  
  100         450  
6 100     100   32606 use Test::Stream::Delta();
  100         153  
  100         1963  
7              
8 100     100   444 use Carp qw/confess croak/;
  100         96  
  100         4393  
9 100     100   368 use Scalar::Util qw/blessed/;
  100         108  
  100         3199  
10              
11 100     100   336 use Test::Stream::Exporter qw/import export/;
  100         111  
  100         467  
12             export compare => sub {
13 1911     1911   2088 my ($got, $check, $convert) = @_;
14              
15 1911         3511 $check = $convert->($check);
16              
17 1911         4569 return $check->run(
18             id => undef,
19             got => $got,
20             exists => 1,
21             convert => $convert,
22             seen => {},
23             );
24             };
25              
26             sub MAX_CYCLES() { 75 }
27              
28             my @BUILD;
29              
30 2027 100   2027   6319 export get_build => sub { @BUILD ? $BUILD[-1] : undef };
31 1     1   3 export push_build => sub { push @BUILD => $_[0] };
32              
33             export pop_build => sub {
34 4 100 66 4   29 return pop @BUILD if @BUILD && $_[0] && $BUILD[-1] == $_[0];
      100        
35 3 100       9 my $have = @BUILD ? "$BUILD[-1]" : 'undef';
36 3 100       6 my $want = $_[0] ? "$_[0]" : 'undef';
37 3         273 croak "INTERNAL ERROR: Attempted to pop incorrect build, have $have, tried to pop $want";
38             };
39              
40             export build => sub {
41 465     465   535 my ($class, $code) = @_;
42              
43 465         2863 my @caller = caller(1);
44              
45 465 100       970 die "'$caller[3]\()' should not be called in void context in $caller[1] line $caller[2]\n"
46             unless defined(wantarray);
47              
48 464         1750 my $build = $class->new(builder => $code, called => \@caller);
49              
50 464         493 push @BUILD => $build;
51 464     464   1838 my ($ok, $err) = try { $code->($build); 1 };
  464         859  
  449         924  
52 464         1243 pop @BUILD;
53 464 100       808 die $err unless $ok;
54              
55 449         1279 return $build;
56             };
57 100     100   475 no Test::Stream::Exporter;
  100         118  
  100         325  
58              
59             use Test::Stream::HashBase(
60 100         456 accessors => [qw/builder _file _lines _info called/]
61 100     100   383 );
  100         146  
62              
63             *set_lines = \&set__lines;
64             *set_file = \&set__file;
65              
66             sub init {
67 10091     10091 0 7791 my $self = shift;
68 10091 100       15083 $self->{_lines} = delete $self->{lines} if exists $self->{lines};
69 10091 100       21441 $self->{_file} = delete $self->{file} if exists $self->{file};
70             }
71              
72             sub file {
73 64     64 0 53 my $self = shift;
74 64 100       125 return $self->{+_FILE} if $self->{+_FILE};
75              
76 50 100       90 if ($self->{+BUILDER}) {
    50          
77 32   33     50 $self->{+_INFO} ||= sub_info($self->{+BUILDER});
78 32         100 return $self->{+_INFO}->{file};
79             }
80             elsif ($self->{+CALLED}) {
81 0         0 return $self->{+CALLED}->[1];
82             }
83              
84 18         55 return undef;
85             }
86              
87             sub lines {
88 229     229 0 211 my $self = shift;
89 229 100       473 return $self->{+_LINES} if $self->{+_LINES};
90              
91 134 100       197 if ($self->{+BUILDER}) {
92 75   66     176 $self->{+_INFO} ||= sub_info($self->{+BUILDER});
93 75 50       59 return $self->{+_INFO}->{lines} if @{$self->{+_INFO}->{lines}};
  75         266  
94             }
95 59 50       109 if ($self->{+CALLED}) {
96 0         0 return [$self->{+CALLED}->[2]];
97             }
98 59         122 return [];
99             }
100              
101 231     231 1 876 sub delta_class { 'Test::Stream::Delta' }
102              
103 5347     5347 1 6085 sub deltas { () }
104 140     140 1 203 sub got_lines { () }
105              
106 69     69 0 169 sub stringify_got { 0 }
107              
108 50     50 1 91 sub operator { '' }
109 1     1 1 114 sub verify { confess "unimplemented" }
110 1     1 1 82 sub name { confess "unimplemented" }
111              
112             sub render {
113 153     153 1 111 my $self = shift;
114 153         284 return $self->name;
115             }
116              
117             sub run {
118 7512     7512 1 6311 my $self = shift;
119 7512         16691 my %params = @_;
120              
121 7512         6404 my $id = $params{id};
122 7512 50       10870 my $convert = $params{convert} or confess "no convert sub provided";
123 7512   50     11077 my $seen = $params{seen} ||= {};
124              
125             $params{exists} = exists $params{got} ? 1 : 0
126 7512 50       10148 unless exists $params{exists};
    100          
127              
128 7512         5949 my $exists = $params{exists};
129 7512 100       9686 my $got = $exists ? $params{got} : undef;
130              
131             # Prevent infinite cycles
132 7512 100 100     21541 if ($got && ref $got) {
133             die "Cycle detected in comparison, aborting"
134 2212 50 66     5189 if $seen->{$got} && $seen->{$got} >= MAX_CYCLES;
135 2212         4082 $seen->{$got}++;
136             }
137              
138 7512         20752 my $ok = $self->verify(%params);
139 7512 100       20537 my @deltas = $ok ? $self->deltas(%params) : ();
140              
141 7512 100 100     22887 $seen->{$got}-- if $got && ref $got;
142              
143 7512 100 100     42454 return if $ok && !@deltas;
144              
145 216 100       461 return $self->delta_class->new(
146             verified => $ok,
147             id => $id,
148             got => $got,
149             check => $self,
150             children => \@deltas,
151             $exists ? () : (dne => 'got'),
152             );
153             }
154              
155             1;
156              
157             __END__