summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/source/latex/qstest
diff options
context:
space:
mode:
authorKarl Berry <karl@freefriends.org>2007-02-26 01:15:02 +0000
committerKarl Berry <karl@freefriends.org>2007-02-26 01:15:02 +0000
commitaf0a12985674bb2c95947a4c9c439887b679f168 (patch)
treea19c338e27b62cbb17969095279a5885596e41f1 /Master/texmf-dist/source/latex/qstest
parent4a0068129d6635fb71e1d030ac322a3ab55c45e1 (diff)
new latex package qstest (22feb07)
git-svn-id: svn://tug.org/texlive/trunk@3990 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist/source/latex/qstest')
-rw-r--r--Master/texmf-dist/source/latex/qstest/Makefile76
-rw-r--r--Master/texmf-dist/source/latex/qstest/makematch.drv44
-rw-r--r--Master/texmf-dist/source/latex/qstest/makematch.dtx598
-rw-r--r--Master/texmf-dist/source/latex/qstest/qstest.drv170
-rw-r--r--Master/texmf-dist/source/latex/qstest/qstest.dtx1674
-rw-r--r--Master/texmf-dist/source/latex/qstest/qstest.ins41
6 files changed, 2603 insertions, 0 deletions
diff --git a/Master/texmf-dist/source/latex/qstest/Makefile b/Master/texmf-dist/source/latex/qstest/Makefile
new file mode 100644
index 00000000000..7c7fb14853e
--- /dev/null
+++ b/Master/texmf-dist/source/latex/qstest/Makefile
@@ -0,0 +1,76 @@
+# Copyright (C) 2006, 2007 QuinScape GmbH
+# http://www.quinscape.de
+# This file comes without warranty of any kind.
+# It may be freely used, copied, modified and distributed.
+#
+# The following assumes the current directory to be
+# $TEXMF/source/tex/latex/contrib/qstest and is only used for the
+# `install' target.
+STYLEDIR=../../../../../tex/latex/qstest
+DOCDIR=../../../../../doc/latex/qstest
+
+all: makematch.dvi makematch.pdf makematch.sty qstest.ins qstest.dvi qstest.pdf qstest.sty test
+
+.PHONY: all test clean distclean tarball install
+
+.DELETE_ON_ERROR:
+
+test: qstest-qs.log makematch-qs.log
+
+qstest-qs.lgout qstest-qs.log: qstest-qs.tex makematch.sty qstest.sty
+ latex qstest-qs.tex
+
+makematch-qs.log: makematch-qs.tex makematch.sty qstest.sty
+ latex makematch-qs.tex
+
+qstest.drv qstest-qs.tex qstest.sty: qstest.dtx qstest.ins
+ tex "\let\Make=y \input qstest.ins"
+
+makematch.drv makematch-qs.tex makematch.sty: makematch.dtx qstest.ins
+ tex "\let\Make=y \input qstest.ins"
+
+qstest.ins: qstest.dtx
+ tex "\def\jobname{qstest.ins}\input docstrip \askforoverwritefalse\generate{\file{qstest.ins}{\from{qstest.dtx}{installer}}}\endbatchfile"
+
+qstest.dvi: qstest.drv qstest.sty qstest.dtx qstest-qs.lgout
+ latex qstest.drv
+ latex qstest.drv
+ latex qstest.drv
+
+qstest.pdf: qstest.drv qstest.sty qstest.dtx qstest-qs.lgout
+ rm -f qstest.out
+ pdflatex qstest.dtx
+ pdflatex qstest.dtx
+ pdflatex qstest.dtx
+
+makematch.dvi: makematch.drv makematch.sty makematch.dtx
+ latex makematch.drv
+ latex makematch.drv
+ latex makematch.drv
+
+makematch.pdf: makematch.sty makematch.dtx
+ rm -f makematch.out
+ pdflatex makematch.dtx
+ pdflatex makematch.dtx
+ pdflatex makematch.dtx
+
+install: qstest.sty makematch.sty qstest.dvi makematch.dvi
+ [ -d $(STYLEDIR) ] || mkdir $(STYLEDIR)
+ [ -d $(DOCDIR) ] || mkdir $(DOCDIR)
+ install qstest.sty makematch.sty $(STYLEDIR)
+ install qstest.dvi makematch.dvi $(DOCDIR)
+
+clean:
+ rm -f *.dvi *.pdf *.aux *.toc *.glo *.idx *.gls *.ind *.log *.lgout *.qsout *.out qstest-qs.* makematch-qs.*
+
+distclean: clean
+ rm -f qstest.sty qstest.ins qstest.drv makematch.sty makematch.drv
+
+tarball: qstest.tar.gz
+
+qstest.tar.gz: test README Makefile qstest.ins qstest.dtx qstest.pdf makematch.dtx makematch.pdf
+ rm -rf qstest
+ mkdir qstest
+ ln README Makefile qstest.ins qstest.dtx qstest.pdf makematch.dtx makematch.pdf qstest
+ tar cf - qstest | gzip -9 > qstest.tar.gz
+ rm -rf qstest
diff --git a/Master/texmf-dist/source/latex/qstest/makematch.drv b/Master/texmf-dist/source/latex/qstest/makematch.drv
new file mode 100644
index 00000000000..e2b289984b8
--- /dev/null
+++ b/Master/texmf-dist/source/latex/qstest/makematch.drv
@@ -0,0 +1,44 @@
+%%
+%% This is file `makematch.drv',
+%% generated with the docstrip utility.
+%%
+%% The original source files were:
+%%
+%% makematch.dtx (with options: `driver,etex')
+%%
+%% IMPORTANT NOTICE:
+%%
+%% For the copyright see the source file.
+%%
+%% Any modified versions of this file must be renamed
+%% with new filenames distinct from makematch.drv.
+%%
+%% For distribution of the original source see the terms
+%% for copying and modification in the file makematch.dtx.
+%%
+%% This generated file may be distributed as long as the
+%% original source files, as listed above, are part of the
+%% same distribution. (The sources need not necessarily be
+%% in the same archive or directory.)
+%%
+%% Copyright (C) 2006, 2007 QuinScape GmbH
+%% http://www.quinscape.de
+\documentclass{ltxdoc}
+\usepackage{makematch}
+\usepackage{ifpdf}
+\usepackage{hyperref}
+\OnlyDescription
+ \AlsoImplementation
+\begin{document}
+\GetFileInfo{makematch.sty}
+\date{\filedate}
+\title{\texttt{\filename}\\\fileinfo\\version \fileversion}
+\author{David Kastrup\thanks{\href{mailto:dak@gnu.org}%
+ {David.Kastrup@QuinScape.de}, \href{http://quinscape.de}{QuinScape
+ GmbH}}}
+\maketitle
+\DocInput{makematch.dtx}
+\end{document}
+\endinput
+%%
+%% End of file `makematch.drv'.
diff --git a/Master/texmf-dist/source/latex/qstest/makematch.dtx b/Master/texmf-dist/source/latex/qstest/makematch.dtx
new file mode 100644
index 00000000000..b66ec1a70d9
--- /dev/null
+++ b/Master/texmf-dist/source/latex/qstest/makematch.dtx
@@ -0,0 +1,598 @@
+% \iffalse
+%%
+%% Copyright (C) 2006, 2007 QuinScape GmbH
+%% http://www.quinscape.de
+%
+% This file may be distributed and/or modified under the
+% conditions of the LaTeX Project Public License, either version 1.3
+% of this license or (at your option) any later version.
+% The latest version of this license is in
+% http://www.latex-project.org/lppl.txt
+% \fi
+% \CheckSum{354}
+% \section{Using \texttt{makematch}}
+%
+% The basic idea of \texttt{makematch} is to compile patterns and
+% targets (and/or lists of them) and match the former to the latter.
+% This functionality is used extensively in QuinScape's
+% \href{file:qstest}{\texttt{qstest}} package for unit testing. We'll
+% use that package for documenting usage of \texttt{makematch}; the
+% following construct is skips the tests when \texttt{makematch.dtx} is
+% used as a standalone file.
+% \begin{macrocode}
+%<*dtx>
+\iffalse
+%</dtx>
+%<*test>
+\RequirePackage{makematch,qstest}
+\IncludeTests{*}
+% \end{macrocode}
+%
+% \texttt{makematch} requires an e\TeX-based \LaTeX\ which should be
+% standard for current \TeX\ distributions.
+%
+% \hypertarget{patterns}{%
+% \subsection{Match patterns and targets}
+% } This
+% package has the notion of match patterns and targets. Patterns and
+% targets get sanitized at the time they are specified; this means
+% that nothing gets expanded, but replaced by a textual representation
+% consisting of spaces (with catcode~10) and other characters
+% (catcode~12). Control words are usually followed by a single space
+% when getting sanitized.
+%
+% Patterns and targets are actually generalized to pattern and target
+% lists by this package: you can, when specifying either, instead give
+% a list by using an optional argument for specifying a list separator
+% (the lists used in \texttt{qstest} are comma-separated).
+%
+% Target lists are unordered: the order of targets in them is
+% irrelevant. Leading spaces in front of each target get stripped,
+% all others are retained.
+%
+% Pattern lists similarly consist of a list of patterns, with leading
+% spaces stripped from each pattern. In contrast to target lists, the
+% order of pattern lists is significant, with later patterns
+% overriding earlier ones. Also in contrast to target lists, empty
+% patterns are removed.
+%
+% There are two special characters inside of a pattern: the first is
+% the wildcard |*| which matches any number of consecutive characters
+% (including the empty string) in a target. Wildcards can occur
+% anywhere and more than once in a pattern.
+%
+% The second special character in a pattern is only recognized at the
+% beginning of a pattern, and only if that pattern is part of a
+% pattern list (namely, when a list separator is
+% specified).\footnote{And if |!| is not the list separator of the
+% list.} If a pattern is preceded by |!| then the following
+% pattern, if it matches, causes any previous match from the pattern
+% list to be disregarded.
+%
+% So for example, the pattern list |{*,!foo}| matches any target list
+% that does not contain the match target |foo|.
+%
+% An empty target list |{}| is considered to contain the empty string.
+% Thus the pattern |*| matches every target list, including empty
+% ones, while the pattern list |{}| does not match any keyword list,
+% including empty ones.
+%
+% \subsection{The Interface}
+%
+% \DescribeMacro{\MakeMatcher} takes two mandatory arguments. The
+% first is a macro name. This macro will become the new matcher. The
+% second argument of \cmd{\MakeMatcher} is the pattern to match. An
+% optional argument before the mandatory ones can be used for
+% specifying a list separator in which case the first mandatory
+% argument becomes a pattern list (only in this case are leading |!|
+% characters before list elements interpreted specially).
+% \begin{macrocode}
+\begin{qstest}{\MakeMatcher}{\MakeMatcher}
+ \MakeMatcher\stylefiles{*.sty}
+ \MakeMatcher\headbang{!*}
+ \MakeMatcher[,]\truestylefiles{*.sty,!.thumbnails/*,!*/.thumbnails/*}
+% \end{macrocode}
+% The matcher constructed in that manner is called with three
+% arguments. The first argument is a control sequence name containing
+% a match target (or target list) prepared using
+% \cmd{\MakeMatchTarget} (see below).
+%
+% Alternatively, the first argument can be a brace-enclosed list (note
+% that you'll need \emph{two} nested levels of braces, one for
+% enclosing the argument, one for specifying that this is a list)
+% which will then get passed to \cmd{\MakeMatchTarget} (see below) for
+% processing before use. The inner level of braces inside of the
+% first argument may be preceded by a bracketed optional argument
+% specifying the list separator for this list.
+%
+% The second argument of the matcher is executed if the pattern list
+% for which the matcher has been built matches the keyword list. The
+% third is executed if it doesn't. List separators of pattern and
+% keyword list are completely independent from each other. Ok, we
+% expect the following to result just in calls of \cmd{\true} (a call
+% of \cmd{\false} is turned into a failed expectation):
+% \begin{macrocode}
+ \begin{qstest}{\Makematcher literal}{\MakeMatcher}
+ \begin{ExpectCallSequence}{\true{}\false{}`%
+ .#1{\Expect*{\CalledName#1}{true}}+'}
+ \stylefiles{{xxx/.thumbnails/blubb.sty}}{\true}{\false}
+ \truestylefiles{{xxx/.thumbnails/blubb.sty}}{\false}{\true}
+ \headbang{{xxx/.thumbnails/blubb.sty}}{\false}{\true}
+ \stylefiles{[ ]{x.sty.gz .thumbnails/x.sty !x}}{\true}{\false}
+ \truestylefiles{[ ]{x.sty.gz .thumbnails/x.sty !x}}{\false}{\true}
+ \headbang{[ ]{x.sty.gz .thumbnails/x.sty !x}}{\true}{\false}
+ \end{ExpectCallSequence}
+ \end{qstest}
+% \end{macrocode}
+%
+% So how do we create a sanitized keyword list in a control sequence?
+%
+% \DescribeMacro{\MakeMatchTarget} is called with two mandatory
+% arguments, the first being a control sequence name where the keyword
+% list in the second argument will get stored in a sanitized form: it
+% is converted without expansion to characters of either ``special''
+% or ``space'' category (catcodes 12 and~10, respectively), and any
+% leading spaces at the beginning of an element is removed. Without
+% an optional bracketed argument, not more than sanitization and
+% leading space stripping is done. If an optional bracketed argument
+% before the mandatory arguments is specified, it defines the list
+% separator: this has to be a single sanitized character token (either
+% a space or a character of category ``other'') that is used as the
+% list separator for the input (the finished list will actually always
+% use the macro |\,| as a list separator).
+% \begin{macrocode}
+ \begin{qstest}{\Makematcher with \MakeMatchTarget}%
+ {\MakeMatcher,\MakeMatchTarget}
+ \MakeMatchTarget\single{xxx/.thumbnails/blubb.sty}
+ \MakeMatchTarget[ ]\multiple{x.sty.gz .thumbnails/x.sty !x}
+ \begin{ExpectCallSequence}{\true{}\false{}`%
+ .#1{\Expect*{\CalledName#1}{true}}+'}
+ \stylefiles{\single}{\true}{\false}
+ \truestylefiles\single{\false}{\true}
+ \headbang\single{\false}{\true}
+ \stylefiles{\multiple}{\true}{\false}
+ \truestylefiles\multiple{\false}{\true}
+ \headbang\multiple{\true}{\false}
+ \end{ExpectCallSequence}
+ \end{qstest}
+% \end{macrocode}
+% \DescribeMacro{\MatchedTarget} This will after a match process
+% contain the target matched by the last matching pattern (if several
+% targets in a match target list match, only the first of those is
+% considered and recorded), regardless of whether the corresponding
+% pattern was negated with |!|.
+%
+% \DescribeMacro{\RemoveMatched} After a successful match, you can
+% call \cmd{\RemoveMatched} with one argument: the control sequence
+% name where the list was kept, and the match will get removed from
+% the list. If every list element is removed, the list will be
+% identical to \cmd{\@empty}.
+% \begin{macrocode}
+ \begin{qstest}{\MatchedTarget}
+ {\MakeMatcher,\MakeMatchTarget,\MatchedTarget}
+ \MakeMatchTarget\single{xxx/.thumbnails/blubb.sty}
+ \MakeMatchTarget[ ]\multiple{x.sty.gz .thumbnails/x.sty !x}
+ \begin{ExpectCallSequence}{\true{}\false{}`%
+ .#1{\Expect*{\CalledName#1}{true}}+'}
+ \stylefiles{\single}{\true}{\false}
+ \Expect*{\single}{xxx/.thumbnails/blubb.sty}
+ \Expect*{\meaning\MatchedTarget}*{\meaning\single}
+ \RemoveMatched\single
+ \Expect*{\meaning\single}{macro:->}
+ \truestylefiles\single{\false}{\true}
+ \headbang\single{\false}{\true}
+ \stylefiles{\multiple}{\true}{\false}
+ \Expect*{\MatchedTarget}{.thumbnails/x.sty}
+ \RemoveMatched\multiple
+ \Expect\expandafter{\multiple}{x.sty.gz\,!x}
+ \truestylefiles\multiple{\false}{\true}
+ \Expect*{\meaning\MatchedTarget}{undefined}
+ \headbang\multiple{\true}{\false}
+ \Expect*{\MatchedTarget}{!x}
+ \RemoveMatched\multiple
+ \Expect*{\multiple}{x.sty.gz}
+ \end{ExpectCallSequence}
+ \end{qstest}
+\end{qstest}
+% \end{macrocode}
+%
+% \subsection{Notes on sanitization}
+% Note that sanitization to printable characters has several
+% consequences: it means that the control sequence \cmd{\,} will turn
+% into the string |\| followed by the end of the keyword. Note also
+% that single-character control sequences with a nonletter name are
+% not followed by a space in sanitization. This means that
+% sanitization depends on the current catcodes. Most particularly,
+% sanitizing the input |\@abc12| will turn into |\@abc 12| when |@| is
+% of catcode letter, but to |\@abc12| when |@| is a nonletter.
+%
+% So sanitization cannot hide all effects of catcode differences. It
+% is still essential since otherwise braces would cause rather severe
+% complications during matching.
+%
+% Another curiosity of sanitization is that explicit macro parameter
+% characters (usually |#|) get duplicated while being sanitized.
+%
+% So this is the end of the documentation section, so we end our test
+% file setup by complementing the beginning:
+% \begin{macrocode}
+%</test>
+%<*dtx>
+\fi
+%</dtx>
+% \end{macrocode}
+%
+% \StopEventually{}
+% \section{The driver file}
+% An explicit driver file generated by docstrip will typeset the
+% implementation. Running the |.dtx| file through, in contrast, will
+% only typeset the user level documentation.
+% \begin{macrocode}
+%<*driver>
+\documentclass{ltxdoc}
+\usepackage{makematch}
+\usepackage{ifpdf}
+\usepackage{hyperref}
+\OnlyDescription
+%<driver> \AlsoImplementation
+\begin{document}
+\GetFileInfo{makematch.sty}
+\date{\filedate}
+\title{\texttt{\filename}\\\fileinfo\\version \fileversion}
+\author{David Kastrup\thanks{\href{mailto:dak@gnu.org}%
+ {David.Kastrup@QuinScape.de}, \href{http://quinscape.de}{QuinScape
+ GmbH}}}
+\maketitle
+\DocInput{makematch.dtx}
+\end{document}
+%</driver>
+% \end{macrocode}
+% \section{The installer file}
+%
+% There is no separate installer file for this package as it is part
+% of the \texttt{qstest} bundle and uses its
+% \href{file:qstest#installer}{installer}.
+%
+% \section{The Implementation}
+% \subsection{Front matter}
+% Some data and version magic from SVN keyword expansion.
+% \begin{macrocode}
+%<*package>
+\NeedsTeXFormat{LaTeX2e}
+\def\next$#1: #2.dtx #3 #4-#5-#6 #7${%
+ \ProvidesPackage{#2}[#4/#5/#6 1.#3 Pattern matching with
+ wildcards]
+}
+\next
+$Id: makematch.dtx 7925 2007-02-23 14:22:19Z dkastrup $
+% \end{macrocode}
+% \subsection{Pattern matching}
+% \begin{macro}{\MakeMatcher}
+% This is the principal magic for doing pattern matching. The
+% control sequence name given in |#1| becomes a pattern matching
+% engine for the pattern list specified in |#2|. If this control
+% sequence is executed at a later point of time, it matches the
+% compiled pattern list to the keyword list contained in the
+% sanitized macro specified in its first argument (if the first
+% argument itself starts with an additional opening brace, it is
+% considered to be a keyword list that yet needs to be sanitized).
+%
+% Macros in |#2| are not expanded, and everything but spaces is
+% converted to catcode~12 characters. At the start of a pattern or
+% a keyword, spaces get ignored. Spaces inside of patterns or
+% keywords should work as expected, however.
+% \begin{macrocode}
+\newcommand\MakeMatcher[3][\relax]{%
+%<etex> \edef#2{\detokenize{#3}}%
+%<*!etex>
+ \toks@{#3}%
+ \edef#2{\the\toks@}%
+ \@onelevel@sanitize#2%
+%</!etex>
+ \def\qst@mmtmp##1##2#1{\qst@parseonecase{##1}{##2}}%
+ \let\qst@comma= #1\relax
+ \edef#2##1{\noexpand\qst@setup##1%
+ \expandafter\qst@parsestart\expandafter\@firstoftwo
+% \end{macrocode}
+% The following |{#1\m@ne}| sequence causes \cmd{\qst@parsestart} to
+% end parsing.
+% \begin{macrocode}
+ #2#1{#1\m@ne}\noexpand\qst@finish}}
+% \end{macrocode}
+% \end{macro}
+% We define two shorthands for matchers that match always and never,
+% respectively:
+% \begin{macro}{\qst@matchalways}
+% \begin{macrocode}
+\long\def\qst@matchalways#1#2#3{#2}
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{\qst@matchnever}
+% \begin{macrocode}
+\long\def\qst@matchnever#1#2#3{#3}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\qst@setup}
+% Gets one argument, namely a macro containing the match list, or
+% otherwise a list enclosed with a level of braces, optionally
+% preceded by the list separator to be used in brackets. This is
+% stored in \cmd{\qst@matchlist}. Furthermore, \cmd{\qst@finish} is
+% set to the default value indicating a non-match.
+% \begin{macrocode}
+\def\qst@setup{\let\MatchedTarget\@undefined
+ \let\qst@finish\@secondoftwo
+ \futurelet\qst@matchlist\qst@setupii}
+\def\qst@setupii{\ifcase
+ \ifcat\noexpand\qst@matchlist\bgroup\@ne\fi
+ \ifx\qst@matchlist[\tw@\fi %]
+ \m@ne
+ \or
+ \expandafter\MakeMatchTarget\expandafter\qst@matchlist
+ \or
+ \expandafter\qst@setupiii
+ \else \expandafter\@gobble
+ \fi}
+\def\qst@setupiii[#1]{\MakeMatchTarget[{#1}]\qst@matchlist}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\qst@parsestart}
+% This tests at the start of a new word whether we are finished or
+% whether there is an inverted condition. Note that this will
+% remove spaces before a word. |#1| indicates the polarity, |#2|~is
+% always a single token, no braces possible.
+% \begin{macrocode}
+\def\qst@parsestart#1#2{%
+ \ifcase
+ \ifx\qst@comma#2\@ne\fi
+ \ifx\qst@comma\relax
+ \else\ifx!#2#1\tw@\@ne\fi
+ \fi
+ \thr@@
+ \or
+ \expandafter\qst@parsestart
+ \expandafter\@firstoftwo
+ \or
+ \expandafter\qst@parsestart
+ \expandafter\@secondoftwo
+ \or
+ \expandafter\qst@mmtmp
+ \expandafter#1%
+ \expandafter#2%
+ \fi
+}
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{\qst@afterfi}
+% This is just a helper macro cleaning up a following |\fi|.
+% \begin{macrocode}
+\def\qst@afterfi#1#2\fi{\fi#1}
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{\qst@parseonecase}
+% We process one pattern here. A pattern ends with |,| and we have
+% passed in |#1| the command to execute in case the pattern
+% matches.
+% \begin{macrocode}
+\def\qst@parseonecase#1#2{%
+ \noexpand\qst@checkname {\qst@parsewild#2*\,23456789*}%
+ \noexpand#1\qst@parsestart\@firstoftwo}
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{\qst@parsewild}
+% This is the parsing macro for wildcards and stuff. |#1|~is
+% material before the next |*| character or the end of the sequence,
+% |#2|~is either empty (indicating the end of the word to match) or
+% material coming after a wildcard and terminated by |*|,
+% |#3|~contains the next unused parameter number, and |#4| contains
+% following parameter numbers. If we emitted a wildcard code, we
+% jump into \cmd{\qst@skipwild} in order to skip additional
+% wildcards.
+% \begin{macrocode}
+\def\qst@parsewild#1*#2\,#3#4*{%
+ #1%
+ \ifx\,#2\,%
+ \else
+ #####3%
+ \qst@afterfi{\qst@skipwild#2\,#4*}%
+ \fi}
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{\qst@skipwild}
+% This caters for the case where successive wildcards are
+% encountered. This is the case if |#1| is empty, meaning that the
+% string started with |*|, but |#2| is non-empty, indicating that we
+% are not at the terminal |*|.
+% \begin{macrocode}
+\def\qst@skipwild#1*#2\,{%
+ #1%
+ \ifcase
+ \ifx *#1*\ifx\,#2\,\else \@ne \fi \fi
+ \tw@
+ \or
+ \expandafter\qst@skipwild
+ \or
+ \expandafter\qst@parsewild\expandafter*%
+ \fi#2\,}
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{\qst@checkname}
+% This is called with a compiled form of a test pattern in~|#1| and
+% a single token that will get assigned to \cmd{\qst@finish} in case
+% that we got a match of the pattern with any of the comma-separated
+% keywords in \cmd{\MatchList}.
+%
+% Here is how \cmd{\qst@checkname} works: both test pattern and
+% option list are placed between commas (actually \cmd{\,}) so that
+% a match of the test pattern on the list implies a full match. The
+% test pattern happens to match itself when just interpreted as an
+% unexpanded pattern string, and this pattern string does not
+% contain commas in itself. We append the pattern string as an
+% artificial last element in the option list. Since the trailing
+% comma placed at the end of the match pattern can't match inside of
+% an option, options are consumed only completely. If the pattern
+% matched a string containing a comma, it actually did so across
+% more than a single option. In that case, we remove everything up
+% to the first comma and try again.
+%
+% We define \cmd{\qst@mmtmp} as a macro that matches starting at an
+% arbitrary comma (throwing away everything preceding), then
+% retaining the matched string (note that |#1| in the replacement
+% text will faithfully reproduce what was matched by |#1| in the
+% argument string, also note the difference between |#1| and |##1|),
+% appending a separator of \cmd{\@nil} in order to delimit the
+% matched sequence.
+% \begin{macrocode}
+\def\qst@checkname#1{%
+ \def\qst@mmtmp##1\,#1\,{#1\,\@nil}%
+ \expandafter\expandafter\expandafter\qst@checknameii
+ \expandafter\qst@mmtmp
+ \expandafter\,\qst@matchlist\,#1\,\@nil}
+% \end{macrocode}
+% \begin{macro}{\qst@checknameii}
+% So we now do the check. If |#3| is |\@nil|, the sentinel has been
+% consumed and we did not match anything. If this is not the case,
+% we split the matched material at the first comma into |#1|
+% and~|#2|. If |#2| is empty, no comma is contained in the match,
+% so we matched a complete option. Otherwise, if |#2| is non-empty,
+% the match contained a comma and was across several options
+% (possibly breaking into the sentinel without consuming it). Ugh.
+% We remove the first option that was conflated in the match, and
+% restart the match process.
+%
+% Note that |#3| has its origin from behind a comma, so at its
+% position there are no leading spaces that could get lost by it
+% being an undelimited argument.
+% \begin{macrocode}
+\def\qst@checknameii#1\,#2\@nil#3{%
+ \ifcase
+ \ifx\@nil#3\@ne\fi
+ \ifx\@nil#2\@nil \tw@\fi
+ \m@ne
+ \or
+ \expandafter\qst@checknamenomatch
+ \or
+ \expandafter\qst@checknamematch
+ \fi \expandafter\qst@checknameii\qst@mmtmp#1\,#2#3}
+% \end{macrocode}
+% \begin{macro}{\qst@checknamenomatch}
+% This removes remaining garbage and the code corresponding to the
+% polarity of the test since the test is not taken.
+% \begin{macrocode}
+\def\qst@checknamenomatch#1\@nil#2{}
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{\qst@checknamematch}
+% We had a match, something which did not include a comma and at the
+% same time left the sentinel at the end of the word list intact.
+% So clean up and take over the right polarity.
+% \begin{macrocode}
+\def\qst@checknamematch#1\qst@mmtmp#2\,#3\@nil{%
+ \def\MatchedTarget{#2}%
+ \let\qst@finish}
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% Now for removing patterns: |\romannumeral\z@| expands to
+% nothing, but we use it as a an \cmd{\expandafter}-Propagator.
+% \begin{macro}{\RemoveMatched}
+% \begin{macrocode}
+\def\RemoveMatched#1{\ifx#1\MatchedTarget
+ \let#1\@empty
+ \else
+ \expandafter\def\expandafter\qst@mmtmp
+ \expandafter##\expandafter1\expandafter\,\MatchedTarget\,{##1\,}%
+ \expandafter\def\expandafter#1\expandafter{%
+ \romannumeral\expandafter\expandafter\expandafter\z@
+ \expandafter\qst@remmat
+ \romannumeral\expandafter\expandafter\expandafter\z@
+ \expandafter\qst@mmtmp\expandafter\,#1\,\@nil}%
+ \fi}
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{\qst@remmat}
+% This is just a helper macro removing \cmd{\,} from around the
+% list.
+% \begin{macrocode}
+\def\qst@remmat\,#1\,\@nil{#1}
+% \end{macrocode}
+% \end{macro}
+%
+% Ok, let's test this thing for some patterns.
+% \begin{macrocode}
+%</package>
+%<*test>
+\makeatletter
+\begin{qstest}{\MakeMatcher internals}{\MakeMatcher,internal}
+ \MakeMatcher\sometest{}
+ \Expect*{\meaning\sometest}{macro:#1->\qst@setup#1\qst@finish}
+ \MakeMatcher[,]\sometest{ a, bc*, !woozle**, !*#*woz***.*x, !!*ab}
+ \Expect*{\meaning\sometest}{macro:#1->%
+ \qst@setup#1%
+ \qst@checkname{a}\@firstoftwo
+ \qst@checkname{bc##2}\@firstoftwo
+ \qst@checkname{woozle##2}\@secondoftwo
+ \qst@checkname{##2####3woz##4.##5x}\@secondoftwo
+ \qst@checkname{##2ab}\@firstoftwo
+ \qst@finish}
+ \MakeMatcher[ ]\another{ a bc* ! woozle** ! *#*woz***.*x ! ! *ab}
+ \Expect*{\meaning\another}*{\meaning\sometest}
+\end{qstest}
+%</test>
+%<*package>
+% \end{macrocode}
+%
+% \begin{macro}{\MakeMatchTarget}
+% This gets two obligatory arguments, a control sequence name and
+% the keyword list. This list is sanitized and prepared for
+% matching. The list sanitized in this manner is stored in the
+% control sequence in~|#2|, the first obligatory argument. The
+% gobbledygook before and after the detokenized content is there to
+% get started nicely into the loop with \cmd{\qst@mmtmp} and get out
+% again without having to employ expensive tests. The purpose of
+% \cmd{\qst@mmtmp} is to remove leading spaces from list elements
+% and replace the list separator (which defaults to `|,|' but can be
+% specified with an optional argument to \cmd{\MakeMatchTarget})
+% with the sentinel separator |\,| which can't otherwise occur in a
+% sanitized list. There are several special values for the list
+% separator that make sense:
+% \begin{description}
+% \item[\textvisiblespace] A space character (catcode 10). List
+% entries are separated by spaces.
+% \item[$\textrm{other}_{12}$] A character of catcode~12 that is
+% going to be used as a list separator. Don't use anything other
+% than sanitized characters, or the effects will be as with the
+% following:
+% \item[\texttt{\string\relax}] The default, does not do any list
+% replacement.
+% \end{description}
+% Don't ever pass anything other than a single token (possibly
+% brace-enclosed) in this manner, or things will go really wrong.
+% \begin{macrocode}
+\newcommand\MakeMatchTarget[3][\relax]{%
+ \def\qst@mmtmp##1#1##2{##1\noexpand\,\qst@mmtmp##2}%
+%<*etex>
+ \edef#2{\expandafter\qst@mmtmp\expandafter
+ \@gobbletwo\expandafter#1\detokenize{#3}\iffalse#1\fi}%
+%</etex>
+%<*!etex>
+ \toks@{#3}%
+ \edef#2{\the\toks@}%
+ \@onelevel@sanitize#2%
+ \edef#2{\expandafter\qst@mmtmp\expandafter
+ \@gobbletwo\expandafter#1#2\iffalse#1\fi}%
+%</!etex>
+}
+% \end{macrocode}
+% \end{macro}
+% \subsection{The End}
+% The test can be ended either in the driver file, or in a standalone
+% testfile. \cmd{\stop} is \LaTeX's way of ending the processing of
+% an input file before any document processing or setup has been done.
+% \begin{macrocode}
+%</package>
+%<test>\stop
+% \end{macrocode}
+% \Finale
diff --git a/Master/texmf-dist/source/latex/qstest/qstest.drv b/Master/texmf-dist/source/latex/qstest/qstest.drv
new file mode 100644
index 00000000000..b866c210857
--- /dev/null
+++ b/Master/texmf-dist/source/latex/qstest/qstest.drv
@@ -0,0 +1,170 @@
+%%
+%% This is file `qstest.drv',
+%% generated with the docstrip utility.
+%%
+%% The original source files were:
+%%
+%% qstest.dtx (with options: `driver,test,etex')
+%%
+%% IMPORTANT NOTICE:
+%%
+%% For the copyright see the source file.
+%%
+%% Any modified versions of this file must be renamed
+%% with new filenames distinct from qstest.drv.
+%%
+%% For distribution of the original source see the terms
+%% for copying and modification in the file qstest.dtx.
+%%
+%% This generated file may be distributed as long as the
+%% original source files, as listed above, are part of the
+%% same distribution. (The sources need not necessarily be
+%% in the same archive or directory.)
+\errorcontextlines=\maxdimen
+%%
+%% Copyright (C) 2006, 2007 QuinScape GmbH
+%% http://www.quinscape.de
+\RequirePackage{qstest}
+\LogTests{lgout}{*}{*}
+\begin{qstest}{# in isolation}{\Expect, #, \unexpanded}
+ \toks0{# and #}
+ \Expect*{\the\toks0}*{\unexpanded{# and #}}
+\end{qstest}
+\begin{qstest}{# in isolation 2}{\Expect, #, \string}
+ \toks0{# and #}
+ \Expect*{\the\toks0}*{\string#\string# and \string#\string#}
+\end{qstest}
+\begin{qstest}{# as macro parameter}{\Expect, #}
+ \toks0{\def\xxx#1{}}
+ \Expect\expandafter{\the\toks0}{\def\xxx#1{}}
+\end{qstest}
+\makeatletter
+\begin{qstest}{Some LaTeX definitions}{\Expect}
+ \Expect*{\meaning\@gobble}{\long macro:#1->}
+ \Expect*{\the\maxdimen}{16383.99998pt}
+\end{qstest}
+\RequirePackage{ifthen}
+\begin{qstest}{\ExpectIfThen}{\ExpectIfThen}
+ \ExpectIfThen{\lengthtest{\maxdimen=16383.99998pt}\AND
+ \maxdimen>1000000000}
+\end{qstest}
+\begin{qstest}{\InRange success}{\InRange}
+ \dimen@=10pt
+ \Expect*{\the\dimen@}\InRange{5pt}{15pt}
+ \Expect*{\the\dimen@}\InRange{10pt}{15pt}
+ \Expect*{\the\dimen@}\InRange{5pt}{10pt}
+\end{qstest}
+\begin{qstest}{\InRange failure}{\InRange, fails}
+ \dimen@=10pt \dimen@ii=9.99998pt
+ \Expect*{\the\dimen@}\InRange{5pt}{\dimen@ii}
+ \dimen@ii=10.00002pt
+ \Expect*{\the\dimen@}*\InRange{\the\dimen@ii}{15pt}
+\end{qstest}
+\begin{qstest}{\NearTo success}{\NearTo}
+ \dimen@=10pt
+ \Expect*{\the\dimen@}\NearTo{10.05pt}
+ \Expect*{\the\dimen@}\NearTo{9.95pt}
+ \Expect*{\the\dimen@}\NearTo[2pt]{12pt}
+ \Expect*{\the\dimen@}\NearTo[0.1pt]{9.9pt}
+\end{qstest}
+\begin{qstest}{\NearTo failure}{\NearTo, fails}
+ \dimen@=10pt
+ \Expect*{\the\dimen@}\NearTo{10.05002pt}
+ \Expect*{\the\dimen@}\NearTo[1pt]{11.00001pt}
+\end{qstest}
+\begin{qstest}{\SavedValue}{\SavedValue}
+ \SaveValueFile{\jobname.qsout}
+ \SaveValue{\InternalSetValue}*{\meaning\InternalSetValue}
+ \SaveValue{\IncludeTests}*{\meaning\IncludeTests}
+ \SaveValue{whatever}*{3.1415}
+ \SaveValue{\maxdimen}*{\the\maxdimen}
+ \Expect{Whatever}\SavedValue{\InternalSetValue}
+ \Expect[\IncludeTests]{Whatever else}\SavedValue{\IncludeTests}
+ \Expect[whatever]{2.71828}\SavedValue{whatever}
+ \Expect[undefined]{1.618034}\SavedValue{undefined}
+ \CloseValueFile
+ \input{\jobname.qsout}
+ \Expect*{\meaning\InternalSetValue}\SavedValue{\InternalSetValue}
+ \Expect[\IncludeTests]*{\meaning\IncludeTests}%
+ \SavedValue{\IncludeTests}
+ \Expect[whatever]{3.1415}\SavedValue{whatever}
+ \Expect[undefined]{1.618034}\SavedValue{undefined}
+\end{qstest}
+\begin{qstest}{\SavedValue failure}{\SavedValue,fails}
+ \Expect{Whatever}\SavedValue{\InternalSetValue}
+ \Expect[\IncludeTests]{Whatever else}\SavedValue{\IncludeTests}
+ \Expect{2.71828}\SavedValue{whatever}
+\end{qstest}
+\begin{qstest}{ExpectCallSequence}{ExpectCallSequence}
+ \def\e{e} \def\f{f}
+ \def\g{g} \def\h{h}
+ \begin{ExpectCallSequence}{`\e#1{%
+ \Expect\expandafter{\csname\CalledName#1\endcsname}{\e }%
+ \Expect*{\meaning#1}{macro:->e}}+\f#1{}'}
+ \e \e \e \e \f
+ \end{ExpectCallSequence}
+\end{qstest}
+\LogClose{lgout}
+\documentclass{ltxdoc}
+\usepackage{qstest}
+\usepackage{hyperref}
+\OnlyDescription
+ \AlsoImplementation
+\begin{document}
+\GetFileInfo{qstest.sty}
+\date{\filedate}
+\title{\texttt{\filename}\\\fileinfo\\version \fileversion}
+\author{David Kastrup\thanks{\href{mailto:dak@gnu.org}
+ {David.Kastrup@QuinScape.de}, \href{http://quinscape.de}{QuinScape
+ GmbH}}}
+\maketitle
+\DocInput{qstest.dtx}
+\end{document}
+\IncludeTests{*}
+\makeatletter
+\begin{qstest}{\LogClose}{}
+\begin{ExpectCallSequence}{%
+ `\PackageInfo#1#2#3{\Expect[##1]{#2}{qstest}%
+ \Expect[##2]{#3}{Logging off: \jobname.log}%
+ #1{#2}{#3}}'}
+ \LogClose{log}
+\end{ExpectCallSequence}
+\end{qstest}
+\begin{qstest}{\LogTests}{}
+\begin{ExpectCallSequence}{%
+ \PackageInfo#1#2#3{\Expect[##1]{#2}{qstest}%
+ \Expect[##2]{#3}{Logging on: \jobname.log}%
+ #1{#2}{#3}}}
+ \LogTests{log}{*}{*}
+\end{ExpectCallSequence}
+\end{qstest}
+\begin{qstest}{ExpectCallSequence state machine}%
+ {ExpectCallSequence,internal}
+ \def\foo#1#2#3{\relax\relax}
+ \let\fie\relax
+ \Expect*{\qst@csallocstate}{3}
+ \Expect*{\qst@csalloctrans}{2}
+ \begin{ExpectCallSequence}{\fie{}%
+ `\foo#1#2#3{#2\bar{#3}}(\bar#1#2{#2}|.#1{})+%
+ \foo#1{}}
+ \Expect*{\qst@csstate}{7}
+ \Expect*{\qst@csallocstate}{15}
+ \foo{\Expect*{\qst@csstate}{8}}{\Expect*{\qst@csstate}{10}}
+ \Expect*{\qst@csstate}{10}
+ \fie
+ \Expect*{\qst@csstate}{12}
+ \foo
+ \Expect*{\qst@csstate}{14}
+ \fie
+ \Expect*{\qst@csstate}{0}
+ \Expect*{\meaning\fie}*{\meaning\relax}
+ \foo\junk\junk\junk
+ \Expect*{\qst@csstate}{0}
+ \Expect*{\meaning\foo}{macro:#1#2#3->\relax \relax}
+ \end{ExpectCallSequence}
+\end{qstest}
+ \stop
+
+\endinput
+%%
+%% End of file `qstest.drv'.
diff --git a/Master/texmf-dist/source/latex/qstest/qstest.dtx b/Master/texmf-dist/source/latex/qstest/qstest.dtx
new file mode 100644
index 00000000000..b485af31517
--- /dev/null
+++ b/Master/texmf-dist/source/latex/qstest/qstest.dtx
@@ -0,0 +1,1674 @@
+\errorcontextlines=\maxdimen
+% \iffalse
+%%
+%% Copyright (C) 2006, 2007 QuinScape GmbH
+%% http://www.quinscape.de
+%
+% This file may be distributed and/or modified under the
+% conditions of the LaTeX Project Public License, either version 1.3
+% of this license or (at your option) any later version.
+% The latest version of this license is in
+% http://www.latex-project.org/lppl.txt
+% \fi
+%
+% \CheckSum{1258}
+% \section{Using \texttt{qstest}}
+%
+% The basic idea of \texttt{qstest} is to let the user specify a
+% number of tests that can be performed either at package load time or
+% while running a separate test file through \LaTeX. If you are
+% writing |.dtx| files, it is a good idea to use Docstrip `modules'
+% for specifying which lines are to be used for testing. The file
+% |qstest.dtx| from which both the style file as well as this
+% documentation have been generated has been done in this manner.
+%
+% Since the following tests should be ignored when the |dtx| file is
+% compiled itself, we use this for skipping over the tests:
+% \begin{macrocode}
+%<*dtx>
+\iffalse
+%</dtx>
+% \end{macrocode}
+%
+% A standalone test file actually does not need a preamble. We can
+% load the packages with \cmd{\RequirePackage} and just go ahead. Let
+% us demonstrate how to build such a test file by testing the |qstest|
+% package itself:
+% \begin{macrocode}
+%<*test>
+\RequirePackage{qstest}
+% \end{macrocode}
+%
+% \subsection{Pattern and keyword lists}
+%
+% Check section \href{file:makematch#patterns}{``Match patterns and
+% targets''} of the |makematch| package for an explanation of the
+% comma-separated pattern and keyword lists. In a nutshell, both are
+% lists of arbitrary material that is not expanded but rather used in
+% sanitized (printable) form. Patterns may contain wildcard
+% characters |*| matching zero or more characters, and may be preceded
+% by |!| in order to negate a match from an earlier pattern in the
+% pattern list. Leading spaces before an item in either list are
+% discarded.
+%
+% \subsection{Specifying test sets}
+%
+% \DescribeMacro{\IncludeTests} This macro specifies a pattern list
+% matched to tests' keyword lists in order to determine the tests to
+% be included in this test run. The characters |*| and |!| are
+% interpreted as explained above.
+%
+% For example,
+% \begin{quote}
+% |\IncludeTests{*, !\cs}|
+% \end{quote}
+% will run all tests except those that have a test keyword of |\cs| in
+% their list of keywords. It is a good convention to specify the
+% principal macro or environment to be tested as the first keyword.
+%
+% The default is to include all tests. If you are interspersing
+% possibly expensive tests with your source file, you might want to
+% specify something like
+% \begin{quote}
+% |\IncludeTests{*, !expensive}|
+% \end{quote}
+% or even
+% \begin{quote}
+% |\IncludeTests{}|
+% \end{quote}
+% in your document preamble, and then possibly override this on the
+% command line with
+% \begin{quote}
+% |latex "\AtBeginDocument{\IncludeTests{*}}\input{file}"|
+% \end{quote}
+% or similar for getting a more complete test.
+%
+% \DescribeMacro{\TestErrors} This defines test patterns that will
+% throw an error when failing. A test that throws an error will not
+% also add a warning to the standard log file with extension |log|
+% since that would be redundant.
+%
+% The default is |\TestErrors{*, !fails}|, have all tests that are not
+% marked as broken throw an error when they fail.
+%
+% The throwing of errors does not depend on the logging settings (see
+% below) for the default |log| file.
+%
+% \DescribeMacro{\LogTests} This macro receives three arguments. The
+% first is the filename extension of a log file (the extension |log|
+% is treated specially and uses package warning and info commands to
+% log test failures and passes, respectively). The second is a
+% keyword list that indicates which passed tests are to be logged.
+% The third is a keyword list specifying which failed tests are to be
+% logged. Let us open a file logging everything:
+% \begin{macrocode}
+\LogTests{lgout}{*}{*}
+% \end{macrocode}
+% The choice of |lgout| is made to make it possible to also have
+% |lgin| for comparison purposes: the latter would be an |lgout| file
+% from a previous, `definitive run', renamed and checked into version
+% control, for the sake of being able to compare the log output from
+% different versions.
+%
+% An already open log file stays open and just changes what is logged.
+% By default, the standard |log|
+% \mbox{(pseudo-)}\discretionary{}{}{}file is already open and logs
+% everything.
+%
+% Passed and failed tests are not completely symmetric with regard to
+% logging: test failures are logged and/or indicated on the individual
+% failed assertions, while a successful test is only logged and/or
+% indicated in summary.
+%
+% \DescribeMacro{\LogClose} You can explicitly close a log file if you
+% want to reread it in the course of processing, or call an executable
+% that would process it. The standard file with extension |log| will
+% not actually get closed and flushed if you do this (though logging
+% would stop on it), but all others might. The actual example for
+% this follows after the tests. You can reopen a closed log file
+% using \cmd{\LogTests}. It will then get rewritten from the
+% beginning (with the exception for the standard |log| file, of
+% course).
+%
+% \subsection{The tests}
+%
+% \DescribeEnv{qstest}
+% Tests are performed within the |qstest| environment. The
+% environment gets two arguments. The first is the name of the test
+% recorded in the log file. The second is a list of test keywords
+% used for deciding which tests are performed and logged.
+%
+% Before delving in the details of what kind of tests you can perform
+% in this environment, we list the various commands that are given
+% patterns and thus control what kind of tests are performed and
+% logged.
+%
+% \DescribeMacro{\Expect}
+% This is the workhorse for checking that values, dimensions, macros
+% and other things are just like the test designer would expect them
+% to be.
+%
+% This macro basically receives two brace-delimited
+% arguments\footnote{The arguments are collected with a token register
+% assignment. This gives several options for specifying them,
+% including giving a token register without braces around it. It
+% also makes it possible to precede the \textsl{balanced text} with
+% \cmd{\expandafter} and similar expandable stuff.} and checks that
+% they are equal after being passed through \cmd{\def} and sanitized.
+% This means that you can't normally use |#| except when followed by a
+% digit (all from 1 to 9 are allowed) or |#|. If you precede one of
+% those arguments with |*| it gets passed through through \cmd{\edef}
+% instead of \cmd{\def}. There may also be additional tokens like
+% |\expandafter| before the opening brace. Note that the combination
+% of \cmd{\edef} and |\the|\meta{token variable} can be used to pass
+% through |#| characters without interpretation. e\TeX\ provides a
+% similar effect with \cmd{\unexpanded}. So if you want to compare a
+% token list that may contain isolated hash characters, you can do so
+% by writing something like
+% \begin{macrocode}
+%<*etex>
+\begin{qstest}{# in isolation}{\Expect, #, \unexpanded}
+ \toks0{# and #}
+ \Expect*{\the\toks0}*{\unexpanded{# and #}}
+\end{qstest}
+%</etex>
+% \end{macrocode}
+% Since the sanitized version will convert |#| macro parameters to the
+% string |##|, you might also do this explicitly (and without e\TeX)
+% as
+% \begin{macrocode}
+\begin{qstest}{# in isolation 2}{\Expect, #, \string}
+ \toks0{# and #}
+ \Expect*{\the\toks0}*{\string#\string# and \string#\string#}
+\end{qstest}
+% \end{macrocode}
+% If the token register is guaranteed to only contain `proper' |#|
+% characters that are either followed by another |#| or a digit, you
+% can let the normal interpretation of a macro parameter for
+% \cmd{\def} kick in and use this as
+% \begin{macrocode}
+\begin{qstest}{# as macro parameter}{\Expect, #}
+ \toks0{\def\xxx#1{}}
+ \Expect\expandafter{\the\toks0}{\def\xxx#1{}}
+\end{qstest}
+% \end{macrocode}
+% In this manner, |#1| is interpreted (and sanitized) as a macro
+% parameter on both sides, and consequently no doubling of |#|
+% occurs.
+%
+% Before the comparison is done, both arguments are sanitized,
+% converted into printing characters with standardized catcodes
+% throughout\footnote{Spaces get catcode~10, all other characters
+% catcode~12.}. A word of warning: both sanitization as well as
+% using \cmd{\meaning} still depend on catcode settings, since
+% single-letter control sequences (made from a catcode 11 letter)
+% are followed by a space, and other single-character control
+% sequences are not. For that reason, a standalone test file for
+% \LaTeX\ class or package files will usually need to declare
+% \begin{macrocode}
+\makeatletter
+% \end{macrocode}
+% in order to make `|@|' a letter, like it usually is in such
+% files.
+%
+% All of the of the following expectations would turn out correct:
+% \begin{macrocode}
+\begin{qstest}{Some LaTeX definitions}{\Expect}
+ \Expect*{\meaning\@gobble}{\long macro:#1->}
+ \Expect*{\the\maxdimen}{16383.99998pt}
+\end{qstest}
+% \end{macrocode}
+% Note that there is no way to convert the contents of a box into a
+% printable rendition, so with regard to boxes, you will be mostly
+% reduced to check that dimensions of a box meet expectations.
+%
+% \subsection{Expecting \texttt{ifthen} conditions}
+% \DescribeMacro{\ExpectIfThen}
+% This is used for evaluating a condition as provided by the
+% |ifthen| package. See its docs for the kind of condition that is
+% possible there. You just specify one argument: the condition that
+% you expect to be true. Here is an example:
+% \begin{macrocode}
+\RequirePackage{ifthen}
+\begin{qstest}{\ExpectIfThen}{\ExpectIfThen}
+ \ExpectIfThen{\lengthtest{\maxdimen=16383.99998pt}\AND
+ \maxdimen>1000000000}
+\end{qstest}
+% \end{macrocode}
+%
+% \subsection{Dimension ranges}
+%
+% \DescribeMacro{\InRange} Sometimes we want to check whether some
+% dimension is not exactly like some value, but rather in some range.
+% We do this by specifying as the second argument to \cmd{\Expect} an
+% artificial macro with two arguments specifying the range in
+% question. This will make \cmd{\Expect} succeed if its first
+% argument is in the range specified by the two arguments to
+% \cmd{\InRange}.
+%
+% The range is specified as two \TeX\ dimens. If you use a dimen
+% register and you want to have a possible error message display the
+% value instead of the dimen register, you can do so by using the |*|
+% modifier before \cmd{\InRange} (which will cause the value to be
+% expanded before printing and comparing) and put \cmd{\the} before
+% the dimen register since such register are not expandible by
+% themselves.
+%
+% Here are some examples:
+% \begin{macrocode}
+\begin{qstest}{\InRange success}{\InRange}
+ \dimen@=10pt
+ \Expect*{\the\dimen@}\InRange{5pt}{15pt}
+ \Expect*{\the\dimen@}\InRange{10pt}{15pt}
+ \Expect*{\the\dimen@}\InRange{5pt}{10pt}
+\end{qstest}
+\begin{qstest}{\InRange failure}{\InRange, fails}
+ \dimen@=10pt \dimen@ii=9.99998pt
+ \Expect*{\the\dimen@}\InRange{5pt}{\dimen@ii}
+ \dimen@ii=10.00002pt
+ \Expect*{\the\dimen@}*\InRange{\the\dimen@ii}{15pt}
+\end{qstest}
+% \end{macrocode}
+% \DescribeMacro{\NearTo} This requires e\TeX's arithmetic and will
+% not be available for versions built without e\TeX\ support. The
+% macro is used in lieu of an expected value and is similar to
+% \cmd{InRange} in that it is a pseudovalue to be used for the second
+% argument of \cmd{\Expect}. It makes \cmd{\Expect} succeed if its
+% own mandatory argument is close to the first argument from
+% \cmd{\Expect}, where closeness is defined as being within |0.05pt|.
+% This size can be varied by specifying a different one as optional
+% argument to \cmd{\NearTo}. Here is a test:
+% \begin{macrocode}
+%<*etex>
+\begin{qstest}{\NearTo success}{\NearTo}
+ \dimen@=10pt
+ \Expect*{\the\dimen@}\NearTo{10.05pt}
+ \Expect*{\the\dimen@}\NearTo{9.95pt}
+ \Expect*{\the\dimen@}\NearTo[2pt]{12pt}
+ \Expect*{\the\dimen@}\NearTo[0.1pt]{9.9pt}
+\end{qstest}
+\begin{qstest}{\NearTo failure}{\NearTo, fails}
+ \dimen@=10pt
+ \Expect*{\the\dimen@}\NearTo{10.05002pt}
+ \Expect*{\the\dimen@}\NearTo[1pt]{11.00001pt}
+\end{qstest}
+%</etex>
+% \end{macrocode}
+%
+% \subsection{Saved results}
+%
+% The purpose of saved results is to be able to check that the value
+% has remained the same over passes. Results are given a unique label
+% name and are written to an auxiliary file where they can be read in
+% for the sake of comparison. One can use the normal |aux| file for
+% this purpose, but it might be preferable to use a separate dedicated
+% file. That way it is possible to input a versioned \emph{copy} of
+% this file and have a fixed point of reference rather than the last
+% run.
+%
+% While the |aux| file is read in automatically at the beginning of
+% the document, this does not happen with explicitly named files. You
+% have to read them in yourself, preferably using
+% \begin{quote}
+% |\InputIfFileExists|\marg{filename}|{}{}|
+% \end{quote}
+% so that no error is thrown when the file does not yet exist.
+%
+% \DescribeMacro{\SaveValueFile} This gets one argument specifying
+% which file name to use for saving results. If this is specified, a
+% special file is opened. If \cmd{\SaveValueFile} is not called, the
+% standard |aux| file is used instead, but then you can only save
+% values after |\begin||{document}|. |\jobname.qsout| seems like a
+% useful file name to use here (the extension |out| is already in
+% use by PDF\TeX).
+% \begin{macrocode}
+\begin{qstest}{\SavedValue}{\SavedValue}
+ \SaveValueFile{\jobname.qsout}
+% \end{macrocode}
+% If this were a real test instead of just documentation, we probably
+% would have written something like
+% \begin{quote}
+% |\InputIfFileExists{\jobname.qsin}{}{}|
+% \end{quote}
+% first in order to read in values from a previous run. The given
+% file would have been a copy of a previous |qsout| file, possibly
+% checked into version control in order to make sure behavior is
+% consistent across runs. If it is an error to not have such a file
+% (once you have established appropriate testing), you can just write
+% \begin{quote}
+% |\input{\jobname.qsin}|
+% \end{quote}
+% instead, of course.
+%
+% \DescribeMacro{\CloseValueFile} This macro takes no argument and
+% will close a value save file if one is open (using this has no
+% effect if no file has been opened and values are saved on the |aux|
+% file instead). We'll demonstrate use of it later. It is probably
+% only necessary for testing |qstest| itself (namely, when you read in
+% saved values in the same run), or when you do the
+% processing/comparison with a previous version by executing commands
+% via \TeX's |\write18| mechanism.
+%
+% \DescribeMacro{\SaveValue} This gets the label name as first
+% argument. If you are using the non-e\TeX-version, the label name
+% gets sanitized using \cmd{\string} and so can't deal with
+% non-character material except at its immediate beginning. The
+% e\TeX-version has no such constraint.
+%
+% The second argument is the same kind of argument as \cmd{\Expect}
+% expects, namely something suitable for a token register assignment
+% which is passed through \cmd{\def} if not preceded by |*|, and by
+% \cmd{\edef} if preceded by |*|. The value is written out to the
+% save file where it can be read in afterwards.
+%
+% Let us save a few values under different names now:
+% \begin{macrocode}
+ \SaveValue{\InternalSetValue}*{\meaning\InternalSetValue}
+ \SaveValue{\IncludeTests}*{\meaning\IncludeTests}
+ \SaveValue{whatever}*{3.1415}
+ \SaveValue{\maxdimen}*{\the\maxdimen}
+% \end{macrocode}
+% \DescribeMacro{\InternalSetValue} A call to this macro is placed
+% into the save file for each call of \cmd{\SaveValue}. The details
+% are not really relevant: in case you run into problems while
+% inputting the save file, it might be nice to know.
+%
+% \DescribeMacro{\SavedValue} This is used for retrieving a saved
+% value. When used as the second argument to \cmd{\Expect}, it will
+% default to the value of the first argument to \cmd{\Expect} unless
+% it has been read in from a save file. This behavior is intended for
+% making it easy to add tests and saved values and not get errors at
+% first, until actually values from a previous test become available.
+%
+% Consequently, the following tests will all turn out true before we
+% read in a file, simply because all the saved values are not yet
+% defined and default to the expectations:
+% \begin{macrocode}
+ \Expect{Whatever}\SavedValue{\InternalSetValue}
+ \Expect[\IncludeTests]{Whatever else}\SavedValue{\IncludeTests}
+ \Expect[whatever]{2.71828}\SavedValue{whatever}
+ \Expect[undefined]{1.618034}\SavedValue{undefined}
+% \end{macrocode}
+% After closing and rereading the file, we'll need to be more careful
+% with our expectations, but the last line still works since there
+% still is no saved value for ``undefined''.
+% \begin{macrocode}
+ \CloseValueFile
+ \input{\jobname.qsout}
+ \Expect*{\meaning\InternalSetValue}\SavedValue{\InternalSetValue}
+ \Expect[\IncludeTests]*{\meaning\IncludeTests}%
+ \SavedValue{\IncludeTests}
+ \Expect[whatever]{3.1415}\SavedValue{whatever}
+ \Expect[undefined]{1.618034}\SavedValue{undefined}
+\end{qstest}
+% \end{macrocode}
+% Ok, and now lets take the previous tests which succeeded again and
+% let them fail now that the variables are defined:
+% \begin{macrocode}
+\begin{qstest}{\SavedValue failure}{\SavedValue,fails}
+ \Expect{Whatever}\SavedValue{\InternalSetValue}
+ \Expect[\IncludeTests]{Whatever else}\SavedValue{\IncludeTests}
+ \Expect{2.71828}\SavedValue{whatever}
+\end{qstest}
+% \end{macrocode}
+%
+%
+% \subsection{Checking for call sequences}
+% \DescribeEnv{ExpectCallSequence} The environment
+% |ExpectCallSequence| tells the test system that macros are going to
+% be called in a certain order and with particular types of arguments.
+%
+% It gets as an argument the expected call sequence. The call
+% sequence contains entries that look like a macro definition:
+% starting with the macro name followed with a macro argument list and
+% a brace-enclosed substitution text that gets executed in place of
+% the macro. The argument list given to this macro substitution will
+% get as its first argument a macro with the original definition of
+% the control sequence, so you can get at the original arguments for
+% this particular macro call starting with |#2|. As a consequence, if
+% you specify no arguments at all and an empty replacement text for
+% the substitution, the original macro gets executed with the original
+% arguments.
+%
+% \DescribeMacro{\CalledName} If you want to get back from the control
+% sequence with the original meaning in |#1| to the original macro
+% name, you can use \cmd{\CalledName} on it. This will expand to the
+% original control sequence \emph{name}, all in printable characters
+% fit for output or typesetting in a typewriter font (or use in
+% \cmd{\csname}), but without leading backslash character. You can
+% get to the control sequence itself by using
+% \begin{quote}
+% |\csname \CalledName#1\endcsname|
+% \end{quote}
+% and to a printable version including backslash by using
+% \begin{quote}
+% |\expandafter \string \csname \CalledName#1\endcsname|
+% \end{quote}
+%
+% Going into more detail, a substitution function is basically defined
+% using
+% \begin{quote}
+% |\protected| |\long| |\def|
+% \end{quote}
+% so it will not usually get expanded except when hit with
+% \cmd{\expandafter} or actually being executed. Note that you can't
+% use this on stuff that has to work at expansion time. This really
+% works mainly with macros that would also be suitable candidates for
+% \cmd{\DeclareRobustCommand}.
+%
+% It is also a bad idea to trace a conditional in this manner: while
+% the substitution could be made to work when being executed, it will
+% appear like an ordinary macro when being skipped, disturbing the
+% conditional nesting.
+%
+% Only macros occuring somewhere in the call sequence will get
+% tracked, other macros are not affected. The environment can
+% actually get nested, in which case the outer sequences will get
+% tracked independently from the inner sequence.
+%
+% This makes it possible to use |ExpectCallSequence| in order to
+% spoof, for example, both input consuming and output producing macros
+% without knowing the exact relationship of both.
+%
+% Apart from specifying macro calls, the call sequence specification
+% can contain special characters that also carry meaning:
+% \begin{description}
+% \item[\texttt{\string`}] If this is set in the call sequence, it
+% places the initial parsing state here. This will make it an error
+% if non-matching entries occur at the start of the sequence, which
+% otherwise is effectively enclosed with
+% \begin{quote}
+% |.{}*(|\meta{sequence}|).{}*|
+% \end{quote}
+% meaning that nonmatching entries before the first and after the
+% last matching item of the sequence are ignored by default (this
+% makes it closer to normal regexp matchers). Since the matching
+% will then start at |`|, you can put macros before that position
+% that you want to be flagged if they occur in the sequence, even
+% when they are mentioned nowhere else (macros which would be an
+% error if actually called). Also available as the more customary
+% |^| character, but that tends to behave worse in \LaTeX-aware
+% editors.
+% \item[\texttt{\string'}] This indicates the last call sequence
+% element to be matched. If any traced macros appear after this
+% point, an error will get generated. Any immediately following
+% call sequence entries will not get reached.
+% \item[|.|] A single dot indicates a wildcard: any of the tracked
+% control sequences might occur here. You still have to follow this
+% with macro arguments and a braced replacement text. Wildcards are
+% considered as a fallback when nothing else matches.
+% \item[|(|\dots|)|] Parens may be used for grouping alternatives
+% and\slash or combining items for the sake of repeating
+% specifications, of which there are three:
+% \item[|?|] If a question mark follows either a macro call, wildcard
+% call, parenthesized group, or call sequence end, the item before
+% it is optional.
+% \item[|+|] A plus sign following an item means that this item may be
+% repeated one or more times.
+% \item[|*|] An asterisk following an item means that this item may be
+% repeated zero or more times.
+% \item[\texttt{\string|}] A vertical bar separates alternatives.
+% Alternatives extend as far as possible, to the next bar, to an
+% enclosing paren group, or to the start and\slash or end of the
+% whole call sequence specification if nothing else intervenes.
+% \end{description}
+% Note that opposed to traditional regexp evaluation, no backtracking
+% is employed: at each point in the call sequence, the next match is
+% immediately chosen and a choice can (for obvious reasons) not be
+% reverted. It is the task of the user to specify a call sequence in
+% a sufficiently non-ambiguous manner that will make the call sequence
+% tracing not pick dead ends.
+% \begin{macrocode}
+\begin{qstest}{ExpectCallSequence}{ExpectCallSequence}
+ \def\e{e} \def\f{f}
+ \def\g{g} \def\h{h}
+ \begin{ExpectCallSequence}{`\e#1{%
+ \Expect\expandafter{\csname\CalledName#1\endcsname}{\e }%
+ \Expect*{\meaning#1}{macro:->e}}+\f#1{}'}
+ \e \e \e \e \f
+ \end{ExpectCallSequence}
+\end{qstest}
+% \end{macrocode}
+%
+% \subsection{Ending a standalone test file}
+% One finishes a standalone test file by calling the \LaTeX\ control
+% sequence \cmd{\quit}. This stops processing even when we did not
+% actually get into a document. We don't actually do this here since
+% there will be further tests in the full documentation file.
+% However, we will now close the log file we opened for this demonstration.
+% \begin{macrocode}
+\LogClose{lgout}
+%</test>
+% \end{macrocode}
+% \IfFileExists{qstest-qs.lgout}{%
+% And now we will show the resulting standalone log file:
+% \IndexInput{qstest-qs.lgout}}{%
+% \GenericError{(\jobname) }%
+% {`qstest-qs.lgout' is missing}
+% {Please run `qstest-qs.tex' (unpacked by `qstest.ins') through LaTeX first.}
+% {Documentation will be incomplete otherwise.}}
+%
+% We can now stop skipping if we are compiling the |dtx| file
+% standalone.
+% \begin{macrocode}
+%<*dtx>
+\fi
+%</dtx>
+% \end{macrocode}
+% \StopEventually{}
+% \section{The driver file}
+% \begin{macrocode}
+%<*driver>
+\documentclass{ltxdoc}
+\usepackage{qstest}
+\usepackage{hyperref}
+\OnlyDescription
+%<driver> \AlsoImplementation
+\begin{document}
+\GetFileInfo{qstest.sty}
+\date{\filedate}
+\title{\texttt{\filename}\\\fileinfo\\version \fileversion}
+\author{David Kastrup\thanks{\href{mailto:dak@gnu.org}
+ {David.Kastrup@QuinScape.de}, \href{http://quinscape.de}{QuinScape
+ GmbH}}}
+\maketitle
+\DocInput{qstest.dtx}
+\end{document}
+%</driver>
+% \end{macrocode}
+% \hypertarget{installer}{%
+% \section{The installer file}
+% }
+% If you did not get an installer file with the package, you can
+% recreate it by running
+% \begin{quote}
+% |tex docstrip|
+% \end{quote}
+% and specifying |dtx| as input extension, |ins| as output extension,
+% |installer| as option list and |qstest| as input file name.
+%
+% Installations with a non-e\TeX-based \LaTeX\ can try to remove the
+% |etex| option from the style, but it will impact robustness and
+% performance of the package.
+%
+% When called from a Makefile, you want to allow overwriting files,
+% and you don't want to install into the final target tree. In this
+% case, call
+% \begin{quote}
+% |tex "\let\Make=y \input makematch.ins"|
+% \end{quote}
+% \begin{macrocode}
+%<*installer>
+\input docstrip
+\ifx\Make y\askforoverwritefalse\fi
+\generate{
+ \file{qstest.drv}{\from{qstest.dtx}{driver,test,etex}}
+ \file{qstest-qs.tex}{\from{qstest.dtx}{test,etex}}
+ \file{makematch.drv}{\from{makematch.dtx}{driver,etex}}
+ \file{makematch-qs.tex}{\from{makematch.dtx}{test,etex}}
+ \ifx\Make y\else \usedir{tex/latex/qstest}\fi
+ \file{qstest.sty}{\from{qstest.dtx}{package,etex}}
+ \file{makematch.sty}{\from{makematch.dtx}{package,etex}}}
+\endbatchfile
+%</installer>
+% \end{macrocode}
+%
+% \section{The Implementation}
+% \subsection{Front matter}
+% Some data and version magic from SVN keyword expansion.
+% \begin{macrocode}
+%<*package>
+\NeedsTeXFormat{LaTeX2e}
+\def\next$Id: #1.dtx #2 #3-#4-#5 #6${%
+ \ProvidesPackage{#1}[#3/#4/#5 1.#2 QuinScape Unit Test Package]
+}
+\next
+$Id: qstest.dtx 7896 2007-02-21 14:03:26Z dkastrup $
+\RequirePackage{makematch}
+\newtoks\qst@tmptoks
+% \end{macrocode}
+%
+% \subsection{Error logging and treatment}
+% \begin{macro}{\TestErrors}
+% This defines test patterns that will throw an error when failing.
+% \begin{macrocode}
+\newcommand*{\TestErrors}{\MakeMatcher[,]\qst@errorcheck}
+\TestErrors{*, !fails}
+\newif\ifqst@error
+\def\qst@ifqst@error{\qst@errorcheck\qst@options
+ \qst@errortrue\qst@errorfalse\ifqst@error}
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{\qst@failed}
+% This is the internal macro we call for every failure. It gets the
+% test message which is expanded and then sanitized.
+% \begin{macrocode}
+\long\def\qst@error#1{%
+ \global\qst@testpassedfalse
+ \global\let\qst@lastfailure\qst@testname
+ \edef\qst@message{Failed: \qst@testname^^J#1}%
+ \@onelevel@sanitize\qst@message
+ \qst@failed}
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{\ifqst@testpassed}
+% This is used to flag failures in a test.
+% \begin{macrocode}
+\newif\ifqst@testpassed
+% \end{macrocode}
+% \end{macro}
+%
+% \subsection{Logging}
+% \label{sec:logging}
+% \begin{macro}{\LogTests}
+% This macro receives three arguments. The first is the filename
+% extension of a log file. The second is a keyword list that
+% indicates which passed tests are to be logged. The third is a
+% keyword list indicating which failed tests are to be logged.
+% \begin{macrocode}
+\newcommand{\LogTests}[3]{%
+%<etex> \ifcsname qst:log:#1\endcsname \else
+%<*!etex>
+ {\expandafter}\expandafter\ifx\csname qst:log:#1\endcsname
+ \@undefined
+%</!etex>
+ \expandafter\newwrite\csname qst:log:#1\endcsname
+ \qst@gpush\qst@passed{\qst@logentry+{#1}}%
+ \qst@gpush\qst@failed{\qst@logentry-{#1}}%
+ \global\expandafter\let\csname qst:+log:#1\endcsname\qst@matchnever
+ \global\expandafter\let\csname qst:-log:#1\endcsname\qst@matchnever
+ \fi
+ \expandafter\ifx \csname qst:+log:#1\endcsname \qst@matchnever
+ \PackageInfo{qstest}{Logging on: \jobname.#1}%
+ \ifnum\csname qst:log:#1\endcsname>\m@ne
+ \immediate\openout\csname qst:log:#1\endcsname\jobname.#1\relax
+ \fi
+ \fi
+ \MakeMatcher[,]\qst@tmp{#2}%
+ \global\expandafter\let\csname qst:+log:#1\endcsname\qst@tmp
+ \MakeMatcher[,]\qst@tmp{#3}%
+ \global\expandafter\let\csname qst:-log:#1\endcsname\qst@tmp
+}
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{\qst@gpush}
+% \begin{macrocode}
+%<*etex>
+\long\def\qst@gpush#1#2{\xdef#1{\unexpanded{#2}%
+ \unexpanded\expandafter{#1}}}
+%</etex>
+%<*!etex>
+\long\def\qst@gpush#1#2{\qst@tmptoks{#2}%
+ \qst@tmptoks\expandafter{\the\expandafter\qst@tmptoks#1}%
+ \xdef#1{\the\qst@tmptoks}}
+%</!etex>
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\qst@logentry}
+% \begin{macrocode}
+\def\qst@logentry#1#2{\qst@maybelog#1{#2}{%
+ \immediate\write\csname qst:log:#2\endcsname{\qst@message}}}
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{\qst@maybelog}
+% \begin{macrocode}
+\def\qst@maybelog#1#2#3{\csname qst:#1log:#2\endcsname\qst@options
+ {#3}{}}
+% \end{macrocode}
+% \end{macro}
+% If the user specifies |log| as the extension, we don't want to
+% overwrite the log file. Instead we convert this to package warnings
+% and infos.
+% \begin{macrocode}
+\expandafter\let\csname qst:log:log\endcsname\m@ne
+\global\expandafter\let\csname qst:+log:log\endcsname\qst@matchalways
+\global\expandafter\let\csname qst:-log:log\endcsname\qst@matchalways
+\def\qst@passed{\qst@maybelog+{log}%
+ {\PackageInfo{qstest}{\qst@message}}}
+\def\qst@failed{\ifqst@error
+ \PackageError{qstest}{\qst@message}{}%
+ \else
+ \qst@maybelog-{log}{\PackageWarning{qstest}{\qst@message}}%
+ \fi}
+% \end{macrocode}
+% \begin{macro}{\LogClose}
+% This closes the specified log file again. This is needed if the
+% log file gets processed during the \TeX\ run, like with verbatim
+% input or by running a |\write18| process on it. It is possible to
+% reopen the file later. Specifying |log| will not actually close
+% the log file, but just stop logging.
+% \begin{macrocode}
+\newcommand*\LogClose[1]{%
+ \expandafter\ifx \csname qst:+log:#1\endcsname\qst@matchnever
+ \else
+ \PackageInfo{qstest}{Logging off: \jobname.#1}%
+ \ifnum\csname qst:log:#1\endcsname>\m@ne
+ \immediate\closeout\csname qst:log:#1\endcsname
+ \fi
+ \global\expandafter\let\csname qst:+log:#1\endcsname\qst@matchnever
+ \global\expandafter\let\csname qst:-log:#1\endcsname\qst@matchnever
+ \fi
+}
+%</package>
+%<*test>
+\IncludeTests{*}
+\makeatletter
+\begin{qstest}{\LogClose}{}
+\begin{ExpectCallSequence}{%
+ `\PackageInfo#1#2#3{\Expect[##1]{#2}{qstest}%
+ \Expect[##2]{#3}{Logging off: \jobname.log}%
+ #1{#2}{#3}}'}
+ \LogClose{log}
+\end{ExpectCallSequence}
+\end{qstest}
+\begin{qstest}{\LogTests}{}
+\begin{ExpectCallSequence}{%
+ \PackageInfo#1#2#3{\Expect[##1]{#2}{qstest}%
+ \Expect[##2]{#3}{Logging on: \jobname.log}%
+ #1{#2}{#3}}}
+ \LogTests{log}{*}{*}
+\end{ExpectCallSequence}
+\end{qstest}
+%</test>
+%<*package>
+% \end{macrocode}
+% \end{macro}
+%
+% \subsection{The test code itself}
+%
+% \begin{macro}{\IncludeTests}
+% This defines the test case patterns to be included. Keyword
+% specifications and patterns are `sanitized': macros are not
+% expanded, and everything but spaces is converted to catcode~12
+% characters. At the start of a pattern or a keyword, spaces get
+% ignored. Spaces inside of patterns or keywords should work as
+% expected, however.
+% \begin{macrocode}
+\def\IncludeTests{\MakeMatcher[,]\qst@includecheck}
+\let\qst@includecheck\qst@matchalways
+% \end{macrocode}
+% \end{macro}
+% \begin{environment}{qstest}
+% This is the environment for defining a test. |#1| is the name of
+% the test for the log file. The name is sanitized, so control
+% sequence names can be used verbatim. |#2| is a sequence of
+% options that may be matched by the patterns from
+% \cmd{\IncludeTests}. If there is no match the environment is
+% skipped like a comment environment.
+% \begin{macrocode}
+\RequirePackage{verbatim}
+\newenvironment{qstest}[2]{%
+% \end{macrocode}
+% We sanitize test name and options. In case people nest tests, we
+% don't want to announce an outer test passed when a single inner test
+% has passed. So we don't set \cmd{\qst@testpassedtrue} globally.
+% While a mixture of local and global assignments should in general be
+% avoided as it leads to ``savestack buildup'', this can't actually
+% happen here since the local assignment is done only once at the
+% start of a group.
+% \begin{macrocode}
+ \qst@testpassedtrue
+%<etex> \edef\qst@testname{\detokenize{#1}}%
+%<*!etex>
+ \qst@tmptoks{#1}%
+ \edef\qst@testname{\the\qst@tmptoks}%
+ \@onelevel@sanitize\qst@testname
+%</!etex>
+ \MakeMatchTarget[,]\qst@options{#2}%
+ \let\ifqst@error\qst@ifqst@error
+ \qst@includecheck\qst@options\ignorespaces{%
+ \let\endqstest\endcomment}}%
+ {\ifqst@testpassed
+ \edef\qst@message{Passed: \qst@testname}%
+ \qst@passed
+ \else
+ \ifx\qst@testname\qst@lastfailure
+ \else
+ \edef\qst@message{Failed: \qst@testname}%
+ \qst@failed
+ \fi
+ \fi}
+% \end{macrocode}
+% \end{environment}
+% \begin{macro}{\qst@testname}
+% Let us set up a default test name in case any tests occur outside
+% of a |qstest| environment.
+% \begin{macrocode}
+\def\qst@testname{unspecified}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\Expect}
+% This macro basically receives two brace-delimited
+% arguments\footnote{Actually, the arguments are collected with a
+% token register assignment. This gives several options for
+% specifying them, including giving a token register without
+% braces around it.} and checks that they are equal after being
+% passed through \cmd{\def} and sanitized.
+% If you precede one of those arguments
+% with |*| it gets passed through through \cmd{\edef} instead of
+% \cmd{\def}. There may also be additional tokens like
+% |\expandafter| before the opening brace.
+% \begin{macrocode}
+\newcommand\Expect[1][]{%
+%<etex> \edef\qst@tmpc{\unexpanded{#1}}%
+%<!etex> \qst@tmptoks{#1}%
+%<!etex> \edef\qst@tmpc{\the\qst@tmptoks}%
+ \qst@expectarg\qst@defaultvalue\qst@expecttwo}
+\def\qst@expectarg#1#2{%
+ \@ifstar{\qst@expectargii\edef#1#2}{\qst@expectargii\def#1#2}}
+\def\qst@expectargii#1#2#3{\long\def\qst@tmp##1{%
+ #1#2####1####2####3####4####5####6####7####8####9{##1}%
+ \@onelevel@sanitize#2#3}%
+ \afterassignment\qst@expectargiii
+ \qst@tmptoks=}
+\def\qst@expectargiii{\expandafter
+ \qst@tmp\expandafter{\the\qst@tmptoks}}
+\def\qst@expecttwo{%
+ \ifx\qst@tmpc\@empty
+ \edef\qst@tmpc{\the\qst@tmptoks}%
+ \fi
+ \qst@expectarg\qst@tmpb\qst@expectfinish}
+\def\qst@expectfinish{%
+ \ifx\qst@defaultvalue\qst@tmpb
+ \else
+%<!etex> \qst@tmptoks\expandafter{\qst@tmpc}%
+ \qst@error{
+%<!etex> \string\Expect: \the\qst@tmptoks^^J
+%<etex> \string\Expect: \unexpanded\expandafter{\qst@tmpc}^^J
+ <\qst@tmpb^^J
+ >\qst@defaultvalue}%
+ \fi}
+% \end{macrocode}
+% \end{macro}
+%
+% \subsection{Dimension ranges}
+%
+% \begin{macro}{\InRange}
+% This is used as a second argument for \cmd{\Expect}. It will
+% make \cmd{\Expect} succeed if the first argument of \cmd{\Expect}
+% happens to lie in the closed range defined by the two arguments of
+% \cmd{\InRange}.
+% \begin{macrocode}
+\def\InRange#1#2{%
+ \ifcase
+ \ifdim\qst@defaultvalue<#1\@ne\fi
+ \ifdim\qst@defaultvalue>#2\@ne\fi
+ \tw@
+ \or
+ \qst@afterfi{{in [#1..#2]}}%
+ \or
+ \qst@afterfi{\expandafter{\qst@defaultvalue}}%
+ \fi}
+% \end{macrocode}
+% \begin{macro}{\qst@afterfi}
+% This is just a helper macro cleaning up a following |\fi|.
+% \begin{macrocode}
+\def\qst@afterfi#1#2\fi{\fi#1}
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \begin{macro}{\NearTo}
+% This is a pseudovalue like the last: it returns
+% \cmd{\qst@defaultvalue} if the specified value |#1| is close to
+% the given default value. There is an optional argument specifying
+% the closeness which defaults to |0.05pt|. It requires e\TeX\
+% since the arithmetic can't be done otherwise.
+% \begin{macrocode}
+%<*etex>
+\newcommand*\NearTo[1]{%
+ \ifx[#1\expandafter\qst@nearto\expandafter[%]]
+ \else \qst@afterfi{\qst@nearto[0.05pt]{#1}}%
+ \fi}
+\def\qst@nearto[#1]#2{%
+ \ifcase
+ \ifdim\qst@defaultvalue>\dimexpr#2+(#1)\relax \@ne\fi
+ \ifdim\qst@defaultvalue<\dimexpr#2-(#1)\relax \@ne\fi
+ \tw@
+ \or
+ \qst@afterfi{{near[#1] to #2}}%
+ \or
+ \qst@afterfi{\expandafter{\qst@defaultvalue}}%
+ \fi}
+%</etex>
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\ExpectIfThen}
+% This is used for evaluating a condition as provided by the
+% |ifthen| package. See its docs for the kind of condition that is
+% possible there.
+% \begin{macrocode}
+\newcommand\ExpectIfThen[1]{%
+%<!etex> \qst@tmptoks{#1}%
+ \ifthenelse{#1}{}{%
+ \qst@error{
+%<etex> \string\ExpectIfThen: \unexpanded{#1}%
+%<!etex> \string\ExpectIfThen: \the\qst@tmptoks
+ }}}
+% \end{macrocode}
+% \end{macro}
+%
+%
+% \begin{environment}{ExpectCallSequence}
+% This tells the test system that macros are going to be called in a
+% certain order and with particular types of arguments.
+%
+% The environment gets as an argument the expected call sequence.
+% The call sequence contains entries that look like a macro
+% definition: starting with the macro name followed with an argument
+% list ended with |{| ^^A}%
+% following it, followed by substitution code executed in place of
+% the macro. The argument list actually starts with an implicit
+% argument of |#1| which contains a macro with the original value of
+% the control sequence, so the explicitly specified argument list
+% starts with the argument called~|#2|.
+%
+% The substitution function is basically defined using
+% \begin{quote}
+% |\protected| |\long| |\def|
+% \end{quote}
+% so it will not usually get expanded except when hit with
+% \cmd{\expandafter} or actually being executed. Note that you
+% can't use this on stuff that has to work at expansion time. This
+% really works mainly with macros that would also be suitable
+% candidates for \cmd{\DeclareRobustCommand}.
+%
+% It is also a bad idea to trace a conditional in this manner: while
+% the substitution should actually work when being executed, it will
+% appear like an ordinary macro when being skipped, disturbing the
+% conditional nesting.
+% \begin{macro}{\qst@advance}
+% We maintain a lot of counters and often need them expanded.
+% Instead of allocating counter registers for them, we keep some of
+% them in macros. Advancing such a macro is done using
+% \cmd{\qst@advance}. Since we may do this in the middle of call
+% tracing, we allocate our own temporary counter in the non-e\TeX\
+% case.
+% \begin{macrocode}
+%<etex> \def\qst@advance#1{\edef#1{\number\numexpr(#1)+1}}
+%<*!etex>
+\newcount\qst@tmpcnt
+\def\qst@advance#1{%
+ \qst@tmpcnt#1%
+ \advance\qst@tmpcnt\@ne
+ \edef#1{\number\qst@tmpcnt}}
+%</!etex>
+% \end{macrocode}
+% \end{macro}
+%
+% \subsection{The regexp state machine}
+% The whole idea of call sequence checking is to match the calls
+% happening throughout controlled macros to a sort of attributed
+% regular expression. To facilitate that, we replace the macros by
+% some fixed code exercising a state machine. For each state of the
+% state machine, we define a state macro (taking one argument) that
+% contains tokens to be matched followed by a corresponding action
+% sequence in braces. The argument that this state macro takes is the
+% control sequence in question itself: by using |#1| as the matching
+% token, one can ensure a match at some place. This is used for
+% implementing wildcards.
+%
+% An action sequence may be of three kinds:
+% \begin{description}
+% \item[explicit match] this matches a given token explicitly and
+% causes the state to change to a defined new state, and causes an
+% action to be called that has been user specified for this state transition.
+% \item[wildcard match] instead of immediately making a state transition,
+% the transition is remembered in case there is not explicit match:
+% explicit matches have priority.
+% \item[empty transition] this inserts the transitions of a different
+% state recursively into the matching process. Every state inserted
+% in this manner is recorded so as to not insert it again. This is
+% not associated with a transition.
+% \end{description}
+%
+% \begin{macro}{\qst@csmaketransition}
+% This will perform an actual transition when called as an action
+% code. It receives in |#1| the state to move to, in |#2| the
+% transition number to use for the replacement code, in |#3| the
+% code sequence to be replaced. Everything until the terminating
+% |.| of the expanded transition table can be thrown away.
+% \begin{macrocode}
+\long\def\qst@csmaketransition#1#2#3#4.{%
+ \qst@cssetstate{#1}%
+ \expandafter
+ \endgroup
+ \csname qst@cstrans:#2\expandafter\endcsname
+ \csname qst@cssaved\romannumeral\qst@csscope>\string#3\endcsname}
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{\CalledName}
+% This is used for getting back the original name from the saved
+% sequence name as text.
+% \begin{macrocode}
+\def\CalledName#1{\expandafter\expandafter\expandafter\@gobble
+ \expandafter\strip@prefix\string#1}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\qst@csstate}
+% \begin{macrocode}
+\def\qst@csstate{\csname qst@csstate\romannumeral
+ \qst@csscope\endcsname}
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{qst@cssetstate}
+% \begin{macrocode}
+\def\qst@cssetstate#1{%
+ \expandafter\expandafter\expandafter\xdef\qst@csstate{#1}}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\qst@csmakewildcard}
+% This matches a wildcard. Since those are considered last, it just
+% redefines \cmd{\qst@csnomatch} to a different default behavior when
+% nothing matched explicitly. It also removes the replicated
+% control sequence name in |#3| and restarts the matching process.
+% Wildcards don't match the end of a match.
+% \begin{macrocode}
+\long\def\qst@csmakewildcard#1#2#3{\ifx#3\endExpectCallSequence
+ \else
+ \def\qst@csnomatch{\qst@csmaketransition{#1}{#2}}%
+ \fi
+ \qst@tmp}
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{\qst@cscheckempty}
+% This first checks whether the current state has already been
+% considered (entering it into \cmd{\qst@lockout} if it has not),
+% then expands its table here and resumes the search.
+% \begin{macrocode}
+\long\def\qst@cscheckempty#1#2{%
+ \ifcase\qst@cslockout{#1}\z@
+ \expandafter\def\expandafter\qst@cslockout
+ \expandafter##\expandafter1\expandafter{%
+ \qst@cslockout{##1}\ifnum##1=#1\@ne\fi}%
+ \expandafter\expandafter\expandafter\qst@tmp
+ \csname qst@csstate:#1\expandafter\endcsname\expandafter#2%
+ \or \expandafter\qst@tmp
+ \fi}
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{\qst@csnext}
+% This does the work of finding a transition from the current state
+% given a specified lookahead token. It does this via defining
+% \cmd{\qst@tmp} to a macro picking out the given token from the
+% following string, taking the corresponding sequence to be called
+% for it and calling it with the token as an argument.
+%
+% The lockout sequence in \cmd{\qst@cslockout} is preloaded with one
+% comparison locking out the current state.
+% \begin{macrocode}
+\long\def\qst@csnext#1#2{%
+ \begingroup
+ \edef\qst@csscope{#1}%
+ \let\qst@csnomatch=\qst@csunexpected
+ \def\qst@cslockout##1{\ifnum\qst@csstate=##1\@ne\fi}%
+ \long\def\qst@tmp##1#2##2{##2#2}%
+ \expandafter\expandafter\expandafter\qst@tmp
+ \csname qst@csstate:\qst@csstate\endcsname#2%
+ #2{\qst@csnomatch}.}
+%<*!etex>
+\let\qst@csnextii\qst@csnext
+\def\qst@csnext{\ifx\protect\@typeset@protect
+ \expandafter\qst@csnextii
+ \else \expandafter \@firstoftwo \expandafter \protect
+ \fi}
+%</!etex>
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\qst@csunexpected}
+% This is the default if we have had no match:
+% \begin{macrocode}
+\long\def\qst@csunexpected#1#2.{%
+ \qst@error{
+ ExpectCallSequence: \string#1}%
+ \expandafter\expandafter\expandafter
+ \endgroup
+ \qst@cssavedcs#1%
+}
+\long\def\qst@cssavedcs#1{%
+ \csname qst@cssaved\romannumeral\qst@csscope>\string#1\endcsname}
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{\qst@csaddstate}
+% This does the actual work of adding something to the state table.
+% Uses \cmd{\def}.
+% \begin{macrocode}
+\long\def\qst@csaddstate#1#2{%
+%<etex> \ifcsname qst@csstate:#1\endcsname \else
+%<!etex> \expandafter\ifx\csname qst@csstate:#1\endcsname\relax
+ \expandafter\let\csname qst@csstate:#1\endcsname \@gobble
+ \fi
+ \long\expandafter
+ \def\csname qst@csstate:#1\expandafter\endcsname
+ \expandafter##\expandafter1\expandafter{\romannumeral
+ \expandafter\expandafter\expandafter\z@
+ \csname qst@csstate:#1\endcsname{##1}#2}}
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{\qst@csaddempty}
+% \begin{macrocode}
+\def\qst@csaddempty#1#2{%
+ \expandafter\qst@csaddstate\expandafter{\number#1\expandafter}%
+ \expandafter{\expandafter##\expandafter1\expandafter{\expandafter
+ \qst@cscheckempty\expandafter{\number#2}}}}
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{\qst@csallocstate}
+% \begin{macro}{\qst@csalloctrans}
+% Those maintain the currently available next state, and the
+% currently available next transition.
+% \begin{macrocode}
+\def\qst@csallocstate{0}
+\def\qst@csalloctrans{0}
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \begin{macro}{\qst@csscope}
+% When we are nesting |ExpectCallSequence| environments,
+% this keeps track of the scope we are in.
+% \begin{macrocode}
+\def\qst@csscope{0}
+% \end{macrocode}
+% \end{macro}
+% \begin{macrocode}
+\newenvironment{ExpectCallSequence}[1]
+{%
+ \qst@advance\qst@csscope
+ \qst@cssetstate{\qst@csallocstate}%
+ \let\qst@csgroupstate\qst@csallocstate
+ \qst@advance\qst@csgroupstate
+ \qst@advance\qst@csgroupstate
+ \let\qst@csstack\@empty
+ \qst@csparse.{}*(#1){...}%
+}{%
+ \def\qst@cssavedcs{\@gobble}%
+ \expandafter\qst@csnext\expandafter\qst@csscope
+ \csname end {ExpectCallSequence}\endcsname}
+% \end{macrocode}
+% \end{environment}
+% \begin{macro}{\qst@csparse}
+% This is doing the basic parsing. We are having some problems
+% stopping non-e\TeX\ from hitting on the string space. This
+% approach will not work with implicit characters like
+% \cmd{\bgroup}, but then there are not too many of those around,
+% and so the impact on string space should be tolerable.
+% \begin{macrocode}
+\long\def\qst@csparse#1{%
+%<etex> \ifcsname qst@csparse:\string#1\endcsname
+%<*!etex>
+ \ifcase
+ \ifcat\relax\noexpand#1%
+ \else
+ \expandafter \ifx \csname qst@csparse:\string#1\endcsname \relax
+ \else @ne \fi
+ \fi \m@ne
+ \or
+%</!etex>
+ \csname qst@csparse:\string#1\expandafter\expandafter\expandafter
+ \endcsname
+ \expandafter\@gobble
+ \else
+ \expandafter\qst@csparsedefault
+ \fi{#1}}
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{\qst@csparse:...}
+% This is what we do at the end of the patterns: we just jump to
+% state~0. At state~0 we add a wildcard restoring any remaining
+% macro redirection when it occurs, and let the end of the call
+% sequence be allowed there to move to state~1. Oh, and we actually
+% call the macro then.
+% \begin{macrocode}
+\expandafter\def\csname qst@cstrans:0\endcsname
+ #1{\expandafter\let\csname\CalledName#1\endcsname= #1%
+ \let#1=\@undefined
+ \csname\CalledName#1\endcsname}
+\qst@csaddstate0{#1{\qst@csmakewildcard00}}
+\qst@csaddempty{0}{1}
+\expandafter\qst@csaddstate\expandafter1\expandafter{%
+ \csname end {ExpectCallSequence}\endcsname{\qst@csmaketransition21}}
+\expandafter\let\csname qst@cstrans:1\endcsname\@gobble
+
+\def\qst@csalloctrans{2}
+\def\qst@csallocstate{3}
+
+\expandafter\let\csname end {ExpectCallSequence}\endcsname
+ \endExpectCallSequence
+
+\expandafter\def\csname qst@csparse:...\endcsname{%
+ \ifx\qst@csstack\@empty
+ \else
+ \PackageError{qstest}{Unmatched `(' in call sequence %)
+ specification}{You need to fix this}%
+ \loop
+ \qst@csstack
+ \ifx\qst@csstack\@empty
+ \else
+ \repeat
+ \fi
+ \qst@csaddempty{\qst@csallocstate}{0}%
+ \qst@advance\qst@csallocstate
+ \ignorespaces}
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{\qst@csparsedefault}
+% Ok, here is the default action. We resolve any pending state to
+% the next available state and set \cmd{\qst@cslaststate} accordingly.
+% Then we add a pending transition from the last state to the next
+% state. The saved definition is not overwritten if the macro
+% itself already has the proper setting. The purpose of that is to
+% be able to preserve undefined macros.
+% \begin{macrocode}
+\long\def\qst@csparsedefault#1{%
+%<*etex>
+ \ifcsname qst@cssaved\romannumeral\qst@csscope>\string#1\endcsname
+ \else \protected
+%</etex>
+%<*!etex>
+ {\expandafter}%
+ \expandafter\ifx\csname qst@cssaved\romannumeral\qst@csscope>%
+ \string#1\endcsname \@undefined
+%</!etex>
+ \edef\qst@tmp{\noexpand\qst@csnext \qst@csscope \noexpand#1}%
+ \ifx#1\qst@tmp
+ \else
+ \expandafter\let
+ \csname qst@cssaved\romannumeral\qst@csscope>\string#1\endcsname
+ = #1%
+ \let#1\qst@tmp
+ \fi
+ \fi
+ \qst@csparsetransition{#1}\qst@csmaketransition}
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{\qst@csparsetransition}
+% Ok, here we read in the code for an actual transition. This will
+% create a new definition using \cmd{\def}.
+% \begin{macrocode}
+\long\def\qst@csparsetransition#1#2{%
+ \let\qst@cslaststate\qst@csallocstate
+ \qst@advance\qst@csallocstate
+ \long\edef\qst@tmp##1##2{%
+ \noexpand\qst@csaddstate{\qst@cslaststate}{%
+ ##1{%
+ ##2{\qst@csallocstate}%
+ {\qst@csalloctrans}}}}%
+ \qst@tmp{#1}{#2}%
+ \expandafter\qst@advance\expandafter\qst@csalloctrans
+ \expandafter\afterassignment\expandafter\qst@csparse
+ \expandafter\long\expandafter\def
+ \csname qst@cstrans:\qst@csalloctrans\endcsname}
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{\qst@csparse:.}
+% \begin{macrocode}
+\expandafter\def\csname qst@csparse:.\endcsname{%
+ \qst@csparsetransition{##1}\qst@csmakewildcard}
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{\qst@csparse:?}
+% This turns the last element into an optional element.
+% \begin{macrocode}
+\expandafter\def\csname qst@csparse:?\endcsname{%
+ \qst@csensurelaststate?%
+ \qst@csaddempty\qst@cslaststate\qst@csallocstate
+ \let\qst@cslaststate\@undefined
+ \qst@csparse}
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{\qst@csensurelaststate}
+% This checks that we have a valid last state to hook onto. There
+% is no really useful error recovery if we haven't.
+% \begin{macrocode}
+\def\qst@csensurelaststate#1{\ifx\qst@cslaststate\@undefined
+ \PackageError{qstest}{Unexpected `#1' in call sequence}{%
+ Expect chaos to ensue}%
+ \def\qst@cslaststate{0}%
+ \fi}
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{\qst@csparse:*}
+% This would need to make the pending state identical with the
+% previous state while leaving all of it pending. But we can't
+% retroactively make previous states pending again, so we instead
+% make do with adding an empty transition from the previous state to
+% the next pending one.
+% \begin{macrocode}
+\expandafter\def\csname qst@csparse:*\endcsname{%
+ \qst@csensurelaststate*%
+ \qst@csaddempty\qst@csallocstate\qst@cslaststate
+ \qst@advance\qst@csallocstate
+ \qst@csaddempty\qst@cslaststate\qst@csallocstate
+ \let\qst@cslaststate\@undefined
+ \qst@csparse}
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{\qst@csparse:+}
+% This is somewhat similar. Note that we have to add an empty
+% transition at the end (like with |*| previously) to make sure that
+% something like |\a{}+\b{}+| does not match |\a\b\a|.
+% \begin{macrocode}
+\expandafter\def\csname qst@csparse:+\endcsname{%
+ \qst@csensurelaststate+%
+ \qst@csaddempty\qst@csallocstate\qst@cslaststate
+ \let\qst@cslaststate\qst@csallocstate
+ \qst@advance\qst@csallocstate
+ \qst@csaddempty\qst@cslaststate\qst@csallocstate
+ \let\qst@cslaststate\@undefined
+ \qst@csparse}
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{\qst@csparse:(}^^A%{)}
+% Ok, now we are getting into grouping. This adds a bit of
+% complexity, but it is actually rather containable (took a lot of
+% work, though).
+% \begin{macrocode}
+\expandafter\def\csname qst@csparse:(\endcsname{%
+%<!etex> \qst@tmptoks\expandafter{\qst@csstack}%
+ \edef\qst@csstack{\def\noexpand\qst@csstack{%
+%<etex> \unexpanded\expandafter{\qst@csstack}%
+%<!etex> \the\qst@tmptoks
+ }%
+ \def\noexpand\qst@csgroupstate{\qst@csgroupstate}}%
+ \let\qst@csgroupstate\qst@csallocstate
+ \qst@advance\qst@csallocstate
+ \qst@csaddempty\qst@csgroupstate\qst@csallocstate
+ \qst@csparse}
+% \end{macrocode}
+% \end{macro}
+% \DeleteShortVerb\|
+% \begin{macro}{\qst@csparse:|}
+% \begin{macrocode}
+\expandafter\def\csname qst@csparse:|\endcsname{%
+ \let\qst@cslaststate\qst@csallocstate
+%<!etex> \qst@tmptoks\expandafter{\qst@csstack}%
+%<!etex> \edef\qst@csstack{\the\qst@csstack
+%<etex> \edef\qst@csstack{\unexpanded\expandafter{\qst@csstack}%
+ \noexpand\qst@csaddempty{\qst@cslaststate}%
+ \noexpand\qst@csallocstate}%
+ \qst@advance\qst@csallocstate
+ \qst@csaddempty\qst@csgroupstate\qst@csallocstate
+ \let\qst@cslaststate\@undefined
+ \qst@csparse}
+% \end{macrocode}
+% \end{macro}
+% \MakeShortVerb\|
+% \begin{macro}{\qst@csparse:)}^^A%{(}
+% \begin{macrocode}
+\expandafter\def\csname qst@csparse:)\endcsname{%
+ \let\qst@cslaststate\qst@csgroupstate
+ \ifx\qst@csstack\@empty
+ \PackageError{qstest}{Unmatched `)' in call sequence
+ specification}{You need to fix this}%
+ \fi
+ \qst@csstack
+ \qst@csparse
+}
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{\qst@csparse:`}
+% We don't check whether this is actually the first encounter with
+% |`|: we just reset the state machine to come here.
+% \begin{macrocode}
+\expandafter\def\csname qst@csparse:`\endcsname{%
+ \qst@cssetstate{\qst@csallocstate}%
+ \let\qst@cslaststate\@undefined
+ \qst@csparse}
+\expandafter\let\csname qst@csparse:^\expandafter\endcsname
+ \csname qst@csparse:`\endcsname
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{\qst@csparse:'}
+% \begin{macrocode}
+\expandafter\def\csname qst@csparse:'\endcsname{%
+ \qst@csaddempty{\qst@csallocstate}{1}%
+ \let\qst@cslaststate\qst@csallocstate
+ \qst@advance\qst@csallocstate
+ \qst@csparse}
+\expandafter\let\csname qst@csparse:$%$
+\expandafter\endcsname\csname qst@csparse:'\endcsname
+% \end{macrocode}
+% \end{macro}
+% Ok, let us test the state machine. First define two macros that we
+% are going to replace:
+% \begin{macrocode}
+%</package>
+%<*test>
+\begin{qstest}{ExpectCallSequence state machine}%
+ {ExpectCallSequence,internal}
+ \def\foo#1#2#3{\relax\relax}
+ \let\fie\relax
+% \end{macrocode}
+% The free state table starts at 3, the free transitions at 2.
+% \begin{macrocode}
+ \Expect*{\qst@csallocstate}{3}
+ \Expect*{\qst@csalloctrans}{2}
+% \end{macrocode}
+% Now we have an implicit start into the call sequence that is |.{}*(|
+% and thus takes away 3 states and one transition. The call sequence
+% starts off with one ignored entry and then the real state, so we
+% expect to be at state~7 initially.
+% \begin{macrocode}
+ \begin{ExpectCallSequence}{\fie{}%
+ `\foo#1#2#3{#2\bar{#3}}(\bar#1#2{#2}|.#1{})+%
+ \foo#1{}}
+ \Expect*{\qst@csstate}{7}
+ \Expect*{\qst@csallocstate}{15}
+% \end{macrocode}
+% The state transitions actually happen before the respective code is
+% called, so we can actually continue in the matching sequence while
+% still working off the replacement for a macro:
+% \begin{macrocode}
+ \foo{\Expect*{\qst@csstate}{8}}{\Expect*{\qst@csstate}{10}}
+ \Expect*{\qst@csstate}{10}
+% \end{macrocode}
+% \cmd{\fie} will match the wildcard. Note that we arrive at a
+% different target state than previously. While this is
+% counterintuively, we have to be aware that an empty transition from
+% state~10 to state~12 exists, so both are actually the same state in
+% reality.
+% \begin{macrocode}
+ \fie
+ \Expect*{\qst@csstate}{12}
+% \end{macrocode}
+% Now \cmd{\foo} kicks us out of the matching. Again, state~14 looks
+% strange, but it has an empty transition to state~0, the ``match
+% everything until we are finished'' state.
+% \begin{macrocode}
+ \foo
+ \Expect*{\qst@csstate}{14}
+% \end{macrocode}
+% So we actually make use of this state and call \cmd{\fie} after
+% which it will have reverted to its original meaning:
+% \begin{macrocode}
+ \fie
+ \Expect*{\qst@csstate}{0}
+ \Expect*{\meaning\fie}*{\meaning\relax}
+% \end{macrocode}
+% It is sort of amusing that the above assertion will fail if we write
+% just
+% \begin{quote}
+% |\Expect*{\meaning\fie}{\relax}|
+% \end{quote}
+% since the meaning of \cmd{\relax} is not ended with a blank, while
+% the printed string of its name does end with one. We check that use
+% of \cmd{\foo} lets us revert its meaning as well.
+% \begin{macrocode}
+ \foo\junk\junk\junk
+ \Expect*{\qst@csstate}{0}
+ \Expect*{\meaning\foo}{macro:#1#2#3->\relax \relax}
+ \end{ExpectCallSequence}
+\end{qstest}
+%</test>
+%<*package>
+% \end{macrocode}
+%
+% \subsection{Saved results}
+%
+% The purpose of saved results is to be able to check that the value
+% has remained the same over passes. Results are given a unique label
+% name and are written to an auxiliary file where they can be read in
+% for the sake of comparison. One can use the normal |.aux| file for
+% this purpose, but it might be preferable to use a separate dedicated
+% file. That way it is possible to input a versioned \emph{copy} of
+% this file and have a fixed point of reference rather than the last
+% run.
+%
+% While the |.aux| file is read in automatically at the beginning of
+% the document, this does not happen with explicitly named files. You
+% have to read them in yourself, preferably using
+% \begin{quote}
+% |\InputIfFileExists|\marg{filename}|{}{}|
+% \end{quote}
+% so that no error is thrown when the file does not yet exist.
+%
+% \begin{macro}{\SaveValueFile}
+% This specifies which file name to use for saving results. If this
+% is specified, a special file is opened. If one does not specify
+% this, instead the standard |.aux| file is used instead.
+% \begin{macrocode}
+\newcommand*\SaveValueFile[1]{%
+ \ifnum\qst@savefile=\@auxout
+ \newwrite\qst@savefile
+ \else
+ \immediate\closeout\qst@savefile
+ \fi
+ \immediate\openout\qst@savefile #1\relax}
+\def\qst@savefile{\@auxout}
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{\CloseValueFile}
+% This is not likely to be used except for testing this package
+% itself: it closes the given file so that it may be read in again
+% immediately.
+% \begin{macrocode}
+\newcommand*\CloseValueFile{%
+ \ifnum\qst@savefile=\@auxout
+ \else
+ \immediate\closeout\qst@savefile
+ \fi}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\SaveValue}
+% This gets the label name as first argument (which gets sanitized
+% more or less, depending on whether you use e\TeX\ or not).
+%
+% The second argument is the same kind of argument as \cmd{\Expect}
+% expects.
+% \begin{macrocode}
+\newcommand\SaveValue[1]{%
+%<etex> \edef\qst@tmpc{\detokenize{#1}}%
+%<!etex> \edef\qst@tmpc{\string#1}%
+ \ifnum\qst@savefile=\@auxout
+ \ifx\@onlypreamble\AtBeginDocument
+ \else
+ \PackageError{qstest}{You need to specify \string\SaveValueFile^^J
+ for test files without document.}{I can't use
+ `\string\SaveValue' before either `\string\begin%
+ {document}'^^J
+ or `\string\SaveValueFile'}%
+ \fi
+ \fi
+ \qst@expectarg\qst@defaultvalue\qst@saveval}
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{\qst@saveval}
+% This is tricky: we don't want to turn either |^^M| or |^^J| into
+% each other. But at least \TeX live will write out |^^J| as a
+% single character (causing a line break) and only |^^M| will
+% actually get escaped. It would be principally ok to just crank
+% out line feeds unmodified, if only \TeX\ would not strip spaces at
+% the end of a line. So we go through the string we want to put
+% out, and change the single character |^^J| manually into the three
+% characters |^^J| after which \TeX\ will preserve spaces.
+% \begin{macrocode}
+\def\qst@saveval{%
+ {\immediate\write\qst@savefile{\string\InternalSetValue^^J%
+ \expandafter\qst@cleanlf\qst@tmpc\qst@endcleanlf^^J%
+ \expandafter\qst@cleanlf\qst@defaultvalue\qst@endcleanlf^^J%
+ \string\EndInternalSetValue^^J}}}
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{\qst@cleanlf}
+% \begin{macro}{\qst@endcleanlf}
+% \begin{macrocode}
+\def\qst@cleanlf#1^^J{#1^%
+ ^J\qst@cleanlf}
+\def\qst@endcleanlf^%
+ ^J\qst@cleanlf{:^^J}
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \begin{macro}{\InternalSetValue}
+% The chosen catcodes are picked in order to have |^^xx| escapes
+% still work out (\TeX\ can't be kept from using them occasionally).
+% Of course, in case |^^| sequences have indeed been present in the
+% original macro (like in \cmd{\qst@cleanlf} above), we get
+% flummoxed. The spaces we read in here should be the same that
+% occur during sanitization. All of this is a bit of compromise.
+% Newlines separate keys and values.
+% \begin{macrocode}
+\newcommand*\InternalSetValue{\begingroup
+ \let\do\@makeother\dospecials
+ \endlinechar`\^^J
+ \catcode`\^7
+ \qst@setsavedii}
+\begingroup
+\catcode`\!=12
+\lccode`\!=`\\
+\lowercase{\endgroup
+ \def\qst@setsavedii#1:^^J#2:^^J!}EndInternalSetValue^^J{\endgroup
+%<etex> \expandafter\gdef\csname qst@value:\detokenize{#1}\endcsname{#2}}
+%<!etex> \expandafter\gdef\csname qst@value:\string#1\endcsname{#2}}
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{\EndInternalSetValue}
+% This should actually never get encountered:
+% \begin{macrocode}
+\newcommand*{\EndInternalSetValue}{%
+ \PackageError{qstest}{\string\InternalSetValue\space got confused}%
+ {You probably wrote something bad to the save file}}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\SavedValue}
+% This is used for retrieving a saved value. If there is no such
+% value, instead the current setting in \cmd{\qst@defaultvalue} is
+% used.
+% \begin{macrocode}
+\def\SavedValue#1{%
+%<*etex>
+ \ifcsname qst@value:\detokenize{#1}\endcsname
+ \expandafter\expandafter\expandafter
+ {\csname qst@value:\detokenize{#1}\expandafter\endcsname\expandafter}%
+ \else
+ \expandafter\expandafter\expandafter{\expandafter\qst@defaultvalue
+ \expandafter}%
+%</etex>
+%<*!etex>
+ \expandafter\ifx\csname qst@value:\string#1\endcsname\relax
+ \expandafter\expandafter\expandafter{\expandafter\qst@defaultvalue
+ \expandafter}%
+ \else
+ \expandafter\expandafter\expandafter
+ {\csname qst@value:\string#1\expandafter\endcsname\expandafter}%
+%</!etex>
+ \fi}
+% \end{macrocode}
+% \end{macro}
+% \subsection{The End}
+% The test can be ended either in the driver file, or in a standalone
+% testfile. \cmd{\stop} is \LaTeX's way of ending the processing of
+% an input file before any document processing or setup has been done.
+% \begin{macrocode}
+%</package>
+%<test> \stop
+% \end{macrocode}
+% \Finale
+
diff --git a/Master/texmf-dist/source/latex/qstest/qstest.ins b/Master/texmf-dist/source/latex/qstest/qstest.ins
new file mode 100644
index 00000000000..ac3853675c0
--- /dev/null
+++ b/Master/texmf-dist/source/latex/qstest/qstest.ins
@@ -0,0 +1,41 @@
+%%
+%% This is file `qstest.ins',
+%% generated with the docstrip utility.
+%%
+%% The original source files were:
+%%
+%% qstest.dtx (with options: `installer')
+%%
+%% IMPORTANT NOTICE:
+%%
+%% For the copyright see the source file.
+%%
+%% Any modified versions of this file must be renamed
+%% with new filenames distinct from qstest.ins.
+%%
+%% For distribution of the original source see the terms
+%% for copying and modification in the file qstest.dtx.
+%%
+%% This generated file may be distributed as long as the
+%% original source files, as listed above, are part of the
+%% same distribution. (The sources need not necessarily be
+%% in the same archive or directory.)
+\errorcontextlines=\maxdimen
+%%
+%% Copyright (C) 2006, 2007 QuinScape GmbH
+%% http://www.quinscape.de
+\input docstrip
+\ifx\Make y\askforoverwritefalse\fi
+\generate{
+ \file{qstest.drv}{\from{qstest.dtx}{driver,test,etex}}
+ \file{qstest-qs.tex}{\from{qstest.dtx}{test,etex}}
+ \file{makematch.drv}{\from{makematch.dtx}{driver,etex}}
+ \file{makematch-qs.tex}{\from{makematch.dtx}{test,etex}}
+ \ifx\Make y\else \usedir{tex/latex/qstest}\fi
+ \file{qstest.sty}{\from{qstest.dtx}{package,etex}}
+ \file{makematch.sty}{\from{makematch.dtx}{package,etex}}}
+\endbatchfile
+
+\endinput
+%%
+%% End of file `qstest.ins'.