diff --git a/testsuite/tests/input/tex/Newcommand.test.ts b/testsuite/tests/input/tex/Newcommand.test.ts
index 4fe7ada38..7c0177191 100644
--- a/testsuite/tests/input/tex/Newcommand.test.ts
+++ b/testsuite/tests/input/tex/Newcommand.test.ts
@@ -1,960 +1,1344 @@
import { afterAll, beforeEach, describe, it } from '@jest/globals';
-import { getTokens, toXmlMatch, setupTex, tex2mml } from '#helpers';
+import { getTokens, toXmlMatch, setupTex, tex2mml, expectTexError } from '#helpers';
import '#js/input/tex/newcommand/NewcommandConfiguration';
import '#js/input/tex/ams/AmsConfiguration';
import '#js/input/tex/colorv2/ColorV2Configuration';
+/**********************************************************************************/
+/**********************************************************************************/
+
describe('Newcommand', () => {
beforeEach(() => setupTex(['base', 'newcommand']));
- it('Newcommand Simple', () =>
+
+ /********************************************************************************/
+
+ it('Newcommand Simple', () => {
toXmlMatch(
tex2mml('\\newcommand{\\sum}{2 + 3}\\sum'),
``
- ));
- it('Newcommand Arg', () =>
+ 2
+ +
+ 3
+ `
+ );
+ });
+
+ /********************************************************************************/
+
+ it('Newcommand Arg', () => {
toXmlMatch(
tex2mml('\\renewcommand{\\sum}[1]{2 #1 3}\\sum{*}'),
``
- ));
- it('Newcommand Optional', () =>
+ 2
+ ∗
+ 3
+ `
+ );
+ });
+
+ /********************************************************************************/
+
+ it('Newcommand Optional', () => {
toXmlMatch(
tex2mml('\\renewcommand{\\sum}[1][+]{2 #1 3}\\sum\\sum[*]'),
``
- ));
- it('Newcommand Arg Optional', () =>
+ 2
+ +
+ 3
+ 2
+ ∗
+ 3
+ `
+ );
+ });
+
+ /********************************************************************************/
+
+ it('Newcommand Arg Optional', () => {
toXmlMatch(
tex2mml('\\renewcommand{\\sum}[2][+]{2 #1 3 #2 4}\\sum{+}\\sum[*]{+}'),
``
- ));
- it('Newenvironment Optional', () =>
+ 2
+ +
+ 3
+ +
+ 4
+ 2
+ ∗
+ 3
+ +
+ 4
+ `
+ );
+ });
+
+ /********************************************************************************/
+
+ it('Newenvironment Optional', () => {
toXmlMatch(
tex2mml(
'\\newenvironment{argument}[1][a]{\\textbf{Argument #1:}}{aa}\\begin{argument}[c]b\\end{argument}'
),
``
- ));
- it('Newenvironment Optional Noarg', () =>
+ Argument c:
+ b
+ a
+ a
+ `
+ );
+ });
+
+ /********************************************************************************/
+
+ it('Newenvironment Optional Noarg', () => {
toXmlMatch(
tex2mml(
'\\newenvironment{argument}[1][a]{\\textbf{Argument #1:}}{aa}\\begin{argument}b\\end{argument}'
),
``
- ));
- it('Newenvironment Arg Optional', () =>
+ Argument a:
+ b
+ a
+ a
+ `
+ );
+ });
+
+ /********************************************************************************/
+
+ it('Newenvironment Arg Optional', () => {
toXmlMatch(
tex2mml(
'\\renewenvironment{argument}[2][a]{\\textbf{Argument #1(#2):}}{aa}\\begin{argument}[c]{3}b\\end{argument}'
),
``
- ));
- it('Def Double Let', () =>
+ Argument c(3):
+ b
+ a
+ a
+ `
+ );
+ });
+
+ /********************************************************************************/
+
+ it('Def Double Let', () => {
toXmlMatch(
tex2mml(
'\\def\\bar{h}\\let\\fooi\\bar\\def\\fooii{\\bar}\\fooi +\\fooii\\def\\bar{g}\\fooi +\\fooii'
),
``
- ));
- it('Def ReDef', () =>
+ h
+ +
+ h
+ h
+ +
+ g
+ `
+ );
+ });
+
+ /********************************************************************************/
+
+ it('Def ReDef', () => {
toXmlMatch(
tex2mml(
'\\def\\foo{a + b}\\foo\\def\\foo#1{a #1 b}\\foo{-}\\def\\foo#1#2{#2 #1 b}\\foo{-}{x}'
),
``
- ));
- it('Let Brace Equal', () =>
+ a
+ +
+ b
+ a
+ −
+ b
+ x
+ −
+ b
+ `
+ );
+ });
+
+ /********************************************************************************/
+
+ it('Let Brace Equal', () => {
toXmlMatch(
tex2mml('\\let\\be={ \\be a}'),
``
- ));
- it('Let Brace', () =>
+
+ a
+
+ `
+ );
+ });
+
+ /********************************************************************************/
+
+ it('Let Brace', () => {
toXmlMatch(
tex2mml('\\let\\be{ \\be a}'),
``
- ));
- it('Let Caret', () =>
+
+ a
+
+ `
+ );
+ });
+
+ /********************************************************************************/
+
+ it('Let Caret', () => {
toXmlMatch(
tex2mml('\\let\\car^ a\\car b'),
``
- ));
- it('Let Brace Delim', () =>
+
+ a
+ b
+
+ `
+ );
+ });
+
+ /********************************************************************************/
+
+ it('Let Brace Delim', () => {
toXmlMatch(
tex2mml('\\let\\lb=\\{ \\lb \\frac{1}{2} \\}'),
``
- ));
- it('Let Paren Delim', () =>
+ {
+
+ 1
+ 2
+
+ }
+ `
+ );
+ });
+
+ /********************************************************************************/
+
+ it('Let Paren Delim', () => {
toXmlMatch(
tex2mml('\\let\\lb( \\lb \\frac{1}{2})'),
``
- ));
- it('Let Relet', () =>
+ (
+
+ 1
+ 2
+
+ )
+ `
+ );
+ });
+
+ /********************************************************************************/
+
+ it('Let Relet', () => {
toXmlMatch(
tex2mml('\\let\\al\\alpha\\al\\alpha\\let\\al\\aleph\\al\\alpha'),
``
- ));
- it('Let Let', () =>
+ α
+ α
+ ℵ
+ α
+ `
+ );
+ });
+
+ /********************************************************************************/
+
+ it('Let Let', () => {
toXmlMatch(
tex2mml('\\let\\al\\alpha\\al\\alpha\\let\\alpha\\beta\\al\\alpha'),
``
- ));
- it('Def Let', () =>
+ α
+ α
+ α
+ β
+ `
+ );
+ });
+
+ /********************************************************************************/
+
+ it('Def Let', () => {
toXmlMatch(
tex2mml('\\def\\bar[#1]#2{#1 + #2}\\bar[a]{b}\\let\\foo\\bar\\foo[c]{d}'),
``
- ));
- it('Newcommand Let', () =>
+ a
+ +
+ b
+ c
+ +
+ d
+ `
+ );
+ });
+
+ /********************************************************************************/
+
+ it('Newcommand Let', () => {
toXmlMatch(
tex2mml(
'\\newcommand{\\bar}[2][1]{#1 + #2}\\bar[a]{b}\\let\\foo\\bar\\foo[c]{d}'
),
``
- ));
- it('Let Circular Macro', () =>
+ a
+ +
+ b
+ c
+ +
+ d
+ `
+ );
+ });
+
+ /********************************************************************************/
+
+ it('Let Circular Macro', () => {
toXmlMatch(
tex2mml(
'\\let\\kk\\alpha\\kk\\let\\rr\\beta\\rr\\let\\rr\\kk\\let\\kk\\beta\\kk\\rr'
),
``
- ));
- it('Let Brace Equal Stretchy', () =>
+ α
+ β
+ β
+ α
+ `
+ );
+ });
+
+ /********************************************************************************/
+
+ it('Let Brace Equal Stretchy', () => {
toXmlMatch(
tex2mml('\\let\\lb=\\{\\left\\lb \\frac{1}{2} \\right\\}'),
``
- ));
- it('Let Paren Stretchy', () =>
+
+ {
+
+ 1
+ 2
+
+ }
+
+ `
+ );
+ });
+
+ /********************************************************************************/
+
+ it('Let Paren Stretchy', () => {
toXmlMatch(
tex2mml('\\let\\lb( \\left\\lb \\frac{1}{2} \\right)'),
``
- ));
- it('Let Fn', () =>
+
+ (
+
+ 1
+ 2
+
+ )
+
+ `
+ );
+ });
+
+ /********************************************************************************/
+
+ it('Let Fn', () => {
toXmlMatch(
tex2mml('\\let\\ll\\sin\\ll(x)'),
``
- ));
- it('Let Fn Double', () =>
+ sin
+
+ (
+ x
+ )
+ `
+ );
+ });
+
+ /********************************************************************************/
+
+ it('Let Fn Double', () => {
toXmlMatch(
tex2mml('\\let\\ll\\sin\\ll(x)\\let\\rr\\ll\\let\\ll\\cos\\rr(x)\\ll(x)'),
``
- ));
- it('Let Fn Circular', () =>
+ sin
+
+ (
+ x
+ )
+ sin
+
+ (
+ x
+ )
+ cos
+
+ (
+ x
+ )
+ `
+ );
+ });
+
+ /********************************************************************************/
+
+ it('Let Fn Circular', () => {
toXmlMatch(
tex2mml(
'\\let\\save\\sin\\let\\sin\\cos\\let\\cos\\tan\\let\\tan\\save\\sin(x)\\cos(x)\\tan(x)'
),
``
- ));
- it('Let Paren Circular', () =>
+ cos
+
+ (
+ x
+ )
+ tan
+
+ (
+ x
+ )
+ sin
+
+ (
+ x
+ )
+ `
+ );
+ });
+
+ /********************************************************************************/
+
+ it('Let Paren Circular', () => {
toXmlMatch(
tex2mml(
'\\let\\lp(\\let\\rp)\\let\\mp\\rp\\left\\lp \\frac{a}{b}\\middle\\mp c \\right\\rp'
),
``
- ));
- it('Let Angle Circular', () =>
+
+ (
+
+ a
+ b
+
+
+ )
+
+ c
+ )
+
+ `
+ );
+ });
+
+ /********************************************************************************/
+
+ it('Let Angle Circular', () => {
toXmlMatch(
tex2mml(
'\\let\\lp\\langle\\let\\rp\\rangle\\let\\mp\\rp\\left\\lp \\frac{a}{b}\\middle\\mp c \\right\\rp'
),
``
- ));
- it('Let Circular Character', () =>
+
+ ⟨
+
+ a
+ b
+
+
+ ⟩
+
+ c
+ ⟩
+
+ `
+ );
+ });
+
+ /********************************************************************************/
+
+ it('Let Circular Character', () => {
toXmlMatch(
tex2mml(
'\\let\\a a\\let\\b b\\a \\b\\let\\c\\a\\let\\a c\\c \\a\\let\\d=\\c\\let\\c\\b\\d \\c'
),
``
- ));
- it('Let Self', () =>
- toXmlMatch(
- tex2mml('\\let\\x\\x \\x'),
- ``
- ));
- it('Let Overwrite Sqrt Choose', () =>
+ a
+ b
+ a
+ c
+ a
+ b
+ `
+ );
+ });
+
+ /********************************************************************************/
+
+ it('Let Self', () => {
+ expectTexError('\\let\\x\\x \\x')
+ .toBe('Undefined control sequence \\x');
+ });
+
+ /********************************************************************************/
+
+ it('Let Overwrite Sqrt Choose', () => {
toXmlMatch(
tex2mml('\\let\\sqrt\\choose a\\sqrt b'),
``
- ));
- it('Def Optional Brace', () =>
+
+
+ (
+
+
+ a
+ b
+
+
+ )
+
+
+ `
+ );
+ });
+
+ /********************************************************************************/
+
+ it('Def Optional Brace', () => {
toXmlMatch(
tex2mml('\\def\\bar[#1]#2{#1 + #2}\\bar[{a}]{b}'),
``
- ));
- it('Def Options CS', () =>
+ a
+ +
+ b
+ `
+ );
+ });
+
+ /********************************************************************************/
+
+ it('Def Options CS', () => {
toXmlMatch(
tex2mml('\\def\\bar[#1]#2{#1 + #2}\\bar[\\sqrt{2}]{b}'),
``
- ));
+
+ 2
+
+ +
+ b
+ `
+ );
+ });
+
+ /********************************************************************************/
+
+ it('Def Template Matching', () => {
+ toXmlMatch(
+ tex2mml('\\def\\ending{+}\\def\\test#1\\end{[#1]} \\test a\\ending b\\end'),
+ ``
+ );
+ });
+
+ /********************************************************************************/
+
+ it('Def Hash Replacement', () => {
+ toXmlMatch(
+ tex2mml('\\def\\x#1{\\def\\y##1#1{[##1]}\\y} \\x\\X abc \\X'),
+ ``
+ );
+ });
+
+ /********************************************************************************/
+
});
+/**********************************************************************************/
+/**********************************************************************************/
+
describe('Newcommand Color v2', () => {
beforeEach(() => setupTex(['base', 'newcommand', 'colorv2']));
- it('Newenvironment Empty', () =>
+
+ /********************************************************************************/
+
+ it('Newenvironment Empty', () => {
toXmlMatch(
tex2mml(
'\\newenvironment{myHeartEnv}{\\color{purple}{\\heartsuit}\\kern-2.5pt\\color{green}{\\heartsuit}}{\\text{ forever}}\\begin{myHeartEnv}\\end{myHeartEnv}'
),
``
- ));
- it('Newenvironment Content', () =>
+
+ ♡
+
+
+
+ ♡
+
+ forever
+ `
+ );
+ });
+
+ /********************************************************************************/
+
+ it('Newenvironment Content', () => {
toXmlMatch(
tex2mml(
'\\newenvironment{myHeartEnv}{\\color{purple}{\\heartsuit}\\kern-2.5pt\\color{green}{\\heartsuit}}{\\text{ forever}}\\begin{myHeartEnv} 2+3\\end{myHeartEnv}'
),
``
- ));
- it('Newenvironment Nested Double', () =>
+
+ ♡
+
+
+
+ ♡
+
+ 2
+ +
+ 3
+ forever
+ `
+ );
+ });
+
+ /********************************************************************************/
+
+ it('Newenvironment Nested Double', () => {
toXmlMatch(
tex2mml(
'\\newenvironment{myHeartEnv}{\\color{purple}{\\heartsuit}\\kern-2.5pt\\color{green}{\\heartsuit}}{\\text{ forever}}\\newenvironment{yourHeartEnv}{\\color{blue}{\\heartsuit}\\kern-2.5pt\\color{black}{\\heartsuit}}{\\text{ never}}\\begin{myHeartEnv}\\begin{yourHeartEnv}a\\end{yourHeartEnv}\\end{myHeartEnv}'
),
``
- ));
- it('Newenvironment Nested Double 2', () =>
+
+ ♡
+
+
+
+ ♡
+
+
+ ♡
+
+
+
+ ♡
+
+ a
+ never
+ forever
+ `
+ );
+ });
+
+ /********************************************************************************/
+
+ it('Newenvironment Nested Double 2', () => {
toXmlMatch(
tex2mml(
'\\newenvironment{myHeartEnv}{\\color{purple}{\\heartsuit}\\kern-2.5pt\\color{green}{\\heartsuit}}{\\text{ forever}}\\newenvironment{yourHeartEnv}{\\color{blue}{\\heartsuit}\\kern-2.5pt\\color{black}{\\heartsuit}}{\\text{ never}}\\newenvironment{theirHeartEnv}{\\color{blue}{\\heartsuit}\\kern-2.5pt\\color{black}{\\heartsuit}}{\\text{ never}}\\begin{myHeartEnv}\\begin{yourHeartEnv}a\\end{yourHeartEnv}\\begin{theirHeartEnv}b\\end{theirHeartEnv}\\end{myHeartEnv}'
),
``
- ));
- it('Newenvironment Nested Triple', () =>
+
+ ♡
+
+
+
+ ♡
+
+
+ ♡
+
+
+
+ ♡
+
+ a
+ never
+
+ ♡
+
+
+
+ ♡
+
+ b
+ never
+ forever
+ `
+ );
+ });
+
+ /********************************************************************************/
+
+ it('Newenvironment Nested Triple', () => {
toXmlMatch(
tex2mml(
'\\newenvironment{myHeartEnv}{\\color{purple}{\\heartsuit}\\kern-2.5pt\\color{green}{\\heartsuit}}{\\text{ forever}}\\newenvironment{yourHeartEnv}{\\color{blue}{\\heartsuit}\\kern-2.5pt\\color{black}{\\heartsuit}}{\\text{ never}}\\newenvironment{theirHeartEnv}{\\color{blue}{\\heartsuit}\\kern-2.5pt\\color{black}{\\heartsuit}}{\\text{ never}}\\begin{myHeartEnv}\\begin{yourHeartEnv}a\\begin{theirHeartEnv}b\\end{theirHeartEnv}\\end{yourHeartEnv}\\end{myHeartEnv}'
),
``
- ));
- it('Newenvironment Nested Triple Text', () =>
+
+ ♡
+
+
+
+ ♡
+
+
+ ♡
+
+
+
+ ♡
+
+ a
+
+ ♡
+
+
+
+ ♡
+
+ b
+ never
+ never
+ forever
+ `
+ );
+ });
+
+ /********************************************************************************/
+
+ it('Newenvironment Nested Triple Text', () => {
toXmlMatch(
tex2mml(
'\\newenvironment{myHeartEnv}{\\color{purple}{\\heartsuit}\\kern-2.5pt\\color{green}{\\heartsuit}}{\\text{ forever}}\\newenvironment{yourHeartEnv}{\\color{blue}{\\heartsuit}\\kern-2.5pt\\color{black}{\\heartsuit}}{\\text{ never}}\\newenvironment{theirHeartEnv}{\\color{blue}{\\heartsuit}\\kern-2.5pt\\color{black}{\\heartsuit}}{\\text{ never}}\\begin{myHeartEnv}\\begin{yourHeartEnv}a\\begin{theirHeartEnv}b\\end{theirHeartEnv}c\\end{yourHeartEnv}d\\end{myHeartEnv}'
),
``
- ));
- it('Newenvironment Nested Error', () =>
- toXmlMatch(
- tex2mml(
+
+ ♡
+
+
+
+ ♡
+
+
+ ♡
+
+
+
+ ♡
+
+ a
+
+ ♡
+
+
+
+ ♡
+
+ b
+ never
+ c
+ never
+ d
+ forever
+ `
+ );
+ });
+
+ /********************************************************************************/
+
+ it('Newenvironment Nested Error', () => {
+ expectTexError(
'\\newenvironment{myHeartEnv}{\\color{purple}{\\heartsuit}\\kern-2.5pt\\color{green}{\\heartsuit}}{\\text{ forever}}\\newenvironment{yourHeartEnv}{\\color{blue}{\\heartsuit}\\kern-2.5pt\\color{black}{\\heartsuit}}{\\text{ never}}\\newenvironment{theirHeartEnv}{\\color{blue}{\\heartsuit}\\kern-2.5pt\\color{black}{\\heartsuit}}{\\text{ never}}\\begin{myHeartEnv}\\begin{yourHeartEnv}a\\begin{theirHeartEnv}b\\end{yourHeartEnv}\\end{theirHeartEnv}\\end{myHeartEnv}'
- ),
- ``
- ));
+ )
+ .toBe('\\begin{theirHeartEnv} ended with \\end{yourHeartEnv}');
+ });
+
+ /********************************************************************************/
+
});
+/**********************************************************************************/
+/**********************************************************************************/
+
describe('Newcommand Ams', () => {
beforeEach(() => setupTex(['base', 'newcommand', 'ams']));
- it('Newenvironment Align', () =>
- toXmlMatch(
- tex2mml(
- '\\newenvironment{proof}{\\textbf{Proof:}}{\\begin{align} \\blacksquare \\end{align}}\\begin{proof}a=b\\end{proof}'
- ),
- ``
- ));
- it('Newenvironment Align End', () =>
- toXmlMatch(
- tex2mml(
- '\\newenvironment{proof}{\\begin{align}\\textbf{Proof:}}{\\end{align}}\\begin{proof}a=b\\end{proof}'
- ),
- ``
- ));
- it('Newenvironment Align Split', () =>
- toXmlMatch(
- tex2mml(
- '\\newenvironment{proof}{\\begin{align}\\textbf{Proof:}&}{ \\begin{split} 5 \\end{split}&& \\blacksquare\\end{align}}\\begin{proof}a&=b\\end{proof}'
- ),
- ``
- ));
- it('Let Bar', () =>
+
+ /********************************************************************************/
+
+ it('Newenvironment Align', () => {
+ expectTexError(
+ '\\newenvironment{proof}{\\textbf{Proof:}}{\\begin{align} \\blacksquare \\end{align}}\\begin{proof}a=b\\end{proof}'
+ ).toBe('Erroneous nesting of equation structures');
+ });
+
+ /********************************************************************************/
+
+ it('Newenvironment Align End', () => {
+ expectTexError(
+ '\\newenvironment{proof}{\\begin{align}\\textbf{Proof:}}{\\end{align}}\\begin{proof}a=b\\end{proof}'
+ ).toBe('Erroneous nesting of equation structures');
+ });
+
+ /********************************************************************************/
+
+ it('Newenvironment Align Split', () => {
+ expectTexError(
+ '\\newenvironment{proof}{\\begin{align}\\textbf{Proof:}&}{ \\begin{split} 5 \\end{split}&& \\blacksquare\\end{align}}\\begin{proof}a&=b\\end{proof}'
+ ).toBe('Erroneous nesting of equation structures');
+ });
+
+ /********************************************************************************/
+
+ it('Let Bar', () => {
toXmlMatch(
tex2mml('\\let\\b\\lvert\\let\\lvert\\langle\\vert\\b\\lvert'),
``
- ));
- it('Let Bar Stretchy', () =>
+ |
+ |
+ ⟨
+ `
+ );
+ });
+
+ /********************************************************************************/
+
+ it('Let Bar Stretchy', () => {
toXmlMatch(
tex2mml('\\let\\b\\lvert\\let\\lvert\\langle\\left\\b q \\right\\lvert'),
``
- ));
+
+ |
+ q
+ ⟨
+
+ `
+ );
+ });
+
+ /********************************************************************************/
+
});
+/**********************************************************************************/
+/**********************************************************************************/
+
describe('NewcommandError', () => {
beforeEach(() => setupTex(['base', 'newcommand']));
- it('No Sequence', () =>
- toXmlMatch(
- tex2mml('\\def\\bar[#1]#3{}'),
- ``
- ));
- it('No CS', () =>
- toXmlMatch(
- tex2mml('\\def{\\bar}[#1]#2{}'),
- ``
- ));
- it('Illegal Hash', () =>
- toXmlMatch(
- tex2mml('\\def\\bar[##1]#2{#1}'),
- ``
- ));
- it('No Replacement', () =>
- toXmlMatch(
- tex2mml('\\def\\bar[#1]#2'),
- ``
- ));
- it('Runaway Argument', () =>
- toXmlMatch(
- tex2mml('\\def\\bar[#1]#2{}\\bar['),
- ``
- ));
- it('Illegal CS', () =>
- toXmlMatch(
- tex2mml('\\newcommand{\\11}{a}'),
- ``
- ));
- it('Illegal Parameter Number', () =>
- toXmlMatch(
- tex2mml('\\newenvironment{hh}[a]{}{}'),
- ``
- ));
- it('Let Undefined CS', () =>
- toXmlMatch(
- tex2mml('\\let\\aa\\bb \\aa'),
- ``
- ));
- it('Missing Arguments', () =>
- toXmlMatch(
- tex2mml('\\def\\bar[#1]#2#3{c + c}\\bar'),
- ``
- ));
- it('Single Let Error', () =>
- toXmlMatch(
- tex2mml('\\let\\aa\\textbf\\let\\bb\\aa\\aa'),
- ``
- ));
- it('Double Let Error', () =>
- toXmlMatch(
- tex2mml('\\let\\aa\\textbf\\let\\bb\\aa\\bb'),
- ``
- ));
- it('Triple Let Error', () =>
- toXmlMatch(
- tex2mml('\\let\\aa\\textbf\\let\\bb\\aa\\let\\textbf\\sqrt\\textbf[1]'),
- ``
- ));
- it('Illegal Argument Number', () =>
- toXmlMatch(
- tex2mml('\\newcommand{\\foo}[a]{#1 + #2}'),
- ``
- ));
- it('Optional Brace Error', () =>
- toXmlMatch(
- tex2mml('\\def\\bar[{#1}]#2{#1 + #2}'),
- ``
- ));
- it('Missing End Error', () =>
- toXmlMatch(
- tex2mml('\\newenvironment{env}{aa}{bb}\\begin{env}cc'),
- ``
- ));
+
+ /********************************************************************************/
+
+ it('No Sequence', () => {
+ expectTexError('\\def\\bar[#1]#3{}')
+ .toBe('Parameters for \\bar must be numbered sequentially');
+ });
+
+ /********************************************************************************/
+
+ it('No CS', () => {
+ expectTexError('\\def{\\bar}[#1]#2{}')
+ .toBe('\\def must be followed by a control sequence');
+ });
+
+ /********************************************************************************/
+
+ it('Illegal Hash', () => {
+ expectTexError('\\def\\bar[##1]#2{#1}')
+ .toBe('Illegal use of # in template for \\bar');
+ });
+
+ /********************************************************************************/
+
+ it('No Replacement', () => {
+ expectTexError('\\def\\bar[#1]#2')
+ .toBe('Missing replacement string for definition of \\def');
+ });
+
+ /********************************************************************************/
+
+ it('Runaway Argument', () => {
+ expectTexError('\\def\\bar[#1]#2{}\\bar[')
+ .toBe('Runaway argument for \\bar?');
+ });
+
+ /********************************************************************************/
+
+ it('Illegal CS', () => {
+ expectTexError('\\newcommand{\\11}{a}')
+ .toBe('Illegal control sequence name for \\newcommand');
+ });
+
+ /********************************************************************************/
+
+ it('Illegal Parameter Number', () => {
+ expectTexError('\\newenvironment{hh}[a]{}{}')
+ .toBe('Illegal number of parameters specified in \\newenvironment');
+ });
+
+ /********************************************************************************/
+
+ it('Let Undefined CS', () => {
+ expectTexError('\\let\\aa\\bb \\aa')
+ .toBe('Undefined control sequence \\aa');
+ });
+
+ /********************************************************************************/
+
+ it('Missing Arguments', () => {
+ expectTexError('\\def\\bar[#1]#2#3{c + c}\\bar')
+ .toBe('Use of \\bar doesn\'t match its definition');
+ });
+
+ /********************************************************************************/
+
+ it('Single Let Error', () => {
+ expectTexError('\\let\\aa\\textbf\\let\\bb\\aa\\aa')
+ .toBe('Missing argument for \\aa');
+ });
+
+ /********************************************************************************/
+
+ it('Double Let Error', () => {
+ expectTexError('\\let\\aa\\textbf\\let\\bb\\aa\\bb')
+ .toBe('Missing argument for \\bb');
+ });
+
+ /********************************************************************************/
+
+ it('Triple Let Error', () => {
+ expectTexError('\\let\\aa\\textbf\\let\\bb\\aa\\let\\textbf\\sqrt\\textbf[1]')
+ .toBe('Missing argument for \\textbf');
+ });
+
+ /********************************************************************************/
+
+ it('Illegal Argument Number', () => {
+ expectTexError('\\newcommand{\\foo}[a]{#1 + #2}')
+ .toBe('Illegal number of parameters specified in \\newcommand');
+ });
+
+ /********************************************************************************/
+
+ it('Optional Brace Error', () => {
+ expectTexError('\\def\\bar[{#1}]#2{#1 + #2}')
+ .toBe("You can't use 'macro parameter character #' in math mode");
+ });
+
+ /********************************************************************************/
+
+ it('Missing End Error', () => {
+ expectTexError('\\newenvironment{env}{aa}{bb}\\begin{env}cc')
+ .toBe('Missing \\end{env}');
+ });
+
+ /********************************************************************************/
+
+ it('Hash Error', () => {
+ expectTexError('\\def\\x#1{a #1 b #c} \\x{a}')
+ .toBe('Illegal macro parameter reference');
+ });
+
+ /********************************************************************************/
+
+ it('Recursive Macro', () => {
+ expectTexError('\\def\\x{\\x} \\x')
+ .toBe('MathJax maximum macro substitution count exceeded; is here a recursive macro call?');
+ });
+
+ /********************************************************************************/
+
+ it('Recursive Environment', () => {
+ expectTexError('\\newenvironment{error}{\\begin{error}}{\\end{error}} \\begin{error}\\end{error}')
+ .toBe('MathJax maximum substitution count exceeded; is there a recursive latex environment?');
+ });
+
+ /********************************************************************************/
+
});
+/**********************************************************************************/
+/**********************************************************************************/
+
describe('Newcommand Overrides', () => {
beforeEach(() => setupTex(['base', 'newcommand']));
- it('Let def macro be undefined', () =>
- toXmlMatch(
- tex2mml('\\def\\test{error} \\let\\test=\\undefined \\test'),
- ``
- ));
- it('Let existing macro be undefined', () =>
- toXmlMatch(
- tex2mml('\\let\\sqrt=\\undefined \\sqrt{x}'),
- ``
- ));
- it('Let existing delimiter be undefined', () =>
- toXmlMatch(
- tex2mml('\\let\\|=\\undefined \\left\\| X \\right\\|'),
- ``
- ));
- it('Let after def of existing macro be undefined', () =>
- toXmlMatch(
- tex2mml('\\def\\sqrt{X} \\let\\sqrt=\\undefined \\sqrt{x}'),
- ``
- ));
- it('Def overrides let delimiter', () =>
- toXmlMatch(
- tex2mml('\\let\\test=\\| \\def\\test{x} \\left\\test X \\right\\test'),
- ``
- ));
- it('Def overrides let delimiter as macro', () =>
- toXmlMatch(
- tex2mml('\\let\\test=\\| \\def\\test{x} \\test'),
- ``
- ));
- it('Def overrides existing delimiter', () =>
- toXmlMatch(
- tex2mml('\\def\\|{x} \\left\\| X \\right\\|'),
- ``
- ));
- it('Def overrides existing delimiter as macro', () =>
- toXmlMatch(
- tex2mml('\\def\\|{x} \\|'),
- ``
- ));
- it('Let overrides def macro', () =>
- toXmlMatch(
- tex2mml('\\def\\test{x} \\let\\test=\\| \\test X \\test'),
- ``
- ));
- it('Let overrides def macro as delimiter', () =>
- toXmlMatch(
- tex2mml('\\def\\test{x} \\let\\test=\\| \\left\\test X \\right\\test'),
- ``
- ));
- it('Let overrides existing macro', () =>
- toXmlMatch(
- tex2mml('\\let\\sqrt=\\| \\sqrt X'),
- ``
- ));
- it('Let overrides existing macro as delimiter', () =>
- toXmlMatch(
- tex2mml('\\let\\sqrt=\\| \\left\\sqrt X \\right\\sqrt'),
- ``
- ));
- it('Let overrides delimiter', () =>
- toXmlMatch(
- tex2mml('\\let\\|=\\sqrt \\left\\| X \\right\\|'),
- ``
- ));
- it('Let overrides delimiter as macro', () =>
- toXmlMatch(
- tex2mml('\\let\\|=\\sqrt \\| X'),
- ``
- ));
- it('Let of character macro overrides delimiter', () =>
- toXmlMatch(
- tex2mml('\\let\\|=\\alpha \\left\\| X \\right\\|'),
- ``
- ));
- it('Let of character creates delimiter', () =>
- toXmlMatch(
- tex2mml('\\let\\test=< \\left\\test X \\right\\test'),
- ``
- ));
- it('Let of character overrides def', () =>
- toXmlMatch(
- tex2mml('\\def\\test{X}\\let\\test=< \\test'),
- ``
- ));
- it('Def template matching', () =>
- toXmlMatch(
- tex2mml('\\def\\ending{+}\\def\\test#1\\end{[#1]} \\test a\\ending b\\end'),
- ``
- ));
+
+ /********************************************************************************/
+
+ it('Let def macro be undefined', () => {
+ expectTexError('\\def\\test{error} \\let\\test=\\undefined \\test')
+ .toBe('Undefined control sequence \\test');
+ });
+
+ /********************************************************************************/
+
+ it('Let existing macro be undefined', () => {
+ expectTexError('\\let\\sqrt=\\undefined \\sqrt{x}')
+ .toBe('Undefined control sequence \\sqrt');
+ });
+
+ /********************************************************************************/
+
+ it('Let existing delimiter be undefined', () => {
+ expectTexError('\\let\\|=\\undefined \\left\\| X \\right\\|')
+ .toBe('Missing or unrecognized delimiter for \\left');
+ });
+
+ /********************************************************************************/
+
+ it('Let after def of existing macro be undefined', () => {
+ expectTexError('\\def\\sqrt{X} \\let\\sqrt=\\undefined \\sqrt{x}')
+ .toBe('Undefined control sequence \\sqrt');
+ });
+
+ /********************************************************************************/
+
+ it('Def overrides let delimiter', () => {
+ expectTexError('\\let\\test=\\| \\def\\test{x} \\left\\test X \\right\\test')
+ .toBe('Missing or unrecognized delimiter for \\left');
+ });
+
+ /********************************************************************************/
+
+ it('Def overrides let delimiter as macro', () => {
+ toXmlMatch(
+ tex2mml('\\let\\test=\\| \\def\\test{x} \\test'),
+ ``
+ );
+ });
+
+ /********************************************************************************/
+
+ it('Def overrides existing delimiter', () => {
+ expectTexError('\\def\\|{x} \\left\\| X \\right\\|')
+ .toBe('Missing or unrecognized delimiter for \\left');
+ });
+
+ /********************************************************************************/
+
+ it('Def overrides existing delimiter as macro', () => {
+ toXmlMatch(
+ tex2mml('\\def\\|{x} \\|'),
+ ``
+ );
+ });
+
+ /********************************************************************************/
+
+ it('Let overrides def macro', () => {
+ toXmlMatch(
+ tex2mml('\\def\\test{x} \\let\\test=\\| \\test X \\test'),
+ ``
+ );
+ });
+
+ /********************************************************************************/
+
+ it('Let overrides def macro as delimiter', () => {
+ toXmlMatch(
+ tex2mml('\\def\\test{x} \\let\\test=\\| \\left\\test X \\right\\test'),
+ ``
+ );
+ });
+
+ /********************************************************************************/
+
+ it('Let overrides existing macro', () => {
+ toXmlMatch(
+ tex2mml('\\let\\sqrt=\\| \\sqrt X'),
+ ``
+ );
+ });
+
+ /********************************************************************************/
+
+ it('Let overrides existing macro as delimiter', () => {
+ toXmlMatch(
+ tex2mml('\\let\\sqrt=\\| \\left\\sqrt X \\right\\sqrt'),
+ ``
+ );
+ });
+
+ /********************************************************************************/
+
+ it('Let overrides delimiter', () => {
+ expectTexError('\\let\\|=\\sqrt \\left\\| X \\right\\|')
+ .toBe('Missing or unrecognized delimiter for \\left');
+ });
+
+ /********************************************************************************/
+
+ it('Let overrides delimiter as macro', () => {
+ toXmlMatch(
+ tex2mml('\\let\\|=\\sqrt \\| X'),
+ ``
+ );
+ });
+
+ /********************************************************************************/
+
+ it('Let of character macro overrides delimiter', () => {
+ expectTexError('\\let\\|=\\alpha \\left\\| X \\right\\|')
+ .toBe('Missing or unrecognized delimiter for \\left');
+ });
+
+ /********************************************************************************/
+
+ it('Let of character creates delimiter', () => {
+ toXmlMatch(
+ tex2mml('\\let\\test=< \\left\\test X \\right\\test'),
+ ``
+ );
+ });
+
+ /********************************************************************************/
+
+ it('Let of character overrides def', () => {
+ toXmlMatch(
+ tex2mml('\\def\\test{X}\\let\\test=< \\test'),
+ ``
+ );
+ });
+
+ /********************************************************************************/
+
+});
+
+/**********************************************************************************/
+/**********************************************************************************/
+
+describe('Nested Environments', () => {
+ beforeEach(() => setupTex(['base', 'ams', 'newcommand']));
+
+ /********************************************************************************/
+
+ it('Newenvironment with Begin', () => {
+ toXmlMatch(
+ tex2mml(
+ [
+ '\\newenvironment{boxed}{\\begin{array}{|c|c|}\\hline}{\\\\\\hline\\end{array}}',
+ '\\begin{boxed}a&b\\\\c&d\\end{boxed}'
+ ].join('')
+ ),
+ ``
+ );
+ });
+
+ /********************************************************************************/
+
+ it('Environments Nested', () => {
+ toXmlMatch(
+ tex2mml(
+ [
+ '\\newenvironment{boxed}{\\begin{array}{|c|c|}\\hline}{\\\\\\hline\\end{array}}',
+ '\\begin{boxed}\\begin{boxed}a&b\\\\c&d\\end{boxed} & X \\\end{boxed}'
+ ].join('')
+ ),
+ ``
+ );
+ });
+
+ /********************************************************************************/
+
+ it('Environments Intermixed', () => {
+ toXmlMatch(
+ tex2mml(
+ [
+ '\\newenvironment{a}{\\begin{b}}{\\end{b}}',
+ '\\newenvironment{b}{x}{y}',
+ '\\begin{a} ... \\end{b}\\begin{b}\\end{a}'
+ ].join('')
+ ),
+ ``
+ );
+ });
+
+ /********************************************************************************/
+
+ it('Nested Begins', () => {
+ toXmlMatch(
+ tex2mml('\\newenvironment{a}{x}{y}\\newenvironment{b}{p}{q}\\begin{a}\\begin{b}X\\end{b}\\end{a}'),
+ ``
+ );
+ });
+
+ /********************************************************************************/
+
+ it('Dangling End', () => {
+ expectTexError('\\newenvironment{a}{x}{y\\end{a}}\\begin{a} ... \\end{a}')
+ .toBe('Missing \\begin{a} or extra \\end{a}');
+ });
+
+ /********************************************************************************/
+
+ it('Nested Dangling End', () => {
+ expectTexError(
+ '\\newenvironment{a}{\\begin{b}}{\\end{b}}\\newenvironment{b}{x}{y\\end{b}}\\begin{a}X\\end{a}')
+ .toBe('\\begin{a} ended with \\end{b}');
+ });
+
+ /********************************************************************************/
+
+ it('Badly Nested Begins', () => {
+ expectTexError(
+ '\\newenvironment{a}{x}{y}\\newenvironment{b}{p}{q}\\begin{a}\\begin{b} ... \\end{a}\\end{b}'
+ ).toBe('\\begin{b} ended with \\end{a}');
+ });
+
+ /********************************************************************************/
+
+ it('Ended by Wrong Environment', () => {
+ expectTexError('\\newenvironment{a}{x}{y}\\begin{a} X \\end{cases}')
+ .toBe('\\begin{a} ended with \\end{cases}');
+ });
+
+ /********************************************************************************/
+
+ it('Unbalanced Ends 1', () => {
+ expectTexError(
+ '\\newenvironment{a}{a}{b\\end{a}}\\newenvironment{b}{x}{y}\\begin{a}\\begin{b}...\\end{b}\\end{a}'
+ ).toBe('Missing \\begin{a} or extra \\end{a}');
+ });
+
+ /********************************************************************************/
+
+ it('Unbalanced Ends 2', () => {
+ expectTexError(
+ '\\newenvironment{a}{a}{b\\end{a}}\\newenvironment{b}{x}{y}\\begin{b}\\begin{a}...\\end{a}\\end{b}'
+ ).toBe('\\begin{b} ended with \\end{a}');
+ });
+
+ /********************************************************************************/
+
+ it('Triple Nesting', () => {
+ expectTexError(
+ [
+ '\\newenvironment{c}{x}{\\end{a}y}',
+ '\\newenvironment{b}{begin{c}x}{\\end{c}y}',
+ '\\newenvironment{a}{\\begin{b}x}{\\end{b}y}',
+ '\\begin{a} ... '
+ ].join('')
+ ).toBe('Missing \\end{b}');
+ });
+
+ /********************************************************************************/
+
});
+/**********************************************************************************/
+/**********************************************************************************/
+
afterAll(() => getTokens('newcommand'));
diff --git a/ts/input/tex/newcommand/NewcommandUtil.ts b/ts/input/tex/newcommand/NewcommandUtil.ts
index bb68f1c7b..d7520ea1e 100644
--- a/ts/input/tex/newcommand/NewcommandUtil.ts
+++ b/ts/input/tex/newcommand/NewcommandUtil.ts
@@ -219,7 +219,7 @@ export const NewcommandUtil = {
i++;
j -= 2;
}
- return j < 0 ? '' : parser.string.substring(i, i + j);
+ return parser.string.substring(i, i + j);
} else if (c === '\\') {
// @test Def Options CS
parser.i++;