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>".
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>):
27 If it exists, overrides variables for the entire suite.
31 If it exists, allows overriding for the directory and for individual
32 tests within the directory
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.
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.
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.
61 Returns the global variable C<@OKS>.
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
73 The unpacked python expects all have this form.
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.
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
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
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>,
100 then C<rediff> is used for fault grading, and the fault grading file
101 is C<$1.xyz.re>. Otherwise, C<diff> is used for fault grading and
102 the fault grading file is C<$1.xyz.df>. If a C<diff> fault grading
103 fails, then the <$1.ok> target repeats the fault grading using
108 Copies C<$1.stderr>, if it exists, and the first of C<$1.my$2> or
109 C<$1.$2> to the target, where C<$2> is the writer. Thus, any error
110 messages printed to STDERR become part of the fault grading.
114 If there was already a C<$1.$2.re> file, this rule does nothing.
115 Otherwise, it was invoked because the straight C<diff> failed. It passes
116 C<$1.stderr>, if it exists, and the first of C<$1.my$2> or C<$1.$2> as
117 arguments to the script C<re$2> (e.g., C<redom>), located in the
118 C<tbin> directory. The purpose of such a script is to elide with
119 regular expressions that part of the output that can validly differ.
123 Dependencies are C<$1.rst> (if it exists), the C<prest> script, and
124 the file containing the implemention of the writer C<$2>. Invokes
126 perl $PERL_FILE_FLAGS{$1} $PERL_DIR_FLAGS $PERL_SUITE_FLAGS \
127 $PERL_WRT_FLAGS{$2} $PERL_FLAGS -I <root>/blib/lib \
128 <root>/blib/script/prest -w $2 \
129 $PREST_FLAGS $PREST_WRT_FLAGS{$2} $PREST_SUITE_FLAGS \
130 $PREST_DIR_FLAGS $PREST_FILE_FLAGS{$1} [$1.rst] \
131 $POSTPROC_FILE{$1} > $target
133 If C<$3> is null, then any output to STDERR is captured in the output
134 file; otherwise the output file contains only the prest output to STDOUT.
135 If there is no C<$1.rst> file, then C<$PREST_FILE_FLAGS{$1}> should
136 contain the list of input files.
140 =head1 GLOBAL VARIABLES
142 As can be seen above, there are a number of global variables that
143 affect the processing of the prest command:
147 =item C<$PERL_DIR_FLAGS> (Dir.smak)
149 Flags for perl invocation of prest for a directory.
151 =item C<$PERL_SUITE_FLAGS> (Suite.smak)
153 Flags for perl invocation of prest for a suite.
155 =item C<%PERL_WRT_FLAGS> (Suite.smak or Perl.smak)
157 Flags for perl invocation of prest for specific writers (indexed by
160 =item C<%PERL_FILE_FLAGS> (Dir.smak)
162 Flags for perl invocation of prest for specific files (indexed by base
165 =item C<$PREST_DIR_FLAGS> (Dir.smak)
167 Writer- and file-independent flags for prest for a directory.
169 =item C<$PREST_FLAGS> (Suite.smak or Dir.smak)
171 Writer- and file-independent flags for prest. Defaults to
173 -D source='test data' -D xformoff='.*' -D align=0
177 =item C<$PREST_SUITE_FLAGS> (Suite.smak)
179 Writer- and file-independent flags for prest for a suite.
181 =item C<%PREST_WRT_FLAGS> (Suite.smak or Dir.smak)
183 Flags for specific writers (indexed by writer). C<$PREST_WRT_FLAGS{dom}>
184 defaults to "-W nobackn" unless already set.
186 =item C<%PREST_FILE_FLAGS> (Dir.smak)
188 Flags for specific files (indexed by base filename).
190 =item C<%POSTPROC_FILE> (Dir.smak)
192 Text for postprocessing output before check for specific files
193 (indexed by base filename). Usually starts with "|".
197 =head1 ENVIRONMENT VARIABLES
203 If set, runs perl with flags to create a coverage database using
208 If set, runs perl with the C<-d> flag (debug mode).
212 If set, echoes to STDERR the commands to be executed, but does not
213 actually execute them.
217 If set, echoes to STDERR the commands as they execute.
228 use vars qw(@OKS @PRETESTS);
229 # Flags that can be set in Suite.smak and Dir.smak:
230 # $EXTRACT_TEST_FLAGS Flags for extract_tests script
231 # $PERL_DIR_FLAGS Flags for perl invocation of prest for a directory
232 # $PERL_SUITE_FLAGS Flags for perl invocation of prest for a suite
233 # %PERL_WRT_FLAGS Flags for perl invocation of prest for specific
234 # writers (indexed by writer)
235 # %PERL_FILE_FLAGS Flags for perl infocation of prest for specific
236 # files (indexed by base filename)
237 # $PREST_DIR_FLAGS Generic flags for prest for a directory
238 # $PREST_FLAGS Generic flags for prest
239 # $PREST_SUITE_FLAGS Generic flags for prest for a suite
240 # %PREST_WRT_FLAGS Flags for specific writers (indexed by writer)
241 # %PREST_FILE_FLAGS Flags for specific files (indexed by base filename)
242 # %POSTPROC_FILE Text for postprocessing output before check for
243 # specific files (indexed by base filename). Usually
246 use vars qw(%EXT_TO_WRT $EXTRACT_TEST_FLAGS $PREST_FLAGS
247 $PERL_DIR_FLAGS $PERL_SUITE_FLAGS %PERL_WRT_FLAGS
250 $PREST_DIR_FLAGS $PREST_SUITE_FLAGS %PREST_WRT_FLAGS
253 %EXT_TO_WRT = (tex => 'latex', idx => 'index');
254 $EXTRACT_TEST_FLAGS = '';
255 @PRETESTS = qw(unpack find_oks);
256 # Executes a command line while possibly echoing it to the screen
259 print STDERR "\t$cmd\n" if $ENV{TRACE} || $ENV{PRINT};
260 system $cmd unless $ENV{PRINT};
265 # Include the suite's SlayMakefile if it exists
266 -include ../Suite.smak
268 # Include the directory's SlayMakefile if it exists
273 pretest: { @PRETESTS }
276 # Set up our make variables
278 use vars qw($EXTRACT_TESTS $LIB $PERL $PERL_FLAGS $SCRIPT $TBIN $TOP
281 # Find our top directory
282 chomp ($TOP = `pwd`);
285 $SCRIPT = "$TOP/blib/script";
286 $LIB = "$TOP/blib/lib";
287 $EXTRACT_TESTS = "$TBIN/extract_tests";
289 # Get list of writers
290 my ($dir, @writers, %writer_seen);
291 foreach $dir (@INC) {
292 push @writers, glob("$dir/Text/Restructured/Writer/*.wrt")
294 @WRITERS = grep(! $writer_seen{$_}++,
295 grep(s|.*/([^/]+)\.wrt$|$1|, @writers));
296 eval "use lib \$LIB; use Text::Restructured::PrestConfig;";
299 push @flags, '-T' if $Text::Restructured::PrestConfig::TAINT =~ /^y/i;
300 push @flags, '-d' if $ENV{DEBUG};
301 push @flags, '-MDevel::Cover=-db,../../cover_db,-silent,1,-summary,0'
303 push @flags, q(-M-warnings) if $ENV{COVER};
304 $PERL_FLAGS = "@flags";
305 # Default version of PREST_FLAGS
306 $PREST_FLAGS = q(-D source='test data' -D xformoff='.*' -D align=0)
307 unless defined $PREST_FLAGS;
308 $PREST_FLAGS .= q( -D no_line_directives) if $ENV{DEBUG};
309 # Default version of PREST_WRT_FLAGS for dom
310 $PREST_WRT_FLAGS{dom} = '-W nobackn' unless defined $PREST_WRT_FLAGS{dom};
313 # Unpack the .py file if it exists
316 my @test_pys = <test_*.py>;
317 foreach (@test_pys) {
318 execute "$PERL $EXTRACT_TESTS $EXTRACT_TEST_FLAGS $_";
325 s/\.rst$/.ok/ foreach @OKS;
328 # Fault grading. This is complicated because we can do either diff or
329 # rediff for checking and we can build the targets in a number of ways,
330 # depending upon which writer needs to be used, which depends upon
331 # what kinds of expects we have
333 my($maker, $target, $matches) = @_;
334 my $m = $matches->[0];
335 # Search for .xyz or .myxyz or .xyzre files for each of
336 # the different writers xyz
337 my @writers = grep(-f "$m.$_" || -f "$m.my$_" ||
339 (@WRITERS, qw(tex idx txt)));
340 my $writer = $writers[0];
341 die "Cannot find expect file for $m" unless defined $writer;
342 my $ext = -f "$m.r" || -f "$m.$writer.re" ? 're' : 'df';
343 ("$m.$writer.$ext", "$m.$writer.out");
347 my($maker, $target, $deps, $matches) = @_;
348 my $is_diff = $deps->[0] =~ /\.df/;
349 my $diffre = "$PERL $TBIN/diffre";
350 my $prog = $is_diff ? 'diff' : $diffre;
351 execute "$prog @$deps[0..1] > $target";
352 if (! -z $target && $is_diff) {
353 $deps->[0] =~ s/\.df$/.re/;
354 $maker->make($deps->[0]);
355 execute "$diffre @$deps[0..1] > $target";
359 # Make a straight diff file
361 my($maker, $target, $matches) = @_;
362 my @exp = grep(-f $_, "$matches->[0].my$matches->[1]",
363 "$matches->[0].$matches->[1]");
365 push @files, "$matches->[0].stderr" if -f "$matches->[0].stderr";
366 push @files, $exp[0];
370 cat $DEP0 $DEP1 > $TARGET
372 # Make a regular expression diff file
374 my($maker, $target, $matches) = @_;
375 my @exp = grep(-f $_, "$matches->[0].my$matches->[1]",
376 "$matches->[0].$matches->[1]");
378 push @files, "$matches->[0].stderr" if -f "$matches->[0].stderr";
379 push @files, $exp[0] if $exp[0];
384 my($maker, $target, $deps, $matches) = @_;
385 my $dep = $deps->[-1];
386 $dep =~ /\. (my)? ([^\.]+?) \z/x;
388 execute "$PERL $TBIN/re$re @$deps > $target";
391 # Run prest with the appropriate writer
392 # Anything after the ".out" causes the output to be generated without STDERR.
394 # Add the prest script and the appropriate writer as dependencies
395 my($maker, $target, $matches) = @_;
396 my $writer = $EXT_TO_WRT{$matches->[1]} || $matches->[1];
398 # Make the .rst file a dependency if it exists (it usually does)
399 push @deps, "$matches->[0].rst" if -f "$matches->[0].rst";
400 # Add the prest script and perl modules to the dependencies
401 push @deps, ("$SCRIPT/prest",
402 "$LIB/Text/Restructured/Writer/$writer.wrt");
403 push @deps, (<$LIB/Text/*.pm>, <$LIB/Text/Restructured/*.pm>,
404 <$LIB/Text/Restructured/Directive/*.pm>);
409 my($maker, $target, $deps, $matches) = @_;
410 my $m0 = $matches->[0];
411 my $writer = $EXT_TO_WRT{$matches->[1]} || $matches->[1];
412 # Note: since these are usually -I flags, the local ones come first
414 grep(defined $_, $PERL_FILE_FLAGS{$m0},
415 $PERL_DIR_FLAGS, $PERL_SUITE_FLAGS,
416 $PERL_WRT_FLAGS{$writer}, $PERL_FLAGS, );
417 my $prest_cmd = "$PERL @perl_flags -I $LIB $SCRIPT/prest";
419 grep(defined $_, $PREST_FLAGS, $PREST_WRT_FLAGS{$writer},
420 $PREST_SUITE_FLAGS, $PREST_DIR_FLAGS,
421 $PREST_FILE_FLAGS{$m0});
422 push @flags, "$m0.rst" if -f "$m0.rst";
423 my $redir = $matches->[2] ? '' : '2>&1' ;
424 my $postproc = $POSTPROC_FILE{$m0} || '';
425 my $redirect = $ENV{DEBUG} ? '' : "> $target";
426 execute "$prest_cmd -w $writer @flags $redir $postproc |
427 grep -v 'Wide character'$redirect";