\ProvidesPackage{unittest}[2022/05/23 Unit testing] \RequirePackage{etoolbox} \newif\if@ut@verbose \@ut@verbosetrue \newcount\ut@testcount \newcount\ut@failcount \def\ut@failtest#1{% \PackageWarning{unittest}{TEST FAILED}% \textbf{TEST FAILED}: #1% \global\advance\ut@failcount\@ne } \AtEndDocument{% \par\vskip\baselineskip \the\ut@testcount\ tests performed. \ifcase\ut@failcount All tests passed.% \immediate\write16{All tests passed.}% \or \textbf{One test failed.}% \PackageWarning{unittest}{ONE TEST FAILED}% \else \textbf{\the\ut@failcount\ tests failed.}% \PackageWarning{unittest}{\the\ut@failcount\space TESTS FAILED}% \fi } \def\ut@showcmd#1{{\frenchspacing\ttfamily\upshape\detokenize{#1}}} \newcommand\expect[3][]{% \noindent \ifstrempty{#1}{% {% \ttfamily\footnotesize\raggedright \def\reserved@a{#2}% \expandafter\strip@prefix\meaning\reserved@a \par }% }{{\footnotesize\itshape#1\par}}% \nobreak \noindent \llap{\hbox to 3em{\textbf{Test:}\hfil}}\nobreak\strut\vrule#2\vrule\par \noindent \llap{\hbox to 3em{\textbf{Exp:}\hfil}}\nobreak\strut\vrule#3\vrule\par \vskip 6pt } % % \AssertEqual\oarg{message}\marg{test}\marg{exp} % Assert that \meta{test} is identical to \meta{exp}, based on the \ifx % testing of macro definition identity. If not, then \meta{message} is used as % the error. % \newcommand\AssertEqual[3][AssertEqual]{% \global\advance\ut@testcount\@ne \def\unittest@a{#2}\def\unittest@b{#3}% \ifx\unittest@a\unittest@b \if@ut@verbose \expect[Passed: #1]{% \texttt{\expandafter\strip@prefix\meaning\unittest@a}% }{% \texttt{\expandafter\strip@prefix\meaning\unittest@b}% }% \fi \else \expect[\ut@failtest{#1}]{% \texttt{\expandafter\strip@prefix\meaning\unittest@a}% }{% \texttt{\expandafter\strip@prefix\meaning\unittest@b}% }% \fi } \newcommand\AssertCharEqual[3][AssertUCEqual]{% \edef\reserved@a{% \noexpand\AssertEqual[\unexpanded{#1}]% {\detokenize{#2}}{\detokenize{#3}}% }\reserved@a } \newcommand\AssertExpandedEqual[3][AssertExpandedEqual]{% \edef\reserved@a{% \unexpanded{\AssertEqual[#1]{#2}}% {#3}% }\reserved@a } \newcommand\AssertNum[3][AssertNum]{% \global\advance\ut@testcount\@ne \ifnum#2#3\relax \if@ut@verbose \par Test passed: #1: \ut@showcmd{#2#3}\par \fi \else \par \ut@failtest{#1}: \ut@showcmd{#2#3}\par \fi } \newcommand\AssertTrue[2][AssertTrue]{% \global\advance\ut@testcount\@ne #2{% \if@ut@verbose \par Test passed: #1: \ut@showcmd{#2}\par \fi }{% \par \ut@failtest{#1}: \ut@showcmd{#2}\par }% } \newcommand\AssertFalse[2][AssertFalse]{% \global\advance\ut@testcount\@ne #2{% \par \ut@failtest{#1}: \ut@showcmd{#2}\par }{% \if@ut@verbose \par Test passed: #1: \ut@showcmd{#2}\par \fi }% } % % Asserts that the macro name of the first argument has the expansion of the % second argument. % \newcommand\AssertMacro[3][\AssertEqual]{% \edef\reserved@a{% \noexpand#1[% \noexpand\ut@showcmd{\noexpand#2->}% ]{\expandonce#2}{\unexpanded{#3}}% }\reserved@a } \newcommand\AssertCS[3][\AssertEqual]{ \@expand{\AssertMacro[#1]}{\csname #2\endcsname}{i}{#3}% } % % Asserts that the \protected@edef expansions of #2 and #3 meet the test of #1, % which by default is \AssertEqual. % \newcommand\AssertExpand[3][\AssertEqual]{% \protected@edef\reserved@a{% \noexpand#1[% \noexpand\ut@showcmd{\unexpanded{#2}}% ]{#2}{#3}% }\reserved@a } % % Asserts that an operation executes a callback on a text that matches the given % text. \#1 is the optional matching operator, \#2 a command that accepts as its % final argument a callback (the callback is left off and added by this unit % test), and \#3 is the text to match against. % \newcommand\AssertCallback[3][\AssertEqual]{% #2{#1[\ut@showcmd{#2}]}{#3}% } \newbox\unittest@boxa \newbox\unittest@boxb \newcommand\AssertBox[3][AssertBox]{% \global\advance\ut@testcount\@ne \setbox\unittest@boxa=\hbox{#2}% \setbox\unittest@boxb=\hbox{#3}% \ifdim\wd\unittest@boxa=\wd\unittest@boxb \expect[Probably passed: #1: \ut@showcmd{#2}]{% \unhbox\unittest@boxa }{% \unhbox\unittest@boxb }% \else %\begingroup % \showboxdepth=1000 \showboxbreadth=1000 % \showbox\unittest@boxa % \showbox\unittest@boxb %\endgroup \expect[\ut@failtest{#1}: \ut@showcmd{#2}]{% \the\wd\unittest@boxa: \unhbox\unittest@boxa }{% \the\wd\unittest@boxb: \unhbox\unittest@boxb }% \fi } \long\def\@footnotetext#1{% \protected@edef\@currentlabel{\csname p@footnote\endcsname\@thefnmark}% \begingroup \hbox{[}#1\hbox{]}% \endgroup } \long\def\InFootnote#1{\@footnotemark\hbox{[}#1\hbox{]}}%