[BACK]Return to regress.pl CVS log [TXT][DIR] Up to [cvsweb.bsd.lv] / mandoc / regress

Annotation of mandoc/regress/regress.pl, Revision 1.9

1.1       schwarze    1: #!/usr/bin/env perl
                      2: #
1.9     ! schwarze    3: # $Id: regress.pl,v 1.8 2017/07/18 18:47:06 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, @_;
1.9     ! schwarze   82:        my $state = 0;
1.1       schwarze   83:        while (<$infd>) {
                     84:                chomp;
                     85:                if (!$state && s/.*<math class="eqn">//) {
1.9     ! schwarze   86:                        $state = 'math';
1.1       schwarze   87:                        next unless length;
1.9     ! schwarze   88:                } elsif (/^BEGINTEST/) {
        !            89:                        $state = 'other';
1.1       schwarze   90:                }
1.9     ! schwarze   91:                if ($state eq 'math') {
1.1       schwarze   92:                        s/^ *//;
1.9     ! schwarze   93:                        if (s/<\/math>.*//) {
        !            94:                                print $outfd "$_\n" if length;
        !            95:                                $state = 0;
        !            96:                                next;
        !            97:                        }
1.1       schwarze   98:                }
                     99:                print $outfd "$_\n" if $state;
1.9     ! schwarze  100:                $state = 0 if /^ENDTEST/;
1.1       schwarze  101:        }
                    102:        close $outfd;
                    103:        close $infd;
                    104:        waitpid $pid, 0;
                    105:        return 0;
                    106: }
                    107:
                    108: my @failures;
1.8       schwarze  109: sub fail ($$) {
1.1       schwarze  110:        warn "FAILED: @_\n";
                    111:        push @failures, [@_];
                    112: }
                    113:
                    114:
                    115: # --- process command line arguments -----------------------------------
                    116:
1.8       schwarze  117: my $onlytest = shift // '';
1.1       schwarze  118: for (@ARGV) {
1.4       schwarze  119:        /^(all|ascii|utf8|man|html|markdown|lint|clean|verbose)$/
1.1       schwarze  120:            or usage "$_: invalid modifier";
                    121:        $targets{$_} = 1;
                    122: }
                    123: $targets{all} = 1
                    124:     unless $targets{ascii} || $targets{utf8} || $targets{man} ||
1.4       schwarze  125:       $targets{html} || $targets{markdown} ||
                    126:       $targets{lint} || $targets{clean};
1.1       schwarze  127: $targets{ascii} = $targets{utf8} = $targets{man} = $targets{html} =
1.4       schwarze  128:     $targets{markdown} = $targets{lint} = 1 if $targets{all};
1.1       schwarze  129:
                    130:
                    131: # --- parse Makefiles --------------------------------------------------
                    132:
1.8       schwarze  133: sub parse_makefile ($%) {
                    134:        my ($filename, $vars) = @_;
1.1       schwarze  135:        open my $fh, '<', $filename or die "$filename: $!";
                    136:        while (<$fh>) {
                    137:                chomp;
                    138:                next unless /\S/;
                    139:                last if /^# OpenBSD only/;
                    140:                next if /^#/;
                    141:                next if /^\.include/;
                    142:                /^(\w+)\s*([?+]?)=\s*(.*)/
                    143:                    or die "$filename: parse error: $_";
                    144:                my $var = $1;
                    145:                my $opt = $2;
                    146:                my $val = $3;
1.8       schwarze  147:                $val =~ s/\$\{(\w+)\}/$vars->{$1}/;
                    148:                $val = "$vars->{$var} $val" if $opt eq '+';
                    149:                $vars->{$var} = $val
                    150:                    unless $opt eq '?' && defined $vars->{$var};
1.1       schwarze  151:        }
                    152:        close $fh;
                    153: }
                    154:
1.8       schwarze  155: my (@regress_tests, @utf8_tests, @lint_tests, @html_tests);
                    156: my (%skip_ascii, %skip_man, %skip_markdown);
                    157: foreach my $module (qw(roff char mdoc man tbl eqn)) {
                    158:        my %modvars;
                    159:        parse_makefile "$module/Makefile", \%modvars;
                    160:        foreach my $subdir (split ' ', $modvars{SUBDIR}) {
                    161:                my %subvars = (MOPTS => '');
                    162:                parse_makefile "$module/$subdir/Makefile", \%subvars;
                    163:                parse_makefile "$module/Makefile.inc", \%subvars;
                    164:                delete $subvars{SKIP_GROFF};
                    165:                delete $subvars{SKIP_GROFF_ASCII};
                    166:                delete $subvars{TBL};
                    167:                delete $subvars{EQN};
                    168:                my @mandoc = ('../mandoc', split ' ', $subvars{MOPTS});
                    169:                delete $subvars{MOPTS};
                    170:                my @regress_testnames;
                    171:                if (defined $subvars{REGRESS_TARGETS}) {
                    172:                        push @regress_testnames,
                    173:                            split ' ', $subvars{REGRESS_TARGETS};
                    174:                        push @regress_tests, {
                    175:                            NAME => "$module/$subdir/$_",
                    176:                            MANDOC => \@mandoc,
                    177:                        } foreach @regress_testnames;
                    178:                        delete $subvars{REGRESS_TARGETS};
                    179:                }
                    180:                if (defined $subvars{UTF8_TARGETS}) {
                    181:                        push @utf8_tests, {
                    182:                            NAME => "$module/$subdir/$_",
                    183:                            MANDOC => \@mandoc,
                    184:                        } foreach split ' ', $subvars{UTF8_TARGETS};
                    185:                        delete $subvars{UTF8_TARGETS};
                    186:                }
                    187:                if (defined $subvars{HTML_TARGETS}) {
                    188:                        push @html_tests, {
                    189:                            NAME => "$module/$subdir/$_",
                    190:                            MANDOC => \@mandoc,
                    191:                        } foreach split ' ', $subvars{HTML_TARGETS};
                    192:                        delete $subvars{HTML_TARGETS};
                    193:                }
                    194:                if (defined $subvars{LINT_TARGETS}) {
                    195:                        push @lint_tests, {
                    196:                            NAME => "$module/$subdir/$_",
                    197:                            MANDOC => \@mandoc,
                    198:                        } foreach split ' ', $subvars{LINT_TARGETS};
                    199:                        delete $subvars{LINT_TARGETS};
                    200:                }
                    201:                if (defined $subvars{SKIP_ASCII}) {
                    202:                        for (split ' ', $subvars{SKIP_ASCII}) {
                    203:                                $skip_ascii{"$module/$subdir/$_"} = 1;
                    204:                                $skip_man{"$module/$subdir/$_"} = 1;
                    205:                        }
                    206:                        delete $subvars{SKIP_ASCII};
                    207:                }
                    208:                if (defined $subvars{SKIP_TMAN}) {
                    209:                        $skip_man{"$module/$subdir/$_"} = 1
                    210:                            for split ' ', $subvars{SKIP_TMAN};
                    211:                        delete $subvars{SKIP_TMAN};
                    212:                }
                    213:                if (defined $subvars{SKIP_MARKDOWN}) {
                    214:                        $skip_markdown{"$module/$subdir/$_"} = 1
                    215:                            for split ' ', $subvars{SKIP_MARKDOWN};
                    216:                        delete $subvars{SKIP_MARKDOWN};
                    217:                }
                    218:                if (keys %subvars) {
                    219:                        my @vars = keys %subvars;
                    220:                        die "unknown var(s) @vars in dir $module/$subdir";
                    221:                }
                    222:                map {
                    223:                        $skip_ascii{"$module/$subdir/$_"} = 1;
                    224:                } @regress_testnames if $skip_ascii{"$module/$subdir/ALL"};
                    225:                map {
                    226:                        $skip_man{"$module/$subdir/$_"} = 1;
                    227:                } @regress_testnames if $skip_man{"$module/$subdir/ALL"};
                    228:                map {
                    229:                        $skip_markdown{"$module/$subdir/$_"} = 1;
                    230:                } @regress_testnames if $skip_markdown{"$module/$subdir/ALL"};
                    231:        }
                    232:        delete $modvars{SUBDIR};
                    233:        if (keys %modvars) {
                    234:                my @vars = keys %modvars;
                    235:                die "unknown var(s) @vars in module $module";
                    236:        }
1.1       schwarze  237: }
                    238:
                    239: # --- run targets ------------------------------------------------------
                    240:
                    241: my $count_total = 0;
                    242: my $count_ascii = 0;
                    243: my $count_man = 0;
1.8       schwarze  244: my $count_rm = 0;
                    245: if ($targets{ascii} || $targets{man}) {
                    246:        print "Running ascii and man tests ";
                    247:        print "...\n" if $targets{verbose};
                    248: }
                    249: for my $test (@regress_tests) {
                    250:        my $i = "$test->{NAME}.in";
                    251:        my $o = "$test->{NAME}.mandoc_ascii";
                    252:        my $w = "$test->{NAME}.out_ascii";
                    253:        if ($targets{ascii} && !$skip_ascii{$test->{NAME}} &&
                    254:            $test->{NAME} =~ /^$onlytest/) {
1.1       schwarze  255:                $count_ascii++;
                    256:                $count_total++;
1.8       schwarze  257:                sysout $o, @{$test->{MANDOC}}, qw(-I os=OpenBSD -T ascii), $i
                    258:                    and fail $test->{NAME}, 'ascii:mandoc';
1.2       schwarze  259:                system @diff, $w, $o
1.8       schwarze  260:                    and fail $test->{NAME}, 'ascii:diff';
                    261:                print "." unless $targets{verbose};
1.1       schwarze  262:        }
1.8       schwarze  263:        my $m = "$test->{NAME}.in_man";
                    264:        my $mo = "$test->{NAME}.mandoc_man";
                    265:        if ($targets{man} && !$skip_man{$test->{NAME}} &&
                    266:            $test->{NAME} =~ /^$onlytest/) {
1.1       schwarze  267:                $count_man++;
                    268:                $count_total++;
1.8       schwarze  269:                sysout $m, @{$test->{MANDOC}}, qw(-I os=OpenBSD -T man), $i
                    270:                    and fail $test->{NAME}, 'man:man';
                    271:                sysout $mo, @{$test->{MANDOC}},
                    272:                    qw(-man -I os=OpenBSD -T ascii -O mdoc), $m
                    273:                    and fail $test->{NAME}, 'man:mandoc';
1.2       schwarze  274:                system @diff, $w, $mo
1.8       schwarze  275:                    and fail $test->{NAME}, 'man:diff';
                    276:                print "." unless $targets{verbose};
1.1       schwarze  277:        }
                    278:        if ($targets{clean}) {
1.8       schwarze  279:                print "rm $o $m $mo\n" if $targets{verbose};
                    280:                $count_rm += unlink $o, $m, $mo;
1.1       schwarze  281:        }
                    282: }
1.8       schwarze  283: if ($targets{ascii} || $targets{man}) {
                    284:        print "Number of ascii and man tests:" if $targets{verbose};
                    285:        print " $count_ascii + $count_man tests run.\n";
                    286: }
1.1       schwarze  287:
                    288: my $count_utf8 = 0;
1.8       schwarze  289: if ($targets{utf8}) {
                    290:        print "Running utf8 tests ";
                    291:        print "...\n" if $targets{verbose};
                    292: }
                    293: for my $test (@utf8_tests) {
                    294:        my $i = "$test->{NAME}.in";
                    295:        my $o = "$test->{NAME}.mandoc_utf8";
                    296:        my $w = "$test->{NAME}.out_utf8";
                    297:        if ($targets{utf8} && $test->{NAME} =~ /^$onlytest/o) {
1.1       schwarze  298:                $count_utf8++;
                    299:                $count_total++;
1.8       schwarze  300:                sysout $o, @{$test->{MANDOC}}, qw(-I os=OpenBSD -T utf8), $i
                    301:                    and fail $test->{NAME}, 'utf8:mandoc';
1.2       schwarze  302:                system @diff, $w, $o
1.8       schwarze  303:                    and fail $test->{NAME}, 'utf8:diff';
                    304:                print "." unless $targets{verbose};
1.1       schwarze  305:        }
                    306:        if ($targets{clean}) {
                    307:                print "rm $o\n" if $targets{verbose};
1.8       schwarze  308:                $count_rm += unlink $o;
1.1       schwarze  309:        }
                    310: }
1.8       schwarze  311: if ($targets{utf8}) {
                    312:        print "Number of utf8 tests:" if $targets{verbose};
                    313:        print " $count_utf8 tests run.\n";
                    314: }
1.1       schwarze  315:
                    316: my $count_html = 0;
1.8       schwarze  317: if ($targets{html}) {
                    318:        print "Running html tests ";
                    319:        print "...\n" if $targets{verbose};
                    320: }
                    321: for my $test (@html_tests) {
                    322:        my $i = "$test->{NAME}.in";
                    323:        my $o = "$test->{NAME}.mandoc_html";
                    324:        my $w = "$test->{NAME}.out_html";
                    325:        if ($targets{html} && $test->{NAME} =~ /^$onlytest/) {
1.1       schwarze  326:                $count_html++;
                    327:                $count_total++;
1.8       schwarze  328:                syshtml $o, @{$test->{MANDOC}}, qw(-T html), $i
                    329:                    and fail $test->{NAME}, 'html:mandoc';
1.2       schwarze  330:                system @diff, $w, $o
1.8       schwarze  331:                    and fail $test->{NAME}, 'html:diff';
                    332:                print "." unless $targets{verbose};
1.1       schwarze  333:        }
                    334:        if ($targets{clean}) {
                    335:                print "rm $o\n" if $targets{verbose};
1.8       schwarze  336:                $count_rm += unlink $o;
1.1       schwarze  337:        }
                    338: }
1.8       schwarze  339: if ($targets{html}) {
                    340:        print "Number of html tests:" if $targets{verbose};
                    341:        print " $count_html tests run.\n";
                    342: }
1.1       schwarze  343:
1.4       schwarze  344: my $count_markdown = 0;
1.8       schwarze  345: if ($targets{markdown}) {
                    346:        print "Running markdown tests ";
                    347:        print "...\n" if $targets{verbose};
                    348: }
                    349: for my $test (@regress_tests) {
                    350:        my $i = "$test->{NAME}.in";
                    351:        my $o = "$test->{NAME}.mandoc_markdown";
                    352:        my $w = "$test->{NAME}.out_markdown";
                    353:        if ($targets{markdown} && !$skip_markdown{$test->{NAME}} &&
                    354:            $test->{NAME} =~ /^$onlytest/) {
1.4       schwarze  355:                $count_markdown++;
                    356:                $count_total++;
1.8       schwarze  357:                sysout $o, @{$test->{MANDOC}},
                    358:                    qw(-I os=OpenBSD -T markdown), $i
                    359:                    and fail $test->{NAME}, 'markdown:mandoc';
1.4       schwarze  360:                system @diff, $w, $o
1.8       schwarze  361:                    and fail $test->{NAME}, 'markdown:diff';
                    362:                print "." unless $targets{verbose};
1.4       schwarze  363:        }
                    364:        if ($targets{clean}) {
                    365:                print "rm $o\n" if $targets{verbose};
1.8       schwarze  366:                $count_rm += unlink $o;
1.4       schwarze  367:        }
                    368: }
1.8       schwarze  369: if ($targets{markdown}) {
                    370:        print "Number of markdown tests:" if $targets{verbose};
                    371:        print " $count_markdown tests run.\n";
                    372: }
1.4       schwarze  373:
1.1       schwarze  374: my $count_lint = 0;
1.8       schwarze  375: if ($targets{lint}) {
                    376:        print "Running lint tests ";
                    377:        print "...\n" if $targets{verbose};
                    378: }
                    379: for my $test (@lint_tests) {
                    380:        my $i = "$test->{NAME}.in";
                    381:        my $o = "$test->{NAME}.mandoc_lint";
                    382:        my $w = "$test->{NAME}.out_lint";
                    383:        if ($targets{lint} && $test->{NAME} =~ /^$onlytest/) {
1.1       schwarze  384:                $count_lint++;
                    385:                $count_total++;
1.8       schwarze  386:                syslint $o, @{$test->{MANDOC}},
                    387:                    qw(-I os=OpenBSD -T lint -W all), $i
                    388:                    and fail $test->{NAME}, 'lint:mandoc';
1.2       schwarze  389:                system @diff, $w, $o
1.8       schwarze  390:                    and fail $test->{NAME}, 'lint:diff';
                    391:                print "." unless $targets{verbose};
1.1       schwarze  392:        }
                    393:        if ($targets{clean}) {
                    394:                print "rm $o\n" if $targets{verbose};
1.8       schwarze  395:                $count_rm += unlink $o;
1.1       schwarze  396:        }
                    397: }
1.8       schwarze  398: if ($targets{lint}) {
                    399:        print "Number of lint tests:" if $targets{verbose};
                    400:        print " $count_lint tests run.\n";
                    401: }
1.1       schwarze  402:
1.8       schwarze  403: # --- final report -----------------------------------------------------
1.1       schwarze  404:
                    405: if (@failures) {
1.8       schwarze  406:        print "\nNUMBER OF FAILED TESTS: ", scalar @failures,
                    407:            " (of $count_total tests run.)\n";
1.1       schwarze  408:        print "@$_\n" for @failures;
                    409:        print "\n";
                    410:        exit 1;
1.8       schwarze  411: }
                    412: print "\n" if $targets{verbose};
                    413: if ($count_total == 1) {
                    414:        print "Test succeeded.\n";
1.1       schwarze  415: } elsif ($count_total) {
1.8       schwarze  416:        print "All $count_total tests OK:";
                    417:        print " $count_ascii ascii" if $count_ascii;
                    418:        print " $count_man man" if $count_man;
                    419:        print " $count_utf8 utf8" if $count_utf8;
                    420:        print " $count_html html" if $count_html;
                    421:        print " $count_markdown markdown" if $count_markdown;
                    422:        print " $count_lint lint" if $count_lint;
                    423:        print "\n";
1.1       schwarze  424: } else {
1.8       schwarze  425:        print "No tests were run.\n";
1.1       schwarze  426: }
1.8       schwarze  427: if ($targets{clean}) {
                    428:        if ($count_rm) {
                    429:                print "Deleted $count_rm test output files.\n";
                    430:                print "The tree is now clean.\n";
                    431:        } else {
                    432:                print "No test output files were found.\n";
                    433:                print "The tree was already clean.\n";
                    434:        }
                    435: }
1.1       schwarze  436: exit 0;

CVSweb