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