Pass subtype to Literal() helper directly
[dbsrgits/SQL-Abstract.git] / lib / SQL / Abstract / Test.pm
CommitLineData
fffe6900 1package SQL::Abstract::Test; # see doc at end of file
2
3use strict;
4use warnings;
5aad8cf3 5use base qw/Test::Builder::Module Exporter/;
fffe6900 6use Data::Dumper;
4abea32b 7use Test::Builder;
01dd4e4f 8use SQL::Abstract::Tree;
fffe6900 9
e7827ba2 10our @EXPORT_OK = qw/&is_same_sql_bind &is_same_sql &is_same_bind
01dd4e4f 11 &eq_sql_bind &eq_sql &eq_bind
fffe6900 12 $case_sensitive $sql_differ/;
13
a24cc3a0 14my $sqlat = SQL::Abstract::Tree->new;
15
fffe6900 16our $case_sensitive = 0;
e40f5df9 17our $parenthesis_significant = 0;
fffe6900 18our $sql_differ; # keeps track of differing portion between SQLs
5aad8cf3 19our $tb = __PACKAGE__->builder;
fffe6900 20
21sub is_same_sql_bind {
22 my ($sql1, $bind_ref1, $sql2, $bind_ref2, $msg) = @_;
23
24 # compare
25823711 25 my $same_sql = eq_sql($sql1, $sql2);
fffe6900 26 my $same_bind = eq_bind($bind_ref1, $bind_ref2);
27
a6daa642 28 # call Test::Builder::ok
1a828f61 29 my $ret = $tb->ok($same_sql && $same_bind, $msg);
fffe6900 30
31 # add debugging info
32 if (!$same_sql) {
e7827ba2 33 _sql_differ_diag($sql1, $sql2);
fffe6900 34 }
35 if (!$same_bind) {
e7827ba2 36 _bind_differ_diag($bind_ref1, $bind_ref2);
fffe6900 37 }
1a828f61 38
39 # pass ok() result further
40 return $ret;
fffe6900 41}
42
e7827ba2 43sub is_same_sql {
44 my ($sql1, $sql2, $msg) = @_;
45
46 # compare
47 my $same_sql = eq_sql($sql1, $sql2);
48
49 # call Test::Builder::ok
1a828f61 50 my $ret = $tb->ok($same_sql, $msg);
e7827ba2 51
52 # add debugging info
53 if (!$same_sql) {
54 _sql_differ_diag($sql1, $sql2);
55 }
1a828f61 56
57 # pass ok() result further
58 return $ret;
e7827ba2 59}
60
61sub is_same_bind {
62 my ($bind_ref1, $bind_ref2, $msg) = @_;
63
64 # compare
65 my $same_bind = eq_bind($bind_ref1, $bind_ref2);
66
67 # call Test::Builder::ok
1a828f61 68 my $ret = $tb->ok($same_bind, $msg);
e7827ba2 69
70 # add debugging info
71 if (!$same_bind) {
72 _bind_differ_diag($bind_ref1, $bind_ref2);
73 }
1a828f61 74
75 # pass ok() result further
76 return $ret;
e7827ba2 77}
78
79sub _sql_differ_diag {
80 my ($sql1, $sql2) = @_;
81
82 $tb->diag("SQL expressions differ\n"
83 ." got: $sql1\n"
84 ."expected: $sql2\n"
85 ."differing in :\n$sql_differ\n"
86 );
87}
88
89sub _bind_differ_diag {
90 my ($bind_ref1, $bind_ref2) = @_;
91
92 $tb->diag("BIND values differ\n"
93 ." got: " . Dumper($bind_ref1)
94 ."expected: " . Dumper($bind_ref2)
95 );
96}
97
98sub eq_sql_bind {
99 my ($sql1, $bind_ref1, $sql2, $bind_ref2) = @_;
100
101 return eq_sql($sql1, $sql2) && eq_bind($bind_ref1, $bind_ref2);
102}
103
104
fffe6900 105sub eq_bind {
106 my ($bind_ref1, $bind_ref2) = @_;
fffe6900 107
fdfbbc65 108 local $Data::Dumper::Useqq = 1;
109 local $Data::Dumper::Sortkeys = 1;
5fe06f15 110 local $Data::Dumper::Deepcopy = 1;
fdfbbc65 111
112 return Dumper($bind_ref1) eq Dumper($bind_ref2);
fffe6900 113}
114
115sub eq_sql {
25823711 116 my ($sql1, $sql2) = @_;
117
118 # parse
a24cc3a0 119 my $tree1 = $sqlat->parse($sql1);
120 my $tree2 = $sqlat->parse($sql2);
25823711 121
6f2a5b66 122 undef $sql_differ;
1b17d1b0 123 return 1 if _eq_sql($tree1, $tree2);
25823711 124}
125
126sub _eq_sql {
fffe6900 127 my ($left, $right) = @_;
128
939db550 129 # one is defined the other not
130 if ( (defined $left) xor (defined $right) ) {
6f2a5b66 131 $sql_differ = sprintf ("[%s] != [%s]\n", map { defined $_ ? $sqlat->unparse ($_) : 'N/A' } ($left, $right) );
939db550 132 return 0;
133 }
6f2a5b66 134
939db550 135 # one is undefined, then so is the other
136 elsif (not defined $left) {
d15c14cc 137 return 1;
138 }
6f2a5b66 139
140 # both are empty
141 elsif (@$left == 0 and @$right == 0) {
0769ac0e 142 return 1;
143 }
6f2a5b66 144
145 # one is empty
146 if (@$left == 0 or @$right == 0) {
147 $sql_differ = sprintf ("left: %s\nright: %s\n", map { @$_ ? $sqlat->unparse ($_) : 'N/A'} ($left, $right) );
148 return 0;
149 }
150
1b17d1b0 151 # one is a list, the other is an op with a list
152 elsif (ref $left->[0] xor ref $right->[0]) {
6f2a5b66 153 $sql_differ = sprintf ("[%s] != [%s]\nleft: %s\nright: %s\n", map
154 { ref $_ ? $sqlat->unparse ($_) : $_ }
155 ($left->[0], $right->[0], $left, $right)
156 );
fffe6900 157 return 0;
158 }
6f2a5b66 159
160 # both are lists
1b17d1b0 161 elsif (ref $left->[0]) {
162 for (my $i = 0; $i <= $#$left or $i <= $#$right; $i++ ) {
6f2a5b66 163 if (not _eq_sql ($left->[$i], $right->[$i]) ) {
164 if (! $sql_differ or $sql_differ !~ /left\:\s .+ right:\s/xs) {
165 $sql_differ ||= '';
166 $sql_differ .= "\n" unless $sql_differ =~ /\n\z/;
167 $sql_differ .= sprintf ("left: %s\nright: %s\n", map { $sqlat->unparse ($_) } ($left, $right) );
168 }
169 return 0;
170 }
1b17d1b0 171 }
172 return 1;
173 }
6f2a5b66 174
175 # both are ops
1b17d1b0 176 else {
177
e40f5df9 178 # unroll parenthesis if possible/allowed
6f2a5b66 179 unless ( $parenthesis_significant ) {
180 $sqlat->_parenthesis_unroll($_) for $left, $right;
181 }
1b17d1b0 182
b9a4fdae 183 if ( $left->[0] ne $right->[0] ) {
1b17d1b0 184 $sql_differ = sprintf "OP [$left->[0]] != [$right->[0]] in\nleft: %s\nright: %s\n",
a24cc3a0 185 $sqlat->unparse($left),
6f2a5b66 186 $sqlat->unparse($right)
187 ;
1b17d1b0 188 return 0;
189 }
6f2a5b66 190
191 # literals have a different arg-sig
192 elsif ($left->[0] eq '-LITERAL') {
193 (my $l = " $left->[1][0] " ) =~ s/\s+/ /g;
194 (my $r = " $right->[1][0] ") =~ s/\s+/ /g;
195 my $eq = $case_sensitive ? $l eq $r : uc($l) eq uc($r);
196 $sql_differ = "[$l] != [$r]\n" if not $eq;
197 return $eq;
198 }
199
200 # if operators are identical, compare operands
01dd4e4f 201 else {
6f2a5b66 202 my $eq = _eq_sql($left->[1], $right->[1]);
203 $sql_differ ||= sprintf ("left: %s\nright: %s\n", map { $sqlat->unparse ($_) } ($left, $right) ) if not $eq;
204 return $eq;
fffe6900 205 }
206 }
207}
208
7853a177 209sub parse { $sqlat->parse(@_) }
fffe6900 2101;
211
212
213__END__
214
215=head1 NAME
216
217SQL::Abstract::Test - Helper function for testing SQL::Abstract
218
219=head1 SYNOPSIS
220
221 use SQL::Abstract;
222 use Test::More;
e7827ba2 223 use SQL::Abstract::Test import => [qw/
224 is_same_sql_bind is_same_sql is_same_bind
225 eq_sql_bind eq_sql eq_bind
226 /];
ec9af79e 227
fffe6900 228 my ($sql, @bind) = SQL::Abstract->new->select(%args);
e7827ba2 229
01dd4e4f 230 is_same_sql_bind($given_sql, \@given_bind,
fffe6900 231 $expected_sql, \@expected_bind, $test_msg);
232
e7827ba2 233 is_same_sql($given_sql, $expected_sql, $test_msg);
234 is_same_bind(\@given_bind, \@expected_bind, $test_msg);
235
01dd4e4f 236 my $is_same = eq_sql_bind($given_sql, \@given_bind,
e7827ba2 237 $expected_sql, \@expected_bind);
238
239 my $sql_same = eq_sql($given_sql, $expected_sql);
240 my $bind_same = eq_bind(\@given_bind, \@expected_bind);
241
fffe6900 242=head1 DESCRIPTION
243
244This module is only intended for authors of tests on
245L<SQL::Abstract|SQL::Abstract> and related modules;
246it exports functions for comparing two SQL statements
247and their bound values.
248
249The SQL comparison is performed on I<abstract syntax>,
250ignoring differences in spaces or in levels of parentheses.
251Therefore the tests will pass as long as the semantics
252is preserved, even if the surface syntax has changed.
253
ec9af79e 254B<Disclaimer> : the semantic equivalence handling is pretty limited.
255A lot of effort goes into distinguishing significant from
256non-significant parenthesis, including AND/OR operator associativity.
257Currently this module does not support commutativity and more
258intelligent transformations like Morgan laws, etc.
259
01dd4e4f 260For a good overview of what this test framework is capable of refer
ec9af79e 261to C<t/10test.t>
fffe6900 262
263=head1 FUNCTIONS
264
265=head2 is_same_sql_bind
266
01dd4e4f 267 is_same_sql_bind($given_sql, \@given_bind,
fffe6900 268 $expected_sql, \@expected_bind, $test_msg);
269
270Compares given and expected pairs of C<($sql, \@bind)>, and calls
e7827ba2 271L<Test::Builder/ok> on the result, with C<$test_msg> as message. If the test
272fails, a detailed diagnostic is printed. For clients which use L<Test::More>,
273this is the one of the three functions (L</is_same_sql_bind>, L</is_same_sql>,
274L</is_same_bind>) that needs to be imported.
275
276=head2 is_same_sql
277
278 is_same_sql($given_sql, $expected_sql, $test_msg);
279
280Compares given and expected SQL statements, and calls L<Test::Builder/ok> on
281the result, with C<$test_msg> as message. If the test fails, a detailed
282diagnostic is printed. For clients which use L<Test::More>, this is the one of
283the three functions (L</is_same_sql_bind>, L</is_same_sql>, L</is_same_bind>)
284that needs to be imported.
285
286=head2 is_same_bind
287
288 is_same_bind(\@given_bind, \@expected_bind, $test_msg);
289
290Compares given and expected bind values, and calls L<Test::Builder/ok> on the
291result, with C<$test_msg> as message. If the test fails, a detailed diagnostic
292is printed. For clients which use L<Test::More>, this is the one of the three
293functions (L</is_same_sql_bind>, L</is_same_sql>, L</is_same_bind>) that needs
294to be imported.
295
296=head2 eq_sql_bind
297
01dd4e4f 298 my $is_same = eq_sql_bind($given_sql, \@given_bind,
e7827ba2 299 $expected_sql, \@expected_bind);
300
301Compares given and expected pairs of C<($sql, \@bind)>. Similar to
302L</is_same_sql_bind>, but it just returns a boolean value and does not print
303diagnostics or talk to L<Test::Builder>.
fffe6900 304
305=head2 eq_sql
306
307 my $is_same = eq_sql($given_sql, $expected_sql);
308
e7827ba2 309Compares the abstract syntax of two SQL statements. Similar to L</is_same_sql>,
310but it just returns a boolean value and does not print diagnostics or talk to
311L<Test::Builder>. If the result is false, the global variable L</$sql_differ>
312will contain the SQL portion where a difference was encountered; this is useful
313for printing diagnostics.
fffe6900 314
315=head2 eq_bind
316
317 my $is_same = eq_sql(\@given_bind, \@expected_bind);
318
e7827ba2 319Compares two lists of bind values, taking into account the fact that some of
320the values may be arrayrefs (see L<SQL::Abstract/bindtype>). Similar to
321L</is_same_bind>, but it just returns a boolean value and does not print
322diagnostics or talk to L<Test::Builder>.
fffe6900 323
324=head1 GLOBAL VARIABLES
325
e7827ba2 326=head2 $case_sensitive
fffe6900 327
328If true, SQL comparisons will be case-sensitive. Default is false;
329
e40f5df9 330=head2 $parenthesis_significant
331
332If true, SQL comparison will preserve and report difference in nested
48d9f5f8 333parenthesis. Useful while testing C<IN (( x ))> vs C<IN ( x )>.
334Defaults to false;
e40f5df9 335
e7827ba2 336=head2 $sql_differ
fffe6900 337
338When L</eq_sql> returns false, the global variable
339C<$sql_differ> contains the SQL portion
340where a difference was encountered.
341
342
343=head1 SEE ALSO
344
a6daa642 345L<SQL::Abstract>, L<Test::More>, L<Test::Builder>.
fffe6900 346
25823711 347=head1 AUTHORS
fffe6900 348
349Laurent Dami, E<lt>laurent.dami AT etat geneve chE<gt>
350
25823711 351Norbert Buchmuller <norbi@nix.hu>
352
e96c510a 353Peter Rabbitson <ribasushi@cpan.org>
354
fffe6900 355=head1 COPYRIGHT AND LICENSE
356
357Copyright 2008 by Laurent Dami.
358
359This library is free software; you can redistribute it and/or modify
01dd4e4f 360it under the same terms as Perl itself.