Add permanent plumbing for _TempExtlib (d0435d75)
[dbsrgits/DBIx-Class.git] / xt / extra / internals / optional_deps.t
1 my ($inc_before, $inc_after);
2 BEGIN {
3   $inc_before = [ keys %INC ];
4   require DBIx::Class::Optional::Dependencies;
5   $inc_after = [ keys %INC ];
6 }
7
8 use strict;
9 use warnings;
10 no warnings qw/once/;
11
12 use Test::More;
13 use Test::Exception;
14
15 # load before we break require()
16 use Scalar::Util();
17 use MRO::Compat();
18 use Carp 'confess';
19 use List::Util 'shuffle';
20 use Config;
21
22 SKIP: {
23   skip 'Lean load pattern testing makes no sense with TempExtlib', 1
24     if grep { $_ =~ /TempExtlib/ } @INC;
25
26   skip 'Lean load pattern testing unsafe with $ENV{PERL5OPT}', 1
27     if $ENV{PERL5OPT};
28
29   skip 'Lean load pattern testing unsafe with sitecustomize.pl', 1
30     if grep { $_ =~ m| \/ sitecustomize\.pl $ |x } keys %INC;
31
32   skip 'Lean load pattern testing useless with $ENV{RELEASE_TESTING}', 1
33     if $ENV{RELEASE_TESTING};
34
35   skip 'Lean load pattern testing useless under cperl', 1
36     if $Config{usecperl};
37
38   is_deeply
39     $inc_before,
40     [],
41     'Nothing was loaded before inc-test'
42   ;
43   is_deeply
44     $inc_after,
45     [ 'DBIx/Class/Optional/Dependencies.pm' ],
46     'Nothing was loaded other than DBIx::Class::OptDeps'
47   ;
48 }
49
50 # check the project-local groups for sanity
51 lives_ok {
52   DBIx::Class::Optional::Dependencies->req_group_list
53 } "The entire optdep list is well formed";
54
55 is_deeply (
56   [ keys %{ DBIx::Class::Optional::Dependencies->req_list_for ('deploy') } ],
57   [ 'SQL::Translator' ],
58   'Correct deploy() dependency list',
59 );
60
61 # scope to break require()
62 {
63
64 # make module loading impossible, regardless of actual libpath contents
65   local @INC;
66
67 # basic test using the deploy target
68   for ('deploy', ['deploy']) {
69
70     # explicitly blow up cache
71     %DBIx::Class::Optional::Dependencies::req_unavailability_cache = ();
72
73     ok (
74       ! DBIx::Class::Optional::Dependencies->req_ok_for ($_),
75       'deploy() deps missing',
76     );
77
78     like (
79       DBIx::Class::Optional::Dependencies->modreq_missing_for ($_),
80       qr/
81         \A
82         SQL::Translator \~ [\d\.]+
83         \z
84       /x,
85       'expected modreq missing string contents',
86     );
87
88     like (
89       DBIx::Class::Optional::Dependencies->req_missing_for ($_),
90       qr/
91         \A
92         SQL::Translator \~ [\d\.]+
93         \Q (see DBIx::Class::Optional::Dependencies documentation for details)\E
94         \z
95       /x,
96       'expected missing string contents',
97     );
98
99     like (
100       DBIx::Class::Optional::Dependencies->modreq_errorlist_for ($_)->{'SQL::Translator'},
101       qr|\QCan't locate SQL/Translator.pm|,
102       'correct "unable to locate"  exception found in errorlist',
103     );
104
105     #make it so module appears loaded
106     local $INC{'SQL/Translator.pm'} = 1;
107     local $SQL::Translator::VERSION = 999;
108
109     ok (
110       ! DBIx::Class::Optional::Dependencies->req_ok_for ($_),
111       'deploy() deps missing cached properly from previous run',
112     );
113
114     # blow cache again
115     %DBIx::Class::Optional::Dependencies::req_unavailability_cache = ();
116
117     ok (
118       DBIx::Class::Optional::Dependencies->req_ok_for ($_),
119       'deploy() deps present',
120     );
121
122     is (
123       DBIx::Class::Optional::Dependencies->req_missing_for ($_),
124       '',
125       'expected null missing string',
126     );
127
128     is_deeply (
129       # use the deprecated method name
130       DBIx::Class::Optional::Dependencies->req_errorlist_for ($_),
131       undef,
132       'expected empty errorlist',
133     );
134   }
135
136 # test single-db text
137   local $ENV{DBICTEST_MYSQL_DSN};
138   is_deeply(
139     DBIx::Class::Optional::Dependencies->req_list_for('test_rdbms_mysql'),
140     undef,
141     'unknown optional dependencies list for testing MySQL without ENV var',
142   );
143   is_deeply(
144     DBIx::Class::Optional::Dependencies->modreq_list_for('test_rdbms_mysql'),
145     { 'DBD::mysql' => 0 },
146     'correct optional module dependencies list for testing MySQL without ENV var',
147   );
148
149   local $ENV{DBICTEST_MYSQL_DSN};
150   local $ENV{DBICTEST_PG_DSN};
151
152 # regular
153   is_deeply(
154     DBIx::Class::Optional::Dependencies->modreq_list_for([shuffle qw( test_rdbms_pg binary_data )]),
155     { 'DBD::Pg' => '2.009002' },
156     'optional dependencies list for testing Postgres without envvar',
157   );
158
159   is_deeply(
160     DBIx::Class::Optional::Dependencies->req_list_for([shuffle qw( test_rdbms_pg binary_data )]),
161     undef,
162     'optional dependencies list for testing Postgres without envvar',
163   );
164
165   is_deeply(
166     DBIx::Class::Optional::Dependencies->req_list_for('rdbms_pg'),
167     { 'DBD::Pg' => '0', },
168     'optional dependencies list for using Postgres matches',
169   );
170
171   is_deeply(
172     DBIx::Class::Optional::Dependencies->req_missing_for('rdbms_pg'),
173     'DBD::Pg (see DBIx::Class::Optional::Dependencies documentation for details)',
174     'optional dependencies missing list for using Postgres matches',
175   );
176
177 # test combination of different requirements on same module (pg's are relatively stable)
178   is_deeply (
179     DBIx::Class::Optional::Dependencies->req_list_for([shuffle qw( rdbms_pg test_rdbms_pg )]),
180     { 'DBD::Pg' => '0' },
181     'optional module dependencies list for testing Postgres matches without envvar',
182   );
183
184   is(
185     DBIx::Class::Optional::Dependencies->req_missing_for([shuffle qw( rdbms_pg test_rdbms_pg binary_data )]),
186     'DBD::Pg~2.009002 as well as the following group(s) of environment variables: DBICTEST_PG_DSN/..._USER/..._PASS',
187     'optional dependencies for testing Postgres without envvar'
188   );
189
190   is(
191     DBIx::Class::Optional::Dependencies->req_missing_for([shuffle qw( test_rdbms_mysql test_rdbms_pg binary_data)]),
192     'DBD::mysql DBD::Pg~2.009002 as well as the following group(s) of environment variables: DBICTEST_MYSQL_DSN/..._USER/..._PASS and DBICTEST_PG_DSN/..._USER/..._PASS',
193     'optional dependencies for testing Postgres+MySQL without envvars'
194   );
195
196   $ENV{DBICTEST_PG_DSN} = 'boo';
197   is_deeply (
198     DBIx::Class::Optional::Dependencies->modreq_list_for([shuffle qw( rdbms_pg test_rdbms_pg binary_data)]),
199     { 'DBD::Pg' => '2.009002' },
200     'optional module dependencies list for testing Postgres matches with envvar',
201   );
202
203   is(
204     DBIx::Class::Optional::Dependencies->req_missing_for([shuffle qw( rdbms_pg test_rdbms_pg binary_data )]),
205     'DBD::Pg~2.009002',
206     'optional dependencies error text for testing Postgres matches with evvar',
207   );
208
209 # ICDT augmentation
210   my %expected_icdt_base = ( DateTime => '0.55', 'DateTime::TimeZone::OlsonDB' => 0 );
211
212   my $mysql_icdt = [shuffle qw( test_rdbms_mysql ic_dt )];
213
214   is_deeply(
215     DBIx::Class::Optional::Dependencies->modreq_list_for($mysql_icdt),
216     {
217       %expected_icdt_base,
218       'DBD::mysql' => 0,
219       'DateTime::Format::MySQL' => 0,
220     },
221     'optional module dependencies list for testing ICDT MySQL without envvar',
222   );
223
224   is_deeply(
225     DBIx::Class::Optional::Dependencies->req_list_for($mysql_icdt),
226     \%expected_icdt_base,
227     'optional dependencies list for testing ICDT MySQL without envvar',
228   );
229
230   is(
231     DBIx::Class::Optional::Dependencies->req_missing_for($mysql_icdt),
232     "DateTime~0.55 DateTime::Format::MySQL DateTime::TimeZone::OlsonDB DBD::mysql as well as the following group(s) of environment variables: DBICTEST_MYSQL_DSN/..._USER/..._PASS",
233     'missing optional dependencies for testing ICDT MySQL without envvars'
234   );
235
236 # test multi-level include with a variable and mandatory part converging on same included dep
237   local $ENV{DBICTEST_MSACCESS_ODBC_DSN};
238   local $ENV{DBICTEST_MSSQL_ODBC_DSN} = 'foo';
239   my $msaccess_mssql_icdt = [ shuffle qw( test_rdbms_msaccess_odbc test_rdbms_mssql_odbc ic_dt ) ];
240   is_deeply(
241     DBIx::Class::Optional::Dependencies->req_missing_for($msaccess_mssql_icdt),
242     'Data::GUID DateTime~0.55 DateTime::Format::Strptime~1.2 DateTime::TimeZone::OlsonDB DBD::ODBC as well as the following group(s) of environment variables: DBICTEST_MSACCESS_ODBC_DSN/..._USER/..._PASS',
243     'Correct req_missing_for on multi-level converging include',
244   );
245
246   is_deeply(
247     DBIx::Class::Optional::Dependencies->modreq_missing_for($msaccess_mssql_icdt),
248     'Data::GUID DateTime~0.55 DateTime::Format::Strptime~1.2 DateTime::TimeZone::OlsonDB DBD::ODBC',
249     'Correct modreq_missing_for on multi-level converging include',
250   );
251
252   is_deeply(
253     DBIx::Class::Optional::Dependencies->req_list_for($msaccess_mssql_icdt),
254     {
255       'DBD::ODBC' => 0,
256       'DateTime::Format::Strptime' => '1.2',
257       %expected_icdt_base,
258     },
259     'Correct req_list_for on multi-level converging include',
260   );
261
262   is_deeply(
263     DBIx::Class::Optional::Dependencies->modreq_list_for($msaccess_mssql_icdt),
264     {
265       'DBD::ODBC' => 0,
266       'Data::GUID' => 0,
267       'DateTime::Format::Strptime' => '1.2',
268       %expected_icdt_base,
269     },
270     'Correct modreq_list_for on multi-level converging include',
271   );
272
273 }
274
275 # test multiple times to find autovivification bugs
276 for my $meth (qw(req_list_for modreq_list_for)) {
277   throws_ok {
278     DBIx::Class::Optional::Dependencies->$meth();
279   } qr/\Qreq_list_for() expects a requirement group name/,
280   "$meth without groupname throws exception";
281
282   throws_ok {
283     DBIx::Class::Optional::Dependencies->$meth('');
284   } qr/\Q$meth() expects a requirement group name/,
285   "$meth with empty groupname throws exception";
286
287   throws_ok {
288     DBIx::Class::Optional::Dependencies->$meth('invalid_groupname');
289   } qr/Requirement group 'invalid_groupname' is not defined/,
290   "$meth with invalid groupname throws exception";
291 }
292
293 done_testing;