File Coverage

blib/lib/Test/SQL/Translator.pm
Criterion Covered Total %
statement 92 191 48.1
branch 23 60 38.3
condition 3 8 37.5
subroutine 13 19 68.4
pod 7 11 63.6
total 138 289 47.7


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