~ubuntu-branches/ubuntu/jaunty/libclass-meta-perl/jaunty

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
#!perl -w

# $Id: errors.t 1379 2005-03-09 18:27:05Z theory $

##############################################################################
# Set up the tests.
##############################################################################
use strict;
use Test::More $] < 5.008
  ? (skip_all => 'Older Carp lacks @CARP_NOT support')
  : (tests => 208);
use File::Spec;
my $fn = File::Spec->catfile('t', 'errors.t');

BEGIN {
    main::use_ok('Class::Meta');
    main::use_ok('Class::Meta::Types::String');
}

##############################################################################
# Packages we'll use for testing type errors.
package NoAttrBuild;
sub foo {}
$INC{'NoAttrBuild.pm'} = __FILE__;

package NoAttrGet;
sub build {}
$INC{'NoAttrGet.pm'} = __FILE__;

package NoAttrSet;
sub build {}
sub build_attr_get {}
$INC{'NoAttrSet.pm'} = __FILE__;

##############################################################################
# Create some simple classes.
##############################################################################

package Class::Meta::Testing;

BEGIN {
    my $cm = Class::Meta->new;
    $cm->add_constructor( name => 'new' );
    $cm->add_attribute( name => 'tail', type => 'string' );
    $cm->build;
}

package Class::Meta::TestAbstract;
@Class::Meta::TestAbstract::ISA = qw(Class::Meta::Testing);

BEGIN {
    my $cm = Class::Meta->new(abstract => 1);
    $cm->build;
}

package main;

##############################################################################
# Test Class::Meta errors.
eval { Class::Meta->new('foobar') };
chk('odd number to Class::Meta->new',
    qr/Odd number of parameters in call to new()/);

my $cm = Class::Meta->new( package => 'foobar' );
eval { Class::Meta->new( package => 'foobar' ) };

##############################################################################
# Test Class::Meta::Attribute errors.
eval { Class::Meta::Attribute->new };
chk('Attribute->new protected',
    qr/ cannot create Class::Meta::Attribute objects/);

eval { $cm->add_attribute('foo') };
chk('odd number to Class::Meta::Attribute->new',
    qr/Odd number of parameters in call to new()/);

eval { $cm->add_attribute(desc => 'foo') };
chk('Attribute name required',
    qr/Parameter 'name' is required in call to new()/);

eval { $cm->add_attribute(name => 'fo&o') };
chk('Invalid attribute name',
    qr/Attribute 'fo&o' is not a valid attribute name/);

# Create an attribute to use for a few tests. It's private so that there are
# no accessors.
ok( my $attr = $cm->add_attribute( name => 'foo',
                                   type => 'string',
                                   view => Class::Meta::PRIVATE),
    "Create 'foo' attribute");

eval { $cm->add_attribute( name => 'foo') };
chk('Attribute exists', qr/Attribute 'foo' already exists/);

for my $p (qw(view authz create context)) {
    eval { $cm->add_attribute( name => 'hey', $p => 100) };
    chk("Invalid Attribute $p", qr/Not a valid $p parameter: '100'/);
}

eval { $attr->get };
chk('No attribute get method', qr/Cannot get attribute 'foo'/);

eval { $attr->set };
chk('No attribute set method', qr/Cannot set attribute 'foo'/);

eval { $attr->build };
chk('Attribute->build protected',
    qr/ cannot call Class::Meta::Attribute->build/);

##############################################################################
# Test Class::Meta::Class errors.
eval { Class::Meta::Class->new };
chk('Class->new protected',
    qr/ cannot create Class::Meta::Class objects/);

eval { Class::Meta->new( package => 'foobar' ) };
chk('Duplicate class', qr/Class object for class 'foobar' already exists/);

eval { $cm->class->build };
chk('Class->build protected',
    qr/ cannot call Class::Meta::Class->build/);

##############################################################################
# Test Class::Meta::Constructor errors.
my $ctor = $cm->class->constructors('new');
eval { Class::Meta::Constructor->new };
chk('Constructor->new protected',
    qr/ cannot create Class::Meta::Constructor objects/);

eval { $cm->add_constructor('foo') };
chk('odd number to Class::Meta::Constructor->new',
    qr/Odd number of parameters in call to new()/);

eval { $cm->add_constructor(desc => 'foo') };
chk('Constructor name required',
    qr/Parameter 'name' is required in call to new()/);

eval { $cm->add_constructor(name => 'fo&o') };
chk('Invalid constructor name',
    qr/Constructor 'fo&o' is not a valid constructor name/);

# Create an constructor to use for a few tests. It's private so that it
# can't be called from here.
ok( $ctor = $cm->add_constructor( name => 'newer',
                                  view => Class::Meta::PRIVATE),
    "Create 'newer' constructor");

eval { $cm->add_constructor( name => 'newer') };
chk('Constructor exists', qr/Method 'newer' already exists/);

eval { $cm->add_constructor( name => 'hey', view => 100) };
chk("Invalid Constructor view", qr/Not a valid view parameter: '100'/);

eval { $cm->add_constructor( name => 'hey', caller => 100) };
chk("Invalid Constructor caller",
    qr/Parameter caller must be a code reference/);

eval { $ctor->call };
chk('Cannot call constructor', qr/Cannot call constructor 'newer'/);

eval { $ctor->build };
chk('Constructor->build protected',
    qr/ cannot call Class::Meta::Constructor->build/);

# Make sure that the actual constructor's own errors are thrown.
eval { Class::Meta::Testing->new( foo => 1 ) };
chk('Invalid parameter to generated constructor',
    qr/No such attribute 'foo' in Class::Meta::Testing objects/);

##############################################################################
# Test Class::Meta::Method errors.
eval { Class::Meta::Method->new };
chk('Method->new protected',
    qr/ cannot create Class::Meta::Method objects/);

eval { $cm->add_method('foo') };
chk('odd number to Class::Meta::Method->new',
    qr/Odd number of parameters in call to new()/);

eval { $cm->add_method(desc => 'foo') };
chk('Method name required',
    qr/Parameter 'name' is required in call to new()/);

eval { $cm->add_method(name => 'fo&o') };
chk('Invalid method name',
    qr/Method 'fo&o' is not a valid method name/);

# Create an method to use for a few tests. It's private so that it
# can't be called from here.
ok( my $meth = $cm->add_method( name => 'hail',
                                view => Class::Meta::PRIVATE),
    "Create 'hail' method");

eval { $cm->add_method( name => 'hail') };
chk('Method exists', qr/Method 'hail' already exists/);

for my $p (qw(view context)) {
    eval { $cm->add_method( name => 'hey', $p => 100) };
    chk("Invalid Method $p", qr/Not a valid $p parameter: '100'/);
}

eval { $cm->add_method( name => 'hey', caller => 100) };
chk("Invalid Method caller", qr/Parameter caller must be a code reference/);

eval { $meth->call };
chk('Cannot call method', qr/Cannot call method 'hail'/);

##############################################################################
# Test Class::Meta::Type errors.
eval { Class::Meta::Type->new };
chk(' Missing type', qr/Type argument required/);

eval { Class::Meta::Type->new('foo') };
chk('Invalid type', qr/Type 'foo' does not exist/);

eval { Class::Meta::Type->add };
chk('Type key required', qr/Parameter 'key' is required/);

eval { Class::Meta::Type->add( key => 'foo') };
chk('Type name required', qr/Parameter 'name' is required/);

eval { Class::Meta::Type->add( key => 'string', name => 'string' ) };
chk('Type already exists', qr/Type 'string' already defined/);

eval { Class::Meta::Type->add( key => 'foo', name => 'foo', check => {}) };
chk('Invalid type check',
    qr/Paremter 'check' in call to add\(\) must be a code reference/);

eval { Class::Meta::Type->add( key => 'foo', name => 'foo', check => [{}]) };
chk('Invalid type check array',
    qr/Paremter 'check' in call to add\(\) must be a code reference/);

eval {
    Class::Meta::Type->add( key => 'foo',
                            name => 'foo',
                            builder => 'NoAttrBuild');
};
chk('No build', qr/No such function 'NoAttrBuild::build\(\)'/);

eval {
    Class::Meta::Type->add( key => 'foo',
                            name => 'foo',
                            builder => 'NoAttrGet');
};
chk('No attr get', qr/No such function 'NoAttrGet::build_attr_get\(\)'/);

eval {
    Class::Meta::Type->add( key => 'foo',
                            name => 'foo',
                            builder => 'NoAttrSet');
};
chk('No attr set', qr/No such function 'NoAttrSet::build_attr_set\(\)'/);

eval { Class::Meta::Type->build };
chk('Type->build protected', qr/ cannot call Class::Meta::Type->build/);

eval { Class::Meta->default_error_handler('') };
chk('Bad error handler', qr/Error handler must be a code reference/);

# Make sure we get an error for invalid class error handlers.
eval { Class::Meta->new(error_handler => '') };
chk('Class cannot have invalid error handler',
    qr/Error handler must be a code reference/);

my $foo;
Class::Meta->default_error_handler(sub { $foo = shift });

# Some places still use the default, of course.
eval {
    Class::Meta::Type->add( key => 'foo',
                            name => 'foo',
                            builder => 'NoAttrSet');
};
like( $foo, qr/No such function 'NoAttrSet::build_attr_set\(\)'/,
      "New error handler");

# Others muse use the original, since the class object was defined before
# we set up the new default.
eval { $cm->class->build };
chk('Class->build still protected',
    qr/ cannot call Class::Meta::Class->build/);

# Test the abstract attribute.
is( Class::Meta::Testing->my_class->abstract, 0,
    "Testing class isn't abstract" );
is( Class::Meta::TestAbstract->my_class->abstract, 1,
    "TestAbstract class isn't abstract" );

eval { Class::Meta::TestAbstract->new };
chk( 'Cannot create from abstract class',
     qr/^Cannot construct objects of astract class Class::Meta::TestAbstract/);

##############################################################################
# This function handles all the tests.
##############################################################################
sub chk {
    my ($name, $qr) = @_;
    # Catch the exception.
    ok( my $err = $@, "Caught $name error" );
    # Check its message.
    like( $err, $qr, "Correct error" );
    # Make sure it refers to this file.
    like( $err, qr/(?:at\s+\Q$fn\E|\Q$fn\E\s+at)\s+line/, 'Correct context' );
    # Make sure it doesn't refer to other Class::Meta files.
    unlike( $err, qr|lib/Class/Meta|, 'Not incorrect context')
}