102 lines
3.8 KiB
C#
102 lines
3.8 KiB
C#
using Wiki.Core.Model;
|
|
using Wiki.Core.Parsing;
|
|
|
|
namespace Wiki.Core.Tests;
|
|
|
|
public class ArticleFileTests
|
|
{
|
|
private static readonly Article Sample = new(
|
|
"de",
|
|
"wall-switches",
|
|
"Wandschalter: Konvention",
|
|
ArticleCategory.System,
|
|
ArticleVisibility.Public,
|
|
[new ArticleSource("schalter-konvention-blueprint-system", "abc123"), new ArticleSource("heizung", "def456")],
|
|
new DateOnly(2026, 10, 24),
|
|
"claude-opus-5-5",
|
|
"Lead [[heizung]].\n\n::: private\nx\n:::\n");
|
|
|
|
private static Document Load(string text, string slug = "de/wall-switches") =>
|
|
DocumentParser.Parse(new DocumentRef(DocumentKind.Article, slug, DocumentParser.PathFor(DocumentKind.Article, slug), "h"), text);
|
|
|
|
[Fact]
|
|
public void ArticleFile_RoundTrip()
|
|
{
|
|
var text = ArticleFile.Build(Sample);
|
|
Assert.Contains("visibility: public\n", text);
|
|
Assert.Contains("category: system\n", text);
|
|
Assert.Contains(" - schalter-konvention-blueprint-system@abc123\n", text);
|
|
Assert.Contains(" - heizung@def456\n", text);
|
|
Assert.Equal(Sample, ArticleFile.Parse(Load(text)));
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData("A: \"B\"")]
|
|
[InlineData("Pfad C:\\x: \"y\"")]
|
|
[InlineData("[x]")]
|
|
[InlineData("{x}")]
|
|
[InlineData("a\\\\b: c")]
|
|
[InlineData("\"quoted\"")]
|
|
public void ArticleFile_RoundTrip_AmbiguousTitles(string title)
|
|
{
|
|
var article = Sample with { Title = title, Model = title };
|
|
Assert.Equal(article, ArticleFile.Parse(Load(ArticleFile.Build(article))));
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData("title: \"say \\\"hi\\\" \\\\ C:\\x\"", "say \"hi\" \\ C:\\x")]
|
|
[InlineData("title: 'it \\\"s'", "it \\\"s")]
|
|
[InlineData("title: plain \\\" text", "plain \\\" text")]
|
|
public void Frontmatter_DoubleQuotedEscapes_AreUnescaped(string line, string expected)
|
|
{
|
|
var (fields, _, _) = Frontmatter.Parse($"---\n{line}\n---\n");
|
|
Assert.Equal(expected, fields["title"].Scalar);
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData("visibility: public\n", "")]
|
|
[InlineData("visibility: public\n", "visibility: secret\n")]
|
|
[InlineData("visibility: public\n", "visibility:\n")]
|
|
public void Parse_MissingOrInvalidVisibility_IsPrivate(string from, string to)
|
|
{
|
|
var text = ArticleFile.Build(Sample).Replace(from, to);
|
|
Assert.Equal(ArticleVisibility.Private, ArticleFile.Parse(Load(text)).Visibility);
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData("subject: wall-switches\n", "subject: other\n")]
|
|
[InlineData("subject: wall-switches\n", "")]
|
|
[InlineData("lang: de\n", "lang: en\n")]
|
|
[InlineData("category: system\n", "category: 1\n")]
|
|
[InlineData("category: system\n", "")]
|
|
[InlineData("generated: 2026-10-24\n", "generated: soon\n")]
|
|
[InlineData("model: claude-opus-5-5\n", "")]
|
|
[InlineData(" - heizung@def456\n", " - heizung\n")]
|
|
public void Parse_BadRequiredKey_Throws(string from, string to)
|
|
{
|
|
var text = ArticleFile.Build(Sample).Replace(from, to);
|
|
Assert.Throws<FormatException>(() => ArticleFile.Parse(Load(text)));
|
|
}
|
|
|
|
[Fact]
|
|
public void Parse_UnsupportedLang_Throws()
|
|
{
|
|
var text = ArticleFile.Build(Sample).Replace("lang: de\n", "lang: fr\n");
|
|
Assert.Throws<FormatException>(() => ArticleFile.Parse(Load(text, "fr/wall-switches")));
|
|
}
|
|
|
|
[Fact]
|
|
public void Parse_NonArticleDocument_Throws()
|
|
{
|
|
var doc = DocumentParser.Parse(new DocumentRef(DocumentKind.Wiki, "x", "wiki/x.md", "h"), ArticleFile.Build(Sample));
|
|
Assert.Throws<FormatException>(() => ArticleFile.Parse(doc));
|
|
}
|
|
|
|
[Fact]
|
|
public void Build_NewlineInScalar_Throws()
|
|
{
|
|
Assert.Throws<ArgumentException>(() => ArticleFile.Build(Sample with { Title = "T\nvisibility: public" }));
|
|
Assert.Throws<ArgumentException>(() => ArticleFile.Build(Sample with { Slug = "../x" }));
|
|
}
|
|
}
|