mirror of
https://codeberg.org/forgejo/forgejo.git
synced 2024-12-01 05:36:19 +01:00
Test renderReadmeFile (#23185)
Add test coverage to the important features of
[`routers.web.repo.renderReadmeFile`](067b0c2664/routers/web/repo/view.go (L273)
);
namely that:
- it can handle looking in docs/, .gitea/, and .github/
- it can handle choosing between multiple competing READMEs
- it prefers the localized README to the markdown README to the
plaintext README
- it can handle broken symlinks when processing all the options
- it uses the name of the symlink, not the name of the target of the
symlink
This commit is contained in:
parent
c5573dbc0f
commit
52e24167e5
48 changed files with 194 additions and 4 deletions
|
@ -25,7 +25,7 @@ func TestIterate(t *testing.T) {
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.EqualValues(t, 83, repoCnt)
|
assert.EqualValues(t, 84, repoCnt)
|
||||||
|
|
||||||
err = db.Iterate(db.DefaultContext, nil, func(ctx context.Context, repoUnit *repo_model.RepoUnit) error {
|
err = db.Iterate(db.DefaultContext, nil, func(ctx context.Context, repoUnit *repo_model.RepoUnit) error {
|
||||||
reopUnit2 := repo_model.RepoUnit{ID: repoUnit.ID}
|
reopUnit2 := repo_model.RepoUnit{ID: repoUnit.ID}
|
||||||
|
|
|
@ -35,11 +35,11 @@ func TestFind(t *testing.T) {
|
||||||
var repoUnits []repo_model.RepoUnit
|
var repoUnits []repo_model.RepoUnit
|
||||||
err := db.Find(db.DefaultContext, &opts, &repoUnits)
|
err := db.Find(db.DefaultContext, &opts, &repoUnits)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.EqualValues(t, 83, len(repoUnits))
|
assert.EqualValues(t, 84, len(repoUnits))
|
||||||
|
|
||||||
cnt, err := db.Count(db.DefaultContext, &opts, new(repo_model.RepoUnit))
|
cnt, err := db.Count(db.DefaultContext, &opts, new(repo_model.RepoUnit))
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.EqualValues(t, 83, cnt)
|
assert.EqualValues(t, 84, cnt)
|
||||||
|
|
||||||
repoUnits = make([]repo_model.RepoUnit, 0, 10)
|
repoUnits = make([]repo_model.RepoUnit, 0, 10)
|
||||||
newCnt, err := db.FindAndCount(db.DefaultContext, &opts, &repoUnits)
|
newCnt, err := db.FindAndCount(db.DefaultContext, &opts, &repoUnits)
|
||||||
|
|
|
@ -569,3 +569,9 @@
|
||||||
type: 3
|
type: 3
|
||||||
config: "{\"IgnoreWhitespaceConflicts\":false,\"AllowMerge\":true,\"AllowRebase\":true,\"AllowRebaseMerge\":true,\"AllowSquash\":true}"
|
config: "{\"IgnoreWhitespaceConflicts\":false,\"AllowMerge\":true,\"AllowRebase\":true,\"AllowRebaseMerge\":true,\"AllowSquash\":true}"
|
||||||
created_unix: 946684810
|
created_unix: 946684810
|
||||||
|
|
||||||
|
-
|
||||||
|
id: 84
|
||||||
|
repo_id: 56
|
||||||
|
type: 1
|
||||||
|
created_unix: 946684810
|
||||||
|
|
|
@ -1634,3 +1634,16 @@
|
||||||
is_private: true
|
is_private: true
|
||||||
num_issues: 1
|
num_issues: 1
|
||||||
status: 0
|
status: 0
|
||||||
|
|
||||||
|
-
|
||||||
|
id: 56
|
||||||
|
owner_id: 2
|
||||||
|
owner_name: user2
|
||||||
|
lower_name: readme-test
|
||||||
|
name: readme-test
|
||||||
|
default_branch: master
|
||||||
|
is_empty: false
|
||||||
|
is_archived: false
|
||||||
|
is_private: true
|
||||||
|
status: 0
|
||||||
|
num_issues: 0
|
||||||
|
|
|
@ -66,7 +66,7 @@
|
||||||
num_followers: 2
|
num_followers: 2
|
||||||
num_following: 1
|
num_following: 1
|
||||||
num_stars: 2
|
num_stars: 2
|
||||||
num_repos: 11
|
num_repos: 12
|
||||||
num_teams: 0
|
num_teams: 0
|
||||||
num_members: 0
|
num_members: 0
|
||||||
visibility: 0
|
visibility: 0
|
||||||
|
|
1
tests/gitea-repositories-meta/user2/readme-test.git/HEAD
Normal file
1
tests/gitea-repositories-meta/user2/readme-test.git/HEAD
Normal file
|
@ -0,0 +1 @@
|
||||||
|
ref: refs/heads/master
|
|
@ -0,0 +1,4 @@
|
||||||
|
[core]
|
||||||
|
repositoryformatversion = 0
|
||||||
|
filemode = true
|
||||||
|
bare = true
|
|
@ -0,0 +1,6 @@
|
||||||
|
# git ls-files --others --exclude-from=.git/info/exclude
|
||||||
|
# Lines that start with '#' are comments.
|
||||||
|
# For a project mostly in C, the following would be a good set of
|
||||||
|
# exclude patterns (uncomment them if you want to use them):
|
||||||
|
# *.[oa]
|
||||||
|
# *~
|
|
@ -0,0 +1,21 @@
|
||||||
|
ea9ef877d1d88af76682d8798418081264f10cfc refs/heads/fallbacks
|
||||||
|
0d4c14db927c9ffba01fa7e126cc748b5c02c01e refs/heads/fallbacks2
|
||||||
|
c66d5b07c2063d3268707f22226c708b589574ef refs/heads/fallbacks3
|
||||||
|
89f8426e9eb5eff35c09b3565836c8f8e15d0ce9 refs/heads/fallbacks4
|
||||||
|
b0e902496eae435ad03c92a5d479f916ef2d4893 refs/heads/fallbacks5
|
||||||
|
84a5500b5cc040b11daf53fc42c542a99589dc76 refs/heads/fallbacks6
|
||||||
|
cf406a96e416d7de5c4c1bbfffdd672300c822bf refs/heads/fallbacks7
|
||||||
|
0d6ac644b969e9199915a492da9dba08c179fd23 refs/heads/fallbacks8
|
||||||
|
5038febc0c57215beb3748d7ae4091a25a4acc93 refs/heads/fallbacks9
|
||||||
|
9134e1f178ca4cccf1a197142646f2d7627e8cd5 refs/heads/i18n
|
||||||
|
744d2441e55bc0010d6b340d303f0106a627ad29 refs/heads/master
|
||||||
|
3c492566170b057e962c025515ab38bbd7444077 refs/heads/plain
|
||||||
|
3882d6373a0882a6739b3cd9b24d21c630621234 refs/heads/sp-ace
|
||||||
|
bf5ed898252eaa50dcc01108ed4417c3ea98a294 refs/heads/special-subdir-.gitea
|
||||||
|
c03543573ab088ce1cf7090a387d2be621426234 refs/heads/special-subdir-.github
|
||||||
|
e75957ad9b7e6ed16dda183529ec283db0bbc5fe refs/heads/special-subdir-docs
|
||||||
|
46f5d5ab33d701642e08c713fab42af89fdd4fea refs/heads/special-subdir-nested
|
||||||
|
9c0f872256b839c2b97ec22fd348d87b14045513 refs/heads/subdir
|
||||||
|
d7a854fff61e45b98234d7aa79ecbcb1619cd3dd refs/heads/symlink
|
||||||
|
30b9c0ed4b1039dbd99f3fb537b84ca507e0549d refs/heads/symlink-loop
|
||||||
|
41489b7be5c2244d2b7b524dcb31caf3bd1f9ccc refs/heads/txt
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,2 @@
|
||||||
|
x<01>Ž;Â0@™s
|
||||||
|
_€*NÒÄH±±1q×u(¢?•tàöTˆ0¾á==™†áQÀ·+‹*4¤Ìd¹¥h“SÌη.z¢à°¢Í™Z3ó¢ctˆ<74>0'<27>As“5hÉzL¶=D¡ÌB˜\cx-Ý´Àõ!O¸¬›ÚéÇqÃêþÃó<õï¡ô•ð 0¦T×装½5ò=-›õÃÜôU sß7,Oó#ÆMÜ
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1 @@
|
||||||
|
x<01>ÎM †aל‚Ø0&ƸsçÊئô'•.¼½Õx—ïâùòñ4]•õ®.)ÉDÖñQÅ|@b6Xbdƒì}Ö2+b¦%<25>Tè ƒI>g<> 2<>7QÇÀˆ. (c µ¶Ó"o÷òºn´M‹<<3C>[6<>_^橼†Z¦³Tç¬Uƹ øû´nêÿ
qOÏ*3•ˆ{ñ™²N\
|
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,3 @@
|
||||||
|
x<01>Ž;Â0@™s
|
||||||
|
_€*N뤕bccâŽëЊþTÒ<54>ÛS!NÀø†÷ôdÇ>ƒ«Ü!¯ªÖ„LuUlÙ#qô¡´”líQÅ,¼ê”¡Œ®lCBn$6¶’XùDɹàbbÒ–R0ÅÆð–»y…[/O¸n»Úé
|
||||||
|
§iÇâñÃË2ï1…ðЇ@„e<E2809E>p´d‘ïiÞÿ殯‰‡!²<Í™ÜN—
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,3 @@
|
||||||
|
x<01>ÎM
|
||||||
|
1†a×=E. ¤mšŽ âÎ<C3A2>wh›¨ƒó#µ"ÞÞA<<3C>Ëgñ~|eǾ<C387>#»jU:×ÙØ–$%ž9o‰Ø{µ9F ™Õ£QdsOU§‘H‘ÕrA´(œ=¡xôçEœØÅ$nkÒ³]ç
|
||||||
|
§¾Üàø\Ò«VØM7—÷yx<79>mØ”´Ë1ê-¬1 šò}Ú–êÿ
3Ì/%=úf>&L¨
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,2 @@
|
||||||
|
P pack-8933bd634b76f8154310cccb52537a0195e43166.pack
|
||||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,22 @@
|
||||||
|
# pack-refs with: peeled fully-peeled sorted
|
||||||
|
ea9ef877d1d88af76682d8798418081264f10cfc refs/heads/fallbacks
|
||||||
|
0d4c14db927c9ffba01fa7e126cc748b5c02c01e refs/heads/fallbacks2
|
||||||
|
c66d5b07c2063d3268707f22226c708b589574ef refs/heads/fallbacks3
|
||||||
|
89f8426e9eb5eff35c09b3565836c8f8e15d0ce9 refs/heads/fallbacks4
|
||||||
|
b0e902496eae435ad03c92a5d479f916ef2d4893 refs/heads/fallbacks5
|
||||||
|
84a5500b5cc040b11daf53fc42c542a99589dc76 refs/heads/fallbacks6
|
||||||
|
cf406a96e416d7de5c4c1bbfffdd672300c822bf refs/heads/fallbacks7
|
||||||
|
0d6ac644b969e9199915a492da9dba08c179fd23 refs/heads/fallbacks8
|
||||||
|
5038febc0c57215beb3748d7ae4091a25a4acc93 refs/heads/fallbacks9
|
||||||
|
9134e1f178ca4cccf1a197142646f2d7627e8cd5 refs/heads/i18n
|
||||||
|
744d2441e55bc0010d6b340d303f0106a627ad29 refs/heads/master
|
||||||
|
3c492566170b057e962c025515ab38bbd7444077 refs/heads/plain
|
||||||
|
3882d6373a0882a6739b3cd9b24d21c630621234 refs/heads/sp-ace
|
||||||
|
bf5ed898252eaa50dcc01108ed4417c3ea98a294 refs/heads/special-subdir-.gitea
|
||||||
|
c03543573ab088ce1cf7090a387d2be621426234 refs/heads/special-subdir-.github
|
||||||
|
e75957ad9b7e6ed16dda183529ec283db0bbc5fe refs/heads/special-subdir-docs
|
||||||
|
46f5d5ab33d701642e08c713fab42af89fdd4fea refs/heads/special-subdir-nested
|
||||||
|
9c0f872256b839c2b97ec22fd348d87b14045513 refs/heads/subdir
|
||||||
|
d7a854fff61e45b98234d7aa79ecbcb1619cd3dd refs/heads/symlink
|
||||||
|
30b9c0ed4b1039dbd99f3fb537b84ca507e0549d refs/heads/symlink-loop
|
||||||
|
41489b7be5c2244d2b7b524dcb31caf3bd1f9ccc refs/heads/txt
|
|
@ -0,0 +1 @@
|
||||||
|
fe495ea336f079ef2bed68648d0ba9a37cdbd4aa
|
|
@ -257,6 +257,111 @@ func TestViewRepoDirectory(t *testing.T) {
|
||||||
assert.Zero(t, repoSummary.Length())
|
assert.Zero(t, repoSummary.Length())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ensure that the all the different ways to find and render a README work
|
||||||
|
func TestViewRepoDirectoryReadme(t *testing.T) {
|
||||||
|
defer tests.PrepareTestEnv(t)()
|
||||||
|
|
||||||
|
// there are many combinations:
|
||||||
|
// - READMEs can be .md, .txt, or have no extension
|
||||||
|
// - READMEs can be tagged with a language and even a country code
|
||||||
|
// - READMEs can be stored in docs/, .gitea/, or .github/
|
||||||
|
// - READMEs can be symlinks to other files
|
||||||
|
// - READMEs can be broken symlinks which should not render
|
||||||
|
//
|
||||||
|
// this doesn't cover all possible cases, just the major branches of the code
|
||||||
|
|
||||||
|
session := loginUser(t, "user2")
|
||||||
|
|
||||||
|
check := func(name, url, expectedFilename, expectedReadmeType, expectedContent string) {
|
||||||
|
t.Run(name, func(t *testing.T) {
|
||||||
|
defer tests.PrintCurrentTest(t)()
|
||||||
|
|
||||||
|
req := NewRequest(t, "GET", url)
|
||||||
|
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||||
|
|
||||||
|
htmlDoc := NewHTMLParser(t, resp.Body)
|
||||||
|
readmeName := htmlDoc.doc.Find("h4.file-header")
|
||||||
|
readmeContent := htmlDoc.doc.Find(".file-view") // TODO: add a id="readme" to the output to make this test more precise
|
||||||
|
readmeType, _ := readmeContent.Attr("class")
|
||||||
|
|
||||||
|
assert.Equal(t, expectedFilename, strings.TrimSpace(readmeName.Text()))
|
||||||
|
assert.Contains(t, readmeType, expectedReadmeType)
|
||||||
|
assert.Contains(t, readmeContent.Text(), expectedContent)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// viewing the top level
|
||||||
|
check("Home", "/user2/readme-test/", "README.md", "markdown", "The cake is a lie.")
|
||||||
|
|
||||||
|
// viewing different file extensions
|
||||||
|
check("md", "/user2/readme-test/src/branch/master/", "README.md", "markdown", "The cake is a lie.")
|
||||||
|
check("txt", "/user2/readme-test/src/branch/txt/", "README.txt", "plain-text", "My spoon is too big.")
|
||||||
|
check("plain", "/user2/readme-test/src/branch/plain/", "README", "plain-text", "Birken my stocks gee howdy")
|
||||||
|
check("i18n", "/user2/readme-test/src/branch/i18n/", "README.zh.md", "markdown", "蛋糕是一个谎言")
|
||||||
|
|
||||||
|
// viewing different subdirectories
|
||||||
|
check("subdir", "/user2/readme-test/src/branch/subdir/libcake", "README.md", "markdown", "Four pints of sugar.")
|
||||||
|
check("docs-direct", "/user2/readme-test/src/branch/special-subdir-docs/docs/", "README.md", "markdown", "This is in docs/")
|
||||||
|
check("docs", "/user2/readme-test/src/branch/special-subdir-docs/", "docs/README.md", "markdown", "This is in docs/")
|
||||||
|
check(".gitea", "/user2/readme-test/src/branch/special-subdir-.gitea/", ".gitea/README.md", "markdown", "This is in .gitea/")
|
||||||
|
check(".github", "/user2/readme-test/src/branch/special-subdir-.github/", ".github/README.md", "markdown", "This is in .github/")
|
||||||
|
|
||||||
|
// symlinks
|
||||||
|
// symlinks are subtle:
|
||||||
|
// - they should be able to handle going a reasonable number of times up and down in the tree
|
||||||
|
// - they shouldn't get stuck on link cycles
|
||||||
|
// - they should determine the filetype based on the name of the link, not the target
|
||||||
|
check("symlink", "/user2/readme-test/src/branch/symlink/", "README.md", "markdown", "This is in some/other/path")
|
||||||
|
check("symlink-multiple", "/user2/readme-test/src/branch/symlink/some/", "README.txt", "plain-text", "This is in some/other/path")
|
||||||
|
check("symlink-up-and-down", "/user2/readme-test/src/branch/symlink/up/back/down/down", "README.md", "markdown", "It's a me, mario")
|
||||||
|
|
||||||
|
// testing fallback rules
|
||||||
|
// READMEs are searched in this order:
|
||||||
|
// - [README.zh-cn.md, README.zh_cn.md, README.zh.md, README_zh.md, README.md, README.txt, README,
|
||||||
|
// docs/README.zh-cn.md, docs/README.zh_cn.md, docs/README.zh.md, docs/README_zh.md, docs/README.md, docs/README.txt, docs/README,
|
||||||
|
// .gitea/README.zh-cn.md, .gitea/README.zh_cn.md, .gitea/README.zh.md, .gitea/README_zh.md, .gitea/README.md, .gitea/README.txt, .gitea/README,
|
||||||
|
|
||||||
|
// .github/README.zh-cn.md, .github/README.zh_cn.md, .github/README.zh.md, .github/README_zh.md, .github/README.md, .github/README.txt, .github/README]
|
||||||
|
// and a broken/looped symlink counts as not existing at all and should be skipped.
|
||||||
|
// again, this doesn't cover all cases, but it covers a few
|
||||||
|
check("fallback/top", "/user2/readme-test/src/branch/fallbacks/", "README.en.md", "markdown", "This is README.en.md")
|
||||||
|
check("fallback/2", "/user2/readme-test/src/branch/fallbacks2/", "README.md", "markdown", "This is README.md")
|
||||||
|
check("fallback/3", "/user2/readme-test/src/branch/fallbacks3/", "README", "plain-text", "This is README")
|
||||||
|
check("fallback/4", "/user2/readme-test/src/branch/fallbacks4/", "docs/README.en.md", "markdown", "This is docs/README.en.md")
|
||||||
|
check("fallback/5", "/user2/readme-test/src/branch/fallbacks5/", "docs/README.md", "markdown", "This is docs/README.md")
|
||||||
|
check("fallback/6", "/user2/readme-test/src/branch/fallbacks6/", "docs/README", "plain-text", "This is docs/README")
|
||||||
|
check("fallback/7", "/user2/readme-test/src/branch/fallbacks7/", ".gitea/README.en.md", "markdown", "This is .gitea/README.en.md")
|
||||||
|
check("fallback/8", "/user2/readme-test/src/branch/fallbacks8/", ".gitea/README.md", "markdown", "This is .gitea/README.md")
|
||||||
|
check("fallback/9", "/user2/readme-test/src/branch/fallbacks9/", ".gitea/README", "plain-text", "This is .gitea/README")
|
||||||
|
|
||||||
|
// this case tests that broken symlinks count as missing files, instead of rendering their contents
|
||||||
|
check("fallbacks-broken-symlinks", "/user2/readme-test/src/branch/fallbacks-broken-symlinks/", "docs/README", "plain-text", "This is docs/README")
|
||||||
|
|
||||||
|
// some cases that should NOT render a README
|
||||||
|
// - /readme
|
||||||
|
// - /.github/docs/README.md
|
||||||
|
// - a symlink loop
|
||||||
|
|
||||||
|
missing := func(name, url string) {
|
||||||
|
t.Run("missing/"+name, func(t *testing.T) {
|
||||||
|
defer tests.PrintCurrentTest(t)()
|
||||||
|
|
||||||
|
req := NewRequest(t, "GET", url)
|
||||||
|
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||||
|
|
||||||
|
htmlDoc := NewHTMLParser(t, resp.Body)
|
||||||
|
_, exists := htmlDoc.doc.Find(".file-view").Attr("class")
|
||||||
|
fmt.Printf("%s", resp.Body)
|
||||||
|
|
||||||
|
assert.False(t, exists, "README should not have rendered")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
missing("sp-ace", "/user2/readme-test/src/branch/sp-ace/")
|
||||||
|
missing("nested-special", "/user2/readme-test/src/branch/special-subdir-nested/subproject") // the special subdirs should only trigger on the repo root
|
||||||
|
// missing("special-subdir-nested", "/user2/readme-test/src/branch/special-subdir-nested/") // This is currently FAILING, due to a bug introduced in https://github.com/go-gitea/gitea/pull/22177
|
||||||
|
missing("symlink-loop", "/user2/readme-test/src/branch/symlink-loop/")
|
||||||
|
}
|
||||||
|
|
||||||
func TestMarkDownImage(t *testing.T) {
|
func TestMarkDownImage(t *testing.T) {
|
||||||
defer tests.PrepareTestEnv(t)()
|
defer tests.PrepareTestEnv(t)()
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue