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