Annotation of mandoc/regress/regress.pl, Revision 1.8
1.1 schwarze 1: #!/usr/bin/env perl
2: #
1.8 ! schwarze 3: # $Id: regress.pl,v 1.7 2017/07/04 15:24:36 schwarze Exp $
1.1 schwarze 4: #
5: # Copyright (c) 2017 Ingo Schwarze <schwarze@openbsd.org>
6: #
7: # Permission to use, copy, modify, and distribute this software for any
8: # purpose with or without fee is hereby granted, provided that the above
9: # copyright notice and this permission notice appear in all copies.
10: #
11: # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12: # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13: # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14: # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15: # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16: # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17: # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18:
19: use warnings;
20: use strict;
21:
22: # Used because open(3p) and open2(3p) provide no way for handling
23: # STDERR of the child process, neither for appending it to STDOUT,
24: # nor for piping it into the Perl program.
25: use IPC::Open3 qw(open3);
26:
1.2 schwarze 27: # Define this at one place such that it can easily be changed
28: # if diff(1) does not support the -a option.
29: my @diff = qw(diff -au);
30:
1.1 schwarze 31: # --- utility functions ------------------------------------------------
32:
33: sub usage ($) {
34: warn shift;
35: print STDERR "usage: $0 [directory[:test] [modifier ...]]\n";
36: exit 1;
37: }
38:
1.8 ! schwarze 39: # Modifier arguments provided on the command line,
! 40: # inspected by the main program and by the utility functions.
! 41: my %targets;
! 42:
1.1 schwarze 43: # Run a command and send STDOUT and STDERR to a file.
44: # 1st argument: path to the output file
45: # 2nd argument: command name
46: # The remaining arguments are passed to the command.
47: sub sysout ($@) {
48: my $outfile = shift;
1.8 ! schwarze 49: print "@_\n" if $targets{verbose};
1.1 schwarze 50: local *OUT_FH;
51: open OUT_FH, '>', $outfile or die "$outfile: $!";
52: my $pid = open3 undef, ">&OUT_FH", undef, @_;
53: close OUT_FH;
54: waitpid $pid, 0;
55: return $? >> 8;
56: }
57:
58: # Simlar, but filter the output as needed for the lint test.
59: sub syslint ($@) {
60: my $outfile = shift;
1.8 ! schwarze 61: print "@_\n" if $targets{verbose};
1.1 schwarze 62: open my $outfd, '>', $outfile or die "$outfile: $!";
63: my $infd;
64: my $pid = open3 undef, $infd, undef, @_;
65: while (<$infd>) {
66: s/^mandoc: [^:]+\//mandoc: /;
67: print $outfd $_;
68: }
69: close $outfd;
70: close $infd;
71: waitpid $pid, 0;
72: return 0;
73: }
74:
75: # Simlar, but filter the output as needed for the html test.
76: sub syshtml ($@) {
77: my $outfile = shift;
1.8 ! schwarze 78: print "@_\n" if $targets{verbose};
1.1 schwarze 79: open my $outfd, '>', $outfile or die "$outfile: $!";
80: my $infd;
81: my $pid = open3 undef, $infd, undef, @_;
82: my $state;
83: while (<$infd>) {
84: chomp;
85: if (!$state && s/.*<math class="eqn">//) {
86: $state = 1;
87: next unless length;
88: }
89: $state = 1 if /^BEGINTEST/;
90: if ($state && s/<\/math>.*//) {
91: s/^ *//;
92: print $outfd "$_\n" if length;
93: undef $state;
94: next;
95: }
96: s/^ *//;
97: print $outfd "$_\n" if $state;
98: undef $state if /^ENDTEST/;
99: }
100: close $outfd;
101: close $infd;
102: waitpid $pid, 0;
103: return 0;
104: }
105:
106: my @failures;
1.8 ! schwarze 107: sub fail ($$) {
1.1 schwarze 108: warn "FAILED: @_\n";
109: push @failures, [@_];
110: }
111:
112:
113: # --- process command line arguments -----------------------------------
114:
1.8 ! schwarze 115: my $onlytest = shift // '';
1.1 schwarze 116: for (@ARGV) {
1.4 schwarze 117: /^(all|ascii|utf8|man|html|markdown|lint|clean|verbose)$/
1.1 schwarze 118: or usage "$_: invalid modifier";
119: $targets{$_} = 1;
120: }
121: $targets{all} = 1
122: unless $targets{ascii} || $targets{utf8} || $targets{man} ||
1.4 schwarze 123: $targets{html} || $targets{markdown} ||
124: $targets{lint} || $targets{clean};
1.1 schwarze 125: $targets{ascii} = $targets{utf8} = $targets{man} = $targets{html} =
1.4 schwarze 126: $targets{markdown} = $targets{lint} = 1 if $targets{all};
1.1 schwarze 127:
128:
129: # --- parse Makefiles --------------------------------------------------
130:
1.8 ! schwarze 131: sub parse_makefile ($%) {
! 132: my ($filename, $vars) = @_;
1.1 schwarze 133: open my $fh, '<', $filename or die "$filename: $!";
134: while (<$fh>) {
135: chomp;
136: next unless /\S/;
137: last if /^# OpenBSD only/;
138: next if /^#/;
139: next if /^\.include/;
140: /^(\w+)\s*([?+]?)=\s*(.*)/
141: or die "$filename: parse error: $_";
142: my $var = $1;
143: my $opt = $2;
144: my $val = $3;
1.8 ! schwarze 145: $val =~ s/\$\{(\w+)\}/$vars->{$1}/;
! 146: $val = "$vars->{$var} $val" if $opt eq '+';
! 147: $vars->{$var} = $val
! 148: unless $opt eq '?' && defined $vars->{$var};
1.1 schwarze 149: }
150: close $fh;
151: }
152:
1.8 ! schwarze 153: my (@regress_tests, @utf8_tests, @lint_tests, @html_tests);
! 154: my (%skip_ascii, %skip_man, %skip_markdown);
! 155: foreach my $module (qw(roff char mdoc man tbl eqn)) {
! 156: my %modvars;
! 157: parse_makefile "$module/Makefile", \%modvars;
! 158: foreach my $subdir (split ' ', $modvars{SUBDIR}) {
! 159: my %subvars = (MOPTS => '');
! 160: parse_makefile "$module/$subdir/Makefile", \%subvars;
! 161: parse_makefile "$module/Makefile.inc", \%subvars;
! 162: delete $subvars{SKIP_GROFF};
! 163: delete $subvars{SKIP_GROFF_ASCII};
! 164: delete $subvars{TBL};
! 165: delete $subvars{EQN};
! 166: my @mandoc = ('../mandoc', split ' ', $subvars{MOPTS});
! 167: delete $subvars{MOPTS};
! 168: my @regress_testnames;
! 169: if (defined $subvars{REGRESS_TARGETS}) {
! 170: push @regress_testnames,
! 171: split ' ', $subvars{REGRESS_TARGETS};
! 172: push @regress_tests, {
! 173: NAME => "$module/$subdir/$_",
! 174: MANDOC => \@mandoc,
! 175: } foreach @regress_testnames;
! 176: delete $subvars{REGRESS_TARGETS};
! 177: }
! 178: if (defined $subvars{UTF8_TARGETS}) {
! 179: push @utf8_tests, {
! 180: NAME => "$module/$subdir/$_",
! 181: MANDOC => \@mandoc,
! 182: } foreach split ' ', $subvars{UTF8_TARGETS};
! 183: delete $subvars{UTF8_TARGETS};
! 184: }
! 185: if (defined $subvars{HTML_TARGETS}) {
! 186: push @html_tests, {
! 187: NAME => "$module/$subdir/$_",
! 188: MANDOC => \@mandoc,
! 189: } foreach split ' ', $subvars{HTML_TARGETS};
! 190: delete $subvars{HTML_TARGETS};
! 191: }
! 192: if (defined $subvars{LINT_TARGETS}) {
! 193: push @lint_tests, {
! 194: NAME => "$module/$subdir/$_",
! 195: MANDOC => \@mandoc,
! 196: } foreach split ' ', $subvars{LINT_TARGETS};
! 197: delete $subvars{LINT_TARGETS};
! 198: }
! 199: if (defined $subvars{SKIP_ASCII}) {
! 200: for (split ' ', $subvars{SKIP_ASCII}) {
! 201: $skip_ascii{"$module/$subdir/$_"} = 1;
! 202: $skip_man{"$module/$subdir/$_"} = 1;
! 203: }
! 204: delete $subvars{SKIP_ASCII};
! 205: }
! 206: if (defined $subvars{SKIP_TMAN}) {
! 207: $skip_man{"$module/$subdir/$_"} = 1
! 208: for split ' ', $subvars{SKIP_TMAN};
! 209: delete $subvars{SKIP_TMAN};
! 210: }
! 211: if (defined $subvars{SKIP_MARKDOWN}) {
! 212: $skip_markdown{"$module/$subdir/$_"} = 1
! 213: for split ' ', $subvars{SKIP_MARKDOWN};
! 214: delete $subvars{SKIP_MARKDOWN};
! 215: }
! 216: if (keys %subvars) {
! 217: my @vars = keys %subvars;
! 218: die "unknown var(s) @vars in dir $module/$subdir";
! 219: }
! 220: map {
! 221: $skip_ascii{"$module/$subdir/$_"} = 1;
! 222: } @regress_testnames if $skip_ascii{"$module/$subdir/ALL"};
! 223: map {
! 224: $skip_man{"$module/$subdir/$_"} = 1;
! 225: } @regress_testnames if $skip_man{"$module/$subdir/ALL"};
! 226: map {
! 227: $skip_markdown{"$module/$subdir/$_"} = 1;
! 228: } @regress_testnames if $skip_markdown{"$module/$subdir/ALL"};
! 229: }
! 230: delete $modvars{SUBDIR};
! 231: if (keys %modvars) {
! 232: my @vars = keys %modvars;
! 233: die "unknown var(s) @vars in module $module";
! 234: }
1.1 schwarze 235: }
236:
237: # --- run targets ------------------------------------------------------
238:
239: my $count_total = 0;
240: my $count_ascii = 0;
241: my $count_man = 0;
1.8 ! schwarze 242: my $count_rm = 0;
! 243: if ($targets{ascii} || $targets{man}) {
! 244: print "Running ascii and man tests ";
! 245: print "...\n" if $targets{verbose};
! 246: }
! 247: for my $test (@regress_tests) {
! 248: my $i = "$test->{NAME}.in";
! 249: my $o = "$test->{NAME}.mandoc_ascii";
! 250: my $w = "$test->{NAME}.out_ascii";
! 251: if ($targets{ascii} && !$skip_ascii{$test->{NAME}} &&
! 252: $test->{NAME} =~ /^$onlytest/) {
1.1 schwarze 253: $count_ascii++;
254: $count_total++;
1.8 ! schwarze 255: sysout $o, @{$test->{MANDOC}}, qw(-I os=OpenBSD -T ascii), $i
! 256: and fail $test->{NAME}, 'ascii:mandoc';
1.2 schwarze 257: system @diff, $w, $o
1.8 ! schwarze 258: and fail $test->{NAME}, 'ascii:diff';
! 259: print "." unless $targets{verbose};
1.1 schwarze 260: }
1.8 ! schwarze 261: my $m = "$test->{NAME}.in_man";
! 262: my $mo = "$test->{NAME}.mandoc_man";
! 263: if ($targets{man} && !$skip_man{$test->{NAME}} &&
! 264: $test->{NAME} =~ /^$onlytest/) {
1.1 schwarze 265: $count_man++;
266: $count_total++;
1.8 ! schwarze 267: sysout $m, @{$test->{MANDOC}}, qw(-I os=OpenBSD -T man), $i
! 268: and fail $test->{NAME}, 'man:man';
! 269: sysout $mo, @{$test->{MANDOC}},
! 270: qw(-man -I os=OpenBSD -T ascii -O mdoc), $m
! 271: and fail $test->{NAME}, 'man:mandoc';
1.2 schwarze 272: system @diff, $w, $mo
1.8 ! schwarze 273: and fail $test->{NAME}, 'man:diff';
! 274: print "." unless $targets{verbose};
1.1 schwarze 275: }
276: if ($targets{clean}) {
1.8 ! schwarze 277: print "rm $o $m $mo\n" if $targets{verbose};
! 278: $count_rm += unlink $o, $m, $mo;
1.1 schwarze 279: }
280: }
1.8 ! schwarze 281: if ($targets{ascii} || $targets{man}) {
! 282: print "Number of ascii and man tests:" if $targets{verbose};
! 283: print " $count_ascii + $count_man tests run.\n";
! 284: }
1.1 schwarze 285:
286: my $count_utf8 = 0;
1.8 ! schwarze 287: if ($targets{utf8}) {
! 288: print "Running utf8 tests ";
! 289: print "...\n" if $targets{verbose};
! 290: }
! 291: for my $test (@utf8_tests) {
! 292: my $i = "$test->{NAME}.in";
! 293: my $o = "$test->{NAME}.mandoc_utf8";
! 294: my $w = "$test->{NAME}.out_utf8";
! 295: if ($targets{utf8} && $test->{NAME} =~ /^$onlytest/o) {
1.1 schwarze 296: $count_utf8++;
297: $count_total++;
1.8 ! schwarze 298: sysout $o, @{$test->{MANDOC}}, qw(-I os=OpenBSD -T utf8), $i
! 299: and fail $test->{NAME}, 'utf8:mandoc';
1.2 schwarze 300: system @diff, $w, $o
1.8 ! schwarze 301: and fail $test->{NAME}, 'utf8:diff';
! 302: print "." unless $targets{verbose};
1.1 schwarze 303: }
304: if ($targets{clean}) {
305: print "rm $o\n" if $targets{verbose};
1.8 ! schwarze 306: $count_rm += unlink $o;
1.1 schwarze 307: }
308: }
1.8 ! schwarze 309: if ($targets{utf8}) {
! 310: print "Number of utf8 tests:" if $targets{verbose};
! 311: print " $count_utf8 tests run.\n";
! 312: }
1.1 schwarze 313:
314: my $count_html = 0;
1.8 ! schwarze 315: if ($targets{html}) {
! 316: print "Running html tests ";
! 317: print "...\n" if $targets{verbose};
! 318: }
! 319: for my $test (@html_tests) {
! 320: my $i = "$test->{NAME}.in";
! 321: my $o = "$test->{NAME}.mandoc_html";
! 322: my $w = "$test->{NAME}.out_html";
! 323: if ($targets{html} && $test->{NAME} =~ /^$onlytest/) {
1.1 schwarze 324: $count_html++;
325: $count_total++;
1.8 ! schwarze 326: syshtml $o, @{$test->{MANDOC}}, qw(-T html), $i
! 327: and fail $test->{NAME}, 'html:mandoc';
1.2 schwarze 328: system @diff, $w, $o
1.8 ! schwarze 329: and fail $test->{NAME}, 'html:diff';
! 330: print "." unless $targets{verbose};
1.1 schwarze 331: }
332: if ($targets{clean}) {
333: print "rm $o\n" if $targets{verbose};
1.8 ! schwarze 334: $count_rm += unlink $o;
1.1 schwarze 335: }
336: }
1.8 ! schwarze 337: if ($targets{html}) {
! 338: print "Number of html tests:" if $targets{verbose};
! 339: print " $count_html tests run.\n";
! 340: }
1.1 schwarze 341:
1.4 schwarze 342: my $count_markdown = 0;
1.8 ! schwarze 343: if ($targets{markdown}) {
! 344: print "Running markdown tests ";
! 345: print "...\n" if $targets{verbose};
! 346: }
! 347: for my $test (@regress_tests) {
! 348: my $i = "$test->{NAME}.in";
! 349: my $o = "$test->{NAME}.mandoc_markdown";
! 350: my $w = "$test->{NAME}.out_markdown";
! 351: if ($targets{markdown} && !$skip_markdown{$test->{NAME}} &&
! 352: $test->{NAME} =~ /^$onlytest/) {
1.4 schwarze 353: $count_markdown++;
354: $count_total++;
1.8 ! schwarze 355: sysout $o, @{$test->{MANDOC}},
! 356: qw(-I os=OpenBSD -T markdown), $i
! 357: and fail $test->{NAME}, 'markdown:mandoc';
1.4 schwarze 358: system @diff, $w, $o
1.8 ! schwarze 359: and fail $test->{NAME}, 'markdown:diff';
! 360: print "." unless $targets{verbose};
1.4 schwarze 361: }
362: if ($targets{clean}) {
363: print "rm $o\n" if $targets{verbose};
1.8 ! schwarze 364: $count_rm += unlink $o;
1.4 schwarze 365: }
366: }
1.8 ! schwarze 367: if ($targets{markdown}) {
! 368: print "Number of markdown tests:" if $targets{verbose};
! 369: print " $count_markdown tests run.\n";
! 370: }
1.4 schwarze 371:
1.1 schwarze 372: my $count_lint = 0;
1.8 ! schwarze 373: if ($targets{lint}) {
! 374: print "Running lint tests ";
! 375: print "...\n" if $targets{verbose};
! 376: }
! 377: for my $test (@lint_tests) {
! 378: my $i = "$test->{NAME}.in";
! 379: my $o = "$test->{NAME}.mandoc_lint";
! 380: my $w = "$test->{NAME}.out_lint";
! 381: if ($targets{lint} && $test->{NAME} =~ /^$onlytest/) {
1.1 schwarze 382: $count_lint++;
383: $count_total++;
1.8 ! schwarze 384: syslint $o, @{$test->{MANDOC}},
! 385: qw(-I os=OpenBSD -T lint -W all), $i
! 386: and fail $test->{NAME}, 'lint:mandoc';
1.2 schwarze 387: system @diff, $w, $o
1.8 ! schwarze 388: and fail $test->{NAME}, 'lint:diff';
! 389: print "." unless $targets{verbose};
1.1 schwarze 390: }
391: if ($targets{clean}) {
392: print "rm $o\n" if $targets{verbose};
1.8 ! schwarze 393: $count_rm += unlink $o;
1.1 schwarze 394: }
395: }
1.8 ! schwarze 396: if ($targets{lint}) {
! 397: print "Number of lint tests:" if $targets{verbose};
! 398: print " $count_lint tests run.\n";
! 399: }
1.1 schwarze 400:
1.8 ! schwarze 401: # --- final report -----------------------------------------------------
1.1 schwarze 402:
403: if (@failures) {
1.8 ! schwarze 404: print "\nNUMBER OF FAILED TESTS: ", scalar @failures,
! 405: " (of $count_total tests run.)\n";
1.1 schwarze 406: print "@$_\n" for @failures;
407: print "\n";
408: exit 1;
1.8 ! schwarze 409: }
! 410: print "\n" if $targets{verbose};
! 411: if ($count_total == 1) {
! 412: print "Test succeeded.\n";
1.1 schwarze 413: } elsif ($count_total) {
1.8 ! schwarze 414: print "All $count_total tests OK:";
! 415: print " $count_ascii ascii" if $count_ascii;
! 416: print " $count_man man" if $count_man;
! 417: print " $count_utf8 utf8" if $count_utf8;
! 418: print " $count_html html" if $count_html;
! 419: print " $count_markdown markdown" if $count_markdown;
! 420: print " $count_lint lint" if $count_lint;
! 421: print "\n";
1.1 schwarze 422: } else {
1.8 ! schwarze 423: print "No tests were run.\n";
1.1 schwarze 424: }
1.8 ! schwarze 425: if ($targets{clean}) {
! 426: if ($count_rm) {
! 427: print "Deleted $count_rm test output files.\n";
! 428: print "The tree is now clean.\n";
! 429: } else {
! 430: print "No test output files were found.\n";
! 431: print "The tree was already clean.\n";
! 432: }
! 433: }
1.1 schwarze 434: exit 0;
CVSweb