include test for failure mode
[catagits/Catalyst-Runtime.git] / t / unit_core_component_loading.t
CommitLineData
0756fe3b 1# 2 initial tests, and 6 per component in the loop below
2# (do not forget to update the number of components in test 3 as well)
b94b200c 3# 5 extra tests for the loading options
4use Test::More tests => 2 + 6 * 24 + 5;
0756fe3b 5
6use strict;
7use warnings;
8
9use File::Spec;
10use File::Path;
11
f27f2c6d 12use Test::MockObject;
13
0756fe3b 14my $libdir = 'test_trash';
15unshift(@INC, $libdir);
16
17my $appclass = 'TestComponents';
18my @components = (
19 { type => 'Controller', prefix => 'C', name => 'Bar' },
20 { type => 'Controller', prefix => 'C', name => 'Foo::Bar' },
21 { type => 'Controller', prefix => 'C', name => 'Foo::Foo::Bar' },
22 { type => 'Controller', prefix => 'C', name => 'Foo::Foo::Foo::Bar' },
23 { type => 'Controller', prefix => 'Controller', name => 'Bar::Bar::Bar::Foo' },
24 { type => 'Controller', prefix => 'Controller', name => 'Bar::Bar::Foo' },
25 { type => 'Controller', prefix => 'Controller', name => 'Bar::Foo' },
26 { type => 'Controller', prefix => 'Controller', name => 'Foo' },
27 { type => 'Model', prefix => 'M', name => 'Bar' },
28 { type => 'Model', prefix => 'M', name => 'Foo::Bar' },
29 { type => 'Model', prefix => 'M', name => 'Foo::Foo::Bar' },
30 { type => 'Model', prefix => 'M', name => 'Foo::Foo::Foo::Bar' },
31 { type => 'Model', prefix => 'Model', name => 'Bar::Bar::Bar::Foo' },
32 { type => 'Model', prefix => 'Model', name => 'Bar::Bar::Foo' },
33 { type => 'Model', prefix => 'Model', name => 'Bar::Foo' },
34 { type => 'Model', prefix => 'Model', name => 'Foo' },
35 { type => 'View', prefix => 'V', name => 'Bar' },
36 { type => 'View', prefix => 'V', name => 'Foo::Bar' },
37 { type => 'View', prefix => 'V', name => 'Foo::Foo::Bar' },
38 { type => 'View', prefix => 'V', name => 'Foo::Foo::Foo::Bar' },
39 { type => 'View', prefix => 'View', name => 'Bar::Bar::Bar::Foo' },
40 { type => 'View', prefix => 'View', name => 'Bar::Bar::Foo' },
41 { type => 'View', prefix => 'View', name => 'Bar::Foo' },
42 { type => 'View', prefix => 'View', name => 'Foo' },
43);
44
ac5c933b 45sub write_component_file {
b94b200c 46 my ($dir_list, $module_name, $content) = @_;
47
48 my $dir = File::Spec->catdir(@$dir_list);
49 my $file = File::Spec->catfile($dir, $module_name . '.pm');
50
51 mkpath(join(q{/}, @$dir_list) );
52 open(my $fh, '>', $file) or die "Could not open file $file for writing: $!";
53 print $fh $content;
54 close $fh;
55}
56
0756fe3b 57sub make_component_file {
58 my ($type, $prefix, $name) = @_;
59
60 my $compbase = "Catalyst::${type}";
61 my $fullname = "${appclass}::${prefix}::${name}";
62 my @namedirs = split(/::/, $name);
63 my $name_final = pop(@namedirs);
64 my @dir_list = ($libdir, $appclass, $prefix, @namedirs);
0756fe3b 65
b94b200c 66 write_component_file(\@dir_list, $name_final, <<EOF);
0756fe3b 67package $fullname;
f27f2c6d 68use MRO::Compat;
0756fe3b 69use base '$compbase';
70sub COMPONENT {
dbb2d5cd 71 my \$self = shift->next::method(\@_);
0756fe3b 72 no strict 'refs';
73 *{\__PACKAGE__ . "::whoami"} = sub { return \__PACKAGE__; };
74 \$self;
75}
761;
77
78EOF
0756fe3b 79}
80
81foreach my $component (@components) {
82 make_component_file($component->{type},
83 $component->{prefix},
84 $component->{name});
85}
86
f27f2c6d 87my $shut_up_deprecated_warnings = q{
88 use Test::MockObject;
89 my $old_logger = __PACKAGE__->log;
90 my $logger = Test::MockObject->new;
91 $logger->mock('warn', sub {
92 my $self = shift;
93 return if $_[0] =~ /deprecated/;
94 $old_logger->warn(@_);
95 });
96 __PACKAGE__->log($logger);
97};
98
99eval "package $appclass; use Catalyst; $shut_up_deprecated_warnings __PACKAGE__->setup";
0756fe3b 100
101can_ok( $appclass, 'components');
102
103my $complist = $appclass->components;
104
105# the +1 below is for the app class itself
106is(scalar keys %$complist, 24+1, "Correct number of components loaded");
107
108foreach (keys %$complist) {
109
110 # Skip the component which happens to be the app itself
111 next if $_ eq $appclass;
112
113 my $instance = $appclass->component($_);
114 isa_ok($instance, $_);
115 can_ok($instance, 'whoami');
116 is($instance->whoami, $_);
117
118 if($_ =~ /^${appclass}::(?:V|View)::(.*)/) {
119 my $moniker = $1;
120 isa_ok($instance, 'Catalyst::View');
121 can_ok($appclass->view($moniker), 'whoami');
122 is($appclass->view($moniker)->whoami, $_);
123 }
124 elsif($_ =~ /^${appclass}::(?:M|Model)::(.*)/) {
125 my $moniker = $1;
126 isa_ok($instance, 'Catalyst::Model');
127 can_ok($appclass->model($moniker), 'whoami');
128 is($appclass->model($moniker)->whoami, $_);
129 }
130 elsif($_ =~ /^${appclass}::(?:C|Controller)::(.*)/) {
131 my $moniker = $1;
132 isa_ok($instance, 'Catalyst::Controller');
133 can_ok($appclass->controller($moniker), 'whoami');
134 is($appclass->controller($moniker)->whoami, $_);
135 }
136 else {
137 die "Something is wrong with this test, this should"
138 . " have been unreachable";
139 }
140}
141
142rmtree($libdir);
18de900e 143
144# test extra component loading options
145
146$appclass = 'ExtraOptions';
147push @components, { type => 'View', prefix => 'Extra', name => 'Foo' };
148
149foreach my $component (@components) {
150 make_component_file($component->{type},
151 $component->{prefix},
152 $component->{name});
153}
154
155eval qq(
156package $appclass;
157use Catalyst;
f27f2c6d 158$shut_up_deprecated_warnings
18de900e 159__PACKAGE__->config->{ setup_components } = {
160 search_extra => [ '::Extra' ],
161 except => [ "${appclass}::Controller::Foo" ]
162};
163__PACKAGE__->setup;
164);
165
166can_ok( $appclass, 'components');
167
168$complist = $appclass->components;
169
170is(scalar keys %$complist, 24+1, "Correct number of components loaded");
171
2d486591 172ok( !exists $complist->{ "${appclass}::Controller::Foo" }, 'Controller::Foo was skipped' );
173ok( exists $complist->{ "${appclass}::Extra::Foo" }, 'Extra::Foo was loaded' );
18de900e 174
b94b200c 175rmtree($libdir);
176
177$appclass = "ComponentOnce";
178
179write_component_file([$libdir, $appclass, 'Model'], 'TopLevel', <<EOF);
180package ${appclass}::Model::TopLevel;
181use base 'Catalyst::Model';
182sub COMPONENT {
ac5c933b 183
dbb2d5cd 184 my \$self = shift->next::method(\@_);
b94b200c 185 no strict 'refs';
186 *{\__PACKAGE__ . "::whoami"} = sub { return \__PACKAGE__; };
187 \$self;
188}
189
190package ${appclass}::Model::TopLevel::Nested;
191
192sub COMPONENT { die "COMPONENT called in the wrong order!"; }
193
1941;
195
196EOF
197
198write_component_file([$libdir, $appclass, 'Model', 'TopLevel'], 'Nested', <<EOF);
199package ${appclass}::Model::TopLevel::Nested;
200use base 'Catalyst::Model';
201
202no warnings 'redefine';
dbb2d5cd 203sub COMPONENT { return shift->next::method(\@_); }
b94b200c 2041;
205
206EOF
207
208eval "package $appclass; use Catalyst; __PACKAGE__->setup";
209
210is($@, '', "Didn't load component twice");
211
212rmtree($libdir);