From 520a7109c33716f86bcfb4dabb3627bf0fbf7c0a Mon Sep 17 00:00:00 2001 From: Martijn Laarman Date: Wed, 13 Nov 2024 12:29:22 +0100 Subject: [PATCH] Ensure include/literalinclude emits validation --- .../Myst/Directives/DirectiveBlock.cs | 21 +++++--- .../Myst/Directives/IncludeBlock.cs | 48 ++++++++++-------- .../Directives/UnsupportedDirectiveBlock.cs | 2 +- .../Directives/UnsupportedTests.cs | 3 +- .../FileInclusion/IncludeTests.cs | 49 +++++++++++++++++++ 5 files changed, 92 insertions(+), 31 deletions(-) diff --git a/src/Elastic.Markdown/Myst/Directives/DirectiveBlock.cs b/src/Elastic.Markdown/Myst/Directives/DirectiveBlock.cs index 5a2cb6d..23c6e52 100644 --- a/src/Elastic.Markdown/Myst/Directives/DirectiveBlock.cs +++ b/src/Elastic.Markdown/Myst/Directives/DirectiveBlock.cs @@ -69,18 +69,25 @@ public abstract class DirectiveBlock(DirectiveBlockParser parser, Dictionary public abstract void FinalizeAndValidate(ParserContext context); - protected void ParseBool(string key, Action setter) + protected bool PropBool(params string[] keys) { - var value = Properties.GetValueOrDefault(key); + var value = Prop(keys); if (string.IsNullOrEmpty(value)) + return Properties.ContainsKey(key); + + return bool.TryParse(value, out var result) && result; + } + + protected string? Prop(params string[] keys) + { + foreach (var key in keys) { - setter(Properties.ContainsKey(key)); - return; + if (Properties.TryGetValue(key, out var value)) + return value; } - if (bool.TryParse(value, out var result)) - setter(result); - //todo invalidate + return default; } + } diff --git a/src/Elastic.Markdown/Myst/Directives/IncludeBlock.cs b/src/Elastic.Markdown/Myst/Directives/IncludeBlock.cs index 8e4a18f..be25ca6 100644 --- a/src/Elastic.Markdown/Myst/Directives/IncludeBlock.cs +++ b/src/Elastic.Markdown/Myst/Directives/IncludeBlock.cs @@ -2,6 +2,7 @@ // Elasticsearch B.V licenses this file to you under the Apache 2.0 License. // See the LICENSE file in the project root for more information using System.IO.Abstractions; +using Elastic.Markdown.Diagnostics; namespace Elastic.Markdown.Myst.Directives; @@ -14,43 +15,46 @@ public class IncludeBlock(DirectiveBlockParser parser, Dictionary properties, ParserContext context) : base(parser, properties, context) => Literal = true; + + protected override string Directive { get; } = "literalinclude"; } diff --git a/src/Elastic.Markdown/Myst/Directives/UnsupportedDirectiveBlock.cs b/src/Elastic.Markdown/Myst/Directives/UnsupportedDirectiveBlock.cs index 6576c72..f0700bb 100644 --- a/src/Elastic.Markdown/Myst/Directives/UnsupportedDirectiveBlock.cs +++ b/src/Elastic.Markdown/Myst/Directives/UnsupportedDirectiveBlock.cs @@ -14,5 +14,5 @@ public class UnsupportedDirectiveBlock(DirectiveBlockParser parser, string direc public string IssueUrl => $"https://github.com/elastic/docs-builder/issues/{issueId}"; public override void FinalizeAndValidate(ParserContext context) => - context.EmitWarning(line:1, column:1, length:2, message: $"Directive block '{directive}' is unsupported. See {IssueUrl} for more information."); + context.EmitWarning(line:1, column:1, length:directive.Length, message: $"Directive block '{directive}' is unsupported. See {IssueUrl} for more information."); } diff --git a/tests/Elastic.Markdown.Tests/Directives/UnsupportedTests.cs b/tests/Elastic.Markdown.Tests/Directives/UnsupportedTests.cs index a5500f8..b22011c 100644 --- a/tests/Elastic.Markdown.Tests/Directives/UnsupportedTests.cs +++ b/tests/Elastic.Markdown.Tests/Directives/UnsupportedTests.cs @@ -33,8 +33,7 @@ A regular paragraph. [Fact] public void EmitsUnsupportedWarnings() { - Collector.Diagnostics.Should().NotBeNullOrEmpty() - .And.HaveCount(1); + Collector.Diagnostics.Should().NotBeNullOrEmpty().And.HaveCount(1); Collector.Diagnostics.Should().OnlyContain(d => d.Severity == Severity.Warning); Collector.Diagnostics.Should() .OnlyContain(d => d.Message.StartsWith($"Directive block '{directive}' is unsupported.")); diff --git a/tests/Elastic.Markdown.Tests/FileInclusion/IncludeTests.cs b/tests/Elastic.Markdown.Tests/FileInclusion/IncludeTests.cs index 0c46850..c77cfeb 100644 --- a/tests/Elastic.Markdown.Tests/FileInclusion/IncludeTests.cs +++ b/tests/Elastic.Markdown.Tests/FileInclusion/IncludeTests.cs @@ -1,6 +1,8 @@ // Licensed to Elasticsearch B.V under one or more agreements. // Elasticsearch B.V licenses this file to you under the Apache 2.0 License. // See the LICENSE file in the project root for more information + +using Elastic.Markdown.Diagnostics; using Elastic.Markdown.Myst.Directives; using Elastic.Markdown.Tests.Directives; using FluentAssertions; @@ -66,3 +68,50 @@ public void InclusionInheritsYamlContext() => .And.Be("

Hello bar

\n") ; } + + +public class IncludeNotFoundTests(ITestOutputHelper output) : DirectiveTest(output, +""" +```{include} _snippets/notfound.md +``` +""" +) +{ + [Fact] + public void ParsesBlock() => Block.Should().NotBeNull(); + + [Fact] + public void IncludesNothing() => Html.Should().Be(""); + + [Fact] + public void EmitsError() + { + Collector.Diagnostics.Should().NotBeNullOrEmpty().And.HaveCount(1); + Collector.Diagnostics.Should().OnlyContain(d => d.Severity == Severity.Error); + Collector.Diagnostics.Should() + .OnlyContain(d => d.Message.Contains("notfound.md` does not exist")); + } +} + +public class IncludeRequiresArgument(ITestOutputHelper output) : DirectiveTest(output, +""" +```{include} +``` +""" +) +{ + [Fact] + public void ParsesBlock() => Block.Should().NotBeNull(); + + [Fact] + public void IncludesNothing() => Html.Should().Be(""); + + [Fact] + public void EmitsError() + { + Collector.Diagnostics.Should().NotBeNullOrEmpty().And.HaveCount(1); + Collector.Diagnostics.Should().OnlyContain(d => d.Severity == Severity.Error); + Collector.Diagnostics.Should() + .OnlyContain(d => d.Message.Contains("include requires an argument.")); + } +}