12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832 |
- discard """
- output: '''
- [Suite] RST parsing
- [Suite] RST tables
- [Suite] RST indentation
- [Suite] Markdown indentation
- [Suite] Warnings
- [Suite] RST include directive
- [Suite] RST escaping
- [Suite] RST inline markup
- '''
- """
- # tests for rst module
- import ../../lib/packages/docutils/[rstgen, rst, rstast]
- import unittest, strutils
- import std/private/miscdollars
- import os
- import std/[assertions, syncio]
- const preferMarkdown = {roPreferMarkdown, roSupportMarkdown, roNimFile, roSandboxDisabled}
- const preferRst = {roSupportMarkdown, roNimFile, roSandboxDisabled}
- proc toAst(input: string,
- rstOptions: RstParseOptions = preferMarkdown,
- error: ref string = nil,
- warnings: ref seq[string] = nil): string =
- ## If `error` is nil then no errors should be generated.
- ## The same goes for `warnings`.
- proc testMsgHandler(filename: string, line, col: int, msgkind: MsgKind,
- arg: string) =
- let mc = msgkind.whichMsgClass
- let a = $msgkind % arg
- var message: string
- toLocation(message, filename, line, col + ColRstOffset)
- message.add " $1: $2" % [$mc, a]
- if mc == mcError:
- if error == nil:
- raise newException(EParseError, "[unexpected error] " & message)
- error[] = message
- # we check only first error because subsequent ones may be meaningless
- raise newException(EParseError, "")
- else:
- doAssert warnings != nil, "unexpected RST warning '" & message & "'"
- warnings[].add message
- try:
- const filen = "input"
- proc myFindFile(filename: string): string =
- # we don't find any files in online mode:
- result = ""
- var (rst, _, _) = rstParse(input, filen, line=LineRstInit, column=ColRstInit,
- rstOptions, myFindFile, testMsgHandler)
- result = treeRepr(rst)
- except EParseError as e:
- if e.msg != "":
- result = e.msg
- suite "RST parsing":
- test "References are whitespace-neutral and case-insensitive":
- # refname is 'lexical-analysis', the same for all the 3 variants:
- check(dedent"""
- Lexical Analysis
- ================
- Ref. `Lexical Analysis`_ or `Lexical analysis`_ or `lexical analysis`_.
- """.toAst ==
- dedent"""
- rnInner
- rnHeadline level=1 anchor='lexical-analysis'
- rnLeaf 'Lexical'
- rnLeaf ' '
- rnLeaf 'Analysis'
- rnParagraph
- rnLeaf 'Ref'
- rnLeaf '.'
- rnLeaf ' '
- rnInternalRef
- rnInner
- rnLeaf 'Lexical'
- rnLeaf ' '
- rnLeaf 'Analysis'
- rnLeaf 'lexical-analysis'
- rnLeaf ' '
- rnLeaf 'or'
- rnLeaf ' '
- rnInternalRef
- rnInner
- rnLeaf 'Lexical'
- rnLeaf ' '
- rnLeaf 'analysis'
- rnLeaf 'lexical-analysis'
- rnLeaf ' '
- rnLeaf 'or'
- rnLeaf ' '
- rnInternalRef
- rnInner
- rnLeaf 'lexical'
- rnLeaf ' '
- rnLeaf 'analysis'
- rnLeaf 'lexical-analysis'
- rnLeaf '.'
- rnLeaf ' '
- """)
- test "RST quoted literal blocks":
- let expected =
- dedent"""
- rnInner
- rnLeaf 'Paragraph'
- rnLeaf ':'
- rnLiteralBlock
- rnLeaf '>x'
- """
- check(dedent"""
- Paragraph::
- >x""".toAst(rstOptions = preferRst) == expected)
- check(dedent"""
- Paragraph::
- >x""".toAst(rstOptions = preferRst) == expected)
- test "RST quoted literal blocks, :: at a separate line":
- let expected =
- dedent"""
- rnInner
- rnInner
- rnLeaf 'Paragraph'
- rnLiteralBlock
- rnLeaf '>x
- >>y'
- """
- check(dedent"""
- Paragraph
- ::
- >x
- >>y""".toAst(rstOptions = preferRst) == expected)
- check(dedent"""
- Paragraph
- ::
- >x
- >>y""".toAst(rstOptions = preferRst) == expected)
- test "Markdown quoted blocks":
- check(dedent"""
- Paragraph.
- >x""".toAst ==
- dedent"""
- rnInner
- rnLeaf 'Paragraph'
- rnLeaf '.'
- rnMarkdownBlockQuote
- rnMarkdownBlockQuoteItem quotationDepth=1
- rnLeaf 'x'
- """)
- # bug #17987
- check(dedent"""
- foo https://github.com/nim-lang/Nim/issues/8258
- > bar""".toAst ==
- dedent"""
- rnInner
- rnInner
- rnLeaf 'foo'
- rnLeaf ' '
- rnStandaloneHyperlink
- rnLeaf 'https://github.com/nim-lang/Nim/issues/8258'
- rnMarkdownBlockQuote
- rnMarkdownBlockQuoteItem quotationDepth=1
- rnLeaf 'bar'
- """)
- let expected = dedent"""
- rnInner
- rnLeaf 'Paragraph'
- rnLeaf '.'
- rnMarkdownBlockQuote
- rnMarkdownBlockQuoteItem quotationDepth=1
- rnInner
- rnLeaf 'x1'
- rnLeaf ' '
- rnLeaf 'x2'
- rnMarkdownBlockQuoteItem quotationDepth=2
- rnInner
- rnLeaf 'y1'
- rnLeaf ' '
- rnLeaf 'y2'
- rnMarkdownBlockQuoteItem quotationDepth=1
- rnLeaf 'z'
- """
- check(dedent"""
- Paragraph.
- >x1 x2
- >>y1 y2
- >z""".toAst == expected)
- check(dedent"""
- Paragraph.
- > x1 x2
- >> y1 y2
- > z""".toAst == expected)
- check(dedent"""
- >x
- >y
- >z""".toAst ==
- dedent"""
- rnMarkdownBlockQuote
- rnMarkdownBlockQuoteItem quotationDepth=1
- rnInner
- rnLeaf 'x'
- rnLeaf ' '
- rnLeaf 'y'
- rnLeaf ' '
- rnLeaf 'z'
- """)
- check(dedent"""
- > z
- > > >y
- """.toAst ==
- dedent"""
- rnMarkdownBlockQuote
- rnMarkdownBlockQuoteItem quotationDepth=1
- rnLeaf 'z'
- rnMarkdownBlockQuoteItem quotationDepth=3
- rnLeaf 'y'
- """)
- test "Markdown quoted blocks: lazy":
- let expected = dedent"""
- rnInner
- rnMarkdownBlockQuote
- rnMarkdownBlockQuoteItem quotationDepth=2
- rnInner
- rnLeaf 'x'
- rnLeaf ' '
- rnLeaf 'continuation1'
- rnLeaf ' '
- rnLeaf 'continuation2'
- rnParagraph
- rnLeaf 'newParagraph'
- """
- check(dedent"""
- >>x
- continuation1
- continuation2
- newParagraph""".toAst == expected)
- check(dedent"""
- >> x
- continuation1
- continuation2
- newParagraph""".toAst == expected)
- # however mixing more than 1 non-lazy line and lazy one(s) splits quote
- # in our parser, which appeared the easiest way to handle such cases:
- var warnings = new seq[string]
- check(dedent"""
- >> x
- >> continuation1
- continuation2
- newParagraph""".toAst(warnings=warnings) ==
- dedent"""
- rnInner
- rnMarkdownBlockQuote
- rnMarkdownBlockQuoteItem quotationDepth=2
- rnLeaf 'x'
- rnMarkdownBlockQuoteItem quotationDepth=2
- rnInner
- rnLeaf 'continuation1'
- rnLeaf ' '
- rnLeaf 'continuation2'
- rnParagraph
- rnLeaf 'newParagraph'
- """)
- check(warnings[] == @[
- "input(2, 1) Warning: RST style: two or more quoted lines " &
- "are followed by unquoted line 3"])
- test "Markdown quoted blocks: not lazy":
- # here is where we deviate from CommonMark specification: 'bar' below is
- # not considered as continuation of 2-level '>> foo' quote.
- check(dedent"""
- >>> foo
- > bar
- >> baz
- """.toAst() ==
- dedent"""
- rnMarkdownBlockQuote
- rnMarkdownBlockQuoteItem quotationDepth=3
- rnLeaf 'foo'
- rnMarkdownBlockQuoteItem quotationDepth=1
- rnLeaf 'bar'
- rnMarkdownBlockQuoteItem quotationDepth=2
- rnLeaf 'baz'
- """)
- test "Markdown quoted blocks: inline markup works":
- check(dedent"""
- > hi **bold** text
- """.toAst == dedent"""
- rnMarkdownBlockQuote
- rnMarkdownBlockQuoteItem quotationDepth=1
- rnInner
- rnLeaf 'hi'
- rnLeaf ' '
- rnStrongEmphasis
- rnLeaf 'bold'
- rnLeaf ' '
- rnLeaf 'text'
- """)
- test "Markdown quoted blocks: blank line separator":
- let expected = dedent"""
- rnInner
- rnMarkdownBlockQuote
- rnMarkdownBlockQuoteItem quotationDepth=1
- rnInner
- rnLeaf 'x'
- rnLeaf ' '
- rnLeaf 'y'
- rnMarkdownBlockQuote
- rnMarkdownBlockQuoteItem quotationDepth=1
- rnInner
- rnLeaf 'z'
- rnLeaf ' '
- rnLeaf 't'
- """
- check(dedent"""
- >x
- >y
- > z
- > t""".toAst == expected)
- check(dedent"""
- >x
- y
- > z
- t""".toAst == expected)
- test "Markdown quoted blocks: nested body blocks/elements work #1":
- let expected = dedent"""
- rnMarkdownBlockQuote
- rnMarkdownBlockQuoteItem quotationDepth=1
- rnBulletList
- rnBulletItem
- rnInner
- rnLeaf 'x'
- rnBulletItem
- rnInner
- rnLeaf 'y'
- """
- check(dedent"""
- > - x
- - y
- """.toAst == expected)
- # TODO: if bug #17340 point 28 is resolved then this may work:
- # check(dedent"""
- # > - x
- # - y
- # """.toAst == expected)
- check(dedent"""
- > - x
- > - y
- """.toAst == expected)
- check(dedent"""
- >
- > - x
- >
- > - y
- >
- """.toAst == expected)
- test "Markdown quoted blocks: nested body blocks/elements work #2":
- let expected = dedent"""
- rnAdmonition adType=note
- [nil]
- [nil]
- rnDefList
- rnDefItem
- rnDefName
- rnLeaf 'deflist'
- rnLeaf ':'
- rnDefBody
- rnMarkdownBlockQuote
- rnMarkdownBlockQuoteItem quotationDepth=2
- rnInner
- rnLeaf 'quote'
- rnLeaf ' '
- rnLeaf 'continuation'
- """
- check(dedent"""
- .. Note:: deflist:
- >> quote
- continuation
- """.toAst(rstOptions = preferRst) == expected)
- check(dedent"""
- .. Note::
- deflist:
- >> quote
- continuation
- """.toAst(rstOptions = preferRst) == expected)
- check(dedent"""
- .. Note::
- deflist:
- >> quote
- >> continuation
- """.toAst(rstOptions = preferRst) == expected)
- # spaces are not significant between `>`:
- check(dedent"""
- .. Note::
- deflist:
- > > quote
- > > continuation
- """.toAst(rstOptions = preferRst) == expected)
- test "Markdown quoted blocks: de-indent handled well":
- check(dedent"""
- >
- > - x
- > - y
- >
- > Paragraph.
- """.toAst(rstOptions = preferRst) == dedent"""
- rnMarkdownBlockQuote
- rnMarkdownBlockQuoteItem quotationDepth=1
- rnInner
- rnBlockQuote
- rnBulletList
- rnBulletItem
- rnInner
- rnLeaf 'x'
- rnBulletItem
- rnInner
- rnLeaf 'y'
- rnParagraph
- rnLeaf 'Paragraph'
- rnLeaf '.'
- """)
- let expectCodeBlock = dedent"""
- rnCodeBlock
- [nil]
- rnFieldList
- rnField
- rnFieldName
- rnLeaf 'default-language'
- rnFieldBody
- rnLeaf 'Nim'
- rnLiteralBlock
- rnLeaf '
- let a = 1
- ```'
- """
- test "Markdown code blocks with more > 3 backticks":
- check(dedent"""
- ````
- let a = 1
- ```
- ````""".toAst == expectCodeBlock)
- test "Markdown code blocks with ~~~":
- check(dedent"""
- ~~~
- let a = 1
- ```
- ~~~""".toAst == expectCodeBlock)
- check(dedent"""
- ~~~~~
- let a = 1
- ```
- ~~~~~""".toAst == expectCodeBlock)
- test "Markdown code blocks with Nim-specific arguments":
- check(dedent"""
- ```nim number-lines=1 test
- let a = 1
- ```""".toAst ==
- dedent"""
- rnCodeBlock
- rnDirArg
- rnLeaf 'nim'
- rnFieldList
- rnField
- rnFieldName
- rnLeaf 'number-lines'
- rnFieldBody
- rnLeaf '1'
- rnField
- rnFieldName
- rnLeaf 'test'
- rnFieldBody
- rnLiteralBlock
- rnLeaf '
- let a = 1'
- """)
- check(dedent"""
- ```nim test = "nim c $1" number-lines = 1
- let a = 1
- ```""".toAst ==
- dedent"""
- rnCodeBlock
- rnDirArg
- rnLeaf 'nim'
- rnFieldList
- rnField
- rnFieldName
- rnLeaf 'test'
- rnFieldBody
- rnLeaf '"nim c $1"'
- rnField
- rnFieldName
- rnLeaf 'number-lines'
- rnFieldBody
- rnLeaf '1'
- rnLiteralBlock
- rnLeaf '
- let a = 1'
- """)
- test "additional indentation < 4 spaces is handled fine":
- check(dedent"""
- Indentation
- ```nim
- let a = 1
- ```""".toAst ==
- dedent"""
- rnInner
- rnParagraph
- rnLeaf 'Indentation'
- rnParagraph
- rnCodeBlock
- rnDirArg
- rnLeaf 'nim'
- [nil]
- rnLiteralBlock
- rnLeaf '
- let a = 1'
- """)
- # | |
- # | \ indentation of exactly two spaces before 'let a = 1'
- test "no blank line is required before or after Markdown code block":
- let inputBacktick = dedent"""
- Some text
- ```
- CodeBlock()
- ```
- Other text"""
- let inputTilde = dedent"""
- Some text
- ~~~~~~~~~
- CodeBlock()
- ~~~~~~~~~
- Other text"""
- let expected = dedent"""
- rnInner
- rnParagraph
- rnLeaf 'Some'
- rnLeaf ' '
- rnLeaf 'text'
- rnParagraph
- rnCodeBlock
- [nil]
- rnFieldList
- rnField
- rnFieldName
- rnLeaf 'default-language'
- rnFieldBody
- rnLeaf 'Nim'
- rnLiteralBlock
- rnLeaf '
- CodeBlock()'
- rnLeaf ' '
- rnLeaf 'Other'
- rnLeaf ' '
- rnLeaf 'text'
- """
- check inputBacktick.toAst == expected
- check inputTilde.toAst == expected
- test "option list has priority over definition list":
- for opt in [preferMarkdown, preferRst]:
- check(dedent"""
- --defusages
- file
- -o set
- """.toAst(rstOptions = opt) ==
- dedent"""
- rnOptionList
- rnOptionListItem order=1
- rnOptionGroup
- rnLeaf '--'
- rnLeaf 'defusages'
- rnDescription
- rnInner
- rnLeaf 'file'
- rnOptionListItem order=2
- rnOptionGroup
- rnLeaf '-'
- rnLeaf 'o'
- rnDescription
- rnLeaf 'set'
- """)
- test "items of 1 option list can be separated by blank lines":
- check(dedent"""
- -a desc1
- -b desc2
- """.toAst ==
- dedent"""
- rnOptionList
- rnOptionListItem order=1
- rnOptionGroup
- rnLeaf '-'
- rnLeaf 'a'
- rnDescription
- rnLeaf 'desc1'
- rnOptionListItem order=2
- rnOptionGroup
- rnLeaf '-'
- rnLeaf 'b'
- rnDescription
- rnLeaf 'desc2'
- """)
- test "definition list does not gobble up the following blocks":
- check(dedent"""
- defName
- defBody
- -b desc2
- """.toAst(rstOptions = preferRst) ==
- dedent"""
- rnInner
- rnDefList
- rnDefItem
- rnDefName
- rnLeaf 'defName'
- rnDefBody
- rnInner
- rnLeaf 'defBody'
- rnOptionList
- rnOptionListItem order=1
- rnOptionGroup
- rnLeaf '-'
- rnLeaf 'b'
- rnDescription
- rnLeaf 'desc2'
- """)
- test "RST comment":
- check(dedent"""
- .. comment1
- comment2
- someParagraph""".toAst ==
- dedent"""
- rnLeaf 'someParagraph'
- """)
- check(dedent"""
- ..
- comment1
- comment2
- someParagraph""".toAst ==
- dedent"""
- rnLeaf 'someParagraph'
- """)
- test "check that additional line right after .. ends comment":
- check(dedent"""
- ..
- notAcomment1
- notAcomment2
- someParagraph""".toAst(rstOptions = preferRst) ==
- dedent"""
- rnInner
- rnBlockQuote
- rnInner
- rnLeaf 'notAcomment1'
- rnLeaf ' '
- rnLeaf 'notAcomment2'
- rnParagraph
- rnLeaf 'someParagraph'
- """)
- test "check that additional line right after .. ends comment (Markdown mode)":
- # in Markdown small indentation does not matter so this should
- # just be split to 2 paragraphs.
- check(dedent"""
- ..
- notAcomment1
- notAcomment2
- someParagraph""".toAst ==
- dedent"""
- rnInner
- rnInner
- rnLeaf 'notAcomment1'
- rnLeaf ' '
- rnLeaf 'notAcomment2'
- rnParagraph
- rnLeaf 'someParagraph'
- """)
- test "but blank lines after 2nd non-empty line don't end the comment":
- check(dedent"""
- ..
- comment1
- comment2
- someParagraph""".toAst ==
- dedent"""
- rnLeaf 'someParagraph'
- """)
- test "using .. as separator b/w directives and block quotes":
- check(dedent"""
- .. note:: someNote
- ..
- someBlockQuote""".toAst(rstOptions = preferRst) ==
- dedent"""
- rnInner
- rnAdmonition adType=note
- [nil]
- [nil]
- rnLeaf 'someNote'
- rnBlockQuote
- rnInner
- rnLeaf 'someBlockQuote'
- """)
- test "no redundant blank lines in literal blocks":
- check(dedent"""
- Check::
- code
- """.toAst(rstOptions = preferRst) ==
- dedent"""
- rnInner
- rnLeaf 'Check'
- rnLeaf ':'
- rnLiteralBlock
- rnLeaf 'code'
- """)
- test "Markdown indented code blocks":
- check(dedent"""
- See
- some code""".toAst ==
- dedent"""
- rnInner
- rnInner
- rnLeaf 'See'
- rnLiteralBlock
- rnLeaf 'some code'
- """)
- # not a code block -- no blank line before:
- check(dedent"""
- See
- some code""".toAst ==
- dedent"""
- rnInner
- rnLeaf 'See'
- rnLeaf ' '
- rnLeaf 'some'
- rnLeaf ' '
- rnLeaf 'code'
- """)
- suite "RST tables":
- test "formatting in tables works":
- check(
- dedent"""
- ========= ===
- `build` `a`
- ========= ===
- """.toAst ==
- dedent"""
- rnTable colCount=2
- rnTableRow
- rnTableDataCell
- rnInlineCode
- rnDirArg
- rnLeaf 'nim'
- [nil]
- rnLiteralBlock
- rnLeaf 'build'
- rnTableDataCell
- rnInlineCode
- rnDirArg
- rnLeaf 'nim'
- [nil]
- rnLiteralBlock
- rnLeaf 'a'
- """)
- test "tables with slightly overflowed cells cause an error (1)":
- var error = new string
- check(
- dedent"""
- ====== ======
- Inputs Output
- ====== ======
- """.toAst(error=error) == "")
- check(error[] == "input(2, 2) Error: Illformed table: " &
- "this word crosses table column from the right")
- test "tables with slightly overflowed cells cause an error (2)":
- var error = new string
- check("" == dedent"""
- ===== ===== ======
- Input Output
- ===== ===== ======
- False False False
- ===== ===== ======
- """.toAst(error=error))
- check(error[] == "input(2, 8) Error: Illformed table: " &
- "this word crosses table column from the right")
- test "tables with slightly underflowed cells cause an error":
- var error = new string
- check("" == dedent"""
- ===== ===== ======
- Input Output
- ===== ===== ======
- False False False
- ===== ===== ======
- """.toAst(error=error))
- check(error[] == "input(2, 7) Error: Illformed table: " &
- "this word crosses table column from the left")
- test "tables with unequal underlines should be reported (1)":
- var error = new string
- error[] = "none"
- check("" == dedent"""
- ===== ======
- Input Output
- ===== ======
- False False
- ===== =======
- """.toAst(error=error))
- check(error[] == "input(5, 14) Error: Illformed table: " &
- "end of table column #2 should end at position 13")
- test "tables with unequal underlines should be reported (2)":
- var error = new string
- check("" == dedent"""
- ===== ======
- Input Output
- ===== =======
- False False
- ===== ======
- """.toAst(error=error))
- check(error[] == "input(3, 14) Error: Illformed table: " &
- "end of table column #2 should end at position 13")
- test "tables with empty first cells":
- check(
- dedent"""
- = = =
- x y z
- t
- = = =
- """.toAst ==
- dedent"""
- rnTable colCount=3
- rnTableRow
- rnTableDataCell
- rnLeaf 'x'
- rnTableDataCell
- rnInner
- rnLeaf 'y'
- rnLeaf ' '
- rnTableDataCell
- rnInner
- rnLeaf 'z'
- rnLeaf ' '
- rnLeaf 't'
- """)
- test "tables with spanning cells & separators":
- check(
- dedent"""
- ===== ===== ======
- Inputs Output
- ------------ ------
- A B A or B
- ===== ===== ======
- False False False
- True False True
- ----- ----- ------
- False True True
- True True True
- ===== ===== ======
- """.toAst ==
- dedent"""
- rnTable colCount=3
- rnTableRow
- rnTableHeaderCell span=2
- rnLeaf 'Inputs'
- rnTableHeaderCell span=1
- rnLeaf 'Output'
- rnTableRow endsHeader
- rnTableHeaderCell
- rnLeaf 'A'
- rnTableHeaderCell
- rnLeaf 'B'
- rnTableHeaderCell
- rnInner
- rnLeaf 'A'
- rnLeaf ' '
- rnLeaf 'or'
- rnLeaf ' '
- rnLeaf 'B'
- rnTableRow
- rnTableDataCell
- rnLeaf 'False'
- rnTableDataCell
- rnLeaf 'False'
- rnTableDataCell
- rnLeaf 'False'
- rnTableRow
- rnTableDataCell span=1
- rnLeaf 'True'
- rnTableDataCell span=1
- rnLeaf 'False'
- rnTableDataCell span=1
- rnLeaf 'True'
- rnTableRow
- rnTableDataCell
- rnLeaf 'False'
- rnTableDataCell
- rnLeaf 'True'
- rnTableDataCell
- rnLeaf 'True'
- rnTableRow
- rnTableDataCell
- rnLeaf 'True'
- rnTableDataCell
- rnLeaf 'True'
- rnTableDataCell
- rnLeaf 'True'
- """)
- test "tables with spanning cells with uneqal underlines cause an error":
- var error = new string
- check(
- dedent"""
- ===== ===== ======
- Inputs Output
- ------------- ------
- A B A or B
- ===== ===== ======
- """.toAst(error=error) == "")
- check(error[] == "input(3, 1) Error: Illformed table: " &
- "spanning underline does not match main table columns")
- let expTable = dedent"""
- rnTable colCount=2
- rnTableRow
- rnTableDataCell
- rnLeaf 'Inputs'
- rnTableDataCell
- rnLeaf 'Output'
- """
- test "only tables with `=` columns specs are allowed (1)":
- var warnings = new seq[string]
- check(
- dedent"""
- ------ ------
- Inputs Output
- ------ ------
- """.toAst(warnings=warnings) ==
- expTable)
- check(warnings[] ==
- @["input(1, 1) Warning: RST style: " &
- "only tables with `=` columns specification are allowed",
- "input(3, 1) Warning: RST style: " &
- "only tables with `=` columns specification are allowed"])
- test "only tables with `=` columns specs are allowed (2)":
- var warnings = new seq[string]
- check(
- dedent"""
- ====== ======
- Inputs Output
- ~~~~~~ ~~~~~~
- """.toAst(warnings=warnings) ==
- expTable)
- check(warnings[] ==
- @["input(3, 1) Warning: RST style: "&
- "only tables with `=` columns specification are allowed"])
- suite "RST indentation":
- test "nested bullet lists":
- let input = dedent """
- * - bullet1
- - bullet2
- * - bullet3
- - bullet4
- """
- let output = input.toAst
- check(output == dedent"""
- rnBulletList
- rnBulletItem
- rnBulletList
- rnBulletItem
- rnInner
- rnLeaf 'bullet1'
- rnBulletItem
- rnInner
- rnLeaf 'bullet2'
- rnBulletItem
- rnBulletList
- rnBulletItem
- rnInner
- rnLeaf 'bullet3'
- rnBulletItem
- rnInner
- rnLeaf 'bullet4'
- """)
- test "nested markup blocks":
- let input = dedent"""
- #) .. Hint:: .. Error:: none
- #) .. Warning:: term0
- Definition0
- #) some
- paragraph1
- #) term1
- Definition1
- term2
- Definition2
- """
- check(input.toAst(rstOptions = preferRst) == dedent"""
- rnEnumList labelFmt=1)
- rnEnumItem
- rnAdmonition adType=hint
- [nil]
- [nil]
- rnAdmonition adType=error
- [nil]
- [nil]
- rnLeaf 'none'
- rnEnumItem
- rnAdmonition adType=warning
- [nil]
- [nil]
- rnDefList
- rnDefItem
- rnDefName
- rnLeaf 'term0'
- rnDefBody
- rnInner
- rnLeaf 'Definition0'
- rnEnumItem
- rnInner
- rnLeaf 'some'
- rnLeaf ' '
- rnLeaf 'paragraph1'
- rnEnumItem
- rnDefList
- rnDefItem
- rnDefName
- rnLeaf 'term1'
- rnDefBody
- rnInner
- rnLeaf 'Definition1'
- rnDefItem
- rnDefName
- rnLeaf 'term2'
- rnDefBody
- rnInner
- rnLeaf 'Definition2'
- """)
- test "code-block parsing":
- let input1 = dedent"""
- .. code-block:: nim
- :test: "nim c $1"
- template additive(typ: typedesc) =
- discard
- """
- let input2 = dedent"""
- .. code-block:: nim
- :test: "nim c $1"
- template additive(typ: typedesc) =
- discard
- """
- let input3 = dedent"""
- .. code-block:: nim
- :test: "nim c $1"
- template additive(typ: typedesc) =
- discard
- """
- let inputWrong = dedent"""
- .. code-block:: nim
- :test: "nim c $1"
- template additive(typ: typedesc) =
- discard
- """
- let ast = dedent"""
- rnCodeBlock
- rnDirArg
- rnLeaf 'nim'
- rnFieldList
- rnField
- rnFieldName
- rnLeaf 'test'
- rnFieldBody
- rnInner
- rnLeaf '"'
- rnLeaf 'nim'
- rnLeaf ' '
- rnLeaf 'c'
- rnLeaf ' '
- rnLeaf '$'
- rnLeaf '1'
- rnLeaf '"'
- rnField
- rnFieldName
- rnLeaf 'default-language'
- rnFieldBody
- rnLeaf 'Nim'
- rnLiteralBlock
- rnLeaf 'template additive(typ: typedesc) =
- discard'
- """
- check input1.toAst == ast
- check input2.toAst == ast
- check input3.toAst == ast
- # "template..." should be parsed as a definition list attached to ":test:":
- check inputWrong.toAst != ast
- test "Markdown definition lists work in conjunction with bullet lists":
- check(dedent"""
- * some term
- : the definition
- Paragraph.""".toAst ==
- dedent"""
- rnInner
- rnBulletList
- rnBulletItem
- rnMdDefList
- rnDefItem
- rnDefName
- rnLeaf 'some'
- rnLeaf ' '
- rnLeaf 'term'
- rnDefBody
- rnInner
- rnLeaf 'the'
- rnLeaf ' '
- rnLeaf 'definition'
- rnParagraph
- rnLeaf 'Paragraph'
- rnLeaf '.'
- """)
- test "Markdown definition lists work with blank lines and extra paragraphs":
- check(dedent"""
- Term1
- : Definition1
- Term2 *inline markup*
- : Definition2
- Paragraph2
- Term3
- : * point1
- * point2
- : term3definition2
- """.toAst == dedent"""
- rnMdDefList
- rnDefItem
- rnDefName
- rnLeaf 'Term1'
- rnDefBody
- rnInner
- rnLeaf 'Definition1'
- rnDefItem
- rnDefName
- rnLeaf 'Term2'
- rnLeaf ' '
- rnEmphasis
- rnLeaf 'inline'
- rnLeaf ' '
- rnLeaf 'markup'
- rnDefBody
- rnParagraph
- rnLeaf 'Definition2'
- rnParagraph
- rnLeaf 'Paragraph2'
- rnDefItem
- rnDefName
- rnLeaf 'Term3'
- rnDefBody
- rnBulletList
- rnBulletItem
- rnInner
- rnLeaf 'point1'
- rnBulletItem
- rnInner
- rnLeaf 'point2'
- rnDefBody
- rnInner
- rnLeaf 'term3definition2'
- """)
- suite "Markdown indentation":
- test "Markdown paragraph indentation":
- # Additional spaces (<=3) of indentation does not break the paragraph.
- # TODO: in 2nd case de-indentation causes paragraph to break, this is
- # reasonable but does not seem to conform the Markdown spec.
- check(dedent"""
- Start1
- stop1
- Start2
- stop2
- """.toAst ==
- dedent"""
- rnInner
- rnParagraph
- rnLeaf 'Start1'
- rnLeaf ' '
- rnLeaf 'stop1'
- rnParagraph
- rnLeaf 'Start2'
- rnParagraph
- rnLeaf 'stop2'
- rnLeaf ' '
- """)
- suite "Warnings":
- test "warnings for broken footnotes/links/substitutions":
- let input = dedent"""
- firstParagraph
- footnoteRef [som]_
- link `a broken Link`_
- substitution |undefined subst|
- link short.link_
- lastParagraph
- """
- var warnings = new seq[string]
- let output = input.toAst(rstOptions=preferRst, warnings=warnings)
- check(warnings[] == @[
- "input(3, 14) Warning: broken link 'citation-som'",
- "input(5, 7) Warning: broken link 'a broken Link'",
- "input(7, 15) Warning: unknown substitution 'undefined subst'",
- "input(9, 6) Warning: broken link 'short.link'"
- ])
- test "Pandoc Markdown concise link warning points to target":
- var warnings = new seq[string]
- check(
- "ref [here][target]".toAst(warnings=warnings) ==
- dedent"""
- rnInner
- rnLeaf 'ref'
- rnLeaf ' '
- rnPandocRef
- rnInner
- rnLeaf 'here'
- rnInner
- rnLeaf 'target'
- """)
- check warnings[] == @["input(1, 12) Warning: broken link 'target'"]
- test "With include directive and blank lines at the beginning":
- "other.rst".writeFile(dedent"""
- firstParagraph
- here brokenLink_""")
- let input = ".. include:: other.rst"
- var warnings = new seq[string]
- let output = input.toAst(warnings=warnings)
- check warnings[] == @["other.rst(5, 6) Warning: broken link 'brokenLink'"]
- check(output == dedent"""
- rnInner
- rnParagraph
- rnLeaf 'firstParagraph'
- rnParagraph
- rnLeaf 'here'
- rnLeaf ' '
- rnRstRef
- rnLeaf 'brokenLink'
- """)
- removeFile("other.rst")
- test "warnings for ambiguous links (references + anchors)":
- # Reference like `x`_ generates a link alias x that may clash with others
- let input = dedent"""
- Manual reference: `foo <#foo,string,string>`_
- .. _foo:
- Paragraph.
- Ref foo_
- """
- var warnings = new seq[string]
- let output = input.toAst(warnings=warnings)
- check(warnings[] == @[
- dedent """
- input(7, 5) Warning: ambiguous doc link `foo`
- clash:
- (3, 8): (manual directive anchor)
- (1, 45): (implicitly-generated hyperlink alias)"""
- ])
- # reference should be resolved to the manually set anchor:
- check(output ==
- dedent"""
- rnInner
- rnParagraph
- rnLeaf 'Manual'
- rnLeaf ' '
- rnLeaf 'reference'
- rnLeaf ':'
- rnLeaf ' '
- rnHyperlink
- rnInner
- rnLeaf 'foo'
- rnInner
- rnLeaf '#foo,string,string'
- rnParagraph anchor='foo'
- rnLeaf 'Paragraph'
- rnLeaf '.'
- rnParagraph
- rnLeaf 'Ref'
- rnLeaf ' '
- rnInternalRef
- rnInner
- rnLeaf 'foo'
- rnLeaf 'foo'
- rnLeaf ' '
- """)
- suite "RST include directive":
- test "Include whole":
- "other.rst".writeFile("**test1**")
- let input = ".. include:: other.rst"
- doAssert "<strong>test1</strong>" == rstToHtml(input, {roSandboxDisabled}, defaultConfig())
- removeFile("other.rst")
- test "Include starting from":
- "other.rst".writeFile("""
- And this should **NOT** be visible in `docs.html`
- OtherStart
- *Visible*
- """)
- let input = """
- .. include:: other.rst
- :start-after: OtherStart
- """
- check "<em>Visible</em>" == rstToHtml(input, {roSandboxDisabled}, defaultConfig())
- removeFile("other.rst")
- test "Include everything before":
- "other.rst".writeFile("""
- *Visible*
- OtherEnd
- And this should **NOT** be visible in `docs.html`
- """)
- let input = """
- .. include:: other.rst
- :end-before: OtherEnd
- """
- doAssert "<em>Visible</em>" == rstToHtml(input, {roSandboxDisabled}, defaultConfig())
- removeFile("other.rst")
- test "Include everything between":
- "other.rst".writeFile("""
- And this should **NOT** be visible in `docs.html`
- OtherStart
- *Visible*
- OtherEnd
- And this should **NOT** be visible in `docs.html`
- """)
- let input = """
- .. include:: other.rst
- :start-after: OtherStart
- :end-before: OtherEnd
- """
- check "<em>Visible</em>" == rstToHtml(input, {roSandboxDisabled}, defaultConfig())
- removeFile("other.rst")
- test "Ignore premature ending string":
- "other.rst".writeFile("""
- OtherEnd
- And this should **NOT** be visible in `docs.html`
- OtherStart
- *Visible*
- OtherEnd
- And this should **NOT** be visible in `docs.html`
- """)
- let input = """
- .. include:: other.rst
- :start-after: OtherStart
- :end-before: OtherEnd
- """
- doAssert "<em>Visible</em>" == rstToHtml(input, {roSandboxDisabled}, defaultConfig())
- removeFile("other.rst")
- suite "RST escaping":
- test "backspaces":
- check("""\ this""".toAst == dedent"""
- rnLeaf 'this'
- """)
- check("""\\ this""".toAst == dedent"""
- rnInner
- rnLeaf '\'
- rnLeaf ' '
- rnLeaf 'this'
- """)
- check("""\\\ this""".toAst == dedent"""
- rnInner
- rnLeaf '\'
- rnLeaf 'this'
- """)
- check("""\\\\ this""".toAst == dedent"""
- rnInner
- rnLeaf '\'
- rnLeaf '\'
- rnLeaf ' '
- rnLeaf 'this'
- """)
- suite "RST inline markup":
- test "* and ** surrounded by spaces are not inline markup":
- check("a * b * c ** d ** e".toAst == dedent"""
- rnInner
- rnLeaf 'a'
- rnLeaf ' '
- rnLeaf '*'
- rnLeaf ' '
- rnLeaf 'b'
- rnLeaf ' '
- rnLeaf '*'
- rnLeaf ' '
- rnLeaf 'c'
- rnLeaf ' '
- rnLeaf '**'
- rnLeaf ' '
- rnLeaf 'd'
- rnLeaf ' '
- rnLeaf '**'
- rnLeaf ' '
- rnLeaf 'e'
- """)
- test "end-string has repeating symbols":
- check("*emphasis content****".toAst == dedent"""
- rnEmphasis
- rnLeaf 'emphasis'
- rnLeaf ' '
- rnLeaf 'content'
- rnLeaf '***'
- """)
- check("""*emphasis content\****""".toAst == dedent"""
- rnEmphasis
- rnLeaf 'emphasis'
- rnLeaf ' '
- rnLeaf 'content'
- rnLeaf '*'
- rnLeaf '**'
- """) # exact configuration of leafs with * is not really essential,
- # only total number of * is essential
- check("**strong content****".toAst == dedent"""
- rnStrongEmphasis
- rnLeaf 'strong'
- rnLeaf ' '
- rnLeaf 'content'
- rnLeaf '**'
- """)
- check("""**strong content*\****""".toAst == dedent"""
- rnStrongEmphasis
- rnLeaf 'strong'
- rnLeaf ' '
- rnLeaf 'content'
- rnLeaf '*'
- rnLeaf '*'
- rnLeaf '*'
- """)
- check("``lit content`````".toAst == dedent"""
- rnInlineLiteral
- rnLeaf 'lit'
- rnLeaf ' '
- rnLeaf 'content'
- rnLeaf '```'
- """)
- test "interpreted text parsing: code fragments":
- check(dedent"""
- .. default-role:: option
- `--gc:refc`""".toAst ==
- dedent"""
- rnInner
- rnDefaultRole
- rnDirArg
- rnLeaf 'option'
- [nil]
- [nil]
- rnParagraph
- rnCodeFragment
- rnInner
- rnLeaf '--'
- rnLeaf 'gc'
- rnLeaf ':'
- rnLeaf 'refc'
- rnLeaf 'option'
- """)
- test """interpreted text can be ended with \` """:
- let output = (".. default-role:: literal\n" & """`\``""").toAst
- check(output.endsWith """
- rnParagraph
- rnInlineLiteral
- rnLeaf '`'""" & "\n")
- let output2 = """`\``""".toAst
- check(output2 == dedent"""
- rnInlineCode
- rnDirArg
- rnLeaf 'nim'
- [nil]
- rnLiteralBlock
- rnLeaf '`'
- """)
- let output3 = """`proc \`+\``""".toAst
- check(output3 == dedent"""
- rnInlineCode
- rnDirArg
- rnLeaf 'nim'
- [nil]
- rnLiteralBlock
- rnLeaf 'proc `+`'
- """)
- check("""`\\`""".toAst ==
- dedent"""
- rnInlineCode
- rnDirArg
- rnLeaf 'nim'
- [nil]
- rnLiteralBlock
- rnLeaf '\\'
- """)
- test "Markdown-style code/backtick":
- # no whitespace is required before `
- check("`try`...`except`".toAst ==
- dedent"""
- rnInner
- rnInlineCode
- rnDirArg
- rnLeaf 'nim'
- [nil]
- rnLiteralBlock
- rnLeaf 'try'
- rnLeaf '...'
- rnInlineCode
- rnDirArg
- rnLeaf 'nim'
- [nil]
- rnLiteralBlock
- rnLeaf 'except'
- """)
- test """inline literals can contain \ anywhere""":
- check("""``\``""".toAst == dedent"""
- rnInlineLiteral
- rnLeaf '\'
- """)
- check("""``\\``""".toAst == dedent"""
- rnInlineLiteral
- rnLeaf '\'
- rnLeaf '\'
- """)
- check("""``\```""".toAst == dedent"""
- rnInlineLiteral
- rnLeaf '\'
- rnLeaf '`'
- """)
- check("""``\\```""".toAst == dedent"""
- rnInlineLiteral
- rnLeaf '\'
- rnLeaf '\'
- rnLeaf '`'
- """)
- check("""``\````""".toAst == dedent"""
- rnInlineLiteral
- rnLeaf '\'
- rnLeaf '`'
- rnLeaf '`'
- """)
- test "references with _ at the end":
- check(dedent"""
- .. _lnk: https
- lnk_""".toAst ==
- dedent"""
- rnHyperlink
- rnInner
- rnLeaf 'lnk'
- rnInner
- rnLeaf 'https'
- """)
- test "not a hyper link":
- check(dedent"""
- .. _lnk: https
- lnk___""".toAst ==
- dedent"""
- rnInner
- rnLeaf 'lnk'
- rnLeaf '___'
- """)
- test "no punctuation in the end of a standalone URI is allowed":
- check(dedent"""
- [see (http://no.org)], end""".toAst(rstOptions = preferRst) ==
- dedent"""
- rnInner
- rnLeaf '['
- rnLeaf 'see'
- rnLeaf ' '
- rnLeaf '('
- rnStandaloneHyperlink
- rnLeaf 'http://no.org'
- rnLeaf ')'
- rnLeaf ']'
- rnLeaf ','
- rnLeaf ' '
- rnLeaf 'end'
- """)
- # but `/` at the end is OK
- check(
- dedent"""
- See http://no.org/ end""".toAst ==
- dedent"""
- rnInner
- rnLeaf 'See'
- rnLeaf ' '
- rnStandaloneHyperlink
- rnLeaf 'http://no.org/'
- rnLeaf ' '
- rnLeaf 'end'
- """)
- # a more complex URL with some made-up ending '&='.
- # Github Markdown would include final &= and
- # so would rst2html.py in contradiction with RST spec.
- check(
- dedent"""
- See https://www.google.com/url?sa=t&source=web&cd=&cad=rja&url=https%3A%2F%2Fnim-lang.github.io%2FNim%2Frst.html%23features&usg=AO&= end""".toAst ==
- dedent"""
- rnInner
- rnLeaf 'See'
- rnLeaf ' '
- rnStandaloneHyperlink
- rnLeaf 'https://www.google.com/url?sa=t&source=web&cd=&cad=rja&url=https%3A%2F%2Fnim-lang.github.io%2FNim%2Frst.html%23features&usg=AO'
- rnLeaf '&'
- rnLeaf '='
- rnLeaf ' '
- rnLeaf 'end'
- """)
- test "Markdown-style link can be split to a few lines":
- check(dedent"""
- is [term-rewriting
- macros](manual.html#term-rewriting-macros)""".toAst ==
- dedent"""
- rnInner
- rnLeaf 'is'
- rnLeaf ' '
- rnHyperlink
- rnLeaf 'term-rewriting macros'
- rnLeaf 'manual.html#term-rewriting-macros'
- """)
- test "URL with balanced parentheses (Markdown rule)":
- # 2 balanced parens, 1 unbalanced:
- check(dedent"""
- https://en.wikipedia.org/wiki/APL_((programming_language)))""".toAst ==
- dedent"""
- rnInner
- rnStandaloneHyperlink
- rnLeaf 'https://en.wikipedia.org/wiki/APL_((programming_language))'
- rnLeaf ')'
- """)
- # the same for Markdown-style link:
- check(dedent"""
- [foo [bar]](https://en.wikipedia.org/wiki/APL_((programming_language))))""".toAst ==
- dedent"""
- rnInner
- rnHyperlink
- rnLeaf 'foo [bar]'
- rnLeaf 'https://en.wikipedia.org/wiki/APL_((programming_language))'
- rnLeaf ')'
- """)
- # unbalanced (here behavior is more RST-like actually):
- check(dedent"""
- https://en.wikipedia.org/wiki/APL_(programming_language(""".toAst ==
- dedent"""
- rnInner
- rnStandaloneHyperlink
- rnLeaf 'https://en.wikipedia.org/wiki/APL_(programming_language'
- rnLeaf '('
- """)
- # unbalanced [, but still acceptable:
- check(dedent"""
- [my {link example](http://example.com/bracket_(symbol_[))""".toAst ==
- dedent"""
- rnHyperlink
- rnLeaf 'my {link example'
- rnLeaf 'http://example.com/bracket_(symbol_[)'
- """)
- test "not a Markdown link":
- # bug #17340 (27) `f` will be considered as a protocol and blocked as unsafe
- var warnings = new seq[string]
- check("[T](f: var Foo)".toAst(warnings = warnings) ==
- dedent"""
- rnInner
- rnLeaf '['
- rnLeaf 'T'
- rnLeaf ']'
- rnLeaf '('
- rnLeaf 'f'
- rnLeaf ':'
- rnLeaf ' '
- rnLeaf 'var'
- rnLeaf ' '
- rnLeaf 'Foo'
- rnLeaf ')'
- """)
- check(warnings[] == @["input(1, 5) Warning: broken link 'f'"])
|