Skip to content

Commit

Permalink
Test renderReadmeFile (#23185)
Browse files Browse the repository at this point in the history
Add test coverage to the important features of
[`routers.web.repo.renderReadmeFile`](https://github.com/go-gitea/gitea/blob/067b0c2664d127c552ccdfd264257caca4907a77/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
  • Loading branch information
kousu authored Mar 9, 2023
1 parent c5573db commit 52e2416
Show file tree
Hide file tree
Showing 48 changed files with 194 additions and 4 deletions.
2 changes: 1 addition & 1 deletion models/db/iterate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ func TestIterate(t *testing.T) {
return nil
})
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 {
reopUnit2 := repo_model.RepoUnit{ID: repoUnit.ID}
Expand Down
4 changes: 2 additions & 2 deletions models/db/list_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,11 @@ func TestFind(t *testing.T) {
var repoUnits []repo_model.RepoUnit
err := db.Find(db.DefaultContext, &opts, &repoUnits)
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))
assert.NoError(t, err)
assert.EqualValues(t, 83, cnt)
assert.EqualValues(t, 84, cnt)

repoUnits = make([]repo_model.RepoUnit, 0, 10)
newCnt, err := db.FindAndCount(db.DefaultContext, &opts, &repoUnits)
Expand Down
6 changes: 6 additions & 0 deletions models/fixtures/repo_unit.yml
Original file line number Diff line number Diff line change
Expand Up @@ -569,3 +569,9 @@
type: 3
config: "{\"IgnoreWhitespaceConflicts\":false,\"AllowMerge\":true,\"AllowRebase\":true,\"AllowRebaseMerge\":true,\"AllowSquash\":true}"
created_unix: 946684810

-
id: 84
repo_id: 56
type: 1
created_unix: 946684810
13 changes: 13 additions & 0 deletions models/fixtures/repository.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1634,3 +1634,16 @@
is_private: true
num_issues: 1
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
2 changes: 1 addition & 1 deletion models/fixtures/user.yml
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@
num_followers: 2
num_following: 1
num_stars: 2
num_repos: 11
num_repos: 12
num_teams: 0
num_members: 0
visibility: 0
Expand Down
1 change: 1 addition & 0 deletions tests/gitea-repositories-meta/user2/readme-test.git/HEAD
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ref: refs/heads/master
4 changes: 4 additions & 0 deletions tests/gitea-repositories-meta/user2/readme-test.git/config
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[core]
repositoryformatversion = 0
filemode = true
bare = true
Original file line number Diff line number Diff line change
@@ -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]
# *~
21 changes: 21 additions & 0 deletions tests/gitea-repositories-meta/user2/readme-test.git/info/refs
Original file line number Diff line number Diff line change
@@ -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.
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
x��;�0 @�s
_�*N��H��1q�u(�?�t��T�0��==���Q��+�*4��d��h�S�η.z���͙Z3�ct��0'�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.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
x��M� �aל� � 0&Ƹs�� ئ�'�.���x������4 ]���.)�D��Q�|@b6Xbd��}�2+b�%�T� �I>g� 2�7Q���. (c�����"o��n�M�<�[6�_^橼�Z��T�U�� ���n��qO�*3��{���N\
Expand Down
Binary file not shown.
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
x��;�0 @�s
_�*N뤕bcc���Њ�Tҁ�S!N�����d�>���!���քLu�Ul�#q����l�Q�,�ꔡ��lCBn$6��X�Dɹ�bbҖR0���y�[/O�n���
�i�����2�1��Ї@�e�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.
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
x��M
1 �a�=E.��m�� �Νwh����#�"��A<��g�~|eǾ�#�jU:����$%�9o��{�9F �գQdsOU��H��rA�(�=�x��E���$nkҳ]�
�����\ҫV�M 7��yx�mؔ��1�-�1 ��}ږ��3�/�%=�f>&L�
Expand Down
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
P pack-8933bd634b76f8154310cccb52537a0195e43166.pack

Binary file not shown.
Binary file not shown.
Binary file not shown.
22 changes: 22 additions & 0 deletions tests/gitea-repositories-meta/user2/readme-test.git/packed-refs
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
fe495ea336f079ef2bed68648d0ba9a37cdbd4aa
105 changes: 105 additions & 0 deletions tests/integration/repo_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,111 @@ func TestViewRepoDirectory(t *testing.T) {
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) {
defer tests.PrepareTestEnv(t)()

Expand Down

0 comments on commit 52e2416

Please sign in to comment.