docstring fix
[docutils.git] / prest / t / Common.smak
blobbc8fba1f2494d57597e4e34fdcda8101b6749dc0
1 # -*- makefile -*-
2 # A common SlayMakefile for executing tests
3 # It is intended to be called from two levels lower in the directory
4 # hierarchy using "slaymake -f ../../Common.smak <target>".
8 =head1 NAME
10 Common.smak
12 =head1 DESCRIPTION
14 Used as the common C<Slay::Makefile> input for all the
15 C<Text::Restructured> tests.  It contains all the infrastructure needed
16 for executing the python tests from docutils, while still providing
17 tailorability for tests that do not fit the framework.  The tests are
18 divided into suites (e.g., C<10_parse>), each of which can have more
19 than one C<.t> file in it with its associated C<.init> directory to
20 implement multiple related tests.  The customizability comes the
21 following files (relative to the C<.dir> directory created by C<gress.pm>):
23 =over
25 =item ../Suite.smak
27 If it exists, overrides variables for the entire suite.
29 =item Dir.smak
31 If it exists, allows overriding for the directory and for individual
32 tests within the directory
34 =back
36 =head1 TARGETS
38 =over
40 =item pretest
42 Returns the dependencies in global variable C<@PRETESTS>, which is
43 initialized to the targets C<unpack> and C<find_oks>, but can be added
44 to by the custom C<Slay::Makefile> files above.
46 =item unpack
48 Checks for a python test file and, if it exists, calls the
49 C<extract_tests> script from the C<tbin> directory on it to create a
50 series of C<.rst> and C<.dom> files for testing.
52 =item find_oks
54 Sets the global variable C<@OKS> to contain the list of C<.rst> files
55 in the directory with the C<.rst> extension replaced by C<.ok>.
56 Override this target if there is a different way to determine the list
57 of targets corresponding to tests.
59 =item test
61 Returns the global variable C<@OKS>.
63 =item %.ok
65 Looks for an expect file for the C<$1> part (the part matching the
66 first C<%>) in order to determine which writer to use when calling
67 C<prest>.  For writer C<xyz>, the expect file should be one of
69 =over
71 =item C<$1.xyz>
73 The unpacked python expects all have this form.
75 =item C<$1.myxyz>
77 Sometimes prest intentionally does not match the python output, so
78 C<$1.myxyz> is used in preference to C<$1.xyz> if both exist.
80 =item C<$1.xyz.re>
82 Sometimes a regular expression difference, using the C<rediff> script
83 in the C<tbin> directory, needs to be done for fault grading.  This
84 file contains regular expressions and is used in preference to either
85 of the previous two.
87 =back
89 Note: There are two exceptions to the one-to-one mapping between
90 C<xyz> and the writer namely, namely C<tex> runs the C<latex> writer
91 and C<idx> runs the C<index> writer.
93 This target returns an error if no expect file for a known writer is
94 found.
96 After determining which writer is appropriate, this target returns two
97 dependencies, one of which will be the output of the writer
98 (C<$1.xyz.out>), and the other of which is the file against which
99 fault grading occurs.  If the expect file has extension C<.xyz.re> or
100 if there exists a file C<$1.r>, then C<rediff> is used for fault
101 grading, and the fault grading file is C<$1.xyz.re>.  Otherwise,
102 C<diff> is used for fault grading and the fault grading file is
103 C<$1.xyz.df>.
105 =item %.%.df
107 Copies C<$1.stderr>, if it exists, and the first of C<$1.my$2> or
108 C<$1.$2> to the target, where C<$2> is the writer.  Thus, any error
109 messages printed to STDERR become part of the fault grading.
111 =item %.%.re
113 If there was already a C<$1.$2.re> file, this rule does nothing.
114 Otherwise, it was invoked because there was a C<$1.r> file.  It passes
115 C<$1.stderr>, if it exists, and the first of C<$1.my$2> or C<$1.$2> as
116 arguments to the script C<re$2> (e.g., C<redom>), located in the
117 C<tbin> directory.  The purpose of such a script is to elide with
118 regular expressions that part of the output that can validly differ.
120 =item %.%.out%
122 Dependencies are C<$1.rst> (if it exists), the C<prest> script, and
123 the file containing the implemention of the writer C<$2>.  Invokes
125   perl $PERL_FILE_FLAGS{$1} $PERL_DIR_FLAGS $PERL_SUITE_FLAGS \
126        $PERL_WRT_FLAGS{$2} $PERL_FLAGS -I <root>/blib/lib \
127        <root>/blib/script/prest -w $2 \
128        $PREST_FLAGS $PREST_WRT_FLAGS{$2} $PREST_SUITE_FLAGS \
129        $PREST_DIR_FLAGS $PREST_FILE_FLAGS{$1} [$1.rst] \
130        $POSTPROC_FILE{$1} > $target
132 If C<$3> is null, then any output to STDERR is captured in the output
133 file; otherwise the output file contains only the prest output to STDOUT.
134 If there is no C<$1.rst> file, then C<$PREST_FILE_FLAGS{$1}> should
135 contain the list of input files.
137 =back
139 =head1 GLOBAL VARIABLES
141 As can be seen above, there are a number of global variables that
142 affect the processing of the prest command:
144 =over
146 =item C<$PERL_DIR_FLAGS> (Dir.smak)
148 Flags for perl invocation of prest for a directory.
150 =item C<$PERL_SUITE_FLAGS> (Suite.smak)
152 Flags for perl invocation of prest for a suite.
154 =item C<%PERL_WRT_FLAGS> (Suite.smak or Perl.smak)
156 Flags for perl invocation of prest for specific writers (indexed by
157 writer).
159 =item C<%PERL_FILE_FLAGS> (Dir.smak)
161 Flags for perl invocation of prest for specific files (indexed by base
162 filename).
164 =item C<$PREST_DIR_FLAGS> (Dir.smak)
166 Writer- and file-independent flags for prest for a directory.
168 =item C<$PREST_FLAGS> (Suite.smak or Dir.smak)
170 Writer- and file-independent flags for prest.  Defaults to 
172   -D source='test data' -D xformoff='.*' -D align=0
174 unless already set.
176 =item C<$PREST_SUITE_FLAGS> (Suite.smak)
178 Writer- and file-independent flags for prest for a suite.
180 =item C<%PREST_WRT_FLAGS> (Suite.smak or Dir.smak)
182 Flags for specific writers (indexed by writer).  C<$PREST_WRT_FLAGS{dom}>
183 defaults to "-W nobackn" unless already set.
185 =item C<%PREST_FILE_FLAGS> (Dir.smak)
187 Flags for specific files (indexed by base filename).
189 =item C<%POSTPROC_FILE> (Dir.smak)
191 Text for postprocessing output before check for specific files
192 (indexed by base filename).  Usually starts with "|".
194 =back
196 =head1 ENVIRONMENT VARIABLES
198 =over
200 =item C<COVER>
202 If set, runs perl with flags to create a coverage database using
203 C<Devel::Cover>.
205 =item C<DEBUG>
207 If set, runs perl with the C<-d> flag (debug mode).
209 =item C<PRINT>
211 If set, echoes to STDERR the commands to be executed, but does not
212 actually execute them.
214 =item C<TRACE>
216 If set, echoes to STDERR the commands as they execute.
218 =back
220 =cut
223 default: test
226     use strict;
227     use vars qw(@OKS @PRETESTS);
228     # Flags that can be set in Suite.smak and Dir.smak:
229     #   $EXTRACT_TEST_FLAGS Flags for extract_tests script
230     #   $PERL_DIR_FLAGS     Flags for perl invocation of prest for a directory
231     #   $PERL_SUITE_FLAGS   Flags for perl invocation of prest for a suite
232     #   %PERL_WRT_FLAGS     Flags for perl invocation of prest for specific
233     #                       writers (indexed by writer)
234     #   %PERL_FILE_FLAGS    Flags for perl infocation of prest for specific
235     #                       files (indexed by base filename)
236     #   $PREST_DIR_FLAGS    Generic flags for prest for a directory
237     #   $PREST_FLAGS        Generic flags for prest
238     #   $PREST_SUITE_FLAGS  Generic flags for prest for a suite
239     #   %PREST_WRT_FLAGS    Flags for specific writers (indexed by writer)
240     #   %PREST_FILE_FLAGS   Flags for specific files (indexed by base filename)
241     #   %POSTPROC_FILE      Text for postprocessing output before check for
242     #                       specific files (indexed by base filename).  Usually
243     #                       starts with "|".
244     
245     use vars qw(%EXT_TO_WRT $EXTRACT_TEST_FLAGS $PREST_FLAGS
246                 $PERL_DIR_FLAGS $PERL_SUITE_FLAGS %PERL_WRT_FLAGS
247                 %PERL_FILE_FLAGS
248                 %POSTPROC_FILE
249                 $PREST_DIR_FLAGS $PREST_SUITE_FLAGS %PREST_WRT_FLAGS
250                 %PREST_FILE_FLAGS);
252     %EXT_TO_WRT = (tex => 'latex', idx => 'index');
253     $EXTRACT_TEST_FLAGS = '';
254     @PRETESTS = qw(unpack find_oks);
255     # Executes a command line while possibly echoing it to the screen
256     sub execute ( $ ) {
257         my ($cmd) = @_;
258         print STDERR "\t$cmd\n" if $ENV{TRACE} || $ENV{PRINT};
259         system $cmd unless $ENV{PRINT};
260         return;
261     }
264 # Include the suite's SlayMakefile if it exists
265 -include ../Suite.smak
267 # Include the directory's SlayMakefile if it exists
268 -include Dir.smak
270 test: { @OKS }
272 pretest: { @PRETESTS } 
275     # Set up our make variables
276     use strict;
277     use vars qw($EXTRACT_TESTS $LIB $PERL $PERL_FLAGS $SCRIPT $TBIN $TOP
278                 @WRITERS);
280     # Find our top directory
281     chomp ($TOP = `pwd`);
282     $TOP =~ s!/t/.*$!!;
283     $TBIN   = "$TOP/tbin";
284     $SCRIPT = "$TOP/blib/script";
285     $LIB    = "$TOP/blib/lib";
286     $EXTRACT_TESTS = "$TBIN/extract_tests";
287     $PERL   = $^X;
288     # Get list of writers
289     my ($dir, @writers, %writer_seen);
290     foreach $dir (@INC) {
291         push @writers, glob("$dir/Text/Restructured/Writer/*.wrt")
292     }
293     @WRITERS = grep(! $writer_seen{$_}++,
294                     grep(s|.*/([^/]+)\.wrt$|$1|, @writers));
295     eval "use lib \$LIB; use Text::Restructured::PrestConfig;";
296     my @flags;
297     push @flags, '-T' if $Text::Restructured::PrestConfig::TAINT =~ /^y/i;
298     push @flags, '-d' if $ENV{DEBUG};
299     push @flags, '-MDevel::Cover=-db,../../cover_db,-silent,1,-summary,0'
300         if $ENV{COVER};
301     push @flags, q(-M-warnings) if $ENV{COVER};
302     $PERL_FLAGS = "@flags";
303     # Default version of PREST_FLAGS
304     $PREST_FLAGS = q(-D source='test data' -D xformoff='.*' -D align=0)
305         unless defined $PREST_FLAGS;
306     $PREST_FLAGS .= q( -D no_line_directives) if $ENV{DEBUG};
307     # Default version of PREST_WRT_FLAGS for dom
308     $PREST_WRT_FLAGS{dom} = '-W nobackn' unless defined $PREST_WRT_FLAGS{dom};
311 # Unpack the .py file if it exists
312 unpack:
313         { 
314             my @test_pys = <test_*.py>;
315             foreach (@test_pys) {
316                 execute "$PERL $EXTRACT_TESTS $EXTRACT_TEST_FLAGS $_";
317             }
318         }
320 find_oks:
321         {
322             @OKS = <*.rst>;
323             s/\.rst$/.ok/ foreach @OKS;
324         }
326 # Fault grading.  This is complicated because we can do either diff or
327 # rediff for checking and we can build the targets in a number of ways,
328 # depending upon which writer needs to be used, which depends upon
329 # what kinds of expects we have
330 %.ok:   {
331             my($maker, $target, $matches) = @_;
332             my $m = $matches->[0];
333             # Search for .xyz or .myxyz or .xyzre files for each of
334             # the different writers xyz
335             my @writers = grep(-f "$m.$_" || -f "$m.my$_" ||
336                                -f "$m.$_.re",
337                                (@WRITERS, qw(tex idx txt)));
338             my $writer = $writers[0];
339             die "Cannot find expect file for $m" unless defined $writer;
340             my $ext = -f "$m.r" || -f "$m.$writer.re" ? 're' : 'df';
341             ("$m.$writer.$ext", "$m.$writer.out");
342         }
343         # ---- ACTIONS ----
344         {
345             my($maker, $target, $deps, $matches) = @_;
346             my $prog = $deps->[0] =~ /\.df/ ? 'diff' : "$PERL $TBIN/diffre";
347             execute "$prog @$deps[0..1] > $target";
348         }
350 # Make a straight diff file
351 %.%.df: { 
352             my($maker, $target, $matches) = @_;
353             my @exp = grep(-f $_, "$matches->[0].my$matches->[1]",
354                            "$matches->[0].$matches->[1]");
355             my @files;
356             push @files, "$matches->[0].stderr" if -f "$matches->[0].stderr";
357             push @files, $exp[0];
358             @files;
359         }
360         # ---- ACTIONS ----
361         cat $DEP0 $DEP1 > $TARGET
363 # Make a regular expression diff file
364 %.%.re: { 
365             my($maker, $target, $matches) = @_;
366             my @exp = grep(-f $_, "$matches->[0].my$matches->[1]",
367                            "$matches->[0].$matches->[1]");
368             my @files;
369             push @files, "$matches->[0].stderr" if -f "$matches->[0].stderr";
370             push @files, $exp[0] if $exp[0];
371             @files;
372         }
373         # ---- ACTIONS ----
374         {
375             my($maker, $target, $deps, $matches) = @_;
376             my $dep = $deps->[-1];
377             $dep =~ /\. (my)? ([^\.]+?) \z/x;
378             my $re = $2;
379             execute "$PERL $TBIN/re$re @$deps > $target";
380         }
382 # Run prest with the appropriate writer
383 # Anything after the ".out" causes the output to be generated without STDERR.
384 %.%.out%: {
385             # Add the prest script and the appropriate writer as dependencies
386             my($maker, $target, $matches) = @_;
387             my $writer = $EXT_TO_WRT{$matches->[1]} || $matches->[1];
388             my @deps;
389             # Make the .rst file a dependency if it exists (it usually does)
390             push @deps, "$matches->[0].rst" if -f "$matches->[0].rst";
391             # Add the prest script and perl modules to the dependencies
392             push @deps, ("$SCRIPT/prest",
393                          "$LIB/Text/Restructured/Writer/$writer.wrt");
394             push @deps, (<$LIB/Text/*.pm>, <$LIB/Text/Restructured/*.pm>,
395                          <$LIB/Text/Restructured/Directive/*.pm>);
396             @deps
397         }
398         # ---- ACTIONS ----
399         {
400             my($maker, $target, $deps, $matches) = @_;
401             my $m0 = $matches->[0];
402             my $writer = $EXT_TO_WRT{$matches->[1]} || $matches->[1];
403             # Note: since these are usually -I flags, the local ones come first
404             my @perl_flags =
405                 grep(defined $_, $PERL_FILE_FLAGS{$m0},
406                      $PERL_DIR_FLAGS, $PERL_SUITE_FLAGS,
407                      $PERL_WRT_FLAGS{$writer}, $PERL_FLAGS, );
408             my $prest_cmd = "$PERL @perl_flags -I $LIB $SCRIPT/prest";
409             my @flags =
410                 grep(defined $_, $PREST_FLAGS, $PREST_WRT_FLAGS{$writer},
411                      $PREST_SUITE_FLAGS, $PREST_DIR_FLAGS, 
412                      $PREST_FILE_FLAGS{$m0});
413             push @flags, "$m0.rst" if -f "$m0.rst";
414             my $redir    = $matches->[2] ? '' : '2>&1' ;
415             my $postproc = $POSTPROC_FILE{$m0} || '';
416             my $redirect = $ENV{DEBUG} ? '' : "> $target";
417             execute "$prest_cmd -w $writer @flags $redir $postproc |
418                      grep -v 'Wide character'$redirect";
419         }