using Markdig.Syntax;
using Xunit;
namespace XFESystem.Documents.Tests;
public sealed class MarkdownRendererTests
{
private readonly MarkdownRenderer _renderer = new();
[Fact]
public void WebsitePipelineRendersHeadingsTablesAndFencedCode()
{
var html = _renderer.RenderHtml("# Notes\n\n| A | B |\n|---|---|\n| 1 | 2 |\n\n```js\nconsole.log('Hello');\n```\n");
Assert.Contains("id=\"notes\"", html);
Assert.Contains("<table>", html);
Assert.Contains("language-js", html);
Assert.IsType<HeadingBlock>(_renderer.Parse("# Test")[0]);
}
[Fact]
public void WebsiteSanitizationRemovesScriptEventsAndDangerousLinks()
{
var html = _renderer.RenderHtml("<script>alert(1)</script><button>Run</button><img src=\"x\" onerror=\"alert(2)\"><a href=\"javascript:alert(3)\">Link</a>");
Assert.DoesNotContain("<script", html, StringComparison.OrdinalIgnoreCase);
Assert.DoesNotContain("<button", html, StringComparison.OrdinalIgnoreCase);
Assert.DoesNotContain("onerror", html, StringComparison.OrdinalIgnoreCase);
Assert.DoesNotContain("javascript:", html, StringComparison.OrdinalIgnoreCase);
}
[Fact]
public void WebsiteAllowedHtmlAndCodeClassesRemainAvailable()
{
var html = _renderer.RenderHtml("<details id=\"More\" class=\"Notes\"><summary>More</summary><p>Content</p></details>");
Assert.Contains("<details", html);
Assert.Contains("id=\"More\"", html);
Assert.Contains("class=\"Notes\"", html);
}
[Theory]
[InlineData(null)]
[InlineData("")]
public void EmptyDocumentsRenderEmpty(string? text) => Assert.Empty(_renderer.RenderHtml(text));
[Fact]
public async Task ConcurrentDocumentsDoNotShareSanitizerMutation()
{
var results = await Task.WhenAll(Enumerable.Range(0, 32).Select(index => Task.Run(() =>
_renderer.RenderHtml($"# Document {index}\n<script>bad()</script>"))));
for (var index = 0; index < results.Length; index++)
{
Assert.Contains($"Document {index}", results[index]);
Assert.DoesNotContain("<script", results[index]);
}
}
}
using Markdig.Syntax;
using Xunit;
namespace XFESystem.Documents.Tests;
public sealed class MarkdownRendererTests
{
private readonly MarkdownRenderer _renderer = new();
[Fact]
public void WebsitePipelineRendersHeadingsTablesAndFencedCode()
{
var html = _renderer.RenderHtml("# Notes\n\n| A | B |\n|---|---|\n| 1 | 2 |\n\n```js\nconsole.log('Hello');\n```\n");
Assert.Contains("id=\"notes\"", html);
Assert.Contains("<table>", html);
Assert.Contains("language-js", html);
Assert.IsType<HeadingBlock>(_renderer.Parse("# Test")[0]);
}
[Fact]
public void WebsiteSanitizationRemovesScriptEventsAndDangerousLinks()
{
var html = _renderer.RenderHtml("<script>alert(1)</script><button>Run</button><img src=\"x\" onerror=\"alert(2)\"><a href=\"javascript:alert(3)\">Link</a>");
Assert.DoesNotContain("<script", html, StringComparison.OrdinalIgnoreCase);
Assert.DoesNotContain("<button", html, StringComparison.OrdinalIgnoreCase);
Assert.DoesNotContain("onerror", html, StringComparison.OrdinalIgnoreCase);
Assert.DoesNotContain("javascript:", html, StringComparison.OrdinalIgnoreCase);
}
[Fact]
public void WebsiteAllowedHtmlAndCodeClassesRemainAvailable()
{
var html = _renderer.RenderHtml("<details id=\"More\" class=\"Notes\"><summary>More</summary><p>Content</p></details>");
Assert.Contains("<details", html);
Assert.Contains("id=\"More\"", html);
Assert.Contains("class=\"Notes\"", html);
}
[Theory]
[InlineData(null)]
[InlineData("")]
public void EmptyDocumentsRenderEmpty(string? text) => Assert.Empty(_renderer.RenderHtml(text));
[Fact]
public async Task ConcurrentDocumentsDoNotShareSanitizerMutation()
{
var results = await Task.WhenAll(Enumerable.Range(0, 32).Select(index => Task.Run(() =>
_renderer.RenderHtml($"# Document {index}\n<script>bad()</script>"))));
for (var index = 0; index < results.Length; index++)
{
Assert.Contains($"Document {index}", results[index]);
Assert.DoesNotContain("<script", results[index]);
}
}
}