root/branches/release-41/t/ddl-tests.pl @ 2705

Revision 2705, 12.8 kB (checked in by bchoate, 17 months ago)

Added support for determining autoincrement/nullable columns for sqlite's DDL module.

  • Property svn:executable set to *
Line 
1#!/usr/bin/perl
2
3# Movable Type (r) Open Source (C) 2001-2008 Six Apart, Ltd.
4# This program is distributed under the terms of the
5# GNU General Public License, version 2.
6#
7# $Id$
8
9use strict;
10use warnings;
11use Data::Dumper;
12use English qw( -no_watch_vars );
13
14$OUTPUT_AUTOFLUSH = 1;
15
16# Run this script as a symlink, in the form of 99-driver.t, ie:
17# ln -s driver-tests.pl 99-driver.t
18
19BEGIN {
20    # Set config to driver-test.cfg when run as /path/to/99-driver.t
21    $ENV{MT_CONFIG} = "$1-test.cfg"
22        if __FILE__ =~ m{ ([^\\/-]+) \.t \z }xms;
23}
24
25use Test::More;
26use lib 't/lib';
27use MT::Test;
28use Test::Class;
29
30BEGIN {
31    plan skip_all => "Configuration file $ENV{MT_CONFIG} not found"
32        if !-r $ENV{MT_CONFIG};
33}
34
35
36package Ddltest;
37use base qw( MT::Object );
38
39__PACKAGE__->install_properties({
40    column_defs => {
41        id           => 'integer not null auto_increment',
42        string_25    => 'string(25)',
43        string_25_nn => 'string(25) not null',
44        string_255   => 'string(255)',
45        string_1024  => 'string(1024)',
46        int_bool     => 'boolean',
47        int_bool_nn  => 'boolean not null',
48        int_small    => 'smallint',
49        int_small_nn => 'smallint not null',
50        int_med      => 'integer',
51        int_med_nn   => 'integer not null',
52        int_big      => 'bigint',
53        int_big_nn   => 'bigint not null',
54        float        => 'float',
55        float_nn     => 'float not null',
56        text         => 'text',
57        text_nn      => 'text not null',
58        blob         => 'blob',
59        blob_nn      => 'blob not null',
60        datetime     => 'datetime',
61        datetime_nn  => 'datetime not null',
62    },
63    indexes => {
64        string_25_nn => 1,
65        int_small_nn => 1,
66        string_dt  => {
67            columns => [ qw( string_25 datetime_nn ) ],
68        },
69    },
70    audit       => 1,
71    datasource  => 'ddltest',
72    primary_key => 'id',
73    cacheable   => 0,
74});
75
76
77package Ddltest::InvalidType;
78use base qw( MT::Object );
79
80__PACKAGE__->install_properties({
81    column_defs => {
82        id => 'integer not null auto_increment',
83        boo => 'asfdasf',
84    },
85    datasource  => 'ddltest_invalidtype',
86    primary_key => 'id',
87    cacheable   => 0,
88});
89
90
91package Ddltest::Fixable;
92use base qw( MT::Object );
93
94__PACKAGE__->install_properties({
95    column_defs => {
96        id  => 'integer not null auto_increment',
97        foo => 'string(10)',
98        bar => 'string(10)',
99        baz => 'string(10)',
100    },
101    datasource  => 'ddltest_fixable',
102    primary_key => 'id',
103    cacheable   => 0,
104});
105
106
107package Test::DDL;
108use base qw( Test::Class MT::Test );
109use Test::More;
110
111sub startup : Test(startup) {
112    my $self = shift;
113
114    my $driver    = MT::Object->dbi_driver;
115    my $dbh       = $driver->rw_handle;
116    my $ddl_class = $driver->dbd->ddl_class;
117
118    # The table may exist from a previous test, so delete it if it does.
119    eval {
120        if ($driver->table_exists('Ddltest')) {
121            my $sql = $driver->dbd->ddl_class->drop_table_sql('Ddltest');
122            $driver->rw_handle->do($sql);
123        }
124    };
125}
126
127sub _00_table_does_not_exist : Tests(3) {
128    my $self = shift;
129
130    my $driver    = MT::Object->dbi_driver;
131    my $dbh       = $driver->rw_handle;
132    my $ddl_class = $driver->dbd->ddl_class;
133
134    ok(!$driver->table_exists('Ddltest'), 'Ddltest table does not yet exist');
135    ok(!defined $ddl_class->column_defs('Ddltest'), 'Ddltest table has no column defs');
136    ok(!defined $ddl_class->index_defs('Ddltest'), 'Ddltest table has no index defs');
137}
138
139sub _01_create_table : Tests(2) {
140    my $self = shift;
141
142    my $driver    = MT::Object->dbi_driver;
143    my $dbh       = $driver->rw_handle;
144    my $ddl_class = $driver->dbd->ddl_class;
145
146    my $create_sql = $ddl_class->create_table_sql('Ddltest');
147    ok($create_sql, 'Create Table SQL for Ddltest is available');
148    my $res = $dbh->do($create_sql);
149    ok($res, 'Driver could perform Create Table SQL for Ddltest');
150    diag($dbh->errstr || $DBI::errstr) if !$res;
151}
152
153sub _02_create_indexes : Tests(5) {
154    my $self = shift;
155
156    my $driver    = MT::Object->dbi_driver;
157    my $dbh       = $driver->rw_handle;
158    my $ddl_class = $driver->dbd->ddl_class;
159
160    my @index_sql = $ddl_class->index_table_sql('Ddltest');
161    ok(@index_sql, 'Index Table SQL for Ddltest is available');
162    is(scalar @index_sql, 3, 'Index Table SQL has 4 statements');
163    for my $index_sql (@index_sql) {
164        my $res = $dbh->do($index_sql);
165        ok($res, 'Driver could perform Index Table SQL for Ddltest');
166        if (!$res) {
167            diag($dbh->errstr || $DBI::errstr);
168            diag('SQL: ' . $index_sql);
169        }
170    }
171}
172
173sub _03_create_sequence : Tests(2) {
174    my $self = shift;
175
176    my $driver    = MT::Object->dbi_driver;
177    my $dbh       = $driver->rw_handle;
178    my $ddl_class = $driver->dbd->ddl_class;
179
180    $ddl_class->create_sequence('Ddltest');
181    pass('Created Ddltest sequence without dying');
182
183    $ddl_class->drop_sequence('Ddltest');
184    $ddl_class->create_sequence('Ddltest');
185    pass('Recreated Ddltest sequence after drop without dying');
186}
187
188sub _def {
189    my ($auto, $not_null, $type, $size) = @_;
190    my $def = {
191        auto => $auto,
192        not_null => $not_null,
193        type => $type,
194    };
195    $def->{size} = $size if defined $size;
196    return $def;
197}
198
199sub is_def {
200    my ($got, $expected, $reason) = @_;
201
202    for my $field (qw( not_null auto )) {
203        if ($expected->{$field} xor $got->{$field}) {
204            fail($reason);
205            diag($expected->{$field}
206                ? "Expected $field but didn't get it"
207                : "Expected not $field but got it");
208            return;
209        }
210    }
211
212    if ($expected->{type} ne $got->{type}) {
213        fail($reason);
214        diag("Expected type ", $expected->{type}, " but got ", $got->{type});
215        return;
216    }
217
218    if (defined $expected->{size} && $expected->{size} != $got->{size}) {
219        fail($reason);
220        diag("Expected size ", $expected->{size}, " but got ", $got->{size});
221        return;
222    }
223
224    pass($reason);
225}
226
227sub table_defs : Tests(26) {
228    my $defs = MT::Object->driver->dbd->ddl_class->column_defs('Ddltest');
229    ok($defs, 'Ddltest DDL settings are defined');
230
231    is_def($defs->{id}, _def(1, 1, 'integer'), 'Ddltest id column def is correct');
232
233    is_def($defs->{string_25},    _def(0, 0, 'string', 25),   'Ddltest string_25 column def is correct');
234    is_def($defs->{string_25_nn}, _def(0, 1, 'string', 25),   'Ddltest string_25_nn column def is correct');
235    is_def($defs->{string_255},   _def(0, 0, 'string', 255),  'Ddltest string_255 column def is correct');
236    is_def($defs->{string_1024},  _def(0, 0, 'string', 1024), 'Ddltest string_1024 column def is correct');
237    is_def($defs->{int_bool},     _def(0, 0, 'boolean'),      'Ddltest int_bool column def is correct');
238    is_def($defs->{int_bool_nn},  _def(0, 1, 'boolean'),      'Ddltest int_bool_nn column def is correct');
239    is_def($defs->{int_small},    _def(0, 0, 'smallint'),     'Ddltest int_small column def is correct');
240    is_def($defs->{int_small_nn}, _def(0, 1, 'smallint'),     'Ddltest int_small_nn column def is correct');
241    is_def($defs->{int_med},      _def(0, 0, 'integer'),      'Ddltest int_med column def is correct');
242    is_def($defs->{int_med_nn},   _def(0, 1, 'integer'),      'Ddltest int_med_nn column def is correct');
243    is_def($defs->{int_big},      _def(0, 0, 'bigint'),       'Ddltest int_big column def is correct');
244    is_def($defs->{int_big_nn},   _def(0, 1, 'bigint'),       'Ddltest int_big_nn column def is correct');
245    is_def($defs->{float},        _def(0, 0, 'float'),        'Ddltest float column def is correct');
246    is_def($defs->{float_nn},     _def(0, 1, 'float'),        'Ddltest float_nn column def is correct');
247    is_def($defs->{text},         _def(0, 0, 'text'),         'Ddltest text column def is correct');
248    is_def($defs->{text_nn},      _def(0, 1, 'text'),         'Ddltest text_nn column def is correct');
249    is_def($defs->{blob},         _def(0, 0, 'blob'),         'Ddltest blob column def is correct');
250    is_def($defs->{blob_nn},      _def(0, 1, 'blob'),         'Ddltest blob_nn column def is correct');
251    is_def($defs->{datetime},     _def(0, 0, 'datetime'),     'Ddltest datetime column def is correct');
252    is_def($defs->{datetime_nn},  _def(0, 1, 'datetime'),     'Ddltest datetime_nn column def is correct');
253
254    # audit fields
255    is_def($defs->{created_on},  _def(0, 0, 'datetime'), 'Ddltest created_on column def is correct');
256    is_def($defs->{created_by},  _def(0, 0, 'integer'),  'Ddltest created_by column def is correct');
257    is_def($defs->{modified_on}, _def(0, 0, 'datetime'), 'Ddltest modified_on column def is correct');
258    is_def($defs->{modified_by}, _def(0, 0, 'integer'),  'Ddltest modified_by column def is correct');
259}
260
261sub index_defs : Tests(5) {
262    my $index_defs = MT::Object->driver->dbd->ddl_class->index_defs('Ddltest');
263    ok($index_defs, 'Ddltest table has index defs');
264
265    is(keys %$index_defs, 3, 'Ddltest table has three indexes');
266    is($index_defs->{string_25_nn}, 1, 'Ddltest table has name index');
267    is($index_defs->{int_small_nn}, 1, 'Ddltest table has status index');
268    is_deeply($index_defs->{string_dt}, {
269        columns => [ qw( string_25 datetime_nn ) ]
270    }, 'Ddltest table has multi-column string_dt index');
271}
272
273sub invalid_type : Tests(3) {
274    my $self = shift;
275
276    my $driver    = MT::Object->dbi_driver;
277    my $dbh       = $driver->rw_handle;
278    my $ddl_class = $driver->dbd->ddl_class;
279
280    ok(!$driver->table_exists('Ddltest::InvalidType'), 'Ddltest::InvalidType table does not yet exist');
281    ok(!defined $ddl_class->column_defs('Ddltest::InvalidType'), 'Ddltest::InvalidType table has no column defs');
282
283    ok(!eval { $ddl_class->create_table_sql('Ddltest::InvalidType') }, 'Ddltest::InvalidType cannot make creation sql');
284}
285
286sub fixable : Tests(12) {
287    my $self = shift;
288
289    my $driver    = MT::Object->dbi_driver;
290    my $dbh       = $driver->rw_handle;
291    my $ddl_class = $driver->dbd->ddl_class;
292
293    eval {
294        if ($driver->table_exists('Ddltest::Fixable')) {
295            my $sql = $ddl_class->drop_table_sql('Ddltest::Fixable');
296            $dbh->do($sql);
297        }
298    };
299    eval {
300        my $sql = $ddl_class->create_table_sql('Ddltest::Fixable');
301        $dbh->do($sql);
302    };
303    for my $i (1..5) {
304        my $obj = Ddltest::Fixable->new;
305        $obj->foo($i);
306        $obj->save;
307    }
308
309    my $defs = $ddl_class->column_defs('Ddltest::Fixable');
310    ok($defs->{baz}, 'Ddltest::Fixable table has baz column after creation');
311
312    my $sql;
313    my $res;
314
315    SKIP: {
316        skip("Driver cannot drop columns", 2) unless $ddl_class->can_drop_column;
317        $sql = $ddl_class->drop_column_sql('Ddltest::Fixable', 'baz');
318        ok($sql, 'Ddltest::Fixable can have column dropping sql');
319        $res = $dbh->do($sql);
320        ok($res, 'Ddltest::Fixable could have its column dropped');
321    }
322
323    {
324        local Ddltest::Fixable->properties->{column_defs}->{borf} = 'string(10)';
325        $sql = $ddl_class->add_column_sql('Ddltest::Fixable', 'borf');
326        ok($sql, 'Ddltest::Fixable can have column adding sql');
327        $res = $dbh->do($sql);
328        ok($res, 'Ddltest::Fixable could have a column added');
329        diag(($dbh->errstr || $DBI::errstr) . "( sql $sql)") if !$res;
330    }
331
332    $defs = $ddl_class->column_defs('Ddltest::Fixable');
333    SKIP: {
334        skip("Driver cannot drop columns", 1) unless $ddl_class->can_drop_column;
335        ok(!$defs->{baz},  'Ddltest::Fixable did indeed have a column dropped');
336    }
337    ok( $defs->{borf}, 'Ddltest::Fixable did indeed have a column added');
338
339    STMT: for my $stmt ($ddl_class->fix_class('Ddltest::Fixable')) {
340        $res = $dbh->do($stmt);
341        if (!$res) {
342            diag($dbh->errstr || $DBI::errstr);
343            last STMT;
344        }
345    }
346    ok($res, q{All Ddltest::Fixable's table-fixing statements were performed});
347    $defs = $ddl_class->column_defs('Ddltest::Fixable');
348    ok( $defs->{baz},  'Ddltest::Fixable regrew its dropped column after a fix_class');
349    ok(!$defs->{borf}, 'Ddltest::Fixable lost its extra column after a fix_class');
350
351    my @objs = Ddltest::Fixable->load();
352    is(scalar @objs, 5, 'There are still 5 Ddltest::Fixable records');
353    is_deeply([ sort map { $_->foo } @objs ], [ 1..5 ], 'Ddltest::Fixable records survived with values intact');
354}
355
356sub _00_drop_table_test : Test(shutdown => 3) {
357    my $self = shift;
358
359    my $driver    = MT::Object->dbi_driver;
360    my $dbh       = $driver->rw_handle;
361    my $ddl_class = $driver->dbd->ddl_class;
362
363    my $drop_sql = $ddl_class->drop_table_sql('Ddltest');
364    ok($drop_sql, 'Drop Table SQL for Ddltest is available');
365    my $res = $dbh->do($drop_sql);
366    ok($res, 'Driver could perform Drop Table SQL for Ddltest');
367    diag($dbh->errstr || $DBI::errstr) if !$res;
368
369    ok(!defined $ddl_class->column_defs('Ddltest'), 'Ddltest table no longer exists');
370}
371
372package main;
373
374Test::DDL->runtests();
375
3761;
377
Note: See TracBrowser for help on using the browser.