Adding side stream changes to Maemian. Working to integrate full upstream libraries...
[maemian] / nokia-lintian / testset / runtests
1 #!/usr/bin/perl -w
2
3 # Copyright (C) 1998 Richard Braakman
4 #
5 # This program is free software; you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License as published by
7 # the Free Software Foundation; either version 2 of the License, or
8 # (at your option) any later version.
9 #
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 # GNU General Public License for more details.
14 #
15 # You should have received a copy of the GNU General Public License
16 # along with this program.  If not, you can find it on the World Wide
17 # Web at http://www.gnu.org/copyleft/gpl.html, or write to the Free
18 # Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
19 # MA 02110-1301, USA.
20
21 use strict;
22
23 sub usage {
24     print <<END;
25 Usage: $0 [-k] [-v] [-d] testset-directory testing-directory [test]
26
27 The -k option means do not stop after one failed test, but try
28 them all and report all errors.
29
30 The -v option will also display those tests that have a description, but are
31 not tested in any testset-package.
32
33 The -d option will display debugging information.
34
35 The optional 3rd parameter causes runtests to only run that particular test.
36 END
37     exit 2;
38 }
39
40 # for debugging:
41 my $debug = 0;
42
43 # Tests layout:
44 # Every test package is in a directory pkgname-version in the testset
45 # directory.  The lintian output that is expected for each package is
46 # in a file tags.pkgname in the testset directory.
47
48 # Running the tests:
49 # Each test package is copied to a subdirectory of the testing-directory,
50 # and built there.  Then lintian is run over the resulting .changes file,
51 # with its output redirected to tags.pkgname in the testing-directory.
52
53 # If the tags output is not identical to the tags.pkgname file in the
54 # testset-directory, then runtests will output the diff and exit with
55 # a failure code.
56
57 # The build output is directed to build.pkgname in the testing-directory.
58
59 # Exit codes:
60 # 0 - success
61 # 1 - one or more tests failed
62 # 2 - an error prevented proper running of the tests
63
64 # Turns out I might as well have written this in bash.  Oh well.
65
66 my $run_all_tests = 0;
67 my $verbose = 0;
68
69 # --- Parse options, such as they are.
70 while ($#ARGV >= 0 && $ARGV[0] =~ m/^-/) {
71     if ($ARGV[0] eq '-k') {
72         $run_all_tests = 1;
73     } elsif ($ARGV[0] eq '-v') {
74         $verbose = 1;
75     } elsif ($ARGV[0] eq '-d') {
76         $debug = 1;
77     } else {
78         usage;
79     }
80     shift;
81 }
82
83 # --- Parse directory arguments
84 if ($#ARGV < 1 || $#ARGV > 2) {
85     usage;
86 }
87
88 my $testset = shift;
89 my $rundir = shift;
90 my $singletest;
91 if ($#ARGV == 0) {
92     $singletest = shift;
93 }
94
95 # --- Set and unset environment variables that lintian is sensitive to
96 BEGIN {
97     my $LINTIAN_ROOT = $ENV{'LINTIAN_ROOT'};
98     if (not $LINTIAN_ROOT) {
99         use Cwd ();
100         $ENV{'LINTIAN_ROOT'} = $LINTIAN_ROOT = Cwd::cwd();
101     }
102     delete $ENV{'LINTIAN_CFG'};
103     delete $ENV{'LINTIAN_LAB'};
104     delete $ENV{'LINTIAN_DIST'};
105     delete $ENV{'LINTIAN_UNPACK_LEVEL'};
106     $ENV{'LC_COLLATE'} = 'C';
107
108     # Set standard umask because many of the test packages rely on this
109     # when creating files from the debian/rules script.
110     umask(022);
111 }
112
113 my $LINTIAN_ROOT = $ENV{'LINTIAN_ROOT'};
114
115 use lib "$ENV{'LINTIAN_ROOT'}/lib";
116 use Util;
117 use Tags;
118
119 # --- Set the ways to call lintian and dpkg-buildpackage
120 my $lintian_options = '-I -E';
121 my $lintian_info_options = '-I -E -i';
122 my $dpkg_buildpackage_options = '-rfakeroot -us -uc -d -iNEVER_MATCH_ANYTHING'
123     . ' -INEVER_MATCH_ANYTHING';
124 my $lintian_path = $LINTIAN_ROOT . "/frontend/lintian";
125
126 my $testok = 0;
127 my %tags;
128 my %types = ( 'E' => 'error', 'W' => 'warning', 'I' => 'info', 'X' => 'experimental' );
129
130 # --- Display output immediately
131 $| = 1;
132
133 # --- Let's play.
134
135 -d $rundir
136     or fail("test directory $rundir does not exist\n");
137
138 # does every tag have an info section?
139 print "Checking for missing info tags ... ";
140
141 $testok = 1;
142 for my $desc_file (<$LINTIAN_ROOT/checks/*.desc>) {
143     for my $i (read_dpkg_control($desc_file)) {
144         $desc_file =~ s#.*/##;
145         if (exists $i->{'tag'}) {
146             if ($i->{'tag'} !~ /^[\w0-9.+-]+$/) {
147                 print "E: test-tag-has-invalid-characters $i->{'tag'}"
148                     . " in $desc_file\n";
149             }
150             if (not exists $i->{'info'}) {
151                 print "E: test-has-no-info $i->{'tag'} in $desc_file\n";
152                 $testok = 0;
153             }
154
155             # Check the tag info for unescaped <> or for unknown tags (which
156             # probably indicate the same thing).
157             my $info = $i->{'info'};
158             my @tags;
159             while ($info =~ s,<([^\s>]+)(?:\s+href=\"[^\"]+\")?>.*?</\1>,,s) {
160                 push (@tags, $1);
161             }
162             my %known = map { $_ => 1 } qw(a em i tt);
163             my %seen;
164             @tags = grep { !$known{$_} && !$seen{$_}++ } @tags;
165             if (@tags) {
166                 print "E: test-info-has-unknown-html-tags $i->{'tag'} @tags"
167                     . " in $desc_file\n";
168             }
169             if ($info =~ /[<>]/) {
170                 print "E: test-info-has-stray-angle-brackets $i->{'tag'}"
171                     . " in $desc_file\n";
172             }
173
174             if (!exists($i->{'type'}) && !exists($i->{'severity'})) {
175                 use Data::Dumper;
176                 print Dumper $i;
177                 print "E: test-has-no-type $i->{'tag'} in $desc_file\n";
178                 $testok = 0;
179                 next;
180             }
181
182             $tags{$i->{'tag'}}{'desc_file'} = $desc_file;
183             if (exists $i->{'experimental'}) {
184                 $tags{$i->{'tag'}}{'desc_type'} = "experimental";
185             } else {
186                 $tags{$i->{'tag'}}{'desc_type'} = $i->{'type'} ||
187                     $Tags::sev_to_type[$i->{'severity'}];
188             }
189         }
190     }
191 }
192
193 if ($testok) {
194     print "done.\n";
195 } else {
196     print "FAILED!\n";
197     exit 1 unless $run_all_tests;
198 }
199
200 # can I make a lab?
201 print "Running static lab test ... create ... ";
202 $testok = runsystem_ok("$lintian_path --lab $rundir/test_lab --setup-lab");
203 # can I renew a lab?
204 print " renew ... ";
205 $testok = runsystem_ok("$lintian_path --lab $rundir/test_lab --setup-lab")
206     if $testok;
207 # can I remove a lab?
208 print " remove ...";
209 $testok = runsystem_ok("$lintian_path --lab $rundir/test_lab --remove-lab")
210     if $testok;
211 # should be empty now
212 print " rmdir ...";
213 $testok = runsystem_ok("rmdir $rundir/test_lab")
214     if $testok;
215 # cleanup
216 runsystem("rm -r $rundir/test_lab") if -d "$rundir/test_lab";
217 if ($testok) {
218     print "done.\n";
219 } else {
220     print "FAILED!\n";
221     exit 1 unless $run_all_tests;
222 }
223
224 # ok, I can make a static lab, now let's test the package checks
225 # in temporary labs
226 my @tests;
227 if ($singletest) {
228     @tests = ( $singletest );
229 } else {
230         opendir(TESTDIR, $testset)
231                 or fail("cannot open $testset: $!\n");
232
233         @tests = sort(readdir(TESTDIR));
234
235         closedir(TESTDIR);
236 }
237
238 for (@tests) {
239     next if $_ eq '.' or $_ eq '..' or $_ eq 'CVS' or $_ eq '.svn';
240     next unless -d "$testset/$_";
241
242     my $pkgdir = $_;
243
244     open(CHANGELOG, "$testset/$pkgdir/debian/changelog") or
245          die("Could not open $testset/$pkgdir/debian/changelog");
246     my $line = <CHANGELOG>;
247     chomp($line);
248     close(CHANGELOG);
249     $line =~ s/^.*\(//;
250     $line =~ s/\).*$//;
251     
252     my ($pkg, $ver) = ($pkgdir, $line);
253     print "Running test on $pkg $ver: copying... ";
254
255     print "Cleaning up and repopulating $rundir/$pkgdir...\n" if $debug;
256     runsystem_ok("rm -rf $rundir/$pkgdir");
257     runsystem("cp -rp $testset/$pkgdir $rundir");
258     opendir D, "$testset" or die;
259     foreach (readdir D) {
260       next unless /^\Q${pkg}\E_.*\.orig\.tar\.gz$/;
261       print "Symlinking $_ in $rundir...\n" if $debug;
262       symlink $ENV{'PWD'}."/$testset/$_", "$rundir/$_";
263     }
264     closedir D;
265     runsystem("find $rundir -name CVS -o -name .svn -print0 | xargs -0r rm -R");
266
267     print "building... ";
268     print "Running dpkg-buildpackage $dpkg_buildpackage_options in $rundir/$pkgdir...\n" if $debug;
269     runsystem("cd $rundir/$pkgdir && dpkg-buildpackage $dpkg_buildpackage_options >../build.$pkg 2>&1");
270
271     print "testing... ";
272     print "Running lintian $lintian_options on $rundir/$pkg\_$ver*.changes...\n" if $debug;
273     runsystem_ok("$lintian_path $lintian_options $rundir/$pkg\_$ver*.changes".
274         " 2>&1 | sort > $rundir/tags.$pkg");
275
276     # Run a sed-script if it exists, for tests that have slightly variable
277     # output
278     runsystem_ok("sed -i -f $testset/tags.$pkg.sed $rundir/tags.$pkg")
279         if -e "$testset/tags.$pkg.sed";
280
281     $testok = runsystem_ok("cmp -s $rundir/tags.$pkg $testset/tags.$pkg");
282     if ($testok) {
283         print "done.\n";
284     } else {
285         print "FAILED:\n";
286         runsystem_ok("diff -u $testset/tags.$pkg $rundir/tags.$pkg");
287         exit 1 unless $run_all_tests;
288         next;
289     }
290
291     open TAGS, "$rundir/tags.$pkg" or fail("Cannot open $rundir/tags.$pkg");
292     while (<TAGS>) {
293         next if /^N: /;
294         if (not /^(.): (\S+)(?: (?:source|udeb))?: (\S+)/) {
295             print "E: Invalid line:\n$_";
296             next;
297         }
298         $tags{$3}{'tested_type'} = $types{$1};
299         $tags{$3}{'tested_package'} = $2;
300     }
301     close TAGS;
302 }
303
304 print "Checking whether all tags are tested and tags have description ... \n";
305 $testok = 1;
306 for (keys %tags) {
307     my $values = $tags{$_};
308     if (not defined $values->{'desc_type'}) {
309         print "E: tag-has-no-description $_ in $values->{'tested_package'}\n";
310         $testok = 0;
311     } elsif (not defined $values->{'tested_type'}) {
312         print "I: tag-is-not-tested $_ in $values->{'desc_file'}\n"
313             if $verbose;
314     } elsif ($values->{'desc_type'} ne $values->{'tested_type'}) {
315         print "E: tag-has-inconsistent-type $_ $values->{'tested_type'} vs ".
316             "$values->{'desc_type'}\n";
317         $testok = 0;
318     }
319 }
320
321 if ($testok) {
322     print "done.\n";
323 } else {
324     print "FAILED\n";
325     exit 1 unless $run_all_tests;
326 }
327
328 # --------------
329 sub runsystem {
330     system(@_) == 0
331         or fail("failed: @_\n");
332 }
333
334 sub runsystem_ok {
335     my $errcode = system(@_);
336     $errcode == 0 or $errcode == (1 << 8)
337         or fail("failed: @_\n");
338     return $errcode == 0;
339 }
340
341 # Local Variables:
342 # indent-tabs-mode: t
343 # cperl-indent-level: 4
344 # End:
345 # vim: ts=8 sw=4