mattermost-community-enterp.../public/shared/markdown/autolink_test.go
Claude ec1f89217a Merge: Complete Mattermost Server with Community Enterprise
Full Mattermost server source with integrated Community Enterprise features.
Includes vendor directory for offline/air-gapped builds.

Structure:
- enterprise-impl/: Enterprise feature implementations
- enterprise-community/: Init files that register implementations
- enterprise/: Bridge imports (community_imports.go)
- vendor/: All dependencies for offline builds

Build (online):
  go build ./cmd/mattermost

Build (offline/air-gapped):
  go build -mod=vendor ./cmd/mattermost

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-17 23:59:07 +09:00

1153 lines
36 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
package markdown
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestParseURLAutolink(t *testing.T) {
testCases := []struct {
Description string
Input string
Position int
Expected string
}{
{
Description: "no link",
Input: "This is an :emoji:",
Position: 11,
Expected: "",
},
{
Description: "no link 2",
Input: "These are two things: apple and orange",
Position: 20,
Expected: "",
},
{
Description: "link with http",
Input: "http://example.com and some text",
Position: 4,
Expected: "http://example.com",
},
{
Description: "link with https",
Input: "https://example.com and some text",
Position: 5,
Expected: "https://example.com",
},
{
Description: "link with ftp",
Input: "ftp://example.com and some text",
Position: 3,
Expected: "ftp://example.com",
},
{
Description: "link with a path",
Input: "https://example.com/abcd and some text",
Position: 5,
Expected: "https://example.com/abcd",
},
{
Description: "link with parameters",
Input: "ftp://example.com/abcd?foo=bar and some text",
Position: 3,
Expected: "ftp://example.com/abcd?foo=bar",
},
{
Description: "link, not at start",
Input: "This is https://example.com and some text",
Position: 13,
Expected: "https://example.com",
},
{
Description: "link with a path, not at start",
Input: "This is also http://www.example.com/abcd and some text",
Position: 17,
Expected: "http://www.example.com/abcd",
},
{
Description: "link with parameters, not at start",
Input: "These are https://www.example.com/abcd?foo=bar and some text",
Position: 15,
Expected: "https://www.example.com/abcd?foo=bar",
},
{
Description: "link with trailing characters",
Input: "This is ftp://www.example.com??",
Position: 11,
Expected: "ftp://www.example.com",
},
{
Description: "multiple links",
Input: "This is https://example.com/abcd and ftp://www.example.com/1234",
Position: 13,
Expected: "https://example.com/abcd",
},
{
Description: "second of multiple links",
Input: "This is https://example.com/abcd and ftp://www.example.com/1234",
Position: 40,
Expected: "ftp://www.example.com/1234",
},
{
Description: "link with brackets",
Input: "Go to ftp://www.example.com/my/page_(disambiguation) and some text",
Position: 9,
Expected: "ftp://www.example.com/my/page_(disambiguation)",
},
{
Description: "link in brackets",
Input: "(https://www.example.com/foo/bar)",
Position: 6,
Expected: "https://www.example.com/foo/bar",
},
{
Description: "link in underscores",
Input: "_http://www.example.com_",
Position: 5,
Expected: "http://www.example.com",
},
{
Description: "link in asterisks",
Input: "This is **ftp://example.com**",
Position: 13,
Expected: "ftp://example.com",
},
{
Description: "link in strikethrough",
Input: "Those were ~~https://example.com~~",
Position: 18,
Expected: "https://example.com",
},
{
Description: "link in html tags",
Input: "<b>We use http://example.com</b>",
Position: 14,
Expected: "http://example.com",
},
{
Description: "bad link protocol",
Input: "://///",
Position: 0,
Expected: "",
},
{
Description: "position greater than input length",
Input: "there is no colon",
Position: 1000,
Expected: "",
},
{
Description: "no link with angle brackets",
Input: "This is an <:emoji:>",
Position: 15,
Expected: "",
},
{
Description: "link with http in angle brackets",
Input: "<http://example.com> and some text",
Position: 5,
Expected: "http://example.com",
},
{
Description: "link with https in angle brackets",
Input: "<https://example.com> and some text",
Position: 6,
Expected: "https://example.com",
},
{
Description: "link with ftp in angle brackets",
Input: "<ftp://example.com> and some text",
Position: 4,
Expected: "ftp://example.com",
},
{
Description: "link with a path in angle brackets",
Input: "<https://example.com/abcd> and some text",
Position: 6,
Expected: "https://example.com/abcd",
},
{
Description: "link with parameters in angle brackets",
Input: "<ftp://example.com/abcd?foo=bar> and some text",
Position: 4,
Expected: "ftp://example.com/abcd?foo=bar",
},
{
Description: "link, not at start in angle brackets",
Input: "This is <https://example.com> and some text",
Position: 14,
Expected: "https://example.com",
},
{
Description: "link with a path, not at start in angle brackets",
Input: "This is also <http://www.example.com/abcd> and some text",
Position: 18,
Expected: "http://www.example.com/abcd",
},
{
Description: "link with parameters, not at start in angle brackets",
Input: "These are <https://www.example.com/abcd?foo=bar> and some text",
Position: 16,
Expected: "https://www.example.com/abcd?foo=bar",
},
{
Description: "link with trailing characters in angle brackets",
Input: "This is <ftp://www.example.com??>",
Position: 12,
Expected: "ftp://www.example.com",
},
{
Description: "multiple links in angle brackets",
Input: "This is <https://example.com/abcd> and <ftp://www.example.com/1234>",
Position: 14,
Expected: "https://example.com/abcd",
},
{
Description: "second of multiple links in angle brackets",
Input: "This is <https://example.com/abcd> and <ftp://www.example.com/1234>",
Position: 43,
Expected: "ftp://www.example.com/1234",
},
{
Description: "multiple links with first one in angle brackets",
Input: "This is <https://example.com/abcd> and ftp://www.example.com/1234",
Position: 14,
Expected: "https://example.com/abcd",
},
{
Description: "second of multiple links with first one in angle brackets",
Input: "This is <https://example.com/abcd> and ftp://www.example.com/1234",
Position: 42,
Expected: "ftp://www.example.com/1234",
},
{
Description: "multiple links with second one in angle brackets",
Input: "This is https://example.com/abcd and <ftp://www.example.com/1234>",
Position: 13,
Expected: "https://example.com/abcd",
},
{
Description: "second of multiple links with second one in angle brackets",
Input: "This is https://example.com/abcd and <ftp://www.example.com/1234>",
Position: 41,
Expected: "ftp://www.example.com/1234",
},
{
Description: "link with brackets wrapped in angle brackets",
Input: "Go to <ftp://www.example.com/my/page_(disambiguation)> and some text",
Position: 10,
Expected: "ftp://www.example.com/my/page_(disambiguation)",
},
{
Description: "link with angle brackets in parenthesis",
Input: "(<https://www.example.com/foo/bar>)",
Position: 7,
Expected: "https://www.example.com/foo/bar",
},
{
Description: "link with angle brackets in underscores",
Input: "_<http://www.example.com>_",
Position: 6,
Expected: "http://www.example.com",
},
{
Description: "link with angle brackets in asterisks",
Input: "This is **<ftp://example.com>**",
Position: 14,
Expected: "ftp://example.com",
},
{
Description: "link with angle brackets in strikethrough",
Input: "Those were ~~<https://example.com>~~",
Position: 19,
Expected: "https://example.com",
},
{
Description: "link with angle brackets in html tags",
Input: "<b>We use <http://example.com></b>",
Position: 15,
Expected: "http://example.com",
},
}
for _, testCase := range testCases {
t.Run(testCase.Description, func(t *testing.T) {
rawRange, ok := parseURLAutolink(testCase.Input, testCase.Position)
if testCase.Expected == "" {
assert.False(t, ok)
assert.Equal(t, Range{0, 0}, rawRange)
} else {
assert.True(t, ok)
assert.Equal(t, testCase.Expected, testCase.Input[rawRange.Position:rawRange.End])
}
})
}
}
func TestParseWWWAutolink(t *testing.T) {
testCases := []struct {
Description string
Input string
Position int
Expected string
}{
{
Description: "no link",
Input: "This is some text",
Position: 0,
Expected: "",
},
{
Description: "link",
Input: "www.example.com and some text",
Position: 0,
Expected: "www.example.com",
},
{
Description: "link with a path",
Input: "www.example.com/abcd and some text",
Position: 0,
Expected: "www.example.com/abcd",
},
{
Description: "link with parameters",
Input: "www.example.com/abcd?foo=bar and some text",
Position: 0,
Expected: "www.example.com/abcd?foo=bar",
},
{
Description: "link, not at start",
Input: "This is www.example.com and some text",
Position: 8,
Expected: "www.example.com",
},
{
Description: "link with a path, not at start",
Input: "This is also www.example.com/abcd and some text",
Position: 13,
Expected: "www.example.com/abcd",
},
{
Description: "link with parameters, not at start",
Input: "These are www.example.com/abcd?foo=bar and some text",
Position: 10,
Expected: "www.example.com/abcd?foo=bar",
},
{
Description: "link with trailing characters",
Input: "This is www.example.com??",
Position: 8,
Expected: "www.example.com",
},
{
Description: "link after current position",
Input: "This is some text and www.example.com",
Position: 0,
Expected: "",
},
{
Description: "multiple links",
Input: "This is www.example.com/abcd and www.example.com/1234",
Position: 8,
Expected: "www.example.com/abcd",
},
{
Description: "multiple links 2",
Input: "This is www.example.com/abcd and www.example.com/1234",
Position: 33,
Expected: "www.example.com/1234",
},
{
Description: "link with brackets",
Input: "Go to www.example.com/my/page_(disambiguation) and some text",
Position: 6,
Expected: "www.example.com/my/page_(disambiguation)",
},
{
Description: "link following other letters",
Input: "aaawww.example.com and some text",
Position: 3,
Expected: "",
},
{
Description: "link in brackets",
Input: "(www.example.com)",
Position: 1,
Expected: "www.example.com",
},
{
Description: "link in underscores",
Input: "_www.example.com_",
Position: 1,
Expected: "www.example.com",
},
{
Description: "link in asterisks",
Input: "This is **www.example.com**",
Position: 10,
Expected: "www.example.com",
},
{
Description: "link in strikethrough",
Input: "Those were ~~www.example.com~~",
Position: 13,
Expected: "www.example.com",
},
{
Description: "using www1",
Input: "Our backup site is at www1.example.com/foo",
Position: 22,
Expected: "www1.example.com/foo",
},
{
Description: "link in html tags",
Input: "<b>We use www2.example.com</b>",
Position: 10,
Expected: "www2.example.com",
},
{
Description: "no link, text with angle brackets",
Input: "This is some <> text",
Position: 0,
Expected: "",
},
{
Description: "link with angle brackets",
Input: "<www.example.com> and some text",
Position: 1,
Expected: "www.example.com",
},
{
Description: "link with a path in angle brackets",
Input: "<www.example.com/abcd> and some text",
Position: 1,
Expected: "www.example.com/abcd",
},
{
Description: "link with parameters in angle brackets",
Input: "<www.example.com/abcd?foo=bar> and some text",
Position: 1,
Expected: "www.example.com/abcd?foo=bar",
},
{
Description: "link in angle brackets, not at start",
Input: "This is <www.example.com> and some text",
Position: len("This is <"),
Expected: "www.example.com",
},
{
Description: "link with a path in angle brackets, not at start",
Input: "This is also <www.example.com/abcd> and some text",
Position: len("This is also <"),
Expected: "www.example.com/abcd",
},
{
Description: "link with parameters in angle brackets, not at start",
Input: "These are <www.example.com/abcd?foo=bar> and some text",
Position: len("These are <"),
Expected: "www.example.com/abcd?foo=bar",
},
{
Description: "link with trailing characters in angle brackets",
Input: "This is <www.example.com??>",
Position: len("This is <"),
Expected: "www.example.com",
},
{
Description: "link in angle brackets after current position",
Input: "This is some text and <www.example.com>",
Position: 0,
Expected: "",
},
{
Description: "multiple links with angle brackets",
Input: "This is <www.example.com/abcd> and <www.example.com/1234>",
Position: len("This is <"),
Expected: "www.example.com/abcd",
},
{
Description: "multiple links 2 with angle brackets",
Input: "This is <www.example.com/abcd> and <www.example.com/1234>",
Position: len("This is <www.example.com/abcd> and <"),
Expected: "www.example.com/1234",
},
{
Description: "multiple links, last one with angle brackets",
Input: "This is www.example.com/abcd and <www.example.com/1234>",
Position: len("This is "),
Expected: "www.example.com/abcd",
},
{
Description: "multiple links, last one with angle brackets 2",
Input: "This is www.example.com/abcd and <www.example.com/1234>",
Position: len("This is www.example.com/abcd and <"),
Expected: "www.example.com/1234",
},
{
Description: "multiple links, first one with angle brackets",
Input: "This is <www.example.com/abcd> and www.example.com/1234",
Position: len("This is <"),
Expected: "www.example.com/abcd",
},
{
Description: "multiple links, first one with angle brackets 2",
Input: "This is <www.example.com/abcd> and www.example.com/1234",
Position: len("This is <www.example.com/abcd> and "),
Expected: "www.example.com/1234",
},
{
Description: "link with brackets in angle brackets",
Input: "Go to <www.example.com/my/page_(disambiguation)> and some text",
Position: 7,
Expected: "www.example.com/my/page_(disambiguation)",
},
{
Description: "link in angle brackets following other letters",
Input: "aaa<www.example.com> and some text",
Position: 4,
Expected: "www.example.com",
},
{
Description: "link with angle brackets in parentheses",
Input: "(<www.example.com>)",
Position: 2,
Expected: "www.example.com",
},
{
Description: "link with angle brackets in underscores",
Input: "_<www.example.com>_",
Position: 2,
Expected: "www.example.com",
},
{
Description: "link with angle brackets in asterisks",
Input: "This is **<www.example.com>**",
Position: len("This is **<"),
Expected: "www.example.com",
},
{
Description: "link with angle brackets in strikethrough",
Input: "Those were ~~<www.example.com>~~",
Position: len("Those were ~~<"),
Expected: "www.example.com",
},
{
Description: "link using www1 in angle brackets",
Input: "Our backup site is at <www1.example.com/foo>",
Position: len("Our backup site is at <"),
Expected: "www1.example.com/foo",
},
{
Description: "link with angle brackets in html tags",
Input: "<b>We use <www2.example.com></b>",
Position: len("<b>We use <"),
Expected: "www2.example.com",
},
{
Description: "link with only opening angle bracket",
Input: "<www.example.com and some text",
Position: 1,
Expected: "www.example.com",
},
{
Description: "link with only closing angle bracket",
Input: "www.example.com> and some text",
Position: 0,
Expected: "www.example.com",
},
{
Description: "link with only opening bracket",
Input: "(www.example.com",
Position: 1,
Expected: "www.example.com",
},
{
Description: "link with only closing bracket",
Input: "www.example.com)",
Position: 0,
Expected: "www.example.com",
},
{
Description: "link with underscore at only start",
Input: "_www.example.com",
Position: 1,
Expected: "www.example.com",
},
{
Description: "link with underscore at only end",
Input: "www.example.com_",
Position: 0,
Expected: "www.example.com",
},
{
Description: "link with asterisks at only start",
Input: "This is **www.example.com",
Position: 10,
Expected: "www.example.com",
},
{
Description: "link with asterisks at only end",
Input: "This is www.example.com**",
Position: 8,
Expected: "www.example.com",
},
{
Description: "link with tildes at only start",
Input: "Those were ~~www.example.com",
Position: 13,
Expected: "www.example.com",
},
{
Description: "link with tildes at only end",
Input: "Those were www.example.com~~",
Position: 11,
Expected: "www.example.com",
},
{
Description: "link with only opening html tag",
Input: "<b>We use www2.example.com",
Position: 10,
Expected: "www2.example.com",
},
{
Description: "link with only closing html tag",
Input: "We use www2.example.com</b>",
Position: 7,
Expected: "www2.example.com",
},
}
for _, testCase := range testCases {
t.Run(testCase.Description, func(t *testing.T) {
rawRange, ok := parseWWWAutolink(testCase.Input, testCase.Position)
if testCase.Expected == "" {
assert.False(t, ok)
assert.Equal(t, Range{0, 0}, rawRange)
} else {
assert.True(t, ok)
assert.Equal(t, testCase.Expected, testCase.Input[rawRange.Position:rawRange.End])
}
})
}
}
func TestTrimTrailingCharactersFromLink(t *testing.T) {
testCases := []struct {
Input string
Start int
End int
ExpectedEnd int
}{
{
Input: "http://www.example.com",
ExpectedEnd: 22,
},
{
Input: "http://www.example.com/abcd",
ExpectedEnd: 27,
},
{
Input: "http://www.example.com/abcd/",
ExpectedEnd: 28,
},
{
Input: "http://www.example.com/1234",
ExpectedEnd: 27,
},
{
Input: "http://www.example.com/abcd?foo=bar",
ExpectedEnd: 35,
},
{
Input: "http://www.example.com/abcd#heading",
ExpectedEnd: 35,
},
{
Input: "http://www.example.com.",
ExpectedEnd: 22,
},
{
Input: "http://www.example.com,",
ExpectedEnd: 22,
},
{
Input: "http://www.example.com?",
ExpectedEnd: 22,
},
{
Input: "http://www.example.com)",
ExpectedEnd: 22,
},
{
Input: "http://www.example.com",
ExpectedEnd: 22,
},
{
Input: "https://en.wikipedia.org/wiki/Dolphin_(disambiguation)",
ExpectedEnd: 54,
},
{
Input: "https://en.wikipedia.org/wiki/Dolphin_(disambiguation",
ExpectedEnd: 53,
},
{
Input: "https://en.wikipedia.org/wiki/Dolphin_(disambiguation))",
ExpectedEnd: 54,
},
{
Input: "https://en.wikipedia.org/wiki/Dolphin_(disambiguation)_(disambiguation)",
ExpectedEnd: 71,
},
{
Input: "https://en.wikipedia.org/wiki/Dolphin_(disambiguation_(disambiguation))",
ExpectedEnd: 71,
},
{
Input: "http://www.example.com&quot;",
ExpectedEnd: 22,
},
{
Input: "this is a sentence containing http://www.example.com in it",
Start: 30,
End: 52,
ExpectedEnd: 52,
},
{
Input: "this is a sentence containing http://www.example.com???",
Start: 30,
End: 55,
ExpectedEnd: 52,
},
{
Input: "http://google.com/å",
ExpectedEnd: len("http://google.com/å"),
},
{
Input: "http://google.com/å...",
ExpectedEnd: len("http://google.com/å"),
},
{
Input: "This is http://google.com/å, a link, and http://google.com/å",
Start: 8,
End: len("This is http://google.com/å,"),
ExpectedEnd: len("This is http://google.com/å"),
},
{
Input: "This is http://google.com/å, a link, and http://google.com/å",
Start: 41,
End: len("This is http://google.com/å, a link, and http://google.com/å"),
ExpectedEnd: len("This is http://google.com/å, a link, and http://google.com/å"),
},
{
Input: "This is http://google.com/å, a link, and http://google.com/å.",
Start: 41,
End: len("This is http://google.com/å, a link, and http://google.com/å."),
ExpectedEnd: len("This is http://google.com/å, a link, and http://google.com/å"),
},
{
Input: "http://🍄.ga/ http://x🍄.ga/",
Start: 0,
End: len("http://🍄.ga/"),
ExpectedEnd: len("http://🍄.ga/"),
},
{
Input: "http://🍄.ga/ http://x🍄.ga/",
Start: len("http://🍄.ga/ "),
End: len("http://🍄.ga/ http://x🍄.ga/"),
ExpectedEnd: len("http://🍄.ga/ http://x🍄.ga/"),
},
{
Input: "<http://www.example.com>",
Start: 1,
ExpectedEnd: 23,
},
{
Input: "<http://www.example.com&quot;>",
Start: 1,
ExpectedEnd: 23,
},
{
Input: "this is a sentence containing <http://www.example.com> in it",
Start: len("this is a sentence containing <"),
End: len("this is a sentence containing <http://www.example.com>"),
ExpectedEnd: 53,
},
{
Input: "this is a sentence containing <http://www.example.com???>",
Start: len("this is a sentence containing <"),
End: len("this is a sentence containing <http://www.example.com???>"),
ExpectedEnd: 53,
},
}
for _, testCase := range testCases {
t.Run(testCase.Input, func(t *testing.T) {
if testCase.End == 0 {
testCase.End = len(testCase.Input) - testCase.Start
}
assert.Equal(t, testCase.ExpectedEnd, trimTrailingCharactersFromLink(testCase.Input, testCase.Start, testCase.End))
})
}
}
func TestAutolinking(t *testing.T) {
// These tests are adapted from https://github.com/mattermost/commonmark.js/test/mattermost.txt.
// It is missing tests for:
// 1. Links surrounded by emphasis (emphasis not implemented on the server)
// 2. IPv6 addresses (not implemented on the server or by GitHub)
// 3. Custom URL schemes (not implemented)
for name, tc := range map[string]struct {
Markdown string
ExpectedHTML string
}{
"valid-link-1": {
Markdown: `http://example.com`,
ExpectedHTML: `<p><a href="http://example.com">http://example.com</a></p>`,
},
"valid-link-2": {
Markdown: `https://example.com`,
ExpectedHTML: `<p><a href="https://example.com">https://example.com</a></p>`,
},
"valid-link-3": {
Markdown: `ftp://example.com`,
ExpectedHTML: `<p><a href="ftp://example.com">ftp://example.com</a></p>`,
},
// "valid-link-4": {
// Markdown: `ts3server://example.com?port=9000`,
// ExpectedHTML: `<p><a href="ts3server://example.com?port=9000">ts3server://example.com?port=9000</a></p>`,
// },
"valid-link-5": {
Markdown: `www.example.com`,
ExpectedHTML: `<p><a href="http://www.example.com">www.example.com</a></p>`,
},
"valid-link-6": {
Markdown: `www.example.com/index`,
ExpectedHTML: `<p><a href="http://www.example.com/index">www.example.com/index</a></p>`,
},
"valid-link-7": {
Markdown: `www.example.com/index.html`,
ExpectedHTML: `<p><a href="http://www.example.com/index.html">www.example.com/index.html</a></p>`,
},
"valid-link-8": {
Markdown: `http://example.com/index/sub`,
ExpectedHTML: `<p><a href="http://example.com/index/sub">http://example.com/index/sub</a></p>`,
},
"valid-link-9": {
Markdown: `www1.example.com`,
ExpectedHTML: `<p><a href="http://www1.example.com">www1.example.com</a></p>`,
},
"valid-link-10": {
Markdown: `https://en.wikipedia.org/wiki/URLs#Syntax`,
ExpectedHTML: `<p><a href="https://en.wikipedia.org/wiki/URLs#Syntax">https://en.wikipedia.org/wiki/URLs#Syntax</a></p>`,
},
"valid-link-11": {
Markdown: `https://groups.google.com/forum/#!msg`,
ExpectedHTML: `<p><a href="https://groups.google.com/forum/#!msg">https://groups.google.com/forum/#!msg</a></p>`,
},
"valid-link-12": {
Markdown: `www.example.com/index?params=1`,
ExpectedHTML: `<p><a href="http://www.example.com/index?params=1">www.example.com/index?params=1</a></p>`,
},
"valid-link-13": {
Markdown: `www.example.com/index?params=1&other=2`,
ExpectedHTML: `<p><a href="http://www.example.com/index?params=1&amp;other=2">www.example.com/index?params=1&amp;other=2</a></p>`,
},
"valid-link-14": {
Markdown: `www.example.com/index?params=1;other=2`,
ExpectedHTML: `<p><a href="http://www.example.com/index?params=1;other=2">www.example.com/index?params=1;other=2</a></p>`,
},
"valid-link-15": {
Markdown: `http://www.example.com/_/page`,
ExpectedHTML: `<p><a href="http://www.example.com/_/page">http://www.example.com/_/page</a></p>`,
},
"valid-link-16": {
Markdown: `https://en.wikipedia.org/wiki/🐬`,
ExpectedHTML: `<p><a href="https://en.wikipedia.org/wiki/%F0%9F%90%AC">https://en.wikipedia.org/wiki/🐬</a></p>`,
},
"valid-link-17": {
Markdown: `http://✪df.ws/1234`,
ExpectedHTML: `<p><a href="http://%E2%9C%AAdf.ws/1234">http://✪df.ws/1234</a></p>`,
},
"valid-link-18": {
Markdown: `https://groups.google.com/forum/#!msg`,
ExpectedHTML: `<p><a href="https://groups.google.com/forum/#!msg">https://groups.google.com/forum/#!msg</a></p>`,
},
"valid-link-19": {
Markdown: `https://пример.срб/пример-26/`,
ExpectedHTML: `<p><a href="https://%D0%BF%D1%80%D0%B8%D0%BC%D0%B5%D1%80.%D1%81%D1%80%D0%B1/%D0%BF%D1%80%D0%B8%D0%BC%D0%B5%D1%80-26/">https://пример.срб/пример-26/</a></p>`,
},
"valid-link-20": {
Markdown: `mailto://test@example.com`,
ExpectedHTML: `<p><a href="mailto://test@example.com">mailto://test@example.com</a></p>`,
},
"valid-link-21": {
Markdown: `tel://555-123-4567`,
ExpectedHTML: `<p><a href="tel://555-123-4567">tel://555-123-4567</a></p>`,
},
"ip-address-1": {
Markdown: `http://127.0.0.1`,
ExpectedHTML: `<p><a href="http://127.0.0.1">http://127.0.0.1</a></p>`,
},
"ip-address-2": {
Markdown: `http://192.168.1.1:4040`,
ExpectedHTML: `<p><a href="http://192.168.1.1:4040">http://192.168.1.1:4040</a></p>`,
},
"ip-address-3": {
Markdown: `http://username:password@127.0.0.1`,
ExpectedHTML: `<p><a href="http://username:password@127.0.0.1">http://username:password@127.0.0.1</a></p>`,
},
"ip-address-4": {
Markdown: `http://username:password@[2001:0:5ef5:79fb:303a:62d5:3312:ff42]:80`,
ExpectedHTML: `<p><a href="http://username:password@%5B2001:0:5ef5:79fb:303a:62d5:3312:ff42%5D:80">http://username:password@[2001:0:5ef5:79fb:303a:62d5:3312:ff42]:80</a></p>`,
},
"link-with-brackets-1": {
Markdown: `https://en.wikipedia.org/wiki/Rendering_(computer_graphics)`,
ExpectedHTML: `<p><a href="https://en.wikipedia.org/wiki/Rendering_(computer_graphics)">https://en.wikipedia.org/wiki/Rendering_(computer_graphics)</a></p>`,
},
"link-with-brackets-2": {
Markdown: `http://example.com/more_(than)_one_(parens)`,
ExpectedHTML: `<p><a href="http://example.com/more_(than)_one_(parens)">http://example.com/more_(than)_one_(parens)</a></p>`,
},
"link-with-brackets-3": {
Markdown: `http://example.com/(something)?after=parens`,
ExpectedHTML: `<p><a href="http://example.com/(something)?after=parens">http://example.com/(something)?after=parens</a></p>`,
},
"link-with-brackets-4": {
Markdown: `http://foo.com/unicode_(✪)_in_parens`,
ExpectedHTML: `<p><a href="http://foo.com/unicode_(%E2%9C%AA)_in_parens">http://foo.com/unicode_(✪)_in_parens</a></p>`,
},
"inside-another-link-1": {
Markdown: `[www.example.com](https://example.com)`,
ExpectedHTML: `<p><a href="https://example.com">www.example.com</a></p>`,
},
"inside-another-link-2": {
Markdown: `[http://www.example.com](https://example.com)`,
ExpectedHTML: `<p><a href="https://example.com">http://www.example.com</a></p>`,
},
"link-in-sentence-1": {
Markdown: `(http://example.com)`,
ExpectedHTML: `<p>(<a href="http://example.com">http://example.com</a>)</p>`,
},
"link-in-sentence-2": {
Markdown: `(see http://example.com)`,
ExpectedHTML: `<p>(see <a href="http://example.com">http://example.com</a>)</p>`,
},
"link-in-sentence-3": {
Markdown: `(http://example.com watch this)`,
ExpectedHTML: `<p>(<a href="http://example.com">http://example.com</a> watch this)</p>`,
},
"link-in-sentence-4": {
Markdown: `This is a sentence with a http://example.com in it.`,
ExpectedHTML: `<p>This is a sentence with a <a href="http://example.com">http://example.com</a> in it.</p>`,
},
"link-in-sentence-5": {
Markdown: `This is a sentence with a [link](http://example.com) in it.`,
ExpectedHTML: `<p>This is a sentence with a <a href="http://example.com">link</a> in it.</p>`,
},
"link-in-sentence-6": {
Markdown: `This is a sentence with a http://example.com/_/underscore in it.`,
ExpectedHTML: `<p>This is a sentence with a <a href="http://example.com/_/underscore">http://example.com/_/underscore</a> in it.</p>`,
},
"link-in-sentence-7": {
Markdown: `This is a sentence with a link (http://example.com) in it.`,
ExpectedHTML: `<p>This is a sentence with a link (<a href="http://example.com">http://example.com</a>) in it.</p>`,
},
"link-in-sentence-8": {
Markdown: `This is a sentence with a (https://en.wikipedia.org/wiki/Rendering_(computer_graphics)) in it.`,
ExpectedHTML: `<p>This is a sentence with a (<a href="https://en.wikipedia.org/wiki/Rendering_(computer_graphics)">https://en.wikipedia.org/wiki/Rendering_(computer_graphics)</a>) in it.</p>`,
},
"link-in-sentence-9": {
Markdown: `This is a sentence with a http://192.168.1.1:4040 in it.`,
ExpectedHTML: `<p>This is a sentence with a <a href="http://192.168.1.1:4040">http://192.168.1.1:4040</a> in it.</p>`,
},
"link-in-sentence-10": {
Markdown: `This is a link to http://example.com.`,
ExpectedHTML: `<p>This is a link to <a href="http://example.com">http://example.com</a>.</p>`,
},
"link-in-sentence-11": {
Markdown: `This is a link to http://example.com*`,
ExpectedHTML: `<p>This is a link to <a href="http://example.com">http://example.com</a>*</p>`,
},
"link-in-sentence-12": {
Markdown: `This is a link to http://example.com_`,
ExpectedHTML: `<p>This is a link to <a href="http://example.com">http://example.com</a>_</p>`,
},
"link-in-sentence-13": {
Markdown: `This is a link containing http://example.com/something?with,commas,in,url, but not at the end`,
ExpectedHTML: `<p>This is a link containing <a href="http://example.com/something?with,commas,in,url">http://example.com/something?with,commas,in,url</a>, but not at the end</p>`,
},
"link-in-sentence-14": {
Markdown: `This is a question about a link http://example.com?`,
ExpectedHTML: `<p>This is a question about a link <a href="http://example.com">http://example.com</a>?</p>`,
},
"plt-7250-link-with-trailing-periods-1": {
Markdown: `http://example.com.`,
ExpectedHTML: `<p><a href="http://example.com">http://example.com</a>.</p>`,
},
"plt-7250-link-with-trailing-periods-2": {
Markdown: `http://example.com...`,
ExpectedHTML: `<p><a href="http://example.com">http://example.com</a>...</p>`,
},
"plt-7250-link-with-trailing-periods-3": {
Markdown: `http://example.com/foo.`,
ExpectedHTML: `<p><a href="http://example.com/foo">http://example.com/foo</a>.</p>`,
},
"plt-7250-link-with-trailing-periods-4": {
Markdown: `http://example.com/foo...`,
ExpectedHTML: `<p><a href="http://example.com/foo">http://example.com/foo</a>...</p>`,
},
"plt-7250-link-with-trailing-periods-5": {
Markdown: `http://example.com/foo.bar`,
ExpectedHTML: `<p><a href="http://example.com/foo.bar">http://example.com/foo.bar</a></p>`,
},
"plt-7250-link-with-trailing-periods-6": {
Markdown: `http://example.com/foo...bar`,
ExpectedHTML: `<p><a href="http://example.com/foo...bar">http://example.com/foo...bar</a></p>`,
},
"rn-319-www-link-as-part-of-word-1": {
Markdown: `testwww.example.com`,
ExpectedHTML: `<p>testwww.example.com</p>`,
},
"mm-10180-link-containing-period-followed-by-non-letter-1": {
Markdown: `https://example.com/123.+Pagetitle`,
ExpectedHTML: `<p><a href="https://example.com/123.+Pagetitle">https://example.com/123.+Pagetitle</a></p>`,
},
"mm-10180-link-containing-period-followed-by-non-letter-2": {
Markdown: `https://example.com/123.?Pagetitle`,
ExpectedHTML: `<p><a href="https://example.com/123.?Pagetitle">https://example.com/123.?Pagetitle</a></p>`,
},
"mm-10180-link-containing-period-followed-by-non-letter-3": {
Markdown: `https://example.com/123.-Pagetitle`,
ExpectedHTML: `<p><a href="https://example.com/123.-Pagetitle">https://example.com/123.-Pagetitle</a></p>`,
},
"mm-10180-link-containing-period-followed-by-non-letter-4": {
Markdown: `https://example.com/123._Pagetitle`,
ExpectedHTML: `<p><a href="https://example.com/123._Pagetitle">https://example.com/123._Pagetitle</a></p>`,
},
"mm-10180-link-containing-period-followed-by-non-letter-5": {
Markdown: `https://example.com/123.+`,
ExpectedHTML: `<p><a href="https://example.com/123.+">https://example.com/123.+</a></p>`,
},
"mm-10180-link-containing-period-followed-by-non-letter-6": {
Markdown: `https://example.com/123.?`,
ExpectedHTML: `<p><a href="https://example.com/123">https://example.com/123</a>.?</p>`,
},
"mm-10180-link-containing-period-followed-by-non-letter-7": {
Markdown: `https://example.com/123.-`,
ExpectedHTML: `<p><a href="https://example.com/123.-">https://example.com/123.-</a></p>`,
},
"mm-10180-link-containing-period-followed-by-non-letter-8": {
Markdown: `https://example.com/123._`,
ExpectedHTML: `<p><a href="https://example.com/123">https://example.com/123</a>._</p>`,
},
} {
t.Run(name, func(t *testing.T) {
assert.Equal(t, tc.ExpectedHTML, RenderHTML(tc.Markdown))
})
}
}
func Test_isAllowedBeforeWWWLink(t *testing.T) {
type args struct {
c byte
}
tests := []struct {
name string
args args
want bool
}{
{
name: "empty space",
args: args{
c: byte(' '),
},
want: false,
},
{
name: "asterisk",
args: args{
c: byte('*'),
},
want: true,
},
{
name: "underscore",
args: args{
c: byte('_'),
},
want: true,
},
{
name: "open parenthesis",
args: args{
c: byte('('),
},
want: true,
},
{
name: "close parenthesis",
args: args{
c: byte(')'),
},
want: true,
},
{
name: "tilde",
args: args{
c: byte('~'),
},
want: true,
},
{
name: "open angle bracket",
args: args{
c: byte('<'),
},
want: true,
},
{
name: "close angle bracket",
args: args{
c: byte('>'),
},
want: true,
},
{
name: "alphabet",
args: args{
c: byte('c'),
},
want: false,
},
{
name: "number",
args: args{
c: byte('4'),
},
want: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
assert.Equalf(t, tt.want, isAllowedBeforeWWWLink(tt.args.c), "isAllowedBeforeWWWLink(%v)", tt.args.c)
})
}
}