#!/usr/bin/perl # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # This program is distributed with GNU Go, a Go program. # # # # Write gnugo@gnu.org or see http://www.gnu.org/software/gnugo/ # # for more information. # # # # Copyright 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 # # and 2008 by the Free Software Foundation. # # # # This program is free software; you can redistribute it and/or # # modify it under the terms of the GNU General Public License # # as published by the Free Software Foundation - version 3 # # or (at your option) any later version. # # # # This program is distributed in the hope that it will be # # useful, but WITHOUT ANY WARRANTY; without even the implied # # warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR # # PURPOSE. See the GNU General Public License in file COPYING # # for more details. # # # # You should have received a copy of the GNU General Public # # License along with this program; if not, write to the Free # # Software Foundation, Inc., 51 Franklin Street, Fifth Floor, # # Boston, MA 02111, USA. # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # Here is a perlscript regress.plx. # # It parses the XML files created by regress.pl and generates HTML. # It is designed to be run as a CGI script. #BEGIN { # use CGI::Carp qw(carpout); # my $errfile = "C:/temp/web.err"; # #open (WEBERR, ">$errfile") or die "Couldn't open $errfile."; # carpout(STDOUT); #} # use strict; use warnings; use CGI qw/:standard/; use CGI::Carp 'fatalsToBrowser'; use FindBin; use lib "$FindBin::Bin/../interface"; use GoImage::Stone; use HTML::Entities ;#qw/encode_entity/; #set $name to whatever this script is called in the URL. #eg, if you access it from http://example.com/regress/ #then set $name = "" my $name = "regress.plx"; my $debug=2; my %colors = ("ALIVE", "green", "DEAD", "cyan", "CRITICAL", "red", "UNKNOWN", "yellow", "UNCHECKED", "magenta"); my $query = new CGI; my ($tstfile, $num, $sortby, $sgf, $reset, $trace, $bycat, $unexpected, $slow, $special, $move, $small); ($tstfile, $num) = ($query->query_string() =~ /keywords=(.*)%3A(.*)/); if (!$tstfile) { $tstfile = $query->param("tstfile"); $num = $query->param("num"); $sortby = $query->param("sortby"); $sgf = $query->param("sgf"); $reset = $query->param("reset"); $trace = $query->param("trace"); $bycat = $query->param("bycat"); $unexpected = $query->param("unexpected"); $slow = $query->param("slow"); $special = $query->param("special"); $move = $query->param("move"); $small = $query->param("small"); } sub sgfFile(%); #print "HTTP/1.0 200 OK\r\n"; print "Content-type: " . do { my $plain = $trace; if ($sgf) { "application/x-go-sgf" } elsif ($plain) { "text/plain" } else {"text/html"; } } . "\r\n\r\n"; if ($tstfile) { $tstfile = $1 if $tstfile =~ /(.*)\.tst$/; } if ($tstfile && !($tstfile =~ /^[a-zA-Z0-9_]+$/)) { print "bad test file: $tstfile\n"; exit; } if ($reset) { unlink glob("html/*.html");# or die "couldn't delete html files: $!"; unlink glob("html/*/*.html");# or die "couldn't delete html/* files: $!"; unlink "html/one.perldata";# or die "couldn't delete data file"; print "Cleaned up!
\n"; } if ($trace) { open (TRACER, "html/$tstfile.tst/$num.trace") or do {print "Couldn't find trace file: $!"; exit;}; while () { print; } close TRACER; exit; } my %points; unless ($tstfile) { #CASE 1 - main index if (!-e "html/index.html") { createIndex(); } else { print STDERR "Cached!\n"; } if ($bycat) { printbycategory(); exit; } if ($unexpected) { printunexpected(); exit; } if ($slow) { printslow(); exit; } if ($special) { printspecial(); exit; } if (-z "html/index.html") { print "Yikes - index missing - please reset!"; exit; } open (TESTFILE, "html/index.html") or do {print "$! ".__LINE__; confess "$!"}; while () { print; } close TESTFILE; exit; } my %fullHash; #use Data::Dumper; sub insinglequote { my $s = shift; $s =~ s@\\@\\\\@g; $s =~ s@'@\\'@g; return "'$s'"; } sub FastDump { my ($h) = @_; open (FILE, ">html/one.perldata.new") or confess "can't open"; print FILE "\$VAR1 = [\n {\n"; #print FILE Dumper([\%h]) or confess "couldn't print"; foreach my $k1 (sort keys %{$h}) { print FILE " '$k1' =>\n {\n"; foreach my $k2 (sort keys %{%{$h}->{$k1}}) { print FILE " '$k2' => " . insinglequote(%{$h}->{$k1}->{$k2}) . ",\n"; } print FILE " },\n"; } print FILE " }\n ];"; close FILE or confess "can't close"; } sub createIndex { my %h; foreach my $file (glob("html/*.tst/*.xml")) { my ($tst, $prob) = $file =~ m@html.(.*).tst.(.*).xml@; open (FILE, "$file"); local $/; undef($/); my $content = ; close FILE; $h{"$tst:$prob"} = game_parse($content, 0); delete $h{"$tst:$prob"}->{gtp_all}; } FastDump(\%h); #print "DONE!\n"; #return; #our $VAR1; #do "html/one.perldata" or confess "can't do perldata"; #my %h = %{$VAR1->[0]}; open I, ">html/index.html"; print I qq@ Regression test summary -

Regression test summary -

Program: _CMDLINE_TBD_
View by category
View unexpected results
@; my @pflist = ("passed", "PASSED", "failed", "FAILED"); my %totHash; @totHash{@pflist} = (0,0,0,0); sub byfilebynum { my ($fileA,$numA) = $a =~ /(.*):(.*)/; my ($fileB,$numB) = $b =~ /(.*):(.*)/; $fileA cmp $fileB or $numA <=> $numB; } my $curfile = ""; my %subTotHash; foreach my $k1 (sort byfilebynum keys %h) { #$k1 = filename if ($k1 !~ /^$curfile:/) { if ($curfile ne "") { #New file = print old totals print I qq@\n \n@; foreach my $k2 (@pflist) { my $c = @{$subTotHash{$k2}}; #i.e. length of array. $totHash{$k2} += $c; if ($k2 !~ /passed/ and $c) { print I " \n"; } else { print I " \n"; } } print I qq@@; } #prepare for next file. ($curfile) = $k1 =~ /(.*):/; @subTotHash{@pflist} = ([],[],[],[]); } push @{$subTotHash{$h{$k1}{status}}}, $h{$k1}{num}; } #direct copy from above - don't miss last time through - HACK! if ($curfile ne "") { #New file = print old totals print I qq@\n \n@; foreach my $k2 (@pflist) { my $c = @{$subTotHash{$k2}}; #i.e. length of array. $totHash{$k2} += $c; if ($k2 !~ /passed/ and $c) { print I " \n"; } else { print I " \n"; } } print I qq@@; } print I "\n \n"; foreach (@pflist) { print I " \n"; } print I "\n"; print I "
filepassedPASSEDfailedFAILED
$curfile$c:
\n"; foreach (sort {$a<=>$b} @{$subTotHash{$k2}}) { print I qq@ $_\n@; } print I "
$c
$curfile$c:
\n"; foreach (sort {$a<=>$b} @{$subTotHash{$k2}}) { print I qq@ $_\n@; } print I "
$c
Total$totHash{$_}
\n"; close I; } sub bypPfF { pPfFtonum($a) <=> pPfFtonum($b); } sub pPfFtonum { $_ = shift; s/FAILED/4/; s/failed/3/; s/PASSED/2/; s/passed/1/; $_; } sub fptonum { $_ = shift; s/FAILED/1/; s/failed/3/; s/PASSED/2/; s/passed/4/; s///; s@@@; $_; } my @counters = qw/connection_node owl_node reading_node trymove/; if ($move) { #CASE 2a - move detail - extract interesting info from trace file. if (!$num) { print "Must provide num if providing move.
"; exit; } print qq@ $tstfile:$num move $move \n@; open (FILE, "html/$tstfile.tst/$num.trace") or die "couldn't open trace file $tstfile, $num: $!."; #local $/; undef($/); #my $content = ; #close FILE; my $blank=1; my $inpattern=0; $move = uc($move); print "
\n";
  while () {
    if (/^$move[^0-9]/ || 
        /[^A-Za-z0-9]$move[^0-9]/ || 
        $inpattern && /^\.\.\./) {
      print encode_entities($_);
      $blank=0;
      $inpattern ||= /^pattern.*at $move/;
    } else {
      print "\n" unless $blank;
      $blank++;
      $inpattern=0;
    }
  }
  print "
\n"; exit; } if ($num) { #CASE 2 - problem detail. if ($sgf && -e "html/$tstfile.tst/$num.sgf") { open (SGFFILE, "html/$tstfile.tst/$num.sgf") or confess "couldn't open file"; while () { print; } close SGFFILE; exit; } open (FILE, "html/$tstfile.tst/$num.xml") or die "couldn't open xml file\n"; local $/; undef($/); my $content = ; close FILE; my %attribs = %{game_parse($content, 1)}; if ($sgf) { foreach (sort keys %attribs) { # print "$_: $attribs{$_}\n"; } sgfFile(%attribs); exit; } print qq@ $tstfile:$num details. \n@; print qq@\n@; print qq@
number:$attribs{"num"}  cputime:$attribs{"cputime"}
status:$attribs{"status"}  $counters[0]:$attribs{"$counters[0]_counter"}
correct:$attribs{"correct"}  $counters[1]:$attribs{"$counters[1]_counter"}
answer:$attribs{"answer"}  $counters[2]:$attribs{"$counters[2]_counter"}
gtp:$attribs{"gtp_command"}  $counters[3]:$attribs{"$counters[3]_counter"}
category:$attribs{"category"}
severity:$attribs{"severity"}
description:$attribs{"description"}
\n\n@; print qq@
\n\n@; print qq@
SGF File    Trace File
@; print qq@
dragon_status | owl_status\n@; my $boardsize = $attribs{"boardsize"}; #need to add to export. my $colorboard; $colorboard .= "\n" . colorboard_letter_row($boardsize). "\n"; for (my $j = $boardsize; $j > 0; $j--) { my $jA = $j; $jA .= " " if ($j <= 9); $colorboard .= " \n \n"; for (my $i = 1; $i <= $boardsize; $i++) { my $iA = ord('A') + $i - 1; if ($iA >= ord('I')) { $iA++; } $iA = chr($iA); my $coord = $iA.$j; my $bw = pval($coord, "stone"); my $img_pix_size = 25; my $dragonletter = pval($coord, "dragon_letter"); my $dragoncolor = $colors{pval($coord, "dragon_status")}; my $owlcolor = $colors{pval($coord, "owl_status")}; my $owlletter = $dragonletter; my $alt = ""; my ($markcolor, $known, $try) = ("", pval($coord, "known"), pval($coord, "try")); $markcolor = "magenta" if ($known and $known eq "wrong"); $markcolor = "green" if ($known and $known eq "right"); $markcolor = "cyan" if ($try and $try eq "right"); $markcolor = "red" if ($try and $try eq "wrong"); my $question = pval($coord, "question"); if ($question) { $dragonletter .= "*"; $owlletter = ""; $dragoncolor = "blue" unless $dragoncolor; } my $score = pval($coord, "move_value"); if ($score) { # FIXME: Should round this, not truncate it. # Also, should remove trailing "." if not necessary. $dragonletter = substr($score, 0,3); $dragoncolor = "blue"; $owlletter=""; $alt = "whack"; } my $colorboard_imgsrc = createPngFile($bw, $img_pix_size, "", $dragonletter, $dragoncolor, $owlletter, $owlcolor, $markcolor); $colorboard .= qq@ \n@; } $colorboard .= " \n \n"; } $colorboard .= colorboard_letter_row($boardsize); $colorboard .= "\n
 $j @ . qq@ $j 
\n"; print $colorboard; print qq@
\n\n\n\n
green=alive
cyan=dead
red=critical
yellow=unknown
magenta=unchecked
@; my $gtpall = $attribs{gtp_all}; $gtpall =~ s/
//mg; $gtpall =~ s/\s+$//mg; $gtpall =~ m@loadsgf\s+ ((?:\w|[-+.\\/])+) [ \t]* (\d*) @x or $gtpall =~m/(.*?)/; #Problems!!!! my $cmdline = "gq -l $1 " . ($2 ? "-L $2 " : ""); if ($gtpall =~ m@ .* (owl_attack|owl_defend|dragon_status) \s* ([A-Z]\d{1,2}) \s* $ @x) { $cmdline .= "--decide-dragon $2 -o x.sgf" ; } elsif ($gtpall =~ m@ .* (reg_genmove\s+[whiteblack]*) \s* $@x) { $cmdline .= "-t -w -d0x101800"; } elsif ($gtpall =~ m@ .* (attack|defend) \s* ([A-Z]\d{1,2}) \s* $ @x) { $cmdline .= "--decide-string $2 -o x.sgf"; } else { $cmdline .= "
(directive unrecognized)"; } print qq@
\n\n@; print qq@\n@; print qq@ \n@; print qq@ \n
CMD Line Hint:$cmdline
Full GTP:$attribs{gtp_all}
\n@; print "\n\n"; # print %attribs; } else { if ($small) { summaryDiagrams(); } #CASE 3 - test file summary. # if (!-e "html/$tstfile.tst/index.html") { summarizeTestFile(); # } else { # print "Cached:
"; # } # open (TESTFILE, "html/$tstfile.tst/index.html") or (print "$! ".__LINE__, die); # while () { # print; # } # close TESTFILE; } sub summaryDiagrams { my $content; foreach my $curfile (glob("html/$tstfile.tst/*.xml")) { %points = {}; $curfile =~ s/html.$tstfile.tst.(.*xml)/$1/; local $/; undef($/); open(FILE, "html/$tstfile.tst/$curfile"); $content = ; close FILE; my %attribs = %{game_parse($content, 1)}; print qq@
$tstfile:$attribs{num}\n@; my $boardsize = $attribs{"boardsize"}; #need to add to export. my $colorboard; $colorboard .= "\n" . "\n"; my $img_pix_size = 9; for (my $j = $boardsize; $j > 0; $j--) { my $jA = $j; $jA .= " " if ($j <= 9); $colorboard .= "\n"; for (my $i = 1; $i <= $boardsize; $i++) { my $iA = ord('A') + $i - 1; if ($iA >= ord('I')) { $iA++; } $iA = chr($iA); my $coord = $iA.$j; my $bw = pval($coord, "stone"); my $alt = ""; my $colorboard_imgsrc = createPngFile($bw, $img_pix_size, "", "","","","", ""); $colorboard .= qq@ \n@; } $colorboard .= "\n"; } #$colorboard .= colorboard_letter_row($boardsize); $colorboard .= "\n
@ . qq@
\n"; print $colorboard; } exit; } my %files; sub summarizeTestFile { unless ($sortby) { $sortby = "filepos"; } # open (TF, "> html/$tstfile.tst/index.html") # or print "couldn't open for output; $!\n", die; *TF = *STDOUT; print TF qq@ $tstfile regression results - _VERSION_ \n@; print TF "\n"; print TF "

$tstfile regression results - _VERSION_

\n"; print TF qq@\n@; my @files = glob("html/$tstfile.tst/*.xml"); foreach my $curfile (@files) { $curfile =~ s/html.$tstfile.tst.(.*xml)/$1/; local $/; undef($/); open(FILE, "html/$tstfile.tst/$curfile"); my $content = ; close FILE; my $gtp_all = $1 if $content =~ m@(.*?)@s; my $gtp = escapeHTML($1) if $content =~ m@(.*?)@s; my $result = $1 if $content =~ m@(.*?)@s; my $got = $1 if $content =~ m@(.*?)@s; my $cputime = $1 if $content =~ m@]*owl_node="?(\d+)@s; my $reading_node = $1 if $content =~ m@]*reading_node="?(\d+)@s; $cputime =~ s/0*$//; $files{$curfile} = { gtp_all => $gtp_all, gtp => $gtp, filepos => $filepos, num => $num, expected => $expected, got => $got, result => $result, cputime => $cputime, owl_node => $owl_node, reading_node => $reading_node, msperowl => ($owl_node ? 1000*$cputime/ $owl_node : 0), } } sub byfilepos { $files{$a}{"filepos"} <=> $files{$b}{"filepos"}; } sub bynum { $files{$a}{"num"} <=> $files{$b}{"num"}; } sub byresult { fptonum($files{$a}{"result"}) <=> fptonum($files{$b}{"result"}) or byfilepos(); } sub bycputime { $files{$b}{cputime} <=> $files{$a}{cputime} or byfilepos(); } sub byowl_node { $files{$b}{owl_node} <=> $files{$a}{owl_node} or byfilepos(); } sub byreading_node { $files{$b}{reading_node} <=> $files{$a}{reading_node} or byfilepos(); } sub bymsperowl { $files{$b}{msperowl} <=> $files{$a}{msperowl} or byfilepos(); } sub filesby { $_ = shift; return byfilepos if /filepos/i; return bynum if /num/i; return byresult if /result/i; return bycputime if /cputime/i; return byowl_node if /owl_node/i || /owlnode/i; return bymsperowl if /msperowl/i; return byreading_node if /reading_node/i || /readingnode/i; $files{$a}{$_} <=> $files{$b}{$_}; } my %totals = (cputime=>0, owl_node=>0); foreach my $curfile (sort {filesby($sortby)} keys %files) { my %h = %{$files{$curfile}}; my $numURL = qq@$h{num}@; my $r = $h{result}; $r =~ s@^([A-Z]*)$@$1@; print TF "" . "" . "" . "\n"; $totals{cputime} += $h{cputime}; $totals{owl_node} += $h{owl_node}; $totals{reading_node} += $h{reading_node}; } print TF "" . "" . "" ." \n"; print TF "
line number result expected got gtp cputime owl_node reading_node 1000*time/owl_node
$h{filepos}$numURL$r$h{expected}$h{got}$h{gtp}$h{cputime}$h{owl_node}$h{reading_node}".sprintf("%.2f",$h{msperowl})."
Total     $totals{cputime}$totals{owl_node}$totals{reading_node}".sprintf("%.2f",1000*$totals{cputime}/($totals{owl_node}+.0001))."
"; #close TF; } sub pval { my ($coord, $attrib) = @_; if ($points{$coord}) { # print "$coord $attrib
\n"; if ($points{$coord} =~ m@$attrib="(.*?)"@) { # if ($attrib eq 'stone') { # print "$attrib=$1
\n"; #} return $1; } else { return ""; } } else { return ""; } } sub game_parse { my $content = shift; my $details = shift; my %attribs; $attribs{"num"} = $1 if $content =~ m@(.*?)@s; $attribs{"answer"} = $1 if $content =~ m@(.*?)@s; $attribs{"gtp_all"} = $1 if $content =~ m@(.*?)@s; $attribs{"description"} = $1 if $content =~ m@(.*?)@s; $attribs{"category"} = $1 if $content =~ m@(.*?)@s; $attribs{"severity"} = $1 if $content =~ m@(.*?)@s; $attribs{"gtp_command"} = $1 if $content =~ m@(.*?)@s; $attribs{"cputime"} = $1 if $content =~ m@]*size=(\d+)@s; foreach (@counters) { $attribs{$_."_counter"} = $1 if $content =~ m@]*$_="?(\d+)@s; } return \%attribs unless $details; $content =~ s@.*?@@s) { my $pattr = $1; if ($pattr =~ m@coord="(.*?)"@s) { $points{$1} = $pattr; } else { print "

MISSING coord: " . encode($content) . "

" . encode($pattr); die; } } return \%attribs; } sub colorboard_letter_row { my $boardsize = shift; my $ret = " \n  \n"; for (my $i = 1; $i <= $boardsize; $i++) { my $iA = ord('A') + $i - 1; if ($iA >= ord('I')) { $iA++; } $iA = chr($iA); $ret .= " $iA\n"; } $ret .= "  \n "; } sub sgfFile(%) { my %attribs = shift; my $boardsize = $attribs{"boardsize"}; #need to add to export. my $ret=""; $ret .= "(;\nFF[4]GM[1]SZ[$boardsize]\nAP[regress.plx]\n"; for (my $j = $boardsize; $j > 0; $j--) { my $jA = $j; $jA .= " " if ($j <= 9); for (my $i = 1; $i <= $boardsize; $i++) { my $iA = ord('A') + $i - 1; if ($iA >= ord('I')) { $iA++; } $iA = chr($iA); my $coord = $iA.$j; my $bw = pval($coord, "stone"); if ($bw eq "black") { $ret .= "AB\[" . GTPtoSGF($coord, $boardsize) . "]"; } elsif ($bw eq "white") { $ret .= "AW\[" . GTPtoSGF($coord, $boardsize) . "]"; } } } $ret.=")"; $ret =~ s/((A[BW]\[..\]){12})/$1\n/g; print $ret; } sub GTPtoSGF { local $_ = shift; my $boardsize = shift; if (! /([A-Z])([0-9]{1,2})/) { return ; } $_ = ord($1) - ord("A") + 1; if ($_ > (ord("I") - ord("A") + 1)) { $_--; } chr(ord("a") + $_ - 1) . chr(ord("a") + $boardsize - $2); } sub printslow { our $VAR1; do "html/one.perldata.new" or confess "can't do perldata"; my %h = %{$VAR1->[0]}; my $by_cputime = sub { $h{$b}->{cputime} <=> $h{$a}->{cputime} or $a cmp $b; }; print qq@ Slow results - GNU Go \n@; print "

Slow results

"; print ""; print "\n"; my $i = 0; foreach my $k (sort $by_cputime keys %h) { $i++; last if $i > 50; print qq@@; print qq@ @; my ($p, $n) = $k =~ /(\w+):(\d+)/; open (F, "html/$p.tst/$n.trace") or do {print "Missing trace file for $k
"; next;}; my $first=1; while () { my $line = $_; if ($line =~ /^owl_.*\d{6} nodes/) { print qq@@ if $first < 1; close F; } print "
ProblemStatusCPU Time
$k$h{$k}->{status}$h{$k}->{cputime}
  @ if $first-- > 0; print qq@$line
@; } } print qq@
\n"; } sub printspecial { our $VAR1; do "html/one.perldata.new" or confess "can't do perldata"; my %h = %{$VAR1->[0]}; my (%special); my $sfile = "special"; print qq@ Special results - GNU Go \n@; print "

Special results

"; print ""; print "\n"; if (-e $sfile) { open (BF, $sfile); while () { if (/^((\w+):(\d+))/) { print qq@@ . qq@\n@; } } close(BF); } print qq@
ProblemStatuscputime
$1$h{$1}->{status}$h{$1}->{cputime}
@; } sub printunexpected{ my (%breakage); if (-e 'BREAKAGE.local') { open (BF, 'BREAKAGE.local'); while () { if (my ($bfile, $bpf) = $_ =~ /^(\w+:\d+)\s+(FAILED|PASSED)/i) { $breakage{lc $bfile} = $bpf; } } close(BF); } our $VAR1; do "html/one.perldata.new" or confess "can't do perldata"; my %h = %{$VAR1->[0]}; my @fails; my @ufails; my @passes; my @upasses; print qq@ Unexpected results - GNU Go \n@; print "

Unexpected results

"; sub bynamenumber { my ($aname, $anumber) = $a =~ /(.*):(.*)/; my ($bname, $bnumber) = $b =~ /(.*):(.*)/; $aname cmp $bname or $anumber <=> $bnumber or $a cmp $b; } foreach my $k (sort bynamenumber keys %h) { my $status = %{$h{$k}}->{status}; defined $status or do { warn "missing status for $k"; next;}; if ($status eq 'FAILED') { unless (defined ($breakage{lc $k}) and $breakage{lc $k}eq 'FAILED') { push @ufails, $k; } } elsif ($status eq 'PASSED') { unless (defined ($breakage{lc $k}) and $breakage{lc $k} eq 'PASSED') { push @upasses, $k; } } elsif ($status eq 'passed') { if (defined ($breakage{lc $k})) { push @passes, $k; } } elsif ($status eq 'failed') { if (defined ($breakage{lc $k})) { push @fails, $k; } } } print "\n"; print qq@\n@; print qq@\n@; print qq@\n@; print qq@\n@; print qq@\n@; print "
FAILS@.scalar(@ufails).qq@
fails@.scalar(@fails).qq@
PASSES@.scalar(@upasses).qq@
passes@.scalar(@passes).qq@
pass : fail@. sprintf("%.2f : 1", ((@upasses + @passes) / (@ufails + @fails + .001))). qq@

\n"; print ""; print "\n"; foreach (@ufails) { print qq@\n@; } foreach (@fails) { print qq@\n@; } foreach (@upasses) { print qq@\n@; } foreach (@passes) { print qq@\n@; } print "
ProblemStatus
$_FAILED
$_failed
$_PASSED
$_passed
\n"; print "\n"; } sub printbycategory { our $VAR1; do "html/one.perldata.new" or confess "can't do perldata"; my %hash = %{$VAR1->[0]}; my %fails; foreach my $k (keys %hash) { my $status = $hash{$k}{status}; $fails{$k} = $hash{$k} if $status =~ /failed/i; } my $by_cat = sub { defined $fails{$a}{file} or do { print '$a:'."$a\n"; confess "missing file"; }; my $ca = $fails{$a}{category}; my $cb = $fails{$b}{category}; defined $ca or $ca = 0; defined $cb or $cb = 0; if ($ca ne "" and $cb eq "") { return -1; } if ($ca eq "" and $cb ne "") { return 1; } $ca ne "" or $ca = $fails{$a}{file}; $cb ne "" or $cb = $fails{$b}{file}; uc ($ca) cmp uc($cb) or do { my $sa = $fails{$a}{severity}; my $sb = $fails{$b}{severity}; #print '$sa <=> $sb :' . "$sa <=> $sb ($ca, $cb)" , "\n" # if defined $sa and defined $sb and ($sa ne "") and ($sb ne ""); defined $sa or $sa = 5; defined $sb or $sb = 5; if ($sa eq "") {$sa = 5}; if ($sb eq "") {$sb = 5}; -($sa <=> $sb); } or do { my $fa = $fails{$a}{file}; my $fb = $fails{$b}{file}; $fa cmp $fb; } or do { my $na = $fails{$a}{num}; my $nb = $fails{$b}{num}; $na <=> $nb; } }; sub getcat(%) { my %h = %{shift()}; $h{category} or $h{file}; } sub getsev(%) { my %h = %{shift()}; my $s = $h{severity}; defined $s or do {return 5}; $s ne "" or do {return 5}; no warnings qw/numeric/; $s+0; } print qq@ Failures by category - GNU Go \n@; print "

Failures by category

"; print qq@main index@; print ""; print "\n"; my $cat = ""; my $sev = ""; foreach my $k (sort $by_cat keys %fails) { if (uc(getcat($fails{$k})) ne $cat) { $cat = uc(getcat($fails{$k})); print "\n"; print "\n"; $sev = ""; } if (($sev eq "") or $sev != getsev($fails{$k})) { print "\n" if ($sev ne ""); $sev = getsev($fails{$k}); print "
CategorySeverityProblem
$cat
 $sev\n"; } print qq@$k  \n@; } print "
\n"; print "\n"; }