125 lines
4.2 KiB
Go
125 lines
4.2 KiB
Go
package validation
|
|
|
|
import (
|
|
"context"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
func TestParseMarkdownLinksAndSourceLocations(t *testing.T) {
|
|
source := []byte("" +
|
|
"é [inline](docs/a\\(b\\).md \"inline title\").\n" +
|
|
"\n" +
|
|
"[ref][target] then [ref][target].\n" +
|
|
"[collapsed][] and [shortcut].\n" +
|
|
"![logo][badge]\n" +
|
|
"\n" +
|
|
"[target]: docs/target.md \"reference title\"\n" +
|
|
"[collapsed]: child.md\n" +
|
|
"[shortcut]: short.md\n" +
|
|
"[badge]: badge.png\n" +
|
|
"Inline example: `[fake](fake.md)`.\n" +
|
|
"```md\n[also fake](fenced.md)\n```\n" +
|
|
"[undefined]\n" +
|
|
"Autolink <https://example.invalid>.\n" +
|
|
"<a href=\"raw.html\">HTML</a>\n")
|
|
document := parseMarkdown(source)
|
|
|
|
want := []markdownLink{
|
|
{Destination: "docs/a(b).md", Title: "inline title", Location: markdownLocation{Line: 1, Column: 4}},
|
|
{Destination: "images/chart one.svg", Title: "image title", Image: true, Location: markdownLocation{Line: 2, Column: 1}},
|
|
{Destination: "docs/target.md", Title: "reference title", Reference: true, Location: markdownLocation{Line: 3, Column: 1}},
|
|
{Destination: "docs/target.md", Title: "reference title", Reference: true, Location: markdownLocation{Line: 3, Column: 20}},
|
|
{Destination: "child.md", Reference: true, Location: markdownLocation{Line: 4, Column: 1}},
|
|
{Destination: "short.md", Reference: true, Location: markdownLocation{Line: 4, Column: 19}},
|
|
{Destination: "badge.png", Image: true, Reference: true, Location: markdownLocation{Line: 5, Column: 1}},
|
|
{Destination: "https://example.invalid", Location: markdownLocation{Line: 16, Column: 10}},
|
|
}
|
|
if len(document.links) != len(want) {
|
|
t.Fatalf("found %d links, want %d: %#v", len(document.links), len(want), document.links)
|
|
}
|
|
for index := range want {
|
|
if got := document.links[index]; got != want[index] {
|
|
t.Errorf("link %d = %#v, want %#v", index, got, want[index])
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestParseMarkdownDecodesEntitiesInDestinations(t *testing.T) {
|
|
document := parseMarkdown([]byte("[entity](<a&b.md>)\n"))
|
|
if len(document.links) != 1 || document.links[0].Destination != "a&b.md" {
|
|
t.Fatalf("parsed links = %#v, want decoded destination a&b.md", document.links)
|
|
}
|
|
}
|
|
|
|
func TestParseMarkdownHeadingAnchors(t *testing.T) {
|
|
source := []byte("" +
|
|
"# Café & 東京 `Code Here` <em>Bold</em>!\n" +
|
|
"Setext **Heading**\n" +
|
|
"---\n" +
|
|
"# Foo\n" +
|
|
"# Foo\n" +
|
|
"# Foo-1\n" +
|
|
"# Foo\n" +
|
|
"# Foo-1\n" +
|
|
"# <https://example.invalid>\n" +
|
|
"# <maintainer@example.invalid>\n" +
|
|
"# Contact <maintainer@example.invalid> Today\n")
|
|
document := parseMarkdown(source)
|
|
for _, anchor := range []string{
|
|
"café--東京-code-here-bold",
|
|
"setext-heading",
|
|
"foo",
|
|
"foo-1",
|
|
"foo-1-1",
|
|
"foo-2",
|
|
"foo-1-2",
|
|
"httpsexampleinvalid",
|
|
"maintainerexampleinvalid",
|
|
"contact-maintainerexampleinvalid-today",
|
|
} {
|
|
if _, ok := document.anchors[anchor]; !ok {
|
|
t.Errorf("missing anchor %q in %#v", anchor, document.anchors)
|
|
}
|
|
}
|
|
if len(document.anchors) != 10 {
|
|
t.Fatalf("found %d anchors, want 10: %#v", len(document.anchors), document.anchors)
|
|
}
|
|
}
|
|
|
|
func TestMarkdownCacheKeepsParsedDocumentsPerCandidatePath(t *testing.T) {
|
|
repository := newTreeRepository(t)
|
|
writeTreeFile(t, repository, "guide.md", []byte("# Guide\n[other](other.md)\n"))
|
|
writeTreeFile(t, repository, "other.md", []byte("# Other\n"))
|
|
gitTree(t, repository, "add", "guide.md", "other.md")
|
|
gitTree(t, repository, "commit", "-m", "add markdown files")
|
|
|
|
commit := strings.TrimSpace(gitTree(t, repository, "rev-parse", "HEAD"))
|
|
tree, err := ReadCandidateTree(context.Background(), repository, commit)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
cache := newMarkdownCache(tree)
|
|
first, err := cache.document(context.Background(), "guide.md")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
second, err := cache.document(context.Background(), "guide.md")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if first != second {
|
|
t.Fatal("repeated document lookup returned a different parsed document")
|
|
}
|
|
other, err := cache.document(context.Background(), "other.md")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if other == first {
|
|
t.Fatal("different candidate paths shared a parsed document")
|
|
}
|
|
if _, ok := other.anchors["other"]; !ok {
|
|
t.Fatalf("other document anchors = %#v", other.anchors)
|
|
}
|
|
}
|