github.com/jancarloviray/community@v0.41.1-0.20170124221257-33a66c87cf2f/app/public/codemirror/mode/markdown/test.js (about)

     1  // CodeMirror, copyright (c) by Marijn Haverbeke and others
     2  // Distributed under an MIT license: http://codemirror.net/LICENSE
     3  
     4  (function() {
     5    var mode = CodeMirror.getMode({tabSize: 4}, "markdown");
     6    function MT(name) { test.mode(name, mode, Array.prototype.slice.call(arguments, 1)); }
     7    var modeHighlightFormatting = CodeMirror.getMode({tabSize: 4}, {name: "markdown", highlightFormatting: true});
     8    function FT(name) { test.mode(name, modeHighlightFormatting, Array.prototype.slice.call(arguments, 1)); }
     9    var modeAtxNoSpace = CodeMirror.getMode({tabSize: 4}, {name: "markdown", allowAtxHeaderWithoutSpace: true});
    10    function AtxNoSpaceTest(name) { test.mode(name, modeAtxNoSpace, Array.prototype.slice.call(arguments, 1)); }
    11    var modeFenced = CodeMirror.getMode({tabSize: 4}, {name: "markdown", fencedCodeBlocks: true});
    12    function FencedTest(name) { test.mode(name, modeFenced, Array.prototype.slice.call(arguments, 1)); }
    13    var modeOverrideClasses = CodeMirror.getMode({tabsize: 4}, {
    14      name: "markdown",
    15      strikethrough: true,
    16      tokenTypeOverrides: {
    17        "header" : "override-header",
    18        "code" : "override-code",
    19        "quote" : "override-quote",
    20        "list1" : "override-list1",
    21        "list2" : "override-list2",
    22        "list3" : "override-list3",
    23        "hr" : "override-hr",
    24        "image" : "override-image",
    25        "linkInline" : "override-link-inline",
    26        "linkEmail" : "override-link-email",
    27        "linkText" : "override-link-text",
    28        "linkHref" : "override-link-href",
    29        "em" : "override-em",
    30        "strong" : "override-strong",
    31        "strikethrough" : "override-strikethrough"
    32    }});
    33    function TokenTypeOverrideTest(name) { test.mode(name, modeOverrideClasses, Array.prototype.slice.call(arguments, 1)); }
    34    var modeFormattingOverride = CodeMirror.getMode({tabsize: 4}, {
    35      name: "markdown",
    36      highlightFormatting: true,
    37      tokenTypeOverrides: {
    38        "formatting" : "override-formatting"
    39    }});
    40    function FormatTokenTypeOverrideTest(name) { test.mode(name, modeFormattingOverride, Array.prototype.slice.call(arguments, 1)); }
    41  
    42  
    43    FT("formatting_emAsterisk",
    44       "[em&formatting&formatting-em *][em foo][em&formatting&formatting-em *]");
    45  
    46    FT("formatting_emUnderscore",
    47       "[em&formatting&formatting-em _][em foo][em&formatting&formatting-em _]");
    48  
    49    FT("formatting_strongAsterisk",
    50       "[strong&formatting&formatting-strong **][strong foo][strong&formatting&formatting-strong **]");
    51  
    52    FT("formatting_strongUnderscore",
    53       "[strong&formatting&formatting-strong __][strong foo][strong&formatting&formatting-strong __]");
    54  
    55    FT("formatting_codeBackticks",
    56       "[comment&formatting&formatting-code `][comment foo][comment&formatting&formatting-code `]");
    57  
    58    FT("formatting_doubleBackticks",
    59       "[comment&formatting&formatting-code ``][comment foo ` bar][comment&formatting&formatting-code ``]");
    60  
    61    FT("formatting_atxHeader",
    62       "[header&header-1&formatting&formatting-header&formatting-header-1 # ][header&header-1 foo # bar ][header&header-1&formatting&formatting-header&formatting-header-1 #]");
    63  
    64    FT("formatting_setextHeader",
    65       "foo",
    66       "[header&header-1&formatting&formatting-header&formatting-header-1 =]");
    67  
    68    FT("formatting_blockquote",
    69       "[quote&quote-1&formatting&formatting-quote&formatting-quote-1 > ][quote&quote-1 foo]");
    70  
    71    FT("formatting_list",
    72       "[variable-2&formatting&formatting-list&formatting-list-ul - ][variable-2 foo]");
    73    FT("formatting_list",
    74       "[variable-2&formatting&formatting-list&formatting-list-ol 1. ][variable-2 foo]");
    75  
    76    FT("formatting_link",
    77       "[link&formatting&formatting-link [][link foo][link&formatting&formatting-link ]]][string&formatting&formatting-link-string&url (][string&url http://example.com/][string&formatting&formatting-link-string&url )]");
    78  
    79    FT("formatting_linkReference",
    80       "[link&formatting&formatting-link [][link foo][link&formatting&formatting-link ]]][string&formatting&formatting-link-string&url [][string&url bar][string&formatting&formatting-link-string&url ]]]",
    81       "[link&formatting&formatting-link [][link bar][link&formatting&formatting-link ]]:] [string&url http://example.com/]");
    82  
    83    FT("formatting_linkWeb",
    84       "[link&formatting&formatting-link <][link http://example.com/][link&formatting&formatting-link >]");
    85  
    86    FT("formatting_linkEmail",
    87       "[link&formatting&formatting-link <][link user@example.com][link&formatting&formatting-link >]");
    88  
    89    FT("formatting_escape",
    90       "[formatting-escape \\*]");
    91  
    92    MT("plainText",
    93       "foo");
    94  
    95    // Don't style single trailing space
    96    MT("trailingSpace1",
    97       "foo ");
    98  
    99    // Two or more trailing spaces should be styled with line break character
   100    MT("trailingSpace2",
   101       "foo[trailing-space-a  ][trailing-space-new-line  ]");
   102  
   103    MT("trailingSpace3",
   104       "foo[trailing-space-a  ][trailing-space-b  ][trailing-space-new-line  ]");
   105  
   106    MT("trailingSpace4",
   107       "foo[trailing-space-a  ][trailing-space-b  ][trailing-space-a  ][trailing-space-new-line  ]");
   108  
   109    // Code blocks using 4 spaces (regardless of CodeMirror.tabSize value)
   110    MT("codeBlocksUsing4Spaces",
   111       "    [comment foo]");
   112  
   113    // Code blocks using 4 spaces with internal indentation
   114    MT("codeBlocksUsing4SpacesIndentation",
   115       "    [comment bar]",
   116       "        [comment hello]",
   117       "            [comment world]",
   118       "    [comment foo]",
   119       "bar");
   120  
   121    // Code blocks should end even after extra indented lines
   122    MT("codeBlocksWithTrailingIndentedLine",
   123       "    [comment foo]",
   124       "        [comment bar]",
   125       "    [comment baz]",
   126       "    ",
   127       "hello");
   128  
   129    // Code blocks using 1 tab (regardless of CodeMirror.indentWithTabs value)
   130    MT("codeBlocksUsing1Tab",
   131       "\t[comment foo]");
   132  
   133    // No code blocks directly after paragraph
   134    // http://spec.commonmark.org/0.19/#example-65
   135    MT("noCodeBlocksAfterParagraph",
   136       "Foo",
   137       "    Bar");
   138  
   139    // Inline code using backticks
   140    MT("inlineCodeUsingBackticks",
   141       "foo [comment `bar`]");
   142  
   143    // Block code using single backtick (shouldn't work)
   144    MT("blockCodeSingleBacktick",
   145       "[comment `]",
   146       "[comment foo]",
   147       "[comment `]");
   148  
   149    // Unclosed backticks
   150    // Instead of simply marking as CODE, it would be nice to have an
   151    // incomplete flag for CODE, that is styled slightly different.
   152    MT("unclosedBackticks",
   153       "foo [comment `bar]");
   154  
   155    // Per documentation: "To include a literal backtick character within a
   156    // code span, you can use multiple backticks as the opening and closing
   157    // delimiters"
   158    MT("doubleBackticks",
   159       "[comment ``foo ` bar``]");
   160  
   161    // Tests based on Dingus
   162    // http://daringfireball.net/projects/markdown/dingus
   163    //
   164    // Multiple backticks within an inline code block
   165    MT("consecutiveBackticks",
   166       "[comment `foo```bar`]");
   167  
   168    // Multiple backticks within an inline code block with a second code block
   169    MT("consecutiveBackticks",
   170       "[comment `foo```bar`] hello [comment `world`]");
   171  
   172    // Unclosed with several different groups of backticks
   173    MT("unclosedBackticks",
   174       "[comment ``foo ``` bar` hello]");
   175  
   176    // Closed with several different groups of backticks
   177    MT("closedBackticks",
   178       "[comment ``foo ``` bar` hello``] world");
   179  
   180    // atx headers
   181    // http://daringfireball.net/projects/markdown/syntax#header
   182  
   183    MT("atxH1",
   184       "[header&header-1 # foo]");
   185  
   186    MT("atxH2",
   187       "[header&header-2 ## foo]");
   188  
   189    MT("atxH3",
   190       "[header&header-3 ### foo]");
   191  
   192    MT("atxH4",
   193       "[header&header-4 #### foo]");
   194  
   195    MT("atxH5",
   196       "[header&header-5 ##### foo]");
   197  
   198    MT("atxH6",
   199       "[header&header-6 ###### foo]");
   200  
   201    // http://spec.commonmark.org/0.19/#example-24
   202    MT("noAtxH7",
   203       "####### foo");
   204  
   205    // http://spec.commonmark.org/0.19/#example-25
   206    MT("noAtxH1WithoutSpace",
   207       "#5 bolt");
   208  
   209    // CommonMark requires a space after # but most parsers don't
   210    AtxNoSpaceTest("atxNoSpaceAllowed_H1NoSpace",
   211       "[header&header-1 #foo]");
   212  
   213    AtxNoSpaceTest("atxNoSpaceAllowed_H4NoSpace",
   214       "[header&header-4 ####foo]");
   215  
   216    AtxNoSpaceTest("atxNoSpaceAllowed_H1Space",
   217       "[header&header-1 # foo]");
   218  
   219    // Inline styles should be parsed inside headers
   220    MT("atxH1inline",
   221       "[header&header-1 # foo ][header&header-1&em *bar*]");
   222  
   223    // Setext headers - H1, H2
   224    // Per documentation, "Any number of underlining =’s or -’s will work."
   225    // http://daringfireball.net/projects/markdown/syntax#header
   226    // Ideally, the text would be marked as `header` as well, but this is
   227    // not really feasible at the moment. So, instead, we're testing against
   228    // what works today, to avoid any regressions.
   229    //
   230    // Check if single underlining = works
   231    MT("setextH1",
   232       "foo",
   233       "[header&header-1 =]");
   234  
   235    // Check if 3+ ='s work
   236    MT("setextH1",
   237       "foo",
   238       "[header&header-1 ===]");
   239  
   240    // Check if single underlining - works
   241    MT("setextH2",
   242       "foo",
   243       "[header&header-2 -]");
   244  
   245    // Check if 3+ -'s work
   246    MT("setextH2",
   247       "foo",
   248       "[header&header-2 ---]");
   249  
   250    // http://spec.commonmark.org/0.19/#example-45
   251    MT("setextH2AllowSpaces",
   252       "foo",
   253       "   [header&header-2 ----      ]");
   254  
   255    // http://spec.commonmark.org/0.19/#example-44
   256    MT("noSetextAfterIndentedCodeBlock",
   257       "     [comment foo]",
   258       "[hr ---]");
   259  
   260    // http://spec.commonmark.org/0.19/#example-51
   261    MT("noSetextAfterQuote",
   262       "[quote&quote-1 > foo]",
   263       "[hr ---]");
   264  
   265    MT("noSetextAfterList",
   266       "[variable-2 - foo]",
   267       "[hr ---]");
   268  
   269    // Single-line blockquote with trailing space
   270    MT("blockquoteSpace",
   271       "[quote&quote-1 > foo]");
   272  
   273    // Single-line blockquote
   274    MT("blockquoteNoSpace",
   275       "[quote&quote-1 >foo]");
   276  
   277    // No blank line before blockquote
   278    MT("blockquoteNoBlankLine",
   279       "foo",
   280       "[quote&quote-1 > bar]");
   281  
   282    // Nested blockquote
   283    MT("blockquoteSpace",
   284       "[quote&quote-1 > foo]",
   285       "[quote&quote-1 >][quote&quote-2 > foo]",
   286       "[quote&quote-1 >][quote&quote-2 >][quote&quote-3 > foo]");
   287  
   288    // Single-line blockquote followed by normal paragraph
   289    MT("blockquoteThenParagraph",
   290       "[quote&quote-1 >foo]",
   291       "",
   292       "bar");
   293  
   294    // Multi-line blockquote (lazy mode)
   295    MT("multiBlockquoteLazy",
   296       "[quote&quote-1 >foo]",
   297       "[quote&quote-1 bar]");
   298  
   299    // Multi-line blockquote followed by normal paragraph (lazy mode)
   300    MT("multiBlockquoteLazyThenParagraph",
   301       "[quote&quote-1 >foo]",
   302       "[quote&quote-1 bar]",
   303       "",
   304       "hello");
   305  
   306    // Multi-line blockquote (non-lazy mode)
   307    MT("multiBlockquote",
   308       "[quote&quote-1 >foo]",
   309       "[quote&quote-1 >bar]");
   310  
   311    // Multi-line blockquote followed by normal paragraph (non-lazy mode)
   312    MT("multiBlockquoteThenParagraph",
   313       "[quote&quote-1 >foo]",
   314       "[quote&quote-1 >bar]",
   315       "",
   316       "hello");
   317  
   318    // Header with leading space after continued blockquote (#3287, negative indentation)
   319    MT("headerAfterContinuedBlockquote",
   320       "[quote&quote-1 > foo]",
   321       "[quote&quote-1 bar]",
   322       "",
   323       " [header&header-1 # hello]");
   324  
   325    // Check list types
   326  
   327    MT("listAsterisk",
   328       "foo",
   329       "bar",
   330       "",
   331       "[variable-2 * foo]",
   332       "[variable-2 * bar]");
   333  
   334    MT("listPlus",
   335       "foo",
   336       "bar",
   337       "",
   338       "[variable-2 + foo]",
   339       "[variable-2 + bar]");
   340  
   341    MT("listDash",
   342       "foo",
   343       "bar",
   344       "",
   345       "[variable-2 - foo]",
   346       "[variable-2 - bar]");
   347  
   348    MT("listNumber",
   349       "foo",
   350       "bar",
   351       "",
   352       "[variable-2 1. foo]",
   353       "[variable-2 2. bar]");
   354  
   355    // Lists require a preceding blank line (per Dingus)
   356    MT("listBogus",
   357       "foo",
   358       "1. bar",
   359       "2. hello");
   360  
   361    // List after hr
   362    MT("listAfterHr",
   363       "[hr ---]",
   364       "[variable-2 - bar]");
   365  
   366    // List after header
   367    MT("listAfterHeader",
   368       "[header&header-1 # foo]",
   369       "[variable-2 - bar]");
   370  
   371    // hr after list
   372    MT("hrAfterList",
   373       "[variable-2 - foo]",
   374       "[hr -----]");
   375  
   376    // Formatting in lists (*)
   377    MT("listAsteriskFormatting",
   378       "[variable-2 * ][variable-2&em *foo*][variable-2  bar]",
   379       "[variable-2 * ][variable-2&strong **foo**][variable-2  bar]",
   380       "[variable-2 * ][variable-2&strong **][variable-2&em&strong *foo**][variable-2&em *][variable-2  bar]",
   381       "[variable-2 * ][variable-2&comment `foo`][variable-2  bar]");
   382  
   383    // Formatting in lists (+)
   384    MT("listPlusFormatting",
   385       "[variable-2 + ][variable-2&em *foo*][variable-2  bar]",
   386       "[variable-2 + ][variable-2&strong **foo**][variable-2  bar]",
   387       "[variable-2 + ][variable-2&strong **][variable-2&em&strong *foo**][variable-2&em *][variable-2  bar]",
   388       "[variable-2 + ][variable-2&comment `foo`][variable-2  bar]");
   389  
   390    // Formatting in lists (-)
   391    MT("listDashFormatting",
   392       "[variable-2 - ][variable-2&em *foo*][variable-2  bar]",
   393       "[variable-2 - ][variable-2&strong **foo**][variable-2  bar]",
   394       "[variable-2 - ][variable-2&strong **][variable-2&em&strong *foo**][variable-2&em *][variable-2  bar]",
   395       "[variable-2 - ][variable-2&comment `foo`][variable-2  bar]");
   396  
   397    // Formatting in lists (1.)
   398    MT("listNumberFormatting",
   399       "[variable-2 1. ][variable-2&em *foo*][variable-2  bar]",
   400       "[variable-2 2. ][variable-2&strong **foo**][variable-2  bar]",
   401       "[variable-2 3. ][variable-2&strong **][variable-2&em&strong *foo**][variable-2&em *][variable-2  bar]",
   402       "[variable-2 4. ][variable-2&comment `foo`][variable-2  bar]");
   403  
   404    // Paragraph lists
   405    MT("listParagraph",
   406       "[variable-2 * foo]",
   407       "",
   408       "[variable-2 * bar]");
   409  
   410    // Multi-paragraph lists
   411    //
   412    // 4 spaces
   413    MT("listMultiParagraph",
   414       "[variable-2 * foo]",
   415       "",
   416       "[variable-2 * bar]",
   417       "",
   418       "    [variable-2 hello]");
   419  
   420    // 4 spaces, extra blank lines (should still be list, per Dingus)
   421    MT("listMultiParagraphExtra",
   422       "[variable-2 * foo]",
   423       "",
   424       "[variable-2 * bar]",
   425       "",
   426       "",
   427       "    [variable-2 hello]");
   428  
   429    // 4 spaces, plus 1 space (should still be list, per Dingus)
   430    MT("listMultiParagraphExtraSpace",
   431       "[variable-2 * foo]",
   432       "",
   433       "[variable-2 * bar]",
   434       "",
   435       "     [variable-2 hello]",
   436       "",
   437       "    [variable-2 world]");
   438  
   439    // 1 tab
   440    MT("listTab",
   441       "[variable-2 * foo]",
   442       "",
   443       "[variable-2 * bar]",
   444       "",
   445       "\t[variable-2 hello]");
   446  
   447    // No indent
   448    MT("listNoIndent",
   449       "[variable-2 * foo]",
   450       "",
   451       "[variable-2 * bar]",
   452       "",
   453       "hello");
   454  
   455    // Blockquote
   456    MT("blockquote",
   457       "[variable-2 * foo]",
   458       "",
   459       "[variable-2 * bar]",
   460       "",
   461       "    [variable-2&quote&quote-1 > hello]");
   462  
   463    // Code block
   464    MT("blockquoteCode",
   465       "[variable-2 * foo]",
   466       "",
   467       "[variable-2 * bar]",
   468       "",
   469       "        [comment > hello]",
   470       "",
   471       "    [variable-2 world]");
   472  
   473    // Code block followed by text
   474    MT("blockquoteCodeText",
   475       "[variable-2 * foo]",
   476       "",
   477       "    [variable-2 bar]",
   478       "",
   479       "        [comment hello]",
   480       "",
   481       "    [variable-2 world]");
   482  
   483    // Nested list
   484  
   485    MT("listAsteriskNested",
   486       "[variable-2 * foo]",
   487       "",
   488       "    [variable-3 * bar]");
   489  
   490    MT("listPlusNested",
   491       "[variable-2 + foo]",
   492       "",
   493       "    [variable-3 + bar]");
   494  
   495    MT("listDashNested",
   496       "[variable-2 - foo]",
   497       "",
   498       "    [variable-3 - bar]");
   499  
   500    MT("listNumberNested",
   501       "[variable-2 1. foo]",
   502       "",
   503       "    [variable-3 2. bar]");
   504  
   505    MT("listMixed",
   506       "[variable-2 * foo]",
   507       "",
   508       "    [variable-3 + bar]",
   509       "",
   510       "        [keyword - hello]",
   511       "",
   512       "            [variable-2 1. world]");
   513  
   514    MT("listBlockquote",
   515       "[variable-2 * foo]",
   516       "",
   517       "    [variable-3 + bar]",
   518       "",
   519       "        [quote&quote-1&variable-3 > hello]");
   520  
   521    MT("listCode",
   522       "[variable-2 * foo]",
   523       "",
   524       "    [variable-3 + bar]",
   525       "",
   526       "            [comment hello]");
   527  
   528    // Code with internal indentation
   529    MT("listCodeIndentation",
   530       "[variable-2 * foo]",
   531       "",
   532       "        [comment bar]",
   533       "            [comment hello]",
   534       "                [comment world]",
   535       "        [comment foo]",
   536       "    [variable-2 bar]");
   537  
   538    // List nesting edge cases
   539    MT("listNested",
   540      "[variable-2 * foo]",
   541      "",
   542      "    [variable-3 * bar]",
   543      "",
   544      "       [variable-3 hello]"
   545    );
   546    MT("listNested",
   547      "[variable-2 * foo]",
   548      "",
   549      "    [variable-3 * bar]",
   550      "",
   551      "      [keyword * foo]"
   552    );
   553  
   554    // Code followed by text
   555    MT("listCodeText",
   556       "[variable-2 * foo]",
   557       "",
   558       "        [comment bar]",
   559       "",
   560       "hello");
   561  
   562    // Following tests directly from official Markdown documentation
   563    // http://daringfireball.net/projects/markdown/syntax#hr
   564  
   565    MT("hrSpace",
   566       "[hr * * *]");
   567  
   568    MT("hr",
   569       "[hr ***]");
   570  
   571    MT("hrLong",
   572       "[hr *****]");
   573  
   574    MT("hrSpaceDash",
   575       "[hr - - -]");
   576  
   577    MT("hrDashLong",
   578       "[hr ---------------------------------------]");
   579  
   580    // Inline link with title
   581    MT("linkTitle",
   582       "[link [[foo]]][string&url (http://example.com/ \"bar\")] hello");
   583  
   584    // Inline link without title
   585    MT("linkNoTitle",
   586       "[link [[foo]]][string&url (http://example.com/)] bar");
   587  
   588    // Inline link with image
   589    MT("linkImage",
   590       "[link [[][tag ![[foo]]][string&url (http://example.com/)][link ]]][string&url (http://example.com/)] bar");
   591  
   592    // Inline link with Em
   593    MT("linkEm",
   594       "[link [[][link&em *foo*][link ]]][string&url (http://example.com/)] bar");
   595  
   596    // Inline link with Strong
   597    MT("linkStrong",
   598       "[link [[][link&strong **foo**][link ]]][string&url (http://example.com/)] bar");
   599  
   600    // Inline link with EmStrong
   601    MT("linkEmStrong",
   602       "[link [[][link&strong **][link&em&strong *foo**][link&em *][link ]]][string&url (http://example.com/)] bar");
   603  
   604    // Image with title
   605    MT("imageTitle",
   606       "[tag ![[foo]]][string&url (http://example.com/ \"bar\")] hello");
   607  
   608    // Image without title
   609    MT("imageNoTitle",
   610       "[tag ![[foo]]][string&url (http://example.com/)] bar");
   611  
   612    // Image with asterisks
   613    MT("imageAsterisks",
   614       "[tag ![[*foo*]]][string&url (http://example.com/)] bar");
   615  
   616    // Not a link. Should be normal text due to square brackets being used
   617    // regularly in text, especially in quoted material, and no space is allowed
   618    // between square brackets and parentheses (per Dingus).
   619    MT("notALink",
   620       "[[foo]] (bar)");
   621  
   622    // Reference-style links
   623    MT("linkReference",
   624       "[link [[foo]]][string&url [[bar]]] hello");
   625  
   626    // Reference-style links with Em
   627    MT("linkReferenceEm",
   628       "[link [[][link&em *foo*][link ]]][string&url [[bar]]] hello");
   629  
   630    // Reference-style links with Strong
   631    MT("linkReferenceStrong",
   632       "[link [[][link&strong **foo**][link ]]][string&url [[bar]]] hello");
   633  
   634    // Reference-style links with EmStrong
   635    MT("linkReferenceEmStrong",
   636       "[link [[][link&strong **][link&em&strong *foo**][link&em *][link ]]][string&url [[bar]]] hello");
   637  
   638    // Reference-style links with optional space separator (per docuentation)
   639    // "You can optionally use a space to separate the sets of brackets"
   640    MT("linkReferenceSpace",
   641       "[link [[foo]]] [string&url [[bar]]] hello");
   642  
   643    // Should only allow a single space ("...use *a* space...")
   644    MT("linkReferenceDoubleSpace",
   645       "[[foo]]  [[bar]] hello");
   646  
   647    // Reference-style links with implicit link name
   648    MT("linkImplicit",
   649       "[link [[foo]]][string&url [[]]] hello");
   650  
   651    // @todo It would be nice if, at some point, the document was actually
   652    // checked to see if the referenced link exists
   653  
   654    // Link label, for reference-style links (taken from documentation)
   655  
   656    MT("labelNoTitle",
   657       "[link [[foo]]:] [string&url http://example.com/]");
   658  
   659    MT("labelIndented",
   660       "   [link [[foo]]:] [string&url http://example.com/]");
   661  
   662    MT("labelSpaceTitle",
   663       "[link [[foo bar]]:] [string&url http://example.com/ \"hello\"]");
   664  
   665    MT("labelDoubleTitle",
   666       "[link [[foo bar]]:] [string&url http://example.com/ \"hello\"] \"world\"");
   667  
   668    MT("labelTitleDoubleQuotes",
   669       "[link [[foo]]:] [string&url http://example.com/  \"bar\"]");
   670  
   671    MT("labelTitleSingleQuotes",
   672       "[link [[foo]]:] [string&url http://example.com/  'bar']");
   673  
   674    MT("labelTitleParenthese",
   675       "[link [[foo]]:] [string&url http://example.com/  (bar)]");
   676  
   677    MT("labelTitleInvalid",
   678       "[link [[foo]]:] [string&url http://example.com/] bar");
   679  
   680    MT("labelLinkAngleBrackets",
   681       "[link [[foo]]:] [string&url <http://example.com/>  \"bar\"]");
   682  
   683    MT("labelTitleNextDoubleQuotes",
   684       "[link [[foo]]:] [string&url http://example.com/]",
   685       "[string \"bar\"] hello");
   686  
   687    MT("labelTitleNextSingleQuotes",
   688       "[link [[foo]]:] [string&url http://example.com/]",
   689       "[string 'bar'] hello");
   690  
   691    MT("labelTitleNextParenthese",
   692       "[link [[foo]]:] [string&url http://example.com/]",
   693       "[string (bar)] hello");
   694  
   695    MT("labelTitleNextMixed",
   696       "[link [[foo]]:] [string&url http://example.com/]",
   697       "(bar\" hello");
   698  
   699    MT("labelEscape",
   700       "[link [[foo \\]] ]]:] [string&url http://example.com/]");
   701  
   702    MT("labelEscapeColon",
   703       "[link [[foo \\]]: bar]]:] [string&url http://example.com/]");
   704  
   705    MT("labelEscapeEnd",
   706       "[[foo\\]]: http://example.com/");
   707  
   708    MT("linkWeb",
   709       "[link <http://example.com/>] foo");
   710  
   711    MT("linkWebDouble",
   712       "[link <http://example.com/>] foo [link <http://example.com/>]");
   713  
   714    MT("linkEmail",
   715       "[link <user@example.com>] foo");
   716  
   717    MT("linkEmailDouble",
   718       "[link <user@example.com>] foo [link <user@example.com>]");
   719  
   720    MT("emAsterisk",
   721       "[em *foo*] bar");
   722  
   723    MT("emUnderscore",
   724       "[em _foo_] bar");
   725  
   726    MT("emInWordAsterisk",
   727       "foo[em *bar*]hello");
   728  
   729    MT("emInWordUnderscore",
   730       "foo[em _bar_]hello");
   731  
   732    // Per documentation: "...surround an * or _ with spaces, it’ll be
   733    // treated as a literal asterisk or underscore."
   734  
   735    MT("emEscapedBySpaceIn",
   736       "foo [em _bar _ hello_] world");
   737  
   738    MT("emEscapedBySpaceOut",
   739       "foo _ bar[em _hello_]world");
   740  
   741    MT("emEscapedByNewline",
   742       "foo",
   743       "_ bar[em _hello_]world");
   744  
   745    // Unclosed emphasis characters
   746    // Instead of simply marking as EM / STRONG, it would be nice to have an
   747    // incomplete flag for EM and STRONG, that is styled slightly different.
   748    MT("emIncompleteAsterisk",
   749       "foo [em *bar]");
   750  
   751    MT("emIncompleteUnderscore",
   752       "foo [em _bar]");
   753  
   754    MT("strongAsterisk",
   755       "[strong **foo**] bar");
   756  
   757    MT("strongUnderscore",
   758       "[strong __foo__] bar");
   759  
   760    MT("emStrongAsterisk",
   761       "[em *foo][em&strong **bar*][strong hello**] world");
   762  
   763    MT("emStrongUnderscore",
   764       "[em _foo][em&strong __bar_][strong hello__] world");
   765  
   766    // "...same character must be used to open and close an emphasis span.""
   767    MT("emStrongMixed",
   768       "[em _foo][em&strong **bar*hello__ world]");
   769  
   770    MT("emStrongMixed",
   771       "[em *foo][em&strong __bar_hello** world]");
   772  
   773    // These characters should be escaped:
   774    // \   backslash
   775    // `   backtick
   776    // *   asterisk
   777    // _   underscore
   778    // {}  curly braces
   779    // []  square brackets
   780    // ()  parentheses
   781    // #   hash mark
   782    // +   plus sign
   783    // -   minus sign (hyphen)
   784    // .   dot
   785    // !   exclamation mark
   786  
   787    MT("escapeBacktick",
   788       "foo \\`bar\\`");
   789  
   790    MT("doubleEscapeBacktick",
   791       "foo \\\\[comment `bar\\\\`]");
   792  
   793    MT("escapeAsterisk",
   794       "foo \\*bar\\*");
   795  
   796    MT("doubleEscapeAsterisk",
   797       "foo \\\\[em *bar\\\\*]");
   798  
   799    MT("escapeUnderscore",
   800       "foo \\_bar\\_");
   801  
   802    MT("doubleEscapeUnderscore",
   803       "foo \\\\[em _bar\\\\_]");
   804  
   805    MT("escapeHash",
   806       "\\# foo");
   807  
   808    MT("doubleEscapeHash",
   809       "\\\\# foo");
   810  
   811    MT("escapeNewline",
   812       "\\",
   813       "[em *foo*]");
   814  
   815    // Class override tests
   816    TokenTypeOverrideTest("overrideHeader1",
   817      "[override-header&override-header-1 # Foo]");
   818  
   819    TokenTypeOverrideTest("overrideHeader2",
   820      "[override-header&override-header-2 ## Foo]");
   821  
   822    TokenTypeOverrideTest("overrideHeader3",
   823      "[override-header&override-header-3 ### Foo]");
   824  
   825    TokenTypeOverrideTest("overrideHeader4",
   826      "[override-header&override-header-4 #### Foo]");
   827  
   828    TokenTypeOverrideTest("overrideHeader5",
   829      "[override-header&override-header-5 ##### Foo]");
   830  
   831    TokenTypeOverrideTest("overrideHeader6",
   832      "[override-header&override-header-6 ###### Foo]");
   833  
   834    TokenTypeOverrideTest("overrideCode",
   835      "[override-code `foo`]");
   836  
   837    TokenTypeOverrideTest("overrideCodeBlock",
   838      "[override-code ```]",
   839      "[override-code foo]",
   840      "[override-code ```]");
   841  
   842    TokenTypeOverrideTest("overrideQuote",
   843      "[override-quote&override-quote-1 > foo]",
   844      "[override-quote&override-quote-1 > bar]");
   845  
   846    TokenTypeOverrideTest("overrideQuoteNested",
   847      "[override-quote&override-quote-1 > foo]",
   848      "[override-quote&override-quote-1 >][override-quote&override-quote-2 > bar]",
   849      "[override-quote&override-quote-1 >][override-quote&override-quote-2 >][override-quote&override-quote-3 > baz]");
   850  
   851    TokenTypeOverrideTest("overrideLists",
   852      "[override-list1 - foo]",
   853      "",
   854      "    [override-list2 + bar]",
   855      "",
   856      "        [override-list3 * baz]",
   857      "",
   858      "            [override-list1 1. qux]",
   859      "",
   860      "                [override-list2 - quux]");
   861  
   862    TokenTypeOverrideTest("overrideHr",
   863      "[override-hr * * *]");
   864  
   865    TokenTypeOverrideTest("overrideImage",
   866      "[override-image ![[foo]]][override-link-href&url (http://example.com/)]")
   867  
   868    TokenTypeOverrideTest("overrideLinkText",
   869      "[override-link-text [[foo]]][override-link-href&url (http://example.com)]");
   870  
   871    TokenTypeOverrideTest("overrideLinkEmailAndInline",
   872      "[override-link-email <][override-link-inline foo@example.com>]");
   873  
   874    TokenTypeOverrideTest("overrideEm",
   875      "[override-em *foo*]");
   876  
   877    TokenTypeOverrideTest("overrideStrong",
   878      "[override-strong **foo**]");
   879  
   880    TokenTypeOverrideTest("overrideStrikethrough",
   881      "[override-strikethrough ~~foo~~]");
   882  
   883    FormatTokenTypeOverrideTest("overrideFormatting",
   884      "[override-formatting-escape \\*]");
   885  
   886    // Tests to make sure GFM-specific things aren't getting through
   887  
   888    MT("taskList",
   889       "[variable-2 * [ ]] bar]");
   890  
   891    MT("noFencedCodeBlocks",
   892       "~~~",
   893       "foo",
   894       "~~~");
   895  
   896    FencedTest("fencedCodeBlocks",
   897       "[comment ```]",
   898       "[comment foo]",
   899       "[comment ```]",
   900       "bar");
   901  
   902    FencedTest("fencedCodeBlocksMultipleChars",
   903       "[comment `````]",
   904       "[comment foo]",
   905       "[comment ```]",
   906       "[comment foo]",
   907       "[comment `````]",
   908       "bar");
   909  
   910    FencedTest("fencedCodeBlocksTildes",
   911       "[comment ~~~]",
   912       "[comment foo]",
   913       "[comment ~~~]",
   914       "bar");
   915  
   916    FencedTest("fencedCodeBlocksTildesMultipleChars",
   917       "[comment ~~~~~]",
   918       "[comment ~~~]",
   919       "[comment foo]",
   920       "[comment ~~~~~]",
   921       "bar");
   922  
   923    FencedTest("fencedCodeBlocksMultipleChars",
   924       "[comment `````]",
   925       "[comment foo]",
   926       "[comment ```]",
   927       "[comment foo]",
   928       "[comment `````]",
   929       "bar");
   930  
   931    FencedTest("fencedCodeBlocksMixed",
   932       "[comment ~~~]",
   933       "[comment ```]",
   934       "[comment foo]",
   935       "[comment ~~~]",
   936       "bar");
   937  
   938    // Tests that require XML mode
   939  
   940    MT("xmlMode",
   941       "[tag&bracket <][tag div][tag&bracket >]",
   942       "*foo*",
   943       "[tag&bracket <][tag http://github.com][tag&bracket />]",
   944       "[tag&bracket </][tag div][tag&bracket >]",
   945       "[link <http://github.com/>]");
   946  
   947    MT("xmlModeWithMarkdownInside",
   948       "[tag&bracket <][tag div] [attribute markdown]=[string 1][tag&bracket >]",
   949       "[em *foo*]",
   950       "[link <http://github.com/>]",
   951       "[tag </div>]",
   952       "[link <http://github.com/>]",
   953       "[tag&bracket <][tag div][tag&bracket >]",
   954       "[tag&bracket </][tag div][tag&bracket >]");
   955  
   956  })();