// Copyright 2017 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT package markdown_test import ( "html/template" "strings" "testing" "code.gitea.io/gitea/modules/gitrepo" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/markup" "code.gitea.io/gitea/modules/markup/markdown" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/svg" "code.gitea.io/gitea/modules/test" "code.gitea.io/gitea/modules/util" "github.com/stretchr/testify/assert" "golang.org/x/text/cases" "golang.org/x/text/language" ) const ( AppURL = "http://localhost:3000/" testRepoOwnerName = "user13" testRepoName = "repo11" FullURL = AppURL + testRepoOwnerName + "/" + testRepoName + "/" ) // these values should match the const above var localMetas = map[string]string{ "user": testRepoOwnerName, "repo": testRepoName, } var localWikiMetas = map[string]string{ "user": testRepoOwnerName, "repo": testRepoName, "markupContentMode": "wiki", } type mockRepo struct { OwnerName string RepoName string } func (m *mockRepo) GetOwnerName() string { return m.OwnerName } func (m *mockRepo) GetName() string { return m.RepoName } func newMockRepo(ownerName, repoName string) gitrepo.Repository { return &mockRepo{ OwnerName: ownerName, RepoName: repoName, } } func TestRender_StandardLinks(t *testing.T) { setting.AppURL = AppURL test := func(input, expected, expectedWiki string) { buffer, err := markdown.RenderString(markup.NewTestRenderContext(markup.Links{Base: FullURL}), input) assert.NoError(t, err) assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(string(buffer))) buffer, err = markdown.RenderString(markup.NewTestRenderContext(markup.Links{Base: FullURL}, localWikiMetas), input) assert.NoError(t, err) assert.Equal(t, strings.TrimSpace(expectedWiki), strings.TrimSpace(string(buffer))) } googleRendered := `
` test("Wiki! Enjoy :)
See commit 65f1bf27bc
Ideas and codes
Wine Staging on website wine-staging.com.
Here are some links to the most important topics. You can find the full list of pages at the sidebar.
Installation | |
---|---|
Usage |
Excelsior JET allows you to create native executables for Windows, Linux and Mac OS X.
(from https://www.markdownguide.org/extended-syntax/)
Here is a simple footnote,1 and here is a longer one.2
This PR has been generated by Renovate Bot.
`, } } // Test cases without ambiguous links var sameCases = []string{ // dear imgui wiki markdown extract: special wiki syntax `Wiki! Enjoy :) - [[Links, Language bindings, Engine bindings|Links]] - [[Tips]] See commit 65f1bf27bc Ideas and codes - Bezier widget (by @r-lyeh) ` + AppURL + `ocornut/imgui/issues/786 - Bezier widget (by @r-lyeh) ` + FullURL + `issues/786 - Node graph editors https://github.com/ocornut/imgui/issues/306 - [[Memory Editor|memory_editor_example]] - [[Plot var helper|plot_var_example]]`, // wine-staging wiki home extract: tables, special wiki syntax, images `## What is Wine Staging? **Wine Staging** on website [wine-staging.com](http://wine-staging.com). ## Quick Links Here are some links to the most important topics. You can find the full list of pages at the sidebar. | [[images/icon-install.png]] | [[Installation]] | |--------------------------------|----------------------------------------------------------| | [[images/icon-usage.png]] | [[Usage]] | `, // libgdx wiki page: inline images with special syntax `[Excelsior JET](http://www.excelsiorjet.com/) allows you to create native executables for Windows, Linux and Mac OS X. 1. [Package your libGDX application](https://github.com/libgdx/libgdx/wiki/Gradle-on-the-Commandline#packaging-for-the-desktop) [[images/1.png]] 2. Perform a test run by hitting the Run! button. [[images/2.png]] ## More tests {#custom-id} (from https://www.markdownguide.org/extended-syntax/) ### Checkboxes - [ ] unchecked - [x] checked - [ ] still unchecked ### Definition list First Term : This is the definition of the first term. Second Term : This is one definition of the second term. : This is another definition of the second term. ### Footnotes Here is a simple footnote,[^1] and here is a longer one.[^bignote] [^1]: This is the first footnote. [^bignote]: Here is one with multiple paragraphs and code. Indent paragraphs to include them in the footnote. ` + "`{ my code }`" + ` Add as many paragraphs as you like. `, ` - [ ] If you want to rebase/retry this PR, click this checkbox. --- This PR has been generated by [Renovate Bot](https://github.com/renovatebot/renovate). `, } func TestTotal_RenderWiki(t *testing.T) { defer test.MockVariableValue(&markup.RenderBehaviorForTesting.ForceHardLineBreak, true)() defer test.MockVariableValue(&markup.RenderBehaviorForTesting.DisableInternalAttributes, true)() setting.AppURL = AppURL answers := testAnswers(util.URLJoin(FullURL, "wiki"), util.URLJoin(FullURL, "wiki", "raw")) for i := 0; i < len(sameCases); i++ { line, err := markdown.RenderString(markup.NewTestRenderContext( markup.Links{Base: FullURL}, newMockRepo(testRepoOwnerName, testRepoName), localWikiMetas, ), sameCases[i]) assert.NoError(t, err) assert.Equal(t, answers[i], string(line)) } testCases := []string{ // Guard wiki sidebar: special syntax `[[Guardfile-DSL / Configuring-Guard|Guardfile-DSL---Configuring-Guard]]`, // rendered `Guardfile-DSL / Configuring-Guard
`, // special syntax `[[Name|Link]]`, // rendered ` `, } for i := 0; i < len(testCases); i += 2 { line, err := markdown.RenderString(markup.NewTestRenderContext(markup.Links{Base: FullURL}, localWikiMetas), testCases[i]) assert.NoError(t, err) assert.EqualValues(t, testCases[i+1], string(line)) } } func TestTotal_RenderString(t *testing.T) { defer test.MockVariableValue(&markup.RenderBehaviorForTesting.ForceHardLineBreak, true)() defer test.MockVariableValue(&markup.RenderBehaviorForTesting.DisableInternalAttributes, true)() setting.AppURL = AppURL answers := testAnswers(util.URLJoin(FullURL, "src", "master"), util.URLJoin(FullURL, "media", "master")) for i := 0; i < len(sameCases); i++ { line, err := markdown.RenderString(markup.NewTestRenderContext( markup.Links{ Base: FullURL, BranchPath: "master", }, newMockRepo(testRepoOwnerName, testRepoName), localMetas, ), sameCases[i]) assert.NoError(t, err) assert.Equal(t, answers[i], string(line)) } testCases := []string{} for i := 0; i < len(testCases); i += 2 { line, err := markdown.RenderString(markup.NewTestRenderContext(markup.Links{Base: FullURL}), testCases[i]) assert.NoError(t, err) assert.Equal(t, template.HTML(testCases[i+1]), line) } } func TestRender_RenderParagraphs(t *testing.T) { test := func(t *testing.T, str string, cnt int) { res, err := markdown.RenderRawString(markup.NewTestRenderContext(), str) assert.NoError(t, err) assert.Equal(t, cnt, strings.Count(res, " ` defer test.MockVariableValue(&markup.RenderBehaviorForTesting.ForceHardLineBreak, true)() res, err := markdown.RenderRawString(markup.NewTestRenderContext(), testcase) assert.NoError(t, err) assert.Equal(t, expected, res) } func TestRenderEmojiInLinks_Issue12331(t *testing.T) { testcase := `[Link with emoji :moon: in text](https://gitea.io)` expected := ` ` res, err := markdown.RenderString(markup.NewTestRenderContext(), testcase) assert.NoError(t, err) assert.Equal(t, template.HTML(expected), res) } func TestColorPreview(t *testing.T) { const nl = "\n" positiveTests := []struct { testcase string expected string }{ { // do not render color names "The CSS class `red` is there", "The CSS class red
is there
#FF0000
rgb(16, 32, 64)
This is the color white #0a0
HSL stands for hue, saturation, and lightness. An example: hsl(0, 100%, 50%)
.
HSL stands for hue, saturation, and lightness. An example: HSL(0, 100%, 50%)
.
a
` + nl,
},
{
"$ a $",
`a
a
b
a
b
a
.
.$a$
` + nl, }, { `$a a$b b$`, `$a a$b b$
` + nl, }, { `a a$b b`, `a a$b b
` + nl, }, { `a$b $a a$b b$`, `a$b $a a$b b$
` + nl, }, { "a$x$", `a$x$
` + nl, }, { "$x$a", `$x$a
` + nl, }, { "$$a$$", `a
` + nl,
},
{
"$a$ ($b$) [$c$] {$d$}",
`a
(b
) [$c$] {$d$}
a
test
test a
foo |
---|
bar |
space @mention-user
/just/a/path.bin
https://example.com/file.bin
local link
remote link
local link
remote link
88fc37a3c0...12fc37a3c0 (hash)
com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb...12fc37a3c0a4dda553bdcfc80c178a58247f42fb pare
88fc37a3c0
com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb mit
đ
mail@domain.com
@mention-user test
#123
space
space @mention-user
/just/a/path.bin
https://example.com/file.bin
local link
remote link
local link
remote link
88fc37a3c0...12fc37a3c0 (hash)
com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb...12fc37a3c0a4dda553bdcfc80c178a58247f42fb pare
88fc37a3c0
com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb mit
đ
mail@domain.com
@mention-user test
#123
space
space @mention-user
/just/a/path.bin
https://example.com/file.bin
local link
remote link
local link
remote link
88fc37a3c0...12fc37a3c0 (hash)
com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb...12fc37a3c0a4dda553bdcfc80c178a58247f42fb pare
88fc37a3c0
com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb mit
đ
mail@domain.com
@mention-user test
#123
space
space @mention-user
/just/a/path.bin
https://example.com/file.bin
local link
remote link
local link
remote link
88fc37a3c0...12fc37a3c0 (hash)
com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb...12fc37a3c0a4dda553bdcfc80c178a58247f42fb pare
88fc37a3c0
com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb mit
đ
mail@domain.com
@mention-user test
#123
space
space @mention-user
/just/a/path.bin
https://example.com/file.bin
local link
remote link
local link
remote link
88fc37a3c0...12fc37a3c0 (hash)
com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb...12fc37a3c0a4dda553bdcfc80c178a58247f42fb pare
88fc37a3c0
com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb mit
đ
mail@domain.com
@mention-user test
#123
space
space @mention-user
/just/a/path.bin
https://example.com/file.bin
local link
remote link
local link
remote link
88fc37a3c0...12fc37a3c0 (hash)
com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb...12fc37a3c0a4dda553bdcfc80c178a58247f42fb pare
88fc37a3c0
com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb mit
đ
mail@domain.com
@mention-user test
#123
space
space @mention-user
/just/a/path.bin
https://example.com/file.bin
local link
remote link
local link
remote link
88fc37a3c0...12fc37a3c0 (hash)
com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb...12fc37a3c0a4dda553bdcfc80c178a58247f42fb pare
88fc37a3c0
com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb mit
đ
mail@domain.com
@mention-user test
#123
space
space @mention-user
/just/a/path.bin
https://example.com/file.bin
local link
remote link
local link
remote link
88fc37a3c0...12fc37a3c0 (hash)
com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb...12fc37a3c0a4dda553bdcfc80c178a58247f42fb pare
88fc37a3c0
com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb mit
đ
mail@domain.com
@mention-user test
#123
space
space @mention-user
/just/a/path.bin
https://example.com/file.bin
local link
remote link
local link
remote link
88fc37a3c0...12fc37a3c0 (hash)
com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb...12fc37a3c0a4dda553bdcfc80c178a58247f42fb pare
88fc37a3c0
com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb mit
đ
mail@domain.com
@mention-user test
#123
space
space @mention-user
/just/a/path.bin
https://example.com/file.bin
local link
remote link
local link
remote link
88fc37a3c0...12fc37a3c0 (hash)
com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb...12fc37a3c0a4dda553bdcfc80c178a58247f42fb pare
88fc37a3c0
com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb mit
đ
mail@domain.com
@mention-user test
#123
space
space @mention-user
/just/a/path.bin
https://example.com/file.bin
local link
remote link
local link
remote link
88fc37a3c0...12fc37a3c0 (hash)
com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb...12fc37a3c0a4dda553bdcfc80c178a58247f42fb pare
88fc37a3c0
com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb mit
đ
mail@domain.com
@mention-user test
#123
space
space @mention-user
/just/a/path.bin
https://example.com/file.bin
local link
remote link
local link
remote link
88fc37a3c0...12fc37a3c0 (hash)
com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb...12fc37a3c0a4dda553bdcfc80c178a58247f42fb pare
88fc37a3c0
com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb mit
đ
mail@domain.com
@mention-user test
#123
space
") test(`> [!note]`, renderAttention("note", "octicon-info")+"\n") test(`> [!tip]`, renderAttention("tip", "octicon-light-bulb")+"\n") test(`> [!important]`, renderAttention("important", "octicon-report")+"\n") test(`> [!warning]`, renderAttention("warning", "octicon-alert")+"\n") test(`> [!caution]`, renderAttention("caution", "octicon-stop")+"\n") // escaped by mdformat test(`> \[!NOTE\]`, renderAttention("note", "octicon-info")+"\n") // legacy GitHub style test(`> **warning**`, renderAttention("warning", "octicon-alert")+"\n") } func BenchmarkSpecializedMarkdown(b *testing.B) { // 240856 4719 ns/op for i := 0; i < b.N; i++ { markdown.SpecializedMarkdown(&markup.RenderContext{}) } } func BenchmarkMarkdownRender(b *testing.B) { // 23202 50840 ns/op for i := 0; i < b.N; i++ { _, _ = markdown.RenderString(markup.NewTestRenderContext(), "https://example.com\n- a\n- b\n") } }{Attention}
` tmpl = strings.ReplaceAll(tmpl, "{attention}", attention) tmpl = strings.ReplaceAll(tmpl, "{icon}", icon) tmpl = strings.ReplaceAll(tmpl, "{Attention}", cases.Title(language.English).String(attention)) return tmpl } test := func(input, expected string) { result, err := markdown.RenderString(markup.NewTestRenderContext(), input) assert.NoError(t, err) assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(string(result))) } test(` > [!NOTE] > text `, renderAttention("note", "octicon-info")+"\ntext
\n