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