File Coverage

blib/lib/Test/SQL/Translator.pm
Criterion Covered Total %
statement 181 191 94.7
branch 39 60 65.0
condition 4 8 50.0
subroutine 19 19 100.0
pod 7 11 63.6
total 250 289 86.5


line stmt bran cond sub pod time code
1             package Test::SQL::Translator;
2              
3             =pod
4              
5             =head1 NAME
6              
7             Test::SQL::Translator - Test::More test functions for the Schema objects.
8              
9             =cut
10              
11 106     106   6709978 use strict;
  105         313308  
  105         4593  
12 62     62   3227 use warnings;
  62         148  
  62         3873  
13 59     59   971 use Test::More;
  59         97310  
  59         934  
14 59     59   43736 use SQL::Translator::Schema::Constants;
  59         176  
  59         6043  
15              
16 59     59   365 use base qw(Exporter);
  59         114  
  59         218864  
17             our @EXPORT_OK;
18             our $VERSION = '1.66';
19             our @EXPORT = qw(
20             schema_ok
21             table_ok
22             field_ok
23             constraint_ok
24             index_ok
25             view_ok
26             trigger_ok
27             procedure_ok
28             maybe_plan
29             );
30              
31             # $ATTRIBUTES{ } = { => , ... }
32             my %ATTRIBUTES = (
33             field => {
34             name => undef,
35             data_type => '',
36             default_value => undef,
37             size => '0',
38             is_primary_key => 0,
39             is_unique => 0,
40             is_nullable => 1,
41             is_foreign_key => 0,
42             is_auto_increment => 0,
43             comments => '',
44             extra => {},
45              
46             # foreign_key_reference,
47             is_valid => 1,
48              
49             # order
50             },
51             constraint => {
52             name => '',
53             type => '',
54             deferrable => 1,
55             expression => '',
56             is_valid => 1,
57             fields => [],
58             match_type => '',
59             options => [],
60             on_delete => '',
61             on_update => '',
62             reference_fields => [],
63             reference_table => '',
64             extra => {},
65             },
66             index => {
67             fields => [],
68             is_valid => 1,
69             name => "",
70             options => [],
71             type => NORMAL,
72             extra => {},
73             },
74             view => {
75             name => "",
76             sql => "",
77             fields => [],
78             is_valid => 1,
79             extra => {},
80             },
81             trigger => {
82             name => '',
83             perform_action_when => undef,
84             database_events => undef,
85             on_table => undef,
86             action => undef,
87             is_valid => 1,
88             extra => {},
89             },
90             procedure => {
91             name => '',
92             sql => '',
93             parameters => [],
94             owner => '',
95             comments => '',
96             extra => {},
97             },
98             table => {
99             comments => undef,
100             name => '',
101              
102             #primary_key => undef, # pkey constraint
103             options => [],
104              
105             #order => 0,
106             fields => undef,
107             constraints => undef,
108             indices => undef,
109             is_valid => 1,
110             extra => {},
111             },
112             schema => {
113             name => '',
114             database => '',
115             procedures => undef, # [] when set
116             tables => undef, # [] when set
117             triggers => undef, # [] when set
118             views => undef, # [] when set
119             is_valid => 1,
120             extra => {},
121             }
122             );
123              
124             # Given a test hash and schema object name set any attribute keys not present in
125             # the test hash to their default value for that schema object type.
126             # e.g. default_attribs( $test, "field" );
127             sub default_attribs {
128 35     35 0 83 my ($hashref, $object_type) = @_;
129              
130 35 50       137 if (!exists $ATTRIBUTES{$object_type}) {
131 0         0 die "Can't add default attribs for unknown Schema " . "object type '$object_type'.";
132             }
133              
134 35         74 for my $attr (
135 374         758 grep { !exists $hashref->{$_} }
136 35         236 keys %{ $ATTRIBUTES{$object_type} }
137             ) {
138 238         1175 $hashref->{$attr} = $ATTRIBUTES{$object_type}{$attr};
139             }
140              
141 35         105 return $hashref;
142             }
143              
144             # Format test name so it will prepend the test names used below.
145             sub t_name {
146 40     40 0 85 my $name = shift;
147 40   50     266 $name ||= "";
148 40 50       104 $name = "$name - " if $name;
149 40         114 return $name;
150             }
151              
152             sub field_ok {
153 21     21 1 102 my ($f1, $test, $name) = @_;
154 21         91 my $t_name = t_name($name);
155 21         83 default_attribs($test, "field");
156              
157 21 50       84 unless ($f1) {
158 0         0 fail " Field '$test->{name}' doesn't exist!";
159              
160             # TODO Do a skip on the following tests. Currently the test counts wont
161             # match at the end. So at least it fails.
162 0         0 return;
163             }
164              
165 21         907 my $full_name = $f1->table->name . "." . $test->{name};
166              
167 21         979 is($f1->name, $test->{name}, "${t_name}Field '$full_name'");
168              
169 21 50       10046 is($f1->is_valid, $test->{is_valid}, "$t_name is " . ($test->{is_valid} ? '' : 'not ') . 'valid');
170              
171 21         8594 is($f1->data_type, $test->{data_type}, "$t_name type is '$test->{data_type}'");
172              
173 21         12444 is($f1->size, $test->{size}, "$t_name size is '$test->{size}'");
174              
175             is(
176             $f1->default_value,
177             $test->{default_value},
178             "$t_name default value is "
179             . (
180             defined($test->{default_value})
181 21 100       8217 ? "'$test->{default_value}'"
182             : "UNDEF"
183             )
184             );
185              
186 21 100       9396 is($f1->is_nullable, $test->{is_nullable}, "$t_name " . ($test->{is_nullable} ? 'can' : 'cannot') . ' be null');
187              
188 21 100       9065 is($f1->is_unique, $test->{is_unique}, "$t_name " . ($test->{is_unique} ? 'can' : 'cannot') . ' be unique');
189              
190             is(
191             $f1->is_primary_key,
192             $test->{is_primary_key},
193 21 100       9019 "$t_name is " . ($test->{is_primary_key} ? '' : 'not ') . 'a primary_key'
194             );
195              
196             is(
197             $f1->is_foreign_key,
198             $test->{is_foreign_key},
199 21 100       8894 "$t_name is " . ($test->{is_foreign_key} ? '' : 'not') . ' a foreign_key'
200             );
201              
202             is(
203             $f1->is_auto_increment,
204             $test->{is_auto_increment},
205 21 100       8450 "$t_name is " . ($test->{is_auto_increment} ? '' : 'not ') . 'an auto_increment'
206             );
207              
208 21         10135 is($f1->comments, $test->{comments}, "$t_name comments");
209              
210 21         8623 is_deeply({ $f1->extra }, $test->{extra}, "$t_name extra");
211             }
212              
213             sub constraint_ok {
214 4     4 1 14 my ($obj, $test, $name) = @_;
215 4         16 my $t_name = t_name($name);
216 4         19 default_attribs($test, "constraint");
217              
218 4         138 is($obj->name, $test->{name}, "${t_name}Constraint '$test->{name}'");
219              
220 4         1936 is($obj->type, $test->{type}, "$t_name type is '$test->{type}'");
221              
222 4 50       2007 is($obj->deferrable, $test->{deferrable}, "$t_name " . ($test->{deferrable} ? 'can' : 'cannot') . ' be deferred');
223              
224 4 50       1886 is($obj->is_valid, $test->{is_valid}, "$t_name is " . ($test->{is_valid} ? '' : 'not ') . 'valid');
225              
226 4         1853 is($obj->table->name, $test->{table}, "$t_name table is '$test->{table}'");
227              
228 4         1940 is($obj->expression, $test->{expression}, "$t_name expression is '$test->{expression}'");
229              
230 4         1816 is_deeply([ $obj->fields ], $test->{fields}, "$t_name fields are '" . join(",", @{ $test->{fields} }) . "'");
  4         38  
231              
232 4         3180 is($obj->reference_table, $test->{reference_table}, "$t_name reference_table is '$test->{reference_table}'");
233              
234             is_deeply(
235             [ $obj->reference_fields ],
236             $test->{reference_fields},
237 4         1893 "$t_name reference_fields are '" . join(",", @{ $test->{reference_fields} }) . "'"
  4         31  
238             );
239              
240 4         2985 is($obj->match_type, $test->{match_type}, "$t_name match_type is '$test->{match_type}'");
241              
242 4         1795 is($obj->on_delete, $test->{on_delete}, "$t_name on_delete is '$test->{on_delete}'");
243              
244 4         1786 is($obj->on_update, $test->{on_update}, "$t_name on_update is '$test->{on_update}'");
245              
246 4         1820 is_deeply([ $obj->options ], $test->{options}, "$t_name options are '" . join(",", @{ $test->{options} }) . "'");
  4         29  
247              
248 4         3197 is_deeply({ $obj->extra }, $test->{extra}, "$t_name extra");
249             }
250              
251             sub index_ok {
252 1     1 1 4 my ($obj, $test, $name) = @_;
253 1         6 my $t_name = t_name($name);
254 1         5 default_attribs($test, "index");
255              
256 1         49 is($obj->name, $test->{name}, "${t_name}Index '$test->{name}'");
257              
258 1 50       436 is($obj->is_valid, $test->{is_valid}, "$t_name is " . ($test->{is_valid} ? '' : 'not ') . 'valid');
259              
260 1         500 is($obj->type, $test->{type}, "$t_name type is '$test->{type}'");
261              
262 1         473 is_deeply([ $obj->fields ], $test->{fields}, "$t_name fields are '" . join(",", @{ $test->{fields} }) . "'");
  1         9  
263              
264 1         440 is_deeply([ $obj->options ], $test->{options}, "$t_name options are '" . join(",", @{ $test->{options} }) . "'");
  1         7  
265              
266 1         748 is_deeply({ $obj->extra }, $test->{extra}, "$t_name extra");
267             }
268              
269             sub trigger_ok {
270 2     2 1 9 my ($obj, $test, $name) = @_;
271 2         9 my $t_name = t_name($name);
272 2         11 default_attribs($test, "index");
273              
274 2         22 is($obj->name, $test->{name}, "${t_name}Trigger '$test->{name}'");
275              
276 2 50       1785 is($obj->is_valid, $test->{is_valid}, "$t_name is " . ($test->{is_valid} ? '' : 'not ') . 'valid');
277              
278             is(
279             $obj->perform_action_when,
280             $test->{perform_action_when},
281 2         4833 "$t_name perform_action_when is '$test->{perform_action_when}'"
282             );
283              
284             is(
285             join(',', $obj->database_events),
286             $test->{database_events},
287 2         1046 sprintf("%s database_events is '%s'", $t_name, $test->{'database_events'},)
288             );
289              
290 2         903 is($obj->on_table, $test->{on_table}, "$t_name on_table is '$test->{on_table}'");
291              
292             is($obj->scope, $test->{scope}, "$t_name scope is '$test->{scope}'")
293 2 50       1049 if exists $test->{scope};
294              
295 2         969 is($obj->action, $test->{action}, "$t_name action is '$test->{action}'");
296              
297 2         1032 is_deeply({ $obj->extra }, $test->{extra}, "$t_name extra");
298             }
299              
300             sub view_ok {
301 1     1 1 2 my ($obj, $test, $name) = @_;
302 1         4 my $t_name = t_name($name);
303 1         4 default_attribs($test, "index");
304              
305             #isa_ok( $v, 'SQL::Translator::Schema::View', 'View' );
306              
307 1         8 is($obj->name, $test->{name}, "${t_name}View '$test->{name}'");
308              
309 1 50       248 is($obj->is_valid, $test->{is_valid}, "$t_name is " . ($test->{is_valid} ? '' : 'not ') . 'valid');
310              
311 1         307 is($obj->sql, $test->{sql}, "$t_name sql is '$test->{sql}'");
312              
313 1         521 is_deeply([ $obj->fields ], $test->{fields}, "$t_name fields are '" . join(",", @{ $test->{fields} }) . "'");
  1         11  
314              
315 1         945 is_deeply({ $obj->extra }, $test->{extra}, "$t_name extra");
316             }
317              
318             sub procedure_ok {
319 1     1 1 6 my ($obj, $test, $name) = @_;
320 1         6 my $t_name = t_name($name);
321 1         5 default_attribs($test, "index");
322              
323             #isa_ok( $v, 'SQL::Translator::Schema::View', 'View' );
324              
325 1         12 is($obj->name, $test->{name}, "${t_name}Procedure '$test->{name}'");
326              
327 1         482 is($obj->sql, $test->{sql}, "$t_name sql is '$test->{sql}'");
328              
329             is_deeply([ $obj->parameters ],
330 1         516 $test->{parameters}, "$t_name parameters are '" . join(",", @{ $test->{parameters} }) . "'");
  1         10  
331              
332 1         882 is($obj->comments, $test->{comments}, "$t_name comments is '$test->{comments}'");
333              
334 1         526 is($obj->owner, $test->{owner}, "$t_name owner is '$test->{owner}'");
335              
336 1         470 is_deeply({ $obj->extra }, $test->{extra}, "$t_name extra");
337             }
338              
339             sub table_ok {
340 4     4 1 12 my ($obj, $test, $name) = @_;
341 4         14 my $t_name = t_name($name);
342 4         18 default_attribs($test, "table");
343 4         23 my %arg = %$test;
344              
345 4   50     17 my $tbl_name = $arg{name} || die "Need a table name to test.";
346 4         29 is($obj->{name}, $arg{name}, "${t_name}Table '$arg{name}'");
347              
348 4         1652 is_deeply([ $obj->options ], $test->{options}, "$t_name options are '" . join(",", @{ $test->{options} }) . "'");
  4         32  
349              
350 4         3820 is_deeply({ $obj->extra }, $test->{extra}, "$t_name extra");
351              
352             # Fields
353 4 50       2600 if ($arg{fields}) {
354 4         9 my @fldnames = map { $_->{name} } @{ $arg{fields} };
  21         52  
  4         12  
355 4         26 is_deeply([ map { $_->name } $obj->get_fields ],
  21         831  
356             [@fldnames], "${t_name} field names are " . join(", ", @fldnames));
357 4         2962 foreach (@{ $arg{fields} }) {
  4         16  
358 21   50     13671 my $f_name = $_->{name} || die "Need a field name to test.";
359 21 50       113 next unless my $fld = $obj->get_field($f_name);
360 21         598 field_ok($fld, $_, $name);
361             }
362             } else {
363 0         0 is(scalar($obj->get_fields), undef, "${t_name} has no fields.");
364             }
365              
366             # Constraints and Indices
367 4         2683 _test_kids(
368             $obj, $test, $name,
369             {
370             constraint => 'constraints',
371             index => 'indices',
372             }
373             );
374             }
375              
376             sub _test_kids {
377 5     5   14 my ($obj, $test, $name, $kids) = @_;
378 5         19 my $t_name = t_name($name);
379 5         16 my $obj_name = ref $obj;
380 5         35 ($obj_name) = $obj_name =~ m/^.*::(.*)$/;
381              
382 5         27 while (my ($object_type, $plural) = each %$kids) {
383 11 100       3256 next unless defined $test->{$plural};
384              
385 5 50       10 if (my @tests = @{ $test->{$plural} }) {
  5         26  
386 5         14 my $meth = "get_$plural";
387 5         38 my @objects = $obj->$meth;
388 5         62 is(scalar(@objects), scalar(@tests), "${t_name}$obj_name has " . scalar(@tests) . " $plural");
389              
390 5         2099 for my $object (@objects) {
391 9         4835 my $ans = { lc($obj_name) => $obj->name, %{ shift @tests } };
  9         215  
392              
393 9         60 my $meth = "${object_type}_ok";
394             {
395 59     59   575 no strict 'refs';
  59         141  
  59         76138  
  9         21  
396 9         53 $meth->($object, $ans, $name);
397             }
398             }
399             }
400             }
401             }
402              
403             sub schema_ok {
404 1     1 0 212 my ($obj, $test, $name) = @_;
405 1         5 my $t_name = t_name($name);
406 1         6 default_attribs($test, "schema");
407              
408 1         14 is($obj->name, $test->{name}, "${t_name}Schema name is '$test->{name}'");
409              
410 1         478 is($obj->database, $test->{database}, "$t_name database is '$test->{database}'");
411              
412 1         479 is_deeply({ $obj->extra }, $test->{extra}, "$t_name extra");
413              
414 1 50       802 is($obj->is_valid, $test->{is_valid}, "$t_name is " . ($test->{is_valid} ? '' : 'not ') . 'valid');
415              
416             # Tables
417 1 50       565 if ($test->{tables}) {
418             is_deeply(
419 2         120 [ map { $_->name } $obj->get_tables ],
420 1         8 [ map { $_->{name} } @{ $test->{tables} } ],
  2         15  
  1         33  
421             "${t_name} table names match"
422             );
423 1         869 foreach (@{ $test->{tables} }) {
  1         6  
424 2   50     727 my $t_name = $_->{name} || die "Need a table name to test.";
425 2         14 table_ok($obj->get_table($t_name), $_, $name);
426             }
427             } else {
428 0         0 is(scalar($obj->get_tables), undef, "${t_name} has no tables.");
429             }
430              
431             # Procedures, Triggers, Views
432 1         6 _test_kids(
433             $obj, $test, $name,
434             {
435             procedure => 'procedures',
436             trigger => 'triggers',
437             view => 'views',
438             }
439             );
440             }
441              
442             # maybe_plan($ntests, @modules)
443             #
444             # Calls plan $ntests if @modules can all be loaded; otherwise,
445             # calls skip_all with an explanation of why the tests were skipped.
446             sub maybe_plan {
447 52     52 0 1005856 my ($ntests, @modules) = @_;
448 52         143 my @errors;
449              
450 52         175 for my $module (@modules) {
451 52     52   62642 eval "use $module;";
  49         152751  
  49         2411  
  102         10813  
452 102 100       796 next if !$@;
453              
454 4 50       73 if ($@ =~ /Can't locate (\S+)/) {
    0          
    0          
455 4         17 my $mod = $1;
456 4         21 $mod =~ s/\.pm$//;
457 4         15 $mod =~ s#/#::#g;
458 4         17 push @errors, $mod;
459             } elsif ($@ =~ /([\w\:]+ version [\d\.]+) required.+?this is only version/) {
460 0         0 push @errors, $1;
461             } elsif ($@ =~ /Can't load .+? for module .+?DynaLoader\.pm/i) {
462 0         0 push @errors, $module;
463             } else {
464 0         0 (my $err = $@) =~ s/\n+/\\n/g; # Can't have newlines in the skip message
465 0         0 push @errors, "$module: $err";
466             }
467             }
468              
469 52 100       284 if (@errors) {
470 3 100       29 my $msg = sprintf "Missing dependenc%s: %s", @errors == 1 ? 'y' : 'ies', join ", ", @errors;
471 3         30 plan skip_all => $msg;
472             }
473 49 100       9764 return unless defined $ntests;
474              
475 43 50       243 if ($ntests ne 'no_plan') {
476 43         386 plan tests => $ntests;
477             } else {
478 0           plan 'no_plan';
479             }
480             }
481              
482             1; # compile please ===========================================================
483             __END__