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