// 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: "We use http://example.com", 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: " and some text", Position: 5, Expected: "http://example.com", }, { Description: "link with https in angle brackets", Input: " and some text", Position: 6, Expected: "https://example.com", }, { Description: "link with ftp in angle brackets", Input: " and some text", Position: 4, Expected: "ftp://example.com", }, { Description: "link with a path in angle brackets", Input: " and some text", Position: 6, Expected: "https://example.com/abcd", }, { Description: "link with parameters in angle brackets", Input: " and some text", Position: 4, Expected: "ftp://example.com/abcd?foo=bar", }, { Description: "link, not at start in angle brackets", Input: "This is and some text", Position: 14, Expected: "https://example.com", }, { Description: "link with a path, not at start in angle brackets", Input: "This is also and some text", Position: 18, Expected: "http://www.example.com/abcd", }, { Description: "link with parameters, not at start in angle brackets", Input: "These are and some text", Position: 16, Expected: "https://www.example.com/abcd?foo=bar", }, { Description: "link with trailing characters in angle brackets", Input: "This is ", Position: 12, Expected: "ftp://www.example.com", }, { Description: "multiple links in angle brackets", Input: "This is and ", Position: 14, Expected: "https://example.com/abcd", }, { Description: "second of multiple links in angle brackets", Input: "This is and ", Position: 43, Expected: "ftp://www.example.com/1234", }, { Description: "multiple links with first one in angle brackets", Input: "This is 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 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 ", 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 ", Position: 41, Expected: "ftp://www.example.com/1234", }, { Description: "link with brackets wrapped in angle brackets", Input: "Go to and some text", Position: 10, Expected: "ftp://www.example.com/my/page_(disambiguation)", }, { Description: "link with angle brackets in parenthesis", Input: "()", Position: 7, Expected: "https://www.example.com/foo/bar", }, { Description: "link with angle brackets in underscores", Input: "__", Position: 6, Expected: "http://www.example.com", }, { Description: "link with angle brackets in asterisks", Input: "This is ****", Position: 14, Expected: "ftp://example.com", }, { Description: "link with angle brackets in strikethrough", Input: "Those were ~~~~", Position: 19, Expected: "https://example.com", }, { Description: "link with angle brackets in html tags", Input: "We use ", 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: "We use www2.example.com", 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: " and some text", Position: 1, Expected: "www.example.com", }, { Description: "link with a path in angle brackets", Input: " and some text", Position: 1, Expected: "www.example.com/abcd", }, { Description: "link with parameters in angle brackets", Input: " and some text", Position: 1, Expected: "www.example.com/abcd?foo=bar", }, { Description: "link in angle brackets, not at start", Input: "This is 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 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 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 ", Position: len("This is <"), Expected: "www.example.com", }, { Description: "link in angle brackets after current position", Input: "This is some text and ", Position: 0, Expected: "", }, { Description: "multiple links with angle brackets", Input: "This is and ", Position: len("This is <"), Expected: "www.example.com/abcd", }, { Description: "multiple links 2 with angle brackets", Input: "This is and ", Position: len("This is and <"), Expected: "www.example.com/1234", }, { Description: "multiple links, last one with angle brackets", Input: "This is www.example.com/abcd and ", 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 ", 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 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 and www.example.com/1234", Position: len("This is and "), Expected: "www.example.com/1234", }, { Description: "link with brackets in angle brackets", Input: "Go to and some text", Position: 7, Expected: "www.example.com/my/page_(disambiguation)", }, { Description: "link in angle brackets following other letters", Input: "aaa and some text", Position: 4, Expected: "www.example.com", }, { Description: "link with angle brackets in parentheses", Input: "()", Position: 2, Expected: "www.example.com", }, { Description: "link with angle brackets in underscores", Input: "__", Position: 2, Expected: "www.example.com", }, { Description: "link with angle brackets in asterisks", Input: "This is ****", Position: len("This is **<"), Expected: "www.example.com", }, { Description: "link with angle brackets in strikethrough", Input: "Those were ~~~~", Position: len("Those were ~~<"), Expected: "www.example.com", }, { Description: "link using www1 in angle brackets", Input: "Our backup site is at ", Position: len("Our backup site is at <"), Expected: "www1.example.com/foo", }, { Description: "link with angle brackets in html tags", Input: "We use ", Position: len("We use <"), Expected: "www2.example.com", }, { Description: "link with only opening angle bracket", Input: " 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: "We use www2.example.com", Position: 10, Expected: "www2.example.com", }, { Description: "link with only closing html tag", Input: "We use www2.example.com", 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"", 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: "", Start: 1, ExpectedEnd: 23, }, { Input: "", Start: 1, ExpectedEnd: 23, }, { Input: "this is a sentence containing in it", Start: len("this is a sentence containing <"), End: len("this is a sentence containing "), ExpectedEnd: 53, }, { Input: "this is a sentence containing ", Start: len("this is a sentence containing <"), End: len("this is a sentence containing "), 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: `

http://example.com

`, }, "valid-link-2": { Markdown: `https://example.com`, ExpectedHTML: `

https://example.com

`, }, "valid-link-3": { Markdown: `ftp://example.com`, ExpectedHTML: `

ftp://example.com

`, }, // "valid-link-4": { // Markdown: `ts3server://example.com?port=9000`, // ExpectedHTML: `

ts3server://example.com?port=9000

`, // }, "valid-link-5": { Markdown: `www.example.com`, ExpectedHTML: `

www.example.com

`, }, "valid-link-6": { Markdown: `www.example.com/index`, ExpectedHTML: `

www.example.com/index

`, }, "valid-link-7": { Markdown: `www.example.com/index.html`, ExpectedHTML: `

www.example.com/index.html

`, }, "valid-link-8": { Markdown: `http://example.com/index/sub`, ExpectedHTML: `

http://example.com/index/sub

`, }, "valid-link-9": { Markdown: `www1.example.com`, ExpectedHTML: `

www1.example.com

`, }, "valid-link-10": { Markdown: `https://en.wikipedia.org/wiki/URLs#Syntax`, ExpectedHTML: `

https://en.wikipedia.org/wiki/URLs#Syntax

`, }, "valid-link-11": { Markdown: `https://groups.google.com/forum/#!msg`, ExpectedHTML: `

https://groups.google.com/forum/#!msg

`, }, "valid-link-12": { Markdown: `www.example.com/index?params=1`, ExpectedHTML: `

www.example.com/index?params=1

`, }, "valid-link-13": { Markdown: `www.example.com/index?params=1&other=2`, ExpectedHTML: `

www.example.com/index?params=1&other=2

`, }, "valid-link-14": { Markdown: `www.example.com/index?params=1;other=2`, ExpectedHTML: `

www.example.com/index?params=1;other=2

`, }, "valid-link-15": { Markdown: `http://www.example.com/_/page`, ExpectedHTML: `

http://www.example.com/_/page

`, }, "valid-link-16": { Markdown: `https://en.wikipedia.org/wiki/🐬`, ExpectedHTML: `

https://en.wikipedia.org/wiki/🐬

`, }, "valid-link-17": { Markdown: `http://✪df.ws/1234`, ExpectedHTML: `

http://✪df.ws/1234

`, }, "valid-link-18": { Markdown: `https://groups.google.com/forum/#!msg`, ExpectedHTML: `

https://groups.google.com/forum/#!msg

`, }, "valid-link-19": { Markdown: `https://пример.срб/пример-26/`, ExpectedHTML: `

https://пример.срб/пример-26/

`, }, "valid-link-20": { Markdown: `mailto://test@example.com`, ExpectedHTML: `

mailto://test@example.com

`, }, "valid-link-21": { Markdown: `tel://555-123-4567`, ExpectedHTML: `

tel://555-123-4567

`, }, "ip-address-1": { Markdown: `http://127.0.0.1`, ExpectedHTML: `

http://127.0.0.1

`, }, "ip-address-2": { Markdown: `http://192.168.1.1:4040`, ExpectedHTML: `

http://192.168.1.1:4040

`, }, "ip-address-3": { Markdown: `http://username:password@127.0.0.1`, ExpectedHTML: `

http://username:password@127.0.0.1

`, }, "ip-address-4": { Markdown: `http://username:password@[2001:0:5ef5:79fb:303a:62d5:3312:ff42]:80`, ExpectedHTML: `

http://username:password@[2001:0:5ef5:79fb:303a:62d5:3312:ff42]:80

`, }, "link-with-brackets-1": { Markdown: `https://en.wikipedia.org/wiki/Rendering_(computer_graphics)`, ExpectedHTML: `

https://en.wikipedia.org/wiki/Rendering_(computer_graphics)

`, }, "link-with-brackets-2": { Markdown: `http://example.com/more_(than)_one_(parens)`, ExpectedHTML: `

http://example.com/more_(than)_one_(parens)

`, }, "link-with-brackets-3": { Markdown: `http://example.com/(something)?after=parens`, ExpectedHTML: `

http://example.com/(something)?after=parens

`, }, "link-with-brackets-4": { Markdown: `http://foo.com/unicode_(✪)_in_parens`, ExpectedHTML: `

http://foo.com/unicode_(✪)_in_parens

`, }, "inside-another-link-1": { Markdown: `[www.example.com](https://example.com)`, ExpectedHTML: `

www.example.com

`, }, "inside-another-link-2": { Markdown: `[http://www.example.com](https://example.com)`, ExpectedHTML: `

http://www.example.com

`, }, "link-in-sentence-1": { Markdown: `(http://example.com)`, ExpectedHTML: `

(http://example.com)

`, }, "link-in-sentence-2": { Markdown: `(see http://example.com)`, ExpectedHTML: `

(see http://example.com)

`, }, "link-in-sentence-3": { Markdown: `(http://example.com watch this)`, ExpectedHTML: `

(http://example.com watch this)

`, }, "link-in-sentence-4": { Markdown: `This is a sentence with a http://example.com in it.`, ExpectedHTML: `

This is a sentence with a http://example.com in it.

`, }, "link-in-sentence-5": { Markdown: `This is a sentence with a [link](http://example.com) in it.`, ExpectedHTML: `

This is a sentence with a link in it.

`, }, "link-in-sentence-6": { Markdown: `This is a sentence with a http://example.com/_/underscore in it.`, ExpectedHTML: `

This is a sentence with a http://example.com/_/underscore in it.

`, }, "link-in-sentence-7": { Markdown: `This is a sentence with a link (http://example.com) in it.`, ExpectedHTML: `

This is a sentence with a link (http://example.com) in it.

`, }, "link-in-sentence-8": { Markdown: `This is a sentence with a (https://en.wikipedia.org/wiki/Rendering_(computer_graphics)) in it.`, ExpectedHTML: `

This is a sentence with a (https://en.wikipedia.org/wiki/Rendering_(computer_graphics)) in it.

`, }, "link-in-sentence-9": { Markdown: `This is a sentence with a http://192.168.1.1:4040 in it.`, ExpectedHTML: `

This is a sentence with a http://192.168.1.1:4040 in it.

`, }, "link-in-sentence-10": { Markdown: `This is a link to http://example.com.`, ExpectedHTML: `

This is a link to http://example.com.

`, }, "link-in-sentence-11": { Markdown: `This is a link to http://example.com*`, ExpectedHTML: `

This is a link to http://example.com*

`, }, "link-in-sentence-12": { Markdown: `This is a link to http://example.com_`, ExpectedHTML: `

This is a link to http://example.com_

`, }, "link-in-sentence-13": { Markdown: `This is a link containing http://example.com/something?with,commas,in,url, but not at the end`, ExpectedHTML: `

This is a link containing http://example.com/something?with,commas,in,url, but not at the end

`, }, "link-in-sentence-14": { Markdown: `This is a question about a link http://example.com?`, ExpectedHTML: `

This is a question about a link http://example.com?

`, }, "plt-7250-link-with-trailing-periods-1": { Markdown: `http://example.com.`, ExpectedHTML: `

http://example.com.

`, }, "plt-7250-link-with-trailing-periods-2": { Markdown: `http://example.com...`, ExpectedHTML: `

http://example.com...

`, }, "plt-7250-link-with-trailing-periods-3": { Markdown: `http://example.com/foo.`, ExpectedHTML: `

http://example.com/foo.

`, }, "plt-7250-link-with-trailing-periods-4": { Markdown: `http://example.com/foo...`, ExpectedHTML: `

http://example.com/foo...

`, }, "plt-7250-link-with-trailing-periods-5": { Markdown: `http://example.com/foo.bar`, ExpectedHTML: `

http://example.com/foo.bar

`, }, "plt-7250-link-with-trailing-periods-6": { Markdown: `http://example.com/foo...bar`, ExpectedHTML: `

http://example.com/foo...bar

`, }, "rn-319-www-link-as-part-of-word-1": { Markdown: `testwww.example.com`, ExpectedHTML: `

testwww.example.com

`, }, "mm-10180-link-containing-period-followed-by-non-letter-1": { Markdown: `https://example.com/123.+Pagetitle`, ExpectedHTML: `

https://example.com/123.+Pagetitle

`, }, "mm-10180-link-containing-period-followed-by-non-letter-2": { Markdown: `https://example.com/123.?Pagetitle`, ExpectedHTML: `

https://example.com/123.?Pagetitle

`, }, "mm-10180-link-containing-period-followed-by-non-letter-3": { Markdown: `https://example.com/123.-Pagetitle`, ExpectedHTML: `

https://example.com/123.-Pagetitle

`, }, "mm-10180-link-containing-period-followed-by-non-letter-4": { Markdown: `https://example.com/123._Pagetitle`, ExpectedHTML: `

https://example.com/123._Pagetitle

`, }, "mm-10180-link-containing-period-followed-by-non-letter-5": { Markdown: `https://example.com/123.+`, ExpectedHTML: `

https://example.com/123.+

`, }, "mm-10180-link-containing-period-followed-by-non-letter-6": { Markdown: `https://example.com/123.?`, ExpectedHTML: `

https://example.com/123.?

`, }, "mm-10180-link-containing-period-followed-by-non-letter-7": { Markdown: `https://example.com/123.-`, ExpectedHTML: `

https://example.com/123.-

`, }, "mm-10180-link-containing-period-followed-by-non-letter-8": { Markdown: `https://example.com/123._`, ExpectedHTML: `

https://example.com/123._

`, }, } { 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) }) } }