// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE
(function() {
  var mode = CodeMirror.getMode({tabSize: 4}, "markdown");
  function MT(name) { test.mode(name, mode, Array.prototype.slice.call(arguments, 1)); }
  var modeHighlightFormatting = CodeMirror.getMode({tabSize: 4}, {name: "markdown", highlightFormatting: true});
  function FT(name) { test.mode(name, modeHighlightFormatting, Array.prototype.slice.call(arguments, 1)); }
  FT("formatting_emAsterisk",
     "[em&formatting&formatting-em *][em foo][em&formatting&formatting-em *]");
  FT("formatting_emUnderscore",
     "[em&formatting&formatting-em _][em foo][em&formatting&formatting-em _]");
  FT("formatting_strongAsterisk",
     "[strong&formatting&formatting-strong **][strong foo][strong&formatting&formatting-strong **]");
  FT("formatting_strongUnderscore",
     "[strong&formatting&formatting-strong __][strong foo][strong&formatting&formatting-strong __]");
  FT("formatting_codeBackticks",
     "[comment&formatting&formatting-code `][comment foo][comment&formatting&formatting-code `]");
  FT("formatting_doubleBackticks",
     "[comment&formatting&formatting-code ``][comment foo ` bar][comment&formatting&formatting-code ``]");
  FT("formatting_atxHeader",
     "[header&header-1&formatting&formatting-header&formatting-header-1 # ][header&header-1 foo # bar ][header&header-1&formatting&formatting-header&formatting-header-1 #]");
  FT("formatting_setextHeader",
     "foo",
     "[header&header-1&formatting&formatting-header&formatting-header-1 =]");
  FT("formatting_blockquote",
     "[quote"e-1&formatting&formatting-quote&formatting-quote-1 > ][quote"e-1 foo]");
  FT("formatting_list",
     "[variable-2&formatting&formatting-list&formatting-list-ul - ][variable-2 foo]");
  FT("formatting_list",
     "[variable-2&formatting&formatting-list&formatting-list-ol 1. ][variable-2 foo]");
  FT("formatting_link",
     "[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 )]");
  FT("formatting_linkReference",
     "[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 ]]]",
     "[link&formatting&formatting-link [][link bar][link&formatting&formatting-link ]]:] [string&url http://example.com/]");
  FT("formatting_linkWeb",
     "[link&formatting&formatting-link <][link http://example.com/][link&formatting&formatting-link >]");
  FT("formatting_linkEmail",
     "[link&formatting&formatting-link <][link user@example.com][link&formatting&formatting-link >]");
  FT("formatting_escape",
     "[formatting-escape \\*]");
  MT("plainText",
     "foo");
  // Don't style single trailing space
  MT("trailingSpace1",
     "foo ");
  // Two or more trailing spaces should be styled with line break character
  MT("trailingSpace2",
     "foo[trailing-space-a  ][trailing-space-new-line  ]");
  MT("trailingSpace3",
     "foo[trailing-space-a  ][trailing-space-b  ][trailing-space-new-line  ]");
  MT("trailingSpace4",
     "foo[trailing-space-a  ][trailing-space-b  ][trailing-space-a  ][trailing-space-new-line  ]");
  // Code blocks using 4 spaces (regardless of CodeMirror.tabSize value)
  MT("codeBlocksUsing4Spaces",
     "    [comment foo]");
  // Code blocks using 4 spaces with internal indentation
  MT("codeBlocksUsing4SpacesIndentation",
     "    [comment bar]",
     "        [comment hello]",
     "            [comment world]",
     "    [comment foo]",
     "bar");
  // Code blocks should end even after extra indented lines
  MT("codeBlocksWithTrailingIndentedLine",
     "    [comment foo]",
     "        [comment bar]",
     "    [comment baz]",
     "    ",
     "hello");
  // Code blocks using 1 tab (regardless of CodeMirror.indentWithTabs value)
  MT("codeBlocksUsing1Tab",
     "\t[comment foo]");
  // No code blocks directly after paragraph
  // http://spec.commonmark.org/0.19/#example-65
  MT("noCodeBlocksAfterParagraph",
     "Foo",
     "    Bar");
  // Inline code using backticks
  MT("inlineCodeUsingBackticks",
     "foo [comment `bar`]");
  // Block code using single backtick (shouldn't work)
  MT("blockCodeSingleBacktick",
     "[comment `]",
     "foo",
     "[comment `]");
  // Unclosed backticks
  // Instead of simply marking as CODE, it would be nice to have an
  // incomplete flag for CODE, that is styled slightly different.
  MT("unclosedBackticks",
     "foo [comment `bar]");
  // Per documentation: "To include a literal backtick character within a
  // code span, you can use multiple backticks as the opening and closing
  // delimiters"
  MT("doubleBackticks",
     "[comment ``foo ` bar``]");
  // Tests based on Dingus
  // http://daringfireball.net/projects/markdown/dingus
  //
  // Multiple backticks within an inline code block
  MT("consecutiveBackticks",
     "[comment `foo```bar`]");
  // Multiple backticks within an inline code block with a second code block
  MT("consecutiveBackticks",
     "[comment `foo```bar`] hello [comment `world`]");
  // Unclosed with several different groups of backticks
  MT("unclosedBackticks",
     "[comment ``foo ``` bar` hello]");
  // Closed with several different groups of backticks
  MT("closedBackticks",
     "[comment ``foo ``` bar` hello``] world");
  // atx headers
  // http://daringfireball.net/projects/markdown/syntax#header
  MT("atxH1",
     "[header&header-1 # foo]");
  MT("atxH2",
     "[header&header-2 ## foo]");
  MT("atxH3",
     "[header&header-3 ### foo]");
  MT("atxH4",
     "[header&header-4 #### foo]");
  MT("atxH5",
     "[header&header-5 ##### foo]");
  MT("atxH6",
     "[header&header-6 ###### foo]");
  // http://spec.commonmark.org/0.19/#example-24
  MT("noAtxH7",
     "####### foo");
  // http://spec.commonmark.org/0.19/#example-25
  MT("noAtxH1WithoutSpace",
     "#5 bolt");
  // Inline styles should be parsed inside headers
  MT("atxH1inline",
     "[header&header-1 # foo ][header&header-1&em *bar*]");
  // Setext headers - H1, H2
  // Per documentation, "Any number of underlining =’s or -’s will work."
  // http://daringfireball.net/projects/markdown/syntax#header
  // Ideally, the text would be marked as `header` as well, but this is
  // not really feasible at the moment. So, instead, we're testing against
  // what works today, to avoid any regressions.
  //
  // Check if single underlining = works
  MT("setextH1",
     "foo",
     "[header&header-1 =]");
  // Check if 3+ ='s work
  MT("setextH1",
     "foo",
     "[header&header-1 ===]");
  // Check if single underlining - works
  MT("setextH2",
     "foo",
     "[header&header-2 -]");
  // Check if 3+ -'s work
  MT("setextH2",
     "foo",
     "[header&header-2 ---]");
  // http://spec.commonmark.org/0.19/#example-45
  MT("setextH2AllowSpaces",
     "foo",
     "   [header&header-2 ----      ]");
  // http://spec.commonmark.org/0.19/#example-44
  MT("noSetextAfterIndentedCodeBlock",
     "     [comment foo]",
     "[hr ---]");
  // http://spec.commonmark.org/0.19/#example-51
  MT("noSetextAfterQuote",
     "[quote"e-1 > foo]",
     "[hr ---]");
  MT("noSetextAfterList",
     "[variable-2 - foo]",
     "[hr ---]");
  // Single-line blockquote with trailing space
  MT("blockquoteSpace",
     "[quote"e-1 > foo]");
  // Single-line blockquote
  MT("blockquoteNoSpace",
     "[quote"e-1 >foo]");
  // No blank line before blockquote
  MT("blockquoteNoBlankLine",
     "foo",
     "[quote"e-1 > bar]");
  // Nested blockquote
  MT("blockquoteSpace",
     "[quote"e-1 > foo]",
     "[quote"e-1 >][quote"e-2 > foo]",
     "[quote"e-1 >][quote"e-2 >][quote"e-3 > foo]");
  // Single-line blockquote followed by normal paragraph
  MT("blockquoteThenParagraph",
     "[quote"e-1 >foo]",
     "",
     "bar");
  // Multi-line blockquote (lazy mode)
  MT("multiBlockquoteLazy",
     "[quote"e-1 >foo]",
     "[quote"e-1 bar]");
  // Multi-line blockquote followed by normal paragraph (lazy mode)
  MT("multiBlockquoteLazyThenParagraph",
     "[quote"e-1 >foo]",
     "[quote"e-1 bar]",
     "",
     "hello");
  // Multi-line blockquote (non-lazy mode)
  MT("multiBlockquote",
     "[quote"e-1 >foo]",
     "[quote"e-1 >bar]");
  // Multi-line blockquote followed by normal paragraph (non-lazy mode)
  MT("multiBlockquoteThenParagraph",
     "[quote"e-1 >foo]",
     "[quote"e-1 >bar]",
     "",
     "hello");
  // Header with leading space after continued blockquote (#3287, negative indentation)
  MT("headerAfterContinuedBlockquote",
     "[quote"e-1 > foo]",
     "[quote"e-1 bar]",
     "",
     " [header&header-1 # hello]");
  // Check list types
  MT("listAsterisk",
     "foo",
     "bar",
     "",
     "[variable-2 * foo]",
     "[variable-2 * bar]");
  MT("listPlus",
     "foo",
     "bar",
     "",
     "[variable-2 + foo]",
     "[variable-2 + bar]");
  MT("listDash",
     "foo",
     "bar",
     "",
     "[variable-2 - foo]",
     "[variable-2 - bar]");
  MT("listNumber",
     "foo",
     "bar",
     "",
     "[variable-2 1. foo]",
     "[variable-2 2. bar]");
  // Lists require a preceding blank line (per Dingus)
  MT("listBogus",
     "foo",
     "1. bar",
     "2. hello");
  // List after hr
  MT("listAfterHr",
     "[hr ---]",
     "[variable-2 - bar]");
  // List after header
  MT("listAfterHeader",
     "[header&header-1 # foo]",
     "[variable-2 - bar]");
  // hr after list
  MT("hrAfterList",
     "[variable-2 - foo]",
     "[hr -----]");
  // Formatting in lists (*)
  MT("listAsteriskFormatting",
     "[variable-2 * ][variable-2&em *foo*][variable-2  bar]",
     "[variable-2 * ][variable-2&strong **foo**][variable-2  bar]",
     "[variable-2 * ][variable-2&strong **][variable-2&em&strong *foo**][variable-2&em *][variable-2  bar]",
     "[variable-2 * ][variable-2&comment `foo`][variable-2  bar]");
  // Formatting in lists (+)
  MT("listPlusFormatting",
     "[variable-2 + ][variable-2&em *foo*][variable-2  bar]",
     "[variable-2 + ][variable-2&strong **foo**][variable-2  bar]",
     "[variable-2 + ][variable-2&strong **][variable-2&em&strong *foo**][variable-2&em *][variable-2  bar]",
     "[variable-2 + ][variable-2&comment `foo`][variable-2  bar]");
  // Formatting in lists (-)
  MT("listDashFormatting",
     "[variable-2 - ][variable-2&em *foo*][variable-2  bar]",
     "[variable-2 - ][variable-2&strong **foo**][variable-2  bar]",
     "[variable-2 - ][variable-2&strong **][variable-2&em&strong *foo**][variable-2&em *][variable-2  bar]",
     "[variable-2 - ][variable-2&comment `foo`][variable-2  bar]");
  // Formatting in lists (1.)
  MT("listNumberFormatting",
     "[variable-2 1. ][variable-2&em *foo*][variable-2  bar]",
     "[variable-2 2. ][variable-2&strong **foo**][variable-2  bar]",
     "[variable-2 3. ][variable-2&strong **][variable-2&em&strong *foo**][variable-2&em *][variable-2  bar]",
     "[variable-2 4. ][variable-2&comment `foo`][variable-2  bar]");
  // Paragraph lists
  MT("listParagraph",
     "[variable-2 * foo]",
     "",
     "[variable-2 * bar]");
  // Multi-paragraph lists
  //
  // 4 spaces
  MT("listMultiParagraph",
     "[variable-2 * foo]",
     "",
     "[variable-2 * bar]",
     "",
     "    [variable-2 hello]");
  // 4 spaces, extra blank lines (should still be list, per Dingus)
  MT("listMultiParagraphExtra",
     "[variable-2 * foo]",
     "",
     "[variable-2 * bar]",
     "",
     "",
     "    [variable-2 hello]");
  // 4 spaces, plus 1 space (should still be list, per Dingus)
  MT("listMultiParagraphExtraSpace",
     "[variable-2 * foo]",
     "",
     "[variable-2 * bar]",
     "",
     "     [variable-2 hello]",
     "",
     "    [variable-2 world]");
  // 1 tab
  MT("listTab",
     "[variable-2 * foo]",
     "",
     "[variable-2 * bar]",
     "",
     "\t[variable-2 hello]");
  // No indent
  MT("listNoIndent",
     "[variable-2 * foo]",
     "",
     "[variable-2 * bar]",
     "",
     "hello");
  // Blockquote
  MT("blockquote",
     "[variable-2 * foo]",
     "",
     "[variable-2 * bar]",
     "",
     "    [variable-2"e"e-1 > hello]");
  // Code block
  MT("blockquoteCode",
     "[variable-2 * foo]",
     "",
     "[variable-2 * bar]",
     "",
     "        [comment > hello]",
     "",
     "    [variable-2 world]");
  // Code block followed by text
  MT("blockquoteCodeText",
     "[variable-2 * foo]",
     "",
     "    [variable-2 bar]",
     "",
     "        [comment hello]",
     "",
     "    [variable-2 world]");
  // Nested list
  MT("listAsteriskNested",
     "[variable-2 * foo]",
     "",
     "    [variable-3 * bar]");
  MT("listPlusNested",
     "[variable-2 + foo]",
     "",
     "    [variable-3 + bar]");
  MT("listDashNested",
     "[variable-2 - foo]",
     "",
     "    [variable-3 - bar]");
  MT("listNumberNested",
     "[variable-2 1. foo]",
     "",
     "    [variable-3 2. bar]");
  MT("listMixed",
     "[variable-2 * foo]",
     "",
     "    [variable-3 + bar]",
     "",
     "        [keyword - hello]",
     "",
     "            [variable-2 1. world]");
  MT("listBlockquote",
     "[variable-2 * foo]",
     "",
     "    [variable-3 + bar]",
     "",
     "        [quote"e-1&variable-3 > hello]");
  MT("listCode",
     "[variable-2 * foo]",
     "",
     "    [variable-3 + bar]",
     "",
     "            [comment hello]");
  // Code with internal indentation
  MT("listCodeIndentation",
     "[variable-2 * foo]",
     "",
     "        [comment bar]",
     "            [comment hello]",
     "                [comment world]",
     "        [comment foo]",
     "    [variable-2 bar]");
  // List nesting edge cases
  MT("listNested",
    "[variable-2 * foo]",
    "",
    "    [variable-3 * bar]",
    "",
    "       [variable-2 hello]"
  );
  MT("listNested",
    "[variable-2 * foo]",
    "",
    "    [variable-3 * bar]",
    "",
    "      [variable-3 * foo]"
  );
  // Code followed by text
  MT("listCodeText",
     "[variable-2 * foo]",
     "",
     "        [comment bar]",
     "",
     "hello");
  // Following tests directly from official Markdown documentation
  // http://daringfireball.net/projects/markdown/syntax#hr
  MT("hrSpace",
     "[hr * * *]");
  MT("hr",
     "[hr ***]");
  MT("hrLong",
     "[hr *****]");
  MT("hrSpaceDash",
     "[hr - - -]");
  MT("hrDashLong",
     "[hr ---------------------------------------]");
  // Inline link with title
  MT("linkTitle",
     "[link [[foo]]][string&url (http://example.com/ \"bar\")] hello");
  // Inline link without title
  MT("linkNoTitle",
     "[link [[foo]]][string&url (http://example.com/)] bar");
  // Inline link with image
  MT("linkImage",
     "[link [[][tag ![[foo]]][string&url (http://example.com/)][link ]]][string&url (http://example.com/)] bar");
  // Inline link with Em
  MT("linkEm",
     "[link [[][link&em *foo*][link ]]][string&url (http://example.com/)] bar");
  // Inline link with Strong
  MT("linkStrong",
     "[link [[][link&strong **foo**][link ]]][string&url (http://example.com/)] bar");
  // Inline link with EmStrong
  MT("linkEmStrong",
     "[link [[][link&strong **][link&em&strong *foo**][link&em *][link ]]][string&url (http://example.com/)] bar");
  // Image with title
  MT("imageTitle",
     "[tag ![[foo]]][string&url (http://example.com/ \"bar\")] hello");
  // Image without title
  MT("imageNoTitle",
     "[tag ![[foo]]][string&url (http://example.com/)] bar");
  // Image with asterisks
  MT("imageAsterisks",
     "[tag ![[*foo*]]][string&url (http://example.com/)] bar");
  // Not a link. Should be normal text due to square brackets being used
  // regularly in text, especially in quoted material, and no space is allowed
  // between square brackets and parentheses (per Dingus).
  MT("notALink",
     "[[foo]] (bar)");
  // Reference-style links
  MT("linkReference",
     "[link [[foo]]][string&url [[bar]]] hello");
  // Reference-style links with Em
  MT("linkReferenceEm",
     "[link [[][link&em *foo*][link ]]][string&url [[bar]]] hello");
  // Reference-style links with Strong
  MT("linkReferenceStrong",
     "[link [[][link&strong **foo**][link ]]][string&url [[bar]]] hello");
  // Reference-style links with EmStrong
  MT("linkReferenceEmStrong",
     "[link [[][link&strong **][link&em&strong *foo**][link&em *][link ]]][string&url [[bar]]] hello");
  // Reference-style links with optional space separator (per docuentation)
  // "You can optionally use a space to separate the sets of brackets"
  MT("linkReferenceSpace",
     "[link [[foo]]] [string&url [[bar]]] hello");
  // Should only allow a single space ("...use *a* space...")
  MT("linkReferenceDoubleSpace",
     "[[foo]]  [[bar]] hello");
  // Reference-style links with implicit link name
  MT("linkImplicit",
     "[link [[foo]]][string&url [[]]] hello");
  // @todo It would be nice if, at some point, the document was actually
  // checked to see if the referenced link exists
  // Link label, for reference-style links (taken from documentation)
  MT("labelNoTitle",
     "[link [[foo]]:] [string&url http://example.com/]");
  MT("labelIndented",
     "   [link [[foo]]:] [string&url http://example.com/]");
  MT("labelSpaceTitle",
     "[link [[foo bar]]:] [string&url http://example.com/ \"hello\"]");
  MT("labelDoubleTitle",
     "[link [[foo bar]]:] [string&url http://example.com/ \"hello\"] \"world\"");
  MT("labelTitleDoubleQuotes",
     "[link [[foo]]:] [string&url http://example.com/  \"bar\"]");
  MT("labelTitleSingleQuotes",
     "[link [[foo]]:] [string&url http://example.com/  'bar']");
  MT("labelTitleParenthese",
     "[link [[foo]]:] [string&url http://example.com/  (bar)]");
  MT("labelTitleInvalid",
     "[link [[foo]]:] [string&url http://example.com/] bar");
  MT("labelLinkAngleBrackets",
     "[link [[foo]]:] [string&url   \"bar\"]");
  MT("labelTitleNextDoubleQuotes",
     "[link [[foo]]:] [string&url http://example.com/]",
     "[string \"bar\"] hello");
  MT("labelTitleNextSingleQuotes",
     "[link [[foo]]:] [string&url http://example.com/]",
     "[string 'bar'] hello");
  MT("labelTitleNextParenthese",
     "[link [[foo]]:] [string&url http://example.com/]",
     "[string (bar)] hello");
  MT("labelTitleNextMixed",
     "[link [[foo]]:] [string&url http://example.com/]",
     "(bar\" hello");
  MT("linkWeb",
     "[link ] foo");
  MT("linkWebDouble",
     "[link ] foo [link ]");
  MT("linkEmail",
     "[link ] foo");
  MT("linkEmailDouble",
     "[link ] foo [link ]");
  MT("emAsterisk",
     "[em *foo*] bar");
  MT("emUnderscore",
     "[em _foo_] bar");
  MT("emInWordAsterisk",
     "foo[em *bar*]hello");
  MT("emInWordUnderscore",
     "foo[em _bar_]hello");
  // Per documentation: "...surround an * or _ with spaces, it’ll be
  // treated as a literal asterisk or underscore."
  MT("emEscapedBySpaceIn",
     "foo [em _bar _ hello_] world");
  MT("emEscapedBySpaceOut",
     "foo _ bar[em _hello_]world");
  MT("emEscapedByNewline",
     "foo",
     "_ bar[em _hello_]world");
  // Unclosed emphasis characters
  // Instead of simply marking as EM / STRONG, it would be nice to have an
  // incomplete flag for EM and STRONG, that is styled slightly different.
  MT("emIncompleteAsterisk",
     "foo [em *bar]");
  MT("emIncompleteUnderscore",
     "foo [em _bar]");
  MT("strongAsterisk",
     "[strong **foo**] bar");
  MT("strongUnderscore",
     "[strong __foo__] bar");
  MT("emStrongAsterisk",
     "[em *foo][em&strong **bar*][strong hello**] world");
  MT("emStrongUnderscore",
     "[em _foo][em&strong __bar_][strong hello__] world");
  // "...same character must be used to open and close an emphasis span.""
  MT("emStrongMixed",
     "[em _foo][em&strong **bar*hello__ world]");
  MT("emStrongMixed",
     "[em *foo][em&strong __bar_hello** world]");
  // These characters should be escaped:
  // \   backslash
  // `   backtick
  // *   asterisk
  // _   underscore
  // {}  curly braces
  // []  square brackets
  // ()  parentheses
  // #   hash mark
  // +   plus sign
  // -   minus sign (hyphen)
  // .   dot
  // !   exclamation mark
  MT("escapeBacktick",
     "foo \\`bar\\`");
  MT("doubleEscapeBacktick",
     "foo \\\\[comment `bar\\\\`]");
  MT("escapeAsterisk",
     "foo \\*bar\\*");
  MT("doubleEscapeAsterisk",
     "foo \\\\[em *bar\\\\*]");
  MT("escapeUnderscore",
     "foo \\_bar\\_");
  MT("doubleEscapeUnderscore",
     "foo \\\\[em _bar\\\\_]");
  MT("escapeHash",
     "\\# foo");
  MT("doubleEscapeHash",
     "\\\\# foo");
  MT("escapeNewline",
     "\\",
     "[em *foo*]");
  // Tests to make sure GFM-specific things aren't getting through
  MT("taskList",
     "[variable-2 * [ ]] bar]");
  MT("fencedCodeBlocks",
     "[comment ```]",
     "foo",
     "[comment ```]");
  // Tests that require XML mode
  MT("xmlMode",
     "[tag&bracket <][tag div][tag&bracket >]",
     "*foo*",
     "[tag&bracket <][tag http://github.com][tag&bracket />]",
     "[tag&bracket ][tag div][tag&bracket >]",
     "[link ]");
  MT("xmlModeWithMarkdownInside",
     "[tag&bracket <][tag div] [attribute markdown]=[string 1][tag&bracket >]",
     "[em *foo*]",
     "[link ]",
     "[tag ]",
     "[link ]",
     "[tag&bracket <][tag div][tag&bracket >]",
     "[tag&bracket ][tag div][tag&bracket >]");
})();