performtest.pl 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. #!/usr/bin/perl
  2. #Perform tests on nasm
  3. use strict;
  4. use warnings;
  5. use Getopt::Long qw(GetOptions);
  6. use Pod::Usage qw(pod2usage);
  7. use File::Basename qw(fileparse);
  8. use File::Compare qw(compare compare_text);
  9. use File::Copy qw(move);
  10. use File::Path qw(mkpath rmtree);
  11. #sub debugprint { print (pop() . "\n"); }
  12. sub debugprint { }
  13. my $globalresult = 0;
  14. #Process one testfile
  15. sub perform {
  16. my ($clean, $diff, $golden, $nasm, $quiet, $testpath) = @_;
  17. my ($stdoutfile, $stderrfile) = ("stdout", "stderr");
  18. my ($testname, $ignoredpath, $ignoredsuffix) = fileparse($testpath, ".asm");
  19. debugprint $testname;
  20. my $outputdir = $golden ? "golden" : "testresults";
  21. mkdir "$outputdir" unless -d "$outputdir";
  22. if ($clean) {
  23. rmtree "$outputdir/$testname";
  24. return;
  25. }
  26. if(-d "$outputdir/$testname") {
  27. rmtree "$outputdir/$testname";
  28. }
  29. open(TESTFILE, '<', $testpath) or (warn "Can't open $testpath\n", return);
  30. TEST:
  31. while(<TESTFILE>) {
  32. #See if there is a test case
  33. last unless /Testname=(.*);\s*Arguments=(.*);\s*Files=(.*)/;
  34. my ($subname, $arguments, $files) = ($1, $2, $3);
  35. debugprint("$subname | $arguments | $files");
  36. #Call nasm with this test case
  37. system("$nasm $arguments $testpath > $stdoutfile 2> $stderrfile");
  38. debugprint("$nasm $arguments $testpath > $stdoutfile 2> $stderrfile ----> $?");
  39. #Move the output to the test dir
  40. mkpath("$outputdir/$testname/$subname");
  41. foreach(split / /,$files) {
  42. if (-f $_) {
  43. move($_, "$outputdir/$testname/$subname/$_") or die $!
  44. }
  45. }
  46. unlink ("$stdoutfile", "$stderrfile"); #Just to be sure
  47. if($golden) {
  48. print "Test $testname/$subname created.\n" unless $quiet;
  49. } else {
  50. #Compare them with the golden files
  51. my $result = 0;
  52. my @failedfiles = ();
  53. foreach(split / /, $files) {
  54. if(-f "$outputdir/$testname/$subname/$_") {
  55. my $temp;
  56. if($_ eq $stdoutfile or $_ eq $stderrfile) {
  57. #Compare stdout and stderr in text mode so line ending changes won't matter
  58. $temp = compare_text("$outputdir/$testname/$subname/$_", "golden/$testname/$subname/$_",
  59. sub { my ($a, $b) = @_;
  60. $a =~ s/\r//g;
  61. $b =~ s/\r//g;
  62. $a ne $b; } );
  63. } else {
  64. $temp = compare("$outputdir/$testname/$subname/$_", "golden/$testname/$subname/$_");
  65. }
  66. if($temp == 1) {
  67. #different
  68. $result = 1;
  69. $globalresult = 1;
  70. push @failedfiles, $_;
  71. } elsif($temp == -1) {
  72. #error
  73. print "Can't compare at $testname/$subname file $_\n";
  74. next TEST;
  75. }
  76. } elsif (-f "golden/$testname/$subname/$_") {
  77. #File exists in golden but not in output
  78. $result = 1;
  79. $globalresult = 1;
  80. push @failedfiles, $_;
  81. }
  82. }
  83. if($result == 0) {
  84. print "Test $testname/$subname succeeded.\n" unless $quiet;
  85. } elsif ($result == 1) {
  86. print "Test $testname/$subname failed on @failedfiles.\n";
  87. if($diff) {
  88. for(@failedfiles) {
  89. if($_ eq $stdoutfile or $_ eq $stderrfile) {
  90. system "diff -u golden/$testname/$subname/$_ $outputdir/$testname/$subname/$_";
  91. print "\n";
  92. }
  93. }
  94. }
  95. } else {
  96. die "Impossible result";
  97. }
  98. }
  99. }
  100. close(TESTFILE);
  101. }
  102. my $nasm;
  103. my $clean = 0;
  104. my $diff = 0;
  105. my $golden = 0;
  106. my $help = 0;
  107. my $verbose = 0;
  108. GetOptions('clean' => \$clean,
  109. 'diff'=> \$diff,
  110. 'golden' => \$golden,
  111. 'help' => \$help,
  112. 'verbose' => \$verbose,
  113. 'nasm=s' => \$nasm
  114. ) or pod2usage();
  115. pod2usage() if $help;
  116. die "Please specify either --nasm or --clean. Use --help for help.\n"
  117. unless $nasm or $clean;
  118. die "Please specify the test files, e.g. *.asm\n" unless @ARGV;
  119. unless (!defined $nasm or -x $nasm) {
  120. warn "Warning: $nasm may not be executable. Expect problems.\n\n";
  121. sleep 5;
  122. }
  123. perform($clean, $diff, $golden, $nasm, ! $verbose, $_) foreach @ARGV;
  124. exit $globalresult;
  125. __END__
  126. =head1 NAME
  127. performtest.pl - NASM regression tester based on golden files
  128. =head1 SYNOPSIS
  129. performtest.pl [options] [testfile.asm ...]
  130. Runs NASM on the specified test files and compare the results
  131. with "golden" output files.
  132. Options:
  133. --clean Clean up test results (or golden files with --golden)
  134. --diff Execute diff when stdout or stderr don't match
  135. --golden Create golden files
  136. --help Get this help
  137. --nasm=file Specify the file name for the NASM executable, e.g. ../nasm
  138. --verbose Get more output
  139. If --clean is not specified, --nasm is required.
  140. testfile.asm ...:
  141. One or more files that NASM should be tested with,
  142. often *.asm in the test directory.
  143. It should contain one or more option lines at the start,
  144. in the following format:
  145. ;Testname=<testname>; Arguments=<arguments to nasm>; Files=<output files>
  146. If no such lines are found at the start, the file is skipped.
  147. testname should ideally describe the arguments, eg. unoptimized for -O0.
  148. arguments can be an optimization level (-O), an output format (-f),
  149. an output file specifier (-o) etc.
  150. The output files should be a space seperated list of files that will
  151. be checked for regressions. This should often be the output file
  152. and the special files stdout and stderr.
  153. Any mismatch could be a regression,
  154. but it doesn't have to be. COFF files have a timestamp which
  155. makes this method useless. ELF files have a comment section
  156. with the current version of NASM, so they will change each version number.
  157. =cut