Browse Source

Changes:

Moved DocNet code to its own folder
Added MarkdownDeep parser code plus tests
Migrated DocNet code to use MarkdownDeep. Not complete yet (the h2
headers aren't collected yet).
tags/0.9.0
Frans Bouma 10 years ago
parent
commit
ab4b402962
100 changed files with 9402 additions and 19 deletions
  1. +13
    -1
      Docnet.sln
  2. +6
    -0
      Themes/Default/Destination/css/theme.css
  3. +0
    -0
      src/DocNet/App.config
  4. +0
    -0
      src/DocNet/CliInput.cs
  5. +0
    -0
      src/DocNet/Config.cs
  6. +6
    -0
      src/DocNet/Docnet.csproj
  7. +0
    -0
      src/DocNet/Engine.cs
  8. +0
    -0
      src/DocNet/INavigationElement.cs
  9. +14
    -13
      src/DocNet/MarkdownSharp.cs
  10. +0
    -0
      src/DocNet/NavigatedPath.cs
  11. +0
    -0
      src/DocNet/NavigationElement.cs
  12. +0
    -0
      src/DocNet/NavigationLevel.cs
  13. +0
    -0
      src/DocNet/Program.cs
  14. +0
    -0
      src/DocNet/Properties/AssemblyInfo.cs
  15. +0
    -0
      src/DocNet/SearchIndexEntry.cs
  16. +0
    -0
      src/DocNet/SimpleNavigationElement.cs
  17. +10
    -5
      src/DocNet/Utils.cs
  18. +0
    -0
      src/DocNet/packages.config
  19. +32
    -0
      src/MarkdownDeep/Abbreviation.cs
  20. +500
    -0
      src/MarkdownDeep/Block.cs
  21. +1565
    -0
      src/MarkdownDeep/BlockProcessor.cs
  22. +32
    -0
      src/MarkdownDeep/FootnoteReference.cs
  23. +351
    -0
      src/MarkdownDeep/HtmlTag.cs
  24. +344
    -0
      src/MarkdownDeep/LinkDefinition.cs
  25. +34
    -0
      src/MarkdownDeep/LinkInfo.cs
  26. +1014
    -0
      src/MarkdownDeep/MardownDeep.cs
  27. +120
    -0
      src/MarkdownDeep/MarkdownDeep.csproj
  28. +37
    -0
      src/MarkdownDeep/Properties/AssemblyInfo.cs
  29. +1171
    -0
      src/MarkdownDeep/SpanFormatter.cs
  30. +541
    -0
      src/MarkdownDeep/StringScanner.cs
  31. +219
    -0
      src/MarkdownDeep/TableSpec.cs
  32. +93
    -0
      src/MarkdownDeep/Token.cs
  33. +495
    -0
      src/MarkdownDeep/Utils.cs
  34. +73
    -0
      src/MarkdownDeepTests/AutoHeaderIDTests.cs
  35. +44
    -0
      src/MarkdownDeepTests/AutoLinkTests.cs
  36. +26
    -0
      src/MarkdownDeepTests/BlockLevelTests.cs
  37. +163
    -0
      src/MarkdownDeepTests/BlockProcessorTests.cs
  38. +59
    -0
      src/MarkdownDeepTests/CodeSpanTests.cs
  39. +240
    -0
      src/MarkdownDeepTests/EmphasisTests.cs
  40. +63
    -0
      src/MarkdownDeepTests/EscapeCharacterTests.cs
  41. +26
    -0
      src/MarkdownDeepTests/ExtraMode.cs
  42. +26
    -0
      src/MarkdownDeepTests/GithubMode.cs
  43. +144
    -0
      src/MarkdownDeepTests/HtmlTagTests.cs
  44. +159
    -0
      src/MarkdownDeepTests/LinkAndImgTests.cs
  45. +108
    -0
      src/MarkdownDeepTests/LinkDefinitionTests.cs
  46. +473
    -0
      src/MarkdownDeepTests/MarkdownDeepTests.csproj
  47. +68
    -0
      src/MarkdownDeepTests/MoreTestFiles.cs
  48. +39
    -0
      src/MarkdownDeepTests/Properties/AssemblyInfo.cs
  49. +26
    -0
      src/MarkdownDeepTests/SafeModeTests.cs
  50. +26
    -0
      src/MarkdownDeepTests/SpanLevelTests.cs
  51. +81
    -0
      src/MarkdownDeepTests/SpecialCharacterTests.cs
  52. +43
    -0
      src/MarkdownDeepTests/StringScannerTests.cs
  53. +85
    -0
      src/MarkdownDeepTests/TableSpecTests.cs
  54. +145
    -0
      src/MarkdownDeepTests/Utils.cs
  55. +136
    -0
      src/MarkdownDeepTests/XssAttackTests.cs
  56. +13
    -0
      src/MarkdownDeepTests/app.config
  57. +4
    -0
      src/MarkdownDeepTests/packages.config
  58. +38
    -0
      src/MarkdownDeepTests/testfiles/blocktests/AtxHeadings.html
  59. +39
    -0
      src/MarkdownDeepTests/testfiles/blocktests/AtxHeadings.txt
  60. +12
    -0
      src/MarkdownDeepTests/testfiles/blocktests/CodeBlocks.html
  61. +14
    -0
      src/MarkdownDeepTests/testfiles/blocktests/CodeBlocks.txt
  62. +27
    -0
      src/MarkdownDeepTests/testfiles/blocktests/ComplexListItems.html
  63. +25
    -0
      src/MarkdownDeepTests/testfiles/blocktests/ComplexListItems.txt
  64. +19
    -0
      src/MarkdownDeepTests/testfiles/blocktests/HardWrappedListItems.html
  65. +15
    -0
      src/MarkdownDeepTests/testfiles/blocktests/HardWrappedListItems.txt
  66. +4
    -0
      src/MarkdownDeepTests/testfiles/blocktests/HardWrappedParagraph.html
  67. +3
    -0
      src/MarkdownDeepTests/testfiles/blocktests/HardWrappedParagraph.txt
  68. +10
    -0
      src/MarkdownDeepTests/testfiles/blocktests/HardWrappedParagraphInListItem.html
  69. +8
    -0
      src/MarkdownDeepTests/testfiles/blocktests/HardWrappedParagraphInListItem.txt
  70. +3
    -0
      src/MarkdownDeepTests/testfiles/blocktests/HardWrappedParagraphWithListLikeLine.html
  71. +3
    -0
      src/MarkdownDeepTests/testfiles/blocktests/HardWrappedParagraphWithListLikeLine.txt
  72. +1
    -0
      src/MarkdownDeepTests/testfiles/blocktests/HtmlAttributeWithoutValue.html
  73. +1
    -0
      src/MarkdownDeepTests/testfiles/blocktests/HtmlAttributeWithoutValue.txt
  74. +18
    -0
      src/MarkdownDeepTests/testfiles/blocktests/HtmlBlock.html
  75. +18
    -0
      src/MarkdownDeepTests/testfiles/blocktests/HtmlBlock.txt
  76. +10
    -0
      src/MarkdownDeepTests/testfiles/blocktests/HtmlComments.html
  77. +9
    -0
      src/MarkdownDeepTests/testfiles/blocktests/HtmlComments.txt
  78. +8
    -0
      src/MarkdownDeepTests/testfiles/blocktests/InsTypes.html
  79. +7
    -0
      src/MarkdownDeepTests/testfiles/blocktests/InsTypes.txt
  80. +2
    -0
      src/MarkdownDeepTests/testfiles/blocktests/MultipleParagraphs.html
  81. +3
    -0
      src/MarkdownDeepTests/testfiles/blocktests/MultipleParagraphs.txt
  82. +6
    -0
      src/MarkdownDeepTests/testfiles/blocktests/NestedListItems.html
  83. +4
    -0
      src/MarkdownDeepTests/testfiles/blocktests/NestedListItems.txt
  84. +10
    -0
      src/MarkdownDeepTests/testfiles/blocktests/ParagraphBreaks.html
  85. +8
    -0
      src/MarkdownDeepTests/testfiles/blocktests/ParagraphBreaks.txt
  86. +53
    -0
      src/MarkdownDeepTests/testfiles/blocktests/PartiallyIndentedLists.html
  87. +29
    -0
      src/MarkdownDeepTests/testfiles/blocktests/PartiallyIndentedLists.txt
  88. +34
    -0
      src/MarkdownDeepTests/testfiles/blocktests/QuoteBlocks.html
  89. +36
    -0
      src/MarkdownDeepTests/testfiles/blocktests/QuoteBlocks.txt
  90. +16
    -0
      src/MarkdownDeepTests/testfiles/blocktests/QuoteBlocksNested.html
  91. +10
    -0
      src/MarkdownDeepTests/testfiles/blocktests/QuoteBlocksNested.txt
  92. +5
    -0
      src/MarkdownDeepTests/testfiles/blocktests/SetExtHeadings.html
  93. +1
    -0
      src/MarkdownDeepTests/testfiles/blocktests/SetExtHeadings.txt
  94. +6
    -0
      src/MarkdownDeepTests/testfiles/blocktests/SimpleOrderedList.html
  95. +3
    -0
      src/MarkdownDeepTests/testfiles/blocktests/SimpleOrderedList.txt
  96. +1
    -0
      src/MarkdownDeepTests/testfiles/blocktests/SimpleParagraph.html
  97. +1
    -0
      src/MarkdownDeepTests/testfiles/blocktests/SimpleParagraph.txt
  98. +5
    -0
      src/MarkdownDeepTests/testfiles/blocktests/SimpleUnorderedList.html
  99. +3
    -0
      src/MarkdownDeepTests/testfiles/blocktests/SimpleUnorderedList.txt
  100. +7
    -0
      src/MarkdownDeepTests/testfiles/extramode/Abbreviations(ExtraMode).html

+ 13
- 1
Docnet.sln View File

@@ -3,7 +3,11 @@ Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 14
VisualStudioVersion = 14.0.24720.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Docnet", "src\Docnet.csproj", "{48CA9947-AF13-459E-9D59-FC451B5C19D7}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Docnet", "src\DocNet\Docnet.csproj", "{48CA9947-AF13-459E-9D59-FC451B5C19D7}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MarkdownDeep", "src\MarkdownDeep\MarkdownDeep.csproj", "{1569ED47-C7C9-4261-B6F4-7445BD0F2C95}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MarkdownDeepTests", "src\MarkdownDeepTests\MarkdownDeepTests.csproj", "{CD1F5BFF-0118-4994-86A2-92658A36CE1B}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -15,6 +19,14 @@ Global
{48CA9947-AF13-459E-9D59-FC451B5C19D7}.Debug|Any CPU.Build.0 = Debug|Any CPU
{48CA9947-AF13-459E-9D59-FC451B5C19D7}.Release|Any CPU.ActiveCfg = Release|Any CPU
{48CA9947-AF13-459E-9D59-FC451B5C19D7}.Release|Any CPU.Build.0 = Release|Any CPU
{1569ED47-C7C9-4261-B6F4-7445BD0F2C95}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1569ED47-C7C9-4261-B6F4-7445BD0F2C95}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1569ED47-C7C9-4261-B6F4-7445BD0F2C95}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1569ED47-C7C9-4261-B6F4-7445BD0F2C95}.Release|Any CPU.Build.0 = Release|Any CPU
{CD1F5BFF-0118-4994-86A2-92658A36CE1B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{CD1F5BFF-0118-4994-86A2-92658A36CE1B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{CD1F5BFF-0118-4994-86A2-92658A36CE1B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{CD1F5BFF-0118-4994-86A2-92658A36CE1B}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE


+ 6
- 0
Themes/Default/Destination/css/theme.css View File

@@ -253,18 +253,22 @@ h1, h2, h3, h4, h5, h6 {

h1 {
font-size: 220%;
margin-bottom:25px;
}

h2 {
font-size: 190%;
margin-bottom:18px;
}

h3 {
font-size: 155%;
margin-bottom:15px;
}

h4 {
font-size: 130%;
margin-bottom: 13px;
}

h4.searchresulttitle {
@@ -273,10 +277,12 @@ h4.searchresulttitle {

h5 {
font-size: 115%;
margin-bottom: 10px;
}

h6 {
font-size: 105%;
margin-bottom: 7px;
}

hr {


src/App.config → src/DocNet/App.config View File


src/CliInput.cs → src/DocNet/CliInput.cs View File


src/Config.cs → src/DocNet/Config.cs View File


src/Docnet.csproj → src/DocNet/Docnet.csproj View File

@@ -67,6 +67,12 @@
<None Include="App.config" />
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\MarkdownDeep\MarkdownDeep.csproj">
<Project>{1569ed47-c7c9-4261-b6f4-7445bd0f2c95}</Project>
<Name>MarkdownDeep</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.

src/Engine.cs → src/DocNet/Engine.cs View File


src/INavigationElement.cs → src/DocNet/INavigationElement.cs View File


src/MarkdownSharp.cs → src/DocNet/MarkdownSharp.cs View File

@@ -1163,18 +1163,6 @@ namespace Docnet
}


private string CreateAndManageAnchorHtmlIfRequired(int headerLevel, string headerText)
{
if(headerLevel != 2)
{
return string.Empty;
}
// create an anchor and collect it for ToC generation.
var anchorText = HttpUtility.HtmlEncode(headerText.Replace(" ", "").Replace("\\", "").Replace("/", "").Replace(".", "").Replace(":", "").Replace(";", ""));
this.CollectedH2AnchorNameTuples.Add(new Tuple<string, string>(anchorText, headerText));
return string.Format("<a name=\"{0}\"></a>", anchorText);
}


private static Regex _horizontalRules = new Regex(@"
^[ ]{0,3} # Leading space
@@ -1633,6 +1621,7 @@ namespace Docnet
}


#region MarkdownSharp extensions
private static Regex _githubCodeBlock = new Regex(@"(?<!\\)(`{3,}) *(\S+)? *\n([\s\S]+?)\s*\1 *(?:\n+|$)", RegexOptions.Compiled);
private string DoGithubCodeBlocks(string text)
{
@@ -1741,7 +1730,19 @@ namespace Docnet
return string.Concat("\n\n<div class=\"alert alert-", alertType, "\"><span class=\"alert-title\"><i class=\"fa fa-", faIconName, "\"></i> ", title, "</span>",
text, "</div>");
}

private string CreateAndManageAnchorHtmlIfRequired(int headerLevel, string headerText)
{
if(headerLevel != 2)
{
return string.Empty;
}
// create an anchor and collect it for ToC generation.
var anchorText = HttpUtility.HtmlEncode(headerText.Replace(" ", "").Replace("\\", "").Replace("/", "").Replace(".", "").Replace(":", "").Replace(";", ""));
this.CollectedH2AnchorNameTuples.Add(new Tuple<string, string>(anchorText, headerText));
return string.Format("<a name=\"{0}\"></a>", anchorText);
}
#endregion


#region Encoding and Normalization

src/NavigatedPath.cs → src/DocNet/NavigatedPath.cs View File


src/NavigationElement.cs → src/DocNet/NavigationElement.cs View File


src/NavigationLevel.cs → src/DocNet/NavigationLevel.cs View File


src/Program.cs → src/DocNet/Program.cs View File


src/Properties/AssemblyInfo.cs → src/DocNet/Properties/AssemblyInfo.cs View File


src/SearchIndexEntry.cs → src/DocNet/SearchIndexEntry.cs View File


src/SimpleNavigationElement.cs → src/DocNet/SimpleNavigationElement.cs View File


src/Utils.cs → src/DocNet/Utils.cs View File

@@ -33,12 +33,17 @@ namespace Docnet
{
public static string ConvertMarkdownToHtml(string toConvert, List<Tuple<string, string>> createdAnchorCollector)
{
var parser = new Markdown(new MarkdownOptions() { EmptyElementSuffix = ">"});
//var parser = new Markdown(new MarkdownOptions() { EmptyElementSuffix = ">"});
//var toReturn = parser.Transform(toConvert);
//if(createdAnchorCollector != null)
//{
// createdAnchorCollector.AddRange(parser.CollectedH2AnchorNameTuples);
//}

var parser = new MarkdownDeep.Markdown();
parser.ExtraMode = true;
parser.GitHubCodeBlocks = true;
var toReturn = parser.Transform(toConvert);
if(createdAnchorCollector != null)
{
createdAnchorCollector.AddRange(parser.CollectedH2AnchorNameTuples);
}
return toReturn;
}


src/packages.config → src/DocNet/packages.config View File


+ 32
- 0
src/MarkdownDeep/Abbreviation.cs View File

@@ -0,0 +1,32 @@
//
// MarkdownDeep - http://www.toptensoftware.com/markdowndeep
// Copyright (C) 2010-2011 Topten Software
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this product except in
// compliance with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software distributed under the License is
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and limitations under the License.
//

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace MarkdownDeep
{
class Abbreviation
{
public Abbreviation(string abbr, string title)
{
Abbr = abbr;
Title = title;
}
public string Abbr;
public string Title;
}
}

+ 500
- 0
src/MarkdownDeep/Block.cs View File

@@ -0,0 +1,500 @@
//
// MarkdownDeep - http://www.toptensoftware.com/markdowndeep
// Copyright (C) 2010-2011 Topten Software
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this product except in
// compliance with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software distributed under the License is
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and limitations under the License.
//

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace MarkdownDeep
{
// Some block types are only used during block parsing, some
// are only used during rendering and some are used during both
internal enum BlockType
{
Blank, // blank line (parse only)
h1, // headings (render and parse)
h2,
h3,
h4,
h5,
h6,
post_h1, // setext heading lines (parse only)
post_h2,
quote, // block quote (render and parse)
ol_li, // list item in an ordered list (render and parse)
ul_li, // list item in an unordered list (render and parse)
p, // paragraph (or plain line during parse)
indent, // an indented line (parse only)
hr, // horizontal rule (render and parse)
user_break, // user break
html, // html content (render and parse)
unsafe_html, // unsafe html that should be encoded
span, // an undecorated span of text (used for simple list items
// where content is not wrapped in paragraph tags
codeblock, // a code block (render only). If in github mode, `Data` contains the language name specified after the leading ```.
li, // a list item (render only)
ol, // ordered list (render only)
ul, // unordered list (render only)
HtmlTag, // Data=(HtmlTag), children = content
Composite, // Just a list of child blocks
table_spec, // A table row specifier eg: |---: | ---| `data` = TableSpec reference
dd, // definition (render and parse) `data` = bool true if blank line before
dt, // render only
dl, // render only
footnote, // footnote definition eg: [^id] `data` holds the footnote id
p_footnote, // paragraph with footnote return link append. Return link string is in `data`.
}

class Block
{
internal Block()
{

}

internal Block(BlockType type)
{
blockType = type;
}

public string Content
{
get
{
switch (blockType)
{
case BlockType.codeblock:
StringBuilder s = new StringBuilder();
foreach (var line in children)
{
s.Append(line.Content);
s.Append('\n');
}
return s.ToString();
}


if (buf==null)
return null;
else
return contentStart == -1 ? buf : buf.Substring(contentStart, contentLen);
}
}

public int LineStart
{
get
{
return lineStart == 0 ? contentStart : lineStart;
}
}

internal void RenderChildren(Markdown m, StringBuilder b)
{
foreach (var block in children)
{
block.Render(m, b);
}
}

internal void RenderChildrenPlain(Markdown m, StringBuilder b)
{
foreach (var block in children)
{
block.RenderPlain(m, b);
}
}

internal string ResolveHeaderID(Markdown m)
{
// Already resolved?
if (this.data!=null && this.data is string)
return (string)this.data;

// Approach 1 - PHP Markdown Extra style header id
int end=contentEnd;
string id = Utils.StripHtmlID(buf, contentStart, ref end);
if (id != null)
{
contentEnd = end;
}
else
{
// Approach 2 - pandoc style header id
id = m.MakeUniqueHeaderID(buf, contentStart, contentLen);
}

this.data = id;
return id;
}

internal void Render(Markdown m, StringBuilder b)
{
switch (blockType)
{
case BlockType.Blank:
return;

case BlockType.p:
m.SpanFormatter.FormatParagraph(b, buf, contentStart, contentLen);
break;

case BlockType.span:
m.SpanFormatter.Format(b, buf, contentStart, contentLen);
b.Append("\n");
break;

case BlockType.h1:
case BlockType.h2:
case BlockType.h3:
case BlockType.h4:
case BlockType.h5:
case BlockType.h6:
if (m.ExtraMode && !m.SafeMode)
{
b.Append("<" + blockType.ToString());
string id = ResolveHeaderID(m);
if (!String.IsNullOrEmpty(id))
{
b.Append(" id=\"");
b.Append(id);
b.Append("\">");
}
else
{
b.Append(">");
}
}
else
{
b.Append("<" + blockType.ToString() + ">");
}
m.SpanFormatter.Format(b, buf, contentStart, contentLen);
b.Append("</" + blockType.ToString() + ">\n");
break;

case BlockType.hr:
b.Append("<hr />\n");
return;

case BlockType.user_break:
return;

case BlockType.ol_li:
case BlockType.ul_li:
b.Append("<li>");
m.SpanFormatter.Format(b, buf, contentStart, contentLen);
b.Append("</li>\n");
break;

case BlockType.dd:
b.Append("<dd>");
if (children != null)
{
b.Append("\n");
RenderChildren(m, b);
}
else
m.SpanFormatter.Format(b, buf, contentStart, contentLen);
b.Append("</dd>\n");
break;

case BlockType.dt:
{
if (children == null)
{
foreach (var l in Content.Split('\n'))
{
b.Append("<dt>");
m.SpanFormatter.Format(b, l.Trim());
b.Append("</dt>\n");
}
}
else
{
b.Append("<dt>\n");
RenderChildren(m, b);
b.Append("</dt>\n");
}
break;
}

case BlockType.dl:
b.Append("<dl>\n");
RenderChildren(m, b);
b.Append("</dl>\n");
return;

case BlockType.html:
b.Append(buf, contentStart, contentLen);
return;

case BlockType.unsafe_html:
m.HtmlEncode(b, buf, contentStart, contentLen);
return;

case BlockType.codeblock:
if(m.FormatCodeBlock == null)
{
var dataArgument = this.data as string ?? string.Empty;
if(m.GitHubCodeBlocks && !string.IsNullOrWhiteSpace(dataArgument))
{
b.AppendFormat("<pre><code class=\"{0}\">", dataArgument);
}
else
{
b.Append("<pre><code>");
}
foreach(var line in children)
{
m.HtmlEncodeAndConvertTabsToSpaces(b, line.buf, line.contentStart, line.contentLen);
b.Append("\n");
}
b.Append("</code></pre>\n\n");
}
else
{
var sb = new StringBuilder();
foreach(var line in children)
{
m.HtmlEncodeAndConvertTabsToSpaces(sb, line.buf, line.contentStart, line.contentLen);
sb.Append("\n");
}
b.Append(m.FormatCodeBlock(m, sb.ToString()));
}
return;

case BlockType.quote:
b.Append("<blockquote>\n");
RenderChildren(m, b);
b.Append("</blockquote>\n");
return;

case BlockType.li:
b.Append("<li>\n");
RenderChildren(m, b);
b.Append("</li>\n");
return;

case BlockType.ol:
b.Append("<ol>\n");
RenderChildren(m, b);
b.Append("</ol>\n");
return;

case BlockType.ul:
b.Append("<ul>\n");
RenderChildren(m, b);
b.Append("</ul>\n");
return;

case BlockType.HtmlTag:
var tag = (HtmlTag)data;

// Prepare special tags
var name=tag.name.ToLowerInvariant();
if (name == "a")
{
m.OnPrepareLink(tag);
}
else if (name == "img")
{
m.OnPrepareImage(tag, m.RenderingTitledImage);
}

tag.RenderOpening(b);
b.Append("\n");
RenderChildren(m, b);
tag.RenderClosing(b);
b.Append("\n");
return;

case BlockType.Composite:
case BlockType.footnote:
RenderChildren(m, b);
return;

case BlockType.table_spec:
((TableSpec)data).Render(m, b);
break;

case BlockType.p_footnote:
b.Append("<p>");
if (contentLen > 0)
{
m.SpanFormatter.Format(b, buf, contentStart, contentLen);
b.Append("&nbsp;");
}
b.Append((string)data);
b.Append("</p>\n");
break;

default:
b.Append("<" + blockType.ToString() + ">");
m.SpanFormatter.Format(b, buf, contentStart, contentLen);
b.Append("</" + blockType.ToString() + ">\n");
break;
}
}

internal void RenderPlain(Markdown m, StringBuilder b)
{
switch (blockType)
{
case BlockType.Blank:
return;

case BlockType.p:
case BlockType.span:
m.SpanFormatter.FormatPlain(b, buf, contentStart, contentLen);
b.Append(" ");
break;

case BlockType.h1:
case BlockType.h2:
case BlockType.h3:
case BlockType.h4:
case BlockType.h5:
case BlockType.h6:
m.SpanFormatter.FormatPlain(b, buf, contentStart, contentLen);
b.Append(" - ");
break;


case BlockType.ol_li:
case BlockType.ul_li:
b.Append("* ");
m.SpanFormatter.FormatPlain(b, buf, contentStart, contentLen);
b.Append(" ");
break;

case BlockType.dd:
if (children != null)
{
b.Append("\n");
RenderChildrenPlain(m, b);
}
else
m.SpanFormatter.FormatPlain(b, buf, contentStart, contentLen);
break;

case BlockType.dt:
{
if (children == null)
{
foreach (var l in Content.Split('\n'))
{
var str = l.Trim();
m.SpanFormatter.FormatPlain(b, str, 0, str.Length);
}
}
else
{
RenderChildrenPlain(m, b);
}
break;
}

case BlockType.dl:
RenderChildrenPlain(m, b);
return;

case BlockType.codeblock:
foreach (var line in children)
{
b.Append(line.buf, line.contentStart, line.contentLen);
b.Append(" ");
}
return;

case BlockType.quote:
case BlockType.li:
case BlockType.ol:
case BlockType.ul:
case BlockType.HtmlTag:
RenderChildrenPlain(m, b);
return;
}
}

public void RevertToPlain()
{
blockType = BlockType.p;
contentStart = lineStart;
contentLen = lineLen;
}

public int contentEnd
{
get
{
return contentStart + contentLen;
}
set
{
contentLen = value - contentStart;
}
}

// Count the leading spaces on a block
// Used by list item evaluation to determine indent levels
// irrespective of indent line type.
public int leadingSpaces
{
get
{
int count = 0;
for (int i = lineStart; i < lineStart + lineLen; i++)
{
if (buf[i] == ' ')
{
count++;
}
else
{
break;
}
}
return count;
}
}

public override string ToString()
{
string c = Content;
return blockType.ToString() + " - " + (c==null ? "<null>" : c);
}

public Block CopyFrom(Block other)
{
blockType = other.blockType;
buf = other.buf;
contentStart = other.contentStart;
contentLen = other.contentLen;
lineStart = other.lineStart;
lineLen = other.lineLen;
return this;
}

internal BlockType blockType;
internal string buf;
internal int contentStart;
internal int contentLen;
internal int lineStart;
internal int lineLen;
internal object data; // content depends on block type
internal List<Block> children;
}
}

+ 1565
- 0
src/MarkdownDeep/BlockProcessor.cs
File diff suppressed because it is too large
View File


+ 32
- 0
src/MarkdownDeep/FootnoteReference.cs View File

@@ -0,0 +1,32 @@
//
// MarkdownDeep - http://www.toptensoftware.com/markdowndeep
// Copyright (C) 2010-2011 Topten Software
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this product except in
// compliance with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software distributed under the License is
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and limitations under the License.
//

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace MarkdownDeep
{
class FootnoteReference
{
public FootnoteReference(int index, string id)
{
this.index = index;
this.id = id;
}
public int index;
public string id;
}
}

+ 351
- 0
src/MarkdownDeep/HtmlTag.cs View File

@@ -0,0 +1,351 @@
//
// MarkdownDeep - http://www.toptensoftware.com/markdowndeep
// Copyright (C) 2010-2011 Topten Software
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this product except in
// compliance with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software distributed under the License is
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and limitations under the License.
//

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace MarkdownDeep
{
[Flags]
public enum HtmlTagFlags
{
Block = 0x0001, // Block tag
Inline = 0x0002, // Inline tag
NoClosing = 0x0004, // No closing tag (eg: <hr> and <!-- -->)
ContentAsSpan = 0x0008, // When markdown=1 treat content as span, not block
};

public class HtmlTag
{
public HtmlTag(string name)
{
m_name = name;
}

// Get the tag name eg: "div"
public string name
{
get { return m_name; }
}

// Get a dictionary of attribute values (no decoding done)
public Dictionary<string, string> attributes
{
get { return m_attributes; }
}

// Is this tag closed eg; <br />
public bool closed
{
get { return m_closed; }
set { m_closed = value; }
}

// Is this a closing tag eg: </div>
public bool closing
{
get { return m_closing; }
}

string m_name;
Dictionary<string, string> m_attributes = new Dictionary<string, string>(StringComparer.CurrentCultureIgnoreCase);
bool m_closed;
bool m_closing;
HtmlTagFlags m_flags = 0;

public HtmlTagFlags Flags
{
get
{
if (m_flags == 0)
{
if (!m_tag_flags.TryGetValue(name.ToLower(), out m_flags))
{
m_flags |= HtmlTagFlags.Inline;
}
}

return m_flags;
}
}

static string[] m_allowed_tags = new string [] {
"b","blockquote","code","dd","dt","dl","del","em","h1","h2","h3","h4","h5","h6","i","kbd","li","ol","ul",
"p", "pre", "s", "sub", "sup", "strong", "strike", "img", "a"
};

static Dictionary<string, string[]> m_allowed_attributes = new Dictionary<string, string[]>() {
{ "a", new string[] { "href", "title", "class" } },
{ "img", new string[] { "src", "width", "height", "alt", "title", "class" } },
};

static Dictionary<string, HtmlTagFlags> m_tag_flags = new Dictionary<string, HtmlTagFlags>() {
{ "p", HtmlTagFlags.Block | HtmlTagFlags.ContentAsSpan },
{ "div", HtmlTagFlags.Block },
{ "h1", HtmlTagFlags.Block | HtmlTagFlags.ContentAsSpan },
{ "h2", HtmlTagFlags.Block | HtmlTagFlags.ContentAsSpan},
{ "h3", HtmlTagFlags.Block | HtmlTagFlags.ContentAsSpan},
{ "h4", HtmlTagFlags.Block | HtmlTagFlags.ContentAsSpan},
{ "h5", HtmlTagFlags.Block | HtmlTagFlags.ContentAsSpan},
{ "h6", HtmlTagFlags.Block | HtmlTagFlags.ContentAsSpan},
{ "blockquote", HtmlTagFlags.Block },
{ "pre", HtmlTagFlags.Block },
{ "table", HtmlTagFlags.Block },
{ "dl", HtmlTagFlags.Block },
{ "ol", HtmlTagFlags.Block },
{ "ul", HtmlTagFlags.Block },
{ "form", HtmlTagFlags.Block },
{ "fieldset", HtmlTagFlags.Block },
{ "iframe", HtmlTagFlags.Block },
{ "script", HtmlTagFlags.Block | HtmlTagFlags.Inline },
{ "noscript", HtmlTagFlags.Block | HtmlTagFlags.Inline },
{ "math", HtmlTagFlags.Block | HtmlTagFlags.Inline },
{ "ins", HtmlTagFlags.Block | HtmlTagFlags.Inline },
{ "del", HtmlTagFlags.Block | HtmlTagFlags.Inline },
{ "img", HtmlTagFlags.Block | HtmlTagFlags.Inline },
{ "li", HtmlTagFlags.ContentAsSpan},
{ "dd", HtmlTagFlags.ContentAsSpan},
{ "dt", HtmlTagFlags.ContentAsSpan},
{ "td", HtmlTagFlags.ContentAsSpan},
{ "th", HtmlTagFlags.ContentAsSpan},
{ "legend", HtmlTagFlags.ContentAsSpan},
{ "address", HtmlTagFlags.ContentAsSpan},
{ "hr", HtmlTagFlags.Block | HtmlTagFlags.NoClosing},
{ "!", HtmlTagFlags.Block | HtmlTagFlags.NoClosing},
{ "head", HtmlTagFlags.Block },
};

// Check if this tag is safe
public bool IsSafe()
{
string name_lower=m_name.ToLowerInvariant();

// Check if tag is in whitelist
if (!Utils.IsInList(name_lower, m_allowed_tags))
return false;

// Find allowed attributes
string[] allowed_attributes;
if (!m_allowed_attributes.TryGetValue(name_lower, out allowed_attributes))
{
// No allowed attributes, check we don't have any
return m_attributes.Count == 0;
}

// Check all are allowed
foreach (var i in m_attributes)
{
if (!Utils.IsInList(i.Key.ToLowerInvariant(), allowed_attributes))
return false;
}

// Check href attribute is ok
string href;
if (m_attributes.TryGetValue("href", out href))
{
if (!Utils.IsSafeUrl(href))
return false;
}

string src;
if (m_attributes.TryGetValue("src", out src))
{
if (!Utils.IsSafeUrl(src))
return false;
}


// Passed all white list checks, allow it
return true;
}

// Render opening tag (eg: <tag attr="value">
public void RenderOpening(StringBuilder dest)
{
dest.Append("<");
dest.Append(name);
foreach (var i in m_attributes)
{
dest.Append(" ");
dest.Append(i.Key);
dest.Append("=\"");
dest.Append(i.Value);
dest.Append("\"");
}

if (m_closed)
dest.Append(" />");
else
dest.Append(">");
}

// Render closing tag (eg: </tag>)
public void RenderClosing(StringBuilder dest)
{
dest.Append("</");
dest.Append(name);
dest.Append(">");
}


public static HtmlTag Parse(string str, ref int pos)
{
StringScanner sp = new StringScanner(str, pos);
var ret = Parse(sp);

if (ret!=null)
{
pos = sp.position;
return ret;
}

return null;
}

public static HtmlTag Parse(StringScanner p)
{
// Save position
int savepos = p.position;

// Parse it
var ret = ParseHelper(p);
if (ret!=null)
return ret;

// Rewind if failed
p.position = savepos;
return null;
}

private static HtmlTag ParseHelper(StringScanner p)
{
// Does it look like a tag?
if (p.current != '<')
return null;

// Skip '<'
p.SkipForward(1);

// Is it a comment?
if (p.SkipString("!--"))
{
p.Mark();

if (p.Find("-->"))
{
var t = new HtmlTag("!");
t.m_attributes.Add("content", p.Extract());
t.m_closed = true;
p.SkipForward(3);
return t;
}
}

// Is it a closing tag eg: </div>
bool bClosing = p.SkipChar('/');

// Get the tag name
string tagName=null;
if (!p.SkipIdentifier(ref tagName))
return null;

// Probably a tag, create the HtmlTag object now
HtmlTag tag = new HtmlTag(tagName);
tag.m_closing = bClosing;


// If it's a closing tag, no attributes
if (bClosing)
{
if (p.current != '>')
return null;

p.SkipForward(1);
return tag;
}


while (!p.eof)
{
// Skip whitespace
p.SkipWhitespace();

// Check for closed tag eg: <hr />
if (p.SkipString("/>"))
{
tag.m_closed=true;
return tag;
}

// End of tag?
if (p.SkipChar('>'))
{
return tag;
}

// attribute name
string attributeName = null;
if (!p.SkipIdentifier(ref attributeName))
return null;

// Skip whitespace
p.SkipWhitespace();

// Skip equal sign
if (p.SkipChar('='))
{
// Skip whitespace
p.SkipWhitespace();

// Optional quotes
if (p.SkipChar('\"'))
{
// Scan the value
p.Mark();
if (!p.Find('\"'))
return null;

// Store the value
tag.m_attributes.Add(attributeName, p.Extract());

// Skip closing quote
p.SkipForward(1);
}
else
{
// Scan the value
p.Mark();
while (!p.eof && !char.IsWhiteSpace(p.current) && p.current != '>' && p.current != '/')
p.SkipForward(1);

if (!p.eof)
{
// Store the value
tag.m_attributes.Add(attributeName, p.Extract());
}
}
}
else
{
tag.m_attributes.Add(attributeName, "");
}
}

return null;
}

}
}

+ 344
- 0
src/MarkdownDeep/LinkDefinition.cs View File

@@ -0,0 +1,344 @@
//
// MarkdownDeep - http://www.toptensoftware.com/markdowndeep
// Copyright (C) 2010-2011 Topten Software
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this product except in
// compliance with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software distributed under the License is
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and limitations under the License.
//

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace MarkdownDeep
{
public class LinkDefinition
{
public LinkDefinition(string id)
{
this.id= id;
}

public LinkDefinition(string id, string url)
{
this.id = id;
this.url = url;
}

public LinkDefinition(string id, string url, string title)
{
this.id = id;
this.url = url;
this.title = title;
}

public string id
{
get;
set;
}

public string url
{
get;
set;
}

public string title
{
get;
set;
}


internal void RenderLink(Markdown m, StringBuilder b, string link_text)
{
if (url.StartsWith("mailto:"))
{
b.Append("<a href=\"");
Utils.HtmlRandomize(b, url);
b.Append('\"');
if (!String.IsNullOrEmpty(title))
{
b.Append(" title=\"");
Utils.SmartHtmlEncodeAmpsAndAngles(b, title);
b.Append('\"');
}
b.Append('>');
Utils.HtmlRandomize(b, link_text);
b.Append("</a>");
}
else
{
HtmlTag tag = new HtmlTag("a");

// encode url
StringBuilder sb = m.GetStringBuilder();
Utils.SmartHtmlEncodeAmpsAndAngles(sb, url);
tag.attributes["href"] = sb.ToString();

// encode title
if (!String.IsNullOrEmpty(title ))
{
sb.Length = 0;
Utils.SmartHtmlEncodeAmpsAndAngles(sb, title);
tag.attributes["title"] = sb.ToString();
}

// Do user processing
m.OnPrepareLink(tag);

// Render the opening tag
tag.RenderOpening(b);

b.Append(link_text); // Link text already escaped by SpanFormatter
b.Append("</a>");
}
}

internal void RenderImg(Markdown m, StringBuilder b, string alt_text)
{
HtmlTag tag = new HtmlTag("img");

// encode url
StringBuilder sb = m.GetStringBuilder();
Utils.SmartHtmlEncodeAmpsAndAngles(sb, url);
tag.attributes["src"] = sb.ToString();

// encode alt text
if (!String.IsNullOrEmpty(alt_text))
{
sb.Length = 0;
Utils.SmartHtmlEncodeAmpsAndAngles(sb, alt_text);
tag.attributes["alt"] = sb.ToString();
}

// encode title
if (!String.IsNullOrEmpty(title))
{
sb.Length = 0;
Utils.SmartHtmlEncodeAmpsAndAngles(sb, title);
tag.attributes["title"] = sb.ToString();
}

tag.closed = true;

m.OnPrepareImage(tag, m.RenderingTitledImage);

tag.RenderOpening(b);
}


// Parse a link definition from a string (used by test cases)
internal static LinkDefinition ParseLinkDefinition(string str, bool ExtraMode)
{
StringScanner p = new StringScanner(str);
return ParseLinkDefinitionInternal(p, ExtraMode);
}

// Parse a link definition
internal static LinkDefinition ParseLinkDefinition(StringScanner p, bool ExtraMode)
{
int savepos=p.position;
var l = ParseLinkDefinitionInternal(p, ExtraMode);
if (l==null)
p.position = savepos;
return l;

}

internal static LinkDefinition ParseLinkDefinitionInternal(StringScanner p, bool ExtraMode)
{
// Skip leading white space
p.SkipWhitespace();

// Must start with an opening square bracket
if (!p.SkipChar('['))
return null;

// Extract the id
p.Mark();
if (!p.Find(']'))
return null;
string id = p.Extract();
if (id.Length == 0)
return null;
if (!p.SkipString("]:"))
return null;

// Parse the url and title
var link=ParseLinkTarget(p, id, ExtraMode);

// and trailing whitespace
p.SkipLinespace();

// Trailing crap, not a valid link reference...
if (!p.eol)
return null;

return link;
}

// Parse just the link target
// For reference link definition, this is the bit after "[id]: thisbit"
// For inline link, this is the bit in the parens: [link text](thisbit)
internal static LinkDefinition ParseLinkTarget(StringScanner p, string id, bool ExtraMode)
{
// Skip whitespace
p.SkipWhitespace();

// End of string?
if (p.eol)
return null;

// Create the link definition
var r = new LinkDefinition(id);

// Is the url enclosed in angle brackets
if (p.SkipChar('<'))
{
// Extract the url
p.Mark();

// Find end of the url
while (p.current != '>')
{
if (p.eof)
return null;
p.SkipEscapableChar(ExtraMode);
}

string url = p.Extract();
if (!p.SkipChar('>'))
return null;

// Unescape it
r.url = Utils.UnescapeString(url.Trim(), ExtraMode);

// Skip whitespace
p.SkipWhitespace();
}
else
{
// Find end of the url
p.Mark();
int paren_depth = 1;
while (!p.eol)
{
char ch=p.current;
if (char.IsWhiteSpace(ch))
break;
if (id == null)
{
if (ch == '(')
paren_depth++;
else if (ch == ')')
{
paren_depth--;
if (paren_depth==0)
break;
}
}

p.SkipEscapableChar(ExtraMode);
}

r.url = Utils.UnescapeString(p.Extract().Trim(), ExtraMode);
}

p.SkipLinespace();

// End of inline target
if (p.DoesMatch(')'))
return r;

bool bOnNewLine = p.eol;
int posLineEnd = p.position;
if (p.eol)
{
p.SkipEol();
p.SkipLinespace();
}

// Work out what the title is delimited with
char delim;
switch (p.current)
{
case '\'':
case '\"':
delim = p.current;
break;

case '(':
delim = ')';
break;

default:
if (bOnNewLine)
{
p.position = posLineEnd;
return r;
}
else
return null;
}

// Skip the opening title delimiter
p.SkipForward(1);

// Find the end of the title
p.Mark();
while (true)
{
if (p.eol)
return null;

if (p.current == delim)
{

if (delim != ')')
{
int savepos = p.position;

// Check for embedded quotes in title

// Skip the quote and any trailing whitespace
p.SkipForward(1);
p.SkipLinespace();

// Next we expect either the end of the line for a link definition
// or the close bracket for an inline link
if ((id == null && p.current != ')') ||
(id != null && !p.eol))
{
continue;
}

p.position = savepos;
}

// End of title
break;
}

p.SkipEscapableChar(ExtraMode);
}

// Store the title
r.title = Utils.UnescapeString(p.Extract(), ExtraMode);

// Skip closing quote
p.SkipForward(1);

// Done!
return r;
}
}
}

+ 34
- 0
src/MarkdownDeep/LinkInfo.cs View File

@@ -0,0 +1,34 @@
//
// MarkdownDeep - http://www.toptensoftware.com/markdowndeep
// Copyright (C) 2010-2011 Topten Software
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this product except in
// compliance with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software distributed under the License is
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and limitations under the License.
//

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace MarkdownDeep
{
internal class LinkInfo
{
public LinkInfo(LinkDefinition def, string link_text)
{
this.def = def;
this.link_text = link_text;
}

public LinkDefinition def;
public string link_text;
}

}

+ 1014
- 0
src/MarkdownDeep/MardownDeep.cs
File diff suppressed because it is too large
View File


+ 120
- 0
src/MarkdownDeep/MarkdownDeep.csproj View File

@@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>9.0.30729</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{1569ED47-C7C9-4261-B6F4-7445BD0F2C95}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>MarkdownDeep</RootNamespace>
<AssemblyName>MarkdownDeep</AssemblyName>
<TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<FileUpgradeFlags>
</FileUpgradeFlags>
<UpgradeBackupLocation>
</UpgradeBackupLocation>
<OldToolsVersion>3.5</OldToolsVersion>
<PublishUrl>publish\</PublishUrl>
<Install>true</Install>
<InstallFrom>Disk</InstallFrom>
<UpdateEnabled>false</UpdateEnabled>
<UpdateMode>Foreground</UpdateMode>
<UpdateInterval>7</UpdateInterval>
<UpdateIntervalUnits>Days</UpdateIntervalUnits>
<UpdatePeriodically>false</UpdatePeriodically>
<UpdateRequired>false</UpdateRequired>
<MapFileExtensions>true</MapFileExtensions>
<ApplicationRevision>0</ApplicationRevision>
<ApplicationVersion>1.0.0.%2a</ApplicationVersion>
<IsWebBootstrapper>false</IsWebBootstrapper>
<UseApplicationTrust>false</UseApplicationTrust>
<BootstrapperEnabled>true</BootstrapperEnabled>
<TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<ItemGroup>
<Reference Include="Accessibility" />
<Reference Include="System" />
<Reference Include="System.Core">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
<Reference Include="System.Drawing" />
<Reference Include="System.Web" />
<Reference Include="System.Xml.Linq">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
<Reference Include="System.Data.DataSetExtensions">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Abbreviation.cs" />
<Compile Include="BlockProcessor.cs" />
<Compile Include="FootnoteReference.cs" />
<Compile Include="HtmlTag.cs" />
<Compile Include="LinkDefinition.cs" />
<Compile Include="LinkInfo.cs" />
<Compile Include="MardownDeep.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Block.cs" />
<Compile Include="SpanFormatter.cs" />
<Compile Include="StringScanner.cs" />
<Compile Include="TableSpec.cs" />
<Compile Include="Token.cs" />
<Compile Include="Utils.cs" />
</ItemGroup>
<ItemGroup>
<BootstrapperPackage Include="Microsoft.Net.Client.3.5">
<Visible>False</Visible>
<ProductName>.NET Framework 3.5 SP1 Client Profile</ProductName>
<Install>false</Install>
</BootstrapperPackage>
<BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
<Visible>False</Visible>
<ProductName>.NET Framework 3.5 SP1</ProductName>
<Install>true</Install>
</BootstrapperPackage>
<BootstrapperPackage Include="Microsoft.Windows.Installer.3.1">
<Visible>False</Visible>
<ProductName>Windows Installer 3.1</ProductName>
<Install>true</Install>
</BootstrapperPackage>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<PropertyGroup>
<PostBuildEvent>
</PostBuildEvent>
</PropertyGroup>
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

+ 37
- 0
src/MarkdownDeep/Properties/AssemblyInfo.cs View File

@@ -0,0 +1,37 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("MarkdownDeep")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Topten Software")]
[assembly: AssemblyProduct("MarkdownDeep")]
[assembly: AssemblyCopyright("Copyright © 2010-2016 Topten Software")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]

// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]

// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("dddc6d83-efc4-4387-90e2-eabe9f5998dd")]

// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.6.0.0")]
[assembly: AssemblyFileVersion("1.6.0")]
[assembly: InternalsVisibleTo("MarkdownDeepTests")]

+ 1171
- 0
src/MarkdownDeep/SpanFormatter.cs
File diff suppressed because it is too large
View File


+ 541
- 0
src/MarkdownDeep/StringScanner.cs View File

@@ -0,0 +1,541 @@
//
// MarkdownDeep - http://www.toptensoftware.com/markdowndeep
// Copyright (C) 2010-2011 Topten Software
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this product except in
// compliance with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software distributed under the License is
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and limitations under the License.
//

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace MarkdownDeep
{
/*
* StringScanner is a simple class to help scan through an input string.
*
* Maintains a current position with various operations to inspect the current
* character, skip forward, check for matches, skip whitespace etc...
*/
public class StringScanner
{
// Constructor
public StringScanner()
{
}

// Constructor
public StringScanner(string str)
{
Reset(str);
}

// Constructor
public StringScanner(string str, int pos)
{
Reset(str, pos);
}

// Constructor
public StringScanner(string str, int pos, int len)
{
Reset(str, pos, len);
}

// Reset
public void Reset(string str)
{
Reset(str, 0, str!=null ? str.Length : 0);
}

// Reset
public void Reset(string str, int pos)
{
Reset(str, pos, str!=null ? str.Length - pos : 0);
}

// Reset
public void Reset(string str, int pos, int len)
{
if (str == null)
str = "";
if (len < 0)
len = 0;
if (pos < 0)
pos = 0;
if (pos > str.Length)
pos = str.Length;

this.str = str;
this.start = pos;
this.pos = pos;
this.end = pos + len;

if (end > str.Length)
end = str.Length;
}

// Get the entire input string
public string input
{
get
{
return str;
}
}

// Get the character at the current position
public char current
{
get
{
if (pos < start || pos >= end)
return '\0';
else
return str[pos];
}
}

// Get/set the current position
public int position
{
get
{
return pos;
}
set
{
pos = value;
}
}

// Get the remainder of the input
// (use this in a watch window while debugging :)
public string remainder
{
get
{
return Substring(position);
}
}

// Skip to the end of file
public void SkipToEof()
{
pos = end;
}


// Skip to the end of the current line
public void SkipToEol()
{
while (pos < end)
{
char ch=str[pos];
if (ch=='\r' || ch=='\n')
break;
pos++;
}
}

// Skip if currently at a line end
public bool SkipEol()
{
if (pos < end)
{
char ch = str[pos];
if (ch == '\r')
{
pos++;
if (pos < end && str[pos] == '\n')
pos++;
return true;
}

else if (ch == '\n')
{
pos++;
if (pos < end && str[pos] == '\r')
pos++;
return true;
}
}

return false;
}

// Skip to the next line
public void SkipToNextLine()
{
SkipToEol();
SkipEol();
}

// Get the character at offset from current position
// Or, \0 if out of range
public char CharAtOffset(int offset)
{
int index = pos + offset;
if (index < start)
return '\0';
if (index >= end)
return '\0';
return str[index];
}

// Skip a number of characters
public void SkipForward(int characters)
{
pos += characters;
}

// Skip a character if present
public bool SkipChar(char ch)
{
if (current == ch)
{
SkipForward(1);
return true;
}

return false;
}

// Skip a matching string
public bool SkipString(string str)
{
if (DoesMatch(str))
{
SkipForward(str.Length);
return true;
}

return false;
}

// Skip a matching string
public bool SkipStringI(string str)
{
if (DoesMatchI(str))
{
SkipForward(str.Length);
return true;
}

return false;
}

// Skip any whitespace
public bool SkipWhitespace()
{
if (!char.IsWhiteSpace(current))
return false;
SkipForward(1);

while (char.IsWhiteSpace(current))
SkipForward(1);

return true;
}

// Check if a character is space or tab
public static bool IsLineSpace(char ch)
{
return ch == ' ' || ch == '\t';
}

// Skip spaces and tabs
public bool SkipLinespace()
{
if (!IsLineSpace(current))
return false;
SkipForward(1);

while (IsLineSpace(current))
SkipForward(1);

return true;
}

// Does current character match something
public bool DoesMatch(char ch)
{
return current == ch;
}

// Does character at offset match a character
public bool DoesMatch(int offset, char ch)
{
return CharAtOffset(offset) == ch;
}

// Does current character match any of a range of characters
public bool DoesMatchAny(char[] chars)
{
for (int i = 0; i < chars.Length; i++)
{
if (DoesMatch(chars[i]))
return true;
}
return false;
}

// Does current character match any of a range of characters
public bool DoesMatchAny(int offset, char[] chars)
{
for (int i = 0; i < chars.Length; i++)
{
if (DoesMatch(offset, chars[i]))
return true;
}
return false;
}

// Does current string position match a string
public bool DoesMatch(string str)
{
for (int i = 0; i < str.Length; i++)
{
if (str[i] != CharAtOffset(i))
return false;
}
return true;
}

// Does current string position match a string
public bool DoesMatchI(string str)
{
return string.Compare(str, Substring(position, str.Length), true) == 0;
}

// Extract a substring
public string Substring(int start)
{
return str.Substring(start, end-start);
}

// Extract a substring
public string Substring(int start, int len)
{
if (start + len > end)
len = end - start;

return str.Substring(start, len);
}

// Scan forward for a character
public bool Find(char ch)
{
if (pos >= end)
return false;

// Find it
int index = str.IndexOf(ch, pos);
if (index < 0 || index>=end)
return false;

// Store new position
pos = index;
return true;
}

// Find any of a range of characters
public bool FindAny(char[] chars)
{
if (pos >= end)
return false;

// Find it
int index = str.IndexOfAny(chars, pos);
if (index < 0 || index>=end)
return false;

// Store new position
pos = index;
return true;
}

// Forward scan for a string
public bool Find(string find)
{
if (pos >= end)
return false;

int index = str.IndexOf(find, pos);
if (index < 0 || index > end-find.Length)
return false;

pos = index;
return true;
}

// Forward scan for a string (case insensitive)
public bool FindI(string find)
{
if (pos >= end)
return false;

int index = str.IndexOf(find, pos, StringComparison.InvariantCultureIgnoreCase);
if (index < 0 || index >= end - find.Length)
return false;

pos = index;
return true;
}

// Are we at eof?
public bool eof
{
get
{
return pos >= end;
}
}

// Are we at eol?
public bool eol
{
get
{
return IsLineEnd(current);
}
}

// Are we at bof?
public bool bof
{
get
{
return pos == start;
}
}

// Mark current position
public void Mark()
{
mark = pos;
}

// Extract string from mark to current position
public string Extract()
{
if (mark >= pos)
return "";

return str.Substring(mark, pos - mark);
}

// Skip an identifier
public bool SkipIdentifier(ref string identifier)
{
int savepos = position;
if (!Utils.ParseIdentifier(this.str, ref pos, ref identifier))
return false;
if (pos >= end)
{
pos = savepos;
return false;
}
return true;
}

public bool SkipFootnoteID(out string id)
{
int savepos = position;

SkipLinespace();

Mark();

while (true)
{
char ch = current;
if (char.IsLetterOrDigit(ch) || ch == '-' || ch == '_' || ch == ':' || ch == '.' || ch == ' ')
SkipForward(1);
else
break;
}

if (position > mark)
{
id = Extract().Trim();
if (!String.IsNullOrEmpty(id))
{
SkipLinespace();
return true;
}
}

position = savepos;
id = null;
return false;
}

// Skip a Html entity (eg: &amp;)
public bool SkipHtmlEntity(ref string entity)
{
int savepos = position;
if (!Utils.SkipHtmlEntity(this.str, ref pos, ref entity))
return false;
if (pos > end)
{
pos = savepos;
return false;
}
return true;
}

// Check if a character marks end of line
public static bool IsLineEnd(char ch)
{
return ch == '\r' || ch == '\n' || ch=='\0';
}

bool IsUrlChar(char ch)
{
switch (ch)
{
case '+':
case '&':
case '@':
case '#':
case '/':
case '%':
case '?':
case '=':
case '~':
case '_':
case '|':
case '[':
case ']':
case '(':
case ')':
case '!':
case ':':
case ',':
case '.':
case ';':
return true;

default:
return Char.IsLetterOrDigit(ch);
}
}

// Attributes
string str;
int start;
int pos;
int end;
int mark;
}
}

+ 219
- 0
src/MarkdownDeep/TableSpec.cs View File

@@ -0,0 +1,219 @@
//
// MarkdownDeep - http://www.toptensoftware.com/markdowndeep
// Copyright (C) 2010-2011 Topten Software
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this product except in
// compliance with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software distributed under the License is
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and limitations under the License.
//

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace MarkdownDeep
{
internal enum ColumnAlignment
{
NA,
Left,
Right,
Center,
}
internal class TableSpec
{
public TableSpec()
{
}

public bool LeadingBar;
public bool TrailingBar;

public List<ColumnAlignment> Columns=new List<ColumnAlignment>();

public List<string> Headers;
public List<List<string>> Rows=new List<List<string>>();

public List<string> ParseRow(StringScanner p)
{
p.SkipLinespace();

if (p.eol)
return null; // Blank line ends the table

bool bAnyBars=LeadingBar;
if (LeadingBar && !p.SkipChar('|'))
{
return null;
}

// Create the row
List<string> row = new List<string>();

// Parse all columns except the last

while (!p.eol)
{
// Find the next vertical bar
p.Mark();
while (!p.eol && p.current != '|')
p.SkipEscapableChar(true);

row.Add(p.Extract().Trim());

bAnyBars|=p.SkipChar('|');
}

// Require at least one bar to continue the table
if (!bAnyBars)
return null;

// Add missing columns
while (row.Count < Columns.Count)
{
row.Add("&nbsp;");
}

p.SkipEol();
return row;
}

internal void RenderRow(Markdown m, StringBuilder b, List<string> row, string type)
{
for (int i=0; i<row.Count; i++)
{
b.Append("\t<");
b.Append(type);

if (i < Columns.Count)
{
switch (Columns[i])
{
case ColumnAlignment.Left:
b.Append(" align=\"left\"");
break;
case ColumnAlignment.Right:
b.Append(" align=\"right\"");
break;
case ColumnAlignment.Center:
b.Append(" align=\"center\"");
break;
}
}

b.Append(">");
m.SpanFormatter.Format(b, row[i]);
b.Append("</");
b.Append(type);
b.Append(">\n");
}
}
public void Render(Markdown m, StringBuilder b)
{
b.Append("<table>\n");
if (Headers != null)
{
b.Append("<thead>\n<tr>\n");
RenderRow(m, b, Headers, "th");
b.Append("</tr>\n</thead>\n");
}

b.Append("<tbody>\n");
foreach (var row in Rows)
{
b.Append("<tr>\n");
RenderRow(m, b, row, "td");
b.Append("</tr>\n");
}
b.Append("</tbody>\n");

b.Append("</table>\n");
}

public static TableSpec Parse(StringScanner p)
{
// Leading line space allowed
p.SkipLinespace();

// Quick check for typical case
if (p.current != '|' && p.current != ':' && p.current != '-')
return null;

// Don't create the spec until it at least looks like one
TableSpec spec = null;

// Leading bar, looks like a table spec
if (p.SkipChar('|'))
{
spec=new TableSpec();
spec.LeadingBar=true;
}


// Process all columns
while (true)
{
// Parse column spec
p.SkipLinespace();

// Must have something in the spec
if (p.current == '|')
return null;

bool AlignLeft = p.SkipChar(':');
while (p.current == '-')
p.SkipForward(1);
bool AlignRight = p.SkipChar(':');
p.SkipLinespace();

// Work out column alignment
ColumnAlignment col = ColumnAlignment.NA;
if (AlignLeft && AlignRight)
col = ColumnAlignment.Center;
else if (AlignLeft)
col = ColumnAlignment.Left;
else if (AlignRight)
col = ColumnAlignment.Right;

if (p.eol)
{
// Not a spec?
if (spec == null)
return null;

// Add the final spec?
spec.Columns.Add(col);
return spec;
}

// We expect a vertical bar
if (!p.SkipChar('|'))
return null;

// Create the table spec
if (spec==null)
spec=new TableSpec();

// Add the column
spec.Columns.Add(col);

// Check for trailing vertical bar
p.SkipLinespace();
if (p.eol)
{
spec.TrailingBar = true;
return spec;
}

// Next column
}
}
}
}

+ 93
- 0
src/MarkdownDeep/Token.cs View File

@@ -0,0 +1,93 @@
//
// MarkdownDeep - http://www.toptensoftware.com/markdowndeep
// Copyright (C) 2010-2011 Topten Software
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this product except in
// compliance with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software distributed under the License is
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and limitations under the License.
//

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace MarkdownDeep
{
/*
* Token is used to mark out various special parts of a string being
* formatted by SpanFormatter.
*
* Strings aren't actually stored in the token - just their offset
* and length in the input string.
*
* For performance, Token's are pooled and reused.
* See SpanFormatter.CreateToken()
*/

// TokenType - what sort of token?
internal enum TokenType
{
Text, // Plain text, should be htmlencoded
HtmlTag, // Valid html tag, write out directly but escape &amps;
Html, // Valid html, write out directly
open_em, // <em>
close_em, // </em>
open_strong, // <strong>
close_strong, // </strong>
code_span, // <code></code>
br, // <br />

link, // <a href>, data = LinkInfo
img, // <img>, data = LinkInfo
footnote, // Footnote reference
abbreviation, // An abbreviation, data is a reference to Abbrevation instance

// These are used during construction of <em> and <strong> tokens
opening_mark, // opening '*' or '_'
closing_mark, // closing '*' or '_'
internal_mark, // internal '*' or '_'
}

// Token
internal class Token
{
// Constructor
public Token(TokenType type, int startOffset, int length)
{
this.type = type;
this.startOffset = startOffset;
this.length = length;
}

// Constructor
public Token(TokenType type, object data)
{
this.type = type;
this.data = data;
}

public override string ToString()
{
if (true || data == null)
{
return string.Format("{0} - {1} - {2}", type.ToString(), startOffset, length);
}
else
{
return string.Format("{0} - {1} - {2} -> {3}", type.ToString(), startOffset, length, data.ToString());
}
}

public TokenType type;
public int startOffset;
public int length;
public object data;
}

}

+ 495
- 0
src/MarkdownDeep/Utils.cs View File

@@ -0,0 +1,495 @@
//
// MarkdownDeep - http://www.toptensoftware.com/markdowndeep
// Copyright (C) 2010-2011 Topten Software
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this product except in
// compliance with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software distributed under the License is
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and limitations under the License.
//

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;

namespace MarkdownDeep
{
/*
* Various utility and extension methods
*/
static class Utils
{
// Extension method. Get the last item in a list (or null if empty)
public static T Last<T>(this List<T> list) where T:class
{
if (list.Count > 0)
return list[list.Count - 1];
else
return null;
}

// Extension method. Get the first item in a list (or null if empty)
public static T First<T>(this List<T> list) where T : class
{
if (list.Count > 0)
return list[0];
else
return null;
}

// Extension method. Use a list like a stack
public static void Push<T>(this List<T> list, T value) where T : class
{
list.Add(value);
}

// Extension method. Remove last item from a list
public static T Pop<T>(this List<T> list) where T : class
{
if (list.Count == 0)
return null;
else
{
T val = list[list.Count - 1];
list.RemoveAt(list.Count - 1);
return val;
}
}


// Scan a string for a valid identifier. Identifier must start with alpha or underscore
// and can be followed by alpha, digit or underscore
// Updates `pos` to character after the identifier if matched
public static bool ParseIdentifier(string str, ref int pos, ref string identifer)
{
if (pos >= str.Length)
return false;

// Must start with a letter or underscore
if (!char.IsLetter(str[pos]) && str[pos] != '_')
{
return false;
}

// Find the end
int startpos = pos;
pos++;
while (pos < str.Length && (char.IsDigit(str[pos]) || char.IsLetter(str[pos]) || str[pos] == '_'))
pos++;

// Return it
identifer = str.Substring(startpos, pos - startpos);
return true;
}

// Skip over anything that looks like a valid html entity (eg: &amp, &#123, &#nnn) etc...
// Updates `pos` to character after the entity if matched
public static bool SkipHtmlEntity(string str, ref int pos, ref string entity)
{
if (str[pos] != '&')
return false;

int savepos = pos;
int len = str.Length;
int i = pos+1;

// Number entity?
bool bNumber=false;
bool bHex = false;
if (i < len && str[i] == '#')
{
bNumber = true;
i++;

// Hex identity?
if (i < len && (str[i] == 'x' || str[i] == 'X'))
{
bHex = true;
i++;
}
}

// Parse the content
int contentpos = i;
while (i < len)
{
char ch=str[i];

if (bHex)
{
if (!(char.IsDigit(ch) || (ch >= 'a' && ch <= 'f') || (ch >= 'A' && ch <= 'F')))
break;
}

else if (bNumber)
{
if (!char.IsDigit(ch))
break;
}
else if (!char.IsLetterOrDigit(ch))
break;

i++;
}

// Quit if ran out of string
if (i == len)
return false;

// Quit if nothing in the content
if (i == contentpos)
return false;

// Quit if didn't find a semicolon
if (str[i] != ';')
return false;

// Looks good...
pos = i + 1;

entity = str.Substring(savepos, pos - savepos);
return true;
}

// Randomize a string using html entities;
public static void HtmlRandomize(StringBuilder dest, string str)
{
// Deterministic random seed
int seed = 0;
foreach (char ch in str)
{
seed = unchecked(seed + ch);
}
Random r = new Random(seed);

// Randomize
foreach (char ch in str)
{
int x = r.Next() % 100;
if (x > 90 && ch != '@')
{
dest.Append(ch);
}
else if (x > 45)
{
dest.Append("&#");
dest.Append(((int)ch).ToString());
dest.Append(";");
}
else
{
dest.Append("&#x");
dest.Append(((int)ch).ToString("x"));
dest.Append(";");
}

}
}

// Like HtmlEncode, but don't escape &'s that look like html entities
public static void SmartHtmlEncodeAmpsAndAngles(StringBuilder dest, string str)
{
if (str == null)
return;

for (int i=0; i<str.Length; i++)
{
switch (str[i])
{
case '&':
int start = i;
string unused=null;
if (SkipHtmlEntity(str, ref i, ref unused))
{
dest.Append(str, start, i - start);
i--;
}
else
{
dest.Append("&amp;");
}
break;

case '<':
dest.Append("&lt;");
break;

case '>':
dest.Append("&gt;");
break;

case '\"':
dest.Append("&quot;");
break;

default:
dest.Append(str[i]);
break;
}
}
}


// Like HtmlEncode, but only escape &'s that don't look like html entities
public static void SmartHtmlEncodeAmps(StringBuilder dest, string str, int startOffset, int len)
{
int end = startOffset + len;
for (int i = startOffset; i < end; i++)
{
switch (str[i])
{
case '&':
int start = i;
string unused = null;
if (SkipHtmlEntity(str, ref i, ref unused))
{
dest.Append(str, start, i - start);
i--;
}
else
{
dest.Append("&amp;");
}
break;

default:
dest.Append(str[i]);
break;
}
}
}

// Check if a string is in an array of strings
public static bool IsInList(string str, string[] list)
{
foreach (var t in list)
{
if (string.Compare(t, str) == 0)
return true;
}
return false;
}

// Check if a url is "safe" (we require urls start with valid protocol)
// Definitely don't allow "javascript:" or any of it's encodings.
public static bool IsSafeUrl(string url)
{
if (!url.StartsWith("http://") && !url.StartsWith("https://") && !url.StartsWith("ftp://"))
return false;

return true;
}

// Check if a character is escapable in markdown
public static bool IsEscapableChar(char ch, bool ExtraMode)
{
switch (ch)
{
case '\\':
case '`':
case '*':
case '_':
case '{':
case '}':
case '[':
case ']':
case '(':
case ')':
case '>': // Not in markdown documentation, but is in markdown.pl
case '#':
case '+':
case '-':
case '.':
case '!':
return true;

case ':':
case '|':
case '=': // Added for escaping Setext H1
case '<':
return ExtraMode;
}

return false;
}

// Extension method. Skip an escapable character, or one normal character
public static void SkipEscapableChar(this StringScanner p, bool ExtraMode)
{
if (p.current == '\\' && IsEscapableChar(p.CharAtOffset(1), ExtraMode))
{
p.SkipForward(2);
}
else
{
p.SkipForward(1);
}
}


// Remove the markdown escapes from a string
public static string UnescapeString(string str, bool ExtraMode)
{
if (str == null || str.IndexOf('\\')==-1)
return str;

var b = new StringBuilder();
for (int i = 0; i < str.Length; i++)
{
if (str[i] == '\\' && i+1<str.Length && IsEscapableChar(str[i+1], ExtraMode))
{
b.Append(str[i + 1]);
i++;
}
else
{
b.Append(str[i]);
}
}

return b.ToString();

}

// Normalize the line ends in a string to just '\n'
// Handles all encodings - '\r\n' (windows), '\n\r' (mac), '\n' (unix) '\r' (something?)
static char[] lineends = new char[] { '\r', '\n' };
public static string NormalizeLineEnds(string str)
{
if (str.IndexOfAny(lineends) < 0)
return str;

StringBuilder sb = new StringBuilder();
StringScanner sp = new StringScanner(str);
while (!sp.eof)
{
if (sp.eol)
{
sb.Append('\n');
sp.SkipEol();
}
else
{
sb.Append(sp.current);
sp.SkipForward(1);
}
}

return sb.ToString();
}

/*
* These two functions IsEmailAddress and IsWebAddress
* are intended as a quick and dirty way to tell if a
* <autolink> url is email, web address or neither.
*
* They are not intended as validating checks.
*
* (use of Regex for more correct test unnecessarily
* slowed down some test documents by up to 300%.)
*/

// Check if a string looks like an email address
public static bool IsEmailAddress(string str)
{
int posAt = str.IndexOf('@');
if (posAt < 0)
return false;

int posLastDot = str.LastIndexOf('.');
if (posLastDot < posAt)
return false;

return true;
}

// Check if a string looks like a url
public static bool IsWebAddress(string str)
{
return str.StartsWith("http://") ||
str.StartsWith("https://") ||
str.StartsWith("ftp://") ||
str.StartsWith("file://");
}

// Check if a string is a valid HTML ID identifier
internal static bool IsValidHtmlID(string str)
{
if (String.IsNullOrEmpty(str))
return false;

// Must start with a letter
if (!Char.IsLetter(str[0]))
return false;

// Check the rest
for (int i = 0; i < str.Length; i++)
{
char ch = str[i];
if (Char.IsLetterOrDigit(ch) || ch == '_' || ch == '-' || ch == ':' || ch == '.')
continue;

return false;
}

// OK
return true;
}

// Strip the trailing HTML ID from a header string
// ie: ## header text ## {#<idhere>}
// ^start ^out end ^end
//
// Returns null if no header id
public static string StripHtmlID(string str, int start, ref int end)
{
// Skip trailing whitespace
int pos = end - 1;
while (pos >= start && Char.IsWhiteSpace(str[pos]))
{
pos--;
}

// Skip closing '{'
if (pos < start || str[pos] != '}')
return null;

int endId = pos;
pos--;

// Find the opening '{'
while (pos >= start && str[pos] != '{')
pos--;

// Check for the #
if (pos < start || str[pos + 1] != '#')
return null;

// Extract and check the ID
int startId = pos + 2;
string strID = str.Substring(startId, endId - startId);
if (!IsValidHtmlID(strID))
return null;

// Skip any preceeding whitespace
while (pos > start && Char.IsWhiteSpace(str[pos - 1]))
pos--;

// Done!
end = pos;
return strID;
}

public static bool IsUrlFullyQualified(string url)
{
return url.Contains("://") || url.StartsWith("mailto:");
}

}
}

+ 73
- 0
src/MarkdownDeepTests/AutoHeaderIDTests.cs View File

@@ -0,0 +1,73 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NUnit.Framework;
using MarkdownDeep;

namespace MarkdownDeepTests
{
[TestFixture]
public class AutoHeaderIDTests
{
[SetUp]
public void SetUp()
{
m = new Markdown();
m.AutoHeadingIDs = true;
m.ExtraMode = true;
}

Markdown m;

/* Tests for pandoc style header ID generation */
/* Tests are based on the examples in the pandoc documentation */

[Test]
public void Simple()
{
Assert.AreEqual(@"header-identifiers-in-html",
m.MakeUniqueHeaderID(@"Header identifiers in HTML"));
}

[Test]
public void WithPunctuation()
{
Assert.AreEqual(@"dogs--in-my-house",
m.MakeUniqueHeaderID(@"Dogs?--in *my* house?"));
}

[Test]
public void WithLinks()
{
Assert.AreEqual(@"html-s5-rtf",
m.MakeUniqueHeaderID(@"[HTML](#html), [S5](#S5), [RTF](#rtf)"));
}

[Test]
public void WithLeadingNumbers()
{
Assert.AreEqual(@"applications",
m.MakeUniqueHeaderID(@"3. Applications"));
}

[Test]
public void RevertToSection()
{
Assert.AreEqual(@"section",
m.MakeUniqueHeaderID(@"!!!"));
}

[Test]
public void Duplicates()
{
Assert.AreEqual(@"heading",
m.MakeUniqueHeaderID(@"heading"));
Assert.AreEqual(@"heading-1",
m.MakeUniqueHeaderID(@"heading"));
Assert.AreEqual(@"heading-2",
m.MakeUniqueHeaderID(@"heading"));
}

}
}

+ 44
- 0
src/MarkdownDeepTests/AutoLinkTests.cs View File

@@ -0,0 +1,44 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MarkdownDeep;
using NUnit.Framework;

namespace MarkdownDeepTests
{
[TestFixture]
class AutoLinkTests
{
[SetUp]
public void SetUp()
{
m = new Markdown();
s = new SpanFormatter(m);
}

[Test]
public void http()
{
Assert.AreEqual("pre <a href=\"http://url.com\">http://url.com</a> post",
s.Format("pre <http://url.com> post"));
}

[Test]
public void https()
{
Assert.AreEqual("pre <a href=\"https://url.com\">https://url.com</a> post",
s.Format("pre <https://url.com> post"));
}

[Test]
public void ftp()
{
Assert.AreEqual("pre <a href=\"ftp://url.com\">ftp://url.com</a> post",
s.Format("pre <ftp://url.com> post"));
}

Markdown m;
SpanFormatter s;
}
}

+ 26
- 0
src/MarkdownDeepTests/BlockLevelTests.cs View File

@@ -0,0 +1,26 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NUnit.Framework;
using MarkdownDeep;
using System.Reflection;

namespace MarkdownDeepTests
{
[TestFixture]
class BlockLevelTests
{
public static IEnumerable<TestCaseData> GetTests()
{
return Utils.GetTests("blocktests");
}


[Test, TestCaseSource("GetTests")]
public void Test(string resourceName)
{
Utils.RunResourceTest(resourceName);
}
}
}

+ 163
- 0
src/MarkdownDeepTests/BlockProcessorTests.cs View File

@@ -0,0 +1,163 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NUnit.Framework;
using MarkdownDeep;

namespace MarkdownDeepTests
{
[TestFixture]
class BlockProcessorTests
{
[SetUp]
public void Setup()
{
p = new BlockProcessor(new Markdown(), false);
}

[Test]
public void SingleLineParagraph()
{
var b = p.Process("paragraph");
Assert.AreEqual(1, b.Count);
Assert.AreEqual(BlockType.p, b[0].blockType);
Assert.AreEqual("paragraph", b[0].Content);
}

[Test]
public void MultilineParagraph()
{
var b = p.Process("l1\nl2\n\n");
Assert.AreEqual(1, b.Count);
Assert.AreEqual(BlockType.p, b[0].blockType);
Assert.AreEqual("l1\nl2", b[0].Content);
}

[Test]
public void SetExtH1()
{
var b = p.Process("heading\n===\n\n");
Assert.AreEqual(1, b.Count);
Assert.AreEqual(BlockType.h1, b[0].blockType);
Assert.AreEqual("heading", b[0].Content);
}

[Test]
public void SetExtH2()
{
var b = p.Process("heading\n---\n\n");
Assert.AreEqual(1, b.Count);
Assert.AreEqual(BlockType.h2, b[0].blockType);
Assert.AreEqual("heading", b[0].Content);
}

[Test]
public void SetExtHeadingInParagraph()
{
var b = p.Process("p1\nheading\n---\np2\n");
Assert.AreEqual(3, b.Count);

Assert.AreEqual(BlockType.p, b[0].blockType);
Assert.AreEqual("p1", b[0].Content);

Assert.AreEqual(BlockType.h2, b[1].blockType);
Assert.AreEqual("heading", b[1].Content);

Assert.AreEqual(BlockType.p, b[2].blockType);
Assert.AreEqual("p2", b[2].Content);
}

[Test]
public void AtxHeaders()
{
var b = p.Process("#heading#\nparagraph\n");
Assert.AreEqual(2, b.Count);

Assert.AreEqual(BlockType.h1, b[0].blockType);
Assert.AreEqual("heading", b[0].Content);

Assert.AreEqual(BlockType.p, b[1].blockType);
Assert.AreEqual("paragraph", b[1].Content);
}

[Test]
public void AtxHeadingInParagraph()
{
var b = p.Process("p1\n## heading ##\np2\n");

Assert.AreEqual(3, b.Count);

Assert.AreEqual(BlockType.p, b[0].blockType);
Assert.AreEqual("p1", b[0].Content);

Assert.AreEqual(BlockType.h2, b[1].blockType);
Assert.AreEqual("heading", b[1].Content);

Assert.AreEqual(BlockType.p, b[2].blockType);
Assert.AreEqual("p2", b[2].Content);
}

[Test]
public void CodeBlock()
{
var b = p.Process("\tcode1\n\t\tcode2\n\tcode3\nparagraph");
Assert.AreEqual(2, b.Count);

Block cb = b[0] as Block;
Assert.AreEqual("code1\n\tcode2\ncode3\n", cb.Content);

Assert.AreEqual(BlockType.p, b[1].blockType);
Assert.AreEqual("paragraph", b[1].Content);
}

[Test]
public void HtmlBlock()
{
var b = p.Process("<div>\n</div>\n");
Assert.AreEqual(1, b.Count);
Assert.AreEqual(BlockType.html, b[0].blockType);
Assert.AreEqual("<div>\n</div>\n", b[0].Content);
}

[Test]
public void HtmlCommentBlock()
{
var b = p.Process("<!-- this is a\ncomments -->\n");
Assert.AreEqual(1, b.Count);
Assert.AreEqual(BlockType.html, b[0].blockType);
Assert.AreEqual("<!-- this is a\ncomments -->\n", b[0].Content);
}

[Test]
public void HorizontalRules()
{
var b = p.Process("---\n");
Assert.AreEqual(1, b.Count);
Assert.AreEqual(BlockType.hr, b[0].blockType);

b = p.Process("___\n");
Assert.AreEqual(1, b.Count);
Assert.AreEqual(BlockType.hr, b[0].blockType);

b = p.Process("***\n");
Assert.AreEqual(1, b.Count);
Assert.AreEqual(BlockType.hr, b[0].blockType);

b = p.Process(" - - - \n");
Assert.AreEqual(1, b.Count);
Assert.AreEqual(BlockType.hr, b[0].blockType);

b = p.Process(" _ _ _ \n");
Assert.AreEqual(1, b.Count);
Assert.AreEqual(BlockType.hr, b[0].blockType);

b = p.Process(" * * * \n");
Assert.AreEqual(1, b.Count);
Assert.AreEqual(BlockType.hr, b[0].blockType);
}


BlockProcessor p;
}
}

+ 59
- 0
src/MarkdownDeepTests/CodeSpanTests.cs View File

@@ -0,0 +1,59 @@
 using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NUnit.Framework;
using MarkdownDeep;

namespace MarkdownDeepTests
{
[TestFixture]
public class CodeSpanTests
{
[SetUp]
public void SetUp()
{
f = new SpanFormatter(new Markdown());
}

SpanFormatter f;

[Test]
public void SingleTick()
{
Assert.AreEqual("pre <code>code span</code> post",
f.Format("pre `code span` post"));
}

[Test]
public void SingleTickWithSpaces()
{
Assert.AreEqual("pre <code>code span</code> post",
f.Format("pre ` code span ` post"));
}

[Test]
public void MultiTick()
{
Assert.AreEqual("pre <code>code span</code> post",
f.Format("pre ````code span```` post"));
}

[Test]
public void MultiTickWithEmbeddedTicks()
{
Assert.AreEqual("pre <code>`code span`</code> post",
f.Format("pre ```` `code span` ```` post"));
}

[Test]
public void ContentEncoded()
{
Assert.AreEqual("pre <code>&lt;div&gt;</code> post",
f.Format("pre ```` <div> ```` post"));
Assert.AreEqual("pre <code>&amp;amp;</code> post",
f.Format("pre ```` &amp; ```` post"));
}

}
}

+ 240
- 0
src/MarkdownDeepTests/EmphasisTests.cs View File

@@ -0,0 +1,240 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NUnit.Framework;
using MarkdownDeep;

namespace MarkdownDeepTests
{
[TestFixture]
public class EmphasisTests
{
[SetUp]
public void SetUp()
{
f = new SpanFormatter(new Markdown());
}

SpanFormatter f;

[Test]
public void PlainText()
{
Assert.AreEqual("This is plain text",
f.Format("This is plain text"));
}


[Test]
public void em_simple()
{
Assert.AreEqual("This is <em>em</em> text",
f.Format("This is *em* text"));
Assert.AreEqual("This is <em>em</em> text",
f.Format("This is _em_ text"));
}

[Test]
public void strong_simple()
{
Assert.AreEqual("This is <strong>strong</strong> text",
f.Format("This is **strong** text"));
Assert.AreEqual("This is <strong>strong</strong> text",
f.Format("This is __strong__ text"));
}

[Test]
public void em_strong_lead_tail()
{
Assert.AreEqual("<strong>strong</strong>",
f.Format("__strong__"));
Assert.AreEqual("<strong>strong</strong>",
f.Format("**strong**"));
Assert.AreEqual("<em>em</em>",
f.Format("_em_"));
Assert.AreEqual("<em>em</em>",
f.Format("*em*"));
}


[Test]
public void strongem()
{
Assert.AreEqual("<strong><em>strongem</em></strong>",
f.Format("***strongem***"));
Assert.AreEqual("<strong><em>strongem</em></strong>",
f.Format("___strongem___"));
}

[Test]
public void no_strongem_if_spaces()
{
Assert.AreEqual("pre * notem *",
f.Format("pre * notem *"));
Assert.AreEqual("pre ** notstrong **",
f.Format("pre ** notstrong **"));
Assert.AreEqual("pre *Apples *Bananas *Oranges",
f.Format("pre *Apples *Bananas *Oranges"));
}

[Test]
public void em_in_word()
{
Assert.AreEqual("un<em>frigging</em>believable",
f.Format("un*frigging*believable"));
}

[Test]
public void strong_in_word()
{
Assert.AreEqual("un<strong>frigging</strong>believable",
f.Format("un**frigging**believable"));
}

[Test]
public void combined_1()
{
Assert.AreEqual("<strong><em>test test</em></strong>",
f.Format("***test test***"));
}

[Test]
public void combined_2()
{
Assert.AreEqual("<strong><em>test test</em></strong>",
f.Format("___test test___"));
}


[Test]
public void combined_3()
{
Assert.AreEqual("<em>test <strong>test</strong></em>",
f.Format("*test **test***"));
}


[Test]
public void combined_4()
{
Assert.AreEqual("<strong>test <em>test</em></strong>",
f.Format("**test *test***"));
}


[Test]
public void combined_5()
{
Assert.AreEqual("<strong><em>test</em> test</strong>",
f.Format("***test* test**"));
}


[Test]
public void combined_6()
{
Assert.AreEqual("<em><strong>test</strong> test</em>",
f.Format("***test** test*"));
}


[Test]
public void combined_7()
{
Assert.AreEqual("<strong><em>test</em> test</strong>",
f.Format("***test* test**"));
}


[Test]
public void combined_8()
{
Assert.AreEqual("<strong>test <em>test</em></strong>",
f.Format("**test *test***"));
}


[Test]
public void combined_9()
{
Assert.AreEqual("<em>test <strong>test</strong></em>",
f.Format("*test **test***"));
}


[Test]
public void combined_10()
{
Assert.AreEqual("<em>test <strong>test</strong></em>",
f.Format("_test __test___"));
}


[Test]
public void combined_11()
{
Assert.AreEqual("<strong>test <em>test</em></strong>",
f.Format("__test _test___"));
}


[Test]
public void combined_12()
{
Assert.AreEqual("<strong><em>test</em> test</strong>",
f.Format("___test_ test__"));
}


[Test]
public void combined_13()
{
Assert.AreEqual("<em><strong>test</strong> test</em>",
f.Format("___test__ test_"));
}


[Test]
public void combined_14()
{
Assert.AreEqual("<strong><em>test</em> test</strong>",
f.Format("___test_ test__"));
}


[Test]
public void combined_15()
{
Assert.AreEqual("<strong>test <em>test</em></strong>",
f.Format("__test _test___"));
}


[Test]
public void combined_16()
{
Assert.AreEqual("<em>test <strong>test</strong></em>",
f.Format("_test __test___"));
}

[Test]
public void combined_17()
{
var fExtra = new SpanFormatter(new Markdown() { ExtraMode = true });
Assert.AreEqual("<strong>Bold</strong> <em>Italic</em>",
fExtra.Format("__Bold__ _Italic_"));
}

[Test]
public void combined_18()
{
var fExtra = new SpanFormatter(new Markdown() { ExtraMode = true });
Assert.AreEqual("<em>Emphasis</em>, trailing",
fExtra.Format("_Emphasis_, trailing"));
}



}
}

+ 63
- 0
src/MarkdownDeepTests/EscapeCharacterTests.cs View File

@@ -0,0 +1,63 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NUnit.Framework;
using MarkdownDeep;

namespace MarkdownDeepTests
{
[TestFixture]
public class EscapeCharacterTests
{
[SetUp]
public void SetUp()
{
f = new SpanFormatter(new Markdown());
}

SpanFormatter f;

[Test]
public void AllEscapeCharacters()
{
Assert.AreEqual(@"pre \ ` * _ { } [ ] ( ) # + - . ! post",
f.Format(@"pre \\ \` \* \_ \{ \} \[ \] \( \) \# \+ \- \. \! post"));
}

[Test]
public void SomeNonEscapableCharacters()
{
Assert.AreEqual( @"pre \q \% \? post",
f.Format(@"pre \q \% \? post"));
}

[Test]
public void BackslashWithTwoDashes()
{
Assert.AreEqual(@"backslash with \-- two dashes",
f.Format(@"backslash with \\-- two dashes"));
}

[Test]
public void BackslashWithGT()
{
Assert.AreEqual(@"backslash with \&gt; greater",
f.Format(@"backslash with \\> greater"));
}

[Test]
public void EscapeNotALink()
{
Assert.AreEqual(@"\[test](not a link)",
f.Format(@"\\\[test](not a link)"));
}

[Test]
public void NoEmphasis()
{
Assert.AreEqual(@"\*no emphasis*",
f.Format(@"\\\*no emphasis*"));
}
}
}

+ 26
- 0
src/MarkdownDeepTests/ExtraMode.cs View File

@@ -0,0 +1,26 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NUnit.Framework;
using MarkdownDeep;
using System.Reflection;

namespace MarkdownDeepTests
{
[TestFixture]
class ExtraModeTests
{
public static IEnumerable<TestCaseData> GetTests()
{
return Utils.GetTests("extramode");
}


[Test, TestCaseSource("GetTests")]
public void Test(string resourceName)
{
Utils.RunResourceTest(resourceName);
}
}
}

+ 26
- 0
src/MarkdownDeepTests/GithubMode.cs View File

@@ -0,0 +1,26 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NUnit.Framework;
using MarkdownDeep;
using System.Reflection;

namespace MarkdownDeepTests
{
[TestFixture]
class GithubModeTests
{
public static IEnumerable<TestCaseData> GetTests()
{
return Utils.GetTests("githubmode");
}


[Test, TestCaseSource("GetTests")]
public void Test(string resourceName)
{
Utils.RunResourceTest(resourceName);
}
}
}

+ 144
- 0
src/MarkdownDeepTests/HtmlTagTests.cs View File

@@ -0,0 +1,144 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NUnit.Framework;
using MarkdownDeep;

namespace MarkdownDeepTests
{
[TestFixture]
class HtmlTagTests
{
[SetUp]
public void SetUp()
{
m_pos = 0;
}

[Test]
public void Unquoted()
{
string str = @"<div x=1 y=2>";
HtmlTag tag = HtmlTag.Parse(str, ref m_pos);

Assert.AreEqual(tag.name, "div");
Assert.AreEqual(tag.closing, false);
Assert.AreEqual(tag.closed, false);
Assert.AreEqual(tag.attributes.Count, 2);
Assert.AreEqual(tag.attributes["x"], "1");
Assert.AreEqual(tag.attributes["y"], "2");
Assert.AreEqual(m_pos, str.Length);

}

[Test]
public void Quoted()
{
string str = @"<div x=""1"" y=""2"">";
HtmlTag tag = HtmlTag.Parse(str, ref m_pos);

Assert.AreEqual(tag.name, "div");
Assert.AreEqual(tag.closing, false);
Assert.AreEqual(tag.closed, false);
Assert.AreEqual(tag.attributes.Count, 2);
Assert.AreEqual(tag.attributes["x"], "1");
Assert.AreEqual(tag.attributes["y"], "2");
Assert.AreEqual(m_pos, str.Length);

}

[Test]
public void Empty()
{
string str = @"<div>";
HtmlTag tag = HtmlTag.Parse(str, ref m_pos);

Assert.AreEqual(tag.name, "div");
Assert.AreEqual(tag.closing, false);
Assert.AreEqual(tag.closed, false);
Assert.AreEqual(tag.attributes.Count, 0);
Assert.AreEqual(m_pos, str.Length);

}

[Test]
public void Closed()
{
string str = @"<div/>";
HtmlTag tag = HtmlTag.Parse(str, ref m_pos);

Assert.AreEqual(tag.name, "div");
Assert.AreEqual(tag.closing, false);
Assert.AreEqual(tag.closed, true);
Assert.AreEqual(tag.attributes.Count, 0);
Assert.AreEqual(m_pos, str.Length);

}

[Test]
public void ClosedWithAttribs()
{
string str = @"<div x=1 y=2/>";
HtmlTag tag = HtmlTag.Parse(str, ref m_pos);

Assert.AreEqual(tag.name, "div");
Assert.AreEqual(tag.closing, false);
Assert.AreEqual(tag.closed, true);
Assert.AreEqual(tag.attributes.Count, 2);
Assert.AreEqual(tag.attributes["x"], "1");
Assert.AreEqual(tag.attributes["y"], "2");
Assert.AreEqual(m_pos, str.Length);

}

[Test]
public void Closing()
{
string str = @"</div>";
HtmlTag tag = HtmlTag.Parse(str, ref m_pos);

Assert.AreEqual(tag.name, "div");
Assert.AreEqual(tag.closing, true);
Assert.AreEqual(tag.closed, false);
Assert.AreEqual(tag.attributes.Count, 0);
Assert.AreEqual(m_pos, str.Length);

}

[Test]
public void Comment()
{
string str = @"<!-- comment -->";
HtmlTag tag = HtmlTag.Parse(str, ref m_pos);

Assert.AreEqual(tag.name, "!");
Assert.AreEqual(tag.closing, false);
Assert.AreEqual(tag.closed, true);
Assert.AreEqual(tag.attributes.Count, 1);
Assert.AreEqual(tag.attributes["content"], " comment ");
Assert.AreEqual(m_pos, str.Length);
}

[Test]
public void NonValuedAttribute()
{
string str = @"<iframe y=""2"" allowfullscreen x=""1"" foo>";
HtmlTag tag = HtmlTag.Parse(str, ref m_pos);

Assert.AreEqual(tag.name, "iframe");
Assert.AreEqual(tag.closing, false);
Assert.AreEqual(tag.closed, false);
Assert.AreEqual(tag.attributes.Count, 4);
Assert.AreEqual(tag.attributes["allowfullscreen"], "");
Assert.AreEqual(tag.attributes["foo"], "");
Assert.AreEqual(tag.attributes["y"], "2");
Assert.AreEqual(tag.attributes["x"], "1");
Assert.AreEqual(m_pos, str.Length);

}

int m_pos;

}
}

+ 159
- 0
src/MarkdownDeepTests/LinkAndImgTests.cs View File

@@ -0,0 +1,159 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MarkdownDeep;
using NUnit.Framework;

namespace MarkdownDeepTests
{
[TestFixture]
class LinkAndImgTests
{
[SetUp]
public void SetUp()
{
m = new Markdown();
m.AddLinkDefinition(new LinkDefinition("link1", "url.com", "title"));
m.AddLinkDefinition(new LinkDefinition("link2", "url.com"));
m.AddLinkDefinition(new LinkDefinition("img1", "url.com/image.png", "title"));
m.AddLinkDefinition(new LinkDefinition("img2", "url.com/image.png"));

s = new SpanFormatter(m);
}

[Test]
public void ReferenceLinkWithTitle()
{
Assert.AreEqual("pre <a href=\"url.com\" title=\"title\">link text</a> post",
s.Format("pre [link text][link1] post"));
}

[Test]
public void ReferenceLinkIdsAreCaseInsensitive()
{
Assert.AreEqual("pre <a href=\"url.com\" title=\"title\">link text</a> post",
s.Format("pre [link text][LINK1] post"));
}

[Test]
public void ImplicitReferenceLinkWithoutTitle()
{
Assert.AreEqual("pre <a href=\"url.com\">link2</a> post",
s.Format("pre [link2] post"));
Assert.AreEqual("pre <a href=\"url.com\">link2</a> post",
s.Format("pre [link2][] post"));
}

[Test]
public void ImplicitReferenceLinkWithTitle()
{
Assert.AreEqual("pre <a href=\"url.com\" title=\"title\">link1</a> post",
s.Format("pre [link1] post"));
Assert.AreEqual("pre <a href=\"url.com\" title=\"title\">link1</a> post",
s.Format("pre [link1][] post"));
}

[Test]
public void ReferenceLinkWithoutTitle()
{
Assert.AreEqual("pre <a href=\"url.com\">link text</a> post",
s.Format("pre [link text][link2] post"));
}

[Test]
public void MissingReferenceLink()
{
Assert.AreEqual("pre [link text][missing] post",
s.Format("pre [link text][missing] post"));
}

[Test]
public void InlineLinkWithTitle()
{
Assert.AreEqual("pre <a href=\"url.com\" title=\"title\">link text</a> post",
s.Format("pre [link text](url.com \"title\") post"));
}

[Test]
public void InlineLinkWithoutTitle()
{
Assert.AreEqual("pre <a href=\"url.com\">link text</a> post",
s.Format("pre [link text](url.com) post"));
}

[Test]
public void Boundaries()
{
Assert.AreEqual("<a href=\"url.com\">link text</a>",
s.Format("[link text](url.com)"));
Assert.AreEqual("<a href=\"url.com\" title=\"title\">link text</a>",
s.Format("[link text][link1]"));
}


[Test]
public void ReferenceImgWithTitle()
{
Assert.AreEqual("pre <img src=\"url.com/image.png\" alt=\"alt text\" title=\"title\" /> post",
s.Format("pre ![alt text][img1] post"));
}

[Test]
public void ImplicitReferenceImgWithoutTitle()
{
Assert.AreEqual("pre <img src=\"url.com/image.png\" alt=\"img2\" /> post",
s.Format("pre ![img2] post"));
Assert.AreEqual("pre <img src=\"url.com/image.png\" alt=\"img2\" /> post",
s.Format("pre ![img2][] post"));
}

[Test]
public void ImplicitReferenceImgWithTitle()
{
Assert.AreEqual("pre <img src=\"url.com/image.png\" alt=\"img1\" title=\"title\" /> post",
s.Format("pre ![img1] post"));
Assert.AreEqual("pre <img src=\"url.com/image.png\" alt=\"img1\" title=\"title\" /> post",
s.Format("pre ![img1][] post"));
}

[Test]
public void ReferenceImgWithoutTitle()
{
Assert.AreEqual("pre <img src=\"url.com/image.png\" alt=\"alt text\" /> post",
s.Format("pre ![alt text][img2] post"));
}

[Test]
public void MissingReferenceImg()
{
Assert.AreEqual("pre ![alt text][missing] post",
s.Format("pre ![alt text][missing] post"));
}

[Test]
public void InlineImgWithTitle()
{
Assert.AreEqual("pre <img src=\"url.com/image.png\" alt=\"alt text\" title=\"title\" /> post",
s.Format("pre ![alt text](url.com/image.png \"title\") post"));
}

[Test]
public void InlineImgWithoutTitle()
{
Assert.AreEqual("pre <img src=\"url.com/image.png\" alt=\"alt text\" /> post",
s.Format("pre ![alt text](url.com/image.png) post"));
}


[Test]
public void ImageLink()
{
Assert.AreEqual("pre <a href=\"url.com\"><img src=\"url.com/image.png\" alt=\"alt text\" /></a> post",
s.Format("pre [![alt text](url.com/image.png)](url.com) post"));
}
Markdown m;
SpanFormatter s;
}
}

+ 108
- 0
src/MarkdownDeepTests/LinkDefinitionTests.cs View File

@@ -0,0 +1,108 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NUnit.Framework;
using MarkdownDeep;

namespace MarkdownDeepTests
{
[TestFixture]
class LinkDefinitionTests
{
[SetUp]
public void Setup()
{
r=null;
}

[Test]
public void NoTitle()
{
string str = "[id]: url.com";
r = LinkDefinition.ParseLinkDefinition(str, false);

Assert.IsNotNull(r);
Assert.AreEqual(r.id, "id");
Assert.AreEqual(r.url, "url.com");
Assert.AreEqual(r.title, null);
}

[Test]
public void DoubleQuoteTitle()
{
string str = "[id]: url.com \"my title\"";
r = LinkDefinition.ParseLinkDefinition(str, false);

Assert.IsNotNull(r);
Assert.AreEqual(r.id, "id");
Assert.AreEqual(r.url, "url.com");
Assert.AreEqual(r.title, "my title");
}

[Test]
public void SingleQuoteTitle()
{
string str = "[id]: url.com \'my title\'";
r = LinkDefinition.ParseLinkDefinition(str, false);

Assert.IsNotNull(r);
Assert.AreEqual(r.id, "id");
Assert.AreEqual(r.url, "url.com");
Assert.AreEqual(r.title, "my title");
}

[Test]
public void ParenthesizedTitle()
{
string str = "[id]: url.com (my title)";
r = LinkDefinition.ParseLinkDefinition(str, false);

Assert.IsNotNull(r);
Assert.AreEqual(r.id, "id");
Assert.AreEqual(r.url, "url.com");
Assert.AreEqual(r.title, "my title");
}

[Test]
public void AngleBracketedUrl()
{
string str = "[id]: <url.com> (my title)";
r = LinkDefinition.ParseLinkDefinition(str, false);

Assert.IsNotNull(r);
Assert.AreEqual(r.id, "id");
Assert.AreEqual(r.url, "url.com");
Assert.AreEqual(r.title, "my title");
}

[Test]
public void MultiLine()
{
string str = "[id]:\n\t http://www.site.com \n\t (my title)";
r = LinkDefinition.ParseLinkDefinition(str, false);

Assert.IsNotNull(r);
Assert.AreEqual(r.id, "id");
Assert.AreEqual(r.url, "http://www.site.com");
Assert.AreEqual(r.title, "my title");
}

[Test]
public void Invalid()
{
Assert.IsNull(LinkDefinition.ParseLinkDefinition("[id", false));
Assert.IsNull(LinkDefinition.ParseLinkDefinition("[id]", false));
Assert.IsNull(LinkDefinition.ParseLinkDefinition("[id]:", false));
Assert.IsNull(LinkDefinition.ParseLinkDefinition("[id]: <url", false));
Assert.IsNull(LinkDefinition.ParseLinkDefinition("[id]: <url> \"title", false));
Assert.IsNull(LinkDefinition.ParseLinkDefinition("[id]: <url> \'title", false));
Assert.IsNull(LinkDefinition.ParseLinkDefinition("[id]: <url> (title", false));
Assert.IsNull(LinkDefinition.ParseLinkDefinition("[id]: <url> \"title\" crap", false));
Assert.IsNull(LinkDefinition.ParseLinkDefinition("[id]: <url> crap", false));
}

LinkDefinition r;
}

}

+ 473
- 0
src/MarkdownDeepTests/MarkdownDeepTests.csproj View File

@@ -0,0 +1,473 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>9.0.30729</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{CD1F5BFF-0118-4994-86A2-92658A36CE1B}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>MarkdownDeepTests</RootNamespace>
<AssemblyName>MarkdownDeepTests</AssemblyName>
<TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<FileUpgradeFlags>
</FileUpgradeFlags>
<UpgradeBackupLocation>
</UpgradeBackupLocation>
<OldToolsVersion>3.5</OldToolsVersion>
<TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<ItemGroup>
<Reference Include="nunit.framework">
<HintPath>..\packages\NUnit.2.5.10.11092\lib\nunit.framework.dll</HintPath>
</Reference>
<Reference Include="nunit.mocks">
<HintPath>..\packages\NUnit.2.5.10.11092\lib\nunit.mocks.dll</HintPath>
</Reference>
<Reference Include="pnunit.framework">
<HintPath>..\packages\NUnit.2.5.10.11092\lib\pnunit.framework.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
<Reference Include="System.Web" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml.Linq">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
<Reference Include="System.Data.DataSetExtensions">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="BlockProcessorTests.cs" />
<Compile Include="CodeSpanTests.cs" />
<Compile Include="AutoLinkTests.cs" />
<Compile Include="AutoHeaderIDTests.cs" />
<Compile Include="GithubMode.cs" />
<Compile Include="TableSpecTests.cs" />
<Compile Include="ExtraMode.cs" />
<Compile Include="SafeModeTests.cs" />
<Compile Include="MoreTestFiles.cs" />
<Compile Include="LinkAndImgTests.cs" />
<Compile Include="SpanLevelTests.cs" />
<Compile Include="EscapeCharacterTests.cs" />
<Compile Include="LinkDefinitionTests.cs" />
<Compile Include="SpecialCharacterTests.cs" />
<Compile Include="HtmlTagTests.cs" />
<Compile Include="BlockLevelTests.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="EmphasisTests.cs" />
<Compile Include="StringScannerTests.cs" />
<Compile Include="Utils.cs" />
<Compile Include="XssAttackTests.cs" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="testfiles\blocktests\SimpleParagraph.txt" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="testfiles\blocktests\SimpleParagraph.html" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="testfiles\blocktests\HardWrappedParagraph.html" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="testfiles\blocktests\HardWrappedParagraph.txt" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="testfiles\blocktests\MultipleParagraphs.html" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="testfiles\blocktests\MultipleParagraphs.txt" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="testfiles\blocktests\SimpleOrderedList.html" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="testfiles\blocktests\SimpleOrderedList.txt" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="testfiles\blocktests\SimpleUnorderedList.html" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="testfiles\blocktests\SimpleUnorderedList.txt" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="testfiles\blocktests\CodeBlocks.html" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="testfiles\blocktests\CodeBlocks.txt" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="testfiles\blocktests\QuoteBlocks.html" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="testfiles\blocktests\QuoteBlocks.txt" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="testfiles\blocktests\QuoteBlocksNested.html" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="testfiles\blocktests\QuoteBlocksNested.txt" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="testfiles\blocktests\HtmlBlock.html" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="testfiles\blocktests\HtmlBlock.txt" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="testfiles\blocktests\ParagraphBreaks.txt" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="testfiles\blocktests\ParagraphBreaks.html" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="testfiles\blocktests\AtxHeadings.html" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="testfiles\blocktests\AtxHeadings.txt" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="testfiles\blocktests\SetExtHeadings.txt" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="testfiles\blocktests\SetExtHeadings.html" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="testfiles\blocktests\HardWrappedListItems.txt" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="testfiles\blocktests\HardWrappedListItems.html" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="testfiles\blocktests\HardWrappedParagraphWithListLikeLine.html" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="testfiles\blocktests\HardWrappedParagraphWithListLikeLine.txt" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="testfiles\blocktests\ComplexListItems.txt" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="testfiles\blocktests\ComplexListItems.html" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="testfiles\blocktests\HardWrappedParagraphInListItem.html" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="testfiles\blocktests\HardWrappedParagraphInListItem.txt" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="testfiles\spantests\ImplicitReferenceLinkWithTitle.txt" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="testfiles\spantests\ImplicitReferenceLinkWithTitle.html" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="testfiles\spantests\ImplicitReferenceLinkWithoutTitle.txt" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="testfiles\spantests\ImplicitReferenceLinkWithoutTitle.html" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="testfiles\spantests\ExplicitReferenceLinkWithTitle.txt" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="testfiles\spantests\ExplicitReferenceLinkWithTitle.html" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="testfiles\spantests\ExplicitReferenceLinkWithoutTitle.txt" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="testfiles\spantests\ExplicitReferenceLinkWithoutTitle.html" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="testfiles\spantests\HtmlEncodeLinks.html" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="testfiles\spantests\HtmlEncodeLinks.txt" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="testfiles\spantests\InlineLinkWithTitle.html" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="testfiles\spantests\InlineLinkWithTitle.txt" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="testfiles\xsstests\xss_attacks.txt" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="testfiles\xsstests\non_attacks.txt" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="testfiles\mdtest11\Amps_and_angle_encoding.html" />
<EmbeddedResource Include="testfiles\mdtest11\Auto_links.html" />
<EmbeddedResource Include="testfiles\mdtest11\Backslash_escapes.html" />
<EmbeddedResource Include="testfiles\mdtest11\Blockquotes_with_code_blocks.html" />
<EmbeddedResource Include="testfiles\mdtest11\Code_Blocks.html" />
<EmbeddedResource Include="testfiles\mdtest11\Code_Spans.html" />
<EmbeddedResource Include="testfiles\mdtest11\Hard_wrapped_paragraphs_with_list_like_lines.html" />
<EmbeddedResource Include="testfiles\mdtest11\Horizontal_rules.html" />
<EmbeddedResource Include="testfiles\mdtest11\Images.html" />
<EmbeddedResource Include="testfiles\mdtest11\Inline_HTML_Advanced.html" />
<EmbeddedResource Include="testfiles\mdtest11\Inline_HTML_comments.html" />
<EmbeddedResource Include="testfiles\mdtest11\Inline_HTML_Simple.html" />
<EmbeddedResource Include="testfiles\mdtest11\Links_inline_style.html" />
<EmbeddedResource Include="testfiles\mdtest11\Links_reference_style.html" />
<EmbeddedResource Include="testfiles\mdtest11\Links_shortcut_references.html" />
<EmbeddedResource Include="testfiles\mdtest11\Literal_quotes_in_titles.html" />
<EmbeddedResource Include="testfiles\mdtest11\Markdown_Documentation_Basics.html" />
<EmbeddedResource Include="testfiles\mdtest11\Markdown_Documentation_Syntax.html" />
<EmbeddedResource Include="testfiles\mdtest11\Nested_blockquotes.html" />
<EmbeddedResource Include="testfiles\mdtest11\Ordered_and_unordered_lists.html" />
<EmbeddedResource Include="testfiles\mdtest11\Strong_and_em_together.html" />
<EmbeddedResource Include="testfiles\mdtest11\Tabs.html" />
<EmbeddedResource Include="testfiles\mdtest11\Tidyness.html" />
<EmbeddedResource Include="testfiles\mdtest01\code-inside-list.html" />
<EmbeddedResource Include="testfiles\mdtest01\line-endings-cr.html" />
<EmbeddedResource Include="testfiles\mdtest01\line-endings-crlf.html" />
<EmbeddedResource Include="testfiles\mdtest01\line-endings-lf.html" />
<EmbeddedResource Include="testfiles\mdtest01\markdown-readme.html" />
<EmbeddedResource Include="testfiles\pandoc\failure-to-escape-less-than.html" />
<EmbeddedResource Include="testfiles\pandoc\nested-divs.html" />
<EmbeddedResource Include="testfiles\pandoc\nested-emphasis.html" />
<EmbeddedResource Include="testfiles\phpmarkdown\Backslash escapes.html" />
<EmbeddedResource Include="testfiles\phpmarkdown\Code block in a list item.html" />
<EmbeddedResource Include="testfiles\phpmarkdown\Code Spans.html" />
<EmbeddedResource Include="testfiles\phpmarkdown\Email auto links.html" />
<EmbeddedResource Include="testfiles\phpmarkdown\Emphasis.html" />
<EmbeddedResource Include="testfiles\phpmarkdown\Headers.html" />
<EmbeddedResource Include="testfiles\phpmarkdown\Horizontal Rules.html" />
<EmbeddedResource Include="testfiles\phpmarkdown\Inline HTML %28Simple%29.html" />
<EmbeddedResource Include="testfiles\phpmarkdown\Inline HTML %28Span%29.html" />
<EmbeddedResource Include="testfiles\phpmarkdown\Inline HTML comments.html" />
<EmbeddedResource Include="testfiles\phpmarkdown\Ins &amp; del.html" />
<EmbeddedResource Include="testfiles\phpmarkdown\Links, inline style.html" />
<EmbeddedResource Include="testfiles\phpmarkdown\MD5 Hashes.html" />
<EmbeddedResource Include="testfiles\phpmarkdown\Nesting.html" />
<EmbeddedResource Include="testfiles\phpmarkdown\Parens in URL.html" />
<EmbeddedResource Include="testfiles\phpmarkdown\PHP-Specific Bugs.html" />
<EmbeddedResource Include="testfiles\phpmarkdown\Tight blocks.html" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="testfiles\mdtest11\Amps_and_angle_encoding.text" />
<EmbeddedResource Include="testfiles\mdtest11\Auto_links.text" />
<EmbeddedResource Include="testfiles\mdtest11\Backslash_escapes.text" />
<EmbeddedResource Include="testfiles\mdtest11\Blockquotes_with_code_blocks.text" />
<EmbeddedResource Include="testfiles\mdtest11\Code_Blocks.text" />
<EmbeddedResource Include="testfiles\mdtest11\Code_Spans.text" />
<EmbeddedResource Include="testfiles\mdtest11\Hard_wrapped_paragraphs_with_list_like_lines.text" />
<EmbeddedResource Include="testfiles\mdtest11\Horizontal_rules.text" />
<EmbeddedResource Include="testfiles\mdtest11\Images.text" />
<EmbeddedResource Include="testfiles\mdtest11\Inline_HTML_Advanced.text" />
<EmbeddedResource Include="testfiles\mdtest11\Inline_HTML_comments.text" />
<EmbeddedResource Include="testfiles\mdtest11\Inline_HTML_Simple.text" />
<EmbeddedResource Include="testfiles\mdtest11\Links_inline_style.text" />
<EmbeddedResource Include="testfiles\mdtest11\Links_reference_style.text" />
<EmbeddedResource Include="testfiles\mdtest11\Links_shortcut_references.text" />
<EmbeddedResource Include="testfiles\mdtest11\Literal_quotes_in_titles.text" />
<EmbeddedResource Include="testfiles\mdtest11\Markdown_Documentation_Basics.text" />
<EmbeddedResource Include="testfiles\mdtest11\Markdown_Documentation_Syntax.text" />
<EmbeddedResource Include="testfiles\mdtest11\Nested_blockquotes.text" />
<EmbeddedResource Include="testfiles\mdtest11\Ordered_and_unordered_lists.text" />
<EmbeddedResource Include="testfiles\mdtest11\Strong_and_em_together.text" />
<EmbeddedResource Include="testfiles\mdtest11\Tabs.text" />
<EmbeddedResource Include="testfiles\mdtest11\Tidyness.text" />
<EmbeddedResource Include="testfiles\mdtest01\code-inside-list.text" />
<EmbeddedResource Include="testfiles\mdtest01\line-endings-cr.text" />
<EmbeddedResource Include="testfiles\mdtest01\line-endings-crlf.text" />
<EmbeddedResource Include="testfiles\mdtest01\line-endings-lf.text" />
<EmbeddedResource Include="testfiles\mdtest01\markdown-readme.text" />
<EmbeddedResource Include="testfiles\pandoc\failure-to-escape-less-than.text" />
<EmbeddedResource Include="testfiles\pandoc\indented-code-in-list-item.text" />
<EmbeddedResource Include="testfiles\pandoc\nested-divs.text" />
<EmbeddedResource Include="testfiles\pandoc\nested-emphasis.text" />
<EmbeddedResource Include="testfiles\pandoc\unordered-list-and-horizontal-rules.text" />
<EmbeddedResource Include="testfiles\pandoc\unordered-list-followed-by-ordered-list.text" />
<EmbeddedResource Include="testfiles\pandoc\unpredictable-sublists.text" />
<EmbeddedResource Include="testfiles\phpmarkdown\Backslash escapes.text" />
<EmbeddedResource Include="testfiles\phpmarkdown\Code block in a list item.text" />
<EmbeddedResource Include="testfiles\phpmarkdown\Code Spans.text" />
<EmbeddedResource Include="testfiles\phpmarkdown\Email auto links.text" />
<EmbeddedResource Include="testfiles\phpmarkdown\Emphasis.text" />
<EmbeddedResource Include="testfiles\phpmarkdown\Headers.text" />
<EmbeddedResource Include="testfiles\phpmarkdown\Horizontal Rules.text" />
<EmbeddedResource Include="testfiles\phpmarkdown\Inline HTML %28Simple%29.text" />
<EmbeddedResource Include="testfiles\phpmarkdown\Inline HTML %28Span%29.text" />
<EmbeddedResource Include="testfiles\phpmarkdown\Inline HTML comments.text" />
<EmbeddedResource Include="testfiles\phpmarkdown\Ins &amp; del.text" />
<EmbeddedResource Include="testfiles\phpmarkdown\Links, inline style.text" />
<EmbeddedResource Include="testfiles\phpmarkdown\MD5 Hashes.text" />
<EmbeddedResource Include="testfiles\phpmarkdown\Nesting.text" />
<EmbeddedResource Include="testfiles\phpmarkdown\Parens in URL.text" />
<EmbeddedResource Include="testfiles\phpmarkdown\PHP-Specific Bugs.text" />
<EmbeddedResource Include="testfiles\phpmarkdown\Tight blocks.text" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="testfiles\blocktests\InsTypes.html" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="testfiles\blocktests\InsTypes.txt" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="testfiles\spantests\LinkTitlesWithEmbeddedQuotes.html" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="testfiles\spantests\LinkTitlesWithEmbeddedQuotes.txt" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="testfiles\blocktests\HtmlComments.html" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="testfiles\blocktests\HtmlComments.txt" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="testfiles\spantests\EscapesInUrls.html" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="testfiles\spantests\EscapesInUrls.txt" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="testfiles\blocktests\NestedListItems.html" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="testfiles\blocktests\NestedListItems.txt" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="testfiles\spantests\ReferenceLinkWithIDOnNextLine.html" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="testfiles\spantests\ReferenceLinkWithIDOnNextLine.txt" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="testfiles\spantests\FormattingInLinkText.txt" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="testfiles\spantests\FormattingInLinkText.html" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="testfiles\pandoc\indented-code-in-list-item.html" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="testfiles\pandoc\unordered-list-and-horizontal-rules.html" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="testfiles\pandoc\unordered-list-followed-by-ordered-list.html" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="testfiles\pandoc\unpredictable-sublists.html" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="testfiles\spantests\Emphasis.html" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="testfiles\spantests\Emphasis.txt" />
</ItemGroup>
<ItemGroup>
<None Include="app.config">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="testfiles\githubmode\FencedCodeBlocksAlt%28GitHubMode%29.html" />
<EmbeddedResource Include="testfiles\githubmode\FencedCodeBlocksAlt%28GitHubMode%29.txt" />
<EmbeddedResource Include="testfiles\extramode\Issue26%28ExtraMode%29.txt" />
<EmbeddedResource Include="testfiles\extramode\Issue26%28ExtraMode%29.html" />
<EmbeddedResource Include="testfiles\extramode\Issue30%28ExtraMode%29.txt" />
<EmbeddedResource Include="testfiles\extramode\Issue30%28ExtraMode%29.html" />
<EmbeddedResource Include="testfiles\extramode\FencedCodeBlocksAlt%28ExtraMode%29.html" />
<EmbeddedResource Include="testfiles\extramode\FencedCodeBlocksAlt%28ExtraMode%29.txt" />
<EmbeddedResource Include="testfiles\extramode\Issue12%28ExtraMode%29.txt" />
<EmbeddedResource Include="testfiles\extramode\Issue12%28ExtraMode%29.html" />
<EmbeddedResource Include="testfiles\blocktests\PartiallyIndentedLists.html" />
<EmbeddedResource Include="testfiles\blocktests\PartiallyIndentedLists.txt" />
<EmbeddedResource Include="testfiles\blocktests\HtmlAttributeWithoutValue.txt" />
<EmbeddedResource Include="testfiles\blocktests\HtmlAttributeWithoutValue.html" />
<EmbeddedResource Include="testfiles\spantests\LinkedImage.txt" />
<EmbeddedResource Include="testfiles\spantests\LinkedImage.html" />
<EmbeddedResource Include="testfiles\spantests\BackslashEscapes.txt" />
<EmbeddedResource Include="testfiles\spantests\BackslashEscapes.html" />
<EmbeddedResource Include="testfiles\extramode\BackslashEscapes%28ExtraMode%29.txt" />
<EmbeddedResource Include="testfiles\extramode\BackslashEscapes%28ExtraMode%29.html" />
<EmbeddedResource Include="testfiles\extramode\Emphasis%28ExtraMode%29.txt" />
<EmbeddedResource Include="testfiles\extramode\Emphasis%28ExtraMode%29.html" />
<EmbeddedResource Include="testfiles\extramode\Abbreviations%28ExtraMode%29.txt" />
<EmbeddedResource Include="testfiles\extramode\Abbreviations%28ExtraMode%29.html" />
<EmbeddedResource Include="testfiles\extramode\Footnotes%28ExtraMode%29.txt" />
<EmbeddedResource Include="testfiles\extramode\Footnotes%28ExtraMode%29.html" />
<EmbeddedResource Include="testfiles\extramode\DefinitionLists%28ExtraMode%29.txt" />
<EmbeddedResource Include="testfiles\extramode\DefinitionLists%28ExtraMode%29.html" />
<EmbeddedResource Include="testfiles\extramode\TableFormatting%28ExtraMode%29.txt" />
<EmbeddedResource Include="testfiles\extramode\TableFormatting%28ExtraMode%29.html" />
<EmbeddedResource Include="testfiles\extramode\TableAlignment%28ExtraMode%29.txt" />
<EmbeddedResource Include="testfiles\extramode\TableAlignment%28ExtraMode%29.html" />
<EmbeddedResource Include="testfiles\extramode\Tables%28ExtraMode%29.txt" />
<EmbeddedResource Include="testfiles\extramode\Tables%28ExtraMode%29.html" />
<EmbeddedResource Include="testfiles\extramode\FencedCodeBlocks%28ExtraMode%29.txt" />
<EmbeddedResource Include="testfiles\extramode\FencedCodeBlocks%28ExtraMode%29.html" />
<EmbeddedResource Include="testfiles\extramode\HeaderIDs%28ExtraMode%29%28AutoHeadingIDs%29.txt" />
<EmbeddedResource Include="testfiles\extramode\HeaderIDs%28ExtraMode%29%28AutoHeadingIDs%29.html" />
<EmbeddedResource Include="testfiles\extramode\HeaderIDs%28ExtraMode%29.html" />
<EmbeddedResource Include="testfiles\extramode\HeaderIDs%28ExtraMode%29.txt" />
<EmbeddedResource Include="testfiles\extramode\MarkdownInHtml-DeepNested%28ExtraMode%29%28MarkdownInHtml%29.txt" />
<EmbeddedResource Include="testfiles\extramode\MarkdownInHtml-DeepNested%28ExtraMode%29%28MarkdownInHtml%29.html" />
<EmbeddedResource Include="testfiles\extramode\MarkdownInHtml-DeepNested%28ExtraMode%29.txt" />
<EmbeddedResource Include="testfiles\extramode\MarkdownInHtml-DeepNested%28ExtraMode%29.html" />
<EmbeddedResource Include="testfiles\extramode\MarkdownInHtml-Nested%28ExtraMode%29.html" />
<EmbeddedResource Include="testfiles\extramode\MarkdownInHtml-Nested%28ExtraMode%29.txt" />
<EmbeddedResource Include="testfiles\extramode\MarkdownInHtml%28ExtraMode%29.txt" />
<EmbeddedResource Include="testfiles\extramode\MarkdownInHtml%28ExtraMode%29.html" />
<EmbeddedResource Include="testfiles\safemode\Basic%28SafeMode%29.txt" />
<EmbeddedResource Include="testfiles\safemode\Basic%28SafeMode%29.html" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\MarkdownDeep\MarkdownDeep.csproj">
<Project>{1569ed47-c7c9-4261-b6f4-7445bd0f2c95}</Project>
<Name>MarkdownDeep</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
<PropertyGroup>
<PostBuildEvent>
</PostBuildEvent>
</PropertyGroup>
<PropertyGroup>
<PreBuildEvent>
</PreBuildEvent>
</PropertyGroup>
</Project>

+ 68
- 0
src/MarkdownDeepTests/MoreTestFiles.cs View File

@@ -0,0 +1,68 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NUnit.Framework;
using MarkdownDeep;
using System.Reflection;

namespace MarkdownDeepTests
{
[TestFixture]
class MoreTestFiles
{
public static IEnumerable<TestCaseData> GetTests_mdtest11()
{
return Utils.GetTests("mdtest11");
}


[Test, TestCaseSource("GetTests_mdtest11")]
public void Test_mdtest11(string resourceName)
{
Utils.RunResourceTest(resourceName);
}

public static IEnumerable<TestCaseData> GetTests_mdtest01()
{
return Utils.GetTests("mdtest01");
}


[Test, TestCaseSource("GetTests_mdtest01")]
public void Test_mdtest01(string resourceName)
{
Utils.RunResourceTest(resourceName);
}


/*
* Don't run the pandoc test's as they're basically a demonstration of things
* that are broken in markdown.
*
public static IEnumerable<TestCaseData> GetTests_pandoc()
{
return Utils.GetTests("pandoc");
}


[Test, TestCaseSource("GetTests_pandoc")]
public void Test_pandoc(string resourceName)
{
Utils.RunResourceTest(resourceName);
}
*/

public static IEnumerable<TestCaseData> GetTests_phpmarkdown()
{
return Utils.GetTests("phpmarkdown");
}


[Test, TestCaseSource("GetTests_phpmarkdown")]
public void Test_phpmarkdown(string resourceName)
{
Utils.RunResourceTest(resourceName);
}
}
}

+ 39
- 0
src/MarkdownDeepTests/Properties/AssemblyInfo.cs View File

@@ -0,0 +1,39 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using NUnit.Framework;

// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("MarkdownDeepTests")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Topten Software")]
[assembly: AssemblyProduct("MarkdownDeepTests")]
[assembly: AssemblyCopyright("Copyright © 2010-2011 Topten Software")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]

// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]

// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("80e81372-b393-44fa-af74-fe39ceae854f")]

// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

[assembly: RequiresSTA]

+ 26
- 0
src/MarkdownDeepTests/SafeModeTests.cs View File

@@ -0,0 +1,26 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NUnit.Framework;
using MarkdownDeep;
using System.Reflection;

namespace MarkdownDeepTests
{
[TestFixture]
class SafeModeTests
{
public static IEnumerable<TestCaseData> GetTests()
{
return Utils.GetTests("safemode");
}


[Test, TestCaseSource("GetTests")]
public void Test(string resourceName)
{
Utils.RunResourceTest(resourceName);
}
}
}

+ 26
- 0
src/MarkdownDeepTests/SpanLevelTests.cs View File

@@ -0,0 +1,26 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NUnit.Framework;
using MarkdownDeep;
using System.Reflection;

namespace MarkdownDeepTests
{
[TestFixture]
class SpanLevelTests
{
public static IEnumerable<TestCaseData> GetTests()
{
return Utils.GetTests("spantests");
}


[Test, TestCaseSource("GetTests")]
public void Test(string resourceName)
{
Utils.RunResourceTest(resourceName);
}
}
}

+ 81
- 0
src/MarkdownDeepTests/SpecialCharacterTests.cs View File

@@ -0,0 +1,81 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NUnit.Framework;
using MarkdownDeep;

namespace MarkdownDeepTests
{
[TestFixture]
public class SpecialCharacterTests
{
[SetUp]
public void SetUp()
{
f = new SpanFormatter(new Markdown());
}

SpanFormatter f;

[Test]
public void SimpleTag()
{
Assert.AreEqual(f.Format("pre <a> post"), "pre <a> post");
}

[Test]
public void TagWithAttributes()
{
Assert.AreEqual(f.Format("pre <a href=\"somewhere.html\" target=\"_blank\">link</a> post"), "pre <a href=\"somewhere.html\" target=\"_blank\">link</a> post");
}

[Test]
public void NotATag()
{
Assert.AreEqual("pre a &lt; b post",
f.Format("pre a < b post"));
}

[Test]
public void NotATag2()
{
Assert.AreEqual("pre a&lt;b post",
f.Format("pre a<b post"));
}

[Test]
public void AmpersandsInUrls()
{
Assert.AreEqual("pre <a href=\"somewhere.html?arg1=a&amp;arg2=b\" target=\"_blank\">link</a> post",
f.Format("pre <a href=\"somewhere.html?arg1=a&arg2=b\" target=\"_blank\">link</a> post"));
}

[Test]
public void AmpersandsInParagraphs()
{
Assert.AreEqual("pre this &amp; that post",
f.Format("pre this & that post"));
}

[Test]
public void HtmlEntities()
{
Assert.AreEqual("pre &amp; post",
f.Format("pre &amp; post"));
Assert.AreEqual("pre &#123; post",
f.Format("pre &#123; post"));
Assert.AreEqual("pre &#x1aF; post",
f.Format("pre &#x1aF; post"));
}

[Test]
public void EscapeChars()
{
Assert.AreEqual(@"\ ` * _ { } [ ] ( ) # + - . ! &gt;",
f.Format(@"\\ \` \* \_ \{ \} \[ \] \( \) \# \+ \- \. \! \>"));
}


}
}

+ 43
- 0
src/MarkdownDeepTests/StringScannerTests.cs View File

@@ -0,0 +1,43 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NUnit.Framework;
using MarkdownDeep;

namespace MarkdownDeepTests
{
[TestFixture]
class StringScannerTests
{
[Test]
public void Tests()
{
var p = new StringScanner();

p.Reset("This is a string with something [bracketed]");
Assert.IsTrue(p.bof);
Assert.IsFalse(p.eof);
Assert.IsTrue(p.SkipString("This"));
Assert.IsFalse(p.bof);
Assert.IsFalse(p.eof);
Assert.IsFalse(p.SkipString("huh?"));
Assert.IsTrue(p.SkipLinespace());
Assert.IsTrue(p.SkipChar('i'));
Assert.IsTrue(p.SkipChar('s'));
Assert.IsTrue(p.SkipWhitespace());
Assert.IsTrue(p.DoesMatchAny(new char[] { 'r', 'a', 't'} ));
Assert.IsFalse(p.Find("Not here"));
Assert.IsFalse(p.Find("WITH"));
Assert.IsFalse(p.FindI("Not here"));
Assert.IsTrue(p.FindI("WITH"));
Assert.IsTrue(p.Find('['));
p.SkipForward(1);
p.Mark();
Assert.IsTrue(p.Find(']'));
Assert.AreEqual("bracketed", p.Extract());
Assert.IsTrue(p.SkipChar(']'));
Assert.IsTrue(p.eof);
}
}
}

+ 85
- 0
src/MarkdownDeepTests/TableSpecTests.cs View File

@@ -0,0 +1,85 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NUnit.Framework;
using MarkdownDeep;

namespace MarkdownDeepTests
{
[TestFixture]
class TableSpecTests
{
[SetUp]
public void SetUp()
{
}

TableSpec Parse(string str)
{
var s = new StringScanner(str);
return TableSpec.Parse(s);
}

[Test]
public void Simple()
{
var s = Parse("--|--");

Assert.IsNotNull(s);
Assert.IsFalse(s.LeadingBar);
Assert.IsFalse(s.TrailingBar);
Assert.AreEqual(2, s.Columns.Count);
Assert.AreEqual(ColumnAlignment.NA, s.Columns[0]);
Assert.AreEqual(ColumnAlignment.NA, s.Columns[1]);
}

[Test]
public void Alignment()
{
var s = Parse("--|:--|--:|:--:");

Assert.IsNotNull(s);
Assert.IsFalse(s.LeadingBar);
Assert.IsFalse(s.TrailingBar);
Assert.AreEqual(4, s.Columns.Count);
Assert.AreEqual(ColumnAlignment.NA, s.Columns[0]);
Assert.AreEqual(ColumnAlignment.Left, s.Columns[1]);
Assert.AreEqual(ColumnAlignment.Right, s.Columns[2]);
Assert.AreEqual(ColumnAlignment.Center, s.Columns[3]);
}

[Test]
public void LeadingTrailingBars()
{
var s = Parse("|--|:--|--:|:--:|");

Assert.IsNotNull(s);
Assert.IsTrue(s.LeadingBar);
Assert.IsTrue(s.TrailingBar);
Assert.AreEqual(4, s.Columns.Count);
Assert.AreEqual(ColumnAlignment.NA, s.Columns[0]);
Assert.AreEqual(ColumnAlignment.Left, s.Columns[1]);
Assert.AreEqual(ColumnAlignment.Right, s.Columns[2]);
Assert.AreEqual(ColumnAlignment.Center, s.Columns[3]);
}


[Test]
public void Whitespace()
{
var s = Parse(" | -- | :-- | --: | :--: | ");

Assert.IsNotNull(s);
Assert.IsTrue(s.LeadingBar);
Assert.IsTrue(s.TrailingBar);
Assert.AreEqual(4, s.Columns.Count);
Assert.AreEqual(ColumnAlignment.NA, s.Columns[0]);
Assert.AreEqual(ColumnAlignment.Left, s.Columns[1]);
Assert.AreEqual(ColumnAlignment.Right, s.Columns[2]);
Assert.AreEqual(ColumnAlignment.Center, s.Columns[3]);
}


}
}

+ 145
- 0
src/MarkdownDeepTests/Utils.cs View File

@@ -0,0 +1,145 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using NUnit.Framework;
using System.Windows.Forms;

namespace MarkdownDeepTests
{
public static class Utils
{
public static IEnumerable<TestCaseData> GetTests(string foldername)
{
var names = Assembly.GetExecutingAssembly().GetManifestResourceNames();

return from name in Assembly.GetExecutingAssembly().GetManifestResourceNames()
where name.StartsWith("MarkdownDeepTests.testfiles." + foldername + ".") && (name.EndsWith(".txt") || name.EndsWith(".text"))
select new TestCaseData(name);
}

public static string LoadTextResource(string name)
{
// get a reference to the current assembly
var a = System.Reflection.Assembly.GetExecutingAssembly();
System.IO.StreamReader r = new System.IO.StreamReader(a.GetManifestResourceStream(name));
string str = r.ReadToEnd();
r.Close();

return str;
}

public static string strip_redundant_whitespace(string str)
{
StringBuilder sb = new StringBuilder();

str = str.Replace("\r\n", "\n");

int i = 0;
while (i < str.Length)
{
char ch = str[i];
switch (ch)
{
case ' ':
case '\t':
case '\r':
case '\n':
// Store start of white space
i++;

// Find end of whitespace
while (i < str.Length)
{
ch = str[i];
if (ch != ' ' && ch != '\t' && ch != '\r' && ch != '\n')
break;

i++;
}


// Replace with a single space
if (i < str.Length && str[i] != '<')
sb.Append(' ');

break;

case '>':
sb.Append("> ");
i++;
while (i < str.Length)
{
ch = str[i];
if (ch != ' ' && ch != '\t' && ch != '\r' && ch != '\n')
break;

i++;
}
break;

case '<':
if (i+5<str.Length && str.Substring(i, 5) == "<pre>")
{
sb.Append(" ");

// Special handling for pre blocks

// Find end
int end = str.IndexOf("</pre>", i);
if (end < 0)
end=str.Length;

// Append the pre block
sb.Append(str, i, end - i);
sb.Append(" ");

// Jump to end
i = end;
}
else
{
sb.Append(" <");
i++;
}
break;

default:
sb.Append(ch);
i++;
break;
}
}

return sb.ToString().Trim();
}

public static void RunResourceTest(string resourceName)
{
string input = Utils.LoadTextResource(resourceName);
string expected = Utils.LoadTextResource(System.IO.Path.ChangeExtension(resourceName, "html"));

var md = new MarkdownDeep.Markdown();
md.SafeMode = resourceName.IndexOf("(SafeMode)") >= 0;
md.ExtraMode = resourceName.IndexOf("(ExtraMode)") >= 0;
md.GitHubCodeBlocks = resourceName.IndexOf("(GitHubMode)") >= 0;
md.MarkdownInHtml = resourceName.IndexOf("(MarkdownInHtml)") >= 0;
md.AutoHeadingIDs = resourceName.IndexOf("(AutoHeadingIDs)") >= 0;

string actual = md.Transform(input);
string actual_clean = Utils.strip_redundant_whitespace(actual);
string expected_clean = Utils.strip_redundant_whitespace(expected);

string sep = new string('-', 30) + "\n";

Console.WriteLine("Input:\n" + sep + input);
Console.WriteLine("Actual:\n" + sep + actual);
Console.WriteLine("Expected:\n" + sep + expected);

Assert.AreEqual(expected_clean, actual_clean);
}
}
}


+ 136
- 0
src/MarkdownDeepTests/XssAttackTests.cs View File

@@ -0,0 +1,136 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MarkdownDeep;
using NUnit.Framework;
using System.Reflection;

namespace MarkdownDeepTests
{
[TestFixture]
public class XssAttackTests
{
public bool IsTagReallySafe(HtmlTag tag)
{
switch (tag.name)
{
case "B":
case "UL":
case "LI":
case "I":
return tag.attributes.Count == 0;

case "A":
case "a":
return tag.closing && tag.attributes.Count == 0;
}

return false;
}


public static IEnumerable<TestCaseData> GetTestsFromFile(string filename)
{
var tests = Utils.LoadTextResource("MarkdownDeepTests.testfiles.xsstests." + filename);

// Split into lines
string[] lines = tests.Replace("\r\n", "\n").Split('\n');

// Join bac
var strings = new List<string>();
string str = null;
foreach (var l in lines)
{
// Ignore
if (l.StartsWith("////"))
continue;

// Terminator?
if (l == "====== UNTESTED ======")
{
str = null;
break;
}

// Blank line?
if (String.IsNullOrEmpty(l.Trim()))
{
if (str != null)
strings.Add(str);
str = null;

continue;
}

if (str == null)
str = l;
else
str = str + "\n" + l;
}

if (str != null)
strings.Add(str);


return from s in strings select new TestCaseData(s);
}

public static IEnumerable<TestCaseData> GetAttacks()
{
return GetTestsFromFile("xss_attacks.txt");
}


[Test, TestCaseSource("GetAttacks")]
public void TestAttacksAreBlocked(string input)
{
StringScanner p = new StringScanner(input);

while (!p.eof)
{
HtmlTag tag=HtmlTag.Parse(p);
if (tag!=null)
{
if (tag.IsSafe())
{
// There's a few tags that really are safe in the test data
Assert.IsTrue(IsTagReallySafe(tag));
}
}
else
{
// Next character
p.SkipForward(1);
}
}
}

public static IEnumerable<TestCaseData> GetAllowed()
{
return GetTestsFromFile("non_attacks.txt");
}


[Test, TestCaseSource("GetAllowed")]
public void TestNonAttacksAreAllowed(string input)
{
StringScanner p = new StringScanner(input);

while (!p.eof)
{
HtmlTag tag = HtmlTag.Parse(p);
if (tag != null)
{
Assert.IsTrue(tag.IsSafe());
}
else
{
// Next character
p.SkipForward(1);
}
}
}

}
}

+ 13
- 0
src/MarkdownDeepTests/app.config View File

@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<configSections>
<sectionGroup name="NUnit">
<section name="TestRunner" type="System.Configuration.NameValueSectionHandler" />
</sectionGroup>
</configSections>
<NUnit>
<TestRunner>
<add key="ApartmentState" value="STA" />
</TestRunner>
</NUnit>
</configuration>

+ 4
- 0
src/MarkdownDeepTests/packages.config View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="NUnit" version="2.5.10.11092" />
</packages>

+ 38
- 0
src/MarkdownDeepTests/testfiles/blocktests/AtxHeadings.html View File

@@ -0,0 +1,38 @@
<h1>heading 1</h1>

<p>para</p>

<h1>heading 1</h1>

<p>para</p>

<h2>heading 2</h2>

<p>para</p>

<h2>heading 2</h2>

<p>para</p>

<h6>heading 6</h6>

<p>para</p>

<h6>heading 6</h6>

<p>para</p>

<h6>heading 6</h6>

<p>para</p>

<h6>heading 6</h6>

<p>para</p>

<h2>heading 2</h2>

<hr />

<p>para</p>


+ 39
- 0
src/MarkdownDeepTests/testfiles/blocktests/AtxHeadings.txt View File

@@ -0,0 +1,39 @@
# heading 1

para

# heading 1 #

para

## heading 2

para

## heading 2 ##

para

###### heading 6

para

###### heading 6 ######

para

############ heading 6

para

############ heading 6 ####################################

para


##heading 2##

-----

para


+ 12
- 0
src/MarkdownDeepTests/testfiles/blocktests/CodeBlocks.html View File

@@ -0,0 +1,12 @@
<p>before</p>
<pre><code>for (int i=0; i&lt;10; i++)
{
print(&quot;%i\n&quot;, i);
}
</code></pre>
<p>sep</p>
<pre><code>&lt;div&gt;
&lt;p&gt;Copyright &amp;copy; 2010
&lt;/div&gt;
</code></pre>
<p>after</p>

+ 14
- 0
src/MarkdownDeepTests/testfiles/blocktests/CodeBlocks.txt View File

@@ -0,0 +1,14 @@
before

for (int i=0; i<10; i++)
{
print("%i\n", i);
}
sep

<div>
<p>Copyright &copy; 2010
</div>

after

+ 27
- 0
src/MarkdownDeepTests/testfiles/blocktests/ComplexListItems.html View File

@@ -0,0 +1,27 @@
<p>before</p>
<ul>
<li>
<p>This is a list item</p>
<p>it contains some code</p>
<pre><code>for (int i=0; i&lt;10; i++)
{
printf(&quot;Hello World\n&quot;);
}
</code></pre>

<p>and a block quote:</p>
<blockquote>
<p>&quot;I have a dream&quot;</p>
</blockquote>
<p>and an embedded list</p>
<ul>
<li>Apples</li>
<li>Pears</li>
<li>Bananas</li>
</ul>
<p>and a hardwrapped
and left aligned paragraph</p>
</li>
</ul>
<p>after</p>


+ 25
- 0
src/MarkdownDeepTests/testfiles/blocktests/ComplexListItems.txt View File

@@ -0,0 +1,25 @@
before

* This is a list item

it contains some code
for (int i=0; i<10; i++)
{
printf("Hello World\n");
}
and a block quote:
> "I have a dream"
and an embedded list
* Apples
* Pears
* Bananas
and a hardwrapped
and left aligned paragraph
after

+ 19
- 0
src/MarkdownDeepTests/testfiles/blocktests/HardWrappedListItems.html View File

@@ -0,0 +1,19 @@
<ol>
<li>Apples
wrapped</li>
<li>Pears
wrapped</li>
<li>Bananas
wrapped</li>
</ol>

<p>sep</p>

<ol>
<li>Apples
wrapped</li>
<li>Pears
wrapped</li>
<li>Bananas
wrapped</li>
</ol>

+ 15
- 0
src/MarkdownDeepTests/testfiles/blocktests/HardWrappedListItems.txt View File

@@ -0,0 +1,15 @@
1. Apples
wrapped
2. Pears
wrapped
3. Bananas
wrapped

sep

1. Apples
wrapped
2. Pears
wrapped
3. Bananas
wrapped

+ 4
- 0
src/MarkdownDeepTests/testfiles/blocktests/HardWrappedParagraph.html View File

@@ -0,0 +1,4 @@
<p>p1
p2
p3
</p>

+ 3
- 0
src/MarkdownDeepTests/testfiles/blocktests/HardWrappedParagraph.txt View File

@@ -0,0 +1,3 @@
p1
p2
p3

+ 10
- 0
src/MarkdownDeepTests/testfiles/blocktests/HardWrappedParagraphInListItem.html View File

@@ -0,0 +1,10 @@
<p>before</p>
<ul>
<li>
<p>This is a list item</p>
<p>with a hardwrapped
and left aligned paragraph</p>
</li>
</ul>
<p>after</p>


+ 8
- 0
src/MarkdownDeepTests/testfiles/blocktests/HardWrappedParagraphInListItem.txt View File

@@ -0,0 +1,8 @@
before

* This is a list item
with a hardwrapped
and left aligned paragraph
after

+ 3
- 0
src/MarkdownDeepTests/testfiles/blocktests/HardWrappedParagraphWithListLikeLine.html View File

@@ -0,0 +1,3 @@
<p>This is a paragraph that was written in
2010. The year it was written shouldn't
be treated like a list item</p>

+ 3
- 0
src/MarkdownDeepTests/testfiles/blocktests/HardWrappedParagraphWithListLikeLine.txt View File

@@ -0,0 +1,3 @@
This is a paragraph that was written in
2010. The year it was written shouldn't
be treated like a list item

+ 1
- 0
src/MarkdownDeepTests/testfiles/blocktests/HtmlAttributeWithoutValue.html View File

@@ -0,0 +1 @@
<iframe y="2" allowfullscreen x="1" foo />

+ 1
- 0
src/MarkdownDeepTests/testfiles/blocktests/HtmlAttributeWithoutValue.txt View File

@@ -0,0 +1 @@
<iframe y="2" allowfullscreen x="1" foo />

+ 18
- 0
src/MarkdownDeepTests/testfiles/blocktests/HtmlBlock.html View File

@@ -0,0 +1,18 @@
<p>before</p>

<div class="MyClass">
<p>whatever</p>
</div>

<p>sep</p>

<div class="MyClass">
<div>
<div>
nested
</div>
</div>
</div>

<p>after</p>


+ 18
- 0
src/MarkdownDeepTests/testfiles/blocktests/HtmlBlock.txt View File

@@ -0,0 +1,18 @@
before

<div class="MyClass">
<p>whatever</p>
</div>

sep

<div class="MyClass">
<div>
<div>
nested
</div>
</div>
</div>


after

+ 10
- 0
src/MarkdownDeepTests/testfiles/blocktests/HtmlComments.html View File

@@ -0,0 +1,10 @@
<p>pre</p>

<!--
Multiline
HTML
Comments
-->

<p>post</p>


+ 9
- 0
src/MarkdownDeepTests/testfiles/blocktests/HtmlComments.txt View File

@@ -0,0 +1,9 @@
pre

<!--
Multiline
HTML
Comments
-->

post

+ 8
- 0
src/MarkdownDeepTests/testfiles/blocktests/InsTypes.html View File

@@ -0,0 +1,8 @@
<ins>
<p>Some text</p>
</ins>

<p><ins>And here it is inside a paragraph.</ins></p>

<p>And here it is <ins>in the middle of</ins> a paragraph.</p>


+ 7
- 0
src/MarkdownDeepTests/testfiles/blocktests/InsTypes.txt View File

@@ -0,0 +1,7 @@
<ins>
<p>Some text</p>
</ins>

<ins>And here it is inside a paragraph.</ins>

And here it is <ins>in the middle of</ins> a paragraph.

+ 2
- 0
src/MarkdownDeepTests/testfiles/blocktests/MultipleParagraphs.html View File

@@ -0,0 +1,2 @@
<p>p1</p>
<p>p2</p>

+ 3
- 0
src/MarkdownDeepTests/testfiles/blocktests/MultipleParagraphs.txt View File

@@ -0,0 +1,3 @@
p1

p2

+ 6
- 0
src/MarkdownDeepTests/testfiles/blocktests/NestedListItems.html View File

@@ -0,0 +1,6 @@
<ul>
<li>Tab
<ul><li>Tab
<ul><li>Tab</li></ul></li></ul></li>
</ul>


+ 4
- 0
src/MarkdownDeepTests/testfiles/blocktests/NestedListItems.txt View File

@@ -0,0 +1,4 @@
* Tab
* Tab
* Tab


+ 10
- 0
src/MarkdownDeepTests/testfiles/blocktests/ParagraphBreaks.html View File

@@ -0,0 +1,10 @@
<p>this is a paragraph<br />
with a contained break</p>

<h1>this is a heading</h1>
<p>followed by a paragraph</p>

<ul>
<li>an item<br />
with a contained break</li>
</ul>

+ 8
- 0
src/MarkdownDeepTests/testfiles/blocktests/ParagraphBreaks.txt View File

@@ -0,0 +1,8 @@
this is a paragraph
with a contained break

# this is a heading
followed by a paragraph

* an item
with a contained break

+ 53
- 0
src/MarkdownDeepTests/testfiles/blocktests/PartiallyIndentedLists.html View File

@@ -0,0 +1,53 @@
<p>pre</p>

<ol>
<li>
Outer 1
<ul>
<li>Inner 1</li>
<li>Inner 2</li>
</ul>
</li>
<li>Outer 2</li>
</ol>

<p>between</p>

<ul>
<li>
Outer 1
<ol>
<li>Inner 1</li>
<li>Inner 2</li>
</ol>
</li>
<li>Outer 2</li>
</ul>

<p>between</p>

<ul>
<li>
Outer 1
<ul>
<li>Inner 1</li>
<li>Inner 2</li>
</ul>
</li>
<li>Outer 2</li>
</ul>

<p>between</p>

<ol>
<li>
Outer 1
<ol>
<li>Inner 1</li>
<li>Inner 2</li>
</ol>
</li>
<li>Outer 2</li>
</ol>

<p>post</p>

+ 29
- 0
src/MarkdownDeepTests/testfiles/blocktests/PartiallyIndentedLists.txt View File

@@ -0,0 +1,29 @@
pre

1. Outer 1
- Inner 1
- Inner 2
2. Outer 2

between

* Outer 1
1. Inner 1
2. Inner 2
* Outer 2

between

* Outer 1
* Inner 1
* Inner 2
* Outer 2

between

1. Outer 1
1. Inner 1
2. Inner 2
2. Outer 2

post

+ 34
- 0
src/MarkdownDeepTests/testfiles/blocktests/QuoteBlocks.html View File

@@ -0,0 +1,34 @@
<p>before</p>
<blockquote>
<p>this is my quote
this is the second part</p>
</blockquote>
<p>after</p>

<p>before</p>
<blockquote>
<p>first line
hard wrapped</p>
<p>second line
hard wrapped</p>
</blockquote>
<p>after</p>

<p>before</p>
<blockquote>
<p>first line
hard wrapped indented</p>
<p>second line
hard wrapped indented</p>
</blockquote>
<p>after</p>

<p>before</p>
<blockquote>
<p>first line
hard wrapped</p>
<p>second line
hard wrapped</p>
</blockquote>
<p>after</p>


+ 36
- 0
src/MarkdownDeepTests/testfiles/blocktests/QuoteBlocks.txt View File

@@ -0,0 +1,36 @@
before

> this is my quote
> this is the second part

after

before

> first line
hard wrapped

> second line
hard wrapped

after

before

> first line
hard wrapped indented

> second line
hard wrapped indented

after

before

>first line
hard wrapped

>second line
hard wrapped

after

+ 16
- 0
src/MarkdownDeepTests/testfiles/blocktests/QuoteBlocksNested.html View File

@@ -0,0 +1,16 @@
<p>before</p>

<blockquote>
<p>this is my quote
this is the second part</p>
<blockquote>
<p>Nested</p>
</blockquote>

<pre><code>this is code
</code></pre>
</blockquote>

<p>after</p>


+ 10
- 0
src/MarkdownDeepTests/testfiles/blocktests/QuoteBlocksNested.txt View File

@@ -0,0 +1,10 @@
before

> this is my quote
> this is the second part
>
> > Nested
>
> this is code

after

+ 5
- 0
src/MarkdownDeepTests/testfiles/blocktests/SetExtHeadings.html View File

@@ -0,0 +1,5 @@
<p>Paragraph</p>

<h1>Header</h1>

<p>Paragraph</p>

+ 1
- 0
src/MarkdownDeepTests/testfiles/blocktests/SetExtHeadings.txt View File

@@ -0,0 +1 @@
Paragraph Header ====== Paragraph

+ 6
- 0
src/MarkdownDeepTests/testfiles/blocktests/SimpleOrderedList.html View File

@@ -0,0 +1,6 @@
<ol>
<li>Apples</li>
<li>Pears</li>
<li>Bananas</li>
</ol>


+ 3
- 0
src/MarkdownDeepTests/testfiles/blocktests/SimpleOrderedList.txt View File

@@ -0,0 +1,3 @@
1. Apples
2. Pears
3. Bananas

+ 1
- 0
src/MarkdownDeepTests/testfiles/blocktests/SimpleParagraph.html View File

@@ -0,0 +1 @@
<p>paragraph</p>

+ 1
- 0
src/MarkdownDeepTests/testfiles/blocktests/SimpleParagraph.txt View File

@@ -0,0 +1 @@
paragraph

+ 5
- 0
src/MarkdownDeepTests/testfiles/blocktests/SimpleUnorderedList.html View File

@@ -0,0 +1,5 @@
<ul>
<li>Apples</li>
<li>Pears</li>
<li>Bananas</li>
</ul>

+ 3
- 0
src/MarkdownDeepTests/testfiles/blocktests/SimpleUnorderedList.txt View File

@@ -0,0 +1,3 @@
* Apples
* Pears
* Bananas

+ 7
- 0
src/MarkdownDeepTests/testfiles/extramode/Abbreviations(ExtraMode).html View File

@@ -0,0 +1,7 @@
<p><abbr title="World Wide Web">WWW</abbr> at start of doc should match</p>
<p>A simple case: <abbr title="World Wide Web">WWW</abbr></p>
<p>A longer version: <abbr title="World Wide Web of Wonder :)">WWWW</abbr> shouldn't match the short one</p>
<p>This shouldn't match: aWWW nor this: WWWa.</p>
<p>This should: (<abbr title="World Wide Web">WWW</abbr>) as should this <em><abbr title="World Wide Web">WWW</abbr></em>.</p>
<p>Multiword abbreviations like &quot;<abbr title="Markdown made Better!">Markdown Deep</abbr>&quot; should also work.</p>


Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save