1 package SQL::Abstract::Test; # see doc at end of file
5 use base qw/Test::Builder::Module Exporter/;
8 use SQL::Abstract::Tree;
10 our @EXPORT_OK = qw/&is_same_sql_bind &is_same_sql &is_same_bind
11 &eq_sql_bind &eq_sql &eq_bind
12 $case_sensitive $sql_differ/;
14 my $sqlat = SQL::Abstract::Tree->new;
16 our $case_sensitive = 0;
17 our $parenthesis_significant = 0;
18 our $sql_differ; # keeps track of differing portion between SQLs
19 our $tb = __PACKAGE__->builder;
21 # All of these keywords allow their parameters to be specified with or without parenthesis without changing the semantics
22 my @unrollable_ops = (
30 sub is_same_sql_bind {
31 my ($sql1, $bind_ref1, $sql2, $bind_ref2, $msg) = @_;
34 my $same_sql = eq_sql($sql1, $sql2);
35 my $same_bind = eq_bind($bind_ref1, $bind_ref2);
37 # call Test::Builder::ok
38 my $ret = $tb->ok($same_sql && $same_bind, $msg);
42 _sql_differ_diag($sql1, $sql2);
45 _bind_differ_diag($bind_ref1, $bind_ref2);
48 # pass ok() result further
53 my ($sql1, $sql2, $msg) = @_;
56 my $same_sql = eq_sql($sql1, $sql2);
58 # call Test::Builder::ok
59 my $ret = $tb->ok($same_sql, $msg);
63 _sql_differ_diag($sql1, $sql2);
66 # pass ok() result further
71 my ($bind_ref1, $bind_ref2, $msg) = @_;
74 my $same_bind = eq_bind($bind_ref1, $bind_ref2);
76 # call Test::Builder::ok
77 my $ret = $tb->ok($same_bind, $msg);
81 _bind_differ_diag($bind_ref1, $bind_ref2);
84 # pass ok() result further
88 sub _sql_differ_diag {
89 my ($sql1, $sql2) = @_;
91 $tb->diag("SQL expressions differ\n"
94 ."differing in :\n$sql_differ\n"
98 sub _bind_differ_diag {
99 my ($bind_ref1, $bind_ref2) = @_;
101 $tb->diag("BIND values differ\n"
102 ." got: " . Dumper($bind_ref1)
103 ."expected: " . Dumper($bind_ref2)
108 my ($sql1, $bind_ref1, $sql2, $bind_ref2) = @_;
110 return eq_sql($sql1, $sql2) && eq_bind($bind_ref1, $bind_ref2);
115 my ($bind_ref1, $bind_ref2) = @_;
117 local $Data::Dumper::Useqq = 1;
118 local $Data::Dumper::Sortkeys = 1;
120 return Dumper($bind_ref1) eq Dumper($bind_ref2);
124 my ($sql1, $sql2) = @_;
127 my $tree1 = $sqlat->parse($sql1);
128 my $tree2 = $sqlat->parse($sql2);
130 return 1 if _eq_sql($tree1, $tree2);
134 my ($left, $right) = @_;
136 # one is defined the other not
137 if ( (defined $left) xor (defined $right) ) {
140 # one is undefined, then so is the other
141 elsif (not defined $left) {
144 # one is a list, the other is an op with a list
145 elsif (ref $left->[0] xor ref $right->[0]) {
146 $sql_differ = sprintf ("left: %s\nright: %s\n", map { $sqlat->unparse ($_) } ($left, $right) );
149 # one is a list, so is the other
150 elsif (ref $left->[0]) {
151 for (my $i = 0; $i <= $#$left or $i <= $#$right; $i++ ) {
152 return 0 if (not _eq_sql ($left->[$i], $right->[$i]) );
156 # both are an op-list combo
159 # unroll parenthesis if possible/allowed
160 _parenthesis_unroll ($_) for ($left, $right);
162 # if operators are different
163 if ( $left->[0] ne $right->[0] ) {
164 $sql_differ = sprintf "OP [$left->[0]] != [$right->[0]] in\nleft: %s\nright: %s\n",
165 $sqlat->unparse($left),
166 $sqlat->unparse($right);
169 # elsif operators are identical, compare operands
171 if ($left->[0] eq 'LITERAL' ) { # unary
172 (my $l = " $left->[1][0] " ) =~ s/\s+/ /g;
173 (my $r = " $right->[1][0] ") =~ s/\s+/ /g;
174 my $eq = $case_sensitive ? $l eq $r : uc($l) eq uc($r);
175 $sql_differ = "[$l] != [$r]\n" if not $eq;
179 my $eq = _eq_sql($left->[1], $right->[1]);
180 $sql_differ ||= sprintf ("left: %s\nright: %s\n", map { $sqlat->unparse ($_) } ($left, $right) ) if not $eq;
187 sub _parenthesis_unroll {
190 return if $parenthesis_significant;
191 return unless (ref $ast and ref $ast->[1]);
198 for my $child (@{$ast->[1]}) {
199 if (not ref $child or not $child->[0] eq 'PAREN') {
200 push @children, $child;
204 # unroll nested parenthesis
205 while ($child->[1][0][0] eq 'PAREN') {
206 $child = $child->[1][0];
210 # if the parenthesis are wrapped around an AND/OR matching the parent AND/OR - open the parenthesis up and merge the list
212 ( $ast->[0] eq 'AND' or $ast->[0] eq 'OR')
214 $child->[1][0][0] eq $ast->[0]
216 push @children, @{$child->[1][0][1]};
220 # if the parent operator explcitly allows it nuke the parenthesis
221 elsif ( grep { $ast->[0] =~ /^ $_ $/xi } @unrollable_ops ) {
222 push @children, $child->[1][0];
226 # only one LITERAL element in the parenthesis
228 @{$child->[1]} == 1 && $child->[1][0][0] eq 'LITERAL'
230 push @children, $child->[1][0];
234 # only one element in the parenthesis which is a binary op with two LITERAL sub-children
238 grep { $child->[1][0][0] =~ /^ $_ $/xi } (SQL::Abstract::Tree::_binary_op_keywords())
240 $child->[1][0][1][0][0] eq 'LITERAL'
242 $child->[1][0][1][1][0] eq 'LITERAL'
244 push @children, $child->[1][0];
248 # otherwise no more mucking for this pass
250 push @children, $child;
254 $ast->[1] = \@children;
260 sub parse { $sqlat->parse(@_) }
268 SQL::Abstract::Test - Helper function for testing SQL::Abstract
274 use SQL::Abstract::Test import => [qw/
275 is_same_sql_bind is_same_sql is_same_bind
276 eq_sql_bind eq_sql eq_bind
279 my ($sql, @bind) = SQL::Abstract->new->select(%args);
281 is_same_sql_bind($given_sql, \@given_bind,
282 $expected_sql, \@expected_bind, $test_msg);
284 is_same_sql($given_sql, $expected_sql, $test_msg);
285 is_same_bind(\@given_bind, \@expected_bind, $test_msg);
287 my $is_same = eq_sql_bind($given_sql, \@given_bind,
288 $expected_sql, \@expected_bind);
290 my $sql_same = eq_sql($given_sql, $expected_sql);
291 my $bind_same = eq_bind(\@given_bind, \@expected_bind);
295 This module is only intended for authors of tests on
296 L<SQL::Abstract|SQL::Abstract> and related modules;
297 it exports functions for comparing two SQL statements
298 and their bound values.
300 The SQL comparison is performed on I<abstract syntax>,
301 ignoring differences in spaces or in levels of parentheses.
302 Therefore the tests will pass as long as the semantics
303 is preserved, even if the surface syntax has changed.
305 B<Disclaimer> : the semantic equivalence handling is pretty limited.
306 A lot of effort goes into distinguishing significant from
307 non-significant parenthesis, including AND/OR operator associativity.
308 Currently this module does not support commutativity and more
309 intelligent transformations like Morgan laws, etc.
311 For a good overview of what this test framework is capable of refer
316 =head2 is_same_sql_bind
318 is_same_sql_bind($given_sql, \@given_bind,
319 $expected_sql, \@expected_bind, $test_msg);
321 Compares given and expected pairs of C<($sql, \@bind)>, and calls
322 L<Test::Builder/ok> on the result, with C<$test_msg> as message. If the test
323 fails, a detailed diagnostic is printed. For clients which use L<Test::More>,
324 this is the one of the three functions (L</is_same_sql_bind>, L</is_same_sql>,
325 L</is_same_bind>) that needs to be imported.
329 is_same_sql($given_sql, $expected_sql, $test_msg);
331 Compares given and expected SQL statements, and calls L<Test::Builder/ok> on
332 the result, with C<$test_msg> as message. If the test fails, a detailed
333 diagnostic is printed. For clients which use L<Test::More>, this is the one of
334 the three functions (L</is_same_sql_bind>, L</is_same_sql>, L</is_same_bind>)
335 that needs to be imported.
339 is_same_bind(\@given_bind, \@expected_bind, $test_msg);
341 Compares given and expected bind values, and calls L<Test::Builder/ok> on the
342 result, with C<$test_msg> as message. If the test fails, a detailed diagnostic
343 is printed. For clients which use L<Test::More>, this is the one of the three
344 functions (L</is_same_sql_bind>, L</is_same_sql>, L</is_same_bind>) that needs
349 my $is_same = eq_sql_bind($given_sql, \@given_bind,
350 $expected_sql, \@expected_bind);
352 Compares given and expected pairs of C<($sql, \@bind)>. Similar to
353 L</is_same_sql_bind>, but it just returns a boolean value and does not print
354 diagnostics or talk to L<Test::Builder>.
358 my $is_same = eq_sql($given_sql, $expected_sql);
360 Compares the abstract syntax of two SQL statements. Similar to L</is_same_sql>,
361 but it just returns a boolean value and does not print diagnostics or talk to
362 L<Test::Builder>. If the result is false, the global variable L</$sql_differ>
363 will contain the SQL portion where a difference was encountered; this is useful
364 for printing diagnostics.
368 my $is_same = eq_sql(\@given_bind, \@expected_bind);
370 Compares two lists of bind values, taking into account the fact that some of
371 the values may be arrayrefs (see L<SQL::Abstract/bindtype>). Similar to
372 L</is_same_bind>, but it just returns a boolean value and does not print
373 diagnostics or talk to L<Test::Builder>.
375 =head1 GLOBAL VARIABLES
377 =head2 $case_sensitive
379 If true, SQL comparisons will be case-sensitive. Default is false;
381 =head2 $parenthesis_significant
383 If true, SQL comparison will preserve and report difference in nested
384 parenthesis. Useful for testing the C<-nest> modifier. Defaults to false;
388 When L</eq_sql> returns false, the global variable
389 C<$sql_differ> contains the SQL portion
390 where a difference was encountered.
395 L<SQL::Abstract>, L<Test::More>, L<Test::Builder>.
399 Laurent Dami, E<lt>laurent.dami AT etat geneve chE<gt>
401 Norbert Buchmuller <norbi@nix.hu>
403 Peter Rabbitson <ribasushi@cpan.org>
405 =head1 COPYRIGHT AND LICENSE
407 Copyright 2008 by Laurent Dami.
409 This library is free software; you can redistribute it and/or modify
410 it under the same terms as Perl itself.