Dpkg_Deps.t 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  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. use strict;
  16. use warnings;
  17. use Test::More tests => 52;
  18. use Dpkg::Arch qw(get_host_arch);
  19. use Dpkg::Version;
  20. use_ok('Dpkg::Deps');
  21. is(deps_concat(), '', 'Concatenate an empty list');
  22. is(deps_concat(undef), '', 'Concatenate list with undef');
  23. is(deps_concat(''), '', 'Concatenate an empty string');
  24. is(deps_concat('', undef), '', 'Concatenate empty string with undef');
  25. is(deps_concat('dep-a', undef, 'dep-b'), 'dep-a, dep-b',
  26. 'Concatenate two strings with intermixed undef');
  27. my $field_multiline = ' , , libgtk2.0-common (= 2.10.13-1) , libatk1.0-0 (>=
  28. 1.13.2), libc6 (>= 2.5-5), libcairo2 (>= 1.4.0), libcupsys2 (>= 1.2.7),
  29. libfontconfig1 (>= 2.4.0), libglib2.0-0 ( >= 2.12.9), libgnutls13 (>=
  30. 1.6.3-0), libjpeg62, python (<< 2.5) , , ';
  31. 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)';
  32. my $dep_multiline = deps_parse($field_multiline);
  33. $dep_multiline->sort();
  34. is($dep_multiline->output(), $field_multiline_sorted, 'Parse, sort and output');
  35. my $dep_sorted = deps_parse('pkgz, pkgz | pkgb, pkgz | pkga, pkga (>= 1.0), pkgz (<= 2.0)');
  36. $dep_sorted->sort();
  37. is($dep_sorted->output(), 'pkga (>= 1.0), pkgz, pkgz | pkga, pkgz | pkgb, pkgz (<= 2.0)', 'Check sort() algorithm');
  38. my $dep_subset = deps_parse('libatk1.0-0 (>> 1.10), libc6, libcairo2');
  39. is($dep_multiline->implies($dep_subset), 1, 'Dep implies subset of itself');
  40. is($dep_subset->implies($dep_multiline), undef, "Subset doesn't imply superset");
  41. my $dep_opposite = deps_parse('python (>= 2.5)');
  42. is($dep_opposite->implies($dep_multiline), 0, 'Opposite condition implies NOT the depends');
  43. my $dep_or1 = deps_parse('a|b (>=1.0)|c (>= 2.0)');
  44. my $dep_or2 = deps_parse('x|y|a|b|c (<= 0.5)|c (>=1.5)|d|e');
  45. is($dep_or1->implies($dep_or2), 1, 'Implication between OR 1/2');
  46. is($dep_or2->implies($dep_or1), undef, 'Implication between OR 2/2');
  47. my $dep_ma_any = deps_parse('libcairo2:any');
  48. my $dep_ma_native = deps_parse('libcairo2');
  49. my $dep_ma_native2 = deps_parse('libcairo2:native', build_dep => 1);
  50. is($dep_ma_native->implies($dep_ma_any), 1, 'foo -> foo:any');
  51. is($dep_ma_native2->implies($dep_ma_any), 1, 'foo:native -> foo:any');
  52. is($dep_ma_any->implies($dep_ma_native), undef, 'foo:any !-> foo');
  53. is($dep_ma_any->implies($dep_ma_native2), undef, 'foo:any !-> foo:native');
  54. my $field_tests = 'self, @, @builddeps@';
  55. $SIG{__WARN__} = sub {};
  56. my $dep_tests_fail = deps_parse($field_tests);
  57. is($dep_tests_fail, undef, 'normal deps with @ in pkgname');
  58. delete $SIG{__WARN__};
  59. my $dep_tests_pass = deps_parse($field_tests, tests_dep => 1);
  60. is($dep_tests_pass->output(), $field_tests, 'tests deps with @ in pkgname');
  61. my $field_arch = 'libc6 (>= 2.5) [!alpha !hurd-i386], libc6.1 [alpha], libc0.1 [hurd-i386]';
  62. my $dep_i386 = deps_parse($field_arch, reduce_arch => 1, host_arch => 'i386');
  63. my $dep_alpha = deps_parse($field_arch, reduce_arch => 1, host_arch => 'alpha');
  64. my $dep_hurd = deps_parse($field_arch, reduce_arch => 1, host_arch => 'hurd-i386');
  65. is($dep_i386->output(), 'libc6 (>= 2.5)', 'Arch reduce 1/3');
  66. is($dep_alpha->output(), 'libc6.1', 'Arch reduce 2/3');
  67. is($dep_hurd->output(), 'libc0.1', 'Arch reduce 3/3');
  68. my $field_profile = 'dep1 <!stage1 !nocheck>, ' .
  69. 'dep2 <stage1 !nocheck>, ' .
  70. 'dep3 <nocheck !stage1>, ' .
  71. 'dep4 <stage1 nocheck>, ' .
  72. 'dep5 <stage1>, dep6 <!stage1>, ' .
  73. 'dep7 <stage1> | dep8 <nocheck>, ' .
  74. 'dep9 <!stage1> <!nocheck>, ' .
  75. 'dep10 <stage1> <!nocheck>, ' .
  76. 'dep11 <stage1> <nocheck>, '.
  77. 'dep12 <!nocheck> <!stage1>, ' .
  78. 'dep13 <nocheck> <!stage1>, ' .
  79. 'dep14 <nocheck> <stage1>';
  80. my $dep_noprof = deps_parse($field_profile, reduce_profiles => 1, build_profiles => []);
  81. my $dep_stage1 = deps_parse($field_profile, reduce_profiles => 1, build_profiles => ['stage1']);
  82. my $dep_nocheck = deps_parse($field_profile, reduce_profiles => 1, build_profiles => ['nocheck']);
  83. my $dep_stage1nocheck = deps_parse($field_profile, reduce_profiles => 1, build_profiles => ['stage1', 'nocheck']);
  84. is($dep_noprof->output(), 'dep1, dep6, dep9, dep10, dep12, dep13', 'Profile reduce 1/4');
  85. is($dep_stage1->output(), 'dep2, dep5, dep7, dep9, dep10, dep11, dep12, dep14', 'Profile reduce 2/4');
  86. is($dep_nocheck->output(), 'dep3, dep6, dep8, dep9, dep11, dep12, dep13, dep14', 'Profile reduce 3/4');
  87. is($dep_stage1nocheck->output(), 'dep4, dep5, dep7 | dep8, dep10, dep11, dep13, dep14', 'Profile reduce 4/4');
  88. $dep_noprof = deps_parse($field_profile);
  89. $dep_noprof->reduce_profiles([]);
  90. $dep_stage1 = deps_parse($field_profile);
  91. $dep_stage1->reduce_profiles(['stage1']);
  92. $dep_nocheck = deps_parse($field_profile);
  93. $dep_nocheck->reduce_profiles(['nocheck']);
  94. $dep_stage1nocheck = deps_parse($field_profile);
  95. $dep_stage1nocheck->reduce_profiles(['stage1', 'nocheck']);
  96. is($dep_noprof->output(), 'dep1, dep6, dep9, dep10, dep12, dep13', 'Profile post-reduce 1/4');
  97. is($dep_stage1->output(), 'dep2, dep5, dep7, dep9, dep10, dep11, dep12, dep14', 'Profile post-reduce 2/4');
  98. is($dep_nocheck->output(), 'dep3, dep6, dep8, dep9, dep11, dep12, dep13, dep14', 'Profile post-reduce 3/4');
  99. is($dep_stage1nocheck->output(), 'dep4, dep5, dep7 | dep8, dep10, dep11, dep13, dep14', 'Profile post-reduce 4/4');
  100. my $field_restrict = 'dep1 <!bootstrap !restrict>, ' .
  101. 'dep2 <bootstrap restrict>, ' .
  102. 'dep3 <!restrict>, ' .
  103. 'dep4 <restrict>, ' .
  104. 'dep5 <!bootstrap> <!restrict>, ' .
  105. 'dep6 <bootstrap> <restrict>';
  106. my $dep_restrict = deps_parse($field_restrict, reduce_restrictions => 1, build_profiles => []);
  107. is($dep_restrict->output(), 'dep1, dep3, dep5', 'Unknown restrictions reduce');
  108. $dep_restrict = deps_parse($field_restrict);
  109. $dep_restrict->reduce_profiles([]);
  110. is($dep_restrict->output(), 'dep1, dep3, dep5', 'Unknown restrictions post-reduce');
  111. my $facts = Dpkg::Deps::KnownFacts->new();
  112. $facts->add_installed_package('mypackage', '1.3.4-1', get_host_arch(), 'no');
  113. $facts->add_installed_package('mypackage2', '1.3.4-1', 'somearch', 'no');
  114. $facts->add_installed_package('pkg-ma-foreign', '1.3.4-1', 'somearch', 'foreign');
  115. $facts->add_installed_package('pkg-ma-foreign2', '1.3.4-1', get_host_arch(), 'foreign');
  116. $facts->add_installed_package('pkg-ma-allowed', '1.3.4-1', 'somearch', 'allowed');
  117. $facts->add_installed_package('pkg-ma-allowed2', '1.3.4-1', 'somearch', 'allowed');
  118. $facts->add_installed_package('pkg-ma-allowed3', '1.3.4-1', get_host_arch(), 'allowed');
  119. $facts->add_provided_package('myvirtual', undef, undef, 'mypackage');
  120. $facts->add_provided_package('myvirtual2', REL_EQ, '1.0-1', 'mypackage');
  121. $facts->add_provided_package('myvirtual3', REL_GE, '2.0-1', 'mypackage');
  122. my $field_duplicate = 'libc6 (>= 2.3), libc6 (>= 2.6-1), mypackage (>=
  123. 1.3), myvirtual | something, python (>= 2.5), mypackage2, pkg-ma-foreign,
  124. pkg-ma-foreign2, pkg-ma-allowed:any, pkg-ma-allowed2, pkg-ma-allowed3';
  125. my $dep_dup = deps_parse($field_duplicate);
  126. $dep_dup->simplify_deps($facts, $dep_opposite);
  127. is($dep_dup->output(), 'libc6 (>= 2.6-1), mypackage2, pkg-ma-allowed2', 'Simplify deps');
  128. my $field_virtual = 'myvirtual | other';
  129. my $dep_virtual = deps_parse($field_virtual);
  130. $dep_virtual->simplify_deps($facts);
  131. is($dep_virtual->output(), '',
  132. 'Simplify unversioned depends with unversioned virtual (satisfied)');
  133. $field_virtual = 'myvirtual (>= 1.0) | other';
  134. $dep_virtual = deps_parse($field_virtual);
  135. $dep_virtual->simplify_deps($facts);
  136. is($dep_virtual->output(), 'myvirtual (>= 1.0) | other',
  137. 'Simplify versioned depends on unversioned virtual (unsatisfied)');
  138. $field_virtual = 'myvirtual2 (>= 0.0) | other';
  139. $dep_virtual = deps_parse($field_virtual);
  140. $dep_virtual->simplify_deps($facts);
  141. is($dep_virtual->output(), '',
  142. 'Simplify versioned depends on versioned virtual (satisfied)');
  143. $field_virtual = 'myvirtual2 (>= 2.0) | other';
  144. $dep_virtual = deps_parse($field_virtual);
  145. $dep_virtual->simplify_deps($facts);
  146. is($dep_virtual->output(), 'myvirtual2 (>= 2.0) | other',
  147. 'Simplify versioned depends on versioned virtual (unsatisfied)');
  148. $field_virtual = 'myvirtual3 (= 2.0-1)';
  149. $dep_virtual = deps_parse($field_virtual);
  150. $dep_virtual->simplify_deps($facts);
  151. is($dep_virtual->output(), 'myvirtual3 (= 2.0-1)',
  152. 'Simplify versioned depends on GT versioned virtual (unsatisfied/ignored)');
  153. my $field_dup_union = 'libc6 (>> 2.3), libc6 (>= 2.6-1), fake (<< 2.0),
  154. fake(>> 3.0), fake (= 2.5), python (<< 2.5), python (= 2.4)';
  155. my $dep_dup_union = deps_parse($field_dup_union, union => 1);
  156. $dep_dup_union->simplify_deps($facts);
  157. is($dep_dup_union->output(), 'libc6 (>> 2.3), fake (<< 2.0), fake (>> 3.0), fake (= 2.5), python (<< 2.5)', 'Simplify union deps');
  158. $dep_dup_union = deps_parse('sipsak (<= 0.9.6-2.1), sipsak (<= 0.9.6-2.2)', union => 1);
  159. $dep_dup_union->simplify_deps($facts);
  160. is($dep_dup_union->output(), 'sipsak (<= 0.9.6-2.2)', 'Simplify union deps 2');
  161. my $dep_red = deps_parse('abc | xyz, two, abc');
  162. $dep_red->simplify_deps($facts, $dep_opposite);
  163. is($dep_red->output(), 'abc, two', 'Simplification respect order');
  164. is("$dep_red", $dep_red->output(), 'Stringification == output()');
  165. my $dep_empty1 = deps_parse('');
  166. is($dep_empty1->output(), '', 'Empty dependency');
  167. my $dep_empty2 = deps_parse(' , , ', union => 1);
  168. is($dep_empty2->output(), '', "' , , ' is also an empty dependency");
  169. # Check sloppy but acceptable dependencies
  170. my $dep_sloppy_version = deps_parse('package (= 1.0 )');
  171. is($dep_sloppy_version->output(), 'package (= 1.0)', 'sloppy version restriction');
  172. my $dep_sloppy_arch = deps_parse('package [ alpha ]');
  173. is($dep_sloppy_arch->output(), 'package [alpha]', 'sloppy arch restriction');
  174. my $dep_sloppy_profile = deps_parse('package < !profile > < other >');
  175. is($dep_sloppy_profile->output(), 'package <!profile> <other>',
  176. 'sloppy profile restriction');
  177. $SIG{__WARN__} = sub {};
  178. my $dep_bad_version = deps_parse('package (= 1.0) (>= 2.0)');
  179. is($dep_bad_version, undef, 'Bogus repeated version restriction');
  180. my $dep_bad_arch = deps_parse('package [alpha] [amd64]');
  181. is($dep_bad_arch, undef, 'Bogus repeated arch restriction');
  182. my $dep_bad_multiline = deps_parse("a, foo\nbar, c");
  183. is($dep_bad_multiline, undef, 'invalid dependency split over multiple line');
  184. delete $SIG{__WARN__};
  185. my $dep_iter = deps_parse('a, b:armel, c | d:armhf, d:mips (>> 1.2)');
  186. my %dep_arches;
  187. my %dep_pkgs;
  188. deps_iterate($dep_iter, sub {
  189. my $dep = shift;
  190. $dep_pkgs{$dep->{package}} = 1;
  191. if ($dep->{archqual}) {
  192. $dep_arches{$dep->{archqual}} = 1;
  193. }
  194. return 1;
  195. });
  196. my @dep_arches = sort keys %dep_arches;
  197. my @dep_pkgs = sort keys %dep_pkgs;
  198. is("@dep_arches", 'armel armhf mips', 'Dependency iterator, get arches');
  199. is("@dep_pkgs", 'a b c d', 'Dependency iterator, get packages');