File Coverage

blib/lib/Test/Stream/Compare.pm
Criterion Covered Total %
statement 92 94 97.8
branch 44 50 88.0
condition 20 26 76.9
subroutine 28 28 100.0
pod 8 12 66.6
total 192 210 91.4


line stmt bran cond sub pod time code
1             package Test::Stream::Compare;
2 100     100   1071 use strict;
  100         171  
  100         2620  
3 100     100   487 use warnings;
  100         180  
  100         2733  
4              
5 100     100   493 use Test::Stream::Util qw/try sub_info/;
  100         173  
  100         650  
6 100     100   53684 use Test::Stream::Delta;
  100         267  
  100         3132  
7              
8 100     100   588 use Carp qw/confess croak/;
  100         239  
  100         5485  
9 100     100   523 use Scalar::Util qw/blessed/;
  100         185  
  100         4164  
10              
11 100     100   530 use Test::Stream::Exporter;
  100         183  
  100         692  
12             export compare => sub {
13 1895     1895   3380 my ($got, $check, $convert) = @_;
14              
15 1895         5155 $check = $convert->($check);
16              
17 1895         6728 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 1999 100   1999   9115 export get_build => sub { @BUILD ? $BUILD[-1] : undef };
31 1     1   4 export push_build => sub { push @BUILD => $_[0] };
32              
33             export pop_build => sub {
34 4 100 66 4   46 return pop @BUILD if @BUILD && $_[0] && $BUILD[-1] == $_[0];
      100        
35 3 100       18 my $have = @BUILD ? "$BUILD[-1]" : 'undef';
36 3 100       8 my $want = $_[0] ? "$_[0]" : 'undef';
37 3         365 croak "INTERNAL ERROR: Attempted to pop incorrect build, have $have, tried to pop $want";
38             };
39              
40             export build => sub {
41 456     456   897 my ($class, $code) = @_;
42              
43 456         3464 my @caller = caller(1);
44              
45 456 100       1315 die "'$caller[3]\()' should not be called in void context in $caller[1] line $caller[2]\n"
46             unless defined(wantarray);
47              
48 455         2375 my $build = $class->new(builder => $code, called => \@caller);
49              
50 455         751 push @BUILD => $build;
51 455     455   2339 my ($ok, $err) = try { $code->($build); 1 };
  455         1253  
  440         1294  
52 455         1639 pop @BUILD;
53 455 100       1246 die $err unless $ok;
54              
55 440         1787 return $build;
56             };
57 100     100   574 no Test::Stream::Exporter;
  100         195  
  100         451  
58              
59             use Test::Stream::HashBase(
60 100         608 accessors => [qw/builder _file _lines _info called/]
61 100     100   590 );
  100         180  
62              
63             *set_lines = \&set__lines;
64             *set_file = \&set__file;
65              
66             sub init {
67 9933     9933 0 13945 my $self = shift;
68 9933 100       23631 $self->{_lines} = delete $self->{lines} if exists $self->{lines};
69 9933 100       33934 $self->{_file} = delete $self->{file} if exists $self->{file};
70             }
71              
72             sub file {
73 64     64 0 91 my $self = shift;
74 64 100       175 return $self->{+_FILE} if $self->{+_FILE};
75              
76 50 100       150 if ($self->{+BUILDER}) {
    50          
77 32   33     79 $self->{+_INFO} ||= sub_info($self->{+BUILDER});
78 32         131 return $self->{+_INFO}->{file};
79             }
80             elsif ($self->{+CALLED}) {
81 0         0 return $self->{+CALLED}->[1];
82             }
83              
84 18         84 return undef;
85             }
86              
87             sub lines {
88 228     228 0 345 my $self = shift;
89 228 100       764 return $self->{+_LINES} if $self->{+_LINES};
90              
91 133 100       332 if ($self->{+BUILDER}) {
92 75   66     278 $self->{+_INFO} ||= sub_info($self->{+BUILDER});
93 75 50       90 return $self->{+_INFO}->{lines} if @{$self->{+_INFO}->{lines}};
  75         429  
94             }
95 58 50       193 if ($self->{+CALLED}) {
96 0         0 return [$self->{+CALLED}->[2]];
97             }
98 58         201 return [];
99             }
100              
101 100     100   599 use Test::Stream::Delta;
  100         196  
  100         37529  
102 230     230 1 1261 sub delta_class { 'Test::Stream::Delta' }
103              
104 5256     5256 1 9331 sub deltas { () }
105 139     139 1 325 sub got_lines { () }
106              
107 74     74 0 287 sub stringify_got { 0 }
108              
109 50     50 1 139 sub operator { '' }
110 1     1 1 170 sub verify { confess "unimplemented" }
111 1     1 1 116 sub name { confess "unimplemented" }
112              
113             sub render {
114 152     152 1 199 my $self = shift;
115 152         480 return $self->name;
116             }
117              
118             sub run {
119 7379     7379 1 10120 my $self = shift;
120 7379         27178 my %params = @_;
121              
122 7379         11361 my $id = $params{id};
123 7379 50       16488 my $convert = $params{convert} or confess "no convert sub provided";
124 7379   50     16998 my $seen = $params{seen} ||= {};
125              
126             $params{exists} = exists $params{got} ? 1 : 0
127 7379 50       15908 unless exists $params{exists};
    100          
128              
129 7379         10035 my $exists = $params{exists};
130 7379 100       14910 my $got = $exists ? $params{got} : undef;
131              
132             # Prevent infinite cycles
133 7379 100 100     29988 if ($got && ref $got) {
134             die "Cycle detected in comparison, aborting"
135 2164 50 66     7014 if $seen->{$got} && $seen->{$got} >= MAX_CYCLES;
136 2164         6151 $seen->{$got}++;
137             }
138              
139 7379         29442 my $ok = $self->verify(%params);
140 7379 100       32688 my @deltas = $ok ? $self->deltas(%params) : ();
141              
142 7379 100 100     34384 $seen->{$got}-- if $got && ref $got;
143              
144 7379 100 100     64514 return if $ok && !@deltas;
145              
146 215 100       635 return $self->delta_class->new(
147             verified => $ok,
148             id => $id,
149             got => $got,
150             check => $self,
151             children => \@deltas,
152             $exists ? () : (dne => 'got'),
153             );
154             }
155              
156             1;
157              
158             __END__