\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{]}}%
