Streamline BYTEA (binary) Pg optdeps using the new augmentation system
[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([shuffle qw( test_rdbms_pg binary_data )]),
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([shuffle qw( test_rdbms_pg binary_data )]),
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([shuffle qw( rdbms_pg test_rdbms_pg binary_data )]),
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 binary_data)]),
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 binary_data)]),
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 binary_data )]),
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       %expected_icdt_base,
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     \%expected_icdt_base,
213     'optional dependencies list for testing ICDT MySQL without envvar',
214   );
215
216   is(
217     DBIx::Class::Optional::Dependencies->req_missing_for($mysql_icdt),
218     "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",
219     'missing optional dependencies for testing ICDT MySQL without envvars'
220   );
221
222 # test multi-level include with a variable and mandatory part converging on same included dep
223   local $ENV{DBICTEST_MSACCESS_ODBC_DSN};
224   local $ENV{DBICTEST_MSSQL_ODBC_DSN} = 'foo';
225   my $msaccess_mssql_icdt = [ shuffle qw( test_rdbms_msaccess_odbc test_rdbms_mssql_odbc ic_dt ) ];
226   is_deeply(
227     DBIx::Class::Optional::Dependencies->req_missing_for($msaccess_mssql_icdt),
228     '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',
229     'Correct req_missing_for on multi-level converging include',
230   );
231
232   is_deeply(
233     DBIx::Class::Optional::Dependencies->modreq_missing_for($msaccess_mssql_icdt),
234     'Data::GUID DateTime~0.55 DateTime::Format::Strptime~1.2 DateTime::TimeZone::OlsonDB DBD::ODBC',
235     'Correct modreq_missing_for on multi-level converging include',
236   );
237
238   is_deeply(
239     DBIx::Class::Optional::Dependencies->req_list_for($msaccess_mssql_icdt),
240     {
241       'DBD::ODBC' => 0,
242       'DateTime::Format::Strptime' => '1.2',
243       %expected_icdt_base,
244     },
245     'Correct req_list_for on multi-level converging include',
246   );
247
248   is_deeply(
249     DBIx::Class::Optional::Dependencies->modreq_list_for($msaccess_mssql_icdt),
250     {
251       'DBD::ODBC' => 0,
252       'Data::GUID' => 0,
253       'DateTime::Format::Strptime' => '1.2',
254       %expected_icdt_base,
255     },
256     'Correct modreq_list_for on multi-level converging include',
257   );
258
259 }
260
261 # test multiple times to find autovivification bugs
262 for my $meth (qw(req_list_for modreq_list_for)) {
263   throws_ok {
264     DBIx::Class::Optional::Dependencies->$meth();
265   } qr/\Qreq_list_for() expects a requirement group name/,
266   "$meth without groupname throws exception";
267
268   throws_ok {
269     DBIx::Class::Optional::Dependencies->$meth('');
270   } qr/\Q$meth() expects a requirement group name/,
271   "$meth with empty groupname throws exception";
272
273   throws_ok {
274     DBIx::Class::Optional::Dependencies->$meth('invalid_groupname');
275   } qr/Requirement group 'invalid_groupname' is not defined/,
276   "$meth with invalid groupname throws exception";
277 }
278
279 done_testing;