File Coverage

lib/Test/Debian.pm
Criterion Covered Total %
statement 71 91 78.0
branch 27 46 58.7
condition 6 16 37.5
subroutine 11 11 100.0
pod 3 3 100.0
total 118 167 70.6


line stmt bran cond sub pod time code
1             package Test::Debian;
2              
3 1     1   15647 use 5.008008;
  1         2  
4 1     1   3 use strict;
  1         2  
  1         15  
5 1     1   3 use warnings;
  1         4  
  1         20  
6              
7 1     1   2 use Test::More;
  1         2  
  1         3  
8 1     1   196 use base 'Exporter';
  1         1  
  1         881  
9              
10             our @EXPORT = qw(
11             system_is_debian
12             package_is_installed
13             package_isnt_installed
14             );
15              
16             our $VERSION = '0.06';
17              
18             my $DPKG = '/usr/bin/dpkg';
19              
20             sub system_is_debian(;$) {
21 1   50 1 1 12 my $name = shift || 'System is debian';
22 1         17 Test::More->builder->ok( -r '/etc/debian_version', $name );
23             }
24              
25              
26             sub _pkg_list($) {
27 14     14   21 my ($name) = @_;
28 14         16 our %dpkg_list;
29              
30 14 50       342 unless(-x $DPKG) {
31 0         0 Test::More->builder->ok( 0, $name );
32 0         0 diag "$DPKG not found or executable";
33 0         0 return 0;
34             }
35 14 100       102 unless(%dpkg_list) {
36 1         1830 my $pid = open my $fh, '-|', '/usr/bin/dpkg', '--get-selections';
37 1 50       27 unless($pid) {
38 0         0 my $err = $!;
39 0         0 Test::More->builder->ok( 0, $name );
40 0         0 diag $!;
41 0         0 return 0;
42             }
43              
44 264         478 %dpkg_list = map { ( @$_[0, 1] ) }
45 1         11684 map { [ split /\s+/, $_, 3 ] } <$fh>;
  264         643  
46             }
47              
48 14         119 return \%dpkg_list;
49             }
50              
51             sub package_is_installed($;$) {
52 13     13 1 7166 my ($pkgs, $name) = @_;
53              
54 13 50       38 my $list = _pkg_list($name) or return 0;
55              
56 13         133 my $tb = Test::More->builder;
57              
58 13   33     251 $name ||= "package(s) '$pkgs' is/are installed";
59              
60 13         94 for ( split /\s*\|\s*/, $pkgs ) {
61 15         54 my ($pkg, $op, $ver) = _parse_pkg($_);
62 15 50       38 next unless $pkg;
63              
64 15 100       52 next unless exists $list->{ $pkg };
65 14 50       38 next unless $list->{ $pkg } eq 'install';
66              
67 14 100       56 return $tb->ok( 1, $name ) unless $op;
68 10         22 my $ok = _compare_versions_ok($pkg, $op, $ver);
69 10 100       156 return $tb->ok(1, $name) if $ok;
70             }
71              
72 3         50 return $tb->ok( 0, $name );
73             }
74              
75             sub package_isnt_installed($;$) {
76 1     1 1 6992 my ($pkg_spec, $name) = @_;
77              
78 1   33     13 $name ||= "$pkg_spec is not installed";
79              
80 1 50       4 my $list = _pkg_list($name) or return 0;
81              
82 1         8 my $tb = Test::More->builder;
83 1         13 my ($pkg, $op, $ver) = _parse_pkg($pkg_spec);
84 1 50       4 return $tb->ok( 0, $name) unless $pkg;
85              
86 1 50       9 return $tb->ok( 1, $name ) unless exists $list->{ $pkg };
87 0 0       0 return $tb->cmp_ok($list->{ $pkg }, 'ne', 'install', $name) unless $op;
88              
89 0         0 my $res = _compare_versions($pkg, $op, $ver);
90              
91 0 0       0 return $tb->ok( $res ? 1 : 0, $name);
92             }
93              
94              
95             my %ops = (
96             '>' => 'gt',
97             '>=' => 'ge',
98             '=' => 'eq',
99             '!=' => 'ne',
100             '<' => 'lt',
101             '<=' => 'le',
102             );
103              
104             sub _parse_pkg {
105 16     16   23 my ($str) = @_;
106 16         93 $str =~ s/\s+//g;
107 16         134 my ($pkg, $op, $ver) = $str =~ /^([^(]+) (?:\( ([^\d]+) ([^)]+) \))?$/x;
108              
109 16         23 my $err;
110 16 100       41 if ($op) {
111 10         24 $op = $ops{$op};
112 10 50 33     72 $err = 1 unless $op && $ver =~ /^[\d._-]+/;
113             }
114             else {
115 6 50 33     54 $err = 1 unless $pkg && length $str == length $pkg;
116             }
117 16 50       32 if ($err) {
118 0         0 diag "invalid syntax for package '$_[0]'";
119 0         0 return;
120             }
121              
122 16         59 return ($pkg, $op, $ver);
123             }
124              
125             sub _compare_versions_ok {
126 10     10   30 my ($pkg, $op, $req_ver) = @_;
127              
128 10         11617 my $pid = open my $fh, '-|', $DPKG, '-s', $pkg;
129 10 50       68 unless ($pid) {
130 0         0 diag "exec: $!";
131 0         0 return undef;
132             }
133 10         87534 my @info = <$fh>;
134 10         212 waitpid $pid, 0;
135 10 50       93 if ($?) {
136 0         0 diag "$DPKG error: ", $? >> 8;
137 0         0 return undef;
138             }
139 10         23 my $inst_ver;
140 10         58 for (@info) {
141 80 100 50     319 $inst_ver = $1 and last if /^Version:\s+(.+)$/;
142             }
143 10 50       38 unless ($inst_ver) {
144 0         0 diag "Can`t define version $pkg";
145 0         0 return undef;
146             }
147 10         109 $inst_ver =~ s/(^[\d.]+).+$/$1/;
148              
149 10         26089 my $r = system($DPKG, '--compare-versions', $inst_ver, $op, $req_ver);
150 10         47 $r = $r >> 8;
151 10 50       46 if ($r > 1) {
152 0         0 diag "dpkg error: $r";
153 0         0 return undef;
154             }
155 10         504 return $r == 0;
156             }
157              
158              
159             1;
160              
161             =head1 NAME
162              
163             Test::Debian - some tests for debian system
164              
165             =head1 SYNOPSIS
166              
167             use Test::More;
168             use Test::Debian;
169              
170             ok($value, 'test name');
171             system_is_debian;
172             package_is_installed 'dpkg';
173             package_is_installed 'dpkg', 'dpkg is installed';
174             package_isnt_installed 'kde-base';
175              
176              
177             =head1 DESCRIPTION
178              
179             The module provides some perl tests for debian system:
180              
181             =head2 system_is_debian([ $test_name ])
182              
183             Passes if current OS is debian
184              
185             =head2 package_is_installed($pkg_variant [, $test_name ])
186              
187             Passes if package is installed
188              
189             L understands the following syntax:
190              
191             package1 | package2
192             package1 (< 1.23) | package2 (> 1.3)
193              
194              
195             =head2 package_isnt_installed($pkg_name [, $test_name ])
196              
197             Passes if package isn't installed
198              
199             =head1 AUTHOR
200              
201             Dmitry E. Oboukhov, Eunera@debian.org
202              
203             =head1 COPYRIGHT AND LICENSE
204              
205             Copyright (C) 2012 by Dmitry E. Oboukhov
206              
207             This library is free software; you can redistribute it and/or modify
208             it under the same terms as Perl itself, either Perl version 5.8.8 or,
209             at your option, any later version of Perl 5 you may have available.
210              
211             =cut