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'), ` - 2 - + - 3 -` - )); - it('Newcommand Arg', () => + 2 + + + 3 + ` + ); + }); + + /********************************************************************************/ + + it('Newcommand Arg', () => { toXmlMatch( tex2mml('\\renewcommand{\\sum}[1]{2 #1 3}\\sum{*}'), ` - 2 - - 3 -` - )); - it('Newcommand Optional', () => + 2 + + 3 + ` + ); + }); + + /********************************************************************************/ + + it('Newcommand Optional', () => { toXmlMatch( tex2mml('\\renewcommand{\\sum}[1][+]{2 #1 3}\\sum\\sum[*]'), ` - 2 - + - 3 - 2 - - 3 -` - )); - it('Newcommand Arg Optional', () => + 2 + + + 3 + 2 + + 3 + ` + ); + }); + + /********************************************************************************/ + + it('Newcommand Arg Optional', () => { toXmlMatch( tex2mml('\\renewcommand{\\sum}[2][+]{2 #1 3 #2 4}\\sum{+}\\sum[*]{+}'), ` - 2 - + - 3 - + - 4 - 2 - - 3 - + - 4 -` - )); - 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}' ), ` - Argument c: - b - a - a -` - )); - 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}' ), ` - Argument a: - b - a - a - ` - )); - 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}' ), ` - Argument c(3): - b - a - a -` - )); - 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' ), ` - h - + - h - h - + - g -` - )); - 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}' ), ` - a - + - b - a - - b - x - - b -` - )); - it('Let Brace Equal', () => + a + + + b + a + + b + x + + b + ` + ); + }); + + /********************************************************************************/ + + it('Let Brace Equal', () => { toXmlMatch( tex2mml('\\let\\be={ \\be a}'), ` - - a - -` - )); - it('Let Brace', () => + + a + + ` + ); + }); + + /********************************************************************************/ + + it('Let Brace', () => { toXmlMatch( tex2mml('\\let\\be{ \\be a}'), ` - - a - -` - )); - it('Let Caret', () => + + a + + ` + ); + }); + + /********************************************************************************/ + + it('Let Caret', () => { toXmlMatch( tex2mml('\\let\\car^ a\\car b'), ` - - a - b - -` - )); - it('Let Brace Delim', () => + + a + b + + ` + ); + }); + + /********************************************************************************/ + + it('Let Brace Delim', () => { toXmlMatch( tex2mml('\\let\\lb=\\{ \\lb \\frac{1}{2} \\}'), ` - { - - 1 - 2 - - } -` - )); - it('Let Paren Delim', () => + { + + 1 + 2 + + } + ` + ); + }); + + /********************************************************************************/ + + it('Let Paren Delim', () => { toXmlMatch( tex2mml('\\let\\lb( \\lb \\frac{1}{2})'), ` - ( - - 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}'), ` - a - + - b - 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}' ), ` - a - + - b - 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\\}'), ` - - { - - 1 - 2 - - } - -` - )); - it('Let Paren Stretchy', () => + + { + + 1 + 2 + + } + + ` + ); + }); + + /********************************************************************************/ + + it('Let Paren Stretchy', () => { toXmlMatch( tex2mml('\\let\\lb( \\left\\lb \\frac{1}{2} \\right)'), ` - - ( - - 1 - 2 - - ) - -` - )); - it('Let Fn', () => + + ( + + 1 + 2 + + ) + + ` + ); + }); + + /********************************************************************************/ + + it('Let Fn', () => { toXmlMatch( tex2mml('\\let\\ll\\sin\\ll(x)'), ` - sin - - ( - 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)'), ` - sin - - ( - x - ) - sin - - ( - x - ) - cos - - ( - 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)' ), ` - cos - - ( - x - ) - tan - - ( - x - ) - sin - - ( - 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' ), ` - - ( - - a - b - - - ) - - c - ) - -` - )); - 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' ), ` - - - - a - b - - - - - c - - -` - )); - 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' ), ` - a - b - a - c - a - b -` - )); - it('Let Self', () => - toXmlMatch( - tex2mml('\\let\\x\\x \\x'), - ` - - Undefined control sequence \\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'), ` - - - ( - - - a - b - - - ) - - -` - )); - it('Def Optional Brace', () => + + + ( + + + a + b + + + ) + + + ` + ); + }); + + /********************************************************************************/ + + it('Def Optional Brace', () => { toXmlMatch( tex2mml('\\def\\bar[#1]#2{#1 + #2}\\bar[{a}]{b}'), ` - 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 -` - )); + + 2 + + + + b + ` + ); + }); + + /********************************************************************************/ + + it('Def Template Matching', () => { + toXmlMatch( + tex2mml('\\def\\ending{+}\\def\\test#1\\end{[#1]} \\test a\\ending b\\end'), + ` + [ + a + + + b + ] + ` + ); + }); + + /********************************************************************************/ + + it('Def Hash Replacement', () => { + toXmlMatch( + tex2mml('\\def\\x#1{\\def\\y##1#1{[##1]}\\y} \\x\\X abc \\X'), + ` + [ + a + b + c + ] + ` + ); + }); + + /********************************************************************************/ + }); +/**********************************************************************************/ +/**********************************************************************************/ + 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}' ), ` - - - - - - - -  forever -` - )); - 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}' ), ` - - - - - - - - 2 - + - 3 -  forever -` - )); - 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}' ), ` - - - - - - - - - - - - - - - a -  never -  forever -` - )); - 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}' ), ` - - - - - - - - - - - - - - - a -  never - - - - - - - - b -  never -  forever -` - )); - 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}' ), ` - - - - - - - - - - - - - - - a - - - - - - - - b -  never -  never -  forever -` - )); - 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}' ), ` - - - - - - - - - - - - - - - a - - - - - - - - b -  never - c -  never - d -  forever -` - )); - 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}' - ), - ` - - \\begin{theirHeartEnv} ended with \\end{yourHeartEnv} - -` - )); + ) + .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}' - ), - ` - - Erroneous nesting of equation structures - -` - )); - it('Newenvironment Align End', () => - toXmlMatch( - tex2mml( - '\\newenvironment{proof}{\\begin{align}\\textbf{Proof:}}{\\end{align}}\\begin{proof}a=b\\end{proof}' - ), - ` - - Erroneous nesting of equation structures - -` - )); - 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}' - ), - ` - - Erroneous nesting of equation structures - -` - )); - 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 - - -` - )); + + | + q + + + ` + ); + }); + + /********************************************************************************/ + }); +/**********************************************************************************/ +/**********************************************************************************/ + describe('NewcommandError', () => { beforeEach(() => setupTex(['base', 'newcommand'])); - it('No Sequence', () => - toXmlMatch( - tex2mml('\\def\\bar[#1]#3{}'), - ` - - Parameters for \\bar must be numbered sequentially - -` - )); - it('No CS', () => - toXmlMatch( - tex2mml('\\def{\\bar}[#1]#2{}'), - ` - - \\def must be followed by a control sequence - -` - )); - it('Illegal Hash', () => - toXmlMatch( - tex2mml('\\def\\bar[##1]#2{#1}'), - ` - - Illegal use of # in template for \\bar - -` - )); - it('No Replacement', () => - toXmlMatch( - tex2mml('\\def\\bar[#1]#2'), - ` - - Missing replacement string for definition of \\def - -` - )); - it('Runaway Argument', () => - toXmlMatch( - tex2mml('\\def\\bar[#1]#2{}\\bar['), - ` - - Runaway argument for \\bar? - -` - )); - it('Illegal CS', () => - toXmlMatch( - tex2mml('\\newcommand{\\11}{a}'), - ` - - Illegal control sequence name for \\newcommand - -` - )); - it('Illegal Parameter Number', () => - toXmlMatch( - tex2mml('\\newenvironment{hh}[a]{}{}'), - ` - - Illegal number of parameters specified in \\newenvironment - -` - )); - it('Let Undefined CS', () => - toXmlMatch( - tex2mml('\\let\\aa\\bb \\aa'), - ` - - Undefined control sequence \\aa - -` - )); - it('Missing Arguments', () => - toXmlMatch( - tex2mml('\\def\\bar[#1]#2#3{c + c}\\bar'), - ` - - Use of \\bar doesn\'t match its definition - -` - )); - it('Single Let Error', () => - toXmlMatch( - tex2mml('\\let\\aa\\textbf\\let\\bb\\aa\\aa'), - ` - - Missing argument for \\aa - -` - )); - it('Double Let Error', () => - toXmlMatch( - tex2mml('\\let\\aa\\textbf\\let\\bb\\aa\\bb'), - ` - - Missing argument for \\bb - -` - )); - it('Triple Let Error', () => - toXmlMatch( - tex2mml('\\let\\aa\\textbf\\let\\bb\\aa\\let\\textbf\\sqrt\\textbf[1]'), - ` - - Missing argument for \\textbf - -` - )); - it('Illegal Argument Number', () => - toXmlMatch( - tex2mml('\\newcommand{\\foo}[a]{#1 + #2}'), - ` - - Illegal number of parameters specified in \\newcommand - -` - )); - it('Optional Brace Error', () => - toXmlMatch( - tex2mml('\\def\\bar[{#1}]#2{#1 + #2}'), - ` - - You can\'t use \'macro parameter character #\' in math mode - -` - )); - it('Missing End Error', () => - toXmlMatch( - tex2mml('\\newenvironment{env}{aa}{bb}\\begin{env}cc'), - ` - - Missing \\end{env} - - ` - )); + + /********************************************************************************/ + + 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'), - ` - - Undefined control sequence \\test - - ` - )); - it('Let existing macro be undefined', () => - toXmlMatch( - tex2mml('\\let\\sqrt=\\undefined \\sqrt{x}'), - ` - - Undefined control sequence \\sqrt - - ` - )); - it('Let existing delimiter be undefined', () => - toXmlMatch( - tex2mml('\\let\\|=\\undefined \\left\\| X \\right\\|'), - ` - - Missing or unrecognized delimiter for \\left - - ` - )); - it('Let after def of existing macro be undefined', () => - toXmlMatch( - tex2mml('\\def\\sqrt{X} \\let\\sqrt=\\undefined \\sqrt{x}'), - ` - - Undefined control sequence \\sqrt - - ` - )); - it('Def overrides let delimiter', () => - toXmlMatch( - tex2mml('\\let\\test=\\| \\def\\test{x} \\left\\test X \\right\\test'), - ` - - Missing or unrecognized delimiter for \\left - - ` - )); - it('Def overrides let delimiter as macro', () => - toXmlMatch( - tex2mml('\\let\\test=\\| \\def\\test{x} \\test'), - ` - x - ` - )); - it('Def overrides existing delimiter', () => - toXmlMatch( - tex2mml('\\def\\|{x} \\left\\| X \\right\\|'), - ` - - Missing or unrecognized delimiter for \\left - - ` - )); - it('Def overrides existing delimiter as macro', () => - toXmlMatch( - tex2mml('\\def\\|{x} \\|'), - ` - x - ` - )); - it('Let overrides def macro', () => - toXmlMatch( - tex2mml('\\def\\test{x} \\let\\test=\\| \\test X \\test'), - ` - - X - - ` - )); - it('Let overrides def macro as delimiter', () => - toXmlMatch( - tex2mml('\\def\\test{x} \\let\\test=\\| \\left\\test X \\right\\test'), - ` - - - X - - - ` - )); - it('Let overrides existing macro', () => - toXmlMatch( - tex2mml('\\let\\sqrt=\\| \\sqrt X'), - ` - - X - ` - )); - it('Let overrides existing macro as delimiter', () => - toXmlMatch( - tex2mml('\\let\\sqrt=\\| \\left\\sqrt X \\right\\sqrt'), - ` - - - X - - - ` - )); - it('Let overrides delimiter', () => - toXmlMatch( - tex2mml('\\let\\|=\\sqrt \\left\\| X \\right\\|'), - ` - - Missing or unrecognized delimiter for \\left - - ` - )); - it('Let overrides delimiter as macro', () => - toXmlMatch( - tex2mml('\\let\\|=\\sqrt \\| X'), - ` - - X - - ` - )); - it('Let of character macro overrides delimiter', () => - toXmlMatch( - tex2mml('\\let\\|=\\alpha \\left\\| X \\right\\|'), - ` - - Missing or unrecognized delimiter for \\left - - ` - )); - it('Let of character creates delimiter', () => - toXmlMatch( - tex2mml('\\let\\test=< \\left\\test X \\right\\test'), - ` - - - X - - - ` - )); - 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'), - ` - [ - a - + - b - ] - ` - )); + + /********************************************************************************/ + + 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'), + ` + x + ` + ); + }); + + /********************************************************************************/ + + 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} \\|'), + ` + x + ` + ); + }); + + /********************************************************************************/ + + it('Let overrides def macro', () => { + toXmlMatch( + tex2mml('\\def\\test{x} \\let\\test=\\| \\test X \\test'), + ` + + X + + ` + ); + }); + + /********************************************************************************/ + + it('Let overrides def macro as delimiter', () => { + toXmlMatch( + tex2mml('\\def\\test{x} \\let\\test=\\| \\left\\test X \\right\\test'), + ` + + + X + + + ` + ); + }); + + /********************************************************************************/ + + it('Let overrides existing macro', () => { + toXmlMatch( + tex2mml('\\let\\sqrt=\\| \\sqrt X'), + ` + + X + ` + ); + }); + + /********************************************************************************/ + + it('Let overrides existing macro as delimiter', () => { + toXmlMatch( + tex2mml('\\let\\sqrt=\\| \\left\\sqrt X \\right\\sqrt'), + ` + + + X + + + ` + ); + }); + + /********************************************************************************/ + + 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'), + ` + + 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'), + ` + + + X + + + ` + ); + }); + + /********************************************************************************/ + + 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('') + ), + ` + + + + a + + + b + + + + + c + + + d + + + + ` + ); + }); + + /********************************************************************************/ + + 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('') + ), + ` + + + + + + + a + + + b + + + + + c + + + d + + + + + + X + + + + ` + ); + }); + + /********************************************************************************/ + + it('Environments Intermixed', () => { + toXmlMatch( + tex2mml( + [ + '\\newenvironment{a}{\\begin{b}}{\\end{b}}', + '\\newenvironment{b}{x}{y}', + '\\begin{a} ... \\end{b}\\begin{b}\\end{a}' + ].join('') + ), + ` + x + . + . + . + y + x + y + ` + ); + }); + + /********************************************************************************/ + + it('Nested Begins', () => { + toXmlMatch( + tex2mml('\\newenvironment{a}{x}{y}\\newenvironment{b}{p}{q}\\begin{a}\\begin{b}X\\end{b}\\end{a}'), + ` + x + p + X + q + y + ` + ); + }); + + /********************************************************************************/ + + 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++;