chiark / gitweb /
lib/dpkg/tarfn.c: Kludge `tar_header_decode' to handle spurious `errno'.
[dpkg] / scripts / t / Dpkg_Deps.t
1 #!/usr/bin/perl
2 #
3 # This program is free software; you can redistribute it and/or modify
4 # it under the terms of the GNU General Public License as published by
5 # the Free Software Foundation; either version 2 of the License, or
6 # (at your option) any later version.
7 #
8 # This program is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 # GNU General Public License for more details.
12 #
13 # You should have received a copy of the GNU General Public License
14 # along with this program.  If not, see <https://www.gnu.org/licenses/>.
15
16 use strict;
17 use warnings;
18
19 use Test::More tests => 70;
20
21 use Dpkg::Arch qw(get_host_arch);
22 use Dpkg::Version;
23
24 use_ok('Dpkg::Deps');
25
26 is(deps_concat(), '', 'Concatenate an empty list');
27 is(deps_concat(undef), '', 'Concatenate list with undef');
28 is(deps_concat(''), '', 'Concatenate an empty string');
29 is(deps_concat('', undef), '', 'Concatenate empty string with undef');
30 is(deps_concat('dep-a', undef, 'dep-b'), 'dep-a, dep-b',
31    'Concatenate two strings with intermixed undef');
32
33 sub test_dep_parse_option {
34     my %options = @_;
35
36     eval {
37         my $dep_croak = deps_parse('pkg', %options);
38     };
39     my $options = join ' ', map { "$_=$options{$_}" } keys %options;
40     ok(defined $@, "Parse with bogus arch options $options");
41 }
42
43 test_dep_parse_option(host_arch => 'all');
44 test_dep_parse_option(host_arch => 'any');
45 test_dep_parse_option(host_arch => 'linux-any');
46 test_dep_parse_option(host_arch => 'unknown-arch');
47 test_dep_parse_option(build_arch => 'all');
48 test_dep_parse_option(build_arch => 'any');
49 test_dep_parse_option(build_arch => 'linux-any');
50 test_dep_parse_option(build_arch => 'unknown-arch');
51
52 my $field_multiline = ' , , libgtk2.0-common (= 2.10.13-1)  , libatk1.0-0 (>=
53 1.13.2), libc6 (>= 2.5-5), libcairo2 (>= 1.4.0), libcupsys2 (>= 1.2.7),
54 libfontconfig1 (>= 2.4.0), libglib2.0-0  (  >= 2.12.9), libgnutls13 (>=
55 1.6.3-0), libjpeg62, python (<< 2.5) , , ';
56 my $field_multiline_sorted = 'libatk1.0-0 (>= 1.13.2), libc6 (>= 2.5-5), libcairo2 (>= 1.4.0), libcupsys2 (>= 1.2.7), libfontconfig1 (>= 2.4.0), libglib2.0-0 (>= 2.12.9), libgnutls13 (>= 1.6.3-0), libgtk2.0-common (= 2.10.13-1), libjpeg62, python (<< 2.5)';
57
58 my $dep_multiline = deps_parse($field_multiline);
59 $dep_multiline->sort();
60 is($dep_multiline->output(), $field_multiline_sorted, 'Parse, sort and output');
61
62 my $dep_sorted = deps_parse('pkgz, pkgz | pkgb, pkgz | pkga, pkga (>= 1.0), pkgz (<= 2.0)');
63 $dep_sorted->sort();
64 is($dep_sorted->output(), 'pkga (>= 1.0), pkgz, pkgz | pkga, pkgz | pkgb, pkgz (<= 2.0)', 'Check sort() algorithm');
65
66 my $dep_subset = deps_parse('libatk1.0-0 (>> 1.10), libc6, libcairo2');
67 is($dep_multiline->implies($dep_subset), 1, 'Dep implies subset of itself');
68 is($dep_subset->implies($dep_multiline), undef, "Subset doesn't imply superset");
69 my $dep_opposite = deps_parse('python (>= 2.5)');
70 is($dep_opposite->implies($dep_multiline), 0, 'Opposite condition implies NOT the depends');
71
72 my $dep_or1 = deps_parse('a|b (>=1.0)|c (>= 2.0)');
73 my $dep_or2 = deps_parse('x|y|a|b|c (<= 0.5)|c (>=1.5)|d|e');
74 is($dep_or1->implies($dep_or2), 1, 'Implication between OR 1/2');
75 is($dep_or2->implies($dep_or1), undef, 'Implication between OR 2/2');
76
77 my $dep_ma_host = deps_parse('libcairo2');
78 my $dep_ma_any = deps_parse('libcairo2:any');
79 my $dep_ma_build = deps_parse('libcairo2:native', build_dep => 1);
80 my $dep_ma_explicit = deps_parse('libcairo2:amd64');
81 is($dep_ma_host->implies($dep_ma_any), undef, 'foo !-> foo:any');
82 is($dep_ma_build->implies($dep_ma_any), undef, 'foo:native !-> foo:any');
83 is($dep_ma_explicit->implies($dep_ma_any), undef, 'foo:<arch> !-> foo:any');
84 is($dep_ma_any->implies($dep_ma_host), undef, 'foo:any !-> foo');
85 is($dep_ma_any->implies($dep_ma_build), undef, 'foo:any !-> foo:native');
86 is($dep_ma_any->implies($dep_ma_explicit), undef, 'foo:any !-> foo:<arch>');
87 is($dep_ma_host->implies($dep_ma_host), 1, 'foo -> foo');
88 is($dep_ma_any->implies($dep_ma_any), 1, 'foo:any -> foo:any');
89 is($dep_ma_build->implies($dep_ma_build), 1, 'foo:native -> foo:native');
90 is($dep_ma_explicit->implies($dep_ma_explicit), 1, 'foo:<arch>-> foo:<arch>');
91
92 my $field_tests = 'self, @, @builddeps@';
93 $SIG{__WARN__} = sub {};
94 my $dep_tests_fail = deps_parse($field_tests);
95 is($dep_tests_fail, undef, 'normal deps with @ in pkgname');
96 delete $SIG{__WARN__};
97 my $dep_tests_pass = deps_parse($field_tests, tests_dep => 1);
98 is($dep_tests_pass->output(), $field_tests, 'tests deps with @ in pkgname');
99
100 my $field_arch = 'libc6 (>= 2.5) [!alpha !hurd-i386], libc6.1 [alpha], libc0.1 [hurd-i386]';
101 my $dep_i386 = deps_parse($field_arch, reduce_arch => 1, host_arch => 'i386');
102 my $dep_alpha = deps_parse($field_arch, reduce_arch => 1, host_arch => 'alpha');
103 my $dep_hurd = deps_parse($field_arch, reduce_arch => 1, host_arch => 'hurd-i386');
104 is($dep_i386->output(), 'libc6 (>= 2.5)', 'Arch reduce 1/3');
105 is($dep_alpha->output(), 'libc6.1', 'Arch reduce 2/3');
106 is($dep_hurd->output(), 'libc0.1', 'Arch reduce 3/3');
107
108 my $field_profile = 'dep1 <!stage1 !nocheck>, ' .
109 'dep2 <stage1 !nocheck>, ' .
110 'dep3 <nocheck !stage1>, ' .
111 'dep4 <stage1 nocheck>, ' .
112 'dep5 <stage1>, dep6 <!stage1>, ' .
113 'dep7 <stage1> | dep8 <nocheck>, ' .
114 'dep9 <!stage1> <!nocheck>, ' .
115 'dep10 <stage1> <!nocheck>, ' .
116 'dep11 <stage1> <nocheck>, '.
117 'dep12 <!nocheck> <!stage1>, ' .
118 'dep13 <nocheck> <!stage1>, ' .
119 'dep14 <nocheck> <stage1>';
120 my $dep_noprof = deps_parse($field_profile, reduce_profiles => 1, build_profiles => []);
121 my $dep_stage1 = deps_parse($field_profile, reduce_profiles => 1, build_profiles => ['stage1']);
122 my $dep_nocheck = deps_parse($field_profile, reduce_profiles => 1, build_profiles => ['nocheck']);
123 my $dep_stage1nocheck = deps_parse($field_profile, reduce_profiles => 1, build_profiles => ['stage1', 'nocheck']);
124 is($dep_noprof->output(), 'dep1, dep6, dep9, dep10, dep12, dep13', 'Profile reduce 1/4');
125 is($dep_stage1->output(), 'dep2, dep5, dep7, dep9, dep10, dep11, dep12, dep14', 'Profile reduce 2/4');
126 is($dep_nocheck->output(), 'dep3, dep6, dep8, dep9, dep11, dep12, dep13, dep14', 'Profile reduce 3/4');
127 is($dep_stage1nocheck->output(), 'dep4, dep5, dep7 | dep8, dep10, dep11, dep13, dep14', 'Profile reduce 4/4');
128
129 $dep_noprof = deps_parse($field_profile);
130 $dep_noprof->reduce_profiles([]);
131 $dep_stage1 = deps_parse($field_profile);
132 $dep_stage1->reduce_profiles(['stage1']);
133 $dep_nocheck = deps_parse($field_profile);
134 $dep_nocheck->reduce_profiles(['nocheck']);
135 $dep_stage1nocheck = deps_parse($field_profile);
136 $dep_stage1nocheck->reduce_profiles(['stage1', 'nocheck']);
137 is($dep_noprof->output(), 'dep1, dep6, dep9, dep10, dep12, dep13', 'Profile post-reduce 1/4');
138 is($dep_stage1->output(), 'dep2, dep5, dep7, dep9, dep10, dep11, dep12, dep14', 'Profile post-reduce 2/4');
139 is($dep_nocheck->output(), 'dep3, dep6, dep8, dep9, dep11, dep12, dep13, dep14', 'Profile post-reduce 3/4');
140 is($dep_stage1nocheck->output(), 'dep4, dep5, dep7 | dep8, dep10, dep11, dep13, dep14', 'Profile post-reduce 4/4');
141
142 my $field_restrict = 'dep1 <!bootstrap !restrict>, ' .
143 'dep2 <bootstrap restrict>, ' .
144 'dep3 <!restrict>, ' .
145 'dep4 <restrict>, ' .
146 'dep5 <!bootstrap> <!restrict>, ' .
147 'dep6 <bootstrap> <restrict>';
148 my $dep_restrict = deps_parse($field_restrict, reduce_restrictions => 1, build_profiles => []);
149 is($dep_restrict->output(), 'dep1, dep3, dep5', 'Unknown restrictions reduce');
150
151 $dep_restrict = deps_parse($field_restrict);
152 $dep_restrict->reduce_profiles([]);
153 is($dep_restrict->output(), 'dep1, dep3, dep5', 'Unknown restrictions post-reduce');
154
155 my $facts = Dpkg::Deps::KnownFacts->new();
156 $facts->add_installed_package('mypackage', '1.3.4-1', get_host_arch(), 'no');
157 $facts->add_installed_package('mypackage2', '1.3.4-1', 'somearch', 'no');
158 $facts->add_installed_package('pkg-ma-foreign', '1.3.4-1', 'somearch', 'foreign');
159 $facts->add_installed_package('pkg-ma-foreign2', '1.3.4-1', get_host_arch(), 'foreign');
160 $facts->add_installed_package('pkg-ma-allowed', '1.3.4-1', 'somearch', 'allowed');
161 $facts->add_installed_package('pkg-ma-allowed2', '1.3.4-1', 'somearch', 'allowed');
162 $facts->add_installed_package('pkg-ma-allowed3', '1.3.4-1', get_host_arch(), 'allowed');
163 $facts->add_provided_package('myvirtual', undef, undef, 'mypackage');
164 $facts->add_provided_package('myvirtual2', REL_EQ, '1.0-1', 'mypackage');
165 $facts->add_provided_package('myvirtual3', REL_GE, '2.0-1', 'mypackage');
166
167 my $field_duplicate = 'libc6 (>= 2.3), libc6 (>= 2.6-1), mypackage (>=
168 1.3), myvirtual | something, python (>= 2.5), mypackage2, pkg-ma-foreign,
169 pkg-ma-foreign2, pkg-ma-allowed:any, pkg-ma-allowed2, pkg-ma-allowed3';
170 my $dep_dup = deps_parse($field_duplicate);
171 $dep_dup->simplify_deps($facts, $dep_opposite);
172 is($dep_dup->output(), 'libc6 (>= 2.6-1), mypackage2, pkg-ma-allowed2', 'Simplify deps');
173
174 my $field_virtual = 'myvirtual | other';
175 my $dep_virtual = deps_parse($field_virtual);
176 $dep_virtual->simplify_deps($facts);
177 is($dep_virtual->output(), '',
178    'Simplify unversioned depends with unversioned virtual (satisfied)');
179
180 $field_virtual = 'myvirtual (>= 1.0) | other';
181 $dep_virtual = deps_parse($field_virtual);
182 $dep_virtual->simplify_deps($facts);
183 is($dep_virtual->output(), 'myvirtual (>= 1.0) | other',
184    'Simplify versioned depends on unversioned virtual (unsatisfied)');
185
186 $field_virtual = 'myvirtual2 (>= 0.0) | other';
187 $dep_virtual = deps_parse($field_virtual);
188 $dep_virtual->simplify_deps($facts);
189 is($dep_virtual->output(), '',
190    'Simplify versioned depends on versioned virtual (satisfied)');
191
192 $field_virtual = 'myvirtual2 (>= 2.0) | other';
193 $dep_virtual = deps_parse($field_virtual);
194 $dep_virtual->simplify_deps($facts);
195 is($dep_virtual->output(), 'myvirtual2 (>= 2.0) | other',
196    'Simplify versioned depends on versioned virtual (unsatisfied)');
197
198 $field_virtual = 'myvirtual3 (= 2.0-1)';
199 $dep_virtual = deps_parse($field_virtual);
200 $dep_virtual->simplify_deps($facts);
201 is($dep_virtual->output(), 'myvirtual3 (= 2.0-1)',
202    'Simplify versioned depends on GT versioned virtual (unsatisfied/ignored)');
203
204 my $field_dup_union = 'libc6 (>> 2.3), libc6 (>= 2.6-1), fake (<< 2.0),
205 fake(>> 3.0), fake (= 2.5), python (<< 2.5), python (= 2.4)';
206 my $dep_dup_union = deps_parse($field_dup_union, union => 1);
207 $dep_dup_union->simplify_deps($facts);
208 is($dep_dup_union->output(), 'libc6 (>> 2.3), fake (<< 2.0), fake (>> 3.0), fake (= 2.5), python (<< 2.5)', 'Simplify union deps');
209
210 $dep_dup_union = deps_parse('sipsak (<= 0.9.6-2.1), sipsak (<= 0.9.6-2.2)', union => 1);
211 $dep_dup_union->simplify_deps($facts);
212 is($dep_dup_union->output(), 'sipsak (<= 0.9.6-2.2)', 'Simplify union deps 2');
213
214 my $dep_red = deps_parse('abc | xyz, two, abc');
215 $dep_red->simplify_deps($facts, $dep_opposite);
216 is($dep_red->output(), 'abc, two', 'Simplification respect order');
217 is("$dep_red", $dep_red->output(), 'Stringification == output()');
218
219 my $dep_profiles = deps_parse('dupe <stage1 cross>, dupe <stage1 cross>');
220 $dep_profiles->simplify_deps($facts);
221 is($dep_profiles->output(), 'dupe <stage1 cross>',
222    'Simplification respects duplicated profiles');
223
224 $dep_profiles = deps_parse('tool <!cross>, tool <stage1 cross>');
225 $dep_profiles->simplify_deps($facts);
226 # XXX: Ideally this would get simplified to "tool <!cross> <stage1 cross>".
227 is($dep_profiles->output(), 'tool <!cross>, tool <stage1 cross>',
228    'Simplification respects profiles');
229
230 $dep_profiles = deps_parse('libfoo-dev:native <!stage1>, libfoo-dev <!stage1 cross>', build_dep => 1);
231 $dep_profiles->simplify_deps($facts);
232 is($dep_profiles->output(),
233    'libfoo-dev:native <!stage1>, libfoo-dev <!stage1 cross>',
234    'Simplification respects archqualifiers and profiles');
235
236 my $dep_version = deps_parse('pkg, pkg (= 1.0)');
237 $dep_version->simplify_deps($facts);
238 is($dep_version->output(), 'pkg (= 1.0)', 'Simplification merges versions');
239
240 my $dep_empty1 = deps_parse('');
241 is($dep_empty1->output(), '', 'Empty dependency');
242
243 my $dep_empty2 = deps_parse(' , , ', union => 1);
244 is($dep_empty2->output(), '', "' , , ' is also an empty dependency");
245
246 # Check sloppy but acceptable dependencies
247
248 my $dep_sloppy_version = deps_parse('package (=   1.0  )');
249 is($dep_sloppy_version->output(), 'package (= 1.0)', 'sloppy version restriction');
250
251 my $dep_sloppy_arch = deps_parse('package [  alpha    ]');
252 is($dep_sloppy_arch->output(), 'package [alpha]', 'sloppy arch restriction');
253
254 my $dep_sloppy_profile = deps_parse('package <  !profile    >   <  other  >');
255 is($dep_sloppy_profile->output(), 'package <!profile> <other>',
256    'sloppy profile restriction');
257
258 $SIG{__WARN__} = sub {};
259
260 my $dep_bad_version = deps_parse('package (= 1.0) (>= 2.0)');
261 is($dep_bad_version, undef, 'Bogus repeated version restriction');
262
263 my $dep_bad_arch = deps_parse('package [alpha] [amd64]');
264 is($dep_bad_arch, undef, 'Bogus repeated arch restriction');
265
266 my $dep_bad_multiline = deps_parse("a, foo\nbar, c");
267 is($dep_bad_multiline, undef, 'invalid dependency split over multiple line');
268
269 delete $SIG{__WARN__};
270
271 my $dep_iter = deps_parse('a, b:armel, c | d:armhf, d:mips (>> 1.2)');
272 my %dep_arches;
273 my %dep_pkgs;
274 deps_iterate($dep_iter, sub {
275     my $dep = shift;
276
277     $dep_pkgs{$dep->{package}} = 1;
278     if ($dep->{archqual}) {
279         $dep_arches{$dep->{archqual}} = 1;
280     }
281     return 1;
282 });
283 my @dep_arches = sort keys %dep_arches;
284 my @dep_pkgs = sort keys %dep_pkgs;
285 is("@dep_arches", 'armel armhf mips', 'Dependency iterator, get arches');
286 is("@dep_pkgs", 'a b c d', 'Dependency iterator, get packages');