File Coverage

blib/lib/SQL/Abstract/Test.pm
Criterion Covered Total %
statement 90 112 80.3
branch 41 54 75.9
condition 28 56 50.0
subroutine 14 19 73.6
pod 6 9 66.6
total 179 250 71.6


line stmt bran cond sub pod time code
1             package SQL::Abstract::Test; # see doc at end of file
2              
3 14     14   703796 use strict;
  14         124  
  14         371  
4 14     14   66 use warnings;
  14         20  
  14         339  
5 14     14   71 use base qw(Test::Builder::Module);
  14         23  
  14         1781  
6 14     14   91 use Test::Builder;
  14         20  
  14         305  
7 14     14   7605 use Test::Deep ();
  14         133890  
  14         368  
8 14     14   6302 use SQL::Abstract::Tree;
  14         62  
  14         16863  
9              
10             our @EXPORT_OK = qw(
11             is_same_sql_bind is_same_sql is_same_bind
12             eq_sql_bind eq_sql eq_bind dumper diag_where
13             $case_sensitive $sql_differ
14             );
15              
16             my $sqlat = SQL::Abstract::Tree->new;
17              
18             our $case_sensitive = 0;
19             our $parenthesis_significant = 0;
20             our $order_by_asc_significant = 0;
21              
22             our $sql_differ; # keeps track of differing portion between SQLs
23             our $tb; # not documented, but someone might be overriding it anyway
24              
25             sub _unpack_arrayrefref {
26              
27 538     538   729 my @args;
28 538         966 for (1,2) {
29 1076         1571 my $chunk = shift @_;
30              
31 1076 100 66     2329 if (ref $chunk eq 'REF' and ref $$chunk eq 'ARRAY') {
32 3         8 my ($sql, @bind) = @$$chunk;
33 3         10 push @args, ($sql, \@bind);
34             }
35             else {
36 1073         2013 push @args, $chunk, shift @_;
37             }
38              
39             }
40              
41             # maybe $msg and ... stuff
42 538         737 push @args, @_;
43              
44 538         1425 @args;
45             }
46              
47             sub is_same_sql_bind {
48 534     534 1 122120 my ($sql1, $bind_ref1, $sql2, $bind_ref2, $msg) = &_unpack_arrayrefref;
49              
50             # compare
51 534         1245 my $same_sql = eq_sql($sql1, $sql2);
52 534         1011 my $same_bind = eq_bind($bind_ref1, $bind_ref2);
53              
54             # call Test::Builder::ok
55 534   33     649431 my $tb = $tb || __PACKAGE__->builder;
56 534   33     5813 my $ret = $tb->ok($same_sql && $same_bind, $msg);
57              
58             # add debugging info
59 534 50       134670 if (!$same_sql) {
60 0         0 _sql_differ_diag($sql1, $sql2);
61             }
62 534 50       1080 if (!$same_bind) {
63 0         0 _bind_differ_diag($bind_ref1, $bind_ref2);
64             }
65              
66             # pass ok() result further
67 534         3066 return $ret;
68             }
69              
70             sub is_same_sql {
71 35     35 1 5251 my ($sql1, $sql2, $msg) = @_;
72              
73             # compare
74 35         85 my $same_sql = eq_sql($sql1, $sql2);
75              
76             # call Test::Builder::ok
77 35   33     203 my $tb = $tb || __PACKAGE__->builder;
78 35         489 my $ret = $tb->ok($same_sql, $msg);
79              
80             # add debugging info
81 35 50       10997 if (!$same_sql) {
82 0         0 _sql_differ_diag($sql1, $sql2);
83             }
84              
85             # pass ok() result further
86 35         122 return $ret;
87             }
88              
89             sub is_same_bind {
90 1     1 1 4 my ($bind_ref1, $bind_ref2, $msg) = @_;
91              
92             # compare
93 1         3 my $same_bind = eq_bind($bind_ref1, $bind_ref2);
94              
95             # call Test::Builder::ok
96 1   33     952 my $tb = $tb || __PACKAGE__->builder;
97 1         11 my $ret = $tb->ok($same_bind, $msg);
98              
99             # add debugging info
100 1 50       239 if (!$same_bind) {
101 0         0 _bind_differ_diag($bind_ref1, $bind_ref2);
102             }
103              
104             # pass ok() result further
105 1         3 return $ret;
106             }
107              
108             sub dumper {
109             # FIXME
110             # if we save the instance, we will end up with $VARx references
111             # no time to figure out how to avoid this (Deepcopy is *not* an option)
112 0     0 0 0 require Data::Dumper;
113 0         0 Data::Dumper->new([])->Terse(1)->Indent(1)->Useqq(1)->Deparse(1)->Quotekeys(0)->Sortkeys(1)->Maxdepth(0)
114             ->Values([@_])->Dump;
115             }
116              
117             sub diag_where{
118 0   0 0 0 0 my $tb = $tb || __PACKAGE__->builder;
119 0         0 $tb->diag("Search term:\n" . &dumper);
120             }
121              
122             sub _sql_differ_diag {
123 0   0 0   0 my $sql1 = shift || '';
124 0   0     0 my $sql2 = shift || '';
125              
126 0   0     0 my $tb = $tb || __PACKAGE__->builder;
127 0 0       0 $tb->${\($tb->in_todo ? 'note' : 'diag')} (
  0         0  
128             "SQL expressions differ\n"
129             ." got: $sql1\n"
130             ."want: $sql2\n"
131             ."\nmismatch around\n$sql_differ\n"
132             );
133             }
134              
135             sub _bind_differ_diag {
136 0     0   0 my ($bind_ref1, $bind_ref2) = @_;
137              
138 0   0     0 my $tb = $tb || __PACKAGE__->builder;
139 0 0       0 $tb->${\($tb->in_todo ? 'note' : 'diag')} (
  0         0  
140             "BIND values differ " . dumper({ got => $bind_ref1, want => $bind_ref2 })
141             );
142             }
143              
144             sub eq_sql_bind {
145 4     4 1 3705 my ($sql1, $bind_ref1, $sql2, $bind_ref2) = &_unpack_arrayrefref;
146              
147 4   100     13 return eq_sql($sql1, $sql2) && eq_bind($bind_ref1, $bind_ref2);
148             }
149              
150              
151 667     667 1 273477 sub eq_bind { goto &Test::Deep::eq_deeply };
152              
153             sub eq_sql {
154 2211     2211 1 568472 my ($sql1, $sql2) = @_;
155              
156             # parse
157 2211         7160 my $tree1 = $sqlat->parse($sql1);
158 2211         5590 my $tree2 = $sqlat->parse($sql2);
159              
160 2211         3910 undef $sql_differ;
161 2211 100       4620 return 1 if _eq_sql($tree1, $tree2);
162             }
163              
164             sub _eq_sql {
165 39540     39540   56428 my ($left, $right) = @_;
166              
167             # one is defined the other not
168 39540 100 100     151407 if ((defined $left) xor (defined $right)) {
    100 100        
    100          
169 21 100       51 $sql_differ = sprintf ("[%s] != [%s]\n", map { defined $_ ? $sqlat->unparse($_) : 'N/A' } ($left, $right) );
  42         132  
170 21         62 return 0;
171             }
172              
173             # one is undefined, then so is the other
174             elsif (not defined $left) {
175 1044         1722 return 1;
176             }
177              
178             # both are empty
179             elsif (@$left == 0 and @$right == 0) {
180 18         41 return 1;
181             }
182              
183             # one is empty
184 38457 100 100     165580 if (@$left == 0 or @$right == 0) {
    50 50        
    100          
185 9 100       24 $sql_differ = sprintf ("left: %s\nright: %s\n", map { @$_ ? $sqlat->unparse($_) : 'N/A'} ($left, $right) );
  18         77  
186 9         29 return 0;
187             }
188              
189             # one is a list, the other is an op with a list
190             elsif (ref $left->[0] xor ref $right->[0]) {
191             $sql_differ = sprintf ("[%s] != [%s]\nleft: %s\nright: %s\n", map
192 0 0       0 { ref $_ ? $sqlat->unparse($_) : $_ }
  0         0  
193             ($left->[0], $right->[0], $left, $right)
194             );
195 0         0 return 0;
196             }
197              
198             # both are lists
199             elsif (ref $left->[0]) {
200 14373   100     32484 for (my $i = 0; $i <= $#$left or $i <= $#$right; $i++ ) {
201 23060 100       39505 if (not _eq_sql ($left->[$i], $right->[$i]) ) {
202 4348 100 66     19519 if (! $sql_differ or $sql_differ !~ /left\:\s .+ right:\s/xs) {
203 886   50     1751 $sql_differ ||= '';
204 886 50       3047 $sql_differ .= "\n" unless $sql_differ =~ /\n\z/;
205 886         1823 $sql_differ .= sprintf ("left: %s\nright: %s\n", map { $sqlat->unparse($_) } ($left, $right) );
  1772         4238  
206             }
207 4348         25386 return 0;
208             }
209             }
210 10025         24973 return 1;
211             }
212              
213             # both are ops
214             else {
215              
216             # unroll parenthesis if possible/allowed
217 24075 100       39879 unless ($parenthesis_significant) {
218 23818         55711 $sqlat->_parenthesis_unroll($_) for $left, $right;
219             }
220              
221             # unroll ASC order by's
222 24075 100       40031 unless ($order_by_asc_significant) {
223 24057         51044 $sqlat->_strip_asc_from_order_by($_) for $left, $right;
224             }
225              
226 24075 100       53005 if ($left->[0] ne $right->[0]) {
    100          
227 378         1247 $sql_differ = sprintf "OP [$left->[0]] != [$right->[0]] in\nleft: %s\nright: %s\n",
228             $sqlat->unparse($left),
229             $sqlat->unparse($right)
230             ;
231 378         1208 return 0;
232             }
233              
234             # literals have a different arg-sig
235             elsif ($left->[0] eq '-LITERAL') {
236 9428         46652 (my $l = " $left->[1][0] " ) =~ s/\s+/ /g;
237 9428         33839 (my $r = " $right->[1][0] ") =~ s/\s+/ /g;
238 9428 50       22696 my $eq = $case_sensitive ? $l eq $r : uc($l) eq uc($r);
239 9428 100       16799 $sql_differ = "[$l] != [$r]\n" if not $eq;
240 9428         39382 return $eq;
241             }
242              
243             # if operators are identical, compare operands
244             else {
245 14269         26470 my $eq = _eq_sql($left->[1], $right->[1]);
246 14269 100 33     24472 $sql_differ ||= sprintf ("left: %s\nright: %s\n", map { $sqlat->unparse($_) } ($left, $right) ) if not $eq;
  0         0  
247 14269         35365 return $eq;
248             }
249             }
250             }
251              
252 0     0 0   sub parse { $sqlat->parse(@_) }
253             1;
254              
255              
256             __END__