0.01002 - fix email addr typo, doh
[dbsrgits/DBIx-Class-Schema-Loader.git] / t / dbixcsl_common_tests.pm
1 package dbixcsl_common_tests;
2
3 use strict;
4 use warnings;
5
6 use Test::More;
7 use DBIx::Class::Schema::Loader;
8 use DBI;
9
10 sub new {
11     my $class = shift;
12
13     my $self;
14
15     if( ref($_[0]) eq 'HASH') {
16        my $args = shift;
17        $self = { (%$args) };
18     }
19     else {
20        $self = { @_ };
21     }
22
23     # Only MySQL uses this
24     $self->{innodb} ||= '';
25     
26     $self->{verbose} = $ENV{TEST_VERBOSE} || 0;
27
28     return bless $self => $class;
29 }
30
31 sub skip_tests {
32     my ($self, $why) = @_;
33
34     plan skip_all => $why;
35 }
36
37 sub run_tests {
38     my $self = shift;
39
40     plan tests => 41;
41
42     $self->create();
43
44     my $schema_class = 'DBIXCSL_Test_' . $self->{vendor} . '::Schema';
45
46     my $debug = ($self->{verbose} > 1) ? 1 : 0;
47
48     my %loader_opts = (
49         dsn                     => $self->{dsn},
50         user                    => $self->{user},
51         password                => $self->{password},
52         constraint              => '^(?:\S+\.)?(?i:loader_test)[0-9]+$',
53         relationships           => 1,
54         additional_classes      => 'TestAdditional',
55         additional_base_classes => 'TestAdditionalBase',
56         left_base_classes       => [ qw/TestLeftBase/ ],
57         debug                   => $debug,
58     );
59
60     $loader_opts{db_schema} = $self->{db_schema} if $self->{db_schema};
61     $loader_opts{drop_db_schema} = $self->{drop_db_schema} if $self->{drop_db_schema};
62
63     eval qq{
64         package $schema_class;
65         use base qw/DBIx::Class::Schema::Loader/;
66
67         __PACKAGE__->load_from_connection(\%loader_opts);
68     };
69     ok(!$@, "Loader initialization") or diag $@;
70
71     my $conn = $schema_class->connect($self->{dsn},$self->{user},$self->{password});
72     my $monikers = $schema_class->loader->monikers;
73     my $classes = $schema_class->loader->classes;
74
75     my $moniker1 = $monikers->{loader_test1};
76     my $class1   = $classes->{loader_test1};
77     my $rsobj1   = $conn->resultset($moniker1);
78
79     my $moniker2 = $monikers->{loader_test2};
80     my $class2   = $classes->{loader_test2};
81     my $rsobj2   = $conn->resultset($moniker2);
82
83     isa_ok( $rsobj1, "DBIx::Class::ResultSet" );
84     isa_ok( $rsobj2, "DBIx::Class::ResultSet" );
85
86     can_ok( $class1, 'test_additional_base' );
87     can_ok( $class1, 'test_additional_base_override' );
88     can_ok( $class1, 'test_additional_base_additional' );
89
90     is( $class1->test_additional_base, "test_additional_base",
91         "Additional Base method" );
92
93     is( $class1->test_additional_base_override, "test_left_base_override",
94         "Left Base overrides Additional Base method" );
95
96     is( $class1->test_additional_base_additional, "test_additional",
97         "Additional Base can use Additional package method" );
98
99     my $obj    = $rsobj1->find(1);
100     is( $obj->id,  1 );
101     is( $obj->dat, "foo" );
102     is( $rsobj2->count, 4 );
103
104     my ($obj2) = $rsobj2->find( dat => 'bbb' );
105     is( $obj2->id, 2 );
106
107     SKIP: {
108         skip $self->{skip_rels}, 28 if $self->{skip_rels};
109
110         my $moniker3 = $monikers->{loader_test3};
111         my $class3   = $classes->{loader_test3};
112         my $rsobj3   = $conn->resultset($moniker3);
113
114         my $moniker4 = $monikers->{loader_test4};
115         my $class4   = $classes->{loader_test4};
116         my $rsobj4   = $conn->resultset($moniker4);
117
118         my $moniker5 = $monikers->{loader_test5};
119         my $class5   = $classes->{loader_test5};
120         my $rsobj5   = $conn->resultset($moniker5);
121
122         my $moniker6 = $monikers->{loader_test6};
123         my $class6   = $classes->{loader_test6};
124         my $rsobj6   = $conn->resultset($moniker6);
125
126         my $moniker7 = $monikers->{loader_test7};
127         my $class7   = $classes->{loader_test7};
128         my $rsobj7   = $conn->resultset($moniker7);
129
130         my $moniker8 = $monikers->{loader_test8};
131         my $class8   = $classes->{loader_test8};
132         my $rsobj8   = $conn->resultset($moniker8);
133
134         my $moniker9 = $monikers->{loader_test9};
135         my $class9   = $classes->{loader_test9};
136         my $rsobj9   = $conn->resultset($moniker9);
137
138         isa_ok( $rsobj3, "DBIx::Class::ResultSet" );
139         isa_ok( $rsobj4, "DBIx::Class::ResultSet" );
140         isa_ok( $rsobj5, "DBIx::Class::ResultSet" );
141         isa_ok( $rsobj6, "DBIx::Class::ResultSet" );
142         isa_ok( $rsobj7, "DBIx::Class::ResultSet" );
143         isa_ok( $rsobj8, "DBIx::Class::ResultSet" );
144         isa_ok( $rsobj9, "DBIx::Class::ResultSet" );
145
146         # basic rel test
147         my $obj4 = $rsobj4->find(123);
148         isa_ok( $obj4->fkid, $class3);
149
150         # fk def in comments should not be parsed
151         my $obj5 = $rsobj5->find( id1 => 1, id2 => 1 );
152         is( ref( $obj5->id2 ), '' );
153
154         # mulit-col fk def
155         my $obj6 = $rsobj6->find(1);
156         isa_ok( $obj6->loader_test2, $class2);
157         isa_ok( $obj6->loader_test5, $class5);
158
159         # fk that references a non-pk key (UNIQUE)
160         my $obj8 = $rsobj8->find(1);
161         isa_ok( $obj8->loader_test7, $class7);
162
163         # from Chisel's tests...
164         SKIP: {
165             if($self->{vendor} =~ /sqlite/i) {
166                 skip 'SQLite cannot do the advanced tests', 8;
167             }
168
169             my $moniker10 = $monikers->{loader_test10};
170             my $class10   = $classes->{loader_test10};
171             my $rsobj10   = $conn->resultset($moniker10);
172
173             my $moniker11 = $monikers->{loader_test11};
174             my $class11   = $classes->{loader_test11};
175             my $rsobj11   = $conn->resultset($moniker11);
176
177             isa_ok( $rsobj10, "DBIx::Class::ResultSet" ); 
178             isa_ok( $rsobj11, "DBIx::Class::ResultSet" );
179
180             my $obj10 = $rsobj10->create({ subject => 'xyzzy' });
181
182             $obj10->update();
183             ok( defined $obj10, '$obj10 is defined' );
184
185             my $obj11 = $rsobj11->create({ loader_test10 => $obj10->id() });
186             $obj11->update();
187             ok( defined $obj11, '$obj11 is defined' );
188
189             eval {
190                 my $obj10_2 = $obj11->loader_test10;
191                 $obj10_2->loader_test11( $obj11->id11() );
192                 $obj10_2->update();
193             };
194             is($@, '', 'No errors after eval{}');
195
196             SKIP: {
197                 skip 'Previous eval block failed', 3
198                     unless ($@ eq '');
199         
200                 my $results = $rsobj10->search({ subject => 'xyzzy' });
201                 is( $results->count(), 1,
202                     'One $rsobj10 returned from search' );
203
204                 my $obj10_3 = $results->first();
205                 isa_ok( $obj10_3, $class10 );
206                 is( $obj10_3->loader_test11()->id(), $obj11->id(),
207                     'found same $rsobj11 object we expected' );
208             }
209         }
210
211         SKIP: {
212             skip 'This vendor cannot do inline relationship definitions', 5
213                 if $self->{no_inline_rels};
214
215             my $moniker12 = $monikers->{loader_test12};
216             my $class12   = $classes->{loader_test12};
217             my $rsobj12   = $conn->resultset($moniker12);
218
219             my $moniker13 = $monikers->{loader_test13};
220             my $class13   = $classes->{loader_test13};
221             my $rsobj13   = $conn->resultset($moniker13);
222
223             isa_ok( $rsobj12, "DBIx::Class::ResultSet" ); 
224             isa_ok( $rsobj13, "DBIx::Class::ResultSet" );
225
226             my $obj13 = $rsobj13->find(1);
227             isa_ok( $obj13->id, $class12 );
228             isa_ok( $obj13->loader_test12, $class12);
229             isa_ok( $obj13->dat, $class12);
230         }
231
232         SKIP: {
233             skip 'This vendor cannot do out-of-line implicit rel defs', 3
234                 if $self->{no_implicit_rels};
235             my $moniker14 = $monikers->{loader_test14};
236             my $class14   = $classes->{loader_test14};
237             my $rsobj14   = $conn->resultset($moniker14);
238
239             my $moniker15 = $monikers->{loader_test15};
240             my $class15   = $classes->{loader_test15};
241             my $rsobj15   = $conn->resultset($moniker15);
242
243             isa_ok( $rsobj14, "DBIx::Class::ResultSet" ); 
244             isa_ok( $rsobj15, "DBIx::Class::ResultSet" );
245
246             my $obj15 = $rsobj15->find(1);
247             isa_ok( $obj15->loader_test14, $class14 );
248         }
249     }
250 }
251
252 sub dbconnect {
253     my ($self, $complain) = @_;
254
255     my $dbh = DBI->connect(
256          $self->{dsn}, $self->{user},
257          $self->{password},
258          {
259              RaiseError => $complain,
260              PrintError => $complain,
261              AutoCommit => 1,
262          }
263     );
264
265     die "Failed to connect to database: $DBI::errstr" if !$dbh;
266
267     return $dbh;
268 }
269
270 sub create {
271     my $self = shift;
272
273     my @statements = (
274         qq{
275             CREATE TABLE loader_test1 (
276                 id $self->{auto_inc_pk},
277                 dat VARCHAR(32)
278             ) $self->{innodb}
279         },
280
281         q{ INSERT INTO loader_test1 (dat) VALUES('foo') },
282         q{ INSERT INTO loader_test1 (dat) VALUES('bar') }, 
283         q{ INSERT INTO loader_test1 (dat) VALUES('baz') }, 
284
285         qq{ 
286             CREATE TABLE loader_test2 (
287                 id $self->{auto_inc_pk},
288                 dat VARCHAR(32)
289             ) $self->{innodb}
290         },
291
292         q{ INSERT INTO loader_test2 (dat) VALUES('aaa') }, 
293         q{ INSERT INTO loader_test2 (dat) VALUES('bbb') }, 
294         q{ INSERT INTO loader_test2 (dat) VALUES('ccc') }, 
295         q{ INSERT INTO loader_test2 (dat) VALUES('ddd') }, 
296     );
297
298     my @statements_reltests = (
299         qq{
300             CREATE TABLE loader_test3 (
301                 id INTEGER NOT NULL PRIMARY KEY,
302                 dat VARCHAR(32)
303             ) $self->{innodb}
304         },
305
306         q{ INSERT INTO loader_test3 (id,dat) VALUES(1,'aaa') }, 
307         q{ INSERT INTO loader_test3 (id,dat) VALUES(2,'bbb') }, 
308         q{ INSERT INTO loader_test3 (id,dat) VALUES(3,'ccc') }, 
309         q{ INSERT INTO loader_test3 (id,dat) VALUES(4,'ddd') }, 
310
311         qq{
312             CREATE TABLE loader_test4 (
313                 id INTEGER NOT NULL PRIMARY KEY,
314                 fkid INTEGER NOT NULL,
315                 dat VARCHAR(32),
316                 FOREIGN KEY (fkid) REFERENCES loader_test3 (id)
317             ) $self->{innodb}
318         },
319
320         q{ INSERT INTO loader_test4 (id,fkid,dat) VALUES(123,1,'aaa') },
321         q{ INSERT INTO loader_test4 (id,fkid,dat) VALUES(124,2,'bbb') }, 
322         q{ INSERT INTO loader_test4 (id,fkid,dat) VALUES(125,3,'ccc') },
323         q{ INSERT INTO loader_test4 (id,fkid,dat) VALUES(126,4,'ddd') },
324
325         qq{
326             CREATE TABLE loader_test5 (
327                 id1 INTEGER NOT NULL,
328                 id2 INTEGER NOT NULL, -- , id2 INTEGER REFERENCES loader_test1,
329                 dat VARCHAR(8),
330                 PRIMARY KEY (id1,id2)
331             ) $self->{innodb}
332         },
333
334         q{ INSERT INTO loader_test5 (id1,id2,dat) VALUES (1,1,'aaa') },
335
336         qq{
337             CREATE TABLE loader_test6 (
338                 id INTEGER NOT NULL PRIMARY KEY,
339                 id2 INTEGER,
340                 loader_test2 INTEGER,
341                 dat VARCHAR(8),
342                 FOREIGN KEY (loader_test2) REFERENCES loader_test2 (id),
343                 FOREIGN KEY (id, id2 ) REFERENCES loader_test5 (id1,id2)
344             ) $self->{innodb}
345         },
346
347         (q{ INSERT INTO loader_test6 (id, id2,loader_test2,dat) } .
348          q{ VALUES (1, 1,1,'aaa') }),
349
350         qq{
351             CREATE TABLE loader_test7 (
352                 id INTEGER NOT NULL PRIMARY KEY,
353                 id2 VARCHAR(8) NOT NULL UNIQUE,
354                 dat VARCHAR(8)
355             ) $self->{innodb}
356         },
357
358         q{ INSERT INTO loader_test7 (id,id2,dat) VALUES (1,'aaa','bbb') },
359
360         qq{
361             CREATE TABLE loader_test8 (
362                 id INTEGER NOT NULL PRIMARY KEY,
363                 loader_test7 VARCHAR(8) NOT NULL,
364                 dat VARCHAR(8),
365                 FOREIGN KEY (loader_test7) REFERENCES loader_test7 (id2)
366             ) $self->{innodb}
367         },
368
369         (q{ INSERT INTO loader_test8 (id,loader_test7,dat) } .
370          q{ VALUES (1,'aaa','bbb') }),
371
372         qq{
373             CREATE TABLE loader_test9 (
374                 loader_test9 VARCHAR(8) NOT NULL
375             ) $self->{innodb}
376         },
377     );
378
379     my @statements_advanced = (
380         qq{
381             CREATE TABLE loader_test10 (
382                 id10 $self->{auto_inc_pk},
383                 subject VARCHAR(8),
384                 loader_test11 INTEGER
385             ) $self->{innodb}
386         },
387
388         qq{
389             CREATE TABLE loader_test11 (
390                 id11 $self->{auto_inc_pk},
391                 message VARCHAR(8) DEFAULT 'foo',
392                 loader_test10 INTEGER,
393                 FOREIGN KEY (loader_test10) REFERENCES loader_test10 (id10)
394             ) $self->{innodb}
395         },
396
397         (q{ ALTER TABLE loader_test10 ADD CONSTRAINT } .
398          q{ loader_test11_fk FOREIGN KEY (loader_test11) } .
399          q{ REFERENCES loader_test11 (id11) }),
400     );
401
402     my @statements_inline_rels = (
403         qq{
404             CREATE TABLE loader_test12 (
405                 id INTEGER NOT NULL PRIMARY KEY,
406                 id2 VARCHAR(8) NOT NULL UNIQUE,
407                 dat VARCHAR(8) NOT NULL UNIQUE
408             ) $self->{innodb}
409         },
410
411         q{ INSERT INTO loader_test12 (id,id2,dat) VALUES (1,'aaa','bbb') },
412
413         qq{
414             CREATE TABLE loader_test13 (
415                 id INTEGER NOT NULL PRIMARY KEY REFERENCES loader_test12,
416                 loader_test12 VARCHAR(8) NOT NULL REFERENCES loader_test12 (id2),
417                 dat VARCHAR(8) REFERENCES loader_test12 (dat)
418             ) $self->{innodb}
419         },
420
421         (q{ INSERT INTO loader_test13 (id,loader_test12,dat) } .
422          q{ VALUES (1,'aaa','bbb') }),
423     );
424
425
426     my @statements_implicit_rels = (
427         qq{
428             CREATE TABLE loader_test14 (
429                 id INTEGER NOT NULL PRIMARY KEY,
430                 dat VARCHAR(8)
431             ) $self->{innodb}
432         },
433  
434         q{ INSERT INTO loader_test14 (id,dat) VALUES (123,'aaa') },
435
436         qq{
437             CREATE TABLE loader_test15 (
438                 id INTEGER NOT NULL PRIMARY KEY,
439                 loader_test14 INTEGER NOT NULL,
440                 FOREIGN KEY (loader_test14) REFERENCES loader_test14
441             ) $self->{innodb}
442         },
443
444         q{ INSERT INTO loader_test15 (id,loader_test14) VALUES (1,123) },
445    );
446
447     $self->drop_tables;
448
449     $self->{created} = 1;
450
451     my $dbh = $self->dbconnect(1);
452
453     # Silence annoying but harmless postgres "NOTICE:  CREATE TABLE..."
454     local $SIG{__WARN__} = sub {
455         my $msg = shift;
456         print STDERR $msg unless $msg =~ m{^NOTICE:\s+CREATE TABLE};
457     };
458
459     $dbh->do($_) for (@statements);
460     unless($self->{skip_rels}) {
461         # hack for now, since DB2 doesn't like inline comments, and we need
462         # to test one for mysql, which works on everyone else...
463         # this all needs to be refactored anyways.
464         if($self->{vendor} =~ /DB2/i) {
465             @statements_reltests = map { s/--.*\n//; $_ } @statements_reltests;
466         }
467         $dbh->do($_) for (@statements_reltests);
468         unless($self->{vendor} =~ /sqlite/i) {
469             $dbh->do($_) for (@statements_advanced);
470         }
471         unless($self->{no_inline_rels}) {
472             $dbh->do($_) for (@statements_inline_rels);
473         }
474         unless($self->{no_implicit_rels}) {
475             $dbh->do($_) for (@statements_implicit_rels);
476         }
477     }
478     $dbh->disconnect();
479 }
480
481 sub drop_tables {
482     my $self = shift;
483
484     return unless $self->{created};
485
486     my @tables = qw/
487         loader_test1
488         loader_test2
489     /;
490
491     my @tables_reltests = qw/
492         loader_test4
493         loader_test3
494         loader_test6
495         loader_test5
496         loader_test8
497         loader_test7
498         loader_test9
499     /;
500
501     my @tables_advanced = qw/
502         loader_test11
503         loader_test10
504     /;
505
506     my @tables_inline_rels = qw/
507         loader_test13
508         loader_test12
509     /;
510
511     my @tables_implicit_rels = qw/
512         loader_test15
513         loader_test14
514     /;
515
516     my $drop_fk_mysql =
517         q{ALTER TABLE loader_test10 DROP FOREIGN KEY loader_test11_fk;};
518
519     my $drop_fk =
520         q{ALTER TABLE loader_test10 DROP CONSTRAINT loader_test11_fk;};
521
522     my $dbh = $self->dbconnect(0);
523
524     unless($self->{skip_rels}) {
525         $dbh->do("DROP TABLE $_") for (@tables_reltests);
526         unless($self->{vendor} =~ /sqlite/i) {
527             if($self->{vendor} =~ /mysql/i) {
528                 $dbh->do($drop_fk_mysql);
529             }
530             else {
531                 $dbh->do($drop_fk);
532             }
533             $dbh->do("DROP TABLE $_") for (@tables_advanced);
534         }
535         unless($self->{no_inline_rels}) {
536             $dbh->do("DROP TABLE $_") for (@tables_inline_rels);
537         }
538         unless($self->{no_implicit_rels}) {
539             $dbh->do("DROP TABLE $_") for (@tables_implicit_rels);
540         }
541     }
542     $dbh->do("DROP TABLE $_") for (@tables);
543     $dbh->disconnect;
544 }
545
546 sub DESTROY { shift->drop_tables; }
547
548 1;