aboutsummaryrefslogtreecommitdiff
path: root/runtests.pl
blob: 09f0ba147c9096ace0a6d17ac3427c06e5a95b72 (plain)
  1. #!/usr/bin/env perl
  2. use warnings;
  3. use strict;
  4. use Term::ANSIColor;
  5. use IO::Handle;
  6. use IPC::Open2;
  7. my $usage="runtests.pl SPEC PROGRAM\nSet ANSI_COLORS_DISABLED=1 if you redirect to a file.\nSet PATT='...' to restrict tests to sections matching a regex.\n";
  8. my $SPEC = shift @ARGV;
  9. my @PROG = @ARGV;
  10. my $PATT=$ENV{'PATT'};
  11. if (!(@PROG && defined $SPEC)) {
  12. print STDERR $usage;
  13. exit 1;
  14. }
  15. my $passed = 0;
  16. my $failed = 0;
  17. my $skipped = 0;
  18. my $errored = 0;
  19. # Markdown implementations vary on insignificant whitespace.
  20. # Some leave blanks between block elements, others don't.
  21. # This function tries to normalize the output so it can be
  22. # compared with our test. tidy takes two arguments: the
  23. # string containing the actual output, and a pathname of the
  24. # file to which the tidied output is to be saved.
  25. sub tidy
  26. {
  27. my $inpre = 0;
  28. my $out = "";
  29. my $outfh;
  30. open($outfh, '>', \$out);
  31. for (split /^/, $_[0]) {
  32. if (/<pre/) {
  33. $inpre = 1;
  34. } elsif (/<\/pre/) {
  35. $inpre = 0;
  36. }
  37. # remove \r to allow mixing linux/windows newlines
  38. s/\r//;
  39. if ($inpre) {
  40. print $outfh $_;
  41. } else {
  42. # remove leading spaces
  43. s/^ *//;
  44. # remove trailing spaces
  45. s/ *$//;
  46. # collapse consecutive spaces
  47. s/ */ /;
  48. # collapse space before /> in tag
  49. s/ *\/>/\/>/;
  50. s/>\n$/>/;
  51. # skip blank line
  52. if (/^$/) {
  53. next;
  54. }
  55. print $outfh $_;
  56. }
  57. }
  58. close $outfh;
  59. return $out;
  60. }
  61. # return 0 for passing test, -1 for failing, positive for error
  62. sub dotest
  63. {
  64. my $markdown = $_[0];
  65. my $html = $_[1];
  66. my $testname = $_[2];
  67. my $actual = "";
  68. # We use → to indicate tab and ␣ space in the spec
  69. $markdown =~ s/→/\t/g;s/␣/ /g;
  70. $html =~ s/→/\t/g;s/␣/ /g;
  71. my $pid = open2(my $out, my $in, @PROG);
  72. print $in $markdown;
  73. close $in;
  74. flush $out;
  75. $actual = do { local $/; <$out>; };
  76. close $out;
  77. waitpid($pid, 0);
  78. my $exit_status = $?;
  79. $html = &tidy($html);
  80. $actual = &tidy($actual);
  81. $actual =~ s/\&#39;/'/g;
  82. if ($actual eq $html) {
  83. print colored("✓", "green");
  84. return 0;
  85. } else {
  86. print colored("\n$testname", "red");
  87. print "\n";
  88. print color "cyan";
  89. print "=== markdown ===============\n";
  90. print $markdown;
  91. print "=== expected ===============\n";
  92. print $html;
  93. print "\n";
  94. print "=== got ====================\n";
  95. print $actual;
  96. print "\n";
  97. print color "black";
  98. if ($exit_status == 0) {
  99. return -1;
  100. } else {
  101. return $exit_status;
  102. }
  103. }
  104. }
  105. my $stage = 0;
  106. my $markdown = "";
  107. my $html = "";
  108. my $example = 0;
  109. my $linenum = 0;
  110. my $exampleline = 0;
  111. my @secnums = ();
  112. my $secheading;
  113. my $testresult;
  114. open(SPEC, "< $SPEC");
  115. while (<SPEC>) {
  116. $linenum++;
  117. if (/^\.$/) {
  118. $stage = ($stage + 1) % 3;
  119. if ($stage == 1) {
  120. $exampleline = $linenum;
  121. }
  122. if ($stage == 0) {
  123. $example++;
  124. if (!$PATT || $secheading =~ /$PATT/) {
  125. $testresult = &dotest($markdown, $html, "Example $example (line $exampleline)");
  126. if ($testresult == 0) {
  127. $passed++;
  128. } elsif ($testresult == -1) {
  129. $failed++;
  130. } else {
  131. $errored++;
  132. }
  133. } else {
  134. $skipped++;
  135. }
  136. $markdown = "";
  137. $html = "";
  138. }
  139. } elsif ($stage == 0 && $_ =~ /^<!-- END TESTS -->/) {
  140. last;
  141. } elsif ($stage == 0 && $_ =~ /^(#+) +(.*)/) {
  142. my $seclevel = length($1);
  143. $secheading = $2;
  144. if ($#secnums == $seclevel - 1) {
  145. $secnums[$#secnums]++;
  146. } elsif ($#secnums > $seclevel - 1) {
  147. @secnums = @secnums[0..($seclevel - 1)];
  148. $secnums[$#secnums]++;
  149. } else {
  150. while ($#secnums < $seclevel - 1) {
  151. push(@secnums, 1);
  152. }
  153. }
  154. if (!$PATT || $secheading =~ /$PATT/) {
  155. print ("\n", join(".", @secnums) . " " . $secheading, " ");
  156. }
  157. } elsif ($stage == 1) {
  158. $markdown .= $_;
  159. } elsif ($stage == 2) {
  160. $html .= $_;
  161. }
  162. }
  163. print "\n";
  164. print STDERR colored("$passed tests passed, $failed failed, $errored errored, $skipped skipped.", "bold");
  165. print STDERR "\n";
  166. exit $failed;