Stop differentiating between ORDER BY foo and ORDER BY foo ASC by default
[scpubgit/Q-Branch.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;
328c5eac 8use Test::Deep ();
01dd4e4f 9use SQL::Abstract::Tree;
fffe6900 10
e7827ba2 11our @EXPORT_OK = qw/&is_same_sql_bind &is_same_sql &is_same_bind
01dd4e4f 12 &eq_sql_bind &eq_sql &eq_bind
fffe6900 13 $case_sensitive $sql_differ/;
14
a24cc3a0 15my $sqlat = SQL::Abstract::Tree->new;
16
fffe6900 17our $case_sensitive = 0;
e40f5df9 18our $parenthesis_significant = 0;
0c2de280 19our $order_by_asc_significant = 0;
20
fffe6900 21our $sql_differ; # keeps track of differing portion between SQLs
5aad8cf3 22our $tb = __PACKAGE__->builder;
fffe6900 23
24sub is_same_sql_bind {
25 my ($sql1, $bind_ref1, $sql2, $bind_ref2, $msg) = @_;
26
27 # compare
25823711 28 my $same_sql = eq_sql($sql1, $sql2);
fffe6900 29 my $same_bind = eq_bind($bind_ref1, $bind_ref2);
30
a6daa642 31 # call Test::Builder::ok
1a828f61 32 my $ret = $tb->ok($same_sql && $same_bind, $msg);
fffe6900 33
34 # add debugging info
35 if (!$same_sql) {
e7827ba2 36 _sql_differ_diag($sql1, $sql2);
fffe6900 37 }
38 if (!$same_bind) {
e7827ba2 39 _bind_differ_diag($bind_ref1, $bind_ref2);
fffe6900 40 }
1a828f61 41
42 # pass ok() result further
43 return $ret;
fffe6900 44}
45
e7827ba2 46sub is_same_sql {
47 my ($sql1, $sql2, $msg) = @_;
48
49 # compare
50 my $same_sql = eq_sql($sql1, $sql2);
51
52 # call Test::Builder::ok
1a828f61 53 my $ret = $tb->ok($same_sql, $msg);
e7827ba2 54
55 # add debugging info
56 if (!$same_sql) {
57 _sql_differ_diag($sql1, $sql2);
58 }
1a828f61 59
60 # pass ok() result further
61 return $ret;
e7827ba2 62}
63
64sub is_same_bind {
65 my ($bind_ref1, $bind_ref2, $msg) = @_;
66
67 # compare
68 my $same_bind = eq_bind($bind_ref1, $bind_ref2);
69
70 # call Test::Builder::ok
1a828f61 71 my $ret = $tb->ok($same_bind, $msg);
e7827ba2 72
73 # add debugging info
74 if (!$same_bind) {
75 _bind_differ_diag($bind_ref1, $bind_ref2);
76 }
1a828f61 77
78 # pass ok() result further
79 return $ret;
e7827ba2 80}
81
82sub _sql_differ_diag {
83 my ($sql1, $sql2) = @_;
84
85 $tb->diag("SQL expressions differ\n"
86 ." got: $sql1\n"
87 ."expected: $sql2\n"
88 ."differing in :\n$sql_differ\n"
89 );
90}
91
92sub _bind_differ_diag {
93 my ($bind_ref1, $bind_ref2) = @_;
94
95 $tb->diag("BIND values differ\n"
96 ." got: " . Dumper($bind_ref1)
97 ."expected: " . Dumper($bind_ref2)
98 );
99}
100
101sub eq_sql_bind {
102 my ($sql1, $bind_ref1, $sql2, $bind_ref2) = @_;
103
104 return eq_sql($sql1, $sql2) && eq_bind($bind_ref1, $bind_ref2);
105}
106
107
328c5eac 108sub eq_bind { goto &Test::Deep::eq_deeply };
fffe6900 109
110sub eq_sql {
25823711 111 my ($sql1, $sql2) = @_;
112
113 # parse
a24cc3a0 114 my $tree1 = $sqlat->parse($sql1);
115 my $tree2 = $sqlat->parse($sql2);
25823711 116
6f2a5b66 117 undef $sql_differ;
1b17d1b0 118 return 1 if _eq_sql($tree1, $tree2);
25823711 119}
120
121sub _eq_sql {
fffe6900 122 my ($left, $right) = @_;
123
939db550 124 # one is defined the other not
125 if ( (defined $left) xor (defined $right) ) {
6f2a5b66 126 $sql_differ = sprintf ("[%s] != [%s]\n", map { defined $_ ? $sqlat->unparse ($_) : 'N/A' } ($left, $right) );
939db550 127 return 0;
128 }
6f2a5b66 129
939db550 130 # one is undefined, then so is the other
131 elsif (not defined $left) {
d15c14cc 132 return 1;
133 }
6f2a5b66 134
135 # both are empty
136 elsif (@$left == 0 and @$right == 0) {
0769ac0e 137 return 1;
138 }
6f2a5b66 139
140 # one is empty
141 if (@$left == 0 or @$right == 0) {
142 $sql_differ = sprintf ("left: %s\nright: %s\n", map { @$_ ? $sqlat->unparse ($_) : 'N/A'} ($left, $right) );
143 return 0;
144 }
145
1b17d1b0 146 # one is a list, the other is an op with a list
147 elsif (ref $left->[0] xor ref $right->[0]) {
6f2a5b66 148 $sql_differ = sprintf ("[%s] != [%s]\nleft: %s\nright: %s\n", map
149 { ref $_ ? $sqlat->unparse ($_) : $_ }
150 ($left->[0], $right->[0], $left, $right)
151 );
fffe6900 152 return 0;
153 }
6f2a5b66 154
155 # both are lists
1b17d1b0 156 elsif (ref $left->[0]) {
157 for (my $i = 0; $i <= $#$left or $i <= $#$right; $i++ ) {
6f2a5b66 158 if (not _eq_sql ($left->[$i], $right->[$i]) ) {
159 if (! $sql_differ or $sql_differ !~ /left\:\s .+ right:\s/xs) {
160 $sql_differ ||= '';
161 $sql_differ .= "\n" unless $sql_differ =~ /\n\z/;
162 $sql_differ .= sprintf ("left: %s\nright: %s\n", map { $sqlat->unparse ($_) } ($left, $right) );
163 }
164 return 0;
165 }
1b17d1b0 166 }
167 return 1;
168 }
6f2a5b66 169
170 # both are ops
1b17d1b0 171 else {
172
e40f5df9 173 # unroll parenthesis if possible/allowed
6f2a5b66 174 unless ( $parenthesis_significant ) {
175 $sqlat->_parenthesis_unroll($_) for $left, $right;
176 }
1b17d1b0 177
0c2de280 178 # unroll ASC order by's
179 unless ($order_by_asc_significant) {
180 $sqlat->_strip_asc_from_order_by($_) for $left, $right;
181 }
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
0c2de280 336=head2 $order_by_asc_significant
337
338If true SQL comparison will consider C<ORDER BY foo ASC> and
339C<ORDER BY foo> to be different. Default is false;
340
e7827ba2 341=head2 $sql_differ
fffe6900 342
343When L</eq_sql> returns false, the global variable
344C<$sql_differ> contains the SQL portion
345where a difference was encountered.
346
347
348=head1 SEE ALSO
349
a6daa642 350L<SQL::Abstract>, L<Test::More>, L<Test::Builder>.
fffe6900 351
25823711 352=head1 AUTHORS
fffe6900 353
354Laurent Dami, E<lt>laurent.dami AT etat geneve chE<gt>
355
25823711 356Norbert Buchmuller <norbi@nix.hu>
357
e96c510a 358Peter Rabbitson <ribasushi@cpan.org>
359
fffe6900 360=head1 COPYRIGHT AND LICENSE
361
362Copyright 2008 by Laurent Dami.
363
364This library is free software; you can redistribute it and/or modify
01dd4e4f 365it under the same terms as Perl itself.