File Coverage

blib/lib/Test/DBIx/Class.pm
Criterion Covered Total %
statement 366 411 89.0
branch 107 152 70.3
condition 36 63 57.1
subroutine 49 51 96.0
pod 0 1 0.0
total 558 678 82.3


line stmt bran cond sub pod time code
1             package Test::DBIx::Class;
2              
3 17     17   464898 use 5.008;
  17         43  
4 17     17   68 use strict;
  17         16  
  17         280  
5 17     17   50 use warnings;
  17         29  
  17         475  
6              
7 17     17   63 use base 'Test::Builder::Module';
  17         24  
  17         2038  
8              
9             our $VERSION = '0.52';
10             our $AUTHORITY = 'cpan:JJNAPIORK';
11              
12 17     17   49719 use Config::Any;
  17         148770  
  17         484  
13 17     17   7992 use Data::Visitor::Callback;
  17         6088055  
  17         591  
14 17     17   118 use Digest::MD5;
  17         22  
  17         667  
15 17     17   8870 use Hash::Merge;
  17         31735  
  17         684  
16 17     17   5889 use Path::Class;
  17         418228  
  17         932  
17 17     17   196 use Scalar::Util ();
  17         21  
  17         267  
18 17     17   62 use Sub::Exporter;
  17         19  
  17         164  
19 17     17   9749 use Test::DBIx::Class::SchemaManager;
  17         5055  
  17         568  
20 17     17   10675 use Test::Deep ();
  17         102064  
  17         371  
21 17     17   95 use Test::More ();
  17         19  
  17         21722  
22              
23             sub eq_or_diff2 {
24 32     32 0 72 my ($given, $expected, $message) = @_;
25 32         118 my ($ok, $stack) = Test::Deep::cmp_details($given, $expected);
26 32 50       107242 if($ok) {
27 32         105 Test::More::pass($message);
28             } else {
29 0         0 my $diag = Test::Deep::deep_diag($stack);
30 0         0 Test::More::fail("$message: $diag");
31             }
32             }
33              
34             sub import {
35 10     10   122 my ($class, @opts) = @_;
36 10         24 my ($schema_manager, $merged_config, @exports) = $class->_initialize(@opts);
37             my $exporter = Sub::Exporter::build_exporter({
38             exports => [
39             dump_settings => sub {
40             return sub {
41 0     0   0 return $merged_config, @exports;
42 10     10   173 };
43             },
44             Schema => sub {
45             return sub {
46 1         114 return $schema_manager->schema;
47             }
48 10     11   2271 },
49             ResultSet => sub {
50 10     10   147 my ($local_class, $name, $arg) = @_;
51             return sub {
52 5         14471 my $source = shift @_;
53 5         9 my $search = shift @_;
54 5         175 my $resultset = $schema_manager->schema->resultset($source);
55              
56 5 50       1439 if(my $global_search = $arg->{search}) {
57 0 0       0 my @global_search = ref $global_search eq 'ARRAY' ? @$global_search : ($global_search);
58 0         0 $resultset = $resultset->search(@global_search);
59             }
60              
61 5 50       14 if(my $global_cb = $arg->{exec}) {
62 0         0 $resultset = $global_cb->($resultset);
63             }
64              
65 5 100       20 if($search) {
66 4 100       17 my @search = ref $search eq 'ARRAY' ? @$search : ($search, @_);
67 4         19 $resultset = $resultset->search(@search);
68             }
69              
70 5         668 return $resultset;
71             }
72 10         60 },
73             is_result => sub {
74 10     15   129 my ($local_class, $name, $arg) = @_;
75 10 50       46 my $global_class = defined $arg->{isa_class} ? $arg->{isa_class} : '';
76             return sub {
77 0         0 my $rs = shift @_;
78 0   0     0 my $compare = shift @_ || $global_class || "DBIx::Class";
79 0         0 my $message = shift @_;
80 0         0 Test::More::isa_ok($rs, $compare, $message);
81             }
82 10         45 },
83             is_resultset => sub {
84 10     10   135 my ($local_class, $name, $arg) = @_;
85 10 50       39 my $global_class = defined $arg->{isa_class} ? $arg->{isa_class} : '';
86             return sub {
87 11         1702 my $rs = shift @_;
88 11   100     109 my $compare = shift @_ || $global_class || "DBIx::Class::ResultSet";
89 11         17 my $message = shift @_;
90 11         38 Test::More::isa_ok($rs, $compare, $message);
91             }
92 10         44 },
93             eq_result => sub {
94             return sub {
95 1         1811 my ($result1, $result2, $message) = @_;
96 1 50       4 $message = defined $message ? $message : ref($result1) . " equals " . ref($result2);
97 1 50       5 if( ref($result1) eq ref($result2) ) {
98 1         5 eq_or_diff2(
99             {$result2->get_columns},
100             {$result1->get_columns},
101             $message,
102             );
103             } else {
104 0         0 Test::More::fail($message ." :Result arguments not of same class");
105             }
106             },
107 10     21   190 },
108             eq_resultset => sub {
109             return sub {
110 3         1189 my ($rs1, $rs2, $message) = @_;
111 3 100       14 $message = defined $message ? $message : ref($rs1) . " equals " . ref($rs2);
112 3 50       11 if( ref($rs1) eq ref($rs2) ) {
113             ($rs1, $rs2) = map {
114 3         6 my $me = $_->current_source_alias;
  6         119  
115 6         44 my @pks = map { "$me.$_"} $_->result_source->primary_columns;
  6         42  
116 6         28 my @result = $_->search({}, {
117             result_class => 'DBIx::Class::ResultClass::HashRefInflator',
118             order_by => [@pks],
119             })->all;
120 6         10787 [@result];
121             } ($rs1, $rs2);
122              
123 3         122 eq_or_diff2([$rs2],[$rs1],$message);
124             } else {
125 0         0 Test::More::fail($message ." :ResultSet arguments not of same class");
126             }
127             },
128 10     14   173 },
129             hri_dump => sub {
130             return sub {
131 11         1664 (shift)->search ({}, {
132             result_class => 'DBIx::Class::ResultClass::HashRefInflator'
133             });
134             }
135 10     21   160 },
136             fixtures_ok => sub {
137             return sub {
138 13         8199 my ($arg, $message) = @_;
139 13 100       53 $message = defined $message ? $message : 'Fixtures Installed';
140              
141 13 100 66     280 if ($arg && ref $arg && (ref $arg eq 'CODE')) {
    100 100        
    50 66        
      66        
      66        
142 1         2 eval {
143 1         33 $arg->($schema_manager->schema);
144 1 50       7398119 }; if($@) {
145 0         0 Test::More::fail($message);
146 0         0 $schema_manager->builder->diag($@);
147              
148             } else {
149 1         51 Test::More::pass($message);
150             }
151             } elsif( $arg && ref $arg && (ref $arg eq 'HASH' || ref $arg eq 'ARRAY') ) {
152 7         14 my @return;
153 7         11 eval {
154 7         81 @return = $schema_manager->install_fixtures($arg);
155 7 50       1983 }; if($@) {
156 0         0 Test::More::fail($message);
157 0         0 $schema_manager->builder->diag($@);
158             } else {
159 7         51 Test::More::pass($message);
160 7         4428 return @return;
161             }
162             } elsif( $arg ) {
163 5 50       16 my @sets = ref $arg ? @$arg : ($arg);
164 5         49 my @fixtures = $schema_manager->get_fixture_sets(@sets);
165 5         8 my @return;
166 5         11 foreach my $fixture (@fixtures) {
167 5         10 eval {
168 5         26 push @return, $schema_manager->install_fixtures($fixture);
169 5 50       1075 }; if($@) {
170 0         0 Test::More::fail($message);
171 0         0 $schema_manager->builder->diag($@);
172             } else {
173 5         25 Test::More::pass($message);
174 5         2688 return @return;
175             }
176             }
177             } else {
178 0         0 Test::More::fail("Can't figure out what fixtures you want");
179             }
180             }
181 10     23   176 },
182             is_fields => sub {
183 10     10   128 my ($local_class, $name, $arg) = @_;
184 10         22 my @default_fields = ();
185 10 50 33     134 if(defined $arg && ref $arg eq 'HASH' && defined $arg->{fields}) {
      33        
186 0 0       0 @default_fields = ref $arg->{fields} ? @{$arg->{fields}} : ($arg->{fields});
  0         0  
187             }
188             return sub {
189 28         4922 my @args = @_;
190 28         53 my @fields = @default_fields;
191 28 100 100     202 if(!ref($args[0]) || (ref($args[0]) eq 'ARRAY')) {
192 27         41 my $fields = shift(@args);
193 27 100       98 @fields = ref $fields ? @$fields : ($fields);
194             }
195 28 100 33     578 if(Scalar::Util::blessed($args[0]) &&
    50 66        
      33        
196             $args[0]->isa('DBIx::Class') &&
197             !$args[0]->isa('DBIx::Class::ResultSet')
198             ) {
199 7         8 my $result = shift(@args);
200 7 100       13 unless(@fields) {
201 1         4 my @pks = $result->result_source->primary_columns;
202             push @fields, grep {
203 1         14 my $field = $_;
  5         15  
204 5   100     5 $field ne ((grep { $field eq $_ } @pks)[0] || '')
205             } ($result->result_source->columns);
206             }
207 7         8 my $compare = shift(@args);
208 7 100       23 if(ref $compare eq 'HASH') {
    100          
    50          
209             } elsif(ref $compare eq 'ARRAY') {
210 3         4 my @localfields = @fields;
211             $compare = {map {
212 3         7 my $value = $_;
  4         5  
213 4         3 my $key = shift(@localfields);
214 4         12 $key => $value } @$compare};
215 3 50       8 Test::More::fail('Too many fields!') if @localfields;
216             } elsif(!ref $compare) {
217 2         4 my @localfields = @fields;
218             $compare = {map {
219 2         3 my $value = $_;
  2         3  
220 2         3 my $key = shift(@localfields);
221 2         6 $key => $value } ($compare)};
222 2 50       5 Test::More::fail('Too many fields!') if @localfields;
223             }
224 7   100     24 my $message = shift(@args) || 'Fields match';
225             my $compare_rs = {map {
226 7 50       7 die "$_ is not an available field"
  12         69  
227             unless $result->can($_);
228 12         239 $_ => $result->$_ } @fields};
229 7         85 eq_or_diff2($compare,$compare_rs,$message);
230 7         2064 return $compare;
231             } elsif (Scalar::Util::blessed($args[0]) && $args[0]->isa('DBIx::Class::ResultSet')) {
232              
233 21         36 my $resultset = shift(@args);
234 21 50       65 unless(@fields) {
235 0         0 my @pks = $resultset->result_source->primary_columns;
236             push @fields, grep {
237 0         0 my $field = $_;
  0         0  
238 0   0     0 $field ne ((grep { $field eq $_ } @pks)[0] || '')
239             } ($resultset->result_source->columns);
240             }
241 21         26 my @compare = @{shift(@args)};
  21         50  
242 21         41 foreach (@compare) {
243 58 100       155 if(!ref $_) {
    100          
244 7         9 my @localfields = @fields;
245             $_ = {map {
246 7         11 my $value = $_;
  7         8  
247 7         5 my $key = shift(@localfields);
248 7         19 $key => $value } ($_)};
249 7 50       17 Test::More::fail('Too many fields!') if @localfields;
250             } elsif(ref $_ eq 'ARRAY') {
251 48         74 my @localfields = @fields;
252             $_ = {map {
253 48         67 my $value = $_;
  98         90  
254 98         68 my $key = shift(@localfields);
255 98         188 $key => $value } (@$_)};
256 48 50       118 Test::More::fail('Too many fields!') if @localfields;
257             }
258             }
259 21   50     64 my $message = shift(@args) || 'Fields match';
260              
261 21         130 my @resultset = $resultset->search({}, {
262             result_class => 'DBIx::Class::ResultClass::HashRefInflator',
263             columns => [@fields],
264             })->all;
265 21         54112 my %compare_rs;
266 21         730 foreach my $row(@resultset) {
267 17     17   91 no warnings 'uninitialized';
  17         28  
  17         1705  
268 58         141 my $id = Digest::MD5::md5_hex(join('.', map {$row->{$_}} sort keys %$row));
  111         318  
269 58         101 $compare_rs{$id} = { map { $_,"$row->{$_}"} keys %$row};
  111         288  
270             }
271 21         30 my %compare;
272 21         34 foreach my $row(@compare) {
273 17     17   73 no warnings 'uninitialized';
  17         29  
  17         34780  
274 58         119 my $id = Digest::MD5::md5_hex(join('.', map {$row->{$_}} sort keys %$row));
  111         221  
275             ## Force comparison stuff in stringy form :(
276 58         94 $compare{$id} = { map { $_,"$row->{$_}"} keys %$row};
  111         241  
277             }
278 21         67 eq_or_diff2(\%compare,\%compare_rs,$message);
279 21         9217 return \@compare;
280             } else {
281 0         0 die "I'm not sure what to do with your arguments";
282             }
283 10         109 };
284             },
285             reset_schema => sub {
286             return sub {
287 4   50     16789 my $message = shift @_ || 'Schema reset complete';
288 4         62 $schema_manager->reset;
289 4         24 Test::More::pass($message);
290             }
291 10     38   148 },
292             cleanup_schema => sub {
293             return sub {
294 1   50     448 my $message = shift @_ || 'Schema cleanup complete';
295 1         7 $schema_manager->cleanup;
296 1         8 Test::More::pass($message);
297             }
298 10     15   180 },
299             map {
300 10         869 my $source = $_;
  120         515  
301             $source => sub {
302 18     18   341 my ($local_class, $name, $arg) = @_;
303 18         628 my $resultset = $schema_manager->schema->resultset($source);
304 18 100       8279 if(my $search = $arg->{search}) {
305 2 50       10 my @search = ref $search eq 'ARRAY' ? @$search : ($search);
306 2         13 $resultset = $resultset->search(@search);
307             }
308             return sub {
309 54         19030 my $search = shift @_;
310 54 100       170 if($search) {
311 4         8 my @search = ();
312 4 100 66     23 if(ref $search && ref $search eq 'HASH') {
313 2         6 @search = ($search, @_);
314             } else {
315 2         5 @search = ({$search, @_});
316             }
317 4         13 return $resultset->search(@search);
318             }
319 50         304 return $resultset->search_rs;
320             }
321 120         778 };
  18         758  
322             } $schema_manager->schema->sources,
323             ],
324             groups => {
325             resultsets => [$schema_manager->schema->sources],
326             },
327             into_level => 1,
328             });
329              
330 10         5138 $class->$exporter(
331             qw/Schema ResultSet is_result is_resultset hri_dump fixtures_ok reset_schema
332             eq_result eq_resultset is_fields dump_settings cleanup_schema /,
333             @exports
334             );
335             }
336              
337             sub _initialize {
338 10     64   18 my ($class, @opts) = @_;
339 10         27 my ($config, @exports) = $class->_normalize_opts(@opts);
340 10         23 my $merged_config = $class->_prepare_config($config);
341              
342 10 100       265 if(my $resultsets = delete $merged_config->{resultsets}) {
343 1 50       5 if(ref $resultsets eq 'ARRAY') {
344 1         3 push @exports, @$resultsets;
345             } else {
346 0         0 die '"resultsets" options must be a Array Reference.';
347             }
348             }
349 10         103 my $merged_with_fixtures_config = $class->_prepare_fixtures($merged_config);
350 10         443 my $visitor = Data::Visitor::Callback->new(plain_value=>\&_visit_config_values);
351 10         3243 $visitor->visit($merged_with_fixtures_config);
352              
353 10         1810 my $schema_manager = $class->_initialize_schema($merged_with_fixtures_config);
354              
355             return (
356 10         432 $schema_manager,
357             $merged_config,
358             @exports,
359             );
360             }
361              
362             sub _visit_config_values {
363 272 100   272   90782 return unless $_;
364              
365 266         347 &_config_substitutions($_);
366            
367             }
368              
369             sub _config_substitutions {
370 266     266   253 my $subs = {};
371             $subs->{ ENV } =
372             sub {
373 1     1   1 my ( $v ) = @_;
374 1 50       3 if (! defined($ENV{$v})) {
375 0         0 Test::More::fail("Missing environment variable: $v");
376 0         0 return '';
377             } else {
378 1         8 return $ENV{ $v };
379             }
380 266         934 };
381 266   50 0   1010 $subs->{ literal } ||= sub { return $_[ 1 ]; };
  0         0  
382 266         630 my $subsre = join( '|', keys %$subs );
383              
384 266         346 for ( @_ ) {
385 266 50       4367 s{__($subsre)(?:\((.+?)\))?__}{ $subs->{ $1 }->( $2 ? split( /,/, $2 ) : () ) }eg;
  1         7  
386             }
387             }
388              
389             sub _normalize_opts {
390 13     13   401 my ($class, @opts) = @_;
391 13         20 my ($config, @exports) = ({},());
392              
393 13 100       48 if(ref $opts[0]) {
394 7 50       19 if(ref $opts[0] eq 'HASH') {
395 7         12 $config = shift(@opts);
396             } else {
397 0         0 die 'First argument to "use Test::DBIx::Class @args" not properly formed.';
398             }
399             }
400              
401 13         38 while( my $opt = shift(@opts)) {
402 14 100       40 if($opt =~m/^-(.+)/) {
403 3 50       8 if($config->{$1}) {
404 0         0 die "$1 already is defined as $config->{$1}";
405             } else {
406 3         9 $config->{$1} = shift(@opts);
407             }
408             } else {
409 11         20 @exports = ($opt, @opts);
410 11         16 last;
411             }
412             }
413              
414 13 100       49 if(my $resultsets = delete $config->{resultsets}) {
415 1 50       3 if(ref $resultsets eq 'ARRAY') {
416 1         2 push @exports, @$resultsets;
417             } else {
418 0         0 die '"resultsets" options must be a Array Reference.';
419             }
420             }
421              
422 13 50 66     20 @exports = map { ref $_ && ref $_ eq 'ARRAY' ? @$_:$_ } @exports;
  28         90  
423              
424 13         55 return ($config, @exports);
425             }
426              
427             sub _prepare_fixtures {
428 11     11   750 my ($class, $config) = @_;
429              
430 11         17 my @dirs;
431 11 100       58 if(my $fixture_path = delete $config->{fixture_path}) {
432 2         7 @dirs = $class->_normalize_config_path(
433             $class->_default_fixture_paths, $fixture_path,
434             );
435             } else {
436 9         45 @dirs = $class->_normalize_config_path($class->_default_fixture_paths);
437             }
438              
439 11         58 my @extensions = $class->_allowed_extensions;
440             my @files = (
441 16         3978 grep { $class->_is_allowed_extension($_) }
442 13         1055 map {Path::Class::dir($_)->children}
443 11         34390 grep { -e $_ }
  23         594  
444             @dirs
445             );
446              
447 11         128 my $fixture_definitions = Config::Any->load_files({
448             files => \@files,
449             use_ext => 1,
450             });
451              
452 11         87135 my %merged_fixtures;
453 11         44 foreach my $fixture_definition(@$fixture_definitions) {
454 16         63 my ($path, $fixture) = %$fixture_definition;
455             ## hack to normalize arrayref fixtures. needs work!!!
456 16 100       79 $fixture = ref $fixture eq 'HASH' ? [$fixture] : $fixture;
457 16         106 my $file = Path::Class::file($path)->basename;
458 16         1611 $file =~s/\..{1,4}$//;
459 16 100       63 if($merged_fixtures{$file}) {
460 2         3 my $old_fixture = $merged_fixtures{$file};
461 2         14 my $merged_fixture = Hash::Merge::merge($fixture, $old_fixture);
462 2         3081 $merged_fixtures{$file} = $merged_fixture;
463             } else {
464 14         59 $merged_fixtures{$file} = $fixture;
465             }
466             }
467              
468 11 100       59 if(my $old_fixture_sets = delete $config->{fixture_sets}) {
469             ## hack to normalize arrayref fixtures. needs work!!!
470             my %normalized_old_fixture_sets = map {
471 2 50       8 ref($old_fixture_sets->{$_}) eq 'HASH' ? ($_, [$old_fixture_sets->{$_}]): ($_, $old_fixture_sets->{$_});
  2         16  
472             } keys %$old_fixture_sets;
473 2         12 my $new_fixture_sets = Hash::Merge::merge(\%normalized_old_fixture_sets, \%merged_fixtures );
474 2         215 $config->{fixture_sets} = $new_fixture_sets;
475             } else {
476 9         39 $config->{fixture_sets} = \%merged_fixtures;
477             }
478              
479 11         259 return $config;
480             }
481              
482             sub _is_allowed_extension {
483 16     16   28 my ($class, $file) = @_;
484 16         41 my @extensions = $class->_allowed_extensions;
485 16         37722 foreach my $extension(@extensions) {
486 96 100       2134 if($file =~ m/\.$extension$/) {
487 16         331 return $file;
488             }
489             }
490 0         0 return;
491             }
492              
493             sub _prepare_config {
494 12     12   1198 my ($class, $config) = @_;
495              
496 12 100       32 if(my $extra_config = delete $config->{config_path}) {
497 3         15 my @config_data = $class->_load_via_config_any($extra_config);
498 3         11 foreach my $config_datum(reverse @config_data) {
499 8         3312 $config = Hash::Merge::merge($config, $config_datum);
500             }
501             } else {
502 9         22 my @config_data = $class->_load_via_config_any();
503 9         36 foreach my $config_datum(reverse @config_data) {
504 9         81 $config = Hash::Merge::merge($config, $config_datum);
505             }
506             }
507              
508 12 100       26754 if(my $post_config = delete $config->{config_path}) {
509 2         21 my @post_config_paths = $class->_normalize_external_paths($post_config);
510 2         10 my @extensions = $class->_allowed_extensions;
511 30         284 my @post_config_files = grep { -e $_} map {
512 2         259 my $path = $_;
513             map {
514 2         3 $ENV{TEST_DBIC_CONFIG_SUFFIX} ?
515 20 100       528 ("$path.$_", "$path$ENV{TEST_DBIC_CONFIG_SUFFIX}.$_") :
516             ("$path.$_");
517             } @extensions;
518             } map {
519 2 50       6038 my @local_path = ref $_ ? @$_ : ($_);
  2         15  
520 2         15 Path::Class::file(@local_path);
521             } @post_config_paths;
522              
523 2         18 my $post_config = $class->_config_any_load_files(@post_config_files);
524 2         11473 foreach my $config_datum(reverse map { values %$_ } @$post_config) {
  2         10  
525 2         13 $config = Hash::Merge::merge($config, $config_datum);
526             }
527             }
528              
529 12         476 return $config;
530             }
531              
532             sub _load_via_config_any {
533 13     13   822 my ($class, $extra_paths) = @_;
534 13         33 my @files = $class->_valid_config_files($class->_default_paths, $extra_paths);
535 13         72 my $config = $class->_config_any_load_files(@files);
536              
537 13         94409 my @config_data = map { values %$_ } @$config;
  20         95  
538 13         94 return @config_data;
539             }
540              
541             sub _config_any_load_files {
542 15     15   41 my ($class, @files) = @_;
543              
544 15         115 return Config::Any->load_files({
545             files => \@files,
546             use_ext => 1,
547             });
548             }
549              
550             sub _valid_config_files {
551 15     15   2376 my ($class, $default_paths, $extra_paths) = @_;
552 15         33 my @extensions = $class->_allowed_extensions;
553 15         91880 my @paths = $class->_normalize_config_path($default_paths, $extra_paths);
554 410         2657 my @config_files = grep { -e $_} map {
555 15         27 my $path = $_;
  35         377  
556             map {
557 35         40 $ENV{TEST_DBIC_CONFIG_SUFFIX} ?
558 350 100       6089 ("$path.$_", "$path$ENV{TEST_DBIC_CONFIG_SUFFIX}.$_") :
559             ("$path.$_");
560             } @extensions;
561             } @paths;
562              
563 15         101 return @config_files;
564             }
565              
566             sub _allowed_extensions {
567 44     44   83 return @{ Config::Any->extensions };
  44         226  
568             }
569              
570             sub _normalize_external_paths {
571 11     11   14 my ($class, $extra_paths) = @_;
572 11         11 my @extra_paths;
573 11 50       55 if(!ref $extra_paths) {
    50          
574 0         0 @extra_paths = ([$extra_paths]); ## "t/etc" => (["t/etc"])
575             } elsif(ref $extra_paths eq 'ARRAY') {
576 11 100       40 if(!ref $extra_paths->[0]) {
    50          
577 4         10 @extra_paths = ($extra_paths); ## [qw( t etc )]
578             } elsif( ref $extra_paths->[0] eq 'ARRAY') {
579 7         14 @extra_paths = @$extra_paths;
580             }
581             }
582 11         23 return @extra_paths;
583             }
584              
585             sub _normalize_config_path {
586 27     27   1295 my ($class, $default_paths, $extra_paths) = @_;
587              
588 27 100       63 if(defined $extra_paths) {
589 23 100       775 my @extra_paths = map { "$_" eq "+" ? @$default_paths : $_ } map {
590 9 100       28 my @local_path = ref $_ ? @$_ : ($_);
  23         650  
591 23         55 Path::Class::file(@local_path);
592             } $class->_normalize_external_paths($extra_paths);
593              
594 9         248 return @extra_paths;
595             } else {
596 18         48 return @$default_paths;
597             }
598             }
599              
600             sub _script_path {
601 25     25   300 return ($0 =~m/^(.+)\.t$/)[0];
602             }
603              
604             sub _default_fixture_paths {
605 11     11   75 my ($class) = @_;
606 11         41 my $script_path = Path::Class::file($class->_script_path);
607 11         1511 my $script_dir = $script_path->dir;
608 11         95 my @dir_parts = $script_dir->dir_list(1);
609              
610             return [
611 11         139 Path::Class::file(qw/t etc fixtures/),
612             Path::Class::file(qw/t etc fixtures/, @dir_parts, $script_path->basename),
613             ];
614              
615             }
616              
617             sub _default_paths {
618 14     14   710 my ($class) = @_;
619 14         34 my $script_path = Path::Class::file($class->_script_path);
620 14         2373 my $script_dir = $script_path->dir;
621 14         101 my @dir_parts = $script_dir->dir_list(1);
622              
623 14 50 33     178 if(
624             $script_path->basename eq 'schema' &&
625             (scalar(@dir_parts) == 0 )
626             ) {
627             return [
628 0         0 Path::Class::file(qw/t etc schema/),
629             ];
630              
631             } else {
632             return [
633 14         98 Path::Class::file(qw/t etc schema/),
634             Path::Class::file(qw/t etc /, @dir_parts, $script_path->basename),
635             ];
636             }
637             }
638              
639             sub _initialize_schema {
640 20     20   10375 my $class = shift @_;
641 20         39 my $config = shift @_;
642 20         237 my $builder = __PACKAGE__->builder;
643            
644 20         246 my $fail_on_schema_break = delete $config->{fail_on_schema_break};
645 20         27 my $schema_manager;
646 20         33 eval {
647 20         237 $schema_manager = Test::DBIx::Class::SchemaManager->initialize_schema({
648             %$config,
649             builder => $builder,
650             });
651 20 50 33     282 }; if ($@ or !$schema_manager) {
652 0         0 Test::More::diag("Can't initialize a schema with the given configuration");
653 0 0       0 Test::More::diag("Returned Error: ".$@) if $@;
654 0         0 Test::More::diag(
655             Test::More::explain("configuration: " => $config)
656             );
657             # FIXME: make this optional.
658 0 0       0 if($fail_on_schema_break)
659             {
660 0         0 Test::More::fail("Failed remaining tests since we don't have a schema");
661 0         0 Test::More::done_testing();
662 0         0 $builder->finalize();
663 0         0 exit(0);
664             }
665             else
666             {
667 0         0 $builder->skip_all("Skipping remaining tests since we don't have a schema");
668             }
669             }
670              
671 20         111 return $schema_manager
672             }
673              
674             1;
675              
676             __END__
677              
678             =head1 NAME
679              
680             Test::DBIx::Class - Easier test cases for your DBIx::Class applications
681              
682             =head1 SYNOPSIS
683              
684             The following is example usage for this module. Assume you create a standard
685             Perl testing script, such as "MyApp/t/schema/01-basic.t" which is run from the
686             shell like "prove -l t/schema/01-basic.t" or during "make test". That test
687             script could contain:
688              
689             use Test::More;
690              
691             use strict;
692             use warnings;
693              
694             use Test::DBIx::Class {
695             schema_class => 'MyApp::Schema',
696             connect_info => ['dbi:SQLite:dbname=:memory:','',''],
697             connect_opts => { name_sep => '.', quote_char => '`', },
698             fixture_class => '::Populate',
699             }, 'Person', 'Person::Employee' => {-as => 'Employee'}, 'Job', 'Phone';
700              
701             ## Your testing code below ##
702              
703             ## Your testing code above ##
704              
705             done_testing;
706              
707             Yes, it looks like a lot of boilerplate, but sensible defaults are in place
708             (the above code example shows most of the existing defaults) and configuration
709             data L<can be loaded from a central file|/"CONFIGURATION BY FILE">. So,
710             assuming you put all of your test configuration in the standard place, your
711             'real life' example is going to look closer to:
712              
713             use Test::More;
714            
715             use strict;
716             use warnings;
717             use Test::DBIx::Class qw(:resultsets);
718              
719             ## Your testing code below ##
720             ## Your testing code above ##
721              
722             done_testing;
723              
724             Then, assuming the existence of a L<DBIx::Class::Schema> subclass called,
725             "MyApp::Schema" and some L<DBIx::Class::ResultSource>s named like "Person",
726             "Person::Employee", "Job" and "Phone", will automatically deploy a testing
727             schema in the given database / storage (or auto deploy to an in-memory based
728             L<DBD::SQLite> database), install fixtures and let you run some test cases,
729             such as:
730              
731             ## Your testing code below ##
732              
733             fixtures_ok 'basic'
734             => 'installed the basic fixtures from configuration files';
735              
736             fixtures_ok [
737             Job => [
738             [qw/name description/],
739             [Programmer => 'She who writes the code'],
740             ['Movie Star' => 'Knows nothing about the code'],
741             ],
742             ], 'Installed some custom fixtures via the Populate fixture class',
743              
744            
745             ok my $john = Person->find({email=>'jjnapiork@cpan.org'})
746             => 'John has entered the building!';
747              
748             is_fields $john, {
749             name => 'John Napiorkowski',
750             email => 'jjnapiork@cpan.org',
751             age => 40,
752             }, 'John has the expected fields';
753              
754             is_fields ['job_title'], $john->jobs, [
755             {job_title => 'programmer'},
756             {job_title => 'administrator'},
757             ],
758             is_fields 'job_title', $john->jobs,
759             [qw/programmer administrator/],
760             'Same test as above, just different compare format;
761              
762              
763             is_fields [qw/job_title salary/], $john->jobs, [
764             ['programmer', 100000],
765             ['administrator, 120000],
766             ], 'Got expected fields from $john->jobs';
767              
768             is_fields [qw/name age/], $john, ['John Napiorkowski', 40],
769             => 'John has expected name and age';
770              
771             is_fields_multi 'name', [
772             $john, ['John Napiorkowski'],
773             $vanessa, ['Vanessa Li'],
774             $vincent, ['Vincent Zhou'],
775             ] => 'All names as expected';
776              
777             is_fields 'fullname',
778             ResultSet('Country')->find('USA'),
779             'United States of America',
780             'Found the USA';
781              
782             is_deeply [sort Schema->sources], [qw/
783             Person Person::Employee Job Country Phone
784             /], 'Found all expected sources in the schema';
785              
786             fixtures_ok my $first_album = sub {
787             my $schema = shift @_;
788             my $cd_rs = $schema->resultset('CD');
789             return $cd_rs->create({
790             name => 'My First Album',
791             track_rs => [
792             {position=>1, title=>'the first song'},
793             {position=>2, title=>'yet another song'},
794             ],
795             cd_artist_rs=> [
796             {person_artist=>{person => $vanessa}},
797             {person_artist=>{person => $john}},
798             ],
799             });
800             }, 'You can even use a code reference for custom fixtures';
801              
802             ## Your testing code above ##
803              
804             Please see the test cases for more examples.
805              
806             =head1 DESCRIPTION
807              
808             The goal of this distribution is to make it easier to write test cases for your
809             L<DBIx::Class> based applications. It does this in three ways. First, it trys
810             to make it easy to deploy your Schema. This can be to your dedicated testing
811             database, or a simple SQLite database. This allows you to run tests without
812             interfering with your development work and having to stop and set up a testing
813             database instance.
814              
815             Second, we allow you to load test fixtures via several different tools. Last
816             we create some helper functions in your test script so that you can reduce
817             repeated or boilerplate code.
818              
819             Overall, we attempt to reduce the amount of code you have to write before you
820             can begin writing tests.
821              
822             =head1 IMPORTED METHODS
823              
824             The following methods are automatically imported when you use this module.
825              
826             =head2 Schema
827              
828             You probably won't need this directly in your tests unless you have some
829             application logic methods in it.
830              
831              
832             =head2 ResultSet ($source, ?{%search}, ?{%conditions})
833              
834             Although you can import your sources as local keywords, sometimes you might
835             need to get a particular resultset when you don't wish to import it globally.
836             Use like
837              
838             ok ResultSet('Job'), "Yeah, some jobs in the database";
839             ok ResultSet( Job => {hourly_pay=>{'>'=>100}}), "Good paying jobs available!";
840              
841             Since this returns a normal L<DBIx::Class::ResultSet>, you can just call the
842             normal methods against it.
843              
844             ok ResultSet('Job')->search({hourly_pay=>{'>'=>100}}), "Good paying jobs available!";
845              
846             This is the same as the test above.
847              
848             ResultSet can also be called with a C<< $source, [\%search,
849             \%condition] >> signature.
850              
851             =head2 fixtures_ok
852              
853             This is used to install and verify installation of fixtures, either inlined,
854             from a fixture set in a file, or through a custom sub reference. Accept three
855             argument styles:
856              
857             =over 4
858              
859             =item coderef
860              
861             Given a code reference, execute it against the currently defined schema. This
862             is used when you need a lot of control over installing your fixtures. Example:
863              
864             fixtures_ok sub {
865             my $schema = shift @_;
866             my $cd_rs = $schema->resultset('CD');
867             return $cd_rs->create({
868             name => 'My First Album',
869             track_rs => [
870             {position=>1, title=>'the first song'},
871             {position=>2, title=>'yet another song'},
872             ],
873             cd_artist_rs=> [
874             {person_artist=>{person => $vanessa}},
875             {person_artist=>{person => $john}},
876             ],
877             });
878              
879             }, 'Installed fixtures';
880              
881             The above gets executed at runtime and if there is an error it is trapped,
882             reported and we move on to the next test.
883              
884             =item arrayref
885              
886             Given an array reference, attempt to process it via the default fixtures loader
887             or through the specified loader.
888              
889             fixtures_ok [
890             Person => [
891             ['name', 'age', 'email'],
892             ['John', 40, 'john@nowehere.com'],
893             ['Vincent', 15, 'vincent@home.com'],
894             ['Vanessa', 35, 'vanessa@school.com'],
895             ],
896             ], 'Installed fixtures';
897              
898             This is a good option to use while you are building up your fixture sets or
899             when your sets are going to be small and not reused across lots of tests. This
900             will get you rolling without messing around with configuration files.
901              
902             =item fixture set name
903              
904             Given a fixture name, or array reference of names, install the fixtures.
905              
906             fixtures_ok 'core';
907             fixtures_ok [qw/core extra/];
908              
909             Fixtures are installed in the order specified.
910              
911             =back
912              
913             All different types can be mixed and matched in a given test file.
914              
915             =head2 is_result ($result, ?$result)
916              
917             Quick test to make sure $result does inherit from L<DBIx::Class> or that it
918             inherits from a subclass of L<DBIx::Class>.
919              
920             =head2 is_resultset ($resultset, ?$resultset)
921              
922             Quick test to make sure $resultset does inherit from L<DBIx::Class::ResultSet>
923             or from a subclass of L<DBIx::Class::ResultSet>.
924              
925             =head2 eq_resultset ($resultset, $resultset, ?$message)
926              
927             Given two ResultSets, determine if the are equal based on class type and data.
928             This is a true set equality that ignores sorting order of items inside the
929             set.
930              
931             =head2 eq_result ($resultset, $resultset, ?$message)
932              
933             Given two row objects, make sure they are the same.
934              
935             =head2 hri_dump ($resultset)
936              
937             Not a test, just returns a version of the ResultSet that has its inflator set
938             to L<DBIx::Class::ResultClass::HashRefInflator>, which returns a set of hashes
939             and makes it easier to stop issues. This return value is suitable for dumping
940             via L<Data::Dump>, for example.
941              
942             =head2 reset_schema
943              
944             Wipes and reloads the schema.
945              
946             =head2 cleanup_schema
947              
948             Wipes schema and disconnects.
949              
950             =head2 dump_settings
951              
952             Returns the configuration and related settings used to initialize this testing
953             module. This is mostly to help you debug trouble with configuration and to help
954             the authors find and fix bugs. At some point this won't be exported by default
955             so don't use it for your real tests, just to help you understand what is going
956             on. You've been warned!
957              
958             =head2 is_fields
959              
960             A 'Swiss Army Knife' method to check your results or resultsets. Tests the
961             values of a Result or ResultSet against expected via a pattern. A pattern
962             is automatically created by instrospecting the fields of your ResultSet or
963             Result.
964              
965             Example usage for testing a result follows.
966              
967             ok my $john = Person->find('john');
968              
969             is_fields 'name', $john, ['John Napiorkowski'],
970             'Found name of $john';
971              
972             is_fields [qw/name age/], $john, ['John Napiorkowski', 40],
973             'Found $johns name and age';
974              
975             is_fields $john, {
976             name => 'John Napiorkowski',
977             age => 40,
978             email => 'john@home.com'}; # Assuming $john has only the three columns listed
979              
980             In the case where we need to infer the match pattern, we get the columns of the
981             given result but remove the primary key. Please note the following would also
982             work:
983              
984             is_fields [qw/name age/] $john, {
985             name => 'John Napiorkowski',
986             age => 40}, 'Still got the name and age correct';
987              
988             You should choose the method that makes most sense in your tests.
989              
990             Example usage for testing a resultset follows.
991              
992             is_fields 'name', Person, [
993             'John',
994             'Vanessa',
995             'Vincent',
996             ];
997              
998             is_fields ['name'], Person, [
999             'John',
1000             'Vanessa',
1001             'Vincent',
1002             ];
1003              
1004             is_fields ['name','age'], Person, [
1005             ['John',40],
1006             ['Vincent',15],
1007             ['Vanessa',35],
1008             ];
1009              
1010             is_fields ['name','age'], Person, [
1011             {name=>'John', age=>40},
1012             {name=>'Vanessa',age=>35},
1013             {name=>'Vincent', age=>15},
1014             ];
1015              
1016             I find the array version is most consise. Please note that the match is not
1017             ordered. If you need to test that a given Resultset is in a particular order,
1018             you will currently need to write a custom test. If you have a big need for
1019             this I'd be willing to write a test for it, or gladly accept a patch to add it.
1020              
1021             You should examine the test cases for more examples.
1022              
1023             =head2 is_fields_multi
1024              
1025             TBD: Not yet written.
1026              
1027             =head1 SETUP AND INITIALIZATION
1028              
1029             The generic usage for this would look like one of the following:
1030              
1031             use Test::DBIx::Class \%options, @sources
1032             use Test::DBIx::Class %options, @sources
1033              
1034             Where %options are key value pairs and @sources an array as specified below.
1035              
1036             =head2 Initialization Options
1037              
1038             The only difference between the hash and hash reference version of %options
1039             is that the hash version requires its keys to be prepended with "-". If
1040             you are inlining a lot of configuration the hash reference version may look
1041             neater, while if you are only setting one or two options the hash version
1042             might be more readable. For example, the following are the same:
1043              
1044             use Test::DBIx::Class -config_path=>[qw(t etc config)], 'Person', 'Job';
1045             use Test::DBIx::Class {config_path=>[qw(t etc config)]}, 'Person', 'Job';
1046              
1047             The following options are currently standard and always available. Depending
1048             on your storage engine (such as SQLite or MySQL) you will have other options.
1049              
1050             =over 4
1051              
1052             =item config_path
1053              
1054             These are the relative paths searched for configuration file information. See
1055             L</Initialization Sources> for more.
1056              
1057             In the case were we have both inlined and file based configurations, the
1058             inlined is merged last (that is, has highest authority to override configuration
1059             files).
1060              
1061             When the final merging of all configurations (both anything inlined at 'use'
1062             time, and anything found in any of the specified config_paths, we do a single
1063             'post' config_path check. This allows you to add in a configuration file from
1064             inside a configuration file. For safety and sanity you can only do this once.
1065             This feature makes it easier to globalize any additional configuration files.
1066             For example, I often store user specific settings in "~/etc/conf.*". This
1067             feature allows me to add that into my standard "t/etc/schema.*" so it's
1068             available to all my test cases.
1069              
1070             =item schema_class
1071              
1072             Required. This must be your subclass of L<DBIx::Class::Schema> that defines
1073             your database schema.
1074              
1075             =item connect_info
1076              
1077             Required. This will accept anything you can send to L<DBIx::Class/connect>.
1078             Defaults to: ['dbi:SQLite:dbname=:memory:','',''] if left blank (but see
1079             'traits' below for more)
1080              
1081             =item connect_opts
1082              
1083             Use this to customise connect_info if you have left that blank in order to
1084             have the dsn auto-generated, but require extra attributes such as name_sep
1085             and quote_char.
1086              
1087             =item deploy_opts
1088              
1089             Use this to customise any arguments that are to be passed to
1090             L<DBIx::Class::Schema/deploy>, such as add_drop_table or quote_identifiers.
1091              
1092             =item default_resultset_attributes
1093              
1094             Allows you to specify default_resultset_attributes to be set on the schema.
1095             These will be used when creating all new resultsets.
1096              
1097             This is typically done to enable caching or turn on the software_limit flag.
1098              
1099             =item fixture_path
1100              
1101             These are a list of relative paths search for fixtures. Each item should be
1102             a directory that contains files loadable by L<Config::Any> and suitable to
1103             be installed via one of the fixture classes.
1104              
1105             =item fixture_class
1106              
1107             Command class that installs data into the database. Must provide a method
1108             called 'install_fixtures' that accepts a perl data structure and installs
1109             it into the database. Must capture and report errors. Default value is
1110             "::Populate", which loads L<Test::DBIx::Class::FixtureCommand::Populate>, which
1111             is a command class based on L<DBIx::Class::Schema/populate>.
1112              
1113             =item resultsets
1114              
1115             Lets you add in some result source definitions to be imported at test script
1116             runtime. See L</Initialization Sources> for more.
1117              
1118             =item force_drop_table
1119              
1120             When deploying the database this option allows you add a 'drop table' statement
1121             before the create ddl. Since this will return an error if you attempt to drop
1122             a table that doesn't exist, this is off by default for SQLite storage engines.
1123             You may need to enble it you you are using the following 'keep_db' option.
1124              
1125             =item keep_db
1126              
1127             By default your testing database is 'cleaned up' after you are finished. This
1128             drops all the created tables (but currently doesn't delete any related files
1129             or database users, if any). If you want to keep your testing database after
1130             all the tests are run, you can set this to true. If so, you may also need to
1131             set the previously mentioned option 'force_drop_table' to true as well, or we
1132             will attempt to create tables and populate them when they are already populated
1133             and created.
1134              
1135             =item deploy_db
1136              
1137             By default a fresh version of the schema is deployed when 'Test::DBIx::Class'
1138             is invoked. If you want to skip the schema deployment and instead connect
1139             to an already existing and populated database, set this option to false.
1140              
1141             =item traits
1142              
1143             Traits are L<Moose::Role>s that are applied to the class managing the connection
1144             to your database. If you leave this option blank and you don't specify anything
1145             for 'connect_info' (above), we automatically load the SQLite trait (which can
1146             be reviewed at L<Test::DBIx::Class::SchemaManager::Trait::SQLite>). This trait
1147             installs the ability to automatically discover and deploy to an in memory or a
1148             filesystem SQLite database. If you are just getting started with testing, this
1149             is probably your easiest option.
1150              
1151             Currently there are only three traits, the SQLite trait just described (and since
1152             it get's automatically loaded you never need to load it yourself). The
1153             L<Test::DBIx::Class::SchemaManager::Trait::Testmysqld> trait, which is built on
1154             top of L<Test::mysqld> and allows you the ability to deploy to and run tests
1155             against a temporary instance of MySQL. For this trait MySQL and L<DBD::mysql>
1156             needs to be installed, but MySQL does not need to be running, nor do you need
1157             to create a test database or user. The third one is the
1158             L<Test::DBIx::Class::SchemaManager::Trait::Testpostgresql> trait, which is
1159             built on top of L<Test::Postgresql58> and allows you to deploy to and run tests
1160             against a temporary instance of Postgresql. For this trait Postgresql
1161             and L<DBD::Pg> needs to be installed, but Postgresql does not need to be
1162             running, nor do you need to create a test database or user.
1163             See L</TRAITS> for more.
1164              
1165             =item fail_on_schema_break
1166              
1167             Makes the test run fail when the schema can not be created. Normally the
1168             test run is skipped when the schema fails to create. A failure can be more
1169             convenient when you want to spot compilation failures.
1170              
1171             =back
1172              
1173             Please note that although all initialization options can be set inlined or in
1174             a configuration file, some options can also be set via %ENV variables. %ENV
1175             settings will only apply IF there are no existing values for the option in any
1176             configuration file. As of this time we don't merge %ENV settings, they only
1177             provider overrides to the default settings. Example use (assumes you are
1178             using the default SQLite database)
1179              
1180             DBNAME=test.db KEEP_DB=1 prove -lv t/schema/check-person.t
1181              
1182             After running the test there will be a new file called 'test.db' in the home
1183             directory of your distribution. You can use:
1184              
1185             sqlite3 test.db
1186              
1187             to open and view the tables and their data as loaded by any fixtures or create
1188             statements. See L<Test::DBIx::Class::SchemaManager::Trait::SQLite> for more.
1189             Note that you can specify both 'dbpath' and 'keep_db' in your configuration
1190             files if you prefer. I tried to expose a subset of configuration to %ENV that
1191             I thought the most useful. Patches and suggestions welcomed.
1192              
1193             =head2 Initialization Sources
1194              
1195             The @sources are a list of result sources that you want helper methods injected
1196             into your test script namespace. This is the 'Source' part of:
1197              
1198             $schema->resultset('Source');
1199              
1200             Injecting methods are optional since you can also use the 'ResultSet' keyword
1201              
1202             Imported Source keywords use L<Sub::Exporter> so you have quite a few options
1203             for controling how the keywords are imported. For example:
1204              
1205             use Test::DBIx::Class
1206             'Person',
1207             'Person::Employee' => {-as => 'Employee'},
1208             'Person' => {search => {age=>{'>'=>55}}, -as => 'OlderPerson'};
1209              
1210             This would import three local keywork methods, "Person", "Employee" and
1211             "OlderPerson". For "OlderPerson", the search parameter would automatically be
1212             resolved via $resultset->search and the correct resultset returned. You may
1213             wish to preconfigure all your test result set cases in one go at the top of
1214             your test script as a way to promote reusability.
1215              
1216             In addition to the 'search' parameter, there is also an 'exec' parameter
1217             which let's you process your resultset programatically. For example:
1218              
1219             'Person' => {exec => sub { shift->older_than(55) }, -as => 'OlderPerson'};
1220              
1221             This code reference gets passed the resultset object. So you can use any
1222             method on $resultset. For example:
1223              
1224             'Person' => {exec => sub { shift->find('john') }, -as => 'John'};
1225              
1226             is_result John;
1227             is John->name, 'John Napiorkowski', "Got Correct Name";
1228              
1229             Although since fixtures will not yet be installed, the above is probably not
1230             going to be a normally working example :)
1231              
1232             Additionally, since you can also initialize sources via the 'resultsets'
1233             configuration option, which can be placed into your global configuration files
1234             this means you can predefine and result resultsets across all your tests. Here
1235             is an example 't/etc/schema.pl' file where I initialize pretty much everything
1236             in one file:
1237              
1238             {
1239             'schema_class' => 'Test::DBIx::Class::Example::Schema',
1240             'resultsets' => [
1241             'Person',
1242             'Job',
1243             'Person' => { '-as' => 'NotTeenager', search => {age=>{'>'=>18}}},
1244             ],
1245             'fixture_sets' => {
1246             'basic' => [
1247             'Person' => [
1248             [
1249             'name',
1250             'age',
1251             'email'
1252             ],
1253             [
1254             'John',
1255             '40',
1256             'john@nowehere.com'
1257             ],
1258             [
1259             'Vincent',
1260             '15',
1261             'vincent@home.com'
1262             ],
1263             [
1264             'Vanessa',
1265             '35',
1266             'vanessa@school.com'
1267             ]
1268             ]
1269             ]
1270             },
1271             };
1272              
1273             In this case you can simple do "use Test::DBIx::Class" and everything will
1274             happen automatically.
1275              
1276             In the example 't/etc/schema.pl' file, instead of (or as well as) fixture_sets
1277             you could instead define fixture_path to allow resultset data outside of the
1278             main 't/etc/schema.pl' file.
1279              
1280             'fixture_path' => [qw{t etc fixtures}],
1281              
1282             Create the file './t/etc/fixtures/basic.pl' and insert
1283              
1284             [
1285             'Person' => [
1286             [
1287             'name',
1288             'age',
1289             'email'
1290             ],
1291             [
1292             'John',
1293             '40',
1294             'john@nowehere.com'
1295             ],
1296             [
1297             'Vincent',
1298             '15',
1299             'vincent@home.com'
1300             ],
1301             [
1302             'Vanessa',
1303             '35',
1304             'vanessa@school.com'
1305             ]
1306             ]
1307             ]
1308              
1309             Additional rulesets should be included within the outermost [ ] like
1310             this.
1311              
1312             [
1313             'Person' => [
1314             ...
1315             ],
1316             'Job' => [
1317             ...
1318             ]
1319             ]
1320              
1321             The 'basic' fixture would be used with fixtures_ok in exactly the same way
1322             as when it was embedded within schema.pl using fixture_sets.
1323              
1324             =head1 CONFIGURATION BY FILE
1325              
1326             By default, we try to load configuration files from the following locations:
1327              
1328             ./t/etc/schema.*
1329             ./t/etc/[test file path].*
1330              
1331             Where "." is the root of the distribution and "*" is any of the configuration
1332             file types supported by L<Config::Any> configuration loader. This allows you
1333             to store configuration in the format of your choice.
1334              
1335             "[test file path]" is the relative path part under the "t" directory of the
1336             calling test script. For example, if your test script is "t/mytest.t" we add
1337             the path "./t/etc/mytest.*" to the path.
1338              
1339             Additionally, we do a merge using L<Hash::Merge> of all the matching found
1340             configurations. This allows you to do 'cascading' configuration from the most
1341             global to the most local settings.
1342              
1343             You can override this search path with the "-config_path" key in options. For
1344             example, the following searches for "t/etc/myconfig.*" (or whatever is the
1345             correct directory separator for your operating system):
1346              
1347             use Test::DBIx::Class -config_path => [qw/t etc myconfig/];
1348              
1349             Relative paths are rooted to the distribution home directory (ie, the one that
1350             contains your 'lib' and 't' directories). Full paths are searched without
1351             modification.
1352              
1353             You can specify multiple paths. The following would search for both "schema.*"
1354             and "share/schema".
1355              
1356             use Test::DBIx::Class -config_path => [[qw/share schema/], [qw/schema/]];
1357              
1358             Lastly, you can use the special symbol "+" to indicate that your custom path
1359             adds to or prepends to the default search path. Since as indicated we merge
1360             all the configurations found, this means it's easy to create user level
1361             configuration settings mixed with global settings, as in:
1362              
1363             use Test::DBIx::Class
1364             -config_path => [
1365             [qw(/ etc myapp test-schema)],
1366             '+',
1367             [qw(~ etc test-schema)],
1368             ];
1369              
1370             Which would search and combine "/etc/myapp/test-schema.*", "./t/etc/schema.*",
1371             "./etc/[test script name].*" and "~/etc/test-schema.*". This would let you set
1372             up server level global settings, distribution level settings and finally user
1373             level settings.
1374              
1375             Please note that in all the examples given, paths are written as an array
1376             reference of path parts, rather than as a string with delimiters (i.e. we do
1377             [qw(t etc)] rather than "t/etc"). This is not required but recommended. All
1378             arguments, either string or array references, are passed to L<Path::Class> so
1379             that we can maintain better compatibility with non unix filesystems. If you
1380             are writing for CPAN, please consider our non Unix filesystem friends :)
1381              
1382             Lastly, there is an %ENV variable named 'TEST_DBIC_CONFIG_SUFFIX' which, if it
1383             exists, can be used to further customize your configuration path. If we find
1384             that $ENV{TEST_DBIC_CONFIG_SUFFIX} is set, we attempt to find configuration files
1385             with the suffix appended to each of the items in the config_path option. So, if
1386             you have:
1387              
1388             use Test::DBIx::Class
1389             -config_path => [
1390             [qw(/ etc myapp test-schema)],
1391             '+',
1392             [qw(~ etc test-schema)],
1393             ];
1394            
1395             and $ENV{TEST_DBIC_CONFIG_SUFFIX} = '-mysql' we will check the following paths
1396             for valid and loading configuration files (assuming unix filesystem conventions)
1397              
1398             /etc/myapp/test-schema.*
1399             /etc/myapp/test-schema-mysql.*
1400             ./t/etc/schema.*
1401             ./t/etc/schema-mysql.*
1402             ./etc/[test script name].*
1403             ./etc/[test script name]-mysql.*
1404             ~/etc/test-schema.*
1405             ~/etc/test-schema-mysql.*
1406            
1407             Each path is tested in turn and all found configurations are merged from top to
1408             bottom. This feature is intended to make it easier to switch between sets of
1409             configuration files when developing. For example, you can create a test suite
1410             intended for a MySQL database, but allow a failback to the default Sqlite should
1411             certain enviroment variables not exist.
1412              
1413             =head1 CONFIGURATION SUBSTITUTIONS
1414              
1415             Similarly to L<Catalyst::Plugin::ConfigLoader>, there are some macro style
1416             keyword inflators available for use within your configuration files. This
1417             allows you to set the value of a configuration setting from an external source,
1418             such as from %ENV. There are currently two macro substitutions:
1419              
1420             =over 4
1421              
1422             =item ENV
1423              
1424             Given a value in %ENV, substitute the keyword for the value of the named
1425             substitution. For example, if you had:
1426              
1427             email = 'vanessa__ENV(TEST_DBIC_LAST_NAME)__@school.com'
1428              
1429             in your configuration filem your could:
1430              
1431             TEST_DBIC_LAST_NAME=_lee prove -lv t/schema-your-test.t
1432              
1433             and then:
1434              
1435             is $vanessa->email, 'vanessa_lee@school.com', 'Got expected email';
1436              
1437             You might find this useful for configuring localized username and passwords
1438             although personally I'd rather set that via configuration in the user home
1439             directory.
1440              
1441             =back
1442              
1443             =head1 TRAITS
1444              
1445             As described, a trait is a L<Moose::Role> that is applied to the class
1446             managing your database and test instance. Traits are installed by the
1447             'traits' configuration option, which expects an ArrayRef as its input
1448             (however will also normalize a scalar to an ArrayRef).
1449              
1450             Available traits are as follows.
1451              
1452             =head2 SQLite
1453              
1454             This is the default trait which will be loaded if no other traits are installed
1455             and there is not 'connect_info' in the configuration. In this case we assume
1456             you want us to go and create a tempory SQLite database for testing. Please see
1457             L<Test::DBIx::Class::SchemaManager::Trait::SQLite> for more.
1458              
1459             =head2 Testmysqld
1460              
1461             If MySQL is installed on the testing machine, and L<DBD::mysql>, we try to auto
1462             create an instance of MySQL and deploy our tests to that. Similarly to the way
1463             the SQLite trait works, we attempt to create the database without requiring any
1464             other using effort or setup.
1465              
1466             See L<Test::DBIx::Class::SchemaManager::Trait::Testmysqld> for more.
1467              
1468             =head2 Testpostgresql
1469              
1470             If Postgresql is installed on the testing machine, along with L<DBD::Pg>, we try
1471             to auto create an instance of Postgresql in a testing area and deploy our tests
1472             and fixtures to it.
1473              
1474             See L<Test::DBIx::Class::SchemaManager::Trait::Testpostgresql> for more.
1475              
1476             =head1 SEE ALSO
1477              
1478             The following modules or resources may be of interest.
1479              
1480             L<DBIx::Class>, L<DBIx::Class::Schema::PopulateMore>, L<DBIx::Class::Fixtures>
1481              
1482             =head1 AUTHOR
1483              
1484             John Napiorkowski C<< <jjnapiork@cpan.org> >>
1485              
1486             =head1 CONTRIBUTORS
1487              
1488             Tristan Pratt
1489             Tomas Doran C<< <bobtfish@bobtfish.net> >>
1490             Kyle Hasselbacher C<< kyleha@gmail.com >>
1491             cvince
1492             colinnewell
1493             rbuels
1494             wlk
1495             yanick
1496             hippich
1497             lecstor
1498             bphillips
1499             abraxxa
1500             oalders
1501             felliott
1502             Vadim Pushtaev C<< <pushtaev@cpan.org> >>
1503             simonamor
1504              
1505             =head1 COPYRIGHT & LICENSE
1506              
1507             Copyright 2012, John Napiorkowski C<< <jjnapiork@cpan.org> >>
1508              
1509             This program is free software; you can redistribute it and/or modify
1510             it under the same terms as Perl itself.
1511              
1512             =cut