test: consolidate Go tests (#39962)

Consolidate all Go tests. Coverage is identical to before. Go tests are
around 5% faster while being 7% smaller. No non-test code is touched.
This commit is contained in:
silverwind authored and GitHub committed 2026-10-24 13:48:19 +00:00
1 parent ce7364e215
commit 8abda62312
388 files changed
+18410 -29561

No files matched your search

-6
View File
@@ -77,12 +77,6 @@ func TestCanGithubEventMatch(t *testing.T) {
webhook_module.HookEventPullRequest,
true,
},
{
"pull_request_target cannot match",
GithubEventPullRequest,
webhook_module.HookEventPullRequestComment,
false,
},
// pull_request_review event
{
"pull_request_review matches",
+20 -79
View File
@@ -18,72 +18,21 @@ import (
)
func TestParse(t *testing.T) {
tests := []struct {
name string
options []ParseOption
wantErr bool
}{
{
name: "multiple_jobs",
options: nil,
wantErr: false,
},
{
name: "multiple_matrix",
options: nil,
wantErr: false,
},
{
name: "has_needs",
options: nil,
wantErr: false,
},
{
name: "has_with",
options: nil,
wantErr: false,
},
{
name: "has_secrets",
options: nil,
wantErr: false,
},
{
name: "empty_step",
options: nil,
wantErr: false,
},
{
name: "job_name_with_matrix",
options: nil,
wantErr: false,
},
{
name: "prefixed_newline",
options: nil,
wantErr: false,
},
{
name: "continue_on_error_expr",
options: nil,
wantErr: false,
},
}
invalidFileTests := []struct {
name string
}{
{name: "null_job_implicit"},
{name: "null_job_explicit"},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
content := ReadTestdata(t, tt.name+".in.yaml")
want := ReadTestdata(t, tt.name+".out.yaml")
got, err := Parse(content, append([]ParseOption{WithGitContext(&model.GithubContext{})}, tt.options...)...)
if tt.wantErr {
require.Error(t, err)
}
for _, name := range []string{
"multiple_jobs",
"multiple_matrix",
"has_needs",
"has_with",
"has_secrets",
"empty_step",
"job_name_with_matrix",
"prefixed_newline",
"continue_on_error_expr",
} {
t.Run(name, func(t *testing.T) {
content := ReadTestdata(t, name+".in.yaml")
want := ReadTestdata(t, name+".out.yaml")
got, err := Parse(content, WithGitContext(&model.GithubContext{}))
require.NoError(t, err)
builder := &strings.Builder{}
@@ -102,9 +51,9 @@ func TestParse(t *testing.T) {
})
}
for _, tt := range invalidFileTests {
t.Run(tt.name, func(t *testing.T) {
content := ReadTestdata(t, tt.name+".in.yaml")
for _, name := range []string{"null_job_implicit", "null_job_explicit"} {
t.Run(name, func(t *testing.T) {
content := ReadTestdata(t, name+".in.yaml")
require.NotPanics(t, func() {
_, err := Parse(content)
require.Error(t, err)
@@ -460,6 +409,8 @@ func TestExpandMatrixWithNeeds(t *testing.T) {
{"empty vector", "\n version: ${{ fromJson(needs.setup.outputs.empty) }}\n", `Matrix vector "version" does not contain any values`},
{"empty include", "\n include: ${{ fromJson(needs.setup.outputs.empty) }}\n", "Matrix must define at least one vector"},
{"whole matrix not a mapping", " ${{ fromJson(needs.setup.outputs.empty) }}\n", `Matrix "" is not a map of matrix keys to values`},
{"unresolved need", "\n v: ${{ fromJson(needs.missing.outputs.v) }}\n", "evaluate matrix"},
{"invalid strategy field", "\n os: [linux]\nmax-parallel: ${{ fromJSON('bad') }}\n", "evaluate strategy"},
} {
t.Run(tt.name+" errors", func(t *testing.T) {
_, err := expand(t, tt.matrix)
@@ -475,16 +426,6 @@ func TestExpandMatrixWithNeeds(t *testing.T) {
assert.Equal(t, 1, got[0].Strategy.JobTotal)
})
t.Run("unresolved need errors", func(t *testing.T) {
_, err := expand(t, "\n v: ${{ fromJson(needs.missing.outputs.v) }}\n")
require.ErrorContains(t, err, "evaluate matrix")
})
t.Run("invalid strategy field errors", func(t *testing.T) {
_, err := expand(t, "\n os: [linux]\nmax-parallel: ${{ fromJSON('bad') }}\n")
require.ErrorContains(t, err, "evaluate strategy")
})
// The combination count comes from a runtime output, so it must be rejected before one Job per
// combination is built rather than after.
t.Run("too many combinations errors", func(t *testing.T) {
+7 -19
View File
@@ -332,29 +332,17 @@ func TestSingleWorkflow_SetJob(t *testing.T) {
func TestGetContinueOnError(t *testing.T) {
tests := []struct {
name string
yaml string
want bool
name string
continueOnError string
want bool
}{
{
name: "absent",
yaml: "name: test\non: push\njobs:\n job1:\n runs-on: ubuntu-22.04\n steps:\n - run: echo hi\n",
want: false,
},
{
name: "static true",
yaml: "name: test\non: push\njobs:\n job1:\n runs-on: ubuntu-22.04\n continue-on-error: true\n steps:\n - run: echo hi\n",
want: true,
},
{
name: "static false",
yaml: "name: test\non: push\njobs:\n job1:\n runs-on: ubuntu-22.04\n continue-on-error: false\n steps:\n - run: echo hi\n",
want: false,
},
{name: "absent", want: false},
{name: "static true", continueOnError: " continue-on-error: true\n", want: true},
{name: "static false", continueOnError: " continue-on-error: false\n", want: false},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := Parse([]byte(tt.yaml))
got, err := Parse(fmt.Appendf(nil, "name: test\non: push\njobs:\n job1:\n runs-on: ubuntu-22.04\n%s steps:\n - run: echo hi\n", tt.continueOnError))
require.NoError(t, err)
require.Len(t, got, 1)
_, job := got[0].Job()
@@ -13,404 +13,214 @@ import (
func TestMatchPattern(t *testing.T) {
kases := []struct {
inputs []string
inputs [][]string
patterns []string
skipResult bool
filterResult bool
}{
{
patterns: []string{"*"},
inputs: []string{"path/with/slash"},
inputs: [][]string{{"path/with/slash"}},
skipResult: true,
filterResult: false,
},
{
patterns: []string{"path/a", "path/b", "path/c"},
inputs: []string{"meta", "path/b", "otherfile"},
inputs: [][]string{{"meta", "path/b", "otherfile"}},
skipResult: false,
filterResult: false,
},
{
patterns: []string{"path/a", "path/b", "path/c"},
inputs: []string{"path/b"},
inputs: [][]string{{"path/b"}, {"path/c", "path/b"}, {"path/c", "path/b", "path/a"}},
skipResult: false,
filterResult: true,
},
{
patterns: []string{"path/a", "path/b", "path/c"},
inputs: []string{"path/c", "path/b"},
skipResult: false,
filterResult: true,
},
{
patterns: []string{"path/a", "path/b", "path/c"},
inputs: []string{"path/c", "path/b", "path/a"},
skipResult: false,
filterResult: true,
},
{
patterns: []string{"path/a", "path/b", "path/c"},
inputs: []string{"path/c", "path/b", "path/d", "path/a"},
inputs: [][]string{{"path/c", "path/b", "path/d", "path/a"}},
skipResult: false,
filterResult: false,
},
{
patterns: []string{},
inputs: []string{},
inputs: [][]string{{}},
skipResult: false,
filterResult: false,
},
{
patterns: []string{"\\!file"},
inputs: []string{"!file"},
inputs: [][]string{{"!file"}},
skipResult: false,
filterResult: true,
},
{
patterns: []string{"escape\\\\backslash"},
inputs: []string{"escape\\backslash"},
inputs: [][]string{{"escape\\backslash"}},
skipResult: false,
filterResult: true,
},
{
patterns: []string{".yml"},
inputs: []string{"fyml"},
inputs: [][]string{{"fyml"}},
skipResult: true,
filterResult: false,
},
// https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#patterns-to-match-branches-and-tags
{
patterns: []string{"feature/*"},
inputs: []string{"feature/my-branch"},
skipResult: false,
filterResult: true,
},
{
patterns: []string{"feature/*"},
inputs: []string{"feature/your-branch"},
inputs: [][]string{{"feature/my-branch"}, {"feature/your-branch"}},
skipResult: false,
filterResult: true,
},
{
patterns: []string{"feature/**"},
inputs: []string{"feature/beta-a/my-branch"},
skipResult: false,
filterResult: true,
},
{
patterns: []string{"feature/**"},
inputs: []string{"feature/beta-a/my-branch"},
skipResult: false,
filterResult: true,
},
{
patterns: []string{"feature/**"},
inputs: []string{"feature/mona/the/octocat"},
inputs: [][]string{{"feature/beta-a/my-branch"}, {"feature/mona/the/octocat"}},
skipResult: false,
filterResult: true,
},
{
patterns: []string{"main", "releases/mona-the-octocat"},
inputs: []string{"main"},
skipResult: false,
filterResult: true,
},
{
patterns: []string{"main", "releases/mona-the-octocat"},
inputs: []string{"releases/mona-the-octocat"},
inputs: [][]string{{"main"}, {"releases/mona-the-octocat"}},
skipResult: false,
filterResult: true,
},
{
patterns: []string{"*"},
inputs: []string{"main"},
skipResult: false,
filterResult: true,
},
{
patterns: []string{"*"},
inputs: []string{"releases"},
inputs: [][]string{{"main"}, {"releases"}},
skipResult: false,
filterResult: true,
},
{
patterns: []string{"**"},
inputs: []string{"all/the/branches"},
skipResult: false,
filterResult: true,
},
{
patterns: []string{"**"},
inputs: []string{"every/tag"},
inputs: [][]string{{"all/the/branches"}, {"every/tag"}},
skipResult: false,
filterResult: true,
},
{
patterns: []string{"*feature"},
inputs: []string{"mona-feature"},
skipResult: false,
filterResult: true,
},
{
patterns: []string{"*feature"},
inputs: []string{"feature"},
skipResult: false,
filterResult: true,
},
{
patterns: []string{"*feature"},
inputs: []string{"ver-10-feature"},
inputs: [][]string{{"mona-feature"}, {"feature"}, {"ver-10-feature"}},
skipResult: false,
filterResult: true,
},
{
patterns: []string{"v2*"},
inputs: []string{"v2"},
skipResult: false,
filterResult: true,
},
{
patterns: []string{"v2*"},
inputs: []string{"v2.0"},
skipResult: false,
filterResult: true,
},
{
patterns: []string{"v2*"},
inputs: []string{"v2.9"},
inputs: [][]string{{"v2"}, {"v2.0"}, {"v2.9"}},
skipResult: false,
filterResult: true,
},
{
patterns: []string{"v[12].[0-9]+.[0-9]+"},
inputs: []string{"v1.10.1"},
skipResult: false,
filterResult: true,
},
{
patterns: []string{"v[12].[0-9]+.[0-9]+"},
inputs: []string{"v2.0.0"},
inputs: [][]string{{"v1.10.1"}, {"v2.0.0"}},
skipResult: false,
filterResult: true,
},
// https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#patterns-to-match-file-paths
{
patterns: []string{"*"},
inputs: []string{"README.md"},
skipResult: false,
filterResult: true,
},
{
patterns: []string{"*"},
inputs: []string{"server.rb"},
inputs: [][]string{{"README.md"}, {"server.rb"}},
skipResult: false,
filterResult: true,
},
{
patterns: []string{"*.jsx?"},
inputs: []string{"page.js"},
skipResult: false,
filterResult: true,
},
{
patterns: []string{"*.jsx?"},
inputs: []string{"page.jsx"},
inputs: [][]string{{"page.js"}, {"page.jsx"}},
skipResult: false,
filterResult: true,
},
{
patterns: []string{"**"},
inputs: []string{"all/the/files.md"},
inputs: [][]string{{"all/the/files.md"}},
skipResult: false,
filterResult: true,
},
{
patterns: []string{"*.js"},
inputs: []string{"app.js"},
skipResult: false,
filterResult: true,
},
{
patterns: []string{"*.js"},
inputs: []string{"index.js"},
inputs: [][]string{{"app.js"}, {"index.js"}},
skipResult: false,
filterResult: true,
},
{
patterns: []string{"**.js"},
inputs: []string{"index.js"},
skipResult: false,
filterResult: true,
},
{
patterns: []string{"**.js"},
inputs: []string{"js/index.js"},
skipResult: false,
filterResult: true,
},
{
patterns: []string{"**.js"},
inputs: []string{"src/js/app.js"},
inputs: [][]string{{"index.js"}, {"js/index.js"}, {"src/js/app.js"}},
skipResult: false,
filterResult: true,
},
{
patterns: []string{"docs/*"},
inputs: []string{"docs/README.md"},
skipResult: false,
filterResult: true,
},
{
patterns: []string{"docs/*"},
inputs: []string{"docs/file.txt"},
inputs: [][]string{{"docs/README.md"}, {"docs/file.txt"}},
skipResult: false,
filterResult: true,
},
{
patterns: []string{"docs/**"},
inputs: []string{"docs/README.md"},
skipResult: false,
filterResult: true,
},
{
patterns: []string{"docs/**"},
inputs: []string{"docs/mona/octocat.txt"},
inputs: [][]string{{"docs/README.md"}, {"docs/mona/octocat.txt"}},
skipResult: false,
filterResult: true,
},
{
patterns: []string{"docs/**/*.md"},
inputs: []string{"docs/README.md"},
skipResult: false,
filterResult: true,
},
{
patterns: []string{"docs/**/*.md"},
inputs: []string{"docs/mona/hello-world.md"},
skipResult: false,
filterResult: true,
},
{
patterns: []string{"docs/**/*.md"},
inputs: []string{"docs/a/markdown/file.md"},
inputs: [][]string{{"docs/README.md"}, {"docs/mona/hello-world.md"}, {"docs/a/markdown/file.md"}},
skipResult: false,
filterResult: true,
},
{
patterns: []string{"**/docs/**"},
inputs: []string{"docs/hello.md"},
skipResult: false,
filterResult: true,
},
{
patterns: []string{"**/docs/**"},
inputs: []string{"dir/docs/my-file.txt"},
skipResult: false,
filterResult: true,
},
{
patterns: []string{"**/docs/**"},
inputs: []string{"space/docs/plan/space.doc"},
inputs: [][]string{{"docs/hello.md"}, {"dir/docs/my-file.txt"}, {"space/docs/plan/space.doc"}},
skipResult: false,
filterResult: true,
},
{
patterns: []string{"**/README.md"},
inputs: []string{"README.md"},
skipResult: false,
filterResult: true,
},
{
patterns: []string{"**/README.md"},
inputs: []string{"js/README.md"},
inputs: [][]string{{"README.md"}, {"js/README.md"}},
skipResult: false,
filterResult: true,
},
{
patterns: []string{"**/*src/**"},
inputs: []string{"a/src/app.js"},
skipResult: false,
filterResult: true,
},
{
patterns: []string{"**/*src/**"},
inputs: []string{"my-src/code/js/app.js"},
inputs: [][]string{{"a/src/app.js"}, {"my-src/code/js/app.js"}},
skipResult: false,
filterResult: true,
},
{
patterns: []string{"**/*-post.md"},
inputs: []string{"my-post.md"},
skipResult: false,
filterResult: true,
},
{
patterns: []string{"**/*-post.md"},
inputs: []string{"path/their-post.md"},
inputs: [][]string{{"my-post.md"}, {"path/their-post.md"}},
skipResult: false,
filterResult: true,
},
{
patterns: []string{"**/migrate-*.sql"},
inputs: []string{"migrate-10909.sql"},
skipResult: false,
filterResult: true,
},
{
patterns: []string{"**/migrate-*.sql"},
inputs: []string{"db/migrate-v1.0.sql"},
skipResult: false,
filterResult: true,
},
{
patterns: []string{"**/migrate-*.sql"},
inputs: []string{"db/sept/migrate-v1.sql"},
inputs: [][]string{{"migrate-10909.sql"}, {"db/migrate-v1.0.sql"}, {"db/sept/migrate-v1.sql"}},
skipResult: false,
filterResult: true,
},
{
patterns: []string{"*.md", "!README.md"},
inputs: []string{"hello.md"},
inputs: [][]string{{"hello.md"}},
skipResult: false,
filterResult: true,
},
{
patterns: []string{"*.md", "!README.md"},
inputs: []string{"README.md"},
skipResult: true,
filterResult: true,
},
{
patterns: []string{"*.md", "!README.md"},
inputs: []string{"docs/hello.md"},
inputs: [][]string{{"README.md"}, {"docs/hello.md"}},
skipResult: true,
filterResult: true,
},
{
patterns: []string{"*.md", "!README.md", "README*"},
inputs: []string{"hello.md"},
skipResult: false,
filterResult: true,
},
{
patterns: []string{"*.md", "!README.md", "README*"},
inputs: []string{"README.md"},
skipResult: false,
filterResult: true,
},
{
patterns: []string{"*.md", "!README.md", "README*"},
inputs: []string{"README.doc"},
inputs: [][]string{{"hello.md"}, {"README.md"}, {"README.doc"}},
skipResult: false,
filterResult: true,
},
}
for _, kase := range kases {
msg := fmt.Sprintf("patterns=%s, input=%s", strings.Join(kase.patterns, ","), strings.Join(kase.inputs, ","))
patterns, err := CompilePatterns(kase.patterns...)
assert.NoError(t, err, "compile error: %s", msg)
assert.Equal(t, kase.skipResult, Skip(patterns, kase.inputs), "unexpected skip result: %s", msg)
assert.Equal(t, kase.filterResult, Filter(patterns, kase.inputs), "unexpected filter result: %s", msg)
for _, inputs := range kase.inputs {
msg := fmt.Sprintf("patterns=%s, input=%s", strings.Join(kase.patterns, ","), strings.Join(inputs, ","))
patterns, err := CompilePatterns(kase.patterns...)
assert.NoError(t, err, "compile error: %s", msg)
assert.Equal(t, kase.skipResult, Skip(patterns, inputs), "unexpected skip result: %s", msg)
assert.Equal(t, kase.filterResult, Filter(patterns, inputs), "unexpected filter result: %s", msg)
}
}
}
+24 -51
View File
@@ -281,6 +281,24 @@ func TestDetectMatched(t *testing.T) {
}
func TestMatchIssuesEvent(t *testing.T) {
labelChangesPayload := func() *api.IssuePayload {
return &api.IssuePayload{
Action: api.HookIssueLabelUpdated,
Issue: &api.Issue{
Labels: []*api.Label{
{ID: 789, Name: "new-label"},
},
},
Changes: &api.ChangesPayload{
AddedLabels: []*api.Label{
{ID: 789, Name: "new-label"},
},
RemovedLabels: []*api.Label{
{ID: 123, Name: "deleted-label"},
},
},
}
}
testCases := []struct {
desc string
payload *api.IssuePayload
@@ -358,67 +376,22 @@ func TestMatchIssuesEvent(t *testing.T) {
eventType: "unlabeled",
},
{
desc: "Both adding and removing labels should trigger labeled event",
payload: &api.IssuePayload{
Action: api.HookIssueLabelUpdated,
Issue: &api.Issue{
Labels: []*api.Label{
{ID: 789, Name: "new-label"},
},
},
Changes: &api.ChangesPayload{
AddedLabels: []*api.Label{
{ID: 789, Name: "new-label"},
},
RemovedLabels: []*api.Label{
{ID: 123, Name: "deleted-label"},
},
},
},
desc: "Both adding and removing labels should trigger labeled event",
payload: labelChangesPayload(),
yamlOn: "on:\n issues:\n types: [labeled]",
expected: true,
eventType: "labeled",
},
{
desc: "Both adding and removing labels should trigger unlabeled event",
payload: &api.IssuePayload{
Action: api.HookIssueLabelUpdated,
Issue: &api.Issue{
Labels: []*api.Label{
{ID: 789, Name: "new-label"},
},
},
Changes: &api.ChangesPayload{
AddedLabels: []*api.Label{
{ID: 789, Name: "new-label"},
},
RemovedLabels: []*api.Label{
{ID: 123, Name: "deleted-label"},
},
},
},
desc: "Both adding and removing labels should trigger unlabeled event",
payload: labelChangesPayload(),
yamlOn: "on:\n issues:\n types: [unlabeled]",
expected: true,
eventType: "unlabeled",
},
{
desc: "Both adding and removing labels should trigger both events",
payload: &api.IssuePayload{
Action: api.HookIssueLabelUpdated,
Issue: &api.Issue{
Labels: []*api.Label{
{ID: 789, Name: "new-label"},
},
},
Changes: &api.ChangesPayload{
AddedLabels: []*api.Label{
{ID: 789, Name: "new-label"},
},
RemovedLabels: []*api.Label{
{ID: 123, Name: "deleted-label"},
},
},
},
desc: "Both adding and removing labels should trigger both events",
payload: labelChangesPayload(),
yamlOn: "on:\n issues:\n types: [labeled, unlabeled]",
expected: true,
eventType: "multiple",
+12 -24
View File
@@ -74,34 +74,22 @@ func TestLayered(t *testing.T) {
assertRead("", fs.ErrNotExist, "no-such")
files, err := assets.ListFiles(".", true)
assert.NoError(t, err)
assert.Equal(t, []string{"f1", "f2", "fa"}, files)
files, err = assets.ListFiles(".", false)
assert.NoError(t, err)
assert.Equal(t, []string{"d1", "d2", "da"}, files)
files, err = assets.ListFiles(".")
assert.NoError(t, err)
assert.Equal(t, []string{"d1", "d2", "da", "f1", "f2", "fa"}, files)
files, err = assets.ListAllFiles(".", true)
assert.NoError(t, err)
assert.Equal(t, []string{"d1/f", "d2/f", "da/f", "f1", "f2", "fa"}, files)
files, err = assets.ListAllFiles(".", false)
assert.NoError(t, err)
assert.Equal(t, []string{"d1", "d2", "da", "da/sub1", "da/sub2"}, files)
files, err = assets.ListAllFiles(".")
assert.NoError(t, err)
assert.Equal(t, []string{
assertList := func(listFiles func(string, ...bool) ([]string, error), expected []string, fileMode ...bool) {
files, err := listFiles(".", fileMode...)
assert.NoError(t, err)
assert.Equal(t, expected, files)
}
assertList(assets.ListFiles, []string{"f1", "f2", "fa"}, true)
assertList(assets.ListFiles, []string{"d1", "d2", "da"}, false)
assertList(assets.ListFiles, []string{"d1", "d2", "da", "f1", "f2", "fa"})
assertList(assets.ListAllFiles, []string{"d1/f", "d2/f", "da/f", "f1", "f2", "fa"}, true)
assertList(assets.ListAllFiles, []string{"d1", "d2", "da", "da/sub1", "da/sub2"}, false)
assertList(assets.ListAllFiles, []string{
"d1", "d1/f",
"d2", "d2/f",
"da", "da/f", "da/sub1", "da/sub2",
"f1", "f2", "fa",
}, files)
})
assert.Empty(t, assets.GetFileLayerName("no-such"))
assert.Equal(t, "l1", assets.GetFileLayerName("f1"))
+1 -7
View File
@@ -48,7 +48,7 @@ func TestComplexity_Generate(t *testing.T) {
const maxCount = 50
const pwdLen = 50
test := func(t *testing.T, modes []string) {
for _, modes := range [][]string{{"lower"}, {"upper"}, {"lower", "upper", "spec"}, {"off"}, {""}} {
testComplextity(modes)
for range maxCount {
pwd, err := Generate(pwdLen)
@@ -58,12 +58,6 @@ func TestComplexity_Generate(t *testing.T) {
}
}
test(t, []string{"lower"})
test(t, []string{"upper"})
test(t, []string{"lower", "upper", "spec"})
test(t, []string{"off"})
test(t, []string{""})
// Remove settings for other tests
testComplextity([]string{"off"})
}
+15 -19
View File
@@ -47,25 +47,21 @@ func TestPassword(t *testing.T) {
assert.ErrorContains(t, err, "password cannot be empty")
assert.EqualValues(t, -1, count)
count, err = client.CheckPassword(ctx, "pwned", false)
assert.NoError(t, err)
assert.EqualValues(t, 1, count)
count, err = client.CheckPassword(ctx, "notpwned", false)
assert.NoError(t, err)
assert.EqualValues(t, 0, count)
count, err = client.CheckPassword(ctx, "paddedpwned", true)
assert.NoError(t, err)
assert.EqualValues(t, 1, count)
count, err = client.CheckPassword(ctx, "paddednotpwned", true)
assert.NoError(t, err)
assert.EqualValues(t, 0, count)
count, err = client.CheckPassword(ctx, "paddednotpwnedzero", true)
assert.NoError(t, err)
assert.EqualValues(t, 0, count)
for _, test := range []struct {
password string
padding bool
count int
}{
{"pwned", false, 1},
{"notpwned", false, 0},
{"paddedpwned", true, 1},
{"paddednotpwned", true, 0},
{"paddednotpwnedzero", true, 0},
} {
count, err = client.CheckPassword(ctx, test.password, test.padding)
assert.NoError(t, err)
assert.EqualValues(t, test.count, count)
}
count, err = client.CheckPassword(ctx, "ratelimited", false)
assert.Error(t, err)
+11 -18
View File
@@ -16,26 +16,19 @@ import (
"github.com/stretchr/testify/assert"
)
func Test_ProcessAvatarPNG(t *testing.T) {
setting.Avatar.MaxWidth = 4096
setting.Avatar.MaxHeight = 4096
func Test_ProcessAvatarFormats(t *testing.T) {
for _, format := range []string{"png", "jpeg"} {
t.Run(format, func(t *testing.T) {
setting.Avatar.MaxWidth = 4096
setting.Avatar.MaxHeight = 4096
data, err := os.ReadFile("testdata/avatar.png")
assert.NoError(t, err)
data, err := os.ReadFile("testdata/avatar." + format)
assert.NoError(t, err)
_, err = processAvatarImage(data, 262144)
assert.NoError(t, err)
}
func Test_ProcessAvatarJPEG(t *testing.T) {
setting.Avatar.MaxWidth = 4096
setting.Avatar.MaxHeight = 4096
data, err := os.ReadFile("testdata/avatar.jpeg")
assert.NoError(t, err)
_, err = processAvatarImage(data, 262144)
assert.NoError(t, err)
_, err = processAvatarImage(data, 262144)
assert.NoError(t, err)
})
}
}
func Test_ProcessAvatarInvalidData(t *testing.T) {
+50 -76
View File
@@ -87,90 +87,64 @@ func TestToUTF8(t *testing.T) {
}
func TestToUTF8WithFallback(t *testing.T) {
// "ABC"
res := ToUTF8WithFallback([]byte{0x41, 0x42, 0x43}, ConvertOpts{})
assert.Equal(t, []byte{0x41, 0x42, 0x43}, res)
for _, converter := range []struct {
name string
convert func([]byte) []byte
}{
{"fallback", func(content []byte) []byte { return ToUTF8WithFallback(content, ConvertOpts{}) }},
{"drop errors", ToUTF8DropErrors},
} {
t.Run(converter.name, func(t *testing.T) {
// "ABC"
res := converter.convert([]byte{0x41, 0x42, 0x43})
assert.Equal(t, []byte{0x41, 0x42, 0x43}, res)
// "áéíóú"
res = ToUTF8WithFallback([]byte{0xc3, 0xa1, 0xc3, 0xa9, 0xc3, 0xad, 0xc3, 0xb3, 0xc3, 0xba}, ConvertOpts{})
assert.Equal(t, []byte{0xc3, 0xa1, 0xc3, 0xa9, 0xc3, 0xad, 0xc3, 0xb3, 0xc3, 0xba}, res)
// "áéíóú"
res = converter.convert([]byte{0xc3, 0xa1, 0xc3, 0xa9, 0xc3, 0xad, 0xc3, 0xb3, 0xc3, 0xba})
assert.Equal(t, []byte{0xc3, 0xa1, 0xc3, 0xa9, 0xc3, 0xad, 0xc3, 0xb3, 0xc3, 0xba}, res)
// UTF8 BOM + "áéíóú"
res = ToUTF8WithFallback([]byte{0xef, 0xbb, 0xbf, 0xc3, 0xa1, 0xc3, 0xa9, 0xc3, 0xad, 0xc3, 0xb3, 0xc3, 0xba}, ConvertOpts{})
assert.Equal(t, []byte{0xc3, 0xa1, 0xc3, 0xa9, 0xc3, 0xad, 0xc3, 0xb3, 0xc3, 0xba}, res)
// UTF8 BOM + "áéíóú"
res = converter.convert([]byte{0xef, 0xbb, 0xbf, 0xc3, 0xa1, 0xc3, 0xa9, 0xc3, 0xad, 0xc3, 0xb3, 0xc3, 0xba})
assert.Equal(t, []byte{0xc3, 0xa1, 0xc3, 0xa9, 0xc3, 0xad, 0xc3, 0xb3, 0xc3, 0xba}, res)
// "Hola, así cómo ños"
res = ToUTF8WithFallback([]byte{
0x48, 0x6F, 0x6C, 0x61, 0x2C, 0x20, 0x61, 0x73, 0xED, 0x20, 0x63,
0xF3, 0x6D, 0x6F, 0x20, 0xF1, 0x6F, 0x73,
}, ConvertOpts{})
assert.Equal(t, []byte{
0x48, 0x6F, 0x6C, 0x61, 0x2C, 0x20, 0x61, 0x73, 0xC3, 0xAD, 0x20, 0x63,
0xC3, 0xB3, 0x6D, 0x6F, 0x20, 0xC3, 0xB1, 0x6F, 0x73,
}, res)
// "Hola, así cómo ños"
res = converter.convert([]byte{
0x48, 0x6F, 0x6C, 0x61, 0x2C, 0x20, 0x61, 0x73, 0xED, 0x20, 0x63,
0xF3, 0x6D, 0x6F, 0x20, 0xF1, 0x6F, 0x73,
})
if converter.name == "fallback" {
assert.Equal(t, []byte{
0x48, 0x6F, 0x6C, 0x61, 0x2C, 0x20, 0x61, 0x73, 0xC3, 0xAD, 0x20, 0x63,
0xC3, 0xB3, 0x6D, 0x6F, 0x20, 0xC3, 0xB1, 0x6F, 0x73,
}, res)
} else {
assert.Equal(t, []byte{0x48, 0x6F, 0x6C, 0x61, 0x2C, 0x20, 0x61, 0x73}, res[:8])
assert.Equal(t, []byte{0x73}, res[len(res)-1:])
}
// "Hola, así cómo "
minmatch := []byte{0x48, 0x6F, 0x6C, 0x61, 0x2C, 0x20, 0x61, 0x73, 0xC3, 0xAD, 0x20, 0x63, 0xC3, 0xB3, 0x6D, 0x6F, 0x20}
// "Hola, así cómo "
minmatch := []byte{0x48, 0x6F, 0x6C, 0x61, 0x2C, 0x20, 0x61, 0x73, 0xC3, 0xAD, 0x20, 0x63, 0xC3, 0xB3, 0x6D, 0x6F, 0x20}
res = ToUTF8WithFallback([]byte{0x48, 0x6F, 0x6C, 0x61, 0x2C, 0x20, 0x61, 0x73, 0xED, 0x20, 0x63, 0xF3, 0x6D, 0x6F, 0x20, 0x07, 0xA4, 0x6F, 0x73}, ConvertOpts{})
// Do not fail for differences in invalid cases, as the library might change the conversion criteria for those
assert.Equal(t, minmatch, res[0:len(minmatch)])
res = converter.convert([]byte{0x48, 0x6F, 0x6C, 0x61, 0x2C, 0x20, 0x61, 0x73, 0xED, 0x20, 0x63, 0xF3, 0x6D, 0x6F, 0x20, 0x07, 0xA4, 0x6F, 0x73})
// Do not fail for differences in invalid cases, as the library might change the conversion criteria for those
assert.Equal(t, minmatch, res[0:len(minmatch)])
res = ToUTF8WithFallback([]byte{0x48, 0x6F, 0x6C, 0x61, 0x2C, 0x20, 0x61, 0x73, 0xED, 0x20, 0x63, 0xF3, 0x6D, 0x6F, 0x20, 0x81, 0xA4, 0x6F, 0x73}, ConvertOpts{})
// Do not fail for differences in invalid cases, as the library might change the conversion criteria for those
assert.Equal(t, minmatch, res[0:len(minmatch)])
res = converter.convert([]byte{0x48, 0x6F, 0x6C, 0x61, 0x2C, 0x20, 0x61, 0x73, 0xED, 0x20, 0x63, 0xF3, 0x6D, 0x6F, 0x20, 0x81, 0xA4, 0x6F, 0x73})
// Do not fail for differences in invalid cases, as the library might change the conversion criteria for those
assert.Equal(t, minmatch, res[0:len(minmatch)])
// Japanese (Shift-JIS)
// "日属秘ぞしちゅ。"
res = ToUTF8WithFallback([]byte{0x93, 0xFA, 0x91, 0xAE, 0x94, 0xE9, 0x82, 0xBC, 0x82, 0xB5, 0x82, 0xBF, 0x82, 0xE3, 0x81, 0x42}, ConvertOpts{})
assert.Equal(t, []byte{
0xE6, 0x97, 0xA5, 0xE5, 0xB1, 0x9E, 0xE7, 0xA7, 0x98, 0xE3,
0x81, 0x9E, 0xE3, 0x81, 0x97, 0xE3, 0x81, 0xA1, 0xE3, 0x82, 0x85, 0xE3, 0x80, 0x82,
}, res)
// Japanese (Shift-JIS)
// "日属秘ぞしちゅ。"
res = converter.convert([]byte{0x93, 0xFA, 0x91, 0xAE, 0x94, 0xE9, 0x82, 0xBC, 0x82, 0xB5, 0x82, 0xBF, 0x82, 0xE3, 0x81, 0x42})
assert.Equal(t, []byte{
0xE6, 0x97, 0xA5, 0xE5, 0xB1, 0x9E, 0xE7, 0xA7, 0x98, 0xE3,
0x81, 0x9E, 0xE3, 0x81, 0x97, 0xE3, 0x81, 0xA1, 0xE3, 0x82, 0x85, 0xE3, 0x80, 0x82,
}, res)
res = ToUTF8WithFallback([]byte{0x00, 0x00, 0x00, 0x00}, ConvertOpts{})
assert.Equal(t, []byte{0x00, 0x00, 0x00, 0x00}, res)
}
func TestToUTF8DropErrors(t *testing.T) {
// "ABC"
res := ToUTF8DropErrors([]byte{0x41, 0x42, 0x43})
assert.Equal(t, []byte{0x41, 0x42, 0x43}, res)
// "áéíóú"
res = ToUTF8DropErrors([]byte{0xc3, 0xa1, 0xc3, 0xa9, 0xc3, 0xad, 0xc3, 0xb3, 0xc3, 0xba})
assert.Equal(t, []byte{0xc3, 0xa1, 0xc3, 0xa9, 0xc3, 0xad, 0xc3, 0xb3, 0xc3, 0xba}, res)
// UTF8 BOM + "áéíóú"
res = ToUTF8DropErrors([]byte{0xef, 0xbb, 0xbf, 0xc3, 0xa1, 0xc3, 0xa9, 0xc3, 0xad, 0xc3, 0xb3, 0xc3, 0xba})
assert.Equal(t, []byte{0xc3, 0xa1, 0xc3, 0xa9, 0xc3, 0xad, 0xc3, 0xb3, 0xc3, 0xba}, res)
// "Hola, así cómo ños"
res = ToUTF8DropErrors([]byte{0x48, 0x6F, 0x6C, 0x61, 0x2C, 0x20, 0x61, 0x73, 0xED, 0x20, 0x63, 0xF3, 0x6D, 0x6F, 0x20, 0xF1, 0x6F, 0x73})
assert.Equal(t, []byte{0x48, 0x6F, 0x6C, 0x61, 0x2C, 0x20, 0x61, 0x73}, res[:8])
assert.Equal(t, []byte{0x73}, res[len(res)-1:])
// "Hola, así cómo "
minmatch := []byte{0x48, 0x6F, 0x6C, 0x61, 0x2C, 0x20, 0x61, 0x73, 0xC3, 0xAD, 0x20, 0x63, 0xC3, 0xB3, 0x6D, 0x6F, 0x20}
res = ToUTF8DropErrors([]byte{0x48, 0x6F, 0x6C, 0x61, 0x2C, 0x20, 0x61, 0x73, 0xED, 0x20, 0x63, 0xF3, 0x6D, 0x6F, 0x20, 0x07, 0xA4, 0x6F, 0x73})
// Do not fail for differences in invalid cases, as the library might change the conversion criteria for those
assert.Equal(t, minmatch, res[0:len(minmatch)])
res = ToUTF8DropErrors([]byte{0x48, 0x6F, 0x6C, 0x61, 0x2C, 0x20, 0x61, 0x73, 0xED, 0x20, 0x63, 0xF3, 0x6D, 0x6F, 0x20, 0x81, 0xA4, 0x6F, 0x73})
// Do not fail for differences in invalid cases, as the library might change the conversion criteria for those
assert.Equal(t, minmatch, res[0:len(minmatch)])
// Japanese (Shift-JIS)
// "日属秘ぞしちゅ。"
res = ToUTF8DropErrors([]byte{0x93, 0xFA, 0x91, 0xAE, 0x94, 0xE9, 0x82, 0xBC, 0x82, 0xB5, 0x82, 0xBF, 0x82, 0xE3, 0x81, 0x42})
assert.Equal(t, []byte{
0xE6, 0x97, 0xA5, 0xE5, 0xB1, 0x9E, 0xE7, 0xA7, 0x98, 0xE3,
0x81, 0x9E, 0xE3, 0x81, 0x97, 0xE3, 0x81, 0xA1, 0xE3, 0x82, 0x85, 0xE3, 0x80, 0x82,
}, res)
res = ToUTF8DropErrors([]byte{0x00, 0x00, 0x00, 0x00})
assert.Equal(t, []byte{0x00, 0x00, 0x00, 0x00}, res)
res = converter.convert([]byte{0x00, 0x00, 0x00, 0x00})
assert.Equal(t, []byte{0x00, 0x00, 0x00, 0x00}, res)
})
}
assert.Equal(t, "caf ", string(ToUTF8DropErrors([]byte("caf\xe9"))))
}
@@ -173,11 +173,6 @@ func TestCombine(t *testing.T) {
states: CommitStatusStates{CommitStatusSuccess, CommitStatusError, CommitStatusFailure, CommitStatusWarning},
expected: CommitStatusFailure,
},
{
name: "mixed states",
states: CommitStatusStates{CommitStatusPending, CommitStatusSuccess, CommitStatusError, CommitStatusWarning},
expected: CommitStatusFailure,
},
{
name: "mixed states with all success",
states: CommitStatusStates{CommitStatusSuccess, CommitStatusSuccess, CommitStatusPending, CommitStatusWarning},
+8 -33
View File
@@ -307,6 +307,7 @@ func TestGuessDelimiter(t *testing.T) {
cases := []struct {
csv string
expectedDelimiter rune
checkQuotes bool
}{
// case 0 - single cell, comma delmited
{
@@ -373,12 +374,14 @@ quoted,
quoted,
text," d`,
expectedDelimiter: '\t',
checkQuotes: true,
},
// case 10 - semicolon delmited with quotes and semicolon in value
{
csv: `col1;col2
"this has a literal "" in the text";"and an ; in the text"`,
expectedDelimiter: ';',
checkQuotes: true,
},
// case 11 - pipe delimited with quotes
{
@@ -389,6 +392,7 @@ World"|123
|
f" | 4.56 | 789`,
expectedDelimiter: '|',
checkQuotes: true,
},
// case 12 - a tab delimited 6 column CSV, but the values are not quoted and have lots of commas.
// In the previous bestScore algorithm, this would have picked comma as the delimiter, but now it should guess tab
@@ -455,6 +459,10 @@ jkl`,
for n, c := range cases {
delimiter := guessDelimiter([]byte(decodeSlashes(t, c.csv)))
assert.Equal(t, c.expectedDelimiter, delimiter, "case %d: delimiter should be equal, expected '%c' got '%c'", n, c.expectedDelimiter, delimiter)
if c.checkQuotes {
delimiter = guessFromBeforeAfterQuotes([]byte(decodeSlashes(t, c.csv)))
assert.Equal(t, c.expectedDelimiter, delimiter, "case %d: delimiter should be equal, expected '%c' got '%c'", n, c.expectedDelimiter, delimiter)
}
}
}
@@ -463,39 +471,6 @@ func TestGuessFromBeforeAfterQuotes(t *testing.T) {
csv string
expectedDelimiter rune
}{
// case 0 - tab delimited with new lines in values, commas in values
{
csv: `1 "some,""more
""
quoted,
text," a
2 "some,
quoted,\t
text," b
3 "some,
quoted,
text" c
4 "some,
quoted,
text," d`,
expectedDelimiter: '\t',
},
// case 1 - semicolon delmited with quotes and semicolon in value
{
csv: `col1;col2
"this has a literal "" in the text";"and an ; in the text"`,
expectedDelimiter: ';',
},
// case 2 - pipe delimited with quotes
{
csv: `Col1 | Col2 | Col3
abc | "Hello
World"|123
"de
|
f" | 4.56 | 789`,
expectedDelimiter: '|',
},
// case 3 - a complicated quoted CSV that is semicolon delmiited
{
csv: `he; she
+28 -52
View File
@@ -16,60 +16,36 @@ import (
func TestRenderEntryIconHTML_WithDifferentThemes(t *testing.T) {
// Test that folder icons use the folder theme
t.Run("FolderUsesBasicTheme", func(t *testing.T) {
defer test.MockVariableValue(&setting.UI.FileIconTheme, "material")()
defer test.MockVariableValue(&setting.UI.FolderIconTheme, "basic")()
folderEntry := &fileicon.EntryInfo{
BaseName: "testfolder",
EntryMode: git.EntryModeTree,
}
html := fileicon.RenderEntryIconHTML(nil, folderEntry)
for _, testCase := range []struct {
name, folderTheme, expected string
entry fileicon.EntryInfo
}{
// Basic theme renders octicon classes
assert.Contains(t, string(html), "octicon-file-directory-fill")
})
t.Run("FileUsesMaterialTheme", func(t *testing.T) {
defer test.MockVariableValue(&setting.UI.FileIconTheme, "material")()
defer test.MockVariableValue(&setting.UI.FolderIconTheme, "basic")()
fileEntry := &fileicon.EntryInfo{
BaseName: "test.js",
EntryMode: git.EntryModeBlob,
}
html := fileicon.RenderEntryIconHTML(nil, fileEntry)
{
"FolderUsesBasicTheme", "basic", "octicon-file-directory-fill",
fileicon.EntryInfo{BaseName: "testfolder", EntryMode: git.EntryModeTree},
},
// Material theme for files renders material icons
assert.Contains(t, string(html), "svg-mfi-")
})
t.Run("SymlinkToFolderUsesBasicTheme", func(t *testing.T) {
defer test.MockVariableValue(&setting.UI.FileIconTheme, "material")()
defer test.MockVariableValue(&setting.UI.FolderIconTheme, "basic")()
symlinkEntry := &fileicon.EntryInfo{
BaseName: "link",
EntryMode: git.EntryModeSymlink,
SymlinkToMode: git.EntryModeTree,
}
html := fileicon.RenderEntryIconHTML(nil, symlinkEntry)
{
"FileUsesMaterialTheme", "basic", "svg-mfi-",
fileicon.EntryInfo{BaseName: "test.js", EntryMode: git.EntryModeBlob},
},
// Symlinks to folders should use folder theme
assert.Contains(t, string(html), "octicon-file-directory-symlink")
})
t.Run("BothMaterialTheme", func(t *testing.T) {
defer test.MockVariableValue(&setting.UI.FileIconTheme, "material")()
defer test.MockVariableValue(&setting.UI.FolderIconTheme, "material")()
folderEntry := &fileicon.EntryInfo{
BaseName: "testfolder",
EntryMode: git.EntryModeTree,
}
html := fileicon.RenderEntryIconHTML(nil, folderEntry)
{
"SymlinkToFolderUsesBasicTheme", "basic", "octicon-file-directory-symlink",
fileicon.EntryInfo{BaseName: "link", EntryMode: git.EntryModeSymlink, SymlinkToMode: git.EntryModeTree},
},
// Material theme for folders renders material folder icons
assert.Contains(t, string(html), "svg-mfi-")
})
{
"BothMaterialTheme", "material", "svg-mfi-",
fileicon.EntryInfo{BaseName: "testfolder", EntryMode: git.EntryModeTree},
},
} {
t.Run(testCase.name, func(t *testing.T) {
defer test.MockVariableValue(&setting.UI.FileIconTheme, "material")()
defer test.MockVariableValue(&setting.UI.FolderIconTheme, testCase.folderTheme)()
assert.Contains(t, string(fileicon.RenderEntryIconHTML(nil, &testCase.entry)), testCase.expected)
})
}
}
+30 -61
View File
@@ -23,50 +23,31 @@ func Test_nulSeparatedAttributeWriter_ReadAttribute(t *testing.T) {
testStr := ".gitignore\"\n\x00linguist-vendored\x00unspecified\x00"
n, err := wr.Write([]byte(testStr))
assert.Len(t, testStr, n)
assert.NoError(t, err)
select {
case attr := <-wr.ReadAttribute():
assert.Equal(t, ".gitignore\"\n", attr.Filename)
assert.Equal(t, LinguistVendored, attr.Attribute)
assert.Equal(t, "unspecified", attr.Value)
case <-time.After(100 * time.Millisecond):
assert.FailNow(t, "took too long to read an attribute from the list")
}
// Write a second attribute again
n, err = wr.Write([]byte(testStr))
assert.Len(t, testStr, n)
assert.NoError(t, err)
select {
case attr := <-wr.ReadAttribute():
assert.Equal(t, ".gitignore\"\n", attr.Filename)
assert.Equal(t, LinguistVendored, attr.Attribute)
assert.Equal(t, "unspecified", attr.Value)
case <-time.After(100 * time.Millisecond):
assert.FailNow(t, "took too long to read an attribute from the list")
for range 2 {
n, err := wr.Write([]byte(testStr))
assert.Len(t, testStr, n)
assert.NoError(t, err)
select {
case attr := <-wr.ReadAttribute():
assert.Equal(t, ".gitignore\"\n", attr.Filename)
assert.Equal(t, LinguistVendored, attr.Attribute)
assert.Equal(t, "unspecified", attr.Value)
case <-time.After(100 * time.Millisecond):
assert.FailNow(t, "took too long to read an attribute from the list")
}
}
// Write a partial attribute
_, err = wr.Write([]byte("incomplete-file"))
_, err := wr.Write([]byte("incomplete-file"))
assert.NoError(t, err)
_, err = wr.Write([]byte("name\x00"))
assert.NoError(t, err)
select {
case <-wr.ReadAttribute():
assert.FailNow(t, "There should not be an attribute ready to read")
case <-time.After(100 * time.Millisecond):
}
_, err = wr.Write([]byte("attribute\x00"))
assert.NoError(t, err)
select {
case <-wr.ReadAttribute():
assert.FailNow(t, "There should not be an attribute ready to read")
case <-time.After(100 * time.Millisecond):
for _, part := range []string{"name\x00", "attribute\x00"} {
_, err = wr.Write([]byte(part))
assert.NoError(t, err)
select {
case <-wr.ReadAttribute():
assert.FailNow(t, "There should not be an attribute ready to read")
case <-time.After(100 * time.Millisecond):
}
}
_, err = wr.Write([]byte("value\x00"))
@@ -79,27 +60,15 @@ func Test_nulSeparatedAttributeWriter_ReadAttribute(t *testing.T) {
_, err = wr.Write([]byte("shouldbe.vendor\x00linguist-vendored\x00set\x00shouldbe.vendor\x00linguist-generated\x00unspecified\x00shouldbe.vendor\x00linguist-language\x00unspecified\x00"))
assert.NoError(t, err)
attr = <-wr.ReadAttribute()
assert.NoError(t, err)
assert.Equal(t, attributeTriple{
Filename: "shouldbe.vendor",
Attribute: LinguistVendored,
Value: "set",
}, attr)
attr = <-wr.ReadAttribute()
assert.NoError(t, err)
assert.Equal(t, attributeTriple{
Filename: "shouldbe.vendor",
Attribute: LinguistGenerated,
Value: "unspecified",
}, attr)
attr = <-wr.ReadAttribute()
assert.NoError(t, err)
assert.Equal(t, attributeTriple{
Filename: "shouldbe.vendor",
Attribute: LinguistLanguage,
Value: "unspecified",
}, attr)
for _, expected := range []attributeTriple{
{"shouldbe.vendor", LinguistVendored, "set"},
{"shouldbe.vendor", LinguistGenerated, "unspecified"},
{"shouldbe.vendor", LinguistLanguage, "unspecified"},
} {
attr = <-wr.ReadAttribute()
assert.NoError(t, err)
assert.Equal(t, expected, attr)
}
}
func expectedAttrs() *Attributes {
-148
View File
@@ -1,148 +0,0 @@
// Copyright 2024 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package git
import (
"testing"
"gitea.dev/modules/setting"
"github.com/stretchr/testify/assert"
)
func TestReadingBlameOutputSha256(t *testing.T) {
setting.AppDataPath = t.TempDir()
ctx := t.Context()
t.Run("Without .git-blame-ignore-revs", func(t *testing.T) {
storage := mockRepository("repo5_pulls_sha256")
repo, err := OpenRepository(ctx, storage)
assert.NoError(t, err)
defer repo.Close()
commit, err := repo.GetCommit(t.Context(), "0b69b7bb649b5d46e14cabb6468685e5dd721290acc7ffe604d37cde57927345")
assert.NoError(t, err)
parts := []*BlamePart{
{
Sha: "1e35a51dc00fd7de730344c07061acfe80e8117e075ac979b6a29a3a045190ca",
Lines: []string{
"# test_repo",
"Test repository for testing migration from github to gitea",
},
},
{
Sha: "0b69b7bb649b5d46e14cabb6468685e5dd721290acc7ffe604d37cde57927345",
Lines: []string{"", "Do not make any changes to this repo it is used for unit testing"},
PreviousSha: "1e35a51dc00fd7de730344c07061acfe80e8117e075ac979b6a29a3a045190ca",
PreviousPath: "README.md",
},
}
for _, bypass := range []bool{false, true} {
blameReader, err := CreateBlameReader(ctx, Sha256ObjectFormat, storage, repo, commit, "README.md", bypass)
assert.NoError(t, err)
assert.NotNil(t, blameReader)
defer blameReader.Close()
assert.False(t, blameReader.UsesIgnoreRevs())
for _, part := range parts {
actualPart, err := blameReader.NextPart()
assert.NoError(t, err)
assert.Equal(t, part, actualPart)
}
// make sure all parts have been read
actualPart, err := blameReader.NextPart()
assert.Nil(t, actualPart)
assert.NoError(t, err)
}
})
t.Run("With .git-blame-ignore-revs", func(t *testing.T) {
storage := mockRepository("repo6_blame_sha256")
repo, err := OpenRepository(ctx, storage)
assert.NoError(t, err)
defer repo.Close()
full := []*BlamePart{
{
Sha: "ab2b57a4fa476fb2edb74dafa577caf918561abbaa8fba0c8dc63c412e17a7cc",
Lines: []string{"line", "line"},
},
{
Sha: "9347b0198cd1f25017579b79d0938fa89dba34ad2514f0dd92f6bc975ed1a2fe",
Lines: []string{"changed line"},
PreviousSha: "ab2b57a4fa476fb2edb74dafa577caf918561abbaa8fba0c8dc63c412e17a7cc",
PreviousPath: "blame.txt",
},
{
Sha: "ab2b57a4fa476fb2edb74dafa577caf918561abbaa8fba0c8dc63c412e17a7cc",
Lines: []string{"line", "line", ""},
},
}
cases := []struct {
CommitID string
UsesIgnoreRevs bool
Bypass bool
Parts []*BlamePart
}{
{
CommitID: "e2f5660e15159082902960af0ed74fc144921d2b0c80e069361853b3ece29ba3",
UsesIgnoreRevs: true,
Bypass: false,
Parts: []*BlamePart{
{
Sha: "ab2b57a4fa476fb2edb74dafa577caf918561abbaa8fba0c8dc63c412e17a7cc",
Lines: []string{"line", "line", "changed line", "line", "line", ""},
},
},
},
{
CommitID: "e2f5660e15159082902960af0ed74fc144921d2b0c80e069361853b3ece29ba3",
UsesIgnoreRevs: false,
Bypass: true,
Parts: full,
},
{
CommitID: "9347b0198cd1f25017579b79d0938fa89dba34ad2514f0dd92f6bc975ed1a2fe",
UsesIgnoreRevs: false,
Bypass: false,
Parts: full,
},
{
CommitID: "9347b0198cd1f25017579b79d0938fa89dba34ad2514f0dd92f6bc975ed1a2fe",
UsesIgnoreRevs: false,
Bypass: false,
Parts: full,
},
}
objectFormat, err := repo.GetObjectFormat(t.Context())
assert.NoError(t, err)
for _, c := range cases {
commit, err := repo.GetCommit(t.Context(), c.CommitID)
assert.NoError(t, err)
blameReader, err := CreateBlameReader(ctx, objectFormat, storage, repo, commit, "blame.txt", c.Bypass)
assert.NoError(t, err)
assert.NotNil(t, blameReader)
defer blameReader.Close()
assert.Equal(t, c.UsesIgnoreRevs, blameReader.UsesIgnoreRevs())
for _, part := range c.Parts {
actualPart, err := blameReader.NextPart()
assert.NoError(t, err)
assert.Equal(t, part, actualPart)
}
// make sure all parts have been read
actualPart, err := blameReader.NextPart()
assert.Nil(t, actualPart)
assert.NoError(t, err)
}
})
}
+155 -122
View File
@@ -24,137 +24,170 @@ func TestLineBlameCommitID(t *testing.T) {
}
func TestReadingBlameOutput(t *testing.T) {
setting.AppDataPath = t.TempDir()
ctx := t.Context()
for _, scenario := range []struct {
name string
repositorySuffix string
objectFormat ObjectFormat
readmeCommit string
readmePrevious string
blameCommit string
blameChanged string
blameOriginal string
}{
{
name: "sha1",
objectFormat: Sha1ObjectFormat,
readmeCommit: "f32b0a9dfd09a60f616f29158f772cedd89942d2",
readmePrevious: "72866af952e98d02a73003501836074b286a78f6",
blameCommit: "544d8f7a3b15927cddf2299b4b562d6ebd71b6a7",
blameChanged: "45fb6cbc12f970b04eacd5cd4165edd11c8d7376",
blameOriginal: "af7486bd54cfc39eea97207ca666aa69c9d6df93",
},
{
name: "sha256",
repositorySuffix: "_sha256",
objectFormat: Sha256ObjectFormat,
readmeCommit: "0b69b7bb649b5d46e14cabb6468685e5dd721290acc7ffe604d37cde57927345",
readmePrevious: "1e35a51dc00fd7de730344c07061acfe80e8117e075ac979b6a29a3a045190ca",
blameCommit: "e2f5660e15159082902960af0ed74fc144921d2b0c80e069361853b3ece29ba3",
blameChanged: "9347b0198cd1f25017579b79d0938fa89dba34ad2514f0dd92f6bc975ed1a2fe",
blameOriginal: "ab2b57a4fa476fb2edb74dafa577caf918561abbaa8fba0c8dc63c412e17a7cc",
},
} {
t.Run(scenario.name, func(t *testing.T) {
setting.AppDataPath = t.TempDir()
ctx := t.Context()
t.Run("Without .git-blame-ignore-revs", func(t *testing.T) {
storage := mockRepository("repo5_pulls")
repo, err := OpenRepository(ctx, storage)
assert.NoError(t, err)
defer repo.Close()
commit, err := repo.GetCommit(t.Context(), "f32b0a9dfd09a60f616f29158f772cedd89942d2")
assert.NoError(t, err)
parts := []*BlamePart{
{
Sha: "72866af952e98d02a73003501836074b286a78f6",
Lines: []string{
"# test_repo",
"Test repository for testing migration from github to gitea",
},
},
{
Sha: "f32b0a9dfd09a60f616f29158f772cedd89942d2",
Lines: []string{"", "Do not make any changes to this repo it is used for unit testing"},
PreviousSha: "72866af952e98d02a73003501836074b286a78f6",
PreviousPath: "README.md",
},
}
for _, bypass := range []bool{false, true} {
blameReader, err := CreateBlameReader(ctx, Sha1ObjectFormat, storage, repo, commit, "README.md", bypass)
assert.NoError(t, err)
assert.NotNil(t, blameReader)
defer blameReader.Close()
assert.False(t, blameReader.UsesIgnoreRevs())
for _, part := range parts {
actualPart, err := blameReader.NextPart()
t.Run("Without .git-blame-ignore-revs", func(t *testing.T) {
storage := mockRepository("repo5_pulls" + scenario.repositorySuffix)
repo, err := OpenRepository(ctx, storage)
assert.NoError(t, err)
defer repo.Close()
commit, err := repo.GetCommit(t.Context(), scenario.readmeCommit)
assert.NoError(t, err)
assert.Equal(t, part, actualPart)
}
// make sure all parts have been read
actualPart, err := blameReader.NextPart()
assert.Nil(t, actualPart)
assert.NoError(t, err)
}
})
t.Run("With .git-blame-ignore-revs", func(t *testing.T) {
storage := mockRepository("repo6_blame")
repo, err := OpenRepository(ctx, storage)
assert.NoError(t, err)
defer repo.Close()
full := []*BlamePart{
{
Sha: "af7486bd54cfc39eea97207ca666aa69c9d6df93",
Lines: []string{"line", "line"},
},
{
Sha: "45fb6cbc12f970b04eacd5cd4165edd11c8d7376",
Lines: []string{"changed line"},
PreviousSha: "af7486bd54cfc39eea97207ca666aa69c9d6df93",
PreviousPath: "blame.txt",
},
{
Sha: "af7486bd54cfc39eea97207ca666aa69c9d6df93",
Lines: []string{"line", "line", ""},
},
}
cases := []struct {
CommitID string
UsesIgnoreRevs bool
Bypass bool
Parts []*BlamePart
}{
{
CommitID: "544d8f7a3b15927cddf2299b4b562d6ebd71b6a7",
UsesIgnoreRevs: true,
Bypass: false,
Parts: []*BlamePart{
parts := []*BlamePart{
{
Sha: "af7486bd54cfc39eea97207ca666aa69c9d6df93",
Lines: []string{"line", "line", "changed line", "line", "line", ""},
Sha: scenario.readmePrevious,
Lines: []string{
"# test_repo",
"Test repository for testing migration from github to gitea",
},
},
},
},
{
CommitID: "544d8f7a3b15927cddf2299b4b562d6ebd71b6a7",
UsesIgnoreRevs: false,
Bypass: true,
Parts: full,
},
{
CommitID: "45fb6cbc12f970b04eacd5cd4165edd11c8d7376",
UsesIgnoreRevs: false,
Bypass: false,
Parts: full,
},
{
CommitID: "45fb6cbc12f970b04eacd5cd4165edd11c8d7376",
UsesIgnoreRevs: false,
Bypass: false,
Parts: full,
},
}
{
Sha: scenario.readmeCommit,
Lines: []string{"", "Do not make any changes to this repo it is used for unit testing"},
PreviousSha: scenario.readmePrevious,
PreviousPath: "README.md",
},
}
objectFormat, err := repo.GetObjectFormat(t.Context())
assert.NoError(t, err)
for _, c := range cases {
commit, err := repo.GetCommit(t.Context(), c.CommitID)
assert.NoError(t, err)
for _, bypass := range []bool{false, true} {
blameReader, err := CreateBlameReader(ctx, scenario.objectFormat, storage, repo, commit, "README.md", bypass)
assert.NoError(t, err)
assert.NotNil(t, blameReader)
defer blameReader.Close()
blameReader, err := CreateBlameReader(ctx, objectFormat, storage, repo, commit, "blame.txt", c.Bypass)
assert.NoError(t, err)
assert.NotNil(t, blameReader)
defer blameReader.Close()
assert.False(t, blameReader.UsesIgnoreRevs())
assert.Equal(t, c.UsesIgnoreRevs, blameReader.UsesIgnoreRevs())
for _, part := range parts {
actualPart, err := blameReader.NextPart()
assert.NoError(t, err)
assert.Equal(t, part, actualPart)
}
for _, part := range c.Parts {
actualPart, err := blameReader.NextPart()
// make sure all parts have been read
actualPart, err := blameReader.NextPart()
assert.Nil(t, actualPart)
assert.NoError(t, err)
}
})
t.Run("With .git-blame-ignore-revs", func(t *testing.T) {
storage := mockRepository("repo6_blame" + scenario.repositorySuffix)
repo, err := OpenRepository(ctx, storage)
assert.NoError(t, err)
assert.Equal(t, part, actualPart)
}
defer repo.Close()
// make sure all parts have been read
actualPart, err := blameReader.NextPart()
assert.Nil(t, actualPart)
assert.NoError(t, err)
}
})
full := []*BlamePart{
{
Sha: scenario.blameOriginal,
Lines: []string{"line", "line"},
},
{
Sha: scenario.blameChanged,
Lines: []string{"changed line"},
PreviousSha: scenario.blameOriginal,
PreviousPath: "blame.txt",
},
{
Sha: scenario.blameOriginal,
Lines: []string{"line", "line", ""},
},
}
cases := []struct {
CommitID string
UsesIgnoreRevs bool
Bypass bool
Parts []*BlamePart
}{
{
CommitID: scenario.blameCommit,
UsesIgnoreRevs: true,
Bypass: false,
Parts: []*BlamePart{
{
Sha: scenario.blameOriginal,
Lines: []string{"line", "line", "changed line", "line", "line", ""},
},
},
},
{
CommitID: scenario.blameCommit,
UsesIgnoreRevs: false,
Bypass: true,
Parts: full,
},
{
CommitID: scenario.blameChanged,
UsesIgnoreRevs: false,
Bypass: false,
Parts: full,
},
{
CommitID: scenario.blameChanged,
UsesIgnoreRevs: false,
Bypass: false,
Parts: full,
},
}
objectFormat, err := repo.GetObjectFormat(t.Context())
assert.NoError(t, err)
for _, c := range cases {
commit, err := repo.GetCommit(t.Context(), c.CommitID)
assert.NoError(t, err)
blameReader, err := CreateBlameReader(ctx, objectFormat, storage, repo, commit, "blame.txt", c.Bypass)
assert.NoError(t, err)
assert.NotNil(t, blameReader)
defer blameReader.Close()
assert.Equal(t, c.UsesIgnoreRevs, blameReader.UsesIgnoreRevs())
for _, part := range c.Parts {
actualPart, err := blameReader.NextPart()
assert.NoError(t, err)
assert.Equal(t, part, actualPart)
}
// make sure all parts have been read
actualPart, err := blameReader.NextPart()
assert.Nil(t, actualPart)
assert.NoError(t, err)
}
})
})
}
}
+10 -41
View File
@@ -11,60 +11,29 @@ import (
func TestCommitsCount(t *testing.T) {
bareRepo1 := mockRepository("repo1_bare")
commitsCount, err := CommitsCount(t.Context(), bareRepo1,
CommitsCountOptions{
Revision: []string{"8006ff9adbf0cb94da7dad9e537e53817f9fa5c0"},
})
assert.NoError(t, err)
assert.Equal(t, int64(3), commitsCount)
}
func TestCommitsCountWithSinceUntil(t *testing.T) {
bareRepo1 := mockRepository("repo1_bare")
revision := []string{"8006ff9adbf0cb94da7dad9e537e53817f9fa5c0"}
// The three commits on this revision are dated 2018-04-18, 2017-12-19 and 2017-12-19.
cases := []struct {
for _, tc := range []struct {
name string
since string
until string
options CommitsCountOptions
expected int64
}{
{name: "no filter", expected: 3},
{name: "since keeps newer commits", since: "2018-01-01", expected: 1},
{name: "until keeps older commits", until: "2018-01-01", expected: 2},
{name: "since and until bound the range", since: "2017-12-19T22:16:00-08:00", until: "2018-01-01", expected: 1},
}
for _, tc := range cases {
{"revision", CommitsCountOptions{Revision: revision}, 3},
{"no filter", CommitsCountOptions{Revision: revision}, 3},
{"since keeps newer commits", CommitsCountOptions{Revision: revision, Since: "2018-01-01"}, 1},
{"until keeps older commits", CommitsCountOptions{Revision: revision, Until: "2018-01-01"}, 2},
{"since and until bound the range", CommitsCountOptions{Revision: revision, Since: "2017-12-19T22:16:00-08:00", Until: "2018-01-01"}, 1},
{"without base", CommitsCountOptions{Not: "master", Revision: []string{"branch1"}}, 2},
} {
t.Run(tc.name, func(t *testing.T) {
commitsCount, err := CommitsCount(t.Context(), bareRepo1,
CommitsCountOptions{
Revision: revision,
Since: tc.since,
Until: tc.until,
})
commitsCount, err := CommitsCount(t.Context(), bareRepo1, tc.options)
assert.NoError(t, err)
assert.Equal(t, tc.expected, commitsCount)
})
}
}
func TestCommitsCountWithoutBase(t *testing.T) {
bareRepo1 := mockRepository("repo1_bare")
commitsCount, err := CommitsCount(t.Context(), bareRepo1,
CommitsCountOptions{
Not: "master",
Revision: []string{"branch1"},
})
assert.NoError(t, err)
assert.Equal(t, int64(2), commitsCount)
}
func TestGetLatestCommitTime(t *testing.T) {
bareRepo1 := mockRepository("repo1_bare")
lct, err := GetLatestCommitTime(t.Context(), bareRepo1)
+35 -59
View File
@@ -12,7 +12,7 @@ import (
func TestParseCommitFileStatus(t *testing.T) {
type testcase struct {
output string
outputs []string
added []string
removed []string
modified []string
@@ -21,7 +21,11 @@ func TestParseCommitFileStatus(t *testing.T) {
kases := []testcase{
{
// Merge commit
output: "MM\x00options/locale/locale_en-US.ini\x00",
outputs: []string{
"MM\x00options/locale/locale_en-US.ini\x00",
// git 1.7.2 adds an unnecessary \x00 on merge commit
"\x00MM\x00options/locale/locale_en-US.ini\x00",
},
modified: []string{
"options/locale/locale_en-US.ini",
},
@@ -30,7 +34,11 @@ func TestParseCommitFileStatus(t *testing.T) {
},
{
// Spaces commit
output: "D\x00b\x00D\x00b b/b\x00A\x00b b/b b/b b/b\x00A\x00b b/b b/b b/b b/b\x00",
outputs: []string{
"D\x00b\x00D\x00b b/b\x00A\x00b b/b b/b b/b\x00A\x00b b/b b/b b/b b/b\x00",
// git 1.7.2 adds an unnecessary \n on normal commit
"\nD\x00b\x00D\x00b b/b\x00A\x00b b/b b/b b/b\x00A\x00b b/b b/b b/b b/b\x00",
},
removed: []string{
"b",
"b b/b",
@@ -43,7 +51,7 @@ func TestParseCommitFileStatus(t *testing.T) {
},
{
// larger commit
output: "M\x00go.mod\x00M\x00go.sum\x00M\x00modules/ssh/ssh.go\x00M\x00vendor/github.com/gliderlabs/ssh/circle.yml\x00M\x00vendor/github.com/gliderlabs/ssh/context.go\x00A\x00vendor/github.com/gliderlabs/ssh/go.mod\x00A\x00vendor/github.com/gliderlabs/ssh/go.sum\x00M\x00vendor/github.com/gliderlabs/ssh/server.go\x00M\x00vendor/github.com/gliderlabs/ssh/session.go\x00M\x00vendor/github.com/gliderlabs/ssh/ssh.go\x00M\x00vendor/golang.org/x/sys/unix/mkerrors.sh\x00M\x00vendor/golang.org/x/sys/unix/syscall_darwin.go\x00M\x00vendor/golang.org/x/sys/unix/zerrors_darwin_amd64.go\x00M\x00vendor/golang.org/x/sys/unix/zerrors_darwin_arm64.go\x00M\x00vendor/golang.org/x/sys/unix/zerrors_freebsd_386.go\x00M\x00vendor/golang.org/x/sys/unix/zerrors_freebsd_amd64.go\x00M\x00vendor/golang.org/x/sys/unix/zerrors_freebsd_arm.go\x00M\x00vendor/golang.org/x/sys/unix/zerrors_freebsd_arm64.go\x00M\x00vendor/golang.org/x/sys/unix/zerrors_linux.go\x00M\x00vendor/golang.org/x/sys/unix/ztypes_darwin_amd64.go\x00M\x00vendor/golang.org/x/sys/unix/ztypes_darwin_arm64.go\x00M\x00vendor/golang.org/x/sys/unix/ztypes_dragonfly_amd64.go\x00M\x00vendor/golang.org/x/sys/unix/ztypes_freebsd_386.go\x00M\x00vendor/golang.org/x/sys/unix/ztypes_freebsd_amd64.go\x00M\x00vendor/golang.org/x/sys/unix/ztypes_freebsd_arm.go\x00M\x00vendor/golang.org/x/sys/unix/ztypes_freebsd_arm64.go\x00M\x00vendor/golang.org/x/sys/unix/ztypes_netbsd_386.go\x00M\x00vendor/golang.org/x/sys/unix/ztypes_netbsd_amd64.go\x00M\x00vendor/golang.org/x/sys/unix/ztypes_netbsd_arm.go\x00M\x00vendor/golang.org/x/sys/unix/ztypes_netbsd_arm64.go\x00M\x00vendor/modules.txt\x00",
outputs: []string{"M\x00go.mod\x00M\x00go.sum\x00M\x00modules/ssh/ssh.go\x00M\x00vendor/github.com/gliderlabs/ssh/circle.yml\x00M\x00vendor/github.com/gliderlabs/ssh/context.go\x00A\x00vendor/github.com/gliderlabs/ssh/go.mod\x00A\x00vendor/github.com/gliderlabs/ssh/go.sum\x00M\x00vendor/github.com/gliderlabs/ssh/server.go\x00M\x00vendor/github.com/gliderlabs/ssh/session.go\x00M\x00vendor/github.com/gliderlabs/ssh/ssh.go\x00M\x00vendor/golang.org/x/sys/unix/mkerrors.sh\x00M\x00vendor/golang.org/x/sys/unix/syscall_darwin.go\x00M\x00vendor/golang.org/x/sys/unix/zerrors_darwin_amd64.go\x00M\x00vendor/golang.org/x/sys/unix/zerrors_darwin_arm64.go\x00M\x00vendor/golang.org/x/sys/unix/zerrors_freebsd_386.go\x00M\x00vendor/golang.org/x/sys/unix/zerrors_freebsd_amd64.go\x00M\x00vendor/golang.org/x/sys/unix/zerrors_freebsd_arm.go\x00M\x00vendor/golang.org/x/sys/unix/zerrors_freebsd_arm64.go\x00M\x00vendor/golang.org/x/sys/unix/zerrors_linux.go\x00M\x00vendor/golang.org/x/sys/unix/ztypes_darwin_amd64.go\x00M\x00vendor/golang.org/x/sys/unix/ztypes_darwin_arm64.go\x00M\x00vendor/golang.org/x/sys/unix/ztypes_dragonfly_amd64.go\x00M\x00vendor/golang.org/x/sys/unix/ztypes_freebsd_386.go\x00M\x00vendor/golang.org/x/sys/unix/ztypes_freebsd_amd64.go\x00M\x00vendor/golang.org/x/sys/unix/ztypes_freebsd_arm.go\x00M\x00vendor/golang.org/x/sys/unix/ztypes_freebsd_arm64.go\x00M\x00vendor/golang.org/x/sys/unix/ztypes_netbsd_386.go\x00M\x00vendor/golang.org/x/sys/unix/ztypes_netbsd_amd64.go\x00M\x00vendor/golang.org/x/sys/unix/ztypes_netbsd_arm.go\x00M\x00vendor/golang.org/x/sys/unix/ztypes_netbsd_arm64.go\x00M\x00vendor/modules.txt\x00"},
modified: []string{
"go.mod",
"go.sum",
@@ -81,37 +89,17 @@ func TestParseCommitFileStatus(t *testing.T) {
},
removed: []string{},
},
{
// git 1.7.2 adds an unnecessary \x00 on merge commit
output: "\x00MM\x00options/locale/locale_en-US.ini\x00",
modified: []string{
"options/locale/locale_en-US.ini",
},
added: []string{},
removed: []string{},
},
{
// git 1.7.2 adds an unnecessary \n on normal commit
output: "\nD\x00b\x00D\x00b b/b\x00A\x00b b/b b/b b/b\x00A\x00b b/b b/b b/b b/b\x00",
removed: []string{
"b",
"b b/b",
},
modified: []string{},
added: []string{
"b b/b b/b b/b",
"b b/b b/b b/b b/b",
},
},
}
for _, kase := range kases {
fileStatus := NewCommitFileStatus()
parseCommitFileStatus(fileStatus, strings.NewReader(kase.output))
for _, output := range kase.outputs {
fileStatus := NewCommitFileStatus()
parseCommitFileStatus(fileStatus, strings.NewReader(output))
assert.Equal(t, kase.added, fileStatus.Added)
assert.Equal(t, kase.removed, fileStatus.Removed)
assert.Equal(t, kase.modified, fileStatus.Modified)
assert.Equal(t, kase.added, fileStatus.Added)
assert.Equal(t, kase.removed, fileStatus.Removed)
assert.Equal(t, kase.modified, fileStatus.Modified)
}
}
}
@@ -141,35 +129,23 @@ func TestGetCommitFileStatusMerges(t *testing.T) {
func TestGetCommitFileStatusMergesSha256(t *testing.T) {
bareRepo6Sha256 := mockRepository("repo6_merge_sha256")
commitFileStatus, err := GetCommitFileStatus(t.Context(), bareRepo6Sha256, "d2e5609f630dd8db500f5298d05d16def282412e3e66ed68cc7d0833b29129a1")
assert.NoError(t, err)
expected := CommitFileStatus{
[]string{
"add_file.txt",
for _, tc := range []struct {
commitID string
expected CommitFileStatus
}{
{
"d2e5609f630dd8db500f5298d05d16def282412e3e66ed68cc7d0833b29129a1",
CommitFileStatus{[]string{"add_file.txt"}, []string{}, []string{"to_modify.txt"}},
},
[]string{},
[]string{
"to_modify.txt",
{
"da1ded40dc8e5b7c564171f4bf2fc8370487decfb1cb6a99ef28f3ed73d09172",
CommitFileStatus{[]string{}, []string{"to_remove.txt"}, []string{}},
},
} {
commitFileStatus, err := GetCommitFileStatus(t.Context(), bareRepo6Sha256, tc.commitID)
assert.NoError(t, err)
assert.Equal(t, tc.expected.Added, commitFileStatus.Added)
assert.Equal(t, tc.expected.Removed, commitFileStatus.Removed)
assert.Equal(t, tc.expected.Modified, commitFileStatus.Modified)
}
assert.Equal(t, expected.Added, commitFileStatus.Added)
assert.Equal(t, expected.Removed, commitFileStatus.Removed)
assert.Equal(t, expected.Modified, commitFileStatus.Modified)
expected = CommitFileStatus{
[]string{},
[]string{
"to_remove.txt",
},
[]string{},
}
commitFileStatus, err = GetCommitFileStatus(t.Context(), bareRepo6Sha256, "da1ded40dc8e5b7c564171f4bf2fc8370487decfb1cb6a99ef28f3ed73d09172")
assert.NoError(t, err)
assert.Equal(t, expected.Added, commitFileStatus.Added)
assert.Equal(t, expected.Removed, commitFileStatus.Removed)
assert.Equal(t, expected.Modified, commitFileStatus.Modified)
}
-70
View File
@@ -5,11 +5,9 @@ package git
import (
"path/filepath"
"strings"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestGetFullCommitIDSha256(t *testing.T) {
@@ -26,74 +24,6 @@ func TestGetFullCommitIDErrorSha256(t *testing.T) {
}
}
func TestCommitFromReaderSha256(t *testing.T) {
commitString := `tree e7f9e96dd79c09b078cac8b303a7d3b9d65ff9b734e86060a4d20409fd379f9e
parent 26e9ccc29fad747e9c5d9f4c9ddeb7eff61cc45ef6a8dc258cbeb181afc055e8
author Adam Majer <amajer@suse.de> 1698676906 +0100
committer Adam Majer <amajer@suse.de> 1698676906 +0100
gpgsig-sha256 -----BEGIN PGP SIGNATURE-----
` + " " + `
iQIrBAABCgAtFiEES+fB08xlgTrzSdQvhkUIsBsmec8FAmU/wKoPHGFtYWplckBz
dXNlLmRlAAoJEIZFCLAbJnnP4s4PQIJATa++WPzR6/H4etT7bsOGoMyguEJYyWOd
aTybplzT7QAL7h2to0QszGabtzMJPIA39xSFZNYNN30voK5YyyYibXluPKgjemfK
WNXwF+gkwgZI38gSvKf+vlqI+EYyIFe19wOhiju0m8SIlB5NEPiWHa17q2mqmqqx
1FWa2JdqLPYjAtSLFXeSZegrY5V1FxdemyMUONkg8YO9OSIMZiE0GsnnOXQ3xcT4
JTCnmlUxIKw689UiEY80JopUIq+Wl7+qq9507IYYSUCyB6JazL42AKMzVCbD+qBP
oOzh/hafYgk9H9qCQXaLbmvs17zXRpicig1bAzqgAy1FDelvpERyRTydEajSLIG6
U1cRCkgXCZ0NfsYNPPmBa8b3+rnstypXYTbyMwTln7FfUAaGo6o9JYiPMkzxlmsy
zfp/tcaY8+LlBL9aOJjtv+a0p+HrpCGd6CCa4ARfphTLq8QRSSh8uzlB9N+6HnRI
VAEUo6ecdDxSpyt2naeg9pKus/BRi7P6g4B1hkk/zZstUX/QP4IQuAJbXjkvsC+X
HKRr3NlRM/DygzTyj0gN74uoa0goCIbyAQhiT42nm0cuhM7uN/W0ayrlZjGF1cbR
8NCJUL2Nwj0ywKIavC99Ipkb8AsFwpVT6U6effs6
=xybZ
-----END PGP SIGNATURE-----
signed commit`
sha := &Sha256Hash{
0x94, 0x33, 0xb2, 0xa6, 0x2b, 0x96, 0x4c, 0x17, 0xa4, 0x48, 0x5a, 0xe1, 0x80, 0xf4, 0x5f, 0x59,
0x5d, 0x3e, 0x69, 0xd3, 0x1b, 0x78, 0x60, 0x87, 0x77, 0x5e, 0x28, 0xc6, 0xb6, 0x39, 0x9d, 0xf0,
}
gitRepo, err := OpenRepositoryLocal(t.Context(), filepath.Join(testReposDir, "repo1_bare_sha256"))
assert.NoError(t, err)
assert.NotNil(t, gitRepo)
defer gitRepo.Close()
commitFromReader, err := CommitFromReader(sha, strings.NewReader(commitString))
assert.NoError(t, err)
require.NotNil(t, commitFromReader)
assert.EqualValues(t, sha, commitFromReader.ID)
assert.Equal(t, `-----BEGIN PGP SIGNATURE-----
iQIrBAABCgAtFiEES+fB08xlgTrzSdQvhkUIsBsmec8FAmU/wKoPHGFtYWplckBz
dXNlLmRlAAoJEIZFCLAbJnnP4s4PQIJATa++WPzR6/H4etT7bsOGoMyguEJYyWOd
aTybplzT7QAL7h2to0QszGabtzMJPIA39xSFZNYNN30voK5YyyYibXluPKgjemfK
WNXwF+gkwgZI38gSvKf+vlqI+EYyIFe19wOhiju0m8SIlB5NEPiWHa17q2mqmqqx
1FWa2JdqLPYjAtSLFXeSZegrY5V1FxdemyMUONkg8YO9OSIMZiE0GsnnOXQ3xcT4
JTCnmlUxIKw689UiEY80JopUIq+Wl7+qq9507IYYSUCyB6JazL42AKMzVCbD+qBP
oOzh/hafYgk9H9qCQXaLbmvs17zXRpicig1bAzqgAy1FDelvpERyRTydEajSLIG6
U1cRCkgXCZ0NfsYNPPmBa8b3+rnstypXYTbyMwTln7FfUAaGo6o9JYiPMkzxlmsy
zfp/tcaY8+LlBL9aOJjtv+a0p+HrpCGd6CCa4ARfphTLq8QRSSh8uzlB9N+6HnRI
VAEUo6ecdDxSpyt2naeg9pKus/BRi7P6g4B1hkk/zZstUX/QP4IQuAJbXjkvsC+X
HKRr3NlRM/DygzTyj0gN74uoa0goCIbyAQhiT42nm0cuhM7uN/W0ayrlZjGF1cbR
8NCJUL2Nwj0ywKIavC99Ipkb8AsFwpVT6U6effs6
=xybZ
-----END PGP SIGNATURE-----`, commitFromReader.Signature.Signature)
assert.Equal(t, `tree e7f9e96dd79c09b078cac8b303a7d3b9d65ff9b734e86060a4d20409fd379f9e
parent 26e9ccc29fad747e9c5d9f4c9ddeb7eff61cc45ef6a8dc258cbeb181afc055e8
author Adam Majer <amajer@suse.de> 1698676906 +0100
committer Adam Majer <amajer@suse.de> 1698676906 +0100
signed commit`, commitFromReader.Signature.Payload)
assert.Equal(t, "Adam Majer <amajer@suse.de>", commitFromReader.Author.String())
commitFromReader2, err := CommitFromReader(sha, strings.NewReader(commitString+"\n\n"))
assert.NoError(t, err)
commitFromReader.CommitMessage.MessageRaw += "\n\n"
commitFromReader.Signature.Payload += "\n\n"
assert.Equal(t, commitFromReader, commitFromReader2)
}
func TestHasPreviousCommitSha256(t *testing.T) {
bareRepo1Path := filepath.Join(testReposDir, "repo1_bare_sha256")
+100 -50
View File
@@ -28,7 +28,15 @@ func TestGetFullCommitIDError(t *testing.T) {
}
func TestCommitFromReader(t *testing.T) {
commitString := `tree f1a6cb52b2d16773290cefe49ad0684b50a4f930
for _, testCase := range []struct {
name, repo string
sha ObjectID
commitString, signature, payload, author string
}{
{
"TestCommitFromReader", "repo1_bare",
&Sha1Hash{0xfe, 0xaf, 0x4b, 0xa6, 0xbc, 0x63, 0x5f, 0xec, 0x44, 0x2f, 0x46, 0xdd, 0xd4, 0x51, 0x24, 0x16, 0xec, 0x43, 0xc2, 0xc2},
`tree f1a6cb52b2d16773290cefe49ad0684b50a4f930
parent 37991dec2c8e592043f47155ce4808d4580f9123
author silverwind <me@silverwind.io> 1563741793 +0200
committer silverwind <me@silverwind.io> 1563741793 +0200
@@ -49,19 +57,8 @@ gpgsig -----BEGIN PGP SIGNATURE-----
=FRsO
-----END PGP SIGNATURE-----
empty commit`
sha := &Sha1Hash{0xfe, 0xaf, 0x4b, 0xa6, 0xbc, 0x63, 0x5f, 0xec, 0x44, 0x2f, 0x46, 0xdd, 0xd4, 0x51, 0x24, 0x16, 0xec, 0x43, 0xc2, 0xc2}
gitRepo, err := OpenRepositoryLocal(t.Context(), filepath.Join(testReposDir, "repo1_bare"))
assert.NoError(t, err)
assert.NotNil(t, gitRepo)
defer gitRepo.Close()
commitFromReader, err := CommitFromReader(sha, strings.NewReader(commitString))
assert.NoError(t, err)
require.NotNil(t, commitFromReader)
assert.EqualValues(t, sha, commitFromReader.ID)
assert.Equal(t, `-----BEGIN PGP SIGNATURE-----
empty commit`,
`-----BEGIN PGP SIGNATURE-----
iQIzBAABCAAdFiEEWPb2jX6FS2mqyJRQLmK0HJOGlEMFAl00zmEACgkQLmK0HJOG
lEMDFBAAhQKKqLD1VICygJMEB8t1gBmNLgvziOLfpX4KPWdPtBk3v/QJ7OrfMrVK
@@ -76,24 +73,19 @@ sD53z/f0J+We4VZjY+pidvA9BGZPFVdR3wd3xGs8/oH6UWaLJAMGkLG6dDb3qDLm
mfeFhT57UbE4qukTDIQ0Y0WM40UYRTakRaDY7ubhXgLgx09Cnp9XTVMsHgT6j9/i
1pxsB104XLWjQHTjr1JtiaBQEwFh9r2OKTcpvaLcbNtYpo7CzOs=
=FRsO
-----END PGP SIGNATURE-----`, commitFromReader.Signature.Signature)
assert.Equal(t, `tree f1a6cb52b2d16773290cefe49ad0684b50a4f930
-----END PGP SIGNATURE-----`,
`tree f1a6cb52b2d16773290cefe49ad0684b50a4f930
parent 37991dec2c8e592043f47155ce4808d4580f9123
author silverwind <me@silverwind.io> 1563741793 +0200
committer silverwind <me@silverwind.io> 1563741793 +0200
empty commit`, commitFromReader.Signature.Payload)
assert.Equal(t, "silverwind <me@silverwind.io>", commitFromReader.Author.String())
commitFromReader2, err := CommitFromReader(sha, strings.NewReader(commitString+"\n\n"))
assert.NoError(t, err)
commitFromReader.CommitMessage.MessageRaw += "\n\n"
commitFromReader.Signature.Payload += "\n\n"
assert.Equal(t, commitFromReader, commitFromReader2)
}
func TestCommitWithEncodingFromReader(t *testing.T) {
commitString := `tree ca3fad42080dd1a6d291b75acdfc46e5b9b307e5
empty commit`,
"silverwind <me@silverwind.io>",
},
{
"TestCommitWithEncodingFromReader", "repo1_bare",
&Sha1Hash{0xfe, 0xaf, 0x4b, 0xa6, 0xbc, 0x63, 0x5f, 0xec, 0x44, 0x2f, 0x46, 0xdd, 0xd4, 0x51, 0x24, 0x16, 0xec, 0x43, 0xc2, 0xc2},
strings.ReplaceAll(`tree ca3fad42080dd1a6d291b75acdfc46e5b9b307e5
parent 47b24e7ab977ed31c5a39989d570847d6d0052af
author KN4CK3R <admin@oldschoolhack.me> 1711702962 +0100
committer KN4CK3R <admin@oldschoolhack.me> 1711702962 +0100
@@ -113,19 +105,8 @@ gpgsig -----BEGIN PGP SIGNATURE-----
=r3UU
-----END PGP SIGNATURE-----
ISO-8859-1`
commitString = strings.ReplaceAll(commitString, "<SPACE>", " ")
sha := &Sha1Hash{0xfe, 0xaf, 0x4b, 0xa6, 0xbc, 0x63, 0x5f, 0xec, 0x44, 0x2f, 0x46, 0xdd, 0xd4, 0x51, 0x24, 0x16, 0xec, 0x43, 0xc2, 0xc2}
gitRepo, err := OpenRepositoryLocal(t.Context(), filepath.Join(testReposDir, "repo1_bare"))
assert.NoError(t, err)
assert.NotNil(t, gitRepo)
defer gitRepo.Close()
commitFromReader, err := CommitFromReader(sha, strings.NewReader(commitString))
assert.NoError(t, err)
require.NotNil(t, commitFromReader)
assert.EqualValues(t, sha, commitFromReader.ID)
assert.Equal(t, `-----BEGIN PGP SIGNATURE-----
ISO-8859-1`, "<SPACE>", " "),
`-----BEGIN PGP SIGNATURE-----
iQGzBAABCgAdFiEE9HRrbqvYxPT8PXbefPSEkrowAa8FAmYGg7IACgkQfPSEkrow
Aa9olwv+P0HhtCM6CRvlUmPaqswRsDPNR4i66xyXGiSxdI9V5oJL7HLiQIM7KrFR
@@ -138,21 +119,90 @@ SONRzusmu5n3DgV956REL7x62h7JuqmBz/12HZkr0z0zgXkcZ04q08pSJATX5N1F
yN+tWxTsWg+zhDk96d5Esdo9JMjcFvPv0eioo30GAERaz1hoD7zCMT4jgUFTQwgz
jw4YcO5u
=r3UU
-----END PGP SIGNATURE-----`, commitFromReader.Signature.Signature)
assert.Equal(t, `tree ca3fad42080dd1a6d291b75acdfc46e5b9b307e5
-----END PGP SIGNATURE-----`,
`tree ca3fad42080dd1a6d291b75acdfc46e5b9b307e5
parent 47b24e7ab977ed31c5a39989d570847d6d0052af
author KN4CK3R <admin@oldschoolhack.me> 1711702962 +0100
committer KN4CK3R <admin@oldschoolhack.me> 1711702962 +0100
encoding ISO-8859-1
ISO-8859-1`, commitFromReader.Signature.Payload)
assert.Equal(t, "KN4CK3R <admin@oldschoolhack.me>", commitFromReader.Author.String())
ISO-8859-1`,
"KN4CK3R <admin@oldschoolhack.me>",
},
{
"TestCommitFromReaderSha256", "repo1_bare_sha256",
&Sha256Hash{
0x94, 0x33, 0xb2, 0xa6, 0x2b, 0x96, 0x4c, 0x17, 0xa4, 0x48, 0x5a, 0xe1, 0x80, 0xf4, 0x5f, 0x59,
0x5d, 0x3e, 0x69, 0xd3, 0x1b, 0x78, 0x60, 0x87, 0x77, 0x5e, 0x28, 0xc6, 0xb6, 0x39, 0x9d, 0xf0,
},
`tree e7f9e96dd79c09b078cac8b303a7d3b9d65ff9b734e86060a4d20409fd379f9e
parent 26e9ccc29fad747e9c5d9f4c9ddeb7eff61cc45ef6a8dc258cbeb181afc055e8
author Adam Majer <amajer@suse.de> 1698676906 +0100
committer Adam Majer <amajer@suse.de> 1698676906 +0100
gpgsig-sha256 -----BEGIN PGP SIGNATURE-----
` + " " + `
iQIrBAABCgAtFiEES+fB08xlgTrzSdQvhkUIsBsmec8FAmU/wKoPHGFtYWplckBz
dXNlLmRlAAoJEIZFCLAbJnnP4s4PQIJATa++WPzR6/H4etT7bsOGoMyguEJYyWOd
aTybplzT7QAL7h2to0QszGabtzMJPIA39xSFZNYNN30voK5YyyYibXluPKgjemfK
WNXwF+gkwgZI38gSvKf+vlqI+EYyIFe19wOhiju0m8SIlB5NEPiWHa17q2mqmqqx
1FWa2JdqLPYjAtSLFXeSZegrY5V1FxdemyMUONkg8YO9OSIMZiE0GsnnOXQ3xcT4
JTCnmlUxIKw689UiEY80JopUIq+Wl7+qq9507IYYSUCyB6JazL42AKMzVCbD+qBP
oOzh/hafYgk9H9qCQXaLbmvs17zXRpicig1bAzqgAy1FDelvpERyRTydEajSLIG6
U1cRCkgXCZ0NfsYNPPmBa8b3+rnstypXYTbyMwTln7FfUAaGo6o9JYiPMkzxlmsy
zfp/tcaY8+LlBL9aOJjtv+a0p+HrpCGd6CCa4ARfphTLq8QRSSh8uzlB9N+6HnRI
VAEUo6ecdDxSpyt2naeg9pKus/BRi7P6g4B1hkk/zZstUX/QP4IQuAJbXjkvsC+X
HKRr3NlRM/DygzTyj0gN74uoa0goCIbyAQhiT42nm0cuhM7uN/W0ayrlZjGF1cbR
8NCJUL2Nwj0ywKIavC99Ipkb8AsFwpVT6U6effs6
=xybZ
-----END PGP SIGNATURE-----
commitFromReader2, err := CommitFromReader(sha, strings.NewReader(commitString+"\n\n"))
assert.NoError(t, err)
commitFromReader.CommitMessage.MessageRaw += "\n\n"
commitFromReader.Signature.Payload += "\n\n"
assert.Equal(t, commitFromReader, commitFromReader2)
signed commit`,
`-----BEGIN PGP SIGNATURE-----
iQIrBAABCgAtFiEES+fB08xlgTrzSdQvhkUIsBsmec8FAmU/wKoPHGFtYWplckBz
dXNlLmRlAAoJEIZFCLAbJnnP4s4PQIJATa++WPzR6/H4etT7bsOGoMyguEJYyWOd
aTybplzT7QAL7h2to0QszGabtzMJPIA39xSFZNYNN30voK5YyyYibXluPKgjemfK
WNXwF+gkwgZI38gSvKf+vlqI+EYyIFe19wOhiju0m8SIlB5NEPiWHa17q2mqmqqx
1FWa2JdqLPYjAtSLFXeSZegrY5V1FxdemyMUONkg8YO9OSIMZiE0GsnnOXQ3xcT4
JTCnmlUxIKw689UiEY80JopUIq+Wl7+qq9507IYYSUCyB6JazL42AKMzVCbD+qBP
oOzh/hafYgk9H9qCQXaLbmvs17zXRpicig1bAzqgAy1FDelvpERyRTydEajSLIG6
U1cRCkgXCZ0NfsYNPPmBa8b3+rnstypXYTbyMwTln7FfUAaGo6o9JYiPMkzxlmsy
zfp/tcaY8+LlBL9aOJjtv+a0p+HrpCGd6CCa4ARfphTLq8QRSSh8uzlB9N+6HnRI
VAEUo6ecdDxSpyt2naeg9pKus/BRi7P6g4B1hkk/zZstUX/QP4IQuAJbXjkvsC+X
HKRr3NlRM/DygzTyj0gN74uoa0goCIbyAQhiT42nm0cuhM7uN/W0ayrlZjGF1cbR
8NCJUL2Nwj0ywKIavC99Ipkb8AsFwpVT6U6effs6
=xybZ
-----END PGP SIGNATURE-----`,
`tree e7f9e96dd79c09b078cac8b303a7d3b9d65ff9b734e86060a4d20409fd379f9e
parent 26e9ccc29fad747e9c5d9f4c9ddeb7eff61cc45ef6a8dc258cbeb181afc055e8
author Adam Majer <amajer@suse.de> 1698676906 +0100
committer Adam Majer <amajer@suse.de> 1698676906 +0100
signed commit`,
"Adam Majer <amajer@suse.de>",
},
} {
t.Run(testCase.name, func(t *testing.T) {
gitRepo, err := OpenRepositoryLocal(t.Context(), filepath.Join(testReposDir, testCase.repo))
assert.NoError(t, err)
assert.NotNil(t, gitRepo)
defer gitRepo.Close()
commitFromReader, err := CommitFromReader(testCase.sha, strings.NewReader(testCase.commitString))
assert.NoError(t, err)
require.NotNil(t, commitFromReader)
assert.Equal(t, testCase.sha, commitFromReader.ID)
assert.Equal(t, testCase.signature, commitFromReader.Signature.Signature)
assert.Equal(t, testCase.payload, commitFromReader.Signature.Payload)
assert.Equal(t, testCase.author, commitFromReader.Author.String())
commitFromReader2, err := CommitFromReader(testCase.sha, strings.NewReader(testCase.commitString+"\n\n"))
assert.NoError(t, err)
commitFromReader.CommitMessage.MessageRaw += "\n\n"
commitFromReader.Signature.Payload += "\n\n"
assert.Equal(t, commitFromReader, commitFromReader2)
})
}
}
func TestHasPreviousCommit(t *testing.T) {
+34 -83
View File
@@ -43,96 +43,47 @@ Hello from 2
func TestRepoGetDivergingCommits(t *testing.T) {
repo := mockRepository("repo1_bare")
do, err := GetDivergingCommits(t.Context(), repo, "master", "branch2")
assert.NoError(t, err)
assert.Equal(t, &DivergeObject{
Ahead: 1,
Behind: 5,
}, do)
do, err = GetDivergingCommits(t.Context(), repo, "master", "master")
assert.NoError(t, err)
assert.Equal(t, &DivergeObject{
Ahead: 0,
Behind: 0,
}, do)
do, err = GetDivergingCommits(t.Context(), repo, "master", "test")
assert.NoError(t, err)
assert.Equal(t, &DivergeObject{
Ahead: 0,
Behind: 2,
}, do)
for _, testcase := range []struct {
branch string
expected DivergeObject
}{
{"branch2", DivergeObject{Ahead: 1, Behind: 5}},
{"master", DivergeObject{Ahead: 0, Behind: 0}},
{"test", DivergeObject{Ahead: 0, Behind: 2}},
} {
do, err := GetDivergingCommits(t.Context(), repo, "master", testcase.branch)
assert.NoError(t, err)
assert.Equal(t, &testcase.expected, do)
}
}
func TestGetCommitIDsBetweenReverse(t *testing.T) {
repo := mockRepository("repo1_bare")
// tests raw commit IDs
commitIDs, err := GetCommitIDsBetweenReverse(t.Context(), repo,
"8d92fc957a4d7cfd98bc375f0b7bb189a0d6c9f2",
"ce064814f4a0d337b333e646ece456cd39fab612",
"",
100,
)
assert.NoError(t, err)
assert.Equal(t, []string{
startRef := "8d92fc957a4d7cfd98bc375f0b7bb189a0d6c9f2"
endRef := "ce064814f4a0d337b333e646ece456cd39fab612"
expectedCommitIDs := []string{
"8006ff9adbf0cb94da7dad9e537e53817f9fa5c0",
"6fbd69e9823458e6c4a2fc5c0f6bc022b2f2acd1",
"37991dec2c8e592043f47155ce4808d4580f9123",
"feaf4ba6bc635fec442f46ddd4512416ec43c2c2",
"ce064814f4a0d337b333e646ece456cd39fab612",
}, commitIDs)
commitIDs, err = GetCommitIDsBetweenReverse(t.Context(), repo,
"8d92fc957a4d7cfd98bc375f0b7bb189a0d6c9f2",
"ce064814f4a0d337b333e646ece456cd39fab612",
"6fbd69e9823458e6c4a2fc5c0f6bc022b2f2acd1",
100,
)
assert.NoError(t, err)
assert.Equal(t, []string{
"37991dec2c8e592043f47155ce4808d4580f9123",
"feaf4ba6bc635fec442f46ddd4512416ec43c2c2",
"ce064814f4a0d337b333e646ece456cd39fab612",
}, commitIDs)
commitIDs, err = GetCommitIDsBetweenReverse(t.Context(), repo,
"8d92fc957a4d7cfd98bc375f0b7bb189a0d6c9f2",
"ce064814f4a0d337b333e646ece456cd39fab612",
"",
3,
)
assert.NoError(t, err)
assert.Equal(t, []string{
"37991dec2c8e592043f47155ce4808d4580f9123",
"feaf4ba6bc635fec442f46ddd4512416ec43c2c2",
"ce064814f4a0d337b333e646ece456cd39fab612",
}, commitIDs)
// test branch names instead of raw commit IDs.
commitIDs, err = GetCommitIDsBetweenReverse(t.Context(), repo,
"test",
"master",
"",
100,
)
assert.NoError(t, err)
assert.Equal(t, []string{
"feaf4ba6bc635fec442f46ddd4512416ec43c2c2",
"ce064814f4a0d337b333e646ece456cd39fab612",
}, commitIDs)
// add notref to exclude test
commitIDs, err = GetCommitIDsBetweenReverse(t.Context(), repo,
"test",
"master",
"test",
100,
)
assert.NoError(t, err)
assert.Equal(t, []string{
"feaf4ba6bc635fec442f46ddd4512416ec43c2c2",
"ce064814f4a0d337b333e646ece456cd39fab612",
}, commitIDs)
}
for _, testcase := range []struct {
startRef, endRef, notRef string
limit int
expected []string
}{
// tests raw commit IDs
{startRef, endRef, "", 100, expectedCommitIDs},
{startRef, endRef, expectedCommitIDs[1], 100, expectedCommitIDs[2:]},
{startRef, endRef, "", 3, expectedCommitIDs[2:]},
// test branch names instead of raw commit IDs.
{"test", "master", "", 100, expectedCommitIDs[3:]},
// add notref to exclude test
{"test", "master", "test", 100, expectedCommitIDs[3:]},
} {
commitIDs, err := GetCommitIDsBetweenReverse(t.Context(), repo, testcase.startRef, testcase.endRef, testcase.notRef, testcase.limit)
assert.NoError(t, err)
assert.Equal(t, testcase.expected, commitIDs)
}
}
+23 -45
View File
@@ -20,9 +20,7 @@ func TestGrepSearch(t *testing.T) {
assert.NoError(t, err)
defer repo.Close()
res, err := GrepSearch(t.Context(), repo, "void", GrepOptions{})
assert.NoError(t, err)
assert.Equal(t, []*GrepResult{
expectedResults := []*GrepResult{
{
Filename: "java-hello/main.java",
LineNumbers: []int{3},
@@ -33,49 +31,29 @@ func TestGrepSearch(t *testing.T) {
LineNumbers: []int{3},
LineCodes: []string{" public static void main(String[] args)"},
},
}, res)
}
for _, testcase := range []struct {
options GrepOptions
expected []*GrepResult
}{
{GrepOptions{}, expectedResults},
{GrepOptions{PathspecList: []string{":(glob)java-hello/*"}}, expectedResults[:1]},
{GrepOptions{PathspecList: []string{":(glob,exclude)java-hello/*"}}, expectedResults[1:]},
{GrepOptions{MaxResultLimit: 1}, expectedResults[:1]},
{GrepOptions{MaxResultLimit: 1, MaxLineLength: 39}, []*GrepResult{
{
Filename: "java-hello/main.java",
LineNumbers: []int{3},
LineCodes: []string{" public static void main(String[] arg"},
},
}},
} {
res, err := GrepSearch(t.Context(), repo, "void", testcase.options)
assert.NoError(t, err)
assert.Equal(t, testcase.expected, res)
}
res, err = GrepSearch(t.Context(), repo, "void", GrepOptions{PathspecList: []string{":(glob)java-hello/*"}})
assert.NoError(t, err)
assert.Equal(t, []*GrepResult{
{
Filename: "java-hello/main.java",
LineNumbers: []int{3},
LineCodes: []string{" public static void main(String[] args)"},
},
}, res)
res, err = GrepSearch(t.Context(), repo, "void", GrepOptions{PathspecList: []string{":(glob,exclude)java-hello/*"}})
assert.NoError(t, err)
assert.Equal(t, []*GrepResult{
{
Filename: "main.vendor.java",
LineNumbers: []int{3},
LineCodes: []string{" public static void main(String[] args)"},
},
}, res)
res, err = GrepSearch(t.Context(), repo, "void", GrepOptions{MaxResultLimit: 1})
assert.NoError(t, err)
assert.Equal(t, []*GrepResult{
{
Filename: "java-hello/main.java",
LineNumbers: []int{3},
LineCodes: []string{" public static void main(String[] args)"},
},
}, res)
res, err = GrepSearch(t.Context(), repo, "void", GrepOptions{MaxResultLimit: 1, MaxLineLength: 39})
assert.NoError(t, err)
assert.Equal(t, []*GrepResult{
{
Filename: "java-hello/main.java",
LineNumbers: []int{3},
LineCodes: []string{" public static void main(String[] arg"},
},
}, res)
res, err = GrepSearch(t.Context(), repo, "no-such-content", GrepOptions{})
res, err := GrepSearch(t.Context(), repo, "no-such-content", GrepOptions{})
assert.NoError(t, err)
assert.Empty(t, res)
+1 -17
View File
@@ -12,7 +12,7 @@ import (
"github.com/stretchr/testify/assert"
)
func TestParseTreeEntriesLong(t *testing.T) {
func TestParseTreeEntries(t *testing.T) {
testCases := []struct {
Input string
Expected []*TreeEntry
@@ -53,22 +53,6 @@ func TestParseTreeEntriesLong(t *testing.T) {
},
},
},
}
for _, testCase := range testCases {
entries, err := ParseTreeEntries([]byte(testCase.Input))
assert.NoError(t, err)
assert.Len(t, entries, len(testCase.Expected))
for i, entry := range entries {
assert.Equal(t, testCase.Expected[i], entry)
}
}
}
func TestParseTreeEntriesShort(t *testing.T) {
testCases := []struct {
Input string
Expected []*TreeEntry
}{
{
Input: `100644 blob ea0d83c9081af9500ac9f804101b3fd0a5c293af README.md
040000 tree 84b90550547016f73c5dd3f50dea662389e67b6d assets
+18 -25
View File
@@ -40,30 +40,23 @@ func TestRepository_GetBlob_Found(t *testing.T) {
}
}
func TestRepository_GetBlob_NotExist(t *testing.T) {
repoPath := filepath.Join(testReposDir, "repo1_bare")
r, err := OpenRepositoryLocal(t.Context(), repoPath)
assert.NoError(t, err)
defer r.Close()
func TestRepository_GetBlob_Errors(t *testing.T) {
for _, testCase := range []struct {
name string
id string
err error
}{
{"NotExist", "0000000000000000000000000000000000000000", ErrNotExist{"0000000000000000000000000000000000000000", ""}},
{"NoId", "", fmt.Errorf("length %d has no matched object format: %s", len(""), "")},
} {
t.Run(testCase.name, func(t *testing.T) {
r, err := OpenRepositoryLocal(t.Context(), filepath.Join(testReposDir, "repo1_bare"))
assert.NoError(t, err)
defer r.Close()
testCase := "0000000000000000000000000000000000000000"
testError := ErrNotExist{testCase, ""}
blob, err := r.GetBlob(testCase)
assert.Nil(t, blob)
assert.EqualError(t, err, testError.Error())
}
func TestRepository_GetBlob_NoId(t *testing.T) {
repoPath := filepath.Join(testReposDir, "repo1_bare")
r, err := OpenRepositoryLocal(t.Context(), repoPath)
assert.NoError(t, err)
defer r.Close()
testCase := ""
testError := fmt.Errorf("length %d has no matched object format: %s", len(testCase), testCase)
blob, err := r.GetBlob(testCase)
assert.Nil(t, blob)
assert.EqualError(t, err, testError.Error())
blob, err := r.GetBlob(testCase.id)
assert.Nil(t, blob)
assert.EqualError(t, err, testCase.err.Error())
})
}
}
+31 -93
View File
@@ -4,6 +4,7 @@
package git
import (
"context"
"path/filepath"
"testing"
@@ -96,100 +97,37 @@ func BenchmarkGetRefsBySha(b *testing.B) {
_, _ = bareRepo5.GetRefsBySha(b.Context(), "58a4bcc53ac13e7ff76127e0fb518b5262bf09af", "")
}
func TestRepository_IsObjectExist(t *testing.T) {
ctx := t.Context()
repo, err := OpenRepositoryLocal(ctx, filepath.Join(testReposDir, "repo1_bare"))
require.NoError(t, err)
defer repo.Close()
tests := []struct {
name string
arg string
want bool
func TestRepository_Existence(t *testing.T) {
for _, method := range []struct {
name string
exists func(*Repository, context.Context, string) bool
branchExists bool
}{
{
name: "empty",
arg: "",
want: false,
},
{
name: "branch",
arg: "master",
want: false,
},
{
name: "commit hash",
arg: "ce064814f4a0d337b333e646ece456cd39fab612",
want: true,
},
{
name: "short commit hash",
arg: "ce06481",
want: true,
},
{
name: "blob hash",
arg: "153f451b9ee7fa1da317ab17a127e9fd9d384310",
want: true,
},
{
name: "short blob hash",
arg: "153f451",
want: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
assert.Equal(t, tt.want, repo.IsObjectExist(ctx, tt.arg))
})
}
}
func TestRepository_IsReferenceExist(t *testing.T) {
ctx := t.Context()
repo, err := OpenRepositoryLocal(ctx, filepath.Join(testReposDir, "repo1_bare"))
require.NoError(t, err)
defer repo.Close()
tests := []struct {
name string
arg string
want bool
}{
{
name: "empty",
arg: "",
want: false,
},
{
name: "branch",
arg: "master",
want: true,
},
{
name: "commit hash",
arg: "ce064814f4a0d337b333e646ece456cd39fab612",
want: true,
},
{
name: "short commit hash",
arg: "ce06481",
want: true,
},
{
name: "blob hash",
arg: "153f451b9ee7fa1da317ab17a127e9fd9d384310",
want: true,
},
{
name: "short blob hash",
arg: "153f451",
want: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
assert.Equal(t, tt.want, repo.IsReferenceExist(ctx, tt.arg))
{"IsObjectExist", (*Repository).IsObjectExist, false},
{"IsReferenceExist", (*Repository).IsReferenceExist, true},
} {
t.Run(method.name, func(t *testing.T) {
ctx := t.Context()
repo, err := OpenRepositoryLocal(ctx, filepath.Join(testReposDir, "repo1_bare"))
require.NoError(t, err)
defer repo.Close()
for _, testCase := range []struct {
name string
arg string
want bool
}{
{"empty", "", false},
{"branch", "master", method.branchExists},
{"commit hash", "ce064814f4a0d337b333e646ece456cd39fab612", true},
{"short commit hash", "ce06481", true},
{"blob hash", "153f451b9ee7fa1da317ab17a127e9fd9d384310", true},
{"short blob hash", "153f451", true},
} {
t.Run(testCase.name, func(t *testing.T) {
assert.Equal(t, testCase.want, method.exists(repo, ctx, testCase.arg))
})
}
})
}
}
+88 -108
View File
@@ -16,91 +16,96 @@ import (
"github.com/stretchr/testify/require"
)
func TestRepository_GetCommitBranches(t *testing.T) {
bareRepo1Path := filepath.Join(testReposDir, "repo1_bare")
bareRepo1, err := OpenRepositoryLocal(t.Context(), bareRepo1Path)
assert.NoError(t, err)
defer bareRepo1.Close()
// these test case are specific to the repo1_bare test repo
testCases := []struct {
CommitID string
ExpectedBranches []string
func TestRepository_CommitQueries(t *testing.T) {
for _, testCase := range []struct {
name string
run func(*testing.T, *Repository)
}{
{"2839944139e0de9737a044f78b0e4b40d989a9e3", []string{"branch1"}},
{"5c80b0245c1c6f8343fa418ec374b13b5d4ee658", []string{"branch2"}},
{"37991dec2c8e592043f47155ce4808d4580f9123", []string{"master"}},
{"95bb4d39648ee7e325106df01a621c530863a653", []string{"branch1", "branch2"}},
{"8d92fc957a4d7cfd98bc375f0b7bb189a0d6c9f2", []string{"branch2", "master"}},
{"master", []string{"master"}},
{"TestRepository_GetCommitBranches", func(t *testing.T, bareRepo1 *Repository) {
// these test case are specific to the repo1_bare test repo
testCases := []struct {
CommitID string
ExpectedBranches []string
}{
{"2839944139e0de9737a044f78b0e4b40d989a9e3", []string{"branch1"}},
{"5c80b0245c1c6f8343fa418ec374b13b5d4ee658", []string{"branch2"}},
{"37991dec2c8e592043f47155ce4808d4580f9123", []string{"master"}},
{"95bb4d39648ee7e325106df01a621c530863a653", []string{"branch1", "branch2"}},
{"8d92fc957a4d7cfd98bc375f0b7bb189a0d6c9f2", []string{"branch2", "master"}},
{"master", []string{"master"}},
}
for _, testCase := range testCases {
commit, err := bareRepo1.GetCommit(t.Context(), testCase.CommitID)
assert.NoError(t, err)
branches, err := bareRepo1.getBranches(t.Context(), nil, commit.ID.String(), 2)
assert.NoError(t, err)
assert.Equal(t, testCase.ExpectedBranches, branches)
}
}},
{"TestGetTagCommitWithSignature", func(t *testing.T, bareRepo1 *Repository) {
// both the tag and the commit are signed here, this validates only the commit signature
commit, err := bareRepo1.GetCommit(t.Context(), "28b55526e7100924d864dd89e35c1ea62e7a5a32")
assert.NoError(t, err)
assert.NotNil(t, commit)
assert.NotNil(t, commit.Signature)
// test that signature is not in message
assert.Equal(t, "signed-commit\n", commit.CommitMessage.MessageRaw)
}},
{"TestGetCommitWithBadCommitID", func(t *testing.T, bareRepo1 *Repository) {
commit, err := bareRepo1.GetCommit(t.Context(), "bad_branch")
assert.Nil(t, commit)
assert.Error(t, err)
assert.True(t, IsErrNotExist(err))
}},
{"TestIsCommitInRepo", func(t *testing.T, bareRepo1 *Repository) {
exist, err := IsCommitInRepo(t.Context(), bareRepo1, "2839944139e0de9737a044f78b0e4b40d989a9e3")
assert.NoError(t, err)
assert.True(t, exist)
exist, err = IsCommitInRepo(t.Context(), bareRepo1, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")
assert.NoError(t, err)
assert.False(t, exist)
}},
{"TestIsCommitInBranch", func(t *testing.T, bareRepo1 *Repository) {
result, err := IsCommitInBranch(t.Context(), bareRepo1, "2839944139e0de9737a044f78b0e4b40d989a9e3", "branch1")
assert.NoError(t, err)
assert.True(t, result)
result, err = IsCommitInBranch(t.Context(), bareRepo1, "2839944139e0de9737a044f78b0e4b40d989a9e3", "branch2")
assert.NoError(t, err)
assert.False(t, result)
result, err = IsCommitInBranch(t.Context(), bareRepo1, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "branch1")
assert.NoError(t, err)
assert.False(t, result)
}},
{"TestGetRefCommitID", func(t *testing.T, bareRepo1 *Repository) {
// these test case are specific to the repo1_bare test repo
testCases := []struct {
Ref string
ExpectedCommitID string
}{
{RefNameFromBranch("master").String(), "ce064814f4a0d337b333e646ece456cd39fab612"},
{RefNameFromBranch("branch1").String(), "2839944139e0de9737a044f78b0e4b40d989a9e3"},
{RefNameFromTag("test").String(), "3ad28a9149a2864384548f3d17ed7f38014c9e8a"},
{"ce064814f4a0d337b333e646ece456cd39fab612", "ce064814f4a0d337b333e646ece456cd39fab612"},
}
for _, testCase := range testCases {
commitID, err := bareRepo1.GetRefCommitID(t.Context(), testCase.Ref)
if assert.NoError(t, err) {
assert.Equal(t, testCase.ExpectedCommitID, commitID)
}
}
}},
} {
t.Run(testCase.name, func(t *testing.T) {
bareRepo1, err := OpenRepositoryLocal(t.Context(), filepath.Join(testReposDir, "repo1_bare"))
assert.NoError(t, err)
defer bareRepo1.Close()
testCase.run(t, bareRepo1)
})
}
for _, testCase := range testCases {
commit, err := bareRepo1.GetCommit(t.Context(), testCase.CommitID)
assert.NoError(t, err)
branches, err := bareRepo1.getBranches(t.Context(), nil, commit.ID.String(), 2)
assert.NoError(t, err)
assert.Equal(t, testCase.ExpectedBranches, branches)
}
}
func TestGetTagCommitWithSignature(t *testing.T) {
bareRepo1Path := filepath.Join(testReposDir, "repo1_bare")
bareRepo1, err := OpenRepositoryLocal(t.Context(), bareRepo1Path)
assert.NoError(t, err)
defer bareRepo1.Close()
// both the tag and the commit are signed here, this validates only the commit signature
commit, err := bareRepo1.GetCommit(t.Context(), "28b55526e7100924d864dd89e35c1ea62e7a5a32")
assert.NoError(t, err)
assert.NotNil(t, commit)
assert.NotNil(t, commit.Signature)
// test that signature is not in message
assert.Equal(t, "signed-commit\n", commit.CommitMessage.MessageRaw)
}
func TestGetCommitWithBadCommitID(t *testing.T) {
bareRepo1Path := filepath.Join(testReposDir, "repo1_bare")
bareRepo1, err := OpenRepositoryLocal(t.Context(), bareRepo1Path)
assert.NoError(t, err)
defer bareRepo1.Close()
commit, err := bareRepo1.GetCommit(t.Context(), "bad_branch")
assert.Nil(t, commit)
assert.Error(t, err)
assert.True(t, IsErrNotExist(err))
}
func TestIsCommitInRepo(t *testing.T) {
bareRepo1, err := OpenRepositoryLocal(t.Context(), filepath.Join(testReposDir, "repo1_bare"))
assert.NoError(t, err)
defer bareRepo1.Close()
exist, err := IsCommitInRepo(t.Context(), bareRepo1, "2839944139e0de9737a044f78b0e4b40d989a9e3")
assert.NoError(t, err)
assert.True(t, exist)
exist, err = IsCommitInRepo(t.Context(), bareRepo1, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")
assert.NoError(t, err)
assert.False(t, exist)
}
func TestIsCommitInBranch(t *testing.T) {
bareRepo1Path := filepath.Join(testReposDir, "repo1_bare")
bareRepo1, err := OpenRepositoryLocal(t.Context(), bareRepo1Path)
assert.NoError(t, err)
defer bareRepo1.Close()
result, err := IsCommitInBranch(t.Context(), bareRepo1, "2839944139e0de9737a044f78b0e4b40d989a9e3", "branch1")
assert.NoError(t, err)
assert.True(t, result)
result, err = IsCommitInBranch(t.Context(), bareRepo1, "2839944139e0de9737a044f78b0e4b40d989a9e3", "branch2")
assert.NoError(t, err)
assert.False(t, result)
result, err = IsCommitInBranch(t.Context(), bareRepo1, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "branch1")
assert.NoError(t, err)
assert.False(t, result)
}
func TestRepository_CommitsBetween(t *testing.T) {
@@ -125,31 +130,6 @@ func TestRepository_CommitsBetween(t *testing.T) {
}
}
func TestGetRefCommitID(t *testing.T) {
bareRepo1Path := filepath.Join(testReposDir, "repo1_bare")
bareRepo1, err := OpenRepositoryLocal(t.Context(), bareRepo1Path)
assert.NoError(t, err)
defer bareRepo1.Close()
// these test case are specific to the repo1_bare test repo
testCases := []struct {
Ref string
ExpectedCommitID string
}{
{RefNameFromBranch("master").String(), "ce064814f4a0d337b333e646ece456cd39fab612"},
{RefNameFromBranch("branch1").String(), "2839944139e0de9737a044f78b0e4b40d989a9e3"},
{RefNameFromTag("test").String(), "3ad28a9149a2864384548f3d17ed7f38014c9e8a"},
{"ce064814f4a0d337b333e646ece456cd39fab612", "ce064814f4a0d337b333e646ece456cd39fab612"},
}
for _, testCase := range testCases {
commitID, err := bareRepo1.GetRefCommitID(t.Context(), testCase.Ref)
if assert.NoError(t, err) {
assert.Equal(t, testCase.ExpectedCommitID, commitID)
}
}
}
func TestCommitsByFileAndRange(t *testing.T) {
defer test.MockVariableValue(&setting.Git.CommitsRangeSize, 2)()
+19 -48
View File
@@ -185,6 +185,22 @@ func TestRepository_GetAnnotatedTag(t *testing.T) {
}
func TestRepository_parseTagRef(t *testing.T) {
signature := `-----BEGIN PGP SIGNATURE-----
aBCGzBAABCgAdFiEEyWRwv/q1Q6IjSv+D4IPOwzt33PoFAmI8jbIACgkQ4IPOwzt3
3PoRuAv9FVSbPBXvzECubls9KQd7urwEvcfG20Uf79iBwifQJUv+egNQojrs6APT
T4CdIXeGRpwJZaGTUX9RWnoDO1SLXAWnc82CypWraNwrHq8Go2YeoVu0Iy3vb0EU
REdob/tXYZecMuP8AjhUR0XfdYaERYAvJ2dYsH/UkFrqDjM3V4kPXWG+R5DCaZiE
slB5U01i4Dwb/zm/ckzhUGEcOgcnpOKX8SnY5kYRVDY47dl/yJZ1u2XWir3mu60G
1geIitH7StBddHi/8rz+sJwTfcVaLjn2p59p/Dr9aGbk17GIaKq1j0pZA2lKT0Xt
f9jDqU+9vCxnKgjSDhrwN69LF2jT47ZFjEMGV/wFPOa1EBxVWpgQ/CfEolBlbUqx
yVpbxi/6AOK2lmG130e9jEZJcu+WeZUeq851WgKSEkf2d5f/JpwtSTEOlOedu6V6
kl845zu5oE2nKM4zMQ7XrYQn538I31ps+VGQ0H8R07WrZP8WKUWugL2cU8KmXFwg
qbHDASXl
=2yGi
-----END PGP SIGNATURE-----
`
tests := []struct {
name string
@@ -273,38 +289,8 @@ func TestRepository_parseTagRef(t *testing.T) {
* add changelog of v1.9.1
* Update CHANGELOG.md
-----BEGIN PGP SIGNATURE-----
aBCGzBAABCgAdFiEEyWRwv/q1Q6IjSv+D4IPOwzt33PoFAmI8jbIACgkQ4IPOwzt3
3PoRuAv9FVSbPBXvzECubls9KQd7urwEvcfG20Uf79iBwifQJUv+egNQojrs6APT
T4CdIXeGRpwJZaGTUX9RWnoDO1SLXAWnc82CypWraNwrHq8Go2YeoVu0Iy3vb0EU
REdob/tXYZecMuP8AjhUR0XfdYaERYAvJ2dYsH/UkFrqDjM3V4kPXWG+R5DCaZiE
slB5U01i4Dwb/zm/ckzhUGEcOgcnpOKX8SnY5kYRVDY47dl/yJZ1u2XWir3mu60G
1geIitH7StBddHi/8rz+sJwTfcVaLjn2p59p/Dr9aGbk17GIaKq1j0pZA2lKT0Xt
f9jDqU+9vCxnKgjSDhrwN69LF2jT47ZFjEMGV/wFPOa1EBxVWpgQ/CfEolBlbUqx
yVpbxi/6AOK2lmG130e9jEZJcu+WeZUeq851WgKSEkf2d5f/JpwtSTEOlOedu6V6
kl845zu5oE2nKM4zMQ7XrYQn538I31ps+VGQ0H8R07WrZP8WKUWugL2cU8KmXFwg
qbHDASXl
=2yGi
-----END PGP SIGNATURE-----
`,
"contents:signature": `-----BEGIN PGP SIGNATURE-----
aBCGzBAABCgAdFiEEyWRwv/q1Q6IjSv+D4IPOwzt33PoFAmI8jbIACgkQ4IPOwzt3
3PoRuAv9FVSbPBXvzECubls9KQd7urwEvcfG20Uf79iBwifQJUv+egNQojrs6APT
T4CdIXeGRpwJZaGTUX9RWnoDO1SLXAWnc82CypWraNwrHq8Go2YeoVu0Iy3vb0EU
REdob/tXYZecMuP8AjhUR0XfdYaERYAvJ2dYsH/UkFrqDjM3V4kPXWG+R5DCaZiE
slB5U01i4Dwb/zm/ckzhUGEcOgcnpOKX8SnY5kYRVDY47dl/yJZ1u2XWir3mu60G
1geIitH7StBddHi/8rz+sJwTfcVaLjn2p59p/Dr9aGbk17GIaKq1j0pZA2lKT0Xt
f9jDqU+9vCxnKgjSDhrwN69LF2jT47ZFjEMGV/wFPOa1EBxVWpgQ/CfEolBlbUqx
yVpbxi/6AOK2lmG130e9jEZJcu+WeZUeq851WgKSEkf2d5f/JpwtSTEOlOedu6V6
kl845zu5oE2nKM4zMQ7XrYQn538I31ps+VGQ0H8R07WrZP8WKUWugL2cU8KmXFwg
qbHDASXl
=2yGi
-----END PGP SIGNATURE-----
`,
` + signature,
"contents:signature": signature,
},
want: &Tag{
@@ -315,22 +301,7 @@ qbHDASXl
Tagger: parseSignatureFromCommitLine("Foo Bar <foo@bar.com> 1565789218 +0300"),
CommitMessage: CommitMessage{MessageRaw: "Add changelog of v1.9.1 (#7859)\n\n* add changelog of v1.9.1\n* Update CHANGELOG.md\n"},
Signature: &CommitSignature{
Signature: `-----BEGIN PGP SIGNATURE-----
aBCGzBAABCgAdFiEEyWRwv/q1Q6IjSv+D4IPOwzt33PoFAmI8jbIACgkQ4IPOwzt3
3PoRuAv9FVSbPBXvzECubls9KQd7urwEvcfG20Uf79iBwifQJUv+egNQojrs6APT
T4CdIXeGRpwJZaGTUX9RWnoDO1SLXAWnc82CypWraNwrHq8Go2YeoVu0Iy3vb0EU
REdob/tXYZecMuP8AjhUR0XfdYaERYAvJ2dYsH/UkFrqDjM3V4kPXWG+R5DCaZiE
slB5U01i4Dwb/zm/ckzhUGEcOgcnpOKX8SnY5kYRVDY47dl/yJZ1u2XWir3mu60G
1geIitH7StBddHi/8rz+sJwTfcVaLjn2p59p/Dr9aGbk17GIaKq1j0pZA2lKT0Xt
f9jDqU+9vCxnKgjSDhrwN69LF2jT47ZFjEMGV/wFPOa1EBxVWpgQ/CfEolBlbUqx
yVpbxi/6AOK2lmG130e9jEZJcu+WeZUeq851WgKSEkf2d5f/JpwtSTEOlOedu6V6
kl845zu5oE2nKM4zMQ7XrYQn538I31ps+VGQ0H8R07WrZP8WKUWugL2cU8KmXFwg
qbHDASXl
=2yGi
-----END PGP SIGNATURE-----
`,
Signature: signature,
Payload: `object 3325fd8a973321fd59455492976c042dde3fd1ca
type commit
tag v0.0.1
+13 -32
View File
@@ -11,37 +11,18 @@ import (
)
func TestParseSignatureFromCommitLine(t *testing.T) {
tests := []struct {
line string
want *Signature
}{
{
line: "a b <c@d.com> 12345 +0100",
want: &Signature{
Name: "a b",
Email: "c@d.com",
When: time.Unix(12345, 0).In(time.FixedZone("", 3600)),
},
},
{
line: "bad line",
want: &Signature{Name: "bad line"},
},
{
line: "bad < line",
want: &Signature{Name: "bad < line"},
},
{
line: "bad > line",
want: &Signature{Name: "bad > line"},
},
{
line: "bad-line <name@example.com>",
want: &Signature{Name: "bad-line <name@example.com>"},
},
}
for _, test := range tests {
got := parseSignatureFromCommitLine(test.line)
assert.Equal(t, test.want, got)
assert.Equal(t, &Signature{
Name: "a b",
Email: "c@d.com",
When: time.Unix(12345, 0).In(time.FixedZone("", 3600)),
}, parseSignatureFromCommitLine("a b <c@d.com> 12345 +0100"))
for _, line := range []string{
"bad line",
"bad < line",
"bad > line",
"bad-line <name@example.com>",
} {
assert.Equal(t, &Signature{Name: line}, parseSignatureFromCommitLine(line))
}
}
+15 -25
View File
@@ -46,32 +46,22 @@ func TestFollowLink(t *testing.T) {
assert.Nil(t, res)
}
{
// should error for broken links
entry, err := commit.Tree().GetTreeEntryByPath(t.Context(), r, "foo/broken_link")
for _, test := range []struct {
fullPath string
symlinkContent string
checkLink bool
}{
{"foo/broken_link", "nar/broken_link", true}, // should error for broken links
{"foo/outside_repo", "../../outside_repo", true}, // should error for external links
{"foo/link_short", "a", false}, // testing fix for short link bug
} {
entry, err := commit.Tree().GetTreeEntryByPath(t.Context(), r, test.fullPath)
require.NoError(t, err)
assert.True(t, entry.IsLink())
res, err := EntryFollowLink(t.Context(), r, commit, "foo/broken_link", entry)
if test.checkLink {
assert.True(t, entry.IsLink())
}
res, err := EntryFollowLink(t.Context(), r, commit, test.fullPath, entry)
assert.ErrorIs(t, err, util.ErrNotExist)
assert.Equal(t, "nar/broken_link", res.SymlinkContent)
}
{
// should error for external links
entry, err := commit.Tree().GetTreeEntryByPath(t.Context(), r, "foo/outside_repo")
require.NoError(t, err)
assert.True(t, entry.IsLink())
res, err := EntryFollowLink(t.Context(), r, commit, "foo/outside_repo", entry)
assert.ErrorIs(t, err, util.ErrNotExist)
assert.Equal(t, "../../outside_repo", res.SymlinkContent)
}
{
// testing fix for short link bug
entry, err := commit.Tree().GetTreeEntryByPath(t.Context(), r, "foo/link_short")
require.NoError(t, err)
res, err := EntryFollowLink(t.Context(), r, commit, "foo/link_short", entry)
assert.ErrorIs(t, err, util.ErrNotExist)
assert.Equal(t, "a", res.SymlinkContent)
assert.Equal(t, test.symlinkContent, res.SymlinkContent)
}
}
+41 -169
View File
@@ -17,156 +17,37 @@ import (
)
func TestParseGitURLs(t *testing.T) {
kases := []struct {
kase string
expected *GitURL
for _, kase := range []struct {
kase, scheme, host, path string
user *url.Userinfo
extraMark int
}{
{
kase: "git@127.0.0.1:go-gitea/gitea.git",
expected: &GitURL{
URL: &url.URL{
Scheme: "ssh",
User: url.User("git"),
Host: "127.0.0.1",
Path: "go-gitea/gitea.git",
},
extraMark: 1,
},
},
{
kase: "git@[fe80::14fc:cec5:c174:d88%2510]:go-gitea/gitea.git",
expected: &GitURL{
URL: &url.URL{
Scheme: "ssh",
User: url.User("git"),
Host: "[fe80::14fc:cec5:c174:d88%10]",
Path: "go-gitea/gitea.git",
},
extraMark: 1,
},
},
{
kase: "git@[::1]:go-gitea/gitea.git",
expected: &GitURL{
URL: &url.URL{
Scheme: "ssh",
User: url.User("git"),
Host: "[::1]",
Path: "go-gitea/gitea.git",
},
extraMark: 1,
},
},
{
kase: "git@github.com:go-gitea/gitea.git",
expected: &GitURL{
URL: &url.URL{
Scheme: "ssh",
User: url.User("git"),
Host: "github.com",
Path: "go-gitea/gitea.git",
},
extraMark: 1,
},
},
{
kase: "ssh://git@github.com/go-gitea/gitea.git",
expected: &GitURL{
URL: &url.URL{
Scheme: "ssh",
User: url.User("git"),
Host: "github.com",
Path: "/go-gitea/gitea.git",
},
extraMark: 0,
},
},
{
kase: "ssh://git@[::1]/go-gitea/gitea.git",
expected: &GitURL{
URL: &url.URL{
Scheme: "ssh",
User: url.User("git"),
Host: "[::1]",
Path: "/go-gitea/gitea.git",
},
extraMark: 0,
},
},
{
kase: "/repositories/go-gitea/gitea.git",
expected: &GitURL{
URL: &url.URL{
Scheme: "file",
Path: "/repositories/go-gitea/gitea.git",
},
extraMark: 2,
},
},
{
kase: "file:///repositories/go-gitea/gitea.git",
expected: &GitURL{
URL: &url.URL{
Scheme: "file",
Path: "/repositories/go-gitea/gitea.git",
},
extraMark: 0,
},
},
{
kase: "https://github.com/go-gitea/gitea.git",
expected: &GitURL{
URL: &url.URL{
Scheme: "https",
Host: "github.com",
Path: "/go-gitea/gitea.git",
},
extraMark: 0,
},
},
{
kase: "https://git:git@github.com/go-gitea/gitea.git",
expected: &GitURL{
URL: &url.URL{
Scheme: "https",
Host: "github.com",
User: url.UserPassword("git", "git"),
Path: "/go-gitea/gitea.git",
},
extraMark: 0,
},
},
{
kase: "https://[fe80::14fc:cec5:c174:d88%2510]:20/go-gitea/gitea.git",
expected: &GitURL{
URL: &url.URL{
Scheme: "https",
Host: "[fe80::14fc:cec5:c174:d88%10]:20",
Path: "/go-gitea/gitea.git",
},
extraMark: 0,
},
},
{
kase: "git://github.com/go-gitea/gitea.git",
expected: &GitURL{
URL: &url.URL{
Scheme: "git",
Host: "github.com",
Path: "/go-gitea/gitea.git",
},
extraMark: 0,
},
},
}
for _, kase := range kases {
{"git@127.0.0.1:go-gitea/gitea.git", "ssh", "127.0.0.1", "go-gitea/gitea.git", url.User("git"), 1},
{"git@[fe80::14fc:cec5:c174:d88%2510]:go-gitea/gitea.git", "ssh", "[fe80::14fc:cec5:c174:d88%10]", "go-gitea/gitea.git", url.User("git"), 1},
{"git@[::1]:go-gitea/gitea.git", "ssh", "[::1]", "go-gitea/gitea.git", url.User("git"), 1},
{"git@github.com:go-gitea/gitea.git", "ssh", "github.com", "go-gitea/gitea.git", url.User("git"), 1},
{"ssh://git@github.com/go-gitea/gitea.git", "ssh", "github.com", "/go-gitea/gitea.git", url.User("git"), 0},
{"ssh://git@[::1]/go-gitea/gitea.git", "ssh", "[::1]", "/go-gitea/gitea.git", url.User("git"), 0},
{"/repositories/go-gitea/gitea.git", "file", "", "/repositories/go-gitea/gitea.git", nil, 2},
{"file:///repositories/go-gitea/gitea.git", "file", "", "/repositories/go-gitea/gitea.git", nil, 0},
{"https://github.com/go-gitea/gitea.git", "https", "github.com", "/go-gitea/gitea.git", nil, 0},
{"https://git:git@github.com/go-gitea/gitea.git", "https", "github.com", "/go-gitea/gitea.git", url.UserPassword("git", "git"), 0},
{"https://[fe80::14fc:cec5:c174:d88%2510]:20/go-gitea/gitea.git", "https", "[fe80::14fc:cec5:c174:d88%10]:20", "/go-gitea/gitea.git", nil, 0},
{"git://github.com/go-gitea/gitea.git", "git", "github.com", "/go-gitea/gitea.git", nil, 0},
} {
t.Run(kase.kase, func(t *testing.T) {
u, err := ParseGitURL(kase.kase)
assert.NoError(t, err)
assert.Equal(t, kase.expected.extraMark, u.extraMark)
assert.Equal(t, *kase.expected, *u)
assert.Equal(t, kase.extraMark, u.extraMark)
assert.Equal(t, GitURL{
URL: &url.URL{
Scheme: kase.scheme,
User: kase.user,
Host: kase.host,
Path: kase.path,
},
extraMark: kase.extraMark,
}, *u)
})
}
}
@@ -251,27 +132,18 @@ func TestMakeRepositoryBaseLink(t *testing.T) {
defer test.MockVariableValue(&setting.AppURL, "https://localhost:3000/subpath")()
defer test.MockVariableValue(&setting.AppSubURL, "/subpath")()
u, err := ParseRepositoryURL(t.Context(), "https://localhost:3000/subpath/user/repo.git")
assert.NoError(t, err)
assert.Equal(t, "/subpath/user/repo", MakeRepositoryWebLink(u))
u, err = ParseRepositoryURL(t.Context(), "https://github.com/owner/repo.git")
assert.NoError(t, err)
assert.Equal(t, "https://github.com/owner/repo", MakeRepositoryWebLink(u))
u, err = ParseRepositoryURL(t.Context(), "git@github.com:owner/repo.git")
assert.NoError(t, err)
assert.Equal(t, "https://github.com/owner/repo", MakeRepositoryWebLink(u))
u, err = ParseRepositoryURL(t.Context(), "git+ssh://other:123/owner/repo.git")
assert.NoError(t, err)
assert.Equal(t, "https://other/owner/repo", MakeRepositoryWebLink(u))
u, err = ParseRepositoryURL(t.Context(), "git+ssh://[::1]/owner/repo.git")
assert.NoError(t, err)
assert.Equal(t, "https://[::1]/owner/repo", MakeRepositoryWebLink(u))
u, err = ParseRepositoryURL(t.Context(), "git+ssh://[::1]:2222/owner/repo.git")
assert.NoError(t, err)
assert.Equal(t, "https://[::1]/owner/repo", MakeRepositoryWebLink(u))
for _, kase := range []struct {
input, expected string
}{
{"https://localhost:3000/subpath/user/repo.git", "/subpath/user/repo"},
{"https://github.com/owner/repo.git", "https://github.com/owner/repo"},
{"git@github.com:owner/repo.git", "https://github.com/owner/repo"},
{"git+ssh://other:123/owner/repo.git", "https://other/owner/repo"},
{"git+ssh://[::1]/owner/repo.git", "https://[::1]/owner/repo"},
{"git+ssh://[::1]:2222/owner/repo.git", "https://[::1]/owner/repo"},
} {
u, err := ParseRepositoryURL(t.Context(), kase.input)
assert.NoError(t, err)
assert.Equal(t, kase.expected, MakeRepositoryWebLink(u))
}
}
+22 -59
View File
@@ -34,12 +34,14 @@ func TestFile(t *testing.T) {
name string
code string
want []template.HTML
plainWant []template.HTML
lexerName string
}{
{
name: "empty.py",
code: "",
want: lines(""),
plainWant: lines(""),
lexerName: "Python",
},
{
@@ -64,18 +66,21 @@ func TestFile(t *testing.T) {
name: "tags.py",
code: "<>",
want: lines(`<span class="o">&lt;&gt;</span>`),
plainWant: lines("&lt;&gt;"),
lexerName: "Python",
},
{
name: "eol-no.py",
code: "a=1",
want: lines(`<span class="n">a</span><span class="o">=</span><span class="mi">1</span>`),
plainWant: lines(`a=1`),
lexerName: "Python",
},
{
name: "eol-newline1.py",
code: "a=1\n",
want: lines(`<span class="n">a</span><span class="o">=</span><span class="mi">1</span>\n`),
plainWant: lines(`a=1\n`),
lexerName: "Python",
},
{
@@ -86,6 +91,10 @@ func TestFile(t *testing.T) {
\n
`,
),
plainWant: lines(`
a=1\n
\n
`),
lexerName: "Python",
},
{
@@ -106,6 +115,13 @@ c=2
\n
<span class="n">c</span><span class="o">=</span><span class="mi">2</span>`,
),
plainWant: lines(`
def:\n
a=1\n
\n
b=&#39;&#39;\n
\n
c=2`),
lexerName: "Python",
},
{
@@ -135,67 +151,14 @@ Content-Type: text/html
assert.Equal(t, tt.lexerName, lexerName)
})
}
}
func TestPlainText(t *testing.T) {
tests := []struct {
name string
code string
want []template.HTML
}{
{
name: "empty.py",
code: "",
want: lines(""),
},
{
name: "tags.py",
code: "<>",
want: lines("&lt;&gt;"),
},
{
name: "eol-no.py",
code: "a=1",
want: lines(`a=1`),
},
{
name: "eol-newline1.py",
code: "a=1\n",
want: lines(`a=1\n`),
},
{
name: "eol-newline2.py",
code: "a=1\n\n",
want: lines(`
a=1\n
\n
`),
},
{
name: "empty-line-with-space.py",
code: strings.ReplaceAll(strings.TrimSpace(`
def:
a=1
b=''
{space}
c=2
`), "{space}", " "),
want: lines(`
def:\n
a=1\n
\n
b=&#39;&#39;\n
\n
c=2`),
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
out := renderPlainText([]byte(tt.code))
assert.Equal(t, tt.want, out)
})
if tt.plainWant != nil {
t.Run("plaintext/"+tt.name, func(t *testing.T) {
out := renderPlainText([]byte(tt.code))
assert.Equal(t, tt.plainWant, out)
})
}
}
}
+6 -20
View File
@@ -25,76 +25,58 @@ func TestHandleGenericETagCache(t *testing.T) {
respEtag string
reqHeaders map[string]string
wantHandled bool
wantHeaders map[string]string
wantStatus int
}
cases := []testCase{
{
name: "No If-None-Match",
wantHandled: false,
wantHeaders: map[string]string{"Last-Modified": lastModified, "Cache-Control": cacheControl, "Etag": matchedEtag},
},
{
name: "Mismatched If-None-Match",
reqHeaders: map[string]string{"If-None-Match": `"mismatched-etag"`},
wantHandled: false,
wantHeaders: map[string]string{"Last-Modified": lastModified, "Cache-Control": cacheControl, "Etag": matchedEtag},
},
{
name: "Matched If-None-Match",
reqHeaders: map[string]string{"If-None-Match": matchedEtag},
wantHandled: true,
wantHeaders: map[string]string{"Last-Modified": lastModified, "Cache-Control": "", "Etag": matchedEtag},
wantStatus: http.StatusNotModified,
},
{
name: "Multiple Mismatched If-None-Match",
reqHeaders: map[string]string{"If-None-Match": `"mismatched-etag1", "mismatched-etag2"`},
wantHandled: false,
wantHeaders: map[string]string{"Last-Modified": lastModified, "Cache-Control": cacheControl, "Etag": matchedEtag},
},
{
name: "Wildcard If-None-Match matches any current representation",
reqHeaders: map[string]string{"If-None-Match": "*"},
wantHandled: true,
wantHeaders: map[string]string{"Last-Modified": lastModified, "Cache-Control": "", "Etag": matchedEtag},
wantStatus: http.StatusNotModified,
},
{
name: "Weak response tag matched by a strong request tag",
respEtag: weakEtag,
reqHeaders: map[string]string{"If-None-Match": matchedEtag},
wantHandled: true,
wantHeaders: map[string]string{"Last-Modified": lastModified, "Cache-Control": "", "Etag": weakEtag},
wantStatus: http.StatusNotModified,
},
{
name: "Weak response tag matched by a weak request tag",
respEtag: weakEtag,
reqHeaders: map[string]string{"If-None-Match": weakEtag},
wantHandled: true,
wantHeaders: map[string]string{"Last-Modified": lastModified, "Cache-Control": "", "Etag": weakEtag},
wantStatus: http.StatusNotModified,
},
{
name: "If-Modified-Since without If-None-Match",
reqHeaders: map[string]string{"If-Modified-Since": lastModified},
wantHandled: true,
wantHeaders: map[string]string{"Last-Modified": lastModified, "Cache-Control": "", "Etag": matchedEtag},
wantStatus: http.StatusNotModified,
},
{
name: "Mismatched If-None-Match takes precedence over If-Modified-Since",
reqHeaders: map[string]string{"If-None-Match": `"mismatched-etag"`, "If-Modified-Since": lastModified},
wantHandled: false,
wantHeaders: map[string]string{"Last-Modified": lastModified, "Cache-Control": cacheControl, "Etag": matchedEtag},
},
{
name: "Multiple Matched If-None-Match",
reqHeaders: map[string]string{"If-None-Match": `"mismatched-etag", ` + matchedEtag},
wantHandled: true,
wantHeaders: map[string]string{"Last-Modified": lastModified, "Cache-Control": "", "Etag": matchedEtag},
wantStatus: http.StatusNotModified,
},
}
@@ -107,10 +89,14 @@ func TestHandleGenericETagCache(t *testing.T) {
w := httptest.NewRecorder()
assert.Equal(t, tc.wantHandled, HandleGenericETagPrivateCache(req, w, util.IfZero(tc.respEtag, matchedEtag), lastModifiedTime))
resp := w.Result()
for k, v := range tc.wantHeaders {
for k, v := range map[string]string{
"Last-Modified": lastModified,
"Cache-Control": util.Iif(tc.wantHandled, "", cacheControl),
"Etag": util.IfZero(tc.respEtag, matchedEtag),
} {
assert.Equal(t, v, resp.Header.Get(k))
}
assert.Equal(t, tc.wantStatus, util.Iif(resp.StatusCode == http.StatusOK, 0, resp.StatusCode))
assert.Equal(t, util.Iif(tc.wantHandled, http.StatusNotModified, 0), util.Iif(resp.StatusCode == http.StatusOK, 0, resp.StatusCode))
})
}
}
+43 -87
View File
@@ -18,95 +18,51 @@ import (
"github.com/stretchr/testify/require"
)
func TestServeUserContentByReader(t *testing.T) {
func TestServeUserContent(t *testing.T) {
data := "0123456789abcdef"
test := func(t *testing.T, expectedStatusCode int, expectedContent string) {
_, rangeStr, _ := strings.Cut(t.Name(), "_range_")
r := &http.Request{Header: http.Header{}, Form: url.Values{}}
if rangeStr != "" {
r.Header.Set("Range", "bytes="+rangeStr)
}
reader := strings.NewReader(data)
w := httptest.NewRecorder()
ServeUserContentByReader(r, w, int64(len(data)), reader, ServeHeaderOptions{})
assert.Equal(t, expectedStatusCode, w.Code)
if expectedStatusCode == http.StatusPartialContent || expectedStatusCode == http.StatusOK {
assert.Equal(t, strconv.Itoa(len(expectedContent)), w.Header().Get("Content-Length"))
assert.Equal(t, expectedContent, w.Body.String())
}
for _, source := range []string{"reader", "file"} {
t.Run(source, func(t *testing.T) {
var tmpFile string
if source == "file" {
tmpFile = t.TempDir() + "/test"
assert.NoError(t, os.WriteFile(tmpFile, []byte(data), 0o644))
}
for _, tc := range []struct {
rangeStr string
expectedStatusCode int
expectedContent string
}{
{"", http.StatusOK, data},
{"0-", http.StatusPartialContent, data},
{"0-15", http.StatusPartialContent, data},
{"1-", http.StatusPartialContent, data[1:]},
{"1-3", http.StatusPartialContent, data[1 : 3+1]},
{"16-", http.StatusRequestedRangeNotSatisfiable, ""},
{"1-99999", http.StatusPartialContent, data[1:]},
} {
t.Run("_range_"+tc.rangeStr, func(t *testing.T) {
r := &http.Request{Header: http.Header{}, Form: url.Values{}}
if tc.rangeStr != "" {
r.Header.Set("Range", "bytes="+tc.rangeStr)
}
w := httptest.NewRecorder()
if source == "file" {
seekReader, err := os.OpenFile(tmpFile, os.O_RDONLY, 0o644)
require.NoError(t, err)
defer seekReader.Close()
ServeUserContentByFile(r, w, seekReader, ServeHeaderOptions{})
} else {
ServeUserContentByReader(r, w, int64(len(data)), strings.NewReader(data), ServeHeaderOptions{})
}
assert.Equal(t, tc.expectedStatusCode, w.Code)
if tc.expectedStatusCode == http.StatusPartialContent || tc.expectedStatusCode == http.StatusOK {
assert.Equal(t, strconv.Itoa(len(tc.expectedContent)), w.Header().Get("Content-Length"))
assert.Equal(t, tc.expectedContent, w.Body.String())
}
})
}
})
}
t.Run("_range_", func(t *testing.T) {
test(t, http.StatusOK, data)
})
t.Run("_range_0-", func(t *testing.T) {
test(t, http.StatusPartialContent, data)
})
t.Run("_range_0-15", func(t *testing.T) {
test(t, http.StatusPartialContent, data)
})
t.Run("_range_1-", func(t *testing.T) {
test(t, http.StatusPartialContent, data[1:])
})
t.Run("_range_1-3", func(t *testing.T) {
test(t, http.StatusPartialContent, data[1:3+1])
})
t.Run("_range_16-", func(t *testing.T) {
test(t, http.StatusRequestedRangeNotSatisfiable, "")
})
t.Run("_range_1-99999", func(t *testing.T) {
test(t, http.StatusPartialContent, data[1:])
})
}
func TestServeUserContentByFile(t *testing.T) {
data := "0123456789abcdef"
tmpFile := t.TempDir() + "/test"
err := os.WriteFile(tmpFile, []byte(data), 0o644)
assert.NoError(t, err)
test := func(t *testing.T, expectedStatusCode int, expectedContent string) {
_, rangeStr, _ := strings.Cut(t.Name(), "_range_")
r := &http.Request{Header: http.Header{}, Form: url.Values{}}
if rangeStr != "" {
r.Header.Set("Range", "bytes="+rangeStr)
}
seekReader, err := os.OpenFile(tmpFile, os.O_RDONLY, 0o644)
require.NoError(t, err)
defer seekReader.Close()
w := httptest.NewRecorder()
ServeUserContentByFile(r, w, seekReader, ServeHeaderOptions{})
assert.Equal(t, expectedStatusCode, w.Code)
if expectedStatusCode == http.StatusPartialContent || expectedStatusCode == http.StatusOK {
assert.Equal(t, strconv.Itoa(len(expectedContent)), w.Header().Get("Content-Length"))
assert.Equal(t, expectedContent, w.Body.String())
}
}
t.Run("_range_", func(t *testing.T) {
test(t, http.StatusOK, data)
})
t.Run("_range_0-", func(t *testing.T) {
test(t, http.StatusPartialContent, data)
})
t.Run("_range_0-15", func(t *testing.T) {
test(t, http.StatusPartialContent, data)
})
t.Run("_range_1-", func(t *testing.T) {
test(t, http.StatusPartialContent, data[1:])
})
t.Run("_range_1-3", func(t *testing.T) {
test(t, http.StatusPartialContent, data[1:3+1])
})
t.Run("_range_16-", func(t *testing.T) {
test(t, http.StatusRequestedRangeNotSatisfiable, "")
})
t.Run("_range_1-99999", func(t *testing.T) {
test(t, http.StatusPartialContent, data[1:])
})
}
func TestServeSetHeaderContentRelated(t *testing.T) {
+55 -82
View File
@@ -21,99 +21,72 @@ func TestBleveIndexer(t *testing.T) {
tests.TestIndexer(t, indexer)
}
func TestBleveIndexerNoAssignee(t *testing.T) {
dir := t.TempDir()
indexer := NewIndexer(dir)
defer indexer.Close()
_, err := indexer.Init(t.Context())
require.NoError(t, err)
require.NoError(t, indexer.Index(t.Context(),
&internal.IndexerData{ID: 1, Title: "assigned through assignee_ids", AssigneeIDs: []int64{2}},
&internal.IndexerData{ID: 2, Title: "unassigned", NoAssignee: true},
&internal.IndexerData{ID: 3, Title: "assigned through multiple assignee_ids", AssigneeIDs: []int64{3, 4}},
))
testCases := []struct {
func TestBleveIndexerSearch(t *testing.T) {
type searchCase struct {
name string
opts *internal.SearchOptions
expectedIDs []int64
}
for _, testCase := range []struct {
name string
data []*internal.IndexerData
searches []searchCase
checkTotal bool
}{
{
name: "none",
opts: &internal.SearchOptions{AssigneeID: "(none)"},
expectedIDs: []int64{2},
name: "no assignee",
data: []*internal.IndexerData{
{ID: 1, Title: "assigned through assignee_ids", AssigneeIDs: []int64{2}},
{ID: 2, Title: "unassigned", NoAssignee: true},
{ID: 3, Title: "assigned through multiple assignee_ids", AssigneeIDs: []int64{3, 4}},
},
searches: []searchCase{
{"none", &internal.SearchOptions{AssigneeID: "(none)"}, []int64{2}},
{"any", &internal.SearchOptions{AssigneeID: "(any)"}, []int64{1, 3}},
{"specific", &internal.SearchOptions{AssigneeID: "2"}, []int64{1}},
{"specific first multi-assignee", &internal.SearchOptions{AssigneeID: "3"}, []int64{3}},
{"specific second multi-assignee", &internal.SearchOptions{AssigneeID: "4"}, []int64{3}},
},
checkTotal: true,
},
{
name: "any",
opts: &internal.SearchOptions{AssigneeID: "(any)"},
expectedIDs: []int64{1, 3},
name: "token filter",
data: []*internal.IndexerData{
{ID: 1, Title: "fix(packages): SomeThing needs a rewrite (#12345)"},
{ID: 2, Title: "add support for mDNS discovery abc1234"},
},
searches: []searchCase{
{"exact original case", &internal.SearchOptions{Keyword: "SomeThing"}, []int64{1}},
{"case matching original transitions", &internal.SearchOptions{Keyword: "someThing"}, []int64{1}},
{"all lower case", &internal.SearchOptions{Keyword: "something"}, []int64{1}},
{"all upper case", &internal.SearchOptions{Keyword: "SOMETHING"}, []int64{1}},
{"number match", &internal.SearchOptions{Keyword: "12345"}, []int64{1}},
{"number as part", &internal.SearchOptions{Keyword: "1234"}, []int64{2}},
{"sub-word search still works", &internal.SearchOptions{Keyword: "DNS"}, []int64{2}},
{"sub-word search, lower case", &internal.SearchOptions{Keyword: "mdns"}, []int64{2}},
{"keyword is camel case", &internal.SearchOptions{Keyword: "addSupport"}, []int64{2}},
{"keyword not match", &internal.SearchOptions{Keyword: "addsupport"}, []int64{}},
},
},
{
name: "specific",
opts: &internal.SearchOptions{AssigneeID: "2"},
expectedIDs: []int64{1},
},
{
name: "specific first multi-assignee",
opts: &internal.SearchOptions{AssigneeID: "3"},
expectedIDs: []int64{3},
},
{
name: "specific second multi-assignee",
opts: &internal.SearchOptions{AssigneeID: "4"},
expectedIDs: []int64{3},
},
}
for _, testCase := range testCases {
} {
t.Run(testCase.name, func(t *testing.T) {
result, err := indexer.Search(t.Context(), testCase.opts)
indexer := NewIndexer(t.TempDir())
defer indexer.Close()
_, err := indexer.Init(t.Context())
require.NoError(t, err)
assert.Equal(t, int64(len(testCase.expectedIDs)), result.Total)
assert.ElementsMatch(t, testCase.expectedIDs, searchResultIDs(result))
})
}
}
require.NoError(t, indexer.Index(t.Context(), testCase.data...))
func TestBleveIndexerTokenFilter(t *testing.T) {
dir := t.TempDir()
indexer := NewIndexer(dir)
defer indexer.Close()
_, err := indexer.Init(t.Context())
require.NoError(t, err)
require.NoError(t, indexer.Index(t.Context(),
&internal.IndexerData{ID: 1, Title: "fix(packages): SomeThing needs a rewrite (#12345)"},
&internal.IndexerData{ID: 2, Title: "add support for mDNS discovery abc1234"},
))
testCases := []struct {
name string
keyword string
expectedIDs []int64
}{
{name: "exact original case", keyword: "SomeThing", expectedIDs: []int64{1}},
{name: "case matching original transitions", keyword: "someThing", expectedIDs: []int64{1}},
{name: "all lower case", keyword: "something", expectedIDs: []int64{1}},
{name: "all upper case", keyword: "SOMETHING", expectedIDs: []int64{1}},
{name: "number match", keyword: "12345", expectedIDs: []int64{1}},
{name: "number as part", keyword: "1234", expectedIDs: []int64{2}},
{name: "sub-word search still works", keyword: "DNS", expectedIDs: []int64{2}},
{name: "sub-word search, lower case", keyword: "mdns", expectedIDs: []int64{2}},
{name: "keyword is camel case", keyword: "addSupport", expectedIDs: []int64{2}},
{name: "keyword not match", keyword: "addsupport", expectedIDs: []int64{}},
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
result, err := indexer.Search(t.Context(), &internal.SearchOptions{
Keyword: testCase.keyword,
})
require.NoError(t, err)
assert.ElementsMatch(t, testCase.expectedIDs, searchResultIDs(result))
for _, search := range testCase.searches {
t.Run(search.name, func(t *testing.T) {
result, err := indexer.Search(t.Context(), search.opts)
require.NoError(t, err)
if testCase.checkTotal {
assert.Equal(t, int64(len(search.expectedIDs)), result.Total)
}
assert.ElementsMatch(t, search.expectedIDs, searchResultIDs(result))
})
}
})
}
}
@@ -89,6 +89,5 @@ func TestDoubleQuoteKeyword(t *testing.T) {
assert.Empty(t, doubleQuoteKeyword(""))
assert.Equal(t, `"a" "b" "c"`, doubleQuoteKeyword("a b c"))
assert.Equal(t, `"a" "d" "g"`, doubleQuoteKeyword("a d g"))
assert.Equal(t, `"a" "d" "g"`, doubleQuoteKeyword("a d g"))
assert.Equal(t, `"a" "d" "g"`, doubleQuoteKeyword(`a "" "d" """g`))
}
+59 -211
View File
@@ -15,6 +15,11 @@ import (
)
func TestValidate(t *testing.T) {
const metadata = `
name: "test"
about: "this is about"
body:
`
tests := []struct {
name string
filename string
@@ -44,21 +49,13 @@ about: "this is about"
},
{
name: "markdown miss value",
content: `
name: "test"
about: "this is about"
body:
- type: "markdown"
content: metadata + ` - type: "markdown"
`,
wantErr: "body[0](markdown): 'value' is required",
},
{
name: "markdown invalid value",
content: `
name: "test"
about: "this is about"
body:
- type: "markdown"
content: metadata + ` - type: "markdown"
attributes:
value: true
`,
@@ -66,11 +63,7 @@ body:
},
{
name: "markdown empty value",
content: `
name: "test"
about: "this is about"
body:
- type: "markdown"
content: metadata + ` - type: "markdown"
attributes:
value: ""
`,
@@ -78,33 +71,21 @@ body:
},
{
name: "textarea invalid id",
content: `
name: "test"
about: "this is about"
body:
- type: "textarea"
content: metadata + ` - type: "textarea"
id: "?"
`,
wantErr: "body[0](textarea): 'id' should contain only alphanumeric, '-' and '_'",
},
{
name: "textarea miss label",
content: `
name: "test"
about: "this is about"
body:
- type: "textarea"
content: metadata + ` - type: "textarea"
id: "1"
`,
wantErr: "body[0](textarea): 'label' is required",
},
{
name: "textarea conflict id",
content: `
name: "test"
about: "this is about"
body:
- type: "textarea"
content: metadata + ` - type: "textarea"
id: "1"
attributes:
label: "a"
@@ -117,11 +98,7 @@ body:
},
{
name: "textarea invalid description",
content: `
name: "test"
about: "this is about"
body:
- type: "textarea"
content: metadata + ` - type: "textarea"
id: "1"
attributes:
label: "a"
@@ -131,11 +108,7 @@ body:
},
{
name: "textarea invalid required",
content: `
name: "test"
about: "this is about"
body:
- type: "textarea"
content: metadata + ` - type: "textarea"
id: "1"
attributes:
label: "a"
@@ -146,11 +119,7 @@ body:
},
{
name: "input invalid description",
content: `
name: "test"
about: "this is about"
body:
- type: "input"
content: metadata + ` - type: "input"
id: "1"
attributes:
label: "a"
@@ -160,11 +129,7 @@ body:
},
{
name: "input invalid is_number",
content: `
name: "test"
about: "this is about"
body:
- type: "input"
content: metadata + ` - type: "input"
id: "1"
attributes:
label: "a"
@@ -175,11 +140,7 @@ body:
},
{
name: "input invalid regex",
content: `
name: "test"
about: "this is about"
body:
- type: "input"
content: metadata + ` - type: "input"
id: "1"
attributes:
label: "a"
@@ -190,11 +151,7 @@ body:
},
{
name: "dropdown invalid description",
content: `
name: "test"
about: "this is about"
body:
- type: "dropdown"
content: metadata + ` - type: "dropdown"
id: "1"
attributes:
label: "a"
@@ -204,11 +161,7 @@ body:
},
{
name: "dropdown invalid multiple",
content: `
name: "test"
about: "this is about"
body:
- type: "dropdown"
content: metadata + ` - type: "dropdown"
id: "1"
attributes:
label: "a"
@@ -218,11 +171,7 @@ body:
},
{
name: "dropdown invalid list",
content: `
name: "test"
about: "this is about"
body:
- type: "dropdown"
content: metadata + ` - type: "dropdown"
id: "1"
attributes:
label: "a"
@@ -232,11 +181,7 @@ body:
},
{
name: "checkboxes invalid description",
content: `
name: "test"
about: "this is about"
body:
- type: "checkboxes"
content: metadata + ` - type: "checkboxes"
id: "1"
attributes:
label: "a"
@@ -246,11 +191,7 @@ body:
},
{
name: "invalid type",
content: `
name: "test"
about: "this is about"
body:
- type: "video"
content: metadata + ` - type: "video"
id: "1"
attributes:
label: "a"
@@ -259,11 +200,7 @@ body:
},
{
name: "dropdown miss options",
content: `
name: "test"
about: "this is about"
body:
- type: "dropdown"
content: metadata + ` - type: "dropdown"
id: "1"
attributes:
label: "a"
@@ -272,11 +209,7 @@ body:
},
{
name: "dropdown invalid options",
content: `
name: "test"
about: "this is about"
body:
- type: "dropdown"
content: metadata + ` - type: "dropdown"
id: "1"
attributes:
label: "a"
@@ -288,11 +221,7 @@ body:
},
{
name: "checkboxes invalid options",
content: `
name: "test"
about: "this is about"
body:
- type: "checkboxes"
content: metadata + ` - type: "checkboxes"
id: "1"
attributes:
label: "a"
@@ -304,11 +233,7 @@ body:
},
{
name: "checkboxes option miss label",
content: `
name: "test"
about: "this is about"
body:
- type: "checkboxes"
content: metadata + ` - type: "checkboxes"
id: "1"
attributes:
label: "a"
@@ -319,11 +244,7 @@ body:
},
{
name: "checkboxes option invalid required",
content: `
name: "test"
about: "this is about"
body:
- type: "checkboxes"
content: metadata + ` - type: "checkboxes"
id: "1"
attributes:
label: "a"
@@ -335,11 +256,7 @@ body:
},
{
name: "field is required but hidden",
content: `
name: "test"
about: "this is about"
body:
- type: "input"
content: metadata + ` - type: "input"
id: "1"
attributes:
label: "a"
@@ -351,11 +268,7 @@ body:
},
{
name: "checkboxes is required but hidden",
content: `
name: "test"
about: "this is about"
body:
- type: checkboxes
content: metadata + ` - type: checkboxes
id: "1"
attributes:
label: Label of checkboxes
@@ -371,11 +284,7 @@ body:
},
{
name: "dropdown default is not an integer",
content: `
name: "test"
about: "this is about"
body:
- type: dropdown
content: metadata + ` - type: dropdown
id: "1"
attributes:
label: Label of dropdown
@@ -393,11 +302,7 @@ body:
},
{
name: "dropdown default is out of range",
content: `
name: "test"
about: "this is about"
body:
- type: dropdown
content: metadata + ` - type: dropdown
id: "1"
attributes:
label: Label of dropdown
@@ -415,11 +320,7 @@ body:
},
{
name: "dropdown without default is valid",
content: `
name: "test"
about: "this is about"
body:
- type: dropdown
content: metadata + ` - type: dropdown
id: "1"
attributes:
label: Label of dropdown
@@ -770,19 +671,8 @@ Content
}
func TestRenderToMarkdown(t *testing.T) {
type args struct {
template string
values url.Values
}
tests := []struct {
name string
args args
want string
}{
{
name: "normal",
args: args{
template: `
t.Run("normal", func(t *testing.T) {
template, err := Unmarshal("test.yaml", []byte(`
name: Name
title: Title
about: About
@@ -860,18 +750,11 @@ body:
visible: [form]
- label: Hidden Option of checkboxes
visible: [content]
`,
values: map[string][]string{
"form-field-id3": {"Value of id3"},
"form-field-id4": {"Value of id4"},
"form-field-id5": {"0,1"},
"form-field-id6": {"1,2"},
"form-field-id7-0": {"on"},
"form-field-id7-2": {"on"},
},
},
want: `Value of the markdown shown in created issue
`))
if err != nil {
t.Fatal(err)
}
want := `Value of the markdown shown in created issue
### Label of textarea
@@ -894,70 +777,35 @@ Option 1 of dropdown, Option 2 of dropdown
- [ ] Option 2 of checkboxes
- [ ] Hidden Option of checkboxes
`,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
template, err := Unmarshal("test.yaml", []byte(tt.args.template))
if err != nil {
t.Fatal(err)
}
if got := RenderToMarkdown(template, tt.args.values); got != tt.want {
assert.Equal(t, tt.want, got)
}
})
}
`
if got := RenderToMarkdown(template, url.Values{
"form-field-id3": {"Value of id3"},
"form-field-id4": {"Value of id4"},
"form-field-id5": {"0,1"},
"form-field-id6": {"1,2"},
"form-field-id7-0": {"on"},
"form-field-id7-2": {"on"},
}); got != want {
assert.Equal(t, want, got)
}
})
}
func Test_minQuotes(t *testing.T) {
type args struct {
value string
}
tests := []struct {
name string
args args
want string
name string
value string
want string
}{
{
name: "without quote",
args: args{
value: "Hello\nWorld",
},
want: "```",
},
{
name: "with 1 quote",
args: args{
value: "Hello\nWorld\n`text`\n",
},
want: "```",
},
{
name: "with 3 quotes",
args: args{
value: "Hello\nWorld\n`text`\n```go\ntext\n```\n",
},
want: "````",
},
{
name: "with more quotes",
args: args{
value: "Hello\nWorld\n`text`\n```go\ntext\n```\n``````````bash\ntext\n``````````\n",
},
want: "```````````",
},
{
name: "not leading quotes",
args: args{
value: "Hello\nWorld`text````go\ntext`````````````bash\ntext``````````\n",
},
want: "```",
},
{"without quote", "Hello\nWorld", "```"},
{"with 1 quote", "Hello\nWorld\n`text`\n", "```"},
{"with 3 quotes", "Hello\nWorld\n`text`\n```go\ntext\n```\n", "````"},
{"with more quotes", "Hello\nWorld\n`text`\n```go\ntext\n```\n``````````bash\ntext\n``````````\n", "```````````"},
{"not leading quotes", "Hello\nWorld`text````go\ntext`````````````bash\ntext``````````\n", "```"},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := minQuotes(tt.args.value)
got := minQuotes(tt.value)
assert.Equal(t, tt.want, got)
})
}
+94 -191
View File
@@ -162,209 +162,112 @@ func lfsTestRoundtripHandler(req *http.Request) *http.Response {
return &http.Response{StatusCode: http.StatusOK, Body: io.NopCloser(payload)}
}
func TestHTTPClientDownload(t *testing.T) {
p := Pointer{Oid: "fb8f7d8435968c4f82a726a92395be4d16f2f63116caf36c8ad35c60831ab041", Size: 6}
hc := &http.Client{Transport: RoundTripFunc(func(req *http.Request) *http.Response {
assert.Equal(t, "POST", req.Method)
assert.Equal(t, MediaType, req.Header.Get("Content-type"))
assert.Equal(t, AcceptHeader, req.Header.Get("Accept"))
var batchRequest BatchRequest
err := json.NewDecoder(req.Body).Decode(&batchRequest)
assert.NoError(t, err)
assert.Equal(t, "download", batchRequest.Operation)
assert.Equal(t, &Reference{Name: "refs/heads/main"}, batchRequest.Ref)
assert.Len(t, batchRequest.Objects, 1)
assert.Equal(t, p.Oid, batchRequest.Objects[0].Oid)
assert.Equal(t, p.Size, batchRequest.Objects[0].Size)
return lfsTestRoundtripHandler(req)
})}
dummy := &DummyTransferAdapter{}
cases := []struct {
func TestHTTPClientTransfers(t *testing.T) {
type clientCase struct {
endpoint string
expectedError string
}
for _, operation := range []struct {
name string
cases []clientCase
}{
{
endpoint: "https://status-not-ok.io",
expectedError: io.ErrUnexpectedEOF.Error(),
name: "download",
cases: []clientCase{
{"https://status-not-ok.io", io.ErrUnexpectedEOF.Error()},
{"https://invalid-json-response.io", "/(invalid json|invalid character)/"},
{"https://valid-batch-request-download.io", ""},
{"https://response-no-objects.io", ""},
{"https://unknown-transfer-adapter.io", "TransferAdapter not found: "},
{"https://error-in-response-objects.io", "Object not found"},
{"https://empty-actions-map.io", "missing action 'download'"},
{"https://download-actions-map.io", ""},
{"https://upload-actions-map.io", "missing action 'download'"},
{"https://verify-actions-map.io", "missing action 'download'"},
{"https://unknown-actions-map.io", "missing action 'download'"},
{"https://legacy-batch-request-download.io", ""},
},
},
{
endpoint: "https://invalid-json-response.io",
expectedError: "/(invalid json|invalid character)/",
name: "upload",
cases: []clientCase{
{"https://status-not-ok.io", io.ErrUnexpectedEOF.Error()},
{"https://invalid-json-response.io", "/(invalid json|invalid character)/"},
{"https://valid-batch-request-upload.io", ""},
{"https://response-no-objects.io", ""},
{"https://unknown-transfer-adapter.io", "TransferAdapter not found: "},
{"https://error-in-response-objects.io", "Object not found"},
{"https://empty-actions-map.io", ""},
{"https://download-actions-map.io", "missing action 'upload'"},
{"https://upload-actions-map.io", ""},
{"https://verify-actions-map.io", "missing action 'upload'"},
{"https://unknown-actions-map.io", "missing action 'upload'"},
},
},
{
endpoint: "https://valid-batch-request-download.io",
expectedError: "",
},
{
endpoint: "https://response-no-objects.io",
expectedError: "",
},
{
endpoint: "https://unknown-transfer-adapter.io",
expectedError: "TransferAdapter not found: ",
},
{
endpoint: "https://error-in-response-objects.io",
expectedError: "Object not found",
},
{
endpoint: "https://empty-actions-map.io",
expectedError: "missing action 'download'",
},
{
endpoint: "https://download-actions-map.io",
expectedError: "",
},
{
endpoint: "https://upload-actions-map.io",
expectedError: "missing action 'download'",
},
{
endpoint: "https://verify-actions-map.io",
expectedError: "missing action 'download'",
},
{
endpoint: "https://unknown-actions-map.io",
expectedError: "missing action 'download'",
},
{
endpoint: "https://legacy-batch-request-download.io",
expectedError: "",
},
}
} {
t.Run(operation.name, func(t *testing.T) {
p := Pointer{Oid: "fb8f7d8435968c4f82a726a92395be4d16f2f63116caf36c8ad35c60831ab041", Size: 6}
defer test.MockVariableValue(&setting.LFSClient.BatchOperationConcurrency, 8)()
for _, c := range cases {
t.Run(c.endpoint, func(t *testing.T) {
client := &HTTPClient{
client: hc,
endpoint: c.endpoint,
transfers: map[string]TransferAdapter{
"dummy": dummy,
},
}
hc := &http.Client{Transport: RoundTripFunc(func(req *http.Request) *http.Response {
assert.Equal(t, "POST", req.Method)
assert.Equal(t, MediaType, req.Header.Get("Content-type"))
assert.Equal(t, AcceptHeader, req.Header.Get("Accept"))
err := client.Download(t.Context(), "refs/heads/main", []Pointer{p}, func(p Pointer, content io.ReadCloser, objectError error) error {
if objectError != nil {
return objectError
}
b, err := io.ReadAll(content)
var batchRequest BatchRequest
err := json.NewDecoder(req.Body).Decode(&batchRequest)
assert.NoError(t, err)
assert.Equal(t, []byte("dummy"), b)
return nil
})
if c.expectedError != "" {
if strings.HasPrefix(c.expectedError, "/") && strings.HasSuffix(c.expectedError, "/") {
assert.Regexp(t, strings.Trim(c.expectedError, "/"), err.Error())
assert.Equal(t, operation.name, batchRequest.Operation)
if operation.name == "download" {
assert.Equal(t, &Reference{Name: "refs/heads/main"}, batchRequest.Ref)
} else {
assert.ErrorContains(t, err, c.expectedError)
assert.Nil(t, batchRequest.Ref)
}
} else {
assert.NoError(t, err)
}
})
}
}
func TestHTTPClientUpload(t *testing.T) {
p := Pointer{Oid: "fb8f7d8435968c4f82a726a92395be4d16f2f63116caf36c8ad35c60831ab041", Size: 6}
hc := &http.Client{Transport: RoundTripFunc(func(req *http.Request) *http.Response {
assert.Equal(t, "POST", req.Method)
assert.Equal(t, MediaType, req.Header.Get("Content-type"))
assert.Equal(t, AcceptHeader, req.Header.Get("Accept"))
var batchRequest BatchRequest
err := json.NewDecoder(req.Body).Decode(&batchRequest)
assert.NoError(t, err)
assert.Equal(t, "upload", batchRequest.Operation)
assert.Nil(t, batchRequest.Ref)
assert.Len(t, batchRequest.Objects, 1)
assert.Equal(t, p.Oid, batchRequest.Objects[0].Oid)
assert.Equal(t, p.Size, batchRequest.Objects[0].Size)
return lfsTestRoundtripHandler(req)
})}
dummy := &DummyTransferAdapter{}
cases := []struct {
endpoint string
expectedError string
}{
{
endpoint: "https://status-not-ok.io",
expectedError: io.ErrUnexpectedEOF.Error(),
},
{
endpoint: "https://invalid-json-response.io",
expectedError: "/(invalid json|invalid character)/",
},
{
endpoint: "https://valid-batch-request-upload.io",
expectedError: "",
},
{
endpoint: "https://response-no-objects.io",
expectedError: "",
},
{
endpoint: "https://unknown-transfer-adapter.io",
expectedError: "TransferAdapter not found: ",
},
{
endpoint: "https://error-in-response-objects.io",
expectedError: "Object not found",
},
{
endpoint: "https://empty-actions-map.io",
expectedError: "",
},
{
endpoint: "https://download-actions-map.io",
expectedError: "missing action 'upload'",
},
{
endpoint: "https://upload-actions-map.io",
expectedError: "",
},
{
endpoint: "https://verify-actions-map.io",
expectedError: "missing action 'upload'",
},
{
endpoint: "https://unknown-actions-map.io",
expectedError: "missing action 'upload'",
},
}
defer test.MockVariableValue(&setting.LFSClient.BatchOperationConcurrency, 8)()
for _, c := range cases {
t.Run(c.endpoint, func(t *testing.T) {
client := &HTTPClient{
client: hc,
endpoint: c.endpoint,
transfers: map[string]TransferAdapter{
"dummy": dummy,
},
}
err := client.Upload(t.Context(), []Pointer{p}, func(p Pointer, objectError error) (io.ReadCloser, error) {
return io.NopCloser(new(bytes.Buffer)), objectError
})
if c.expectedError != "" {
if strings.HasPrefix(c.expectedError, "/") && strings.HasSuffix(c.expectedError, "/") {
assert.Regexp(t, strings.Trim(c.expectedError, "/"), err.Error())
} else {
assert.ErrorContains(t, err, c.expectedError)
}
} else {
assert.NoError(t, err)
assert.Len(t, batchRequest.Objects, 1)
assert.Equal(t, p.Oid, batchRequest.Objects[0].Oid)
assert.Equal(t, p.Size, batchRequest.Objects[0].Size)
return lfsTestRoundtripHandler(req)
})}
dummy := &DummyTransferAdapter{}
defer test.MockVariableValue(&setting.LFSClient.BatchOperationConcurrency, 8)()
for _, testCase := range operation.cases {
t.Run(testCase.endpoint, func(t *testing.T) {
client := &HTTPClient{
client: hc,
endpoint: testCase.endpoint,
transfers: map[string]TransferAdapter{
"dummy": dummy,
},
}
var err error
if operation.name == "download" {
err = client.Download(t.Context(), "refs/heads/main", []Pointer{p}, func(p Pointer, content io.ReadCloser, objectError error) error {
if objectError != nil {
return objectError
}
b, err := io.ReadAll(content)
assert.NoError(t, err)
assert.Equal(t, []byte("dummy"), b)
return nil
})
} else {
err = client.Upload(t.Context(), []Pointer{p}, func(p Pointer, objectError error) (io.ReadCloser, error) {
return io.NopCloser(new(bytes.Buffer)), objectError
})
}
if testCase.expectedError != "" {
if strings.HasPrefix(testCase.expectedError, "/") && strings.HasSuffix(testCase.expectedError, "/") {
assert.Regexp(t, strings.Trim(testCase.expectedError, "/"), err.Error())
} else {
assert.ErrorContains(t, err, testCase.expectedError)
}
} else {
assert.NoError(t, err)
}
})
}
})
}
+16 -63
View File
@@ -69,7 +69,7 @@ func TestBasicTransferAdapter(t *testing.T) {
hc := &http.Client{Transport: RoundTripFunc(roundTripHandler)}
a := &BasicTransferAdapter{hc}
t.Run("Download", func(t *testing.T) {
testOperation := func(t *testing.T, endpoint string, transfer func(*Link) error) {
cases := []struct {
link *Link
expectederror string
@@ -77,7 +77,7 @@ func TestBasicTransferAdapter(t *testing.T) {
// case 0
{
link: &Link{
Href: "https://download-request.io",
Href: endpoint,
Header: map[string]string{"test-header": "test-value"},
},
expectederror: "",
@@ -93,46 +93,26 @@ func TestBasicTransferAdapter(t *testing.T) {
}
for n, c := range cases {
_, err := a.Download(t.Context(), c.link)
err := transfer(c.link)
if len(c.expectederror) > 0 {
assert.Contains(t, err.Error(), c.expectederror, "case %d: '%s' should contain '%s'", n, err.Error(), c.expectederror)
} else {
assert.NoError(t, err, "case %d", n)
}
}
}
t.Run("Download", func(t *testing.T) {
testOperation(t, "https://download-request.io", func(link *Link) error {
_, err := a.Download(t.Context(), link)
return err
})
})
t.Run("Upload", func(t *testing.T) {
cases := []struct {
link *Link
expectederror string
}{
// case 0
{
link: &Link{
Href: "https://upload-request.io",
Header: map[string]string{"test-header": "test-value"},
},
expectederror: "",
},
// case 1
{
link: &Link{
Href: "https://error-response.io",
Header: map[string]string{"test-header": "test-value"},
},
expectederror: "Object not found",
},
}
for n, c := range cases {
err := a.Upload(t.Context(), c.link, p, strings.NewReader("dummy"))
if len(c.expectederror) > 0 {
assert.Contains(t, err.Error(), c.expectederror, "case %d: '%s' should contain '%s'", n, err.Error(), c.expectederror)
} else {
assert.NoError(t, err, "case %d", n)
}
}
testOperation(t, "https://upload-request.io", func(link *Link) error {
return a.Upload(t.Context(), link, p, strings.NewReader("dummy"))
})
})
t.Run("Upload created", func(t *testing.T) {
@@ -145,35 +125,8 @@ func TestBasicTransferAdapter(t *testing.T) {
})
t.Run("Verify", func(t *testing.T) {
cases := []struct {
link *Link
expectederror string
}{
// case 0
{
link: &Link{
Href: "https://verify-request.io",
Header: map[string]string{"test-header": "test-value"},
},
expectederror: "",
},
// case 1
{
link: &Link{
Href: "https://error-response.io",
Header: map[string]string{"test-header": "test-value"},
},
expectederror: "Object not found",
},
}
for n, c := range cases {
err := a.Verify(t.Context(), c.link, p)
if len(c.expectederror) > 0 {
assert.Contains(t, err.Error(), c.expectederror, "case %d: '%s' should contain '%s'", n, err.Error(), c.expectederror)
} else {
assert.NoError(t, err, "case %d", n)
}
}
testOperation(t, "https://verify-request.io", func(link *Link) error {
return a.Verify(t.Context(), link, p)
})
})
}
+24 -36
View File
@@ -11,45 +11,33 @@ import (
)
func TestItoa(t *testing.T) {
b := itoa(nil, 0, 0)
assert.Equal(t, "0", string(b))
b = itoa(nil, 0, 1)
assert.Equal(t, "0", string(b))
b = itoa(nil, 0, 2)
assert.Equal(t, "00", string(b))
for width, expected := range []string{"0", "0", "00"} {
assert.Equal(t, expected, string(itoa(nil, 0, width)))
}
}
func TestEventFormatTextMessage(t *testing.T) {
res := EventFormatTextMessage(&WriterMode{Prefix: "[PREFIX] ", Colorize: false, Flags: Flags{defined: true, flags: 0xffffffff}},
&Event{
Time: time.Date(2020, 1, 2, 3, 4, 5, 6, time.UTC),
Caller: "caller",
Filename: "filename",
Line: 123,
Level: ERROR,
Stacktrace: "stacktrace",
},
"msg format: %v %v", "arg0", NewColoredValue("arg1", FgBlue),
)
assert.Equal(t, `[PREFIX] 2020/01/02 03:04:05.000000 filename:123:caller [E] [no-gopid] msg format: arg0 arg1
for _, testCase := range []struct {
colorize bool
expected string
}{
{false, `[PREFIX] 2020/01/02 03:04:05.000000 filename:123:caller [E] [no-gopid] msg format: arg0 arg1
stacktrace
`, string(res))
res = EventFormatTextMessage(&WriterMode{Prefix: "[PREFIX] ", Colorize: true, Flags: Flags{defined: true, flags: 0xffffffff}},
&Event{
Time: time.Date(2020, 1, 2, 3, 4, 5, 6, time.UTC),
Caller: "caller",
Filename: "filename",
Line: 123,
Level: ERROR,
Stacktrace: "stacktrace",
},
"msg format: %v %v", "arg0", NewColoredValue("arg1", FgBlue),
)
assert.Equal(t, "[PREFIX] \x1b[36m2020/01/02 03:04:05.000000 \x1b[0m\x1b[32mfilename:123:\x1b[32mcaller\x1b[0m \x1b[1;31m[E]\x1b[0m [\x1b[93mno-gopid\x1b[0m] msg format: arg0 \x1b[34marg1\x1b[0m\n\tstacktrace\n\n", string(res))
`},
{true, "[PREFIX] \x1b[36m2020/01/02 03:04:05.000000 \x1b[0m\x1b[32mfilename:123:\x1b[32mcaller\x1b[0m \x1b[1;31m[E]\x1b[0m [\x1b[93mno-gopid\x1b[0m] msg format: arg0 \x1b[34marg1\x1b[0m\n\tstacktrace\n\n"},
} {
res := EventFormatTextMessage(&WriterMode{Prefix: "[PREFIX] ", Colorize: testCase.colorize, Flags: Flags{defined: true, flags: 0xffffffff}},
&Event{
Time: time.Date(2020, 1, 2, 3, 4, 5, 6, time.UTC),
Caller: "caller",
Filename: "filename",
Line: 123,
Level: ERROR,
Stacktrace: "stacktrace",
},
"msg format: %v %v", "arg0", NewColoredValue("arg1", FgBlue),
)
assert.Equal(t, testCase.expected, string(res))
}
}
+11 -19
View File
@@ -24,25 +24,17 @@ func TestLevelMarshalUnmarshalJSON(t *testing.T) {
assert.Equal(t, string(makeTestLevelBytes(INFO.String())), string(levelBytes))
var testLevel testLevel
err = json.Unmarshal(levelBytes, &testLevel)
assert.NoError(t, err)
assert.Equal(t, INFO, testLevel.Level)
err = json.Unmarshal(makeTestLevelBytes(`FOFOO`), &testLevel)
assert.NoError(t, err)
assert.Equal(t, INFO, testLevel.Level)
err = json.Unmarshal(fmt.Appendf(nil, `{"level":%d}`, 2), &testLevel)
assert.NoError(t, err)
assert.Equal(t, INFO, testLevel.Level)
err = json.Unmarshal(fmt.Appendf(nil, `{"level":%d}`, 10012), &testLevel)
assert.NoError(t, err)
assert.Equal(t, INFO, testLevel.Level)
err = json.Unmarshal([]byte(`{"level":{}}`), &testLevel)
assert.NoError(t, err)
assert.Equal(t, INFO, testLevel.Level)
for _, levelJSON := range [][]byte{
levelBytes,
makeTestLevelBytes(`FOFOO`),
fmt.Appendf(nil, `{"level":%d}`, 2),
fmt.Appendf(nil, `{"level":%d}`, 10012),
[]byte(`{"level":{}}`),
} {
err = json.Unmarshal(levelJSON, &testLevel)
assert.NoError(t, err)
assert.Equal(t, INFO, testLevel.Level)
}
assert.Equal(t, INFO.String(), Level(1001).String())
+12 -21
View File
@@ -21,27 +21,18 @@ func TestCamoHandleLink(t *testing.T) {
setting.Camo.ServerURL = "https://image.proxy"
setting.Camo.HMACKey = "geheim"
dataURL := "data:image/png;base64,i//V"
assert.Equal(t, dataURL, camoHandleLink(dataURL))
assert.Equal(t,
"https://gitea.com/img.jpg",
camoHandleLink("https://gitea.com/img.jpg"))
assert.Equal(t,
"https://testimages.org/img.jpg",
camoHandleLink("https://testimages.org/img.jpg"))
assert.Equal(t,
"https://image.proxy/eivin43gJwGVIjR9MiYYtFIk0mw/aHR0cDovL3Rlc3RpbWFnZXMub3JnL2ltZy5qcGc",
camoHandleLink("http://testimages.org/img.jpg"))
test := func(expectedHTTPS string) {
assert.Equal(t, dataURL, camoHandleLink(dataURL))
assert.Equal(t,
"https://gitea.com/img.jpg",
camoHandleLink("https://gitea.com/img.jpg"))
assert.Equal(t, expectedHTTPS, camoHandleLink("https://testimages.org/img.jpg"))
assert.Equal(t,
"https://image.proxy/eivin43gJwGVIjR9MiYYtFIk0mw/aHR0cDovL3Rlc3RpbWFnZXMub3JnL2ltZy5qcGc",
camoHandleLink("http://testimages.org/img.jpg"))
}
test("https://testimages.org/img.jpg")
setting.Camo.Always = true
assert.Equal(t, dataURL, camoHandleLink(dataURL))
assert.Equal(t,
"https://gitea.com/img.jpg",
camoHandleLink("https://gitea.com/img.jpg"))
assert.Equal(t,
"https://image.proxy/tkdlvmqpbIr7SjONfHNgEU622y0/aHR0cHM6Ly90ZXN0aW1hZ2VzLm9yZy9pbWcuanBn",
camoHandleLink("https://testimages.org/img.jpg"))
assert.Equal(t,
"https://image.proxy/eivin43gJwGVIjR9MiYYtFIk0mw/aHR0cDovL3Rlc3RpbWFnZXMub3JnL2ltZy5qcGc",
camoHandleLink("http://testimages.org/img.jpg"))
test("https://image.proxy/tkdlvmqpbIr7SjONfHNgEU622y0/aHR0cHM6Ly90ZXN0aW1hZ2VzLm9yZy9pbWcuanBn")
}
-10
View File
@@ -85,7 +85,6 @@ func TestRender_IssueIndexPattern(t *testing.T) {
test("#abcd")
test("test#1234")
test("#1234test")
test("#abcd")
test("test!1234")
test("!1234test")
test(" test !1234test")
@@ -257,16 +256,7 @@ func TestRender_IssueIndexPattern_NoShortPattern(t *testing.T) {
testRenderIssueIndexPattern(t, "#1", "#1", NewTestRenderContext(metas))
testRenderIssueIndexPattern(t, "#1312", "#1312", NewTestRenderContext(metas))
testRenderIssueIndexPattern(t, "!1", "!1", NewTestRenderContext(metas))
}
func TestRender_PostProcessIssueTitle(t *testing.T) {
setting.AppURL = TestAppURL
metas := map[string]string{
"format": "https://someurl.com/{user}/{repo}/{index}",
"user": "someUser",
"repo": "someRepo",
"style": IssueNameStyleNumeric,
}
actual := PostProcessIssueTitle(NewTestRenderContext(metas), "#1")
assert.Equal(t, template.HTML("#1"), actual)
}
+20 -35
View File
@@ -37,43 +37,24 @@ func TestRender_IssueList(t *testing.T) {
assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(string(out)))
}
t.Run("NormalIssueRef", func(t *testing.T) {
test(
"#12345",
for _, tc := range []struct {
name, input, expected string
}{
{
"NormalIssueRef", "#12345",
`<p><a href="/test-user/test-repo/issues/12345" class="ref-issue" rel="nofollow">#12345</a></p>`,
)
})
t.Run("ListIssueRef", func(t *testing.T) {
test(
"* #12345",
`<ul>
},
{"ListIssueRef", "* #12345", `<ul>
<li><div>issue #12345</div></li>
</ul>`,
)
})
t.Run("ListIssueRefNormal", func(t *testing.T) {
test(
"* foo #12345 bar",
`<ul>
</ul>`},
{"ListIssueRefNormal", "* foo #12345 bar", `<ul>
<li>foo <a href="/test-user/test-repo/issues/12345" class="ref-issue" rel="nofollow">#12345</a> bar</li>
</ul>`,
)
})
t.Run("ListTodoIssueRef", func(t *testing.T) {
test(
"* [ ] #12345",
`<ul>
</ul>`},
{"ListTodoIssueRef", "* [ ] #12345", `<ul>
<li class="task-list-item"><input type="checkbox" disabled="" data-source-position="2"/><div>issue #12345</div></li>
</ul>`,
)
})
t.Run("IssueFootnote", func(t *testing.T) {
test(
"foo[^1][^2]\n\n[^1]: bar\n[^2]: baz",
</ul>`},
{
"IssueFootnote", "foo[^1][^2]\n\n[^1]: bar\n[^2]: baz",
`<p>foo<sup id="fnref:user-content-1-12345"><a href="#fn:user-content-1-12345" rel="nofollow">1 </a></sup><sup id="fnref:user-content-2-12345"><a href="#fn:user-content-2-12345" rel="nofollow">2 </a></sup></p>
<div>
<hr/>
@@ -86,6 +67,10 @@ func TestRender_IssueList(t *testing.T) {
</li>
</ol>
</div>`,
)
})
},
} {
t.Run(tc.name, func(_t *testing.T) {
test(tc.input, tc.expected)
})
}
}
+49 -64
View File
@@ -11,94 +11,79 @@ import (
)
func TestProcessNodeAttrID_HTMLHeadingWithoutID(t *testing.T) {
// Test that HTML headings without id get an auto-generated id from their text content
// when EnableHeadingIDGeneration is true (for repo files and wiki pages)
testCases := []struct {
name string
input string
expected string
name string
generateHeadingID bool
input, expected string
}{
// Test that HTML headings without id get an auto-generated id from their text content
// when EnableHeadingIDGeneration is true (for repo files and wiki pages)
{
name: "h1 without id",
input: `<h1>Heading without ID</h1>`,
expected: `<h1 id="user-content-heading-without-id">Heading without ID</h1>`,
"h1 without id", true,
`<h1>Heading without ID</h1>`,
`<h1 id="user-content-heading-without-id">Heading without ID</h1>`,
},
{
name: "h2 without id",
input: `<h2>Another Heading</h2>`,
expected: `<h2 id="user-content-another-heading">Another Heading</h2>`,
"h2 without id", true,
`<h2>Another Heading</h2>`,
`<h2 id="user-content-another-heading">Another Heading</h2>`,
},
{
name: "h3 without id",
input: `<h3>Third Level</h3>`,
expected: `<h3 id="user-content-third-level">Third Level</h3>`,
"h3 without id", true,
`<h3>Third Level</h3>`,
`<h3 id="user-content-third-level">Third Level</h3>`,
},
{
name: "h1 with existing id should keep it",
input: `<h1 id="my-custom-id">Heading with ID</h1>`,
expected: `<h1 id="user-content-my-custom-id">Heading with ID</h1>`,
"h1 with existing id should keep it", true,
`<h1 id="my-custom-id">Heading with ID</h1>`,
`<h1 id="user-content-my-custom-id">Heading with ID</h1>`,
},
{
name: "h1 with user-content prefix should not double prefix",
input: `<h1 id="user-content-already-prefixed">Already Prefixed</h1>`,
expected: `<h1 id="user-content-already-prefixed">Already Prefixed</h1>`,
"h1 with user-content prefix should not double prefix", true,
`<h1 id="user-content-already-prefixed">Already Prefixed</h1>`,
`<h1 id="user-content-already-prefixed">Already Prefixed</h1>`,
},
{
name: "heading with special characters",
input: `<h1>What is Wine Staging?</h1>`,
expected: `<h1 id="user-content-what-is-wine-staging">What is Wine Staging?</h1>`,
"heading with special characters", true,
`<h1>What is Wine Staging?</h1>`,
`<h1 id="user-content-what-is-wine-staging">What is Wine Staging?</h1>`,
},
{
name: "heading with nested elements",
input: `<h2><strong>Bold</strong> and <em>Italic</em></h2>`,
expected: `<h2 id="user-content-bold-and-italic"><strong>Bold</strong> and <em>Italic</em></h2>`,
"heading with nested elements", true,
`<h2><strong>Bold</strong> and <em>Italic</em></h2>`,
`<h2 id="user-content-bold-and-italic"><strong>Bold</strong> and <em>Italic</em></h2>`,
},
// Test that HTML headings in comment-like contexts (issue comments)
// do NOT get auto-generated IDs to avoid duplicate IDs on pages with multiple documents.
// This is controlled by EnableHeadingIDGeneration which defaults to false.
// Default context without EnableHeadingIDGeneration (simulates comment rendering)
{
"h1 without id in comment context", false,
`<h1>Heading without ID</h1>`,
`<h1>Heading without ID</h1>`,
},
{
"h2 without id in comment context", false,
`<h2>Another Heading</h2>`,
`<h2>Another Heading</h2>`,
},
{
"h1 with existing id should still be prefixed", false,
`<h1 id="my-custom-id">Heading with ID</h1>`,
`<h1 id="user-content-my-custom-id">Heading with ID</h1>`,
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
var result strings.Builder
ctx := NewTestRenderContext().WithEnableHeadingIDGeneration(true)
ctx := NewTestRenderContext()
if tc.generateHeadingID {
ctx.WithEnableHeadingIDGeneration(true)
}
err := PostProcessDefault(ctx, strings.NewReader(tc.input), &result)
assert.NoError(t, err)
assert.Equal(t, tc.expected, strings.TrimSpace(result.String()))
})
}
}
func TestProcessNodeAttrID_SkipHeadingIDForComments(t *testing.T) {
// Test that HTML headings in comment-like contexts (issue comments)
// do NOT get auto-generated IDs to avoid duplicate IDs on pages with multiple documents.
// This is controlled by EnableHeadingIDGeneration which defaults to false.
testCases := []struct {
name string
input string
expected string
}{
{
name: "h1 without id in comment context",
input: `<h1>Heading without ID</h1>`,
expected: `<h1>Heading without ID</h1>`,
},
{
name: "h2 without id in comment context",
input: `<h2>Another Heading</h2>`,
expected: `<h2>Another Heading</h2>`,
},
{
name: "h1 with existing id should still be prefixed",
input: `<h1 id="my-custom-id">Heading with ID</h1>`,
expected: `<h1 id="user-content-my-custom-id">Heading with ID</h1>`,
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
var result strings.Builder
// Default context without EnableHeadingIDGeneration (simulates comment rendering)
err := PostProcessDefault(NewTestRenderContext(), strings.NewReader(tc.input), &result)
assert.NoError(t, err)
assert.Equal(t, tc.expected, strings.TrimSpace(result.String()))
})
}
}
+120 -266
View File
@@ -145,90 +145,42 @@ func TestRender_links(t *testing.T) {
setting.Markdown.CustomURLSchemes = []string{"ftp", "magnet"}
common.InitLinkURLSchemes(setting.Markdown.CustomURLSchemes)
// Text that should be turned into URL
test(
"https://www.example.com",
`<p><a href="https://www.example.com" rel="nofollow">https://www.example.com</a></p>`)
test(
"http://www.example.com",
`<p><a href="http://www.example.com" rel="nofollow">http://www.example.com</a></p>`)
test(
"https://example.com",
`<p><a href="https://example.com" rel="nofollow">https://example.com</a></p>`)
test(
"http://example.com",
`<p><a href="http://example.com" rel="nofollow">http://example.com</a></p>`)
test(
"http://foo.com/blah_blah",
`<p><a href="http://foo.com/blah_blah" rel="nofollow">http://foo.com/blah_blah</a></p>`)
test(
"http://foo.com/blah_blah/",
`<p><a href="http://foo.com/blah_blah/" rel="nofollow">http://foo.com/blah_blah/</a></p>`)
test(
"http://www.example.com/wpstyle/?p=364",
`<p><a href="http://www.example.com/wpstyle/?p=364" rel="nofollow">http://www.example.com/wpstyle/?p=364</a></p>`)
test(
"https://www.example.com/foo/?bar=baz&inga=42&quux",
`<p><a href="https://www.example.com/foo/?bar=baz&amp;inga=42&amp;quux" rel="nofollow">https://www.example.com/foo/?bar=baz&amp;inga=42&amp;quux</a></p>`)
test(
"http://142.42.1.1/",
`<p><a href="http://142.42.1.1/" rel="nofollow">http://142.42.1.1/</a></p>`)
test(
"https://github.com/go-gitea/gitea/?p=aaa/bbb.html#ccc-ddd",
`<p><a href="https://github.com/go-gitea/gitea/?p=aaa/bbb.html#ccc-ddd" rel="nofollow">https://github.com/go-gitea/gitea/?p=aaa/bbb.html#ccc-ddd</a></p>`)
test(
"https://en.wikipedia.org/wiki/URL_(disambiguation)",
`<p><a href="https://en.wikipedia.org/wiki/URL_(disambiguation)" rel="nofollow">https://en.wikipedia.org/wiki/URL_(disambiguation)</a></p>`)
test(
"https://foo_bar.example.com/",
`<p><a href="https://foo_bar.example.com/" rel="nofollow">https://foo_bar.example.com/</a></p>`)
test(
"https://stackoverflow.com/questions/2896191/what-is-go-used-fore",
`<p><a href="https://stackoverflow.com/questions/2896191/what-is-go-used-fore" rel="nofollow">https://stackoverflow.com/questions/2896191/what-is-go-used-fore</a></p>`)
test(
"https://username:password@gitea.com",
`<p><a href="https://username:password@gitea.com" rel="nofollow">https://username:password@gitea.com</a></p>`)
test(
"ftp://gitea.com/file.txt",
`<p><a href="ftp://gitea.com/file.txt" rel="nofollow">ftp://gitea.com/file.txt</a></p>`)
test(
"magnet:?xt=urn:btih:5dee65101db281ac9c46344cd6b175cdcadabcde&dn=download",
`<p><a href="magnet:?xt=urn:btih:5dee65101db281ac9c46344cd6b175cdcadabcde&amp;dn=download" rel="nofollow">magnet:?xt=urn:btih:5dee65101db281ac9c46344cd6b175cdcadabcde&amp;dn=download</a></p>`)
test(
`[link](https://example.com)`,
`<p><a href="https://example.com" rel="nofollow">link</a></p>`)
test(
`[link](mailto:test@example.com)`,
`<p><a href="mailto:test@example.com" rel="nofollow">link</a></p>`)
test(
`[link](javascript:xss)`,
`<p>link</p>`)
for _, testCase := range []struct {
input, expected string
}{
// Text that should be turned into URL
{"https://www.example.com", `<p><a href="https://www.example.com" rel="nofollow">https://www.example.com</a></p>`},
{"http://www.example.com", `<p><a href="http://www.example.com" rel="nofollow">http://www.example.com</a></p>`},
{"https://example.com", `<p><a href="https://example.com" rel="nofollow">https://example.com</a></p>`},
{"http://example.com", `<p><a href="http://example.com" rel="nofollow">http://example.com</a></p>`},
{"http://foo.com/blah_blah", `<p><a href="http://foo.com/blah_blah" rel="nofollow">http://foo.com/blah_blah</a></p>`},
{"http://foo.com/blah_blah/", `<p><a href="http://foo.com/blah_blah/" rel="nofollow">http://foo.com/blah_blah/</a></p>`},
{"http://www.example.com/wpstyle/?p=364", `<p><a href="http://www.example.com/wpstyle/?p=364" rel="nofollow">http://www.example.com/wpstyle/?p=364</a></p>`},
{"https://www.example.com/foo/?bar=baz&inga=42&quux", `<p><a href="https://www.example.com/foo/?bar=baz&amp;inga=42&amp;quux" rel="nofollow">https://www.example.com/foo/?bar=baz&amp;inga=42&amp;quux</a></p>`},
{"http://142.42.1.1/", `<p><a href="http://142.42.1.1/" rel="nofollow">http://142.42.1.1/</a></p>`},
{"https://github.com/go-gitea/gitea/?p=aaa/bbb.html#ccc-ddd", `<p><a href="https://github.com/go-gitea/gitea/?p=aaa/bbb.html#ccc-ddd" rel="nofollow">https://github.com/go-gitea/gitea/?p=aaa/bbb.html#ccc-ddd</a></p>`},
{"https://en.wikipedia.org/wiki/URL_(disambiguation)", `<p><a href="https://en.wikipedia.org/wiki/URL_(disambiguation)" rel="nofollow">https://en.wikipedia.org/wiki/URL_(disambiguation)</a></p>`},
{"https://foo_bar.example.com/", `<p><a href="https://foo_bar.example.com/" rel="nofollow">https://foo_bar.example.com/</a></p>`},
{"https://stackoverflow.com/questions/2896191/what-is-go-used-fore", `<p><a href="https://stackoverflow.com/questions/2896191/what-is-go-used-fore" rel="nofollow">https://stackoverflow.com/questions/2896191/what-is-go-used-fore</a></p>`},
{"https://username:password@gitea.com", `<p><a href="https://username:password@gitea.com" rel="nofollow">https://username:password@gitea.com</a></p>`},
{"ftp://gitea.com/file.txt", `<p><a href="ftp://gitea.com/file.txt" rel="nofollow">ftp://gitea.com/file.txt</a></p>`},
{"magnet:?xt=urn:btih:5dee65101db281ac9c46344cd6b175cdcadabcde&dn=download", `<p><a href="magnet:?xt=urn:btih:5dee65101db281ac9c46344cd6b175cdcadabcde&amp;dn=download" rel="nofollow">magnet:?xt=urn:btih:5dee65101db281ac9c46344cd6b175cdcadabcde&amp;dn=download</a></p>`},
{`[link](https://example.com)`, `<p><a href="https://example.com" rel="nofollow">link</a></p>`},
{`[link](mailto:test@example.com)`, `<p><a href="mailto:test@example.com" rel="nofollow">link</a></p>`},
{`[link](javascript:xss)`, `<p>link</p>`},
// Test that should *not* be turned into URL
test(
"www.example.com",
`<p>www.example.com</p>`)
test(
"example.com",
`<p>example.com</p>`)
test(
"test.example.com",
`<p>test.example.com</p>`)
test(
"http://",
`<p>http://</p>`)
test(
"https://",
`<p>https://</p>`)
test(
"://",
`<p>://</p>`)
test(
"www",
`<p>www</p>`)
test(
"ftps://gitea.com",
`<p>ftps://gitea.com</p>`)
// Test that should *not* be turned into URL
{"www.example.com", `<p>www.example.com</p>`},
{"example.com", `<p>example.com</p>`},
{"test.example.com", `<p>test.example.com</p>`},
{"http://", `<p>http://</p>`},
{"https://", `<p>https://</p>`},
{"://", `<p>://</p>`},
{"www", `<p>www</p>`},
{"ftps://gitea.com", `<p>ftps://gitea.com</p>`},
} {
test(testCase.input, testCase.expected)
}
t.Run("LinkEllipsis", func(t *testing.T) {
input := util.EllipsisDisplayString("http://10.1.2.3", 12)
@@ -244,73 +196,41 @@ func TestRender_links(t *testing.T) {
func TestRender_email(t *testing.T) {
setting.AppURL = markup.TestAppURL
defer testModule.MockVariableValue(&markup.RenderBehaviorForTesting.DisableAdditionalAttributes, true)()
test := func(input, expected string) {
res, err := testRenderString(markup.NewTestRenderContext().WithRelativePath("a.md"), input)
assert.NoError(t, err)
assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(res), "input: %s", input)
}
for _, testCase := range []struct {
input, expected string
}{
// Text that should be turned into email link
{"info@gitea.com", `<p><a href="mailto:info@gitea.com" rel="nofollow">info@gitea.com</a></p>`},
{"(info@gitea.com)", `<p>(<a href="mailto:info@gitea.com" rel="nofollow">info@gitea.com</a>)</p>`},
{"[info@gitea.com]", `<p>[<a href="mailto:info@gitea.com" rel="nofollow">info@gitea.com</a>]</p>`},
{"info@gitea.com.", `<p><a href="mailto:info@gitea.com" rel="nofollow">info@gitea.com</a>.</p>`},
{"firstname+lastname@gitea.com", `<p><a href="mailto:firstname+lastname@gitea.com" rel="nofollow">firstname+lastname@gitea.com</a></p>`},
{"send email to info@gitea.co.uk.", `<p>send email to <a href="mailto:info@gitea.co.uk" rel="nofollow">info@gitea.co.uk</a>.</p>`},
// Text that should be turned into email link
test(
"info@gitea.com",
`<p><a href="mailto:info@gitea.com" rel="nofollow">info@gitea.com</a></p>`)
test(
"(info@gitea.com)",
`<p>(<a href="mailto:info@gitea.com" rel="nofollow">info@gitea.com</a>)</p>`)
test(
"[info@gitea.com]",
`<p>[<a href="mailto:info@gitea.com" rel="nofollow">info@gitea.com</a>]</p>`)
test(
"info@gitea.com.",
`<p><a href="mailto:info@gitea.com" rel="nofollow">info@gitea.com</a>.</p>`)
test(
"firstname+lastname@gitea.com",
`<p><a href="mailto:firstname+lastname@gitea.com" rel="nofollow">firstname+lastname@gitea.com</a></p>`)
test(
"send email to info@gitea.co.uk.",
`<p>send email to <a href="mailto:info@gitea.co.uk" rel="nofollow">info@gitea.co.uk</a>.</p>`)
test(
`j.doe@example.com,
{`j.doe@example.com,
j.doe@example.com.
j.doe@example.com;
j.doe@example.com?
j.doe@example.com!`,
`<p><a href="mailto:j.doe@example.com" rel="nofollow">j.doe@example.com</a>,
j.doe@example.com!`, `<p><a href="mailto:j.doe@example.com" rel="nofollow">j.doe@example.com</a>,
<a href="mailto:j.doe@example.com" rel="nofollow">j.doe@example.com</a>.
<a href="mailto:j.doe@example.com" rel="nofollow">j.doe@example.com</a>;
<a href="mailto:j.doe@example.com" rel="nofollow">j.doe@example.com</a>?
<a href="mailto:j.doe@example.com" rel="nofollow">j.doe@example.com</a>!</p>`)
<a href="mailto:j.doe@example.com" rel="nofollow">j.doe@example.com</a>!</p>`},
// match GitHub behavior
test("email@domain@domain.com", `<p>email@<a href="mailto:domain@domain.com" rel="nofollow">domain@domain.com</a></p>`)
// match GitHub behavior
{"email@domain@domain.com", `<p>email@<a href="mailto:domain@domain.com" rel="nofollow">domain@domain.com</a></p>`},
// match GitHub behavior
test(`"info@gitea.com"`, `<p>&#34;<a href="mailto:info@gitea.com" rel="nofollow">info@gitea.com</a>&#34;</p>`)
// match GitHub behavior
{`"info@gitea.com"`, `<p>&#34;<a href="mailto:info@gitea.com" rel="nofollow">info@gitea.com</a>&#34;</p>`},
// Test that should *not* be turned into email links
test(
"/home/gitea/mailstore/info@gitea/com",
`<p>/home/gitea/mailstore/info@gitea/com</p>`)
test(
"git@try.gitea.io:go-gitea/gitea.git",
`<p>git@try.gitea.io:go-gitea/gitea.git</p>`)
test(
"https://foo:bar@gitea.io",
`<p><a href="https://foo:bar@gitea.io" rel="nofollow">https://foo:bar@gitea.io</a></p>`)
test(
"gitea@3",
`<p>gitea@3</p>`)
test(
"gitea@gmail.c",
`<p>gitea@gmail.c</p>`)
test(
"email@domain..com",
`<p>email@domain..com</p>`)
// Test that should *not* be turned into email links
{"/home/gitea/mailstore/info@gitea/com", `<p>/home/gitea/mailstore/info@gitea/com</p>`},
{"git@try.gitea.io:go-gitea/gitea.git", `<p>git@try.gitea.io:go-gitea/gitea.git</p>`},
{"https://foo:bar@gitea.io", `<p><a href="https://foo:bar@gitea.io" rel="nofollow">https://foo:bar@gitea.io</a></p>`},
{"gitea@3", `<p>gitea@3</p>`},
{"gitea@gmail.c", `<p>gitea@gmail.c</p>`},
{"email@domain..com", `<p>email@domain..com</p>`},
cases := []struct {
input, expected string
}{
// match GitHub behavior
{"?a@d.zz", `<p>?<a href="mailto:a@d.zz" rel="nofollow">a@d.zz</a></p>`},
{"*a@d.zz", `<p>*<a href="mailto:a@d.zz" rel="nofollow">a@d.zz</a></p>`},
@@ -320,9 +240,10 @@ func TestRender_email(t *testing.T) {
// maybe we should reduce the candidate characters for the "name" part in the future
{"a*a@d.zz", `<p><a href="mailto:a*a@d.zz" rel="nofollow">a*a@d.zz</a></p>`},
{"a~a@d.zz", `<p><a href="mailto:a~a@d.zz" rel="nofollow">a~a@d.zz</a></p>`},
}
for _, c := range cases {
test(c.input, c.expected)
} {
res, err := testRenderString(markup.NewTestRenderContext().WithRelativePath("a.md"), testCase.input)
assert.NoError(t, err)
assert.Equal(t, strings.TrimSpace(testCase.expected), strings.TrimSpace(res), "input: %s", testCase.input)
}
}
@@ -394,12 +315,6 @@ func TestRender_ShortLinks(t *testing.T) {
setting.AppURL = markup.TestAppURL
tree := markup.TestRepoURL + "src/master"
test := func(input, expected string) {
buffer, err := markdown.RenderString(markup.NewTestRenderContext(tree), input)
assert.NoError(t, err)
assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(string(buffer)))
}
url := tree + "/Link"
otherURL := tree + "/Other-Link"
encodedURL := tree + "/Link%3F"
@@ -410,88 +325,36 @@ func TestRender_ShortLinks(t *testing.T) {
renderableFileURL := tree + "/markdown_file.md"
unrenderableFileURL := tree + "/file.zip"
favicon := "http://google.com/favicon.ico"
test(
"[[Link]]",
`<p><a href="`+url+`" rel="nofollow">Link</a></p>`,
)
test(
"[[Link.-]]",
`<p><a href="http://localhost:3000/test-owner/test-repo/src/master/Link.-" rel="nofollow">Link.-</a></p>`,
)
test(
"[[Link.jpg]]",
`<p><a href="`+imgurl+`" rel="nofollow"><img src="`+imgurl+`" title="Link.jpg" alt="Link.jpg"/></a></p>`,
)
test(
"[["+favicon+"]]",
`<p><a href="`+favicon+`" rel="nofollow"><img src="`+favicon+`" title="favicon.ico" alt="`+favicon+`"/></a></p>`,
)
test(
"[[Name|Link]]",
`<p><a href="`+url+`" rel="nofollow">Name</a></p>`,
)
test(
"[[Name|Link.jpg]]",
`<p><a href="`+imgurl+`" rel="nofollow"><img src="`+imgurl+`" title="Name" alt="Name"/></a></p>`,
)
test(
"[[Name|Link.jpg|alt=AltName]]",
`<p><a href="`+imgurl+`" rel="nofollow"><img src="`+imgurl+`" title="AltName" alt="AltName"/></a></p>`,
)
test(
"[[Name|Link.jpg|title=Title]]",
`<p><a href="`+imgurl+`" rel="nofollow"><img src="`+imgurl+`" title="Title" alt="Title"/></a></p>`,
)
test(
"[[Name|Link.jpg|alt=AltName|title=Title]]",
`<p><a href="`+imgurl+`" rel="nofollow"><img src="`+imgurl+`" title="Title" alt="AltName"/></a></p>`,
)
test(
"[[Name|Link.jpg|alt=\"AltName\"|title='Title']]",
`<p><a href="`+imgurl+`" rel="nofollow"><img src="`+imgurl+`" title="Title" alt="AltName"/></a></p>`,
)
test(
"[[Name|Link Other.jpg|alt=\"AltName\"|title='Title']]",
`<p><a href="`+otherImgurl+`" rel="nofollow"><img src="`+otherImgurl+`" title="Title" alt="AltName"/></a></p>`,
)
test(
"[[Link]] [[Other Link]]",
`<p><a href="`+url+`" rel="nofollow">Link</a> <a href="`+otherURL+`" rel="nofollow">Other Link</a></p>`,
)
test(
"[[Link?]]",
`<p><a href="`+encodedURL+`" rel="nofollow">Link?</a></p>`,
)
test(
"[[Link]] [[Other Link]] [[Link?]]",
`<p><a href="`+url+`" rel="nofollow">Link</a> <a href="`+otherURL+`" rel="nofollow">Other Link</a> <a href="`+encodedURL+`" rel="nofollow">Link?</a></p>`,
)
test(
"[[markdown_file.md]]",
`<p><a href="`+renderableFileURL+`" rel="nofollow">markdown_file.md</a></p>`,
)
test(
"[[file.zip]]",
`<p><a href="`+unrenderableFileURL+`" rel="nofollow">file.zip</a></p>`,
)
test(
"[[Link #.jpg]]",
`<p><a href="`+encodedImgurl+`" rel="nofollow"><img src="`+encodedImgurl+`" title="Link #.jpg" alt="Link #.jpg"/></a></p>`,
)
test(
"[[Name|Link #.jpg|alt=\"AltName\"|title='Title']]",
`<p><a href="`+encodedImgurl+`" rel="nofollow"><img src="`+encodedImgurl+`" title="Title" alt="AltName"/></a></p>`,
)
// FIXME: it's unable to resolve: [[link?k=v]]
// FIXME: it is a wrong test case, it is not an image, but a link with anchor "#.jpg"
test(
"[[some/path/Link #.jpg]]",
`<p><a href="`+notencodedImgurl+`" rel="nofollow"><img src="`+notencodedImgurl+`" title="Link #.jpg" alt="some/path/Link #.jpg"/></a></p>`,
)
test(
"<p><a href=\"https://example.org\">[[foobar]]</a></p>",
`<p><a href="https://example.org" rel="nofollow">[[foobar]]</a></p>`,
)
for _, testCase := range []struct {
input, expected string
}{
{"[[Link]]", `<p><a href="` + url + `" rel="nofollow">Link</a></p>`},
{"[[Link.-]]", `<p><a href="http://localhost:3000/test-owner/test-repo/src/master/Link.-" rel="nofollow">Link.-</a></p>`},
{"[[Link.jpg]]", `<p><a href="` + imgurl + `" rel="nofollow"><img src="` + imgurl + `" title="Link.jpg" alt="Link.jpg"/></a></p>`},
{"[[" + favicon + "]]", `<p><a href="` + favicon + `" rel="nofollow"><img src="` + favicon + `" title="favicon.ico" alt="` + favicon + `"/></a></p>`},
{"[[Name|Link]]", `<p><a href="` + url + `" rel="nofollow">Name</a></p>`},
{"[[Name|Link.jpg]]", `<p><a href="` + imgurl + `" rel="nofollow"><img src="` + imgurl + `" title="Name" alt="Name"/></a></p>`},
{"[[Name|Link.jpg|alt=AltName]]", `<p><a href="` + imgurl + `" rel="nofollow"><img src="` + imgurl + `" title="AltName" alt="AltName"/></a></p>`},
{"[[Name|Link.jpg|title=Title]]", `<p><a href="` + imgurl + `" rel="nofollow"><img src="` + imgurl + `" title="Title" alt="Title"/></a></p>`},
{"[[Name|Link.jpg|alt=AltName|title=Title]]", `<p><a href="` + imgurl + `" rel="nofollow"><img src="` + imgurl + `" title="Title" alt="AltName"/></a></p>`},
{"[[Name|Link.jpg|alt=\"AltName\"|title='Title']]", `<p><a href="` + imgurl + `" rel="nofollow"><img src="` + imgurl + `" title="Title" alt="AltName"/></a></p>`},
{"[[Name|Link Other.jpg|alt=\"AltName\"|title='Title']]", `<p><a href="` + otherImgurl + `" rel="nofollow"><img src="` + otherImgurl + `" title="Title" alt="AltName"/></a></p>`},
{"[[Link]] [[Other Link]]", `<p><a href="` + url + `" rel="nofollow">Link</a> <a href="` + otherURL + `" rel="nofollow">Other Link</a></p>`},
{"[[Link?]]", `<p><a href="` + encodedURL + `" rel="nofollow">Link?</a></p>`},
{"[[Link]] [[Other Link]] [[Link?]]", `<p><a href="` + url + `" rel="nofollow">Link</a> <a href="` + otherURL + `" rel="nofollow">Other Link</a> <a href="` + encodedURL + `" rel="nofollow">Link?</a></p>`},
{"[[markdown_file.md]]", `<p><a href="` + renderableFileURL + `" rel="nofollow">markdown_file.md</a></p>`},
{"[[file.zip]]", `<p><a href="` + unrenderableFileURL + `" rel="nofollow">file.zip</a></p>`},
{"[[Link #.jpg]]", `<p><a href="` + encodedImgurl + `" rel="nofollow"><img src="` + encodedImgurl + `" title="Link #.jpg" alt="Link #.jpg"/></a></p>`},
{"[[Name|Link #.jpg|alt=\"AltName\"|title='Title']]", `<p><a href="` + encodedImgurl + `" rel="nofollow"><img src="` + encodedImgurl + `" title="Title" alt="AltName"/></a></p>`},
// FIXME: it's unable to resolve: [[link?k=v]]
// FIXME: it is a wrong test case, it is not an image, but a link with anchor "#.jpg"
{"[[some/path/Link #.jpg]]", `<p><a href="` + notencodedImgurl + `" rel="nofollow"><img src="` + notencodedImgurl + `" title="Link #.jpg" alt="some/path/Link #.jpg"/></a></p>`},
{"<p><a href=\"https://example.org\">[[foobar]]</a></p>", `<p><a href="https://example.org" rel="nofollow">[[foobar]]</a></p>`},
} {
buffer, err := markdown.RenderString(markup.NewTestRenderContext(tree), testCase.input)
assert.NoError(t, err)
assert.Equal(t, strings.TrimSpace(testCase.expected), strings.TrimSpace(string(buffer)))
}
}
func Test_ParseClusterFuzz(t *testing.T) {
@@ -519,45 +382,36 @@ func TestPostProcess(t *testing.T) {
setting.StaticURLPrefix = strings.TrimSuffix(markup.TestAppURL, "/") // can't run standalone
defer testModule.MockVariableValue(&markup.RenderBehaviorForTesting.DisableAdditionalAttributes, true)()
test := func(input, expected string) {
for _, testCase := range []struct {
input, expected string
}{
// Issue index shouldn't be post-processing in a document.
{"#1", "#1"},
// But cross-referenced issue index should work.
{"go-gitea/gitea#12345", `<a href="/go-gitea/gitea/issues/12345" class="ref-issue">go-gitea/gitea#12345</a>`},
// Test that other post-processing still works.
{":gitea:", `<span class="emoji"><img alt=":gitea:" src="` + setting.StaticURLPrefix + `/assets/img/emoji/gitea.png"/></span>`},
{"Some text with 😄 in the middle", `Some text with <span class="emoji" data-alias="smile">😄</span> in the middle`},
{"http://localhost:3000/person/repo/issues/4#issuecomment-1234", `<a href="http://localhost:3000/person/repo/issues/4#issuecomment-1234" class="ref-issue">person/repo#4 (comment)</a>`},
{"<math><mtext>:gitea: go-gitea/gitea#12345</mtext></math>", "<math><mtext>:gitea: go-gitea/gitea#12345</mtext></math>"},
// special tags, GitHub's behavior, and for unclosed tags, output as text content as much as possible
{"<script>a", `&lt;script&gt;a`},
{"<script>a</script>", `&lt;script&gt;a&lt;/script&gt;`},
{"<STYLE>a", `&lt;STYLE&gt;a`},
{"<style>a</STYLE>", `&lt;style&gt;a&lt;/STYLE&gt;`},
// other special tags, our special behavior
{"<?php\nfoo", "&lt;?php\nfoo"},
{"<%asp\nfoo", "&lt;%asp\nfoo"},
} {
var res strings.Builder
err := markup.PostProcessDefault(markup.NewTestRenderContext(markup.TestAppURL, map[string]string{"user": "go-gitea", "repo": "gitea"}), strings.NewReader(input), &res)
err := markup.PostProcessDefault(markup.NewTestRenderContext(markup.TestAppURL, map[string]string{"user": "go-gitea", "repo": "gitea"}), strings.NewReader(testCase.input), &res)
assert.NoError(t, err)
assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(res.String()))
assert.Equal(t, strings.TrimSpace(testCase.expected), strings.TrimSpace(res.String()))
}
// Issue index shouldn't be post-processing in a document.
test(
"#1",
"#1")
// But cross-referenced issue index should work.
test(
"go-gitea/gitea#12345",
`<a href="/go-gitea/gitea/issues/12345" class="ref-issue">go-gitea/gitea#12345</a>`)
// Test that other post-processing still works.
test(
":gitea:",
`<span class="emoji"><img alt=":gitea:" src="`+setting.StaticURLPrefix+`/assets/img/emoji/gitea.png"/></span>`)
test(
"Some text with 😄 in the middle",
`Some text with <span class="emoji" data-alias="smile">😄</span> in the middle`)
test("http://localhost:3000/person/repo/issues/4#issuecomment-1234",
`<a href="http://localhost:3000/person/repo/issues/4#issuecomment-1234" class="ref-issue">person/repo#4 (comment)</a>`)
test(
"<math><mtext>:gitea: go-gitea/gitea#12345</mtext></math>",
"<math><mtext>:gitea: go-gitea/gitea#12345</mtext></math>")
// special tags, GitHub's behavior, and for unclosed tags, output as text content as much as possible
test("<script>a", `&lt;script&gt;a`)
test("<script>a</script>", `&lt;script&gt;a&lt;/script&gt;`)
test("<STYLE>a", `&lt;STYLE&gt;a`)
test("<style>a</STYLE>", `&lt;style&gt;a&lt;/STYLE&gt;`)
// other special tags, our special behavior
test("<?php\nfoo", "&lt;?php\nfoo")
test("<%asp\nfoo", "&lt;%asp\nfoo")
}
func TestIssue16020(t *testing.T) {
+16 -26
View File
@@ -61,30 +61,20 @@ func TestRenderInternalAttrs(t *testing.T) {
}
func TestRenderInternalExtraHead(t *testing.T) {
t.Run("HeadExists", func(t *testing.T) {
out := &bytes.Buffer{}
var r RenderInternal
in := r.init("sec", out, `<MY-TAG>`)
_, _ = io.WriteString(in, `<head>any</head>`)
_ = in.Close()
assert.Equal(t, `<head><MY-TAG>any</head>`, out.String())
})
t.Run("HeadNotExists", func(t *testing.T) {
out := &bytes.Buffer{}
var r RenderInternal
in := r.init("sec", out, `<MY-TAG>`)
_, _ = io.WriteString(in, `<div></div>`)
_ = in.Close()
assert.Equal(t, `<MY-TAG><div></div>`, out.String())
})
t.Run("NotHTML", func(t *testing.T) {
out := &bytes.Buffer{}
var r RenderInternal
in := r.init("sec", out, `<MY-TAG>`)
_, _ = io.WriteString(in, `<any>`)
_ = in.Close()
assert.Equal(t, `<any>`, out.String())
})
for _, test := range []struct {
name, input, expected string
}{
{"HeadExists", `<head>any</head>`, `<head><MY-TAG>any</head>`},
{"HeadNotExists", `<div></div>`, `<MY-TAG><div></div>`},
{"NotHTML", `<any>`, `<any>`},
} {
t.Run(test.name, func(t *testing.T) {
out := &bytes.Buffer{}
var r RenderInternal
in := r.init("sec", out, `<MY-TAG>`)
_, _ = io.WriteString(in, test.input)
_ = in.Close()
assert.Equal(t, test.expected, out.String())
})
}
}
+14 -42
View File
@@ -16,6 +16,12 @@ import (
func TestRender(t *testing.T) {
r := renderer{}
render := func(t *testing.T, ctx *markup.RenderContext, input string) string {
var output strings.Builder
err := r.Render(ctx, strings.NewReader(input), &output)
assert.NoError(t, err)
return output.String()
}
t.Run("Basic notebook", func(t *testing.T) {
input := `{
@@ -37,12 +43,7 @@ func TestRender(t *testing.T) {
"nbformat": 4
}`
var output strings.Builder
ctx := &markup.RenderContext{}
err := r.Render(ctx, strings.NewReader(input), &output)
assert.NoError(t, err)
result := output.String()
result := render(t, &markup.RenderContext{}, input)
assert.Contains(t, result, `<div class="jupyter-notebook">`)
assert.Contains(t, result, `<div class="notebook-cell cell-type-code">`)
assert.Contains(t, result, `In [1]:`)
@@ -68,12 +69,7 @@ func TestRender(t *testing.T) {
"nbformat": 4
}`
var output strings.Builder
ctx := markup.NewRenderContext(t.Context())
err := r.Render(ctx, strings.NewReader(input), &output)
assert.NoError(t, err)
result := output.String()
result := render(t, markup.NewRenderContext(t.Context()), input)
// Assert normal markup still renders correctly
assert.Contains(t, result, `<div class="notebook-cell cell-type-markdown">`)
@@ -94,12 +90,7 @@ func TestRender(t *testing.T) {
}
input := fmt.Sprintf(`{"cells": [%s], "metadata": {}, "nbformat": 4}`, strings.Join(cellBlocks, ","))
var output strings.Builder
ctx := markup.NewRenderContext(t.Context())
err := r.Render(ctx, strings.NewReader(input), &output)
assert.NoError(t, err)
result := output.String()
result := render(t, markup.NewRenderContext(t.Context()), input)
// Verify it halts rendering gracefully and shows the truncation warning
assert.Contains(t, result, "Output truncated.")
@@ -130,12 +121,7 @@ func TestRender(t *testing.T) {
"nbformat": 4
}`
var output strings.Builder
ctx := markup.NewRenderContext(t.Context())
err := r.Render(ctx, strings.NewReader(input), &output)
assert.NoError(t, err)
result := output.String()
result := render(t, markup.NewRenderContext(t.Context()), input)
assert.Contains(t, result, `<img src="data:image/png;base64,`)
assert.Contains(t, result, `iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==`)
})
@@ -161,12 +147,7 @@ func TestRender(t *testing.T) {
"nbformat": 4
}`
var output strings.Builder
ctx := markup.NewRenderContext(t.Context())
err := r.Render(ctx, strings.NewReader(input), &output)
assert.NoError(t, err)
result := output.String()
result := render(t, markup.NewRenderContext(t.Context()), input)
assert.NotContains(t, result, `<style scoped>`)
assert.Contains(t, result, `<table><tr><td>1</td></tr></table>`)
assert.Contains(t, result, `<td>1</td>`)
@@ -193,12 +174,7 @@ func TestRender(t *testing.T) {
"nbformat": 4
}`
var output strings.Builder
ctx := markup.NewRenderContext(t.Context())
err := r.Render(ctx, strings.NewReader(input), &output)
assert.NoError(t, err)
result := output.String()
result := render(t, markup.NewRenderContext(t.Context()), input)
assert.Contains(t, result, `ValueError: test error`)
assert.Contains(t, result, `cell-output-error`)
})
@@ -210,12 +186,8 @@ func TestRender(t *testing.T) {
"nbformat": 3
}`
var output strings.Builder
ctx := markup.NewRenderContext(t.Context())
err := r.Render(ctx, strings.NewReader(input), &output)
assert.NoError(t, err)
assert.Regexp(t, `<div class="file-not-rendered-prompt">This notebook uses an older format.*</div>`, output.String())
result := render(t, markup.NewRenderContext(t.Context()), input)
assert.Regexp(t, `<div class="file-not-rendered-prompt">This notebook uses an older format.*</div>`, result)
})
}
-11
View File
@@ -58,17 +58,6 @@ func TestRender_Images(t *testing.T) {
result := baseLink + "/.images/src/02/train.jpg" // resolved link should not go out of the base link
// hint: With Markdown v2.5.2, there is a new syntax: [link](URL){:target="_blank"} , but we do not support it now
render(
"!["+title+"]("+url+")",
`<p><a href="`+result+`" target="_blank" rel="nofollow noopener"><img src="`+result+`" alt="`+title+`"/></a></p>`)
render(
"[["+title+"|"+url+"]]",
`<p><a href="`+result+`" rel="nofollow"><img src="`+result+`" title="`+title+`" alt="`+title+`"/></a></p>`)
render(
"[!["+title+"]("+url+")]("+href+")",
`<p><a href="`+href+`" rel="nofollow"><img src="`+result+`" alt="`+title+`"/></a></p>`)
render(
"!["+title+"]("+url+")",
`<p><a href="`+result+`" target="_blank" rel="nofollow noopener"><img src="`+result+`" alt="`+title+`"/></a></p>`)
+36 -57
View File
@@ -26,67 +26,46 @@ func (it *IssueTemplate) Valid() bool {
}
func TestExtractMetadata(t *testing.T) {
t.Run("ValidFrontAndBody", func(t *testing.T) {
var meta IssueTemplate
body, err := ExtractMetadata(fmt.Sprintf("%s\n%s\n%s\n%s", sepTest, frontTest, sepTest, bodyTest), &meta)
assert.NoError(t, err)
assert.Equal(t, bodyTest, body)
assert.Equal(t, metaTest, meta)
assert.True(t, meta.Valid())
})
for _, mode := range []string{"String", "Bytes"} {
t.Run(mode, func(t *testing.T) {
extract := func(format string, args ...any) (string, IssueTemplate, error) {
var meta IssueTemplate
if mode == "String" {
body, err := ExtractMetadata(fmt.Sprintf(format, args...), &meta)
return body, meta, err
} else {
body, err := ExtractMetadataBytes(fmt.Appendf(nil, format, args...), &meta)
return string(body), meta, err
}
}
t.Run("NoFirstSeparator", func(t *testing.T) {
var meta IssueTemplate
_, err := ExtractMetadata(fmt.Sprintf("%s\n%s\n%s", frontTest, sepTest, bodyTest), &meta)
assert.Error(t, err)
})
t.Run("ValidFrontAndBody", func(t *testing.T) {
body, meta, err := extract("%s\n%s\n%s\n%s", sepTest, frontTest, sepTest, bodyTest)
assert.NoError(t, err)
assert.Equal(t, bodyTest, body)
assert.Equal(t, metaTest, meta)
assert.True(t, meta.Valid())
})
t.Run("NoLastSeparator", func(t *testing.T) {
var meta IssueTemplate
_, err := ExtractMetadata(fmt.Sprintf("%s\n%s\n%s", sepTest, frontTest, bodyTest), &meta)
assert.Error(t, err)
})
t.Run("NoFirstSeparator", func(t *testing.T) {
_, _, err := extract("%s\n%s\n%s", frontTest, sepTest, bodyTest)
assert.Error(t, err)
})
t.Run("NoBody", func(t *testing.T) {
var meta IssueTemplate
body, err := ExtractMetadata(fmt.Sprintf("%s\n%s\n%s", sepTest, frontTest, sepTest), &meta)
assert.NoError(t, err)
assert.Empty(t, body)
assert.Equal(t, metaTest, meta)
assert.True(t, meta.Valid())
})
}
t.Run("NoLastSeparator", func(t *testing.T) {
_, _, err := extract("%s\n%s\n%s", sepTest, frontTest, bodyTest)
assert.Error(t, err)
})
func TestExtractMetadataBytes(t *testing.T) {
t.Run("ValidFrontAndBody", func(t *testing.T) {
var meta IssueTemplate
body, err := ExtractMetadataBytes(fmt.Appendf(nil, "%s\n%s\n%s\n%s", sepTest, frontTest, sepTest, bodyTest), &meta)
assert.NoError(t, err)
assert.Equal(t, bodyTest, string(body))
assert.Equal(t, metaTest, meta)
assert.True(t, meta.Valid())
})
t.Run("NoFirstSeparator", func(t *testing.T) {
var meta IssueTemplate
_, err := ExtractMetadataBytes(fmt.Appendf(nil, "%s\n%s\n%s", frontTest, sepTest, bodyTest), &meta)
assert.Error(t, err)
})
t.Run("NoLastSeparator", func(t *testing.T) {
var meta IssueTemplate
_, err := ExtractMetadataBytes(fmt.Appendf(nil, "%s\n%s\n%s", sepTest, frontTest, bodyTest), &meta)
assert.Error(t, err)
})
t.Run("NoBody", func(t *testing.T) {
var meta IssueTemplate
body, err := ExtractMetadataBytes(fmt.Appendf(nil, "%s\n%s\n%s", sepTest, frontTest, sepTest), &meta)
assert.NoError(t, err)
assert.Empty(t, string(body))
assert.Equal(t, metaTest, meta)
assert.True(t, meta.Valid())
})
t.Run("NoBody", func(t *testing.T) {
body, meta, err := extract("%s\n%s\n%s", sepTest, frontTest, sepTest)
assert.NoError(t, err)
assert.Empty(t, body)
assert.Equal(t, metaTest, meta)
assert.True(t, meta.Valid())
})
})
}
}
var (
+3 -8
View File
@@ -12,17 +12,12 @@ import (
)
func TestRenderIFrame(t *testing.T) {
render := func(ctx *RenderContext, opts ExternalRendererOptions) string {
sb := &strings.Builder{}
require.NoError(t, RenderIFrame(ctx, &opts, sb))
return sb.String()
}
ctx := NewRenderContext(t.Context()).
WithRelativePath("tree-path").
WithMetas(map[string]string{"user": "test-owner", "repo": "test-repo", "RefTypeNameSubURL": "src/branch/master"})
// iframe doesn't need sandbox, the sandbox is set in render's response header
ret := render(ctx, ExternalRendererOptions{ContentSandbox: "any"})
assert.Equal(t, `<iframe data-src="/test-owner/test-repo/render/src/branch/master/tree-path" data-global-init="initExternalRenderIframe" class="external-render-iframe"></iframe>`, ret)
sb := &strings.Builder{}
require.NoError(t, RenderIFrame(ctx, &ExternalRendererOptions{ContentSandbox: "any"}, sb))
assert.Equal(t, `<iframe data-src="/test-owner/test-repo/render/src/branch/master/tree-path" data-global-init="initExternalRenderIframe" class="external-render-iframe"></iframe>`, sb.String())
}
+21 -69
View File
@@ -8,74 +8,26 @@ import (
"testing"
)
func TestRedisUsernameOpt(t *testing.T) {
uri, _ := url.Parse("redis://redis:password@myredis/0")
opts := getRedisOptions(uri)
if opts.Username != "redis" {
t.Fail()
}
}
func TestRedisPasswordOpt(t *testing.T) {
uri, _ := url.Parse("redis://redis:password@myredis/0")
opts := getRedisOptions(uri)
if opts.Password != "password" {
t.Fail()
}
}
func TestSkipVerifyOpt(t *testing.T) {
uri, _ := url.Parse("rediss://myredis/0?skipverify=true")
tlsConfig := getRedisTLSOptions(uri)
if !tlsConfig.InsecureSkipVerify {
t.Fail()
}
}
func TestInsecureSkipVerifyOpt(t *testing.T) {
uri, _ := url.Parse("rediss://myredis/0?insecureskipverify=true")
tlsConfig := getRedisTLSOptions(uri)
if !tlsConfig.InsecureSkipVerify {
t.Fail()
}
}
func TestRedisSentinelUsernameOpt(t *testing.T) {
uri, _ := url.Parse("redis+sentinel://redis:password@myredis/0?sentinelusername=suser&sentinelpassword=spass")
opts := getRedisOptions(uri).Failover()
if opts.SentinelUsername != "suser" {
t.Fail()
}
}
func TestRedisSentinelPasswordOpt(t *testing.T) {
uri, _ := url.Parse("redis+sentinel://redis:password@myredis/0?sentinelusername=suser&sentinelpassword=spass")
opts := getRedisOptions(uri).Failover()
if opts.SentinelPassword != "spass" {
t.Fail()
}
}
func TestRedisDatabaseIndexTcp(t *testing.T) {
uri, _ := url.Parse("redis://redis:password@myredis/12")
opts := getRedisOptions(uri)
if opts.DB != 12 {
t.Fail()
}
}
func TestRedisDatabaseIndexUnix(t *testing.T) {
uri, _ := url.Parse("redis+socket:///var/run/redis.sock?database=12")
opts := getRedisOptions(uri)
if opts.DB != 12 {
t.Fail()
func TestRedisOptions(t *testing.T) {
for _, test := range []struct {
name string
connection string
valid func(*url.URL) bool
}{
{"username", "redis://redis:password@myredis/0", func(uri *url.URL) bool { return getRedisOptions(uri).Username == "redis" }},
{"password", "redis://redis:password@myredis/0", func(uri *url.URL) bool { return getRedisOptions(uri).Password == "password" }},
{"skipverify", "rediss://myredis/0?skipverify=true", func(uri *url.URL) bool { return getRedisTLSOptions(uri).InsecureSkipVerify }},
{"insecureskipverify", "rediss://myredis/0?insecureskipverify=true", func(uri *url.URL) bool { return getRedisTLSOptions(uri).InsecureSkipVerify }},
{"sentinel username", "redis+sentinel://redis:password@myredis/0?sentinelusername=suser&sentinelpassword=spass", func(uri *url.URL) bool { return getRedisOptions(uri).Failover().SentinelUsername == "suser" }},
{"sentinel password", "redis+sentinel://redis:password@myredis/0?sentinelusername=suser&sentinelpassword=spass", func(uri *url.URL) bool { return getRedisOptions(uri).Failover().SentinelPassword == "spass" }},
{"tcp database", "redis://redis:password@myredis/12", func(uri *url.URL) bool { return getRedisOptions(uri).DB == 12 }},
{"unix database", "redis+socket:///var/run/redis.sock?database=12", func(uri *url.URL) bool { return getRedisOptions(uri).DB == 12 }},
} {
t.Run(test.name, func(t *testing.T) {
uri, _ := url.Parse(test.connection)
if !test.valid(uri) {
t.Fail()
}
})
}
}
+52 -100
View File
@@ -37,16 +37,22 @@ type testSerializationNullPointer struct {
OptNull optional.Option[*time.Time] `json:"opt_null,omitempty" yaml:"opt_null,omitempty"`
}
func TestOptionalToJson(t *testing.T) {
func TestOptionalToJsonAndYaml(t *testing.T) {
tests := []struct {
name string
obj *testSerializationStruct
want string
name string
obj *testSerializationStruct
want string
wantYaml string
}{
{
name: "empty",
obj: new(testSerializationStruct),
want: `{"normal_string":"","normal_bool":false,"optional_two_bool":null,"optional_two_string":null}`,
wantYaml: `normal_string: ""
normal_bool: false
optional_two_bool: null
optional_two_string: null
`,
},
{
name: "some",
@@ -59,6 +65,13 @@ func TestOptionalToJson(t *testing.T) {
OptTwoString: optional.None[string](),
},
want: `{"normal_string":"a string","normal_bool":true,"optional_bool":false,"optional_string":"","optional_two_bool":null,"optional_two_string":null}`,
wantYaml: `normal_string: a string
normal_bool: true
optional_bool: false
optional_string: ""
optional_two_bool: null
optional_two_string: null
`,
},
}
for _, tc := range tests {
@@ -70,6 +83,10 @@ func TestOptionalToJson(t *testing.T) {
b, err = std_json.Marshal(tc.obj)
assert.NoError(t, err)
assert.Equal(t, tc.want, string(b), "std json module returned unexpected")
b, err = yaml.Marshal(tc.obj)
assert.NoError(t, err)
assert.Equal(t, tc.wantYaml, string(b), "yaml module returned unexpected")
})
}
@@ -100,11 +117,12 @@ func TestOptionalToJson(t *testing.T) {
})
}
func TestOptionalFromJson(t *testing.T) {
func TestOptionalFromJsonAndYaml(t *testing.T) {
tests := []struct {
name string
data string
want testSerializationStruct
name string
data string
dataYaml string
want testSerializationStruct
}{
{
name: "empty",
@@ -116,94 +134,7 @@ func TestOptionalFromJson(t *testing.T) {
{
name: "some",
data: `{"normal_string":"a string","normal_bool":true,"optional_bool":false,"optional_string":"","optional_two_bool":null,"optional_two_string":null}`,
want: testSerializationStruct{
NormalString: "a string",
NormalBool: true,
OptBool: optional.Some(false),
OptString: optional.Some(""),
},
},
}
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
var obj1 testSerializationStruct
err := json.Unmarshal([]byte(tc.data), &obj1)
assert.NoError(t, err)
assert.Equal(t, tc.want, obj1, "gitea json module returned unexpected")
var obj2 testSerializationStruct
err = std_json.Unmarshal([]byte(tc.data), &obj2)
assert.NoError(t, err)
assert.Equal(t, tc.want, obj2, "std json module returned unexpected")
})
}
}
func TestOptionalToYaml(t *testing.T) {
tests := []struct {
name string
obj *testSerializationStruct
want string
}{
{
name: "empty",
obj: new(testSerializationStruct),
want: `normal_string: ""
normal_bool: false
optional_two_bool: null
optional_two_string: null
`,
},
{
name: "some",
obj: &testSerializationStruct{
NormalString: "a string",
NormalBool: true,
OptBool: optional.Some(false),
OptString: optional.Some(""),
},
want: `normal_string: a string
normal_bool: true
optional_bool: false
optional_string: ""
optional_two_bool: null
optional_two_string: null
`,
},
}
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
b, err := yaml.Marshal(tc.obj)
assert.NoError(t, err)
assert.Equal(t, tc.want, string(b), "yaml module returned unexpected")
})
}
}
func TestOptionalFromYaml(t *testing.T) {
tests := []struct {
name string
data string
want testSerializationStruct
}{
{
name: "empty",
data: ``,
want: testSerializationStruct{},
},
{
name: "empty but init",
data: `normal_string: ""
normal_bool: false
optional_bool:
optional_two_bool:
optional_two_string:
`,
want: testSerializationStruct{},
},
{
name: "some",
data: `
dataYaml: `
normal_string: a string
normal_bool: true
optional_bool: false
@@ -221,10 +152,31 @@ optional_two_string: null
}
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
var obj testSerializationStruct
err := yaml.Unmarshal([]byte(tc.data), &obj)
assert.NoError(t, err)
assert.Equal(t, tc.want, obj, "yaml module returned unexpected")
for _, format := range []struct {
data string
unmarshal func([]byte, any) error
message string
}{
{tc.data, json.Unmarshal, "gitea json module returned unexpected"},
{tc.data, std_json.Unmarshal, "std json module returned unexpected"},
{tc.dataYaml, yaml.Unmarshal, "yaml module returned unexpected"},
} {
var obj testSerializationStruct
err := format.unmarshal([]byte(format.data), &obj)
assert.NoError(t, err)
assert.Equal(t, tc.want, obj, format.message)
}
})
}
t.Run("empty but init", func(t *testing.T) {
var obj testSerializationStruct
err := yaml.Unmarshal([]byte(`normal_string: ""
normal_bool: false
optional_bool:
optional_two_bool:
optional_two_string:
`), &obj)
assert.NoError(t, err)
assert.Equal(t, testSerializationStruct{}, obj, "yaml module returned unexpected")
})
}
+30 -36
View File
@@ -22,43 +22,37 @@ const (
)
func TestParsePackage(t *testing.T) {
t.Run("MissingMetadataFile", func(t *testing.T) {
var buf bytes.Buffer
zw := gzip.NewWriter(&buf)
tw := tar.NewWriter(zw)
tw.Close()
zw.Close()
for _, name := range []string{"MissingMetadataFile", "Valid"} {
t.Run(name, func(t *testing.T) {
var buf bytes.Buffer
zw := gzip.NewWriter(&buf)
tw := tar.NewWriter(zw)
if name == "Valid" {
content := `{"name":"` + packageName + `","version":"` + packageVersion + `"}`
hdr := &tar.Header{
Name: packageName + "/metadata.json",
Mode: 0o600,
Size: int64(len(content)),
}
tw.WriteHeader(hdr)
tw.Write([]byte(content))
}
tw.Close()
zw.Close()
p, err := ParsePackage(&buf)
assert.Nil(t, p)
assert.ErrorIs(t, err, ErrMissingMetadataFile)
})
t.Run("Valid", func(t *testing.T) {
var buf bytes.Buffer
zw := gzip.NewWriter(&buf)
tw := tar.NewWriter(zw)
content := `{"name":"` + packageName + `","version":"` + packageVersion + `"}`
hdr := &tar.Header{
Name: packageName + "/metadata.json",
Mode: 0o600,
Size: int64(len(content)),
}
tw.WriteHeader(hdr)
tw.Write([]byte(content))
tw.Close()
zw.Close()
p, err := ParsePackage(&buf)
assert.NoError(t, err)
assert.NotNil(t, p)
assert.Equal(t, packageName, p.Name)
assert.Equal(t, packageVersion, p.Version)
assert.NotNil(t, p.Metadata)
})
p, err := ParsePackage(&buf)
if name == "MissingMetadataFile" {
assert.Nil(t, p)
assert.ErrorIs(t, err, ErrMissingMetadataFile)
} else {
assert.NoError(t, err)
assert.NotNil(t, p)
assert.Equal(t, packageName, p.Name)
assert.Equal(t, packageVersion, p.Version)
assert.NotNil(t, p.Metadata)
}
})
}
}
func TestParseChefMetadata(t *testing.T) {
+21 -38
View File
@@ -75,45 +75,28 @@ func TestCommentsUnmarshal(t *testing.T) {
}
func TestParsePackage(t *testing.T) {
t.Run("MissingComposerFile", func(t *testing.T) {
data := test.WriteZipArchive(map[string]string{"dummy.txt": ""}).Bytes()
for _, tc := range []struct {
name, filename, content string
expectedError error
}{
{"MissingComposerFile", "dummy.txt", "", ErrMissingComposerFile},
{"MissingComposerFileInRoot", "sub/sub/composer.json", "", ErrMissingComposerFile},
{"InvalidComposerFile", "composer.json", "", nil},
{"InvalidPackageName", "composer.json", "{}", ErrInvalidName},
{"InvalidPackageVersion", "composer.json", `{"name": "gitea/composer-package", "version": "1.a.3"}`, ErrInvalidVersion},
} {
t.Run(tc.name, func(t *testing.T) {
data := test.WriteZipArchive(map[string]string{tc.filename: tc.content}).Bytes()
cp, err := ParsePackage(bytes.NewReader(data))
assert.Nil(t, cp)
assert.ErrorIs(t, err, ErrMissingComposerFile)
})
t.Run("MissingComposerFileInRoot", func(t *testing.T) {
data := test.WriteZipArchive(map[string]string{"sub/sub/composer.json": ""}).Bytes()
cp, err := ParsePackage(bytes.NewReader(data))
assert.Nil(t, cp)
assert.ErrorIs(t, err, ErrMissingComposerFile)
})
t.Run("InvalidComposerFile", func(t *testing.T) {
data := test.WriteZipArchive(map[string]string{"composer.json": ""}).Bytes()
cp, err := ParsePackage(bytes.NewReader(data))
assert.Nil(t, cp)
assert.Error(t, err)
})
t.Run("InvalidPackageName", func(t *testing.T) {
data := test.WriteZipArchive(map[string]string{"composer.json": "{}"}).Bytes()
cp, err := ParsePackage(bytes.NewReader(data))
assert.Nil(t, cp)
assert.ErrorIs(t, err, ErrInvalidName)
})
t.Run("InvalidPackageVersion", func(t *testing.T) {
data := test.WriteZipArchive(map[string]string{"composer.json": `{"name": "gitea/composer-package", "version": "1.a.3"}`}).Bytes()
cp, err := ParsePackage(bytes.NewReader(data))
assert.Nil(t, cp)
assert.ErrorIs(t, err, ErrInvalidVersion)
})
cp, err := ParsePackage(bytes.NewReader(data))
assert.Nil(t, cp)
if tc.expectedError == nil {
assert.Error(t, err)
} else {
assert.ErrorIs(t, err, tc.expectedError)
}
})
}
t.Run("InvalidReadmePath", func(t *testing.T) {
data := test.WriteZipArchive(map[string]string{"composer.json": `{"name": "gitea/composer-package", "readme": "sub/README.md"}`}).Bytes()
+34 -62
View File
@@ -49,45 +49,25 @@ func TestNewRecipeReference(t *testing.T) {
}
func TestRecipeReferenceRevisionOrDefault(t *testing.T) {
rref, err := NewRecipeReference("name", "1.0", "", "", "")
assert.NoError(t, err)
assert.Equal(t, DefaultRevision, rref.RevisionOrDefault())
rref, err = NewRecipeReference("name", "1.0", "", "", DefaultRevision)
assert.NoError(t, err)
assert.Equal(t, DefaultRevision, rref.RevisionOrDefault())
rref, err = NewRecipeReference("name", "1.0", "", "", "Az09")
assert.NoError(t, err)
assert.Equal(t, "Az09", rref.RevisionOrDefault())
}
func TestRecipeReferenceString(t *testing.T) {
rref, err := NewRecipeReference("name", "1.0", "", "", "")
assert.NoError(t, err)
assert.Equal(t, "name/1.0", rref.String())
rref, err = NewRecipeReference("name", "1.0", "user", "channel", "")
assert.NoError(t, err)
assert.Equal(t, "name/1.0@user/channel", rref.String())
rref, err = NewRecipeReference("name", "1.0", "user", "channel", "Az09")
assert.NoError(t, err)
assert.Equal(t, "name/1.0@user/channel#Az09", rref.String())
}
func TestRecipeReferenceLinkName(t *testing.T) {
rref, err := NewRecipeReference("name", "1.0", "", "", "")
assert.NoError(t, err)
assert.Equal(t, "name/1.0/_/_/0", rref.LinkName())
rref, err = NewRecipeReference("name", "1.0", "user", "channel", "")
assert.NoError(t, err)
assert.Equal(t, "name/1.0/user/channel/0", rref.LinkName())
rref, err = NewRecipeReference("name", "1.0", "user", "channel", "Az09")
assert.NoError(t, err)
assert.Equal(t, "name/1.0/user/channel/Az09", rref.LinkName())
for _, test := range []struct {
user, channel, revision string
method func(*RecipeReference) string
expected string
}{
{"", "", "", (*RecipeReference).RevisionOrDefault, DefaultRevision},
{"", "", DefaultRevision, (*RecipeReference).RevisionOrDefault, DefaultRevision},
{"", "", "Az09", (*RecipeReference).RevisionOrDefault, "Az09"},
{"", "", "", (*RecipeReference).String, "name/1.0"},
{"user", "channel", "", (*RecipeReference).String, "name/1.0@user/channel"},
{"user", "channel", "Az09", (*RecipeReference).String, "name/1.0@user/channel#Az09"},
{"", "", "", (*RecipeReference).LinkName, "name/1.0/_/_/0"},
{"user", "channel", "", (*RecipeReference).LinkName, "name/1.0/user/channel/0"},
{"user", "channel", "Az09", (*RecipeReference).LinkName, "name/1.0/user/channel/Az09"},
} {
rref, err := NewRecipeReference("name", "1.0", test.user, test.channel, test.revision)
assert.NoError(t, err)
assert.Equal(t, test.expected, test.method(rref))
}
}
func TestNewPackageReference(t *testing.T) {
@@ -121,27 +101,19 @@ func TestNewPackageReference(t *testing.T) {
func TestPackageReferenceRevisionOrDefault(t *testing.T) {
rref, _ := NewRecipeReference("name", "1.0", "", "", "")
pref, err := NewPackageReference(rref, "ref", "")
assert.NoError(t, err)
assert.Equal(t, DefaultRevision, pref.RevisionOrDefault())
pref, err = NewPackageReference(rref, "ref", DefaultRevision)
assert.NoError(t, err)
assert.Equal(t, DefaultRevision, pref.RevisionOrDefault())
pref, err = NewPackageReference(rref, "ref", "Az09")
assert.NoError(t, err)
assert.Equal(t, "Az09", pref.RevisionOrDefault())
}
func TestPackageReferenceLinkName(t *testing.T) {
rref, _ := NewRecipeReference("name", "1.0", "", "", "")
pref, err := NewPackageReference(rref, "ref", "")
assert.NoError(t, err)
assert.Equal(t, "ref/0", pref.LinkName())
pref, err = NewPackageReference(rref, "ref", "Az09")
assert.NoError(t, err)
assert.Equal(t, "ref/Az09", pref.LinkName())
for _, test := range []struct {
revision string
method func(*PackageReference) string
expected string
}{
{"", (*PackageReference).RevisionOrDefault, DefaultRevision},
{DefaultRevision, (*PackageReference).RevisionOrDefault, DefaultRevision},
{"Az09", (*PackageReference).RevisionOrDefault, "Az09"},
{"", (*PackageReference).LinkName, "ref/0"},
{"Az09", (*PackageReference).LinkName, "ref/Az09"},
} {
pref, err := NewPackageReference(rref, "ref", test.revision)
assert.NoError(t, err)
assert.Equal(t, test.expected, test.method(pref))
}
}
+33 -57
View File
@@ -37,8 +37,11 @@ func createDescription(name, version string) *bytes.Buffer {
}
func TestParsePackage(t *testing.T) {
t.Run(".tar.gz", func(t *testing.T) {
createArchive := func(filename string, content []byte) *bytes.Reader {
for _, archive := range []struct {
extension string
create func(string, []byte) *bytes.Reader
}{
{".tar.gz", func(filename string, content []byte) *bytes.Reader {
var buf bytes.Buffer
gw := gzip.NewWriter(&buf)
tw := tar.NewWriter(gw)
@@ -52,70 +55,43 @@ func TestParsePackage(t *testing.T) {
tw.Close()
gw.Close()
return bytes.NewReader(buf.Bytes())
}
t.Run("MissingDescriptionFile", func(t *testing.T) {
buf := createArchive(
"dummy.txt",
[]byte{},
)
p, err := ParsePackage(buf, buf.Size())
assert.Nil(t, p)
assert.ErrorIs(t, err, ErrMissingDescriptionFile)
})
t.Run("Valid", func(t *testing.T) {
buf := createArchive(
"package/DESCRIPTION",
createDescription(packageName, packageVersion).Bytes(),
)
p, err := ParsePackage(buf, buf.Size())
assert.NotNil(t, p)
assert.NoError(t, err)
assert.Equal(t, packageName, p.Name)
assert.Equal(t, packageVersion, p.Version)
})
})
t.Run(".zip", func(t *testing.T) {
createArchive := func(filename string, content []byte) *bytes.Reader {
}},
{".zip", func(filename string, content []byte) *bytes.Reader {
var buf bytes.Buffer
archive := zip.NewWriter(&buf)
w, _ := archive.Create(filename)
w.Write(content)
archive.Close()
return bytes.NewReader(buf.Bytes())
}
}},
} {
t.Run(archive.extension, func(t *testing.T) {
t.Run("MissingDescriptionFile", func(t *testing.T) {
buf := archive.create(
"dummy.txt",
[]byte{},
)
t.Run("MissingDescriptionFile", func(t *testing.T) {
buf := createArchive(
"dummy.txt",
[]byte{},
)
p, err := ParsePackage(buf, buf.Size())
assert.Nil(t, p)
assert.ErrorIs(t, err, ErrMissingDescriptionFile)
})
p, err := ParsePackage(buf, buf.Size())
assert.Nil(t, p)
assert.ErrorIs(t, err, ErrMissingDescriptionFile)
t.Run("Valid", func(t *testing.T) {
buf := archive.create(
"package/DESCRIPTION",
createDescription(packageName, packageVersion).Bytes(),
)
p, err := ParsePackage(buf, buf.Size())
assert.NotNil(t, p)
assert.NoError(t, err)
assert.Equal(t, packageName, p.Name)
assert.Equal(t, packageVersion, p.Version)
})
})
t.Run("Valid", func(t *testing.T) {
buf := createArchive(
"package/DESCRIPTION",
createDescription(packageName, packageVersion).Bytes(),
)
p, err := ParsePackage(buf, buf.Size())
assert.NotNil(t, p)
assert.NoError(t, err)
assert.Equal(t, packageName, p.Name)
assert.Equal(t, packageVersion, p.Version)
})
})
}
}
func TestParseDescription(t *testing.T) {
+3 -10
View File
@@ -110,21 +110,14 @@ func TestParsePackage(t *testing.T) {
w.Write(buf.Bytes())
w.Close()
data := createArchive(map[string][]byte{"control.tar" + c.Extension: cbuf.Bytes()})
p, err := ParsePackage(data)
assert.NotNil(t, p)
assert.NoError(t, err)
assert.Equal(t, "gitea", p.Name)
t.Run("TrailingSlash", func(t *testing.T) {
data := createArchive(map[string][]byte{"control.tar" + c.Extension + "/": cbuf.Bytes()})
for _, suffix := range []string{"", "/"} {
data := createArchive(map[string][]byte{"control.tar" + c.Extension + suffix: cbuf.Bytes()})
p, err := ParsePackage(data)
assert.NotNil(t, p)
assert.NoError(t, err)
assert.Equal(t, "gitea", p.Name)
})
}
})
}
})
+31 -48
View File
@@ -28,58 +28,41 @@ func TestParsePackage(t *testing.T) {
return bytes.NewReader(buf.Bytes())
}
t.Run("EmptyPackage", func(t *testing.T) {
data := createArchive(nil)
p, err := ParsePackage(data, int64(data.Len()))
assert.Nil(t, p)
assert.ErrorIs(t, err, ErrInvalidStructure)
})
t.Run("InvalidNameOrVersionStructure", func(t *testing.T) {
data := createArchive(map[string][]byte{
for _, testCase := range []struct {
name string
files map[string][]byte
expectedError error
goMod string
}{
{"EmptyPackage", nil, ErrInvalidStructure, ""},
{"InvalidNameOrVersionStructure", map[string][]byte{
packageName + "/" + packageVersion + "/go.mod": {},
})
p, err := ParsePackage(data, int64(data.Len()))
assert.Nil(t, p)
assert.ErrorIs(t, err, ErrInvalidStructure)
})
t.Run("GoModFileInWrongDirectory", func(t *testing.T) {
data := createArchive(map[string][]byte{
}, ErrInvalidStructure, ""},
{"GoModFileInWrongDirectory", map[string][]byte{
packageName + "@" + packageVersion + "/subdir/go.mod": {},
})
p, err := ParsePackage(data, int64(data.Len()))
assert.NotNil(t, p)
assert.NoError(t, err)
assert.Equal(t, packageName, p.Name)
assert.Equal(t, packageVersion, p.Version)
assert.Equal(t, "module gitea.com/go-gitea/gitea", p.GoMod)
})
t.Run("InvalidVersion", func(t *testing.T) {
data := createArchive(map[string][]byte{
}, nil, "module gitea.com/go-gitea/gitea"},
{"InvalidVersion", map[string][]byte{
packageName + "@v1.0.0\nv99.0.0/go.mod": []byte("module " + packageName),
})
p, err := ParsePackage(data, int64(data.Len()))
assert.Nil(t, p)
assert.ErrorIs(t, err, ErrInvalidVersion)
})
t.Run("Valid", func(t *testing.T) {
data := createArchive(map[string][]byte{
}, ErrInvalidVersion, ""},
{"Valid", map[string][]byte{
packageName + "@" + packageVersion + "/subdir/go.mod": []byte("invalid"),
packageName + "@" + packageVersion + "/go.mod": []byte("valid"),
})
}, nil, "valid"},
} {
t.Run(testCase.name, func(t *testing.T) {
data := createArchive(testCase.files)
p, err := ParsePackage(data, int64(data.Len()))
assert.NotNil(t, p)
assert.NoError(t, err)
assert.Equal(t, packageName, p.Name)
assert.Equal(t, packageVersion, p.Version)
assert.Equal(t, "valid", p.GoMod)
})
p, err := ParsePackage(data, int64(data.Len()))
if testCase.expectedError != nil {
assert.Nil(t, p)
assert.ErrorIs(t, err, testCase.expectedError)
} else {
assert.NotNil(t, p)
assert.NoError(t, err)
assert.Equal(t, packageName, p.Name)
assert.Equal(t, packageVersion, p.Version)
assert.Equal(t, testCase.goMod, p.GoMod)
}
})
}
}
+19 -27
View File
@@ -18,36 +18,28 @@ const (
)
func TestMultiHasherSums(t *testing.T) {
t.Run("Sums", func(t *testing.T) {
h := NewMultiHasher()
h.Write([]byte("gitea"))
for _, content := range []string{"gitea", "git"} {
t.Run(content, func(t *testing.T) {
h := NewMultiHasher()
h.Write([]byte(content))
hashMD5, hashSHA1, hashSHA256, hashSHA512 := h.Sums()
if content == "git" {
state, err := h.MarshalBinary()
assert.NoError(t, err)
assert.Equal(t, expectedMD5, hex.EncodeToString(hashMD5))
assert.Equal(t, expectedSHA1, hex.EncodeToString(hashSHA1))
assert.Equal(t, expectedSHA256, hex.EncodeToString(hashSHA256))
assert.Equal(t, expectedSHA512, hex.EncodeToString(hashSHA512))
})
h = NewMultiHasher()
err = h.UnmarshalBinary(state)
assert.NoError(t, err)
t.Run("State", func(t *testing.T) {
h := NewMultiHasher()
h.Write([]byte("git"))
h.Write([]byte("ea"))
}
state, err := h.MarshalBinary()
assert.NoError(t, err)
hashMD5, hashSHA1, hashSHA256, hashSHA512 := h.Sums()
h2 := NewMultiHasher()
err = h2.UnmarshalBinary(state)
assert.NoError(t, err)
h2.Write([]byte("ea"))
hashMD5, hashSHA1, hashSHA256, hashSHA512 := h2.Sums()
assert.Equal(t, expectedMD5, hex.EncodeToString(hashMD5))
assert.Equal(t, expectedSHA1, hex.EncodeToString(hashSHA1))
assert.Equal(t, expectedSHA256, hex.EncodeToString(hashSHA256))
assert.Equal(t, expectedSHA512, hex.EncodeToString(hashSHA512))
})
assert.Equal(t, expectedMD5, hex.EncodeToString(hashMD5))
assert.Equal(t, expectedSHA1, hex.EncodeToString(hashSHA1))
assert.Equal(t, expectedSHA256, hex.EncodeToString(hashSHA256))
assert.Equal(t, expectedSHA512, hex.EncodeToString(hashSHA512))
})
}
}
+60 -159
View File
@@ -52,71 +52,38 @@ func TestParsePackage(t *testing.T) {
assert.ErrorIs(t, err, ErrInvalidPackage)
})
t.Run("InvalidPackageName", func(t *testing.T) {
test := func(t *testing.T, name string) {
p, err := parseUploadPackage(&packageUpload{
PackageMetadata: PackageMetadata{
ID: name,
Name: name,
Versions: map[string]*PackageMetadataVersion{
packageVersion: {
Name: name,
for _, testCase := range []struct {
name string
names []string
expectedError error
}{
{"InvalidPackageName", []string{
" test ", " test", "test ", "te st", "Test", "_test", ".test", "^test", "te^st",
"te|st", "te)(st", "te'st", "te!st", "te*st", "te~st", "invalid/scope", "@invalid/_name", "@invalid/.name",
}, ErrInvalidPackageName},
{"ValidPackageName", []string{
"test", "@scope/name", "@scope/q", "q", "@scope/package-name", "@scope/package.name", "@scope/package_name",
"123name", "----", packageFullName,
}, ErrInvalidPackageVersion},
} {
t.Run(testCase.name, func(t *testing.T) {
for _, name := range testCase.names {
p, err := parseUploadPackage(&packageUpload{
PackageMetadata: PackageMetadata{
ID: name,
Name: name,
Versions: map[string]*PackageMetadataVersion{
packageVersion: {
Name: name,
},
},
},
},
})
assert.Nil(t, p)
assert.ErrorIs(t, err, ErrInvalidPackageName)
}
test(t, " test ")
test(t, " test")
test(t, "test ")
test(t, "te st")
test(t, "Test")
test(t, "_test")
test(t, ".test")
test(t, "^test")
test(t, "te^st")
test(t, "te|st")
test(t, "te)(st")
test(t, "te'st")
test(t, "te!st")
test(t, "te*st")
test(t, "te~st")
test(t, "invalid/scope")
test(t, "@invalid/_name")
test(t, "@invalid/.name")
})
t.Run("ValidPackageName", func(t *testing.T) {
test := func(t *testing.T, name string) {
p, err := parseUploadPackage(&packageUpload{
PackageMetadata: PackageMetadata{
ID: name,
Name: name,
Versions: map[string]*PackageMetadataVersion{
packageVersion: {
Name: name,
},
},
},
})
assert.Nil(t, p)
assert.ErrorIs(t, err, ErrInvalidPackageVersion)
}
test(t, "test")
test(t, "@scope/name")
test(t, "@scope/q")
test(t, "q")
test(t, "@scope/package-name")
test(t, "@scope/package.name")
test(t, "@scope/package_name")
test(t, "123name")
test(t, "----")
test(t, packageFullName)
})
})
assert.Nil(t, p)
assert.ErrorIs(t, err, testCase.expectedError)
}
})
}
t.Run("InvalidPackageVersion", func(t *testing.T) {
version := "first-version"
@@ -136,108 +103,42 @@ func TestParsePackage(t *testing.T) {
assert.ErrorIs(t, err, ErrInvalidPackageVersion)
})
t.Run("InvalidAttachment", func(t *testing.T) {
b, _ := json.Marshal(packageUpload{
PackageMetadata: PackageMetadata{
ID: packageFullName,
Name: packageFullName,
Versions: map[string]*PackageMetadataVersion{
packageVersion: {
Name: packageFullName,
Version: packageVersion,
},
},
},
Attachments: map[string]*PackageAttachment{
"dummy.tgz": {},
},
})
p, _, err := ParseUpload(bytes.NewReader(b))
assert.Nil(t, p)
assert.ErrorIs(t, err, ErrInvalidAttachment)
})
t.Run("InvalidData", func(t *testing.T) {
filename := fmt.Sprintf("%s-%s.tgz", packageFullName, packageVersion)
b, _ := json.Marshal(packageUpload{
PackageMetadata: PackageMetadata{
ID: packageFullName,
Name: packageFullName,
Versions: map[string]*PackageMetadataVersion{
packageVersion: {
Name: packageFullName,
Version: packageVersion,
},
},
},
Attachments: map[string]*PackageAttachment{
filename: {
Data: "/",
},
},
})
p, _, err := ParseUpload(bytes.NewReader(b))
assert.Nil(t, p)
assert.ErrorIs(t, err, ErrInvalidAttachment)
})
t.Run("InvalidIntegrity", func(t *testing.T) {
filename := fmt.Sprintf("%s-%s.tgz", packageFullName, packageVersion)
b, _ := json.Marshal(packageUpload{
PackageMetadata: PackageMetadata{
ID: packageFullName,
Name: packageFullName,
Versions: map[string]*PackageMetadataVersion{
packageVersion: {
Name: packageFullName,
Version: packageVersion,
Dist: PackageDistribution{
Integrity: "sha512-test==",
for _, testCase := range []struct {
name, filename, data, integrity string
expectedError error
}{
{"InvalidAttachment", "dummy.tgz", "", "", ErrInvalidAttachment},
{"InvalidData", fmt.Sprintf("%s-%s.tgz", packageFullName, packageVersion), "/", "", ErrInvalidAttachment},
{"InvalidIntegrity", fmt.Sprintf("%s-%s.tgz", packageFullName, packageVersion), data, "sha512-test==", ErrInvalidIntegrity},
{"InvalidIntegrity2", fmt.Sprintf("%s-%s.tgz", packageFullName, packageVersion), base64.StdEncoding.EncodeToString([]byte("data")), integrity, ErrInvalidIntegrity},
} {
t.Run(testCase.name, func(t *testing.T) {
b, _ := json.Marshal(packageUpload{
PackageMetadata: PackageMetadata{
ID: packageFullName,
Name: packageFullName,
Versions: map[string]*PackageMetadataVersion{
packageVersion: {
Name: packageFullName,
Version: packageVersion,
Dist: PackageDistribution{
Integrity: testCase.integrity,
},
},
},
},
},
Attachments: map[string]*PackageAttachment{
filename: {
Data: data,
},
},
})
p, _, err := ParseUpload(bytes.NewReader(b))
assert.Nil(t, p)
assert.ErrorIs(t, err, ErrInvalidIntegrity)
})
t.Run("InvalidIntegrity2", func(t *testing.T) {
filename := fmt.Sprintf("%s-%s.tgz", packageFullName, packageVersion)
b, _ := json.Marshal(packageUpload{
PackageMetadata: PackageMetadata{
ID: packageFullName,
Name: packageFullName,
Versions: map[string]*PackageMetadataVersion{
packageVersion: {
Name: packageFullName,
Version: packageVersion,
Dist: PackageDistribution{
Integrity: integrity,
},
Attachments: map[string]*PackageAttachment{
testCase.filename: {
Data: testCase.data,
},
},
},
Attachments: map[string]*PackageAttachment{
filename: {
Data: base64.StdEncoding.EncodeToString([]byte("data")),
},
},
})
})
p, _, err := ParseUpload(bytes.NewReader(b))
assert.Nil(t, p)
assert.ErrorIs(t, err, ErrInvalidIntegrity)
})
p, _, err := ParseUpload(bytes.NewReader(b))
assert.Nil(t, p)
assert.ErrorIs(t, err, testCase.expectedError)
})
}
t.Run("Valid", func(t *testing.T) {
filename := fmt.Sprintf("%s-%s.tgz", packageFullName, packageVersion)
+24 -40
View File
@@ -92,53 +92,37 @@ func TestParsePackageMetaData(t *testing.T) {
return buf.Bytes()
}
t.Run("MissingNuspecFile", func(t *testing.T) {
data := createArchive(map[string]string{"dummy.txt": ""})
np, err := ParsePackageMetaData(bytes.NewReader(data), int64(len(data)))
assert.Nil(t, np)
assert.ErrorIs(t, err, ErrMissingNuspecFile)
})
t.Run("MissingNuspecFileInRoot", func(t *testing.T) {
data := createArchive(map[string]string{"sub/package.nuspec": ""})
np, err := ParsePackageMetaData(bytes.NewReader(data), int64(len(data)))
assert.Nil(t, np)
assert.ErrorIs(t, err, ErrMissingNuspecFile)
})
t.Run("InvalidNuspecFile", func(t *testing.T) {
data := createArchive(map[string]string{"package.nuspec": ""})
np, err := ParsePackageMetaData(bytes.NewReader(data), int64(len(data)))
assert.Nil(t, np)
assert.Error(t, err)
})
t.Run("InvalidPackageId", func(t *testing.T) {
data := createArchive(map[string]string{"package.nuspec": `<?xml version="1.0" encoding="utf-8"?>
for _, testCase := range []struct {
name string
files map[string]string
expectedError error
}{
{"MissingNuspecFile", map[string]string{"dummy.txt": ""}, ErrMissingNuspecFile},
{"MissingNuspecFileInRoot", map[string]string{"sub/package.nuspec": ""}, ErrMissingNuspecFile},
{"InvalidNuspecFile", map[string]string{"package.nuspec": ""}, nil},
{"InvalidPackageId", map[string]string{"package.nuspec": `<?xml version="1.0" encoding="utf-8"?>
<package xmlns="http://schemas.microsoft.com/packaging/2013/05/nuspec.xsd">
<metadata></metadata>
</package>`})
np, err := ParsePackageMetaData(bytes.NewReader(data), int64(len(data)))
assert.Nil(t, np)
assert.ErrorIs(t, err, ErrNuspecInvalidID)
})
t.Run("InvalidPackageVersion", func(t *testing.T) {
data := createArchive(map[string]string{"package.nuspec": `<?xml version="1.0" encoding="utf-8"?>
</package>`}, ErrNuspecInvalidID},
{"InvalidPackageVersion", map[string]string{"package.nuspec": `<?xml version="1.0" encoding="utf-8"?>
<package xmlns="http://schemas.microsoft.com/packaging/2013/05/nuspec.xsd">
<metadata>
<id>` + id + `</id>
</metadata>
</package>`})
</package>`}, ErrNuspecInvalidVersion},
} {
t.Run(testCase.name, func(t *testing.T) {
data := createArchive(testCase.files)
np, err := ParsePackageMetaData(bytes.NewReader(data), int64(len(data)))
assert.Nil(t, np)
assert.ErrorIs(t, err, ErrNuspecInvalidVersion)
})
np, err := ParsePackageMetaData(bytes.NewReader(data), int64(len(data)))
assert.Nil(t, np)
if testCase.expectedError == nil {
assert.Error(t, err)
} else {
assert.ErrorIs(t, err, testCase.expectedError)
}
})
}
t.Run("MissingReadme", func(t *testing.T) {
data := createArchive(map[string]string{"package.nuspec": nuspecContent})
+16 -43
View File
@@ -110,49 +110,22 @@ OvSXaRmpzyTLHvsXg/M9EcwbAAA=`
},
p.FileMetadata.Provides,
)
assert.ElementsMatch(
t,
[]*Entry{
{
Name: "/bin/sh",
},
{
Name: "/bin/sh",
},
{
Name: "/bin/sh",
},
{
Name: "rpmlib(CompressedFileNames)",
Flags: "LE",
Version: "3.0.4",
Epoch: "0",
Release: "1",
},
{
Name: "rpmlib(FileDigests)",
Flags: "LE",
Version: "4.6.0",
Epoch: "0",
Release: "1",
},
{
Name: "rpmlib(PayloadFilesHavePrefix)",
Flags: "LE",
Version: "4.0",
Epoch: "0",
Release: "1",
},
{
Name: "rpmlib(PayloadIsXz)",
Flags: "LE",
Version: "5.2",
Epoch: "0",
Release: "1",
},
},
p.FileMetadata.Requires,
)
requires := []*Entry{{Name: "/bin/sh"}, {Name: "/bin/sh"}, {Name: "/bin/sh"}}
for _, dependency := range []struct{ name, version string }{
{"rpmlib(CompressedFileNames)", "3.0.4"},
{"rpmlib(FileDigests)", "4.6.0"},
{"rpmlib(PayloadFilesHavePrefix)", "4.0"},
{"rpmlib(PayloadIsXz)", "5.2"},
} {
requires = append(requires, &Entry{
Name: dependency.name,
Flags: "LE",
Version: dependency.version,
Epoch: "0",
Release: "1",
})
}
assert.ElementsMatch(t, requires, p.FileMetadata.Requires)
assert.ElementsMatch(
t,
[]*File{
+16 -63
View File
@@ -164,15 +164,15 @@ func TestParsePackage(t *testing.T) {
assert.Equal(t, contentA, p.Metadata.Manifests[""].Content)
})
t.Run("WithMetadata", func(t *testing.T) {
parseWithMetadata := func(metadata string) (*Package, error) {
data := test.WriteZipArchive(map[string]string{
"Package.swift": "// swift-tools-version:5.7\n//\n// Package.swift",
})
return ParsePackage(bytes.NewReader(data.Bytes()), int64(data.Len()), strings.NewReader(metadata))
}
p, err := ParsePackage(
bytes.NewReader(data.Bytes()), int64(data.Len()),
strings.NewReader(`{"name":"`+packageName+`","version":"`+packageVersion+`","description":"`+packageDescription+`","keywords":["swift","package"],"license":"`+packageLicense+`","licenseURL":"`+packageLicenseURL+`","codeRepository":"`+packageRepositoryURL+`","author":{"givenName":"`+packageAuthor+`"},"repositoryURLs":["`+packageRepositoryURL+`"]}`),
)
t.Run("WithMetadata", func(t *testing.T) {
p, err := parseWithMetadata(`{"name":"` + packageName + `","version":"` + packageVersion + `","description":"` + packageDescription + `","keywords":["swift","package"],"license":"` + packageLicense + `","licenseURL":"` + packageLicenseURL + `","codeRepository":"` + packageRepositoryURL + `","author":{"givenName":"` + packageAuthor + `"},"repositoryURLs":["` + packageRepositoryURL + `"]}`)
assert.NotNil(t, p)
assert.NoError(t, err)
@@ -192,15 +192,8 @@ func TestParsePackage(t *testing.T) {
})
t.Run("WithExplicitNameField", func(t *testing.T) {
data := test.WriteZipArchive(map[string]string{
"Package.swift": "// swift-tools-version:5.7\n//\n// Package.swift",
})
authorName := "John Doe"
p, err := ParsePackage(
bytes.NewReader(data.Bytes()), int64(data.Len()),
strings.NewReader(`{"name":"`+packageName+`","version":"`+packageVersion+`","description":"`+packageDescription+`","author":{"name":"`+authorName+`","givenName":"John","familyName":"Doe"}}`),
)
p, err := parseWithMetadata(`{"name":"` + packageName + `","version":"` + packageVersion + `","description":"` + packageDescription + `","author":{"name":"` + authorName + `","givenName":"John","familyName":"Doe"}}`)
assert.NotNil(t, p)
assert.NoError(t, err)
@@ -210,14 +203,7 @@ func TestParsePackage(t *testing.T) {
})
t.Run("WithEmptyJSONMetadata", func(t *testing.T) {
data := test.WriteZipArchive(map[string]string{
"Package.swift": "// swift-tools-version:5.7\n//\n// Package.swift",
})
p, err := ParsePackage(
bytes.NewReader(data.Bytes()), int64(data.Len()),
strings.NewReader(`{}`),
)
p, err := parseWithMetadata(`{}`)
assert.NotNil(t, p)
assert.NoError(t, err)
assert.NotNil(t, p.Metadata)
@@ -226,15 +212,8 @@ func TestParsePackage(t *testing.T) {
})
t.Run("NameFieldGeneration", func(t *testing.T) {
data := test.WriteZipArchive(map[string]string{
"Package.swift": "// swift-tools-version:5.7\n//\n// Package.swift",
})
// Test with only individual name components - Name should be auto-generated
p, err := ParsePackage(
bytes.NewReader(data.Bytes()), int64(data.Len()),
strings.NewReader(`{"author":{"givenName":"John","middleName":"Q","familyName":"Doe"}}`),
)
p, err := parseWithMetadata(`{"author":{"givenName":"John","middleName":"Q","familyName":"Doe"}}`)
assert.NotNil(t, p)
assert.NoError(t, err)
assert.Equal(t, "John Q Doe", p.Metadata.Author.Name)
@@ -245,42 +224,16 @@ func TestParsePackage(t *testing.T) {
}
func TestTrimmedVersionString(t *testing.T) {
cases := []struct {
Version *version.Version
for _, c := range []struct {
Versions []string
Expected string
}{
{
Version: version.Must(version.NewVersion("1")),
Expected: "1.0",
},
{
Version: version.Must(version.NewVersion("1.0")),
Expected: "1.0",
},
{
Version: version.Must(version.NewVersion("1.0.0")),
Expected: "1.0",
},
{
Version: version.Must(version.NewVersion("1.0.1")),
Expected: "1.0.1",
},
{
Version: version.Must(version.NewVersion("1.0+meta")),
Expected: "1.0",
},
{
Version: version.Must(version.NewVersion("1.0.0+meta")),
Expected: "1.0",
},
{
Version: version.Must(version.NewVersion("1.0.1+meta")),
Expected: "1.0.1",
},
}
for _, c := range cases {
assert.Equal(t, c.Expected, TrimmedVersionString(c.Version))
{[]string{"1", "1.0", "1.0.0", "1.0+meta", "1.0.0+meta"}, "1.0"},
{[]string{"1.0.1", "1.0.1+meta"}, "1.0.1"},
} {
for _, input := range c.Versions {
assert.Equal(t, c.Expected, TrimmedVersionString(version.Must(version.NewVersion(input))))
}
}
}
+26 -40
View File
@@ -49,29 +49,6 @@ func TestParseMetadataFromBox(t *testing.T) {
assert.NoError(t, err)
})
t.Run("Valid", func(t *testing.T) {
content, err := json.Marshal(map[string]string{
"description": description,
"author": author,
"website": projectURL,
"repository": repositoryURL,
})
assert.NoError(t, err)
data := createArchive(map[string][]byte{"info.json": content})
metadata, err := ParseMetadataFromBox(data)
assert.NotNil(t, metadata)
assert.NoError(t, err)
assert.Equal(t, author, metadata.Author)
assert.Equal(t, description, metadata.Description)
assert.Equal(t, projectURL, metadata.ProjectURL)
assert.Equal(t, repositoryURL, metadata.RepositoryURL)
})
}
func TestParseInfoFile(t *testing.T) {
t.Run("UnknownKeys", func(t *testing.T) {
content, err := json.Marshal(map[string]string{
"package": "",
@@ -89,22 +66,31 @@ func TestParseInfoFile(t *testing.T) {
assert.Empty(t, metadata.RepositoryURL)
})
t.Run("Valid", func(t *testing.T) {
content, err := json.Marshal(map[string]string{
"description": description,
"author": author,
"website": projectURL,
"repository": repositoryURL,
for name, parse := range map[string]func([]byte) (*Metadata, error){
"ValidBox": func(content []byte) (*Metadata, error) {
return ParseMetadataFromBox(createArchive(map[string][]byte{"info.json": content}))
},
"ValidInfoFile": func(content []byte) (*Metadata, error) {
return ParseInfoFile(bytes.NewReader(content))
},
} {
t.Run(name, func(t *testing.T) {
content, err := json.Marshal(map[string]string{
"description": description,
"author": author,
"website": projectURL,
"repository": repositoryURL,
})
assert.NoError(t, err)
metadata, err := parse(content)
assert.NotNil(t, metadata)
assert.NoError(t, err)
assert.Equal(t, author, metadata.Author)
assert.Equal(t, description, metadata.Description)
assert.Equal(t, projectURL, metadata.ProjectURL)
assert.Equal(t, repositoryURL, metadata.RepositoryURL)
})
assert.NoError(t, err)
metadata, err := ParseInfoFile(bytes.NewReader(content))
assert.NotNil(t, metadata)
assert.NoError(t, err)
assert.Equal(t, author, metadata.Author)
assert.Equal(t, description, metadata.Description)
assert.Equal(t, projectURL, metadata.ProjectURL)
assert.Equal(t, repositoryURL, metadata.RepositoryURL)
})
}
}
+30 -185
View File
@@ -85,226 +85,71 @@ func TestPaginator(t *testing.T) {
assert.True(t, pages[0].IsCurrent())
})
assertPages := func(t *testing.T, total, current, numPages int, expected ...int) {
pages := New(total, 10, current, numPages).Pages()
assert.Len(t, pages, len(expected))
for i, number := range expected {
assert.Equal(t, number, pages[i].Num())
if number == current {
assert.True(t, pages[i].IsCurrent())
} else {
assert.False(t, pages[i].IsCurrent())
}
}
}
t.Run("Total page number is less or equal", func(t *testing.T) {
p := New(1, 10, 1, 2)
pages := p.Pages()
assert.Len(t, pages, 1)
assert.Equal(t, 1, pages[0].Num())
assert.True(t, pages[0].IsCurrent())
assertPages(t, 1, 1, 2, 1)
p = New(11, 10, 1, 2)
pages = p.Pages()
assert.Len(t, pages, 2)
assert.Equal(t, 1, pages[0].Num())
assert.True(t, pages[0].IsCurrent())
assert.Equal(t, 2, pages[1].Num())
assert.False(t, pages[1].IsCurrent())
assertPages(t, 11, 1, 2, 1, 2)
p = New(11, 10, 2, 2)
pages = p.Pages()
assert.Len(t, pages, 2)
assert.Equal(t, 1, pages[0].Num())
assert.False(t, pages[0].IsCurrent())
assert.Equal(t, 2, pages[1].Num())
assert.True(t, pages[1].IsCurrent())
assertPages(t, 11, 2, 2, 1, 2)
p = New(25, 10, 2, 3)
pages = p.Pages()
assert.Len(t, pages, 3)
assert.Equal(t, 1, pages[0].Num())
assert.False(t, pages[0].IsCurrent())
assert.Equal(t, 2, pages[1].Num())
assert.True(t, pages[1].IsCurrent())
assert.Equal(t, 3, pages[2].Num())
assert.False(t, pages[2].IsCurrent())
assertPages(t, 25, 2, 3, 1, 2, 3)
})
t.Run("Has more previous pages ", func(t *testing.T) {
// ... 2
p := New(11, 10, 2, 1)
pages := p.Pages()
assert.Len(t, pages, 2)
assert.Equal(t, -1, pages[0].Num())
assert.False(t, pages[0].IsCurrent())
assert.Equal(t, 2, pages[1].Num())
assert.True(t, pages[1].IsCurrent())
assertPages(t, 11, 2, 1, -1, 2)
// ... 2 3
p = New(21, 10, 2, 2)
pages = p.Pages()
assert.Len(t, pages, 3)
assert.Equal(t, -1, pages[0].Num())
assert.False(t, pages[0].IsCurrent())
assert.Equal(t, 2, pages[1].Num())
assert.True(t, pages[1].IsCurrent())
assert.Equal(t, 3, pages[2].Num())
assert.False(t, pages[2].IsCurrent())
assertPages(t, 21, 2, 2, -1, 2, 3)
// ... 2 3 4
p = New(31, 10, 3, 3)
pages = p.Pages()
assert.Len(t, pages, 4)
assert.Equal(t, -1, pages[0].Num())
assert.False(t, pages[0].IsCurrent())
assert.Equal(t, 2, pages[1].Num())
assert.False(t, pages[1].IsCurrent())
assert.Equal(t, 3, pages[2].Num())
assert.True(t, pages[2].IsCurrent())
assert.Equal(t, 4, pages[3].Num())
assert.False(t, pages[3].IsCurrent())
assertPages(t, 31, 3, 3, -1, 2, 3, 4)
// ... 3 4 5
p = New(41, 10, 4, 3)
pages = p.Pages()
assert.Len(t, pages, 4)
assert.Equal(t, -1, pages[0].Num())
assert.False(t, pages[0].IsCurrent())
assert.Equal(t, 3, pages[1].Num())
assert.False(t, pages[1].IsCurrent())
assert.Equal(t, 4, pages[2].Num())
assert.True(t, pages[2].IsCurrent())
assert.Equal(t, 5, pages[3].Num())
assert.False(t, pages[3].IsCurrent())
assertPages(t, 41, 4, 3, -1, 3, 4, 5)
// ... 4 5 6 7 8 9 10
p = New(100, 10, 9, 7)
pages = p.Pages()
assert.Len(t, pages, 8)
assert.Equal(t, -1, pages[0].Num())
assert.False(t, pages[0].IsCurrent())
assert.Equal(t, 4, pages[1].Num())
assert.False(t, pages[1].IsCurrent())
assert.Equal(t, 5, pages[2].Num())
assert.False(t, pages[2].IsCurrent())
assert.Equal(t, 6, pages[3].Num())
assert.False(t, pages[3].IsCurrent())
assert.Equal(t, 7, pages[4].Num())
assert.False(t, pages[4].IsCurrent())
assert.Equal(t, 8, pages[5].Num())
assert.False(t, pages[5].IsCurrent())
assert.Equal(t, 9, pages[6].Num())
assert.True(t, pages[6].IsCurrent())
assert.Equal(t, 10, pages[7].Num())
assert.False(t, pages[7].IsCurrent())
assertPages(t, 100, 9, 7, -1, 4, 5, 6, 7, 8, 9, 10)
})
t.Run("Has more next pages", func(t *testing.T) {
// 1 ...
p := New(21, 10, 1, 1)
pages := p.Pages()
assert.Len(t, pages, 2)
assert.Equal(t, 1, pages[0].Num())
assert.True(t, pages[0].IsCurrent())
assert.Equal(t, -1, pages[1].Num())
assert.False(t, pages[1].IsCurrent())
assertPages(t, 21, 1, 1, 1, -1)
// 1 2 ...
p = New(21, 10, 1, 2)
pages = p.Pages()
assert.Len(t, pages, 3)
assert.Equal(t, 1, pages[0].Num())
assert.True(t, pages[0].IsCurrent())
assert.Equal(t, 2, pages[1].Num())
assert.False(t, pages[1].IsCurrent())
assert.Equal(t, -1, pages[2].Num())
assert.False(t, pages[2].IsCurrent())
assertPages(t, 21, 1, 2, 1, 2, -1)
// 1 2 3 ...
p = New(31, 10, 2, 3)
pages = p.Pages()
assert.Len(t, pages, 4)
assert.Equal(t, 1, pages[0].Num())
assert.False(t, pages[0].IsCurrent())
assert.Equal(t, 2, pages[1].Num())
assert.True(t, pages[1].IsCurrent())
assert.Equal(t, 3, pages[2].Num())
assert.False(t, pages[2].IsCurrent())
assert.Equal(t, -1, pages[3].Num())
assert.False(t, pages[3].IsCurrent())
assertPages(t, 31, 2, 3, 1, 2, 3, -1)
// 1 2 3 ...
p = New(41, 10, 2, 3)
pages = p.Pages()
assert.Len(t, pages, 4)
assert.Equal(t, 1, pages[0].Num())
assert.False(t, pages[0].IsCurrent())
assert.Equal(t, 2, pages[1].Num())
assert.True(t, pages[1].IsCurrent())
assert.Equal(t, 3, pages[2].Num())
assert.False(t, pages[2].IsCurrent())
assert.Equal(t, -1, pages[3].Num())
assert.False(t, pages[3].IsCurrent())
assertPages(t, 41, 2, 3, 1, 2, 3, -1)
// 1 2 3 4 5 6 7 ...
p = New(100, 10, 1, 7)
pages = p.Pages()
assert.Len(t, pages, 8)
assert.Equal(t, 1, pages[0].Num())
assert.True(t, pages[0].IsCurrent())
assert.Equal(t, 2, pages[1].Num())
assert.False(t, pages[1].IsCurrent())
assert.Equal(t, 3, pages[2].Num())
assert.False(t, pages[2].IsCurrent())
assert.Equal(t, 4, pages[3].Num())
assert.False(t, pages[3].IsCurrent())
assert.Equal(t, 5, pages[4].Num())
assert.False(t, pages[4].IsCurrent())
assert.Equal(t, 6, pages[5].Num())
assert.False(t, pages[5].IsCurrent())
assert.Equal(t, 7, pages[6].Num())
assert.False(t, pages[6].IsCurrent())
assert.Equal(t, -1, pages[7].Num())
assert.False(t, pages[7].IsCurrent())
assertPages(t, 100, 1, 7, 1, 2, 3, 4, 5, 6, 7, -1)
// 1 2 3 4 5 6 7 ...
p = New(100, 10, 2, 7)
pages = p.Pages()
assert.Len(t, pages, 8)
assert.Equal(t, 1, pages[0].Num())
assert.False(t, pages[0].IsCurrent())
assert.Equal(t, 2, pages[1].Num())
assert.True(t, pages[1].IsCurrent())
assert.Equal(t, 3, pages[2].Num())
assert.False(t, pages[2].IsCurrent())
assert.Equal(t, 4, pages[3].Num())
assert.False(t, pages[3].IsCurrent())
assert.Equal(t, 5, pages[4].Num())
assert.False(t, pages[4].IsCurrent())
assert.Equal(t, 6, pages[5].Num())
assert.False(t, pages[5].IsCurrent())
assert.Equal(t, 7, pages[6].Num())
assert.False(t, pages[6].IsCurrent())
assert.Equal(t, -1, pages[7].Num())
assert.False(t, pages[7].IsCurrent())
assertPages(t, 100, 2, 7, 1, 2, 3, 4, 5, 6, 7, -1)
})
t.Run("Has both more previous and next pages", func(t *testing.T) {
// ... 2 3 ...
p := New(35, 10, 2, 2)
pages := p.Pages()
assert.Len(t, pages, 4)
assert.Equal(t, -1, pages[0].Num())
assert.False(t, pages[0].IsCurrent())
assert.Equal(t, 2, pages[1].Num())
assert.True(t, pages[1].IsCurrent())
assert.Equal(t, 3, pages[2].Num())
assert.False(t, pages[2].IsCurrent())
assert.Equal(t, -1, pages[3].Num())
assert.False(t, pages[3].IsCurrent())
assertPages(t, 35, 2, 2, -1, 2, 3, -1)
// ... 2 3 4 ...
p = New(49, 10, 3, 3)
pages = p.Pages()
assert.Len(t, pages, 5)
assert.Equal(t, -1, pages[0].Num())
assert.False(t, pages[0].IsCurrent())
assert.Equal(t, 2, pages[1].Num())
assert.False(t, pages[1].IsCurrent())
assert.Equal(t, 3, pages[2].Num())
assert.True(t, pages[2].IsCurrent())
assert.Equal(t, 4, pages[3].Num())
assert.False(t, pages[3].IsCurrent())
assert.Equal(t, -1, pages[4].Num())
assert.False(t, pages[4].IsCurrent())
assertPages(t, 49, 3, 3, -1, 2, 3, 4, -1)
})
}
+14 -20
View File
@@ -41,29 +41,23 @@ func TestManager_AddContext(t *testing.T) {
func TestManager_Cancel(t *testing.T) {
pm := Manager{processMap: make(map[IDType]*process), next: 1}
ctx, _, finished := pm.AddContext(t.Context(), "foo")
defer finished()
for _, managerCancel := range []bool{true, false} {
ctx, cancel, finished := pm.AddContext(t.Context(), "foo")
defer finished()
pm.Cancel(GetPID(ctx))
if managerCancel {
pm.Cancel(GetPID(ctx))
} else {
cancel()
}
select {
case <-ctx.Done():
default:
assert.FailNow(t, "Cancel should cancel the provided context")
select {
case <-ctx.Done():
default:
assert.FailNow(t, "Cancel should cancel the provided context")
}
finished()
}
finished()
ctx, cancel, finished := pm.AddContext(t.Context(), "foo")
defer finished()
cancel()
select {
case <-ctx.Done():
default:
assert.FailNow(t, "Cancel should cancel the provided context")
}
finished()
}
func TestManager_Remove(t *testing.T) {
+39 -60
View File
@@ -4,6 +4,7 @@
package queue
import (
"fmt"
"slices"
"strconv"
"sync"
@@ -76,40 +77,32 @@ func TestWorkerPoolQueueUnhandled(t *testing.T) {
}
runCount := 2 // we can run these tests even hundreds times to see its stability
t.Run("1/1", func(t *testing.T) {
for range runCount {
test(t, setting.QueueSettings{BatchLength: 1, MaxWorkers: 1})
}
})
t.Run("3/1", func(t *testing.T) {
for range runCount {
test(t, setting.QueueSettings{BatchLength: 3, MaxWorkers: 1})
}
})
t.Run("4/5", func(t *testing.T) {
for range runCount {
test(t, setting.QueueSettings{BatchLength: 4, MaxWorkers: 5})
}
})
for _, queueSetting := range []setting.QueueSettings{
{BatchLength: 1, MaxWorkers: 1},
{BatchLength: 3, MaxWorkers: 1},
{BatchLength: 4, MaxWorkers: 5},
} {
t.Run(fmt.Sprintf("%d/%d", queueSetting.BatchLength, queueSetting.MaxWorkers), func(t *testing.T) {
for range runCount {
test(t, queueSetting)
}
})
}
}
func TestWorkerPoolQueuePersistence(t *testing.T) {
runCount := 2 // we can run these tests even hundreds times to see its stability
t.Run("1/1", func(t *testing.T) {
for range runCount {
testWorkerPoolQueuePersistence(t, setting.QueueSettings{BatchLength: 1, MaxWorkers: 1, Length: 100})
}
})
t.Run("3/1", func(t *testing.T) {
for range runCount {
testWorkerPoolQueuePersistence(t, setting.QueueSettings{BatchLength: 3, MaxWorkers: 1, Length: 100})
}
})
t.Run("4/5", func(t *testing.T) {
for range runCount {
testWorkerPoolQueuePersistence(t, setting.QueueSettings{BatchLength: 4, MaxWorkers: 5, Length: 100})
}
})
for _, queueSetting := range []setting.QueueSettings{
{BatchLength: 1, MaxWorkers: 1, Length: 100},
{BatchLength: 3, MaxWorkers: 1, Length: 100},
{BatchLength: 4, MaxWorkers: 5, Length: 100},
} {
t.Run(fmt.Sprintf("%d/%d", queueSetting.BatchLength, queueSetting.MaxWorkers), func(t *testing.T) {
for range runCount {
testWorkerPoolQueuePersistence(t, queueSetting)
}
})
}
}
func testWorkerPoolQueuePersistence(t *testing.T, queueSetting setting.QueueSettings) {
@@ -184,37 +177,23 @@ func TestWorkerPoolQueueActiveWorkers(t *testing.T) {
return nil
}
q, _ := newWorkerPoolQueueForTest("test-workpoolqueue", setting.QueueSettings{Type: "channel", BatchLength: 1, MaxWorkers: 1, Length: 100}, handler, false)
stop := runWorkerPoolQueue(q)
for i := range 5 {
assert.NoError(t, q.Push(i))
for _, workerCount := range []int{1, 3} {
q, _ := newWorkerPoolQueueForTest("test-workpoolqueue", setting.QueueSettings{Type: "channel", BatchLength: 1, MaxWorkers: workerCount, Length: 100}, handler, false)
stop := runWorkerPoolQueue(q)
for i := range workerCount * 5 {
assert.NoError(t, q.Push(i))
}
time.Sleep(50 * time.Millisecond)
assert.Equal(t, workerCount, q.GetWorkerNumber())
assert.Equal(t, workerCount, q.GetWorkerActiveNumber())
time.Sleep(500 * time.Millisecond)
assert.Equal(t, workerCount, q.GetWorkerNumber())
assert.Equal(t, 0, q.GetWorkerActiveNumber())
time.Sleep(workerIdleDuration)
assert.Equal(t, 1, q.GetWorkerNumber()) // there is at least one worker after the queue begins working
stop()
}
time.Sleep(50 * time.Millisecond)
assert.Equal(t, 1, q.GetWorkerNumber())
assert.Equal(t, 1, q.GetWorkerActiveNumber())
time.Sleep(500 * time.Millisecond)
assert.Equal(t, 1, q.GetWorkerNumber())
assert.Equal(t, 0, q.GetWorkerActiveNumber())
time.Sleep(workerIdleDuration)
assert.Equal(t, 1, q.GetWorkerNumber()) // there is at least one worker after the queue begins working
stop()
q, _ = newWorkerPoolQueueForTest("test-workpoolqueue", setting.QueueSettings{Type: "channel", BatchLength: 1, MaxWorkers: 3, Length: 100}, handler, false)
stop = runWorkerPoolQueue(q)
for i := range 15 {
assert.NoError(t, q.Push(i))
}
time.Sleep(50 * time.Millisecond)
assert.Equal(t, 3, q.GetWorkerNumber())
assert.Equal(t, 3, q.GetWorkerActiveNumber())
time.Sleep(500 * time.Millisecond)
assert.Equal(t, 3, q.GetWorkerNumber())
assert.Equal(t, 0, q.GetWorkerActiveNumber())
time.Sleep(workerIdleDuration)
assert.Equal(t, 1, q.GetWorkerNumber()) // there is at least one worker after the queue begins working
stop()
}
func TestWorkerPoolQueueShutdown(t *testing.T) {
+22 -43
View File
@@ -10,6 +10,7 @@ import (
repo_model "gitea.dev/models/repo"
"gitea.dev/models/unittest"
"gitea.dev/modules/git"
api "gitea.dev/modules/structs"
"github.com/stretchr/testify/assert"
)
@@ -52,49 +53,27 @@ func TestPushCommits_ToAPIPayloadCommits(t *testing.T) {
assert.Len(t, payloadCommits, 3)
assert.NotNil(t, headCommit)
assert.Equal(t, "69554a6", payloadCommits[0].ID)
assert.Equal(t, "not signed commit", payloadCommits[0].Message)
assert.Equal(t, "https://try.gitea.io/user2/repo16/commit/69554a6", payloadCommits[0].URL)
assert.Equal(t, "User2", payloadCommits[0].Committer.Name)
assert.Equal(t, "user2", payloadCommits[0].Committer.UserName)
assert.Equal(t, "User2", payloadCommits[0].Author.Name)
assert.Equal(t, "user2", payloadCommits[0].Author.UserName)
assert.Equal(t, []string{}, payloadCommits[0].Added)
assert.Equal(t, []string{}, payloadCommits[0].Removed)
assert.Equal(t, []string{"readme.md"}, payloadCommits[0].Modified)
assert.Equal(t, "27566bd", payloadCommits[1].ID)
assert.Equal(t, "good signed commit (with not yet validated email)", payloadCommits[1].Message)
assert.Equal(t, "https://try.gitea.io/user2/repo16/commit/27566bd", payloadCommits[1].URL)
assert.Equal(t, "User2", payloadCommits[1].Committer.Name)
assert.Equal(t, "user2", payloadCommits[1].Committer.UserName)
assert.Equal(t, "User2", payloadCommits[1].Author.Name)
assert.Equal(t, "user2", payloadCommits[1].Author.UserName)
assert.Equal(t, []string{}, payloadCommits[1].Added)
assert.Equal(t, []string{}, payloadCommits[1].Removed)
assert.Equal(t, []string{"readme.md"}, payloadCommits[1].Modified)
assert.Equal(t, "5099b81", payloadCommits[2].ID)
assert.Equal(t, "good signed commit", payloadCommits[2].Message)
assert.Equal(t, "https://try.gitea.io/user2/repo16/commit/5099b81", payloadCommits[2].URL)
assert.Equal(t, "User2", payloadCommits[2].Committer.Name)
assert.Equal(t, "user2", payloadCommits[2].Committer.UserName)
assert.Equal(t, "User2", payloadCommits[2].Author.Name)
assert.Equal(t, "user2", payloadCommits[2].Author.UserName)
assert.Equal(t, []string{"readme.md"}, payloadCommits[2].Added)
assert.Equal(t, []string{}, payloadCommits[2].Removed)
assert.Equal(t, []string{}, payloadCommits[2].Modified)
assert.Equal(t, "69554a6", headCommit.ID)
assert.Equal(t, "not signed commit", headCommit.Message)
assert.Equal(t, "https://try.gitea.io/user2/repo16/commit/69554a6", headCommit.URL)
assert.Equal(t, "User2", headCommit.Committer.Name)
assert.Equal(t, "user2", headCommit.Committer.UserName)
assert.Equal(t, "User2", headCommit.Author.Name)
assert.Equal(t, "user2", headCommit.Author.UserName)
assert.Equal(t, []string{}, headCommit.Added)
assert.Equal(t, []string{}, headCommit.Removed)
assert.Equal(t, []string{"readme.md"}, headCommit.Modified)
for _, tt := range []struct {
commit *api.PayloadCommit
id, message, url string
added, modified []string
}{
{payloadCommits[0], "69554a6", "not signed commit", "https://try.gitea.io/user2/repo16/commit/69554a6", []string{}, []string{"readme.md"}},
{payloadCommits[1], "27566bd", "good signed commit (with not yet validated email)", "https://try.gitea.io/user2/repo16/commit/27566bd", []string{}, []string{"readme.md"}},
{payloadCommits[2], "5099b81", "good signed commit", "https://try.gitea.io/user2/repo16/commit/5099b81", []string{"readme.md"}, []string{}},
{headCommit, "69554a6", "not signed commit", "https://try.gitea.io/user2/repo16/commit/69554a6", []string{}, []string{"readme.md"}},
} {
assert.Equal(t, tt.id, tt.commit.ID)
assert.Equal(t, tt.message, tt.commit.Message)
assert.Equal(t, tt.url, tt.commit.URL)
assert.Equal(t, "User2", tt.commit.Committer.Name)
assert.Equal(t, "user2", tt.commit.Committer.UserName)
assert.Equal(t, "User2", tt.commit.Author.Name)
assert.Equal(t, "user2", tt.commit.Author.UserName)
assert.Equal(t, tt.added, tt.commit.Added)
assert.Equal(t, []string{}, tt.commit.Removed)
assert.Equal(t, tt.modified, tt.commit.Modified)
}
}
func TestCommitToPushCommit(t *testing.T) {
+31 -56
View File
@@ -11,22 +11,17 @@ import (
)
func Test_getLicense(t *testing.T) {
type args struct {
name string
values *LicenseValues
}
tests := []struct {
name string
args args
license string
values *LicenseValues
want string
wantErr assert.ErrorAssertionFunc
}{
{
name: "regular",
args: args{
name: "MIT",
values: &LicenseValues{Owner: "Gitea", Year: "2023"},
},
name: "regular",
license: "MIT",
values: &LicenseValues{Owner: "Gitea", Year: "2023"},
want: `MIT License
Copyright (c) 2023 Gitea
@@ -35,41 +30,33 @@ Permission is hereby granted`,
wantErr: assert.NoError,
},
{
name: "license not found",
args: args{
name: "notfound",
},
name: "license not found",
license: "notfound",
wantErr: assert.Error,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := GetLicense(tt.args.name, tt.args.values)
if !tt.wantErr(t, err, fmt.Sprintf("GetLicense(%v, %v)", tt.args.name, tt.args.values)) {
got, err := GetLicense(tt.license, tt.values)
if !tt.wantErr(t, err, fmt.Sprintf("GetLicense(%v, %v)", tt.license, tt.values)) {
return
}
assert.Contains(t, string(got), tt.want, "GetLicense(%v, %v)", tt.args.name, tt.args.values)
assert.Contains(t, string(got), tt.want, "GetLicense(%v, %v)", tt.license, tt.values)
})
}
}
func Test_fillLicensePlaceholder(t *testing.T) {
type args struct {
name string
values *LicenseValues
origin string
}
tests := []struct {
name string
args args
want string
name string
license string
origin string
want string
}{
{
name: "owner",
args: args{
name: "regular",
values: &LicenseValues{Year: "2023", Owner: "Gitea", Email: "teabot@gitea.io", Repo: "gitea"},
origin: `
name: "owner",
license: "regular",
origin: `
<name of author>
<owner>
[NAME]
@@ -81,7 +68,6 @@ func Test_fillLicensePlaceholder(t *testing.T) {
<author's name or designee>
[one or more legally recognised persons or entities offering the Work under the terms and conditions of this Licence]
`,
},
want: `
Gitea
Gitea
@@ -96,39 +82,31 @@ Gitea
`,
},
{
name: "email",
args: args{
name: "regular",
values: &LicenseValues{Year: "2023", Owner: "Gitea", Email: "teabot@gitea.io", Repo: "gitea"},
origin: `
name: "email",
license: "regular",
origin: `
[EMAIL]
`,
},
want: `
teabot@gitea.io
`,
},
{
name: "repo",
args: args{
name: "regular",
values: &LicenseValues{Year: "2023", Owner: "Gitea", Email: "teabot@gitea.io", Repo: "gitea"},
origin: `
name: "repo",
license: "regular",
origin: `
<program>
<one line to give the program's name and a brief idea of what it does.>
`,
},
want: `
gitea
gitea
`,
},
{
name: "year",
args: args{
name: "regular",
values: &LicenseValues{Year: "2023", Owner: "Gitea", Email: "teabot@gitea.io", Repo: "gitea"},
origin: `
name: "year",
license: "regular",
origin: `
<year>
[YEAR]
{YEAR}
@@ -136,7 +114,6 @@ gitea
[Year]
[year]
`,
},
want: `
2023
2023
@@ -147,18 +124,15 @@ gitea
`,
},
{
name: "0BSD",
args: args{
name: "0BSD",
values: &LicenseValues{Year: "2023", Owner: "Gitea", Email: "teabot@gitea.io", Repo: "gitea"},
origin: `
name: "0BSD",
license: "0BSD",
origin: `
Copyright (C) YEAR by AUTHOR EMAIL
...
... THE AUTHOR BE LIABLE FOR ...
`,
},
want: `
Copyright (C) 2023 by Gitea teabot@gitea.io
@@ -170,7 +144,8 @@ Copyright (C) 2023 by Gitea teabot@gitea.io
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
assert.Equalf(t, tt.want, string(fillLicensePlaceholder(tt.args.name, tt.args.values, []byte(tt.args.origin))), "fillLicensePlaceholder(%v, %v, %v)", tt.args.name, tt.args.values, tt.args.origin)
values := &LicenseValues{Year: "2023", Owner: "Gitea", Email: "teabot@gitea.io", Repo: "gitea"}
assert.Equalf(t, tt.want, string(fillLicensePlaceholder(tt.license, values, []byte(tt.origin))), "fillLicensePlaceholder(%v, %v, %v)", tt.license, values, tt.origin)
})
}
}
+31 -63
View File
@@ -15,89 +15,57 @@ import (
)
func Test_getStorageInheritNameSectionTypeForActions(t *testing.T) {
iniStr := `
for _, tc := range []struct {
iniStr, logType, artifactType string
}{
{`
[storage]
STORAGE_TYPE = minio
`
cfg, err := NewConfigProviderFromData(iniStr)
assert.NoError(t, err)
assert.NoError(t, loadActionsFrom(cfg))
assert.EqualValues(t, "minio", Actions.LogStorage.Type)
assert.Equal(t, "actions_log/", Actions.LogStorage.MinioConfig.BasePath)
assert.EqualValues(t, "minio", Actions.ArtifactStorage.Type)
assert.Equal(t, "actions_artifacts/", Actions.ArtifactStorage.MinioConfig.BasePath)
iniStr = `
`, "minio", "minio"},
{`
[storage.actions_log]
STORAGE_TYPE = minio
`
cfg, err = NewConfigProviderFromData(iniStr)
assert.NoError(t, err)
assert.NoError(t, loadActionsFrom(cfg))
assert.EqualValues(t, "minio", Actions.LogStorage.Type)
assert.Equal(t, "actions_log/", Actions.LogStorage.MinioConfig.BasePath)
assert.EqualValues(t, "local", Actions.ArtifactStorage.Type)
assert.Equal(t, "actions_artifacts", filepath.Base(Actions.ArtifactStorage.Path))
iniStr = `
`, "minio", "local"},
{`
[storage.actions_log]
STORAGE_TYPE = my_storage
[storage.my_storage]
STORAGE_TYPE = minio
`
cfg, err = NewConfigProviderFromData(iniStr)
assert.NoError(t, err)
assert.NoError(t, loadActionsFrom(cfg))
assert.EqualValues(t, "minio", Actions.LogStorage.Type)
assert.Equal(t, "actions_log/", Actions.LogStorage.MinioConfig.BasePath)
assert.EqualValues(t, "local", Actions.ArtifactStorage.Type)
assert.Equal(t, "actions_artifacts", filepath.Base(Actions.ArtifactStorage.Path))
iniStr = `
`, "minio", "local"},
{`
[storage.actions_artifacts]
STORAGE_TYPE = my_storage
[storage.my_storage]
STORAGE_TYPE = minio
`
cfg, err = NewConfigProviderFromData(iniStr)
assert.NoError(t, err)
assert.NoError(t, loadActionsFrom(cfg))
assert.EqualValues(t, "local", Actions.LogStorage.Type)
assert.Equal(t, "actions_log", filepath.Base(Actions.LogStorage.Path))
assert.EqualValues(t, "minio", Actions.ArtifactStorage.Type)
assert.Equal(t, "actions_artifacts/", Actions.ArtifactStorage.MinioConfig.BasePath)
iniStr = `
`, "local", "minio"},
{`
[storage.actions_artifacts]
STORAGE_TYPE = my_storage
[storage.my_storage]
STORAGE_TYPE = minio
`
cfg, err = NewConfigProviderFromData(iniStr)
assert.NoError(t, err)
assert.NoError(t, loadActionsFrom(cfg))
`, "local", "minio"},
{``, "local", "local"},
} {
cfg, err := NewConfigProviderFromData(tc.iniStr)
assert.NoError(t, err)
assert.NoError(t, loadActionsFrom(cfg))
assert.EqualValues(t, "local", Actions.LogStorage.Type)
assert.Equal(t, "actions_log", filepath.Base(Actions.LogStorage.Path))
assert.EqualValues(t, "minio", Actions.ArtifactStorage.Type)
assert.Equal(t, "actions_artifacts/", Actions.ArtifactStorage.MinioConfig.BasePath)
iniStr = ``
cfg, err = NewConfigProviderFromData(iniStr)
assert.NoError(t, err)
assert.NoError(t, loadActionsFrom(cfg))
assert.EqualValues(t, "local", Actions.LogStorage.Type)
assert.Equal(t, "actions_log", filepath.Base(Actions.LogStorage.Path))
assert.EqualValues(t, "local", Actions.ArtifactStorage.Type)
assert.Equal(t, "actions_artifacts", filepath.Base(Actions.ArtifactStorage.Path))
assert.EqualValues(t, tc.logType, Actions.LogStorage.Type)
if tc.logType == "minio" {
assert.Equal(t, "actions_log/", Actions.LogStorage.MinioConfig.BasePath)
} else {
assert.Equal(t, "actions_log", filepath.Base(Actions.LogStorage.Path))
}
assert.EqualValues(t, tc.artifactType, Actions.ArtifactStorage.Type)
if tc.artifactType == "minio" {
assert.Equal(t, "actions_artifacts/", Actions.ArtifactStorage.MinioConfig.BasePath)
} else {
assert.Equal(t, "actions_artifacts", filepath.Base(Actions.ArtifactStorage.Path))
}
}
}
func Test_WorkflowDirs(t *testing.T) {
+20 -36
View File
@@ -10,7 +10,10 @@ import (
)
func Test_getStorageCustomType(t *testing.T) {
iniStr := `
for _, tc := range []struct {
iniStr, endpoint, bucket string
}{
{`
[attachment]
STORAGE_TYPE = my_minio
MINIO_BUCKET = gitea-attachment
@@ -18,20 +21,8 @@ MINIO_BUCKET = gitea-attachment
[storage.my_minio]
STORAGE_TYPE = minio
MINIO_ENDPOINT = my_minio:9000
`
cfg, err := NewConfigProviderFromData(iniStr)
assert.NoError(t, err)
assert.NoError(t, loadAttachmentFrom(cfg))
assert.EqualValues(t, "minio", Attachment.Storage.Type)
assert.Equal(t, "my_minio:9000", Attachment.Storage.MinioConfig.Endpoint)
assert.Equal(t, "gitea-attachment", Attachment.Storage.MinioConfig.Bucket)
assert.Equal(t, "attachments/", Attachment.Storage.MinioConfig.BasePath)
}
func Test_getStorageTypeSectionOverridesStorageSection(t *testing.T) {
iniStr := `
`, "my_minio:9000", "gitea-attachment"},
{`
[attachment]
STORAGE_TYPE = minio
@@ -40,19 +31,8 @@ MINIO_BUCKET = gitea-minio
[storage]
MINIO_BUCKET = gitea
`
cfg, err := NewConfigProviderFromData(iniStr)
assert.NoError(t, err)
assert.NoError(t, loadAttachmentFrom(cfg))
assert.EqualValues(t, "minio", Attachment.Storage.Type)
assert.Equal(t, "gitea-minio", Attachment.Storage.MinioConfig.Bucket)
assert.Equal(t, "attachments/", Attachment.Storage.MinioConfig.BasePath)
}
func Test_getStorageSpecificOverridesStorage(t *testing.T) {
iniStr := `
`, "", "gitea-minio"},
{`
[attachment]
STORAGE_TYPE = minio
MINIO_BUCKET = gitea-attachment
@@ -62,15 +42,19 @@ MINIO_BUCKET = gitea
[storage]
STORAGE_TYPE = local
`
cfg, err := NewConfigProviderFromData(iniStr)
assert.NoError(t, err)
`, "", "gitea-attachment"},
} {
cfg, err := NewConfigProviderFromData(tc.iniStr)
assert.NoError(t, err)
assert.NoError(t, loadAttachmentFrom(cfg))
assert.NoError(t, loadAttachmentFrom(cfg))
assert.EqualValues(t, "minio", Attachment.Storage.Type)
assert.Equal(t, "gitea-attachment", Attachment.Storage.MinioConfig.Bucket)
assert.Equal(t, "attachments/", Attachment.Storage.MinioConfig.BasePath)
assert.EqualValues(t, "minio", Attachment.Storage.Type)
if tc.endpoint != "" {
assert.Equal(t, tc.endpoint, Attachment.Storage.MinioConfig.Endpoint)
}
assert.Equal(t, tc.bucket, Attachment.Storage.MinioConfig.Bucket)
assert.Equal(t, "attachments/", Attachment.Storage.MinioConfig.BasePath)
}
}
func Test_getStorageGetDefaults(t *testing.T) {
+33 -41
View File
@@ -11,22 +11,20 @@ import (
)
func TestDecodeEnvSectionKey(t *testing.T) {
ok, section, key := decodeEnvSectionKey("SEC__KEY")
assert.True(t, ok)
assert.Equal(t, "sec", section)
assert.Equal(t, "KEY", key)
for _, tc := range []struct {
input, section, key string
}{
{"SEC__KEY", "sec", "KEY"},
{"sec__key", "sec", "key"},
{"LOG_0x2E_CONSOLE__STDERR", "log.console", "STDERR"},
} {
ok, section, key := decodeEnvSectionKey(tc.input)
assert.True(t, ok)
assert.Equal(t, tc.section, section)
assert.Equal(t, tc.key, key)
}
ok, section, key = decodeEnvSectionKey("sec__key")
assert.True(t, ok)
assert.Equal(t, "sec", section)
assert.Equal(t, "key", key)
ok, section, key = decodeEnvSectionKey("LOG_0x2E_CONSOLE__STDERR")
assert.True(t, ok)
assert.Equal(t, "log.console", section)
assert.Equal(t, "STDERR", key)
ok, section, key = decodeEnvSectionKey("SEC")
ok, section, key := decodeEnvSectionKey("SEC")
assert.False(t, ok)
assert.Empty(t, section)
assert.Empty(t, key)
@@ -36,19 +34,15 @@ func TestDecodeEnvironmentKey(t *testing.T) {
prefix := "GITEA__"
suffix := "__FILE"
ok, section, key, file := decodeEnvironmentKey(prefix, suffix, "SEC__KEY")
assert.False(t, ok)
assert.Empty(t, section)
assert.Empty(t, key)
assert.False(t, file)
for _, input := range []string{"SEC__KEY", "GITEA__SEC"} {
ok, section, key, file := decodeEnvironmentKey(prefix, suffix, input)
assert.False(t, ok)
assert.Empty(t, section)
assert.Empty(t, key)
assert.False(t, file)
}
ok, section, key, file = decodeEnvironmentKey(prefix, suffix, "GITEA__SEC")
assert.False(t, ok)
assert.Empty(t, section)
assert.Empty(t, key)
assert.False(t, file)
ok, section, key, file = decodeEnvironmentKey(prefix, suffix, "GITEA____KEY")
ok, section, key, file := decodeEnvironmentKey(prefix, suffix, "GITEA____KEY")
assert.True(t, ok)
assert.Empty(t, section)
assert.Equal(t, "KEY", key)
@@ -103,20 +97,18 @@ key = old
assert.True(t, changed)
assert.Equal(t, "value-from-file", cfg.Section("sec").Key("key").String())
cfg, _ = NewConfigProviderFromData("")
_ = os.WriteFile(tmpFile, []byte("value-from-file\n"), 0o644)
EnvironmentToConfig(cfg, []string{"GITEA__sec__key__FILE=" + tmpFile})
assert.Equal(t, "value-from-file", cfg.Section("sec").Key("key").String())
cfg, _ = NewConfigProviderFromData("")
_ = os.WriteFile(tmpFile, []byte("value-from-file\r\n"), 0o644)
EnvironmentToConfig(cfg, []string{"GITEA__sec__key__FILE=" + tmpFile})
assert.Equal(t, "value-from-file", cfg.Section("sec").Key("key").String())
cfg, _ = NewConfigProviderFromData("")
_ = os.WriteFile(tmpFile, []byte("value-from-file\n\n"), 0o644)
EnvironmentToConfig(cfg, []string{"GITEA__sec__key__FILE=" + tmpFile})
assert.Equal(t, "value-from-file\n", cfg.Section("sec").Key("key").String())
for _, tc := range []struct {
content, want string
}{
{"value-from-file\n", "value-from-file"},
{"value-from-file\r\n", "value-from-file"},
{"value-from-file\n\n", "value-from-file\n"},
} {
cfg, _ = NewConfigProviderFromData("")
_ = os.WriteFile(tmpFile, []byte(tc.content), 0o644)
EnvironmentToConfig(cfg, []string{"GITEA__sec__key__FILE=" + tmpFile})
assert.Equal(t, tc.want, cfg.Section("sec").Key("key").String())
}
}
func TestEnvironmentToConfigSubSecKey(t *testing.T) {
+23 -47
View File
@@ -12,63 +12,39 @@ import (
)
func TestLoadGlobalLockConfig(t *testing.T) {
t.Run("DefaultGlobalLockConfig", func(t *testing.T) {
defer test.MockVariableValue(&Redis)()
iniStr := ``
cfg, err := NewConfigProviderFromData(iniStr)
assert.NoError(t, err)
loadRedisFrom(cfg)
loadGlobalLockFrom(cfg)
assert.Equal(t, "memory", GlobalLock.ServiceType)
})
t.Run("RedisGlobalLockConfig", func(t *testing.T) {
defer test.MockVariableValue(&Redis)()
iniStr := `
for _, tt := range []struct {
name, config, serviceType, connStr string
}{
{"DefaultGlobalLockConfig", ``, "memory", ""},
{"RedisGlobalLockConfig", `
[global_lock]
SERVICE_TYPE = redis
SERVICE_CONN_STR = addrs=127.0.0.1:6379 db=0
`
cfg, err := NewConfigProviderFromData(iniStr)
assert.NoError(t, err)
loadRedisFrom(cfg)
loadGlobalLockFrom(cfg)
assert.Equal(t, "redis", GlobalLock.ServiceType)
assert.Equal(t, "addrs=127.0.0.1:6379 db=0", GlobalLock.ServiceConnStr)
})
t.Run("RedisGlobalLockFallsBackToSharedRedis", func(t *testing.T) {
defer test.MockVariableValue(&Redis)()
iniStr := `
`, "redis", "addrs=127.0.0.1:6379 db=0"},
{"RedisGlobalLockFallsBackToSharedRedis", `
[redis]
CONN_STR = redis://127.0.0.1:6379/0
[global_lock]
SERVICE_TYPE = redis
`
cfg, err := NewConfigProviderFromData(iniStr)
assert.NoError(t, err)
loadRedisFrom(cfg)
loadGlobalLockFrom(cfg)
assert.Equal(t, "redis", GlobalLock.ServiceType)
assert.Equal(t, "redis://127.0.0.1:6379/0", GlobalLock.ServiceConnStr)
})
t.Run("RedisGlobalLockOwnConnWinsOverSharedRedis", func(t *testing.T) {
defer test.MockVariableValue(&Redis)()
iniStr := `
`, "redis", "redis://127.0.0.1:6379/0"},
{"RedisGlobalLockOwnConnWinsOverSharedRedis", `
[redis]
CONN_STR = redis://127.0.0.1:6379/0
[global_lock]
SERVICE_TYPE = redis
SERVICE_CONN_STR = redis://10.0.0.1:6379/1
`
cfg, err := NewConfigProviderFromData(iniStr)
assert.NoError(t, err)
loadRedisFrom(cfg)
loadGlobalLockFrom(cfg)
assert.Equal(t, "redis", GlobalLock.ServiceType)
assert.Equal(t, "redis://10.0.0.1:6379/1", GlobalLock.ServiceConnStr)
})
`, "redis", "redis://10.0.0.1:6379/1"},
} {
t.Run(tt.name, func(t *testing.T) {
defer test.MockVariableValue(&Redis)()
cfg, err := NewConfigProviderFromData(tt.config)
assert.NoError(t, err)
loadRedisFrom(cfg)
loadGlobalLockFrom(cfg)
assert.Equal(t, tt.serviceType, GlobalLock.ServiceType)
if tt.serviceType == "redis" {
assert.Equal(t, tt.connStr, GlobalLock.ServiceConnStr)
}
})
}
}
+29 -55
View File
@@ -12,82 +12,56 @@ import (
)
func Test_getStorageInheritNameSectionTypeForLFS(t *testing.T) {
iniStr := `
for _, tt := range []struct {
config, storageType, path string
}{
{`
[storage]
STORAGE_TYPE = minio
`
cfg, err := NewConfigProviderFromData(iniStr)
assert.NoError(t, err)
assert.NoError(t, loadLFSFrom(cfg))
assert.EqualValues(t, "minio", LFS.Storage.Type)
assert.Equal(t, "lfs/", LFS.Storage.MinioConfig.BasePath)
iniStr = `
`, "minio", "lfs/"},
{`
[server]
LFS_CONTENT_PATH = path_ignored
[lfs]
PATH = path_used
`
cfg, err = NewConfigProviderFromData(iniStr)
assert.NoError(t, err)
applyDeprecatedKeys(cfg)
assert.NoError(t, loadLFSFrom(cfg))
assert.EqualValues(t, "local", LFS.Storage.Type)
assert.Contains(t, LFS.Storage.Path, "path_used")
iniStr = `
`, "local", "path_used"},
{`
[server]
LFS_CONTENT_PATH = deprecatedpath
`
cfg, err = NewConfigProviderFromData(iniStr)
assert.NoError(t, err)
applyDeprecatedKeys(cfg)
assert.NoError(t, loadLFSFrom(cfg))
assert.EqualValues(t, "local", LFS.Storage.Type)
assert.Contains(t, LFS.Storage.Path, "deprecatedpath")
iniStr = `
`, "local", "deprecatedpath"},
{`
[storage.lfs]
STORAGE_TYPE = minio
`
cfg, err = NewConfigProviderFromData(iniStr)
assert.NoError(t, err)
assert.NoError(t, loadLFSFrom(cfg))
assert.EqualValues(t, "minio", LFS.Storage.Type)
assert.Equal(t, "lfs/", LFS.Storage.MinioConfig.BasePath)
iniStr = `
`, "minio", "lfs/"},
{`
[lfs]
STORAGE_TYPE = my_minio
[storage.my_minio]
STORAGE_TYPE = minio
`
cfg, err = NewConfigProviderFromData(iniStr)
assert.NoError(t, err)
assert.NoError(t, loadLFSFrom(cfg))
assert.EqualValues(t, "minio", LFS.Storage.Type)
assert.Equal(t, "lfs/", LFS.Storage.MinioConfig.BasePath)
iniStr = `
`, "minio", "lfs/"},
{`
[lfs]
STORAGE_TYPE = my_minio
MINIO_BASE_PATH = my_lfs/
[storage.my_minio]
STORAGE_TYPE = minio
`
cfg, err = NewConfigProviderFromData(iniStr)
assert.NoError(t, err)
assert.NoError(t, loadLFSFrom(cfg))
assert.EqualValues(t, "minio", LFS.Storage.Type)
assert.Equal(t, "my_lfs/", LFS.Storage.MinioConfig.BasePath)
`, "minio", "my_lfs/"},
} {
cfg, err := NewConfigProviderFromData(tt.config)
assert.NoError(t, err)
if tt.storageType == "local" {
applyDeprecatedKeys(cfg)
}
assert.NoError(t, loadLFSFrom(cfg))
assert.EqualValues(t, tt.storageType, LFS.Storage.Type)
if tt.storageType == "local" {
assert.Contains(t, LFS.Storage.Path, tt.path)
} else {
assert.Equal(t, tt.path, LFS.Storage.MinioConfig.BasePath)
}
}
}
func Test_LFSStorage1(t *testing.T) {
+23 -84
View File
@@ -36,9 +36,6 @@ func toJSON(v any) string {
}
func TestLogConfigDefault(t *testing.T) {
manager, managerClose := initLoggersByConfig(t, ``)
defer managerClose()
writerDump := `
{
"console": {
@@ -57,95 +54,37 @@ func TestLogConfigDefault(t *testing.T) {
}
`
dump := manager.GetLogger(log.DEFAULT).DumpWriters()
require.JSONEq(t, writerDump, toJSON(dump))
dump = manager.GetLogger("access").DumpWriters()
require.JSONEq(t, "{}", toJSON(dump))
dump = manager.GetLogger("router").DumpWriters()
require.JSONEq(t, writerDump, toJSON(dump))
dump = manager.GetLogger("xorm").DumpWriters()
require.JSONEq(t, writerDump, toJSON(dump))
}
func TestLogConfigDisable(t *testing.T) {
manager, managerClose := initLoggersByConfig(t, `
for _, tt := range []struct {
name, config, routerDump string
}{
{"Default", ``, writerDump},
{"Disable", `
[log]
logger.router.MODE =
logger.xorm.MODE =
`)
defer managerClose()
writerDump := `
{
"console": {
"BufferLen": 10000,
"Colorize": false,
"Expression": "",
"Flags": "stdflags",
"Level": "info",
"Prefix": "",
"StacktraceLevel": "none",
"WriterOption": {
"Stderr": false
},
"WriterType": "console"
}
}
`
dump := manager.GetLogger(log.DEFAULT).DumpWriters()
require.JSONEq(t, writerDump, toJSON(dump))
dump = manager.GetLogger("access").DumpWriters()
require.JSONEq(t, "{}", toJSON(dump))
dump = manager.GetLogger("router").DumpWriters()
require.JSONEq(t, "{}", toJSON(dump))
dump = manager.GetLogger("xorm").DumpWriters()
require.JSONEq(t, "{}", toJSON(dump))
}
func TestLogConfigLegacyDefault(t *testing.T) {
manager, managerClose := initLoggersByConfig(t, `
`, "{}"},
{"LegacyDefault", `
[log]
MODE = console
`)
defer managerClose()
`, writerDump},
} {
t.Run(tt.name, func(t *testing.T) {
manager, managerClose := initLoggersByConfig(t, tt.config)
defer managerClose()
writerDump := `
{
"console": {
"BufferLen": 10000,
"Colorize": false,
"Expression": "",
"Flags": "stdflags",
"Level": "info",
"Prefix": "",
"StacktraceLevel": "none",
"WriterOption": {
"Stderr": false
},
"WriterType": "console"
for _, logger := range []struct {
name, expected string
}{
{log.DEFAULT, writerDump},
{"access", "{}"},
{"router", tt.routerDump},
{"xorm", tt.routerDump},
} {
require.JSONEq(t, logger.expected, toJSON(manager.GetLogger(logger.name).DumpWriters()))
}
})
}
}
`
dump := manager.GetLogger(log.DEFAULT).DumpWriters()
require.JSONEq(t, writerDump, toJSON(dump))
dump = manager.GetLogger("access").DumpWriters()
require.JSONEq(t, "{}", toJSON(dump))
dump = manager.GetLogger("router").DumpWriters()
require.JSONEq(t, writerDump, toJSON(dump))
dump = manager.GetLogger("xorm").DumpWriters()
require.JSONEq(t, writerDump, toJSON(dump))
}
func TestLogConfigLegacyMode(t *testing.T) {
tempDir := t.TempDir()
+52 -122
View File
@@ -31,168 +31,98 @@ func TestMustBytes(t *testing.T) {
}
func Test_getStorageInheritNameSectionTypeForPackages(t *testing.T) {
// packages storage inherits from storage if nothing configured
iniStr := `
for _, testcase := range []struct {
iniStr, basePath string
}{
// packages storage inherits from storage if nothing configured
{`
[storage]
STORAGE_TYPE = minio
`
cfg, err := NewConfigProviderFromData(iniStr)
assert.NoError(t, err)
assert.NoError(t, loadPackagesFrom(cfg))
assert.EqualValues(t, "minio", Packages.Storage.Type)
assert.Equal(t, "packages/", Packages.Storage.MinioConfig.BasePath)
// we can also configure packages storage directly
iniStr = `
`, "packages/"},
// we can also configure packages storage directly
{`
[storage.packages]
STORAGE_TYPE = minio
`
cfg, err = NewConfigProviderFromData(iniStr)
assert.NoError(t, err)
assert.NoError(t, loadPackagesFrom(cfg))
assert.EqualValues(t, "minio", Packages.Storage.Type)
assert.Equal(t, "packages/", Packages.Storage.MinioConfig.BasePath)
// or we can indicate the storage type in the packages section
iniStr = `
`, "packages/"},
// or we can indicate the storage type in the packages section
{`
[packages]
STORAGE_TYPE = my_minio
[storage.my_minio]
STORAGE_TYPE = minio
`
cfg, err = NewConfigProviderFromData(iniStr)
assert.NoError(t, err)
assert.NoError(t, loadPackagesFrom(cfg))
assert.EqualValues(t, "minio", Packages.Storage.Type)
assert.Equal(t, "packages/", Packages.Storage.MinioConfig.BasePath)
// or we can indicate the storage type and minio base path in the packages section
iniStr = `
`, "packages/"},
// or we can indicate the storage type and minio base path in the packages section
{`
[packages]
STORAGE_TYPE = my_minio
MINIO_BASE_PATH = my_packages/
[storage.my_minio]
STORAGE_TYPE = minio
`
cfg, err = NewConfigProviderFromData(iniStr)
assert.NoError(t, err)
assert.NoError(t, loadPackagesFrom(cfg))
`, "my_packages/"},
} {
cfg, err := NewConfigProviderFromData(testcase.iniStr)
assert.NoError(t, err)
assert.NoError(t, loadPackagesFrom(cfg))
assert.EqualValues(t, "minio", Packages.Storage.Type)
assert.Equal(t, "my_packages/", Packages.Storage.MinioConfig.BasePath)
assert.EqualValues(t, "minio", Packages.Storage.Type)
assert.Equal(t, testcase.basePath, Packages.Storage.MinioConfig.BasePath)
}
}
func Test_PackageStorage1(t *testing.T) {
iniStr := `
func Test_PackageStorage(t *testing.T) {
const storageConfig = `STORAGE_TYPE = minio
MINIO_ENDPOINT = s3.my-domain.net
MINIO_BUCKET = gitea
MINIO_LOCATION = homenet
MINIO_USE_SSL = true
MINIO_ACCESS_KEY_ID = correct_key
MINIO_SECRET_ACCESS_KEY = correct_key
`
for _, testcase := range []struct {
iniStr, basePath string
}{
{`
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
[packages]
MINIO_BASE_PATH = packages/
SERVE_DIRECT = true
[storage]
STORAGE_TYPE = minio
MINIO_ENDPOINT = s3.my-domain.net
MINIO_BUCKET = gitea
MINIO_LOCATION = homenet
MINIO_USE_SSL = true
MINIO_ACCESS_KEY_ID = correct_key
MINIO_SECRET_ACCESS_KEY = correct_key
`
cfg, err := NewConfigProviderFromData(iniStr)
assert.NoError(t, err)
assert.NoError(t, loadPackagesFrom(cfg))
storage := Packages.Storage
assert.EqualValues(t, "minio", storage.Type)
assert.Equal(t, "gitea", storage.MinioConfig.Bucket)
assert.Equal(t, "packages/", storage.MinioConfig.BasePath)
assert.True(t, storage.MinioConfig.ServeDirect)
}
func Test_PackageStorage2(t *testing.T) {
iniStr := `
`, "packages/"},
{`
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
[storage.packages]
MINIO_BASE_PATH = packages/
SERVE_DIRECT = true
[storage]
STORAGE_TYPE = minio
MINIO_ENDPOINT = s3.my-domain.net
MINIO_BUCKET = gitea
MINIO_LOCATION = homenet
MINIO_USE_SSL = true
MINIO_ACCESS_KEY_ID = correct_key
MINIO_SECRET_ACCESS_KEY = correct_key
`
cfg, err := NewConfigProviderFromData(iniStr)
assert.NoError(t, err)
assert.NoError(t, loadPackagesFrom(cfg))
storage := Packages.Storage
assert.EqualValues(t, "minio", storage.Type)
assert.Equal(t, "gitea", storage.MinioConfig.Bucket)
assert.Equal(t, "packages/", storage.MinioConfig.BasePath)
assert.True(t, storage.MinioConfig.ServeDirect)
}
func Test_PackageStorage3(t *testing.T) {
iniStr := `
`, "packages/"},
{`
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
[packages]
STORAGE_TYPE = my_cfg
MINIO_BASE_PATH = my_packages/
SERVE_DIRECT = true
[storage.my_cfg]
STORAGE_TYPE = minio
MINIO_ENDPOINT = s3.my-domain.net
MINIO_BUCKET = gitea
MINIO_LOCATION = homenet
MINIO_USE_SSL = true
MINIO_ACCESS_KEY_ID = correct_key
MINIO_SECRET_ACCESS_KEY = correct_key
`
cfg, err := NewConfigProviderFromData(iniStr)
assert.NoError(t, err)
assert.NoError(t, loadPackagesFrom(cfg))
storage := Packages.Storage
assert.EqualValues(t, "minio", storage.Type)
assert.Equal(t, "gitea", storage.MinioConfig.Bucket)
assert.Equal(t, "my_packages/", storage.MinioConfig.BasePath)
assert.True(t, storage.MinioConfig.ServeDirect)
}
func Test_PackageStorage4(t *testing.T) {
iniStr := `
`, "my_packages/"},
{`
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
[storage.packages]
STORAGE_TYPE = my_cfg
MINIO_BASE_PATH = my_packages/
SERVE_DIRECT = true
[storage.my_cfg]
STORAGE_TYPE = minio
MINIO_ENDPOINT = s3.my-domain.net
MINIO_BUCKET = gitea
MINIO_LOCATION = homenet
MINIO_USE_SSL = true
MINIO_ACCESS_KEY_ID = correct_key
MINIO_SECRET_ACCESS_KEY = correct_key
`
cfg, err := NewConfigProviderFromData(iniStr)
assert.NoError(t, err)
`, "my_packages/"},
} {
cfg, err := NewConfigProviderFromData(testcase.iniStr + storageConfig)
assert.NoError(t, err)
assert.NoError(t, loadPackagesFrom(cfg))
storage := Packages.Storage
assert.NoError(t, loadPackagesFrom(cfg))
storage := Packages.Storage
assert.EqualValues(t, "minio", storage.Type)
assert.Equal(t, "gitea", storage.MinioConfig.Bucket)
assert.Equal(t, "my_packages/", storage.MinioConfig.BasePath)
assert.True(t, storage.MinioConfig.ServeDirect)
assert.EqualValues(t, "minio", storage.Type)
assert.Equal(t, "gitea", storage.MinioConfig.Bucket)
assert.Equal(t, testcase.basePath, storage.MinioConfig.BasePath)
assert.True(t, storage.MinioConfig.ServeDirect)
}
}
+35 -57
View File
@@ -10,64 +10,49 @@ import (
)
func Test_getStorageInheritNameSectionTypeForRepoArchive(t *testing.T) {
// packages storage inherits from storage if nothing configured
iniStr := `
for _, tc := range []struct {
ini, basePath string
}{
// packages storage inherits from storage if nothing configured
{`
[storage]
STORAGE_TYPE = minio
`
cfg, err := NewConfigProviderFromData(iniStr)
assert.NoError(t, err)
assert.NoError(t, loadRepoArchiveFrom(cfg))
assert.EqualValues(t, "minio", RepoArchive.Storage.Type)
assert.Equal(t, "repo-archive/", RepoArchive.Storage.MinioConfig.BasePath)
// we can also configure packages storage directly
iniStr = `
`, "repo-archive/"},
// we can also configure packages storage directly
{`
[storage.repo-archive]
STORAGE_TYPE = minio
`
cfg, err = NewConfigProviderFromData(iniStr)
assert.NoError(t, err)
assert.NoError(t, loadRepoArchiveFrom(cfg))
assert.EqualValues(t, "minio", RepoArchive.Storage.Type)
assert.Equal(t, "repo-archive/", RepoArchive.Storage.MinioConfig.BasePath)
// or we can indicate the storage type in the packages section
iniStr = `
`, "repo-archive/"},
// or we can indicate the storage type in the packages section
{`
[repo-archive]
STORAGE_TYPE = my_minio
[storage.my_minio]
STORAGE_TYPE = minio
`
cfg, err = NewConfigProviderFromData(iniStr)
assert.NoError(t, err)
assert.NoError(t, loadRepoArchiveFrom(cfg))
assert.EqualValues(t, "minio", RepoArchive.Storage.Type)
assert.Equal(t, "repo-archive/", RepoArchive.Storage.MinioConfig.BasePath)
// or we can indicate the storage type and minio base path in the packages section
iniStr = `
`, "repo-archive/"},
// or we can indicate the storage type and minio base path in the packages section
{`
[repo-archive]
STORAGE_TYPE = my_minio
MINIO_BASE_PATH = my_archive/
[storage.my_minio]
STORAGE_TYPE = minio
`
cfg, err = NewConfigProviderFromData(iniStr)
assert.NoError(t, err)
assert.NoError(t, loadRepoArchiveFrom(cfg))
`, "my_archive/"},
} {
cfg, err := NewConfigProviderFromData(tc.ini)
assert.NoError(t, err)
assert.NoError(t, loadRepoArchiveFrom(cfg))
assert.EqualValues(t, "minio", RepoArchive.Storage.Type)
assert.Equal(t, "my_archive/", RepoArchive.Storage.MinioConfig.BasePath)
assert.EqualValues(t, "minio", RepoArchive.Storage.Type)
assert.Equal(t, tc.basePath, RepoArchive.Storage.MinioConfig.BasePath)
}
}
func Test_RepoArchiveStorage(t *testing.T) {
iniStr := `
for _, ini := range []string{
`
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
[storage]
STORAGE_TYPE = minio
@@ -77,17 +62,8 @@ MINIO_LOCATION = homenet
MINIO_USE_SSL = true
MINIO_ACCESS_KEY_ID = correct_key
MINIO_SECRET_ACCESS_KEY = correct_key
`
cfg, err := NewConfigProviderFromData(iniStr)
assert.NoError(t, err)
assert.NoError(t, loadRepoArchiveFrom(cfg))
storage := RepoArchive.Storage
assert.EqualValues(t, "minio", storage.Type)
assert.Equal(t, "gitea", storage.MinioConfig.Bucket)
iniStr = `
`,
`
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
[storage.repo-archive]
STORAGE_TYPE = s3
@@ -99,13 +75,15 @@ MINIO_LOCATION = homenet
MINIO_USE_SSL = true
MINIO_ACCESS_KEY_ID = correct_key
MINIO_SECRET_ACCESS_KEY = correct_key
`
cfg, err = NewConfigProviderFromData(iniStr)
assert.NoError(t, err)
`,
} {
cfg, err := NewConfigProviderFromData(ini)
assert.NoError(t, err)
assert.NoError(t, loadRepoArchiveFrom(cfg))
storage = RepoArchive.Storage
assert.NoError(t, loadRepoArchiveFrom(cfg))
storage := RepoArchive.Storage
assert.EqualValues(t, "minio", storage.Type)
assert.Equal(t, "gitea", storage.MinioConfig.Bucket)
assert.EqualValues(t, "minio", storage.Type)
assert.Equal(t, "gitea", storage.MinioConfig.Bucket)
}
}
+15 -35
View File
@@ -54,77 +54,57 @@ func TestLoadServiceVisibilityModes(t *testing.T) {
}
return ret
}
testCases := map[string]func(){
testCases := map[string]struct {
defaultMode structs.VisibleType
allowedModes []structs.VisibilityString
}{
`
[service]
DEFAULT_USER_VISIBILITY = public
ALLOWED_USER_VISIBILITY_MODES = public,limited,private
`: func() {
assert.Equal(t, structs.VisibleTypePublic, Service.DefaultUserVisibilityMode)
assert.Equal(t, visibleTypeSlice("public", "limited", "private"), Service.AllowedUserVisibilityModesSlice.ToVisibleTypeSlice())
},
`: {structs.VisibleTypePublic, []structs.VisibilityString{"public", "limited", "private"}},
`
[service]
DEFAULT_USER_VISIBILITY = public
`: func() {
assert.Equal(t, structs.VisibleTypePublic, Service.DefaultUserVisibilityMode)
assert.Equal(t, visibleTypeSlice("public", "limited", "private"), Service.AllowedUserVisibilityModesSlice.ToVisibleTypeSlice())
},
`: {structs.VisibleTypePublic, []structs.VisibilityString{"public", "limited", "private"}},
`
[service]
DEFAULT_USER_VISIBILITY = limited
`: func() {
assert.Equal(t, structs.VisibleTypeLimited, Service.DefaultUserVisibilityMode)
assert.Equal(t, visibleTypeSlice("public", "limited", "private"), Service.AllowedUserVisibilityModesSlice.ToVisibleTypeSlice())
},
`: {structs.VisibleTypeLimited, []structs.VisibilityString{"public", "limited", "private"}},
`
[service]
ALLOWED_USER_VISIBILITY_MODES = public,limited,private
`: func() {
assert.Equal(t, structs.VisibleTypePublic, Service.DefaultUserVisibilityMode)
assert.Equal(t, visibleTypeSlice("public", "limited", "private"), Service.AllowedUserVisibilityModesSlice.ToVisibleTypeSlice())
},
`: {structs.VisibleTypePublic, []structs.VisibilityString{"public", "limited", "private"}},
`
[service]
DEFAULT_USER_VISIBILITY = public
ALLOWED_USER_VISIBILITY_MODES = limited,private
`: func() {
assert.Equal(t, structs.VisibleTypeLimited, Service.DefaultUserVisibilityMode)
assert.Equal(t, visibleTypeSlice("limited", "private"), Service.AllowedUserVisibilityModesSlice.ToVisibleTypeSlice())
},
`: {structs.VisibleTypeLimited, []structs.VisibilityString{"limited", "private"}},
`
[service]
DEFAULT_USER_VISIBILITY = my_type
ALLOWED_USER_VISIBILITY_MODES = limited,private
`: func() {
assert.Equal(t, structs.VisibleTypeLimited, Service.DefaultUserVisibilityMode)
assert.Equal(t, visibleTypeSlice("limited", "private"), Service.AllowedUserVisibilityModesSlice.ToVisibleTypeSlice())
},
`: {structs.VisibleTypeLimited, []structs.VisibilityString{"limited", "private"}},
`
[service]
DEFAULT_USER_VISIBILITY = my_type
`: func() {
assert.Equal(t, structs.VisibleTypePublic, Service.DefaultUserVisibilityMode)
assert.Equal(t, visibleTypeSlice("public", "limited", "private"), Service.AllowedUserVisibilityModesSlice.ToVisibleTypeSlice())
},
`: {structs.VisibleTypePublic, []structs.VisibilityString{"public", "limited", "private"}},
`
[service]
DEFAULT_USER_VISIBILITY = public
ALLOWED_USER_VISIBILITY_MODES = public, limit, privated
`: func() {
assert.Equal(t, structs.VisibleTypePublic, Service.DefaultUserVisibilityMode)
assert.Equal(t, visibleTypeSlice("public"), Service.AllowedUserVisibilityModesSlice.ToVisibleTypeSlice())
},
`: {structs.VisibleTypePublic, []structs.VisibilityString{"public"}},
}
for tc, fn := range testCases {
for tc, expected := range testCases {
t.Run(tc, func(t *testing.T) {
Service.AllowedUserVisibilityModesSlice = []bool{true, true, true}
Service.DefaultUserVisibilityMode = structs.VisibleTypePublic
cfg, err := NewConfigProviderFromData(tc)
assert.NoError(t, err)
loadServiceFrom(cfg)
fn()
assert.Equal(t, expected.defaultMode, Service.DefaultUserVisibilityMode)
assert.Equal(t, visibleTypeSlice(expected.allowedModes...), Service.AllowedUserVisibilityModesSlice.ToVisibleTypeSlice())
})
}
}
+37 -137
View File
@@ -156,185 +156,85 @@ func testLocalStoragePath(t *testing.T, appDataPath, iniStr string, cases []test
}
func Test_getStorageInheritStorageTypeLocal(t *testing.T) {
testLocalStoragePath(t, "/appdata", `
for _, tc := range []struct {
name, ini, basePath, archivePath string
}{
{"Default", `
[storage]
STORAGE_TYPE = local
`, []testLocalStoragePathCase{
{loadAttachmentFrom, &Attachment.Storage, "/appdata/attachments"},
{loadLFSFrom, &LFS.Storage, "/appdata/lfs"},
{loadActionsFrom, &Actions.ArtifactStorage, "/appdata/actions_artifacts"},
{loadPackagesFrom, &Packages.Storage, "/appdata/packages"},
{loadRepoArchiveFrom, &RepoArchive.Storage, "/appdata/repo-archive"},
{loadActionsFrom, &Actions.LogStorage, "/appdata/actions_log"},
{loadAvatarsFrom, &Avatar.Storage, "/appdata/avatars"},
{loadRepoAvatarFrom, &RepoAvatar.Storage, "/appdata/repo-avatars"},
})
}
func Test_getStorageInheritStorageTypeLocalPath(t *testing.T) {
testLocalStoragePath(t, "/appdata", `
`, "/appdata", "/appdata/repo-archive"},
{"Path", `
[storage]
STORAGE_TYPE = local
PATH = /data/gitea
`, []testLocalStoragePathCase{
{loadAttachmentFrom, &Attachment.Storage, "/data/gitea/attachments"},
{loadLFSFrom, &LFS.Storage, "/data/gitea/lfs"},
{loadActionsFrom, &Actions.ArtifactStorage, "/data/gitea/actions_artifacts"},
{loadPackagesFrom, &Packages.Storage, "/data/gitea/packages"},
{loadRepoArchiveFrom, &RepoArchive.Storage, "/data/gitea/repo-archive"},
{loadActionsFrom, &Actions.LogStorage, "/data/gitea/actions_log"},
{loadAvatarsFrom, &Avatar.Storage, "/data/gitea/avatars"},
{loadRepoAvatarFrom, &RepoAvatar.Storage, "/data/gitea/repo-avatars"},
})
}
func Test_getStorageInheritStorageTypeLocalRelativePath(t *testing.T) {
testLocalStoragePath(t, "/appdata", `
`, "/data/gitea", "/data/gitea/repo-archive"},
{"RelativePath", `
[storage]
STORAGE_TYPE = local
PATH = storages
`, []testLocalStoragePathCase{
{loadAttachmentFrom, &Attachment.Storage, "/appdata/storages/attachments"},
{loadLFSFrom, &LFS.Storage, "/appdata/storages/lfs"},
{loadActionsFrom, &Actions.ArtifactStorage, "/appdata/storages/actions_artifacts"},
{loadPackagesFrom, &Packages.Storage, "/appdata/storages/packages"},
{loadRepoArchiveFrom, &RepoArchive.Storage, "/appdata/storages/repo-archive"},
{loadActionsFrom, &Actions.LogStorage, "/appdata/storages/actions_log"},
{loadAvatarsFrom, &Avatar.Storage, "/appdata/storages/avatars"},
{loadRepoAvatarFrom, &RepoAvatar.Storage, "/appdata/storages/repo-avatars"},
})
}
func Test_getStorageInheritStorageTypeLocalPathOverride(t *testing.T) {
testLocalStoragePath(t, "/appdata", `
`, "/appdata/storages", "/appdata/storages/repo-archive"},
{"PathOverride", `
[storage]
STORAGE_TYPE = local
PATH = /data/gitea
[repo-archive]
PATH = /data/gitea/the-archives-dir
`, []testLocalStoragePathCase{
{loadAttachmentFrom, &Attachment.Storage, "/data/gitea/attachments"},
{loadLFSFrom, &LFS.Storage, "/data/gitea/lfs"},
{loadActionsFrom, &Actions.ArtifactStorage, "/data/gitea/actions_artifacts"},
{loadPackagesFrom, &Packages.Storage, "/data/gitea/packages"},
{loadRepoArchiveFrom, &RepoArchive.Storage, "/data/gitea/the-archives-dir"},
{loadActionsFrom, &Actions.LogStorage, "/data/gitea/actions_log"},
{loadAvatarsFrom, &Avatar.Storage, "/data/gitea/avatars"},
{loadRepoAvatarFrom, &RepoAvatar.Storage, "/data/gitea/repo-avatars"},
})
}
func Test_getStorageInheritStorageTypeLocalPathOverrideEmpty(t *testing.T) {
testLocalStoragePath(t, "/appdata", `
`, "/data/gitea", "/data/gitea/the-archives-dir"},
{"PathOverrideEmpty", `
[storage]
STORAGE_TYPE = local
PATH = /data/gitea
[repo-archive]
`, []testLocalStoragePathCase{
{loadAttachmentFrom, &Attachment.Storage, "/data/gitea/attachments"},
{loadLFSFrom, &LFS.Storage, "/data/gitea/lfs"},
{loadActionsFrom, &Actions.ArtifactStorage, "/data/gitea/actions_artifacts"},
{loadPackagesFrom, &Packages.Storage, "/data/gitea/packages"},
{loadRepoArchiveFrom, &RepoArchive.Storage, "/data/gitea/repo-archive"},
{loadActionsFrom, &Actions.LogStorage, "/data/gitea/actions_log"},
{loadAvatarsFrom, &Avatar.Storage, "/data/gitea/avatars"},
{loadRepoAvatarFrom, &RepoAvatar.Storage, "/data/gitea/repo-avatars"},
})
}
func Test_getStorageInheritStorageTypeLocalRelativePathOverride(t *testing.T) {
testLocalStoragePath(t, "/appdata", `
`, "/data/gitea", "/data/gitea/repo-archive"},
{"RelativePathOverride", `
[storage]
STORAGE_TYPE = local
PATH = /data/gitea
[repo-archive]
PATH = the-archives-dir
`, []testLocalStoragePathCase{
{loadAttachmentFrom, &Attachment.Storage, "/data/gitea/attachments"},
{loadLFSFrom, &LFS.Storage, "/data/gitea/lfs"},
{loadActionsFrom, &Actions.ArtifactStorage, "/data/gitea/actions_artifacts"},
{loadPackagesFrom, &Packages.Storage, "/data/gitea/packages"},
{loadRepoArchiveFrom, &RepoArchive.Storage, "/data/gitea/the-archives-dir"},
{loadActionsFrom, &Actions.LogStorage, "/data/gitea/actions_log"},
{loadAvatarsFrom, &Avatar.Storage, "/data/gitea/avatars"},
{loadRepoAvatarFrom, &RepoAvatar.Storage, "/data/gitea/repo-avatars"},
})
}
func Test_getStorageInheritStorageTypeLocalPathOverride3(t *testing.T) {
testLocalStoragePath(t, "/appdata", `
`, "/data/gitea", "/data/gitea/the-archives-dir"},
{"PathOverride3", `
[storage.repo-archive]
STORAGE_TYPE = local
PATH = /data/gitea/archives
`, []testLocalStoragePathCase{
{loadAttachmentFrom, &Attachment.Storage, "/appdata/attachments"},
{loadLFSFrom, &LFS.Storage, "/appdata/lfs"},
{loadActionsFrom, &Actions.ArtifactStorage, "/appdata/actions_artifacts"},
{loadPackagesFrom, &Packages.Storage, "/appdata/packages"},
{loadRepoArchiveFrom, &RepoArchive.Storage, "/data/gitea/archives"},
{loadActionsFrom, &Actions.LogStorage, "/appdata/actions_log"},
{loadAvatarsFrom, &Avatar.Storage, "/appdata/avatars"},
{loadRepoAvatarFrom, &RepoAvatar.Storage, "/appdata/repo-avatars"},
})
}
func Test_getStorageInheritStorageTypeLocalPathOverride3_5(t *testing.T) {
testLocalStoragePath(t, "/appdata", `
`, "/appdata", "/data/gitea/archives"},
{"PathOverride3_5", `
[storage.repo-archive]
STORAGE_TYPE = local
PATH = a-relative-path
`, []testLocalStoragePathCase{
{loadAttachmentFrom, &Attachment.Storage, "/appdata/attachments"},
{loadLFSFrom, &LFS.Storage, "/appdata/lfs"},
{loadActionsFrom, &Actions.ArtifactStorage, "/appdata/actions_artifacts"},
{loadPackagesFrom, &Packages.Storage, "/appdata/packages"},
{loadRepoArchiveFrom, &RepoArchive.Storage, "/appdata/a-relative-path"},
{loadActionsFrom, &Actions.LogStorage, "/appdata/actions_log"},
{loadAvatarsFrom, &Avatar.Storage, "/appdata/avatars"},
{loadRepoAvatarFrom, &RepoAvatar.Storage, "/appdata/repo-avatars"},
})
}
func Test_getStorageInheritStorageTypeLocalPathOverride4(t *testing.T) {
testLocalStoragePath(t, "/appdata", `
`, "/appdata", "/appdata/a-relative-path"},
{"PathOverride4", `
[storage.repo-archive]
STORAGE_TYPE = local
PATH = /data/gitea/archives
[repo-archive]
PATH = /tmp/gitea/archives
`, []testLocalStoragePathCase{
{loadAttachmentFrom, &Attachment.Storage, "/appdata/attachments"},
{loadLFSFrom, &LFS.Storage, "/appdata/lfs"},
{loadActionsFrom, &Actions.ArtifactStorage, "/appdata/actions_artifacts"},
{loadPackagesFrom, &Packages.Storage, "/appdata/packages"},
{loadRepoArchiveFrom, &RepoArchive.Storage, "/tmp/gitea/archives"},
{loadActionsFrom, &Actions.LogStorage, "/appdata/actions_log"},
{loadAvatarsFrom, &Avatar.Storage, "/appdata/avatars"},
{loadRepoAvatarFrom, &RepoAvatar.Storage, "/appdata/repo-avatars"},
})
}
func Test_getStorageInheritStorageTypeLocalPathOverride5(t *testing.T) {
testLocalStoragePath(t, "/appdata", `
`, "/appdata", "/tmp/gitea/archives"},
{"PathOverride5", `
[storage.repo-archive]
STORAGE_TYPE = local
PATH = /data/gitea/archives
[repo-archive]
`, []testLocalStoragePathCase{
{loadAttachmentFrom, &Attachment.Storage, "/appdata/attachments"},
{loadLFSFrom, &LFS.Storage, "/appdata/lfs"},
{loadActionsFrom, &Actions.ArtifactStorage, "/appdata/actions_artifacts"},
{loadPackagesFrom, &Packages.Storage, "/appdata/packages"},
{loadRepoArchiveFrom, &RepoArchive.Storage, "/data/gitea/archives"},
{loadActionsFrom, &Actions.LogStorage, "/appdata/actions_log"},
{loadAvatarsFrom, &Avatar.Storage, "/appdata/avatars"},
{loadRepoAvatarFrom, &RepoAvatar.Storage, "/appdata/repo-avatars"},
})
`, "/appdata", "/data/gitea/archives"},
} {
t.Run(tc.name, func(t *testing.T) {
testLocalStoragePath(t, "/appdata", tc.ini, []testLocalStoragePathCase{
{loadAttachmentFrom, &Attachment.Storage, tc.basePath + "/attachments"},
{loadLFSFrom, &LFS.Storage, tc.basePath + "/lfs"},
{loadActionsFrom, &Actions.ArtifactStorage, tc.basePath + "/actions_artifacts"},
{loadPackagesFrom, &Packages.Storage, tc.basePath + "/packages"},
{loadRepoArchiveFrom, &RepoArchive.Storage, tc.archivePath},
{loadActionsFrom, &Actions.LogStorage, tc.basePath + "/actions_log"},
{loadAvatarsFrom, &Avatar.Storage, tc.basePath + "/avatars"},
{loadRepoAvatarFrom, &RepoAvatar.Storage, tc.basePath + "/repo-avatars"},
})
})
}
}
func Test_getStorageInheritStorageTypeLocalPathOverride72(t *testing.T) {
+78 -139
View File
@@ -15,151 +15,90 @@ import (
func TestNewSitemap(t *testing.T) {
ts := time.Unix(1651322008, 0).UTC()
tests := []struct {
name string
urls []URL
want string
wantErr string
for _, sitemap := range []struct {
name string
newSitemap func() *Sitemap
root, entry string
wantManyErr string
wantSizeErr string
}{
{
name: "empty",
urls: []URL{},
want: xml.Header + `<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">` +
"" +
"</urlset>\n",
"NewSitemap", NewSitemap, "urlset", "url",
"sitemap contains 50001 URLs, but only 50000 are allowed",
"sitemap has 52428932 bytes, but only 52428800 are allowed",
},
{
name: "regular",
urls: []URL{
{URL: "https://gitea.io/test1", LastMod: &ts},
},
want: xml.Header + `<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">` +
"<url><loc>https://gitea.io/test1</loc><lastmod>2022-04-30T12:33:28Z</lastmod></url>" +
"</urlset>\n",
"NewSitemapIndex", NewSitemapIndex, "sitemapindex", "sitemap",
"sitemap contains 50001 sub-sitemaps, but only 50000 are allowed",
"sitemap has 52428952 bytes, but only 52428800 are allowed",
},
{
name: "without lastmod",
urls: []URL{
{URL: "https://gitea.io/test1"},
},
want: xml.Header + `<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">` +
"<url><loc>https://gitea.io/test1</loc></url>" +
"</urlset>\n",
},
{
name: "multiple",
urls: []URL{
{URL: "https://gitea.io/test1", LastMod: &ts},
{URL: "https://gitea.io/test2", LastMod: nil},
},
want: xml.Header + `<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">` +
"<url><loc>https://gitea.io/test1</loc><lastmod>2022-04-30T12:33:28Z</lastmod></url>" +
"<url><loc>https://gitea.io/test2</loc></url>" +
"</urlset>\n",
},
{
name: "too many urls",
urls: make([]URL, 50001),
wantErr: "sitemap contains 50001 URLs, but only 50000 are allowed",
},
{
name: "too big file",
urls: []URL{
{URL: strings.Repeat("b", 50*1024*1024+1)},
},
wantErr: "sitemap has 52428932 bytes, but only 52428800 are allowed",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
s := NewSitemap()
for _, url := range tt.urls {
s.Add(url)
} {
t.Run(sitemap.name, func(t *testing.T) {
entryStart, entryEnd := "<"+sitemap.entry+">", "</"+sitemap.entry+">"
tests := []struct {
name string
urls []URL
want string
wantErr string
}{
{
name: "empty",
urls: []URL{},
},
{
name: "regular",
urls: []URL{
{URL: "https://gitea.io/test1", LastMod: &ts},
},
want: entryStart + "<loc>https://gitea.io/test1</loc><lastmod>2022-04-30T12:33:28Z</lastmod>" + entryEnd,
},
{
name: "without lastmod",
urls: []URL{
{URL: "https://gitea.io/test1"},
},
want: entryStart + "<loc>https://gitea.io/test1</loc>" + entryEnd,
},
{
name: "multiple",
urls: []URL{
{URL: "https://gitea.io/test1", LastMod: &ts},
{URL: "https://gitea.io/test2", LastMod: nil},
},
want: entryStart + "<loc>https://gitea.io/test1</loc><lastmod>2022-04-30T12:33:28Z</lastmod>" + entryEnd +
entryStart + "<loc>https://gitea.io/test2</loc>" + entryEnd,
},
{
name: "too many " + sitemap.entry + "s",
urls: make([]URL, 50001),
wantErr: sitemap.wantManyErr,
},
{
name: "too big file",
urls: []URL{
{URL: strings.Repeat("b", 50*1024*1024+1)},
},
wantErr: sitemap.wantSizeErr,
},
}
buf := &bytes.Buffer{}
_, err := s.WriteTo(buf)
if tt.wantErr != "" {
assert.EqualError(t, err, tt.wantErr)
} else {
assert.NoError(t, err)
assert.Equalf(t, tt.want, buf.String(), "NewSitemap()")
}
})
}
}
func TestNewSitemapIndex(t *testing.T) {
ts := time.Unix(1651322008, 0).UTC()
tests := []struct {
name string
urls []URL
want string
wantErr string
}{
{
name: "empty",
urls: []URL{},
want: xml.Header + `<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">` +
"" +
"</sitemapindex>\n",
},
{
name: "regular",
urls: []URL{
{URL: "https://gitea.io/test1", LastMod: &ts},
},
want: xml.Header + `<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">` +
"<sitemap><loc>https://gitea.io/test1</loc><lastmod>2022-04-30T12:33:28Z</lastmod></sitemap>" +
"</sitemapindex>\n",
},
{
name: "without lastmod",
urls: []URL{
{URL: "https://gitea.io/test1"},
},
want: xml.Header + `<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">` +
"<sitemap><loc>https://gitea.io/test1</loc></sitemap>" +
"</sitemapindex>\n",
},
{
name: "multiple",
urls: []URL{
{URL: "https://gitea.io/test1", LastMod: &ts},
{URL: "https://gitea.io/test2", LastMod: nil},
},
want: xml.Header + `<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">` +
"<sitemap><loc>https://gitea.io/test1</loc><lastmod>2022-04-30T12:33:28Z</lastmod></sitemap>" +
"<sitemap><loc>https://gitea.io/test2</loc></sitemap>" +
"</sitemapindex>\n",
},
{
name: "too many sitemaps",
urls: make([]URL, 50001),
wantErr: "sitemap contains 50001 sub-sitemaps, but only 50000 are allowed",
},
{
name: "too big file",
urls: []URL{
{URL: strings.Repeat("b", 50*1024*1024+1)},
},
wantErr: "sitemap has 52428952 bytes, but only 52428800 are allowed",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
s := NewSitemapIndex()
for _, url := range tt.urls {
s.Add(url)
}
buf := &bytes.Buffer{}
_, err := s.WriteTo(buf)
if tt.wantErr != "" {
assert.EqualError(t, err, tt.wantErr)
} else {
assert.NoError(t, err)
assert.Equalf(t, tt.want, buf.String(), "NewSitemapIndex()")
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
s := sitemap.newSitemap()
for _, url := range tt.urls {
s.Add(url)
}
buf := &bytes.Buffer{}
_, err := s.WriteTo(buf)
if tt.wantErr != "" {
assert.EqualError(t, err, tt.wantErr)
} else {
assert.NoError(t, err)
assert.Equalf(t,
xml.Header+"<"+sitemap.root+` xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">`+tt.want+"</"+sitemap.root+">\n",
buf.String(), sitemap.name+"()",
)
}
})
}
})
}
+17 -39
View File
@@ -52,18 +52,21 @@ func TestMinioCredentials(t *testing.T) {
FakeEndpoint = "http://localhost"
)
t.Run("Static Credentials", func(t *testing.T) {
cfg := setting.MinioStorageConfig{
AccessKeyID: ExpectedAccessKey,
SecretAccessKey: ExpectedSecretAccessKey,
IamEndpoint: FakeEndpoint,
}
checkCredentials := func(t *testing.T, cfg setting.MinioStorageConfig, suffix string) {
creds := buildMinioCredentials(cfg)
v, err := creds.Get()
assert.NoError(t, err)
assert.Equal(t, ExpectedAccessKey, v.AccessKeyID)
assert.Equal(t, ExpectedSecretAccessKey, v.SecretAccessKey)
assert.Equal(t, ExpectedAccessKey+suffix, v.AccessKeyID)
assert.Equal(t, ExpectedSecretAccessKey+suffix, v.SecretAccessKey)
}
t.Run("Static Credentials", func(t *testing.T) {
checkCredentials(t, setting.MinioStorageConfig{
AccessKeyID: ExpectedAccessKey,
SecretAccessKey: ExpectedSecretAccessKey,
IamEndpoint: FakeEndpoint,
}, "")
})
t.Run("Chain", func(t *testing.T) {
@@ -75,24 +78,14 @@ func TestMinioCredentials(t *testing.T) {
t.Setenv("MINIO_ACCESS_KEY", ExpectedAccessKey+"Minio")
t.Setenv("MINIO_SECRET_KEY", ExpectedSecretAccessKey+"Minio")
creds := buildMinioCredentials(cfg)
v, err := creds.Get()
assert.NoError(t, err)
assert.Equal(t, ExpectedAccessKey+"Minio", v.AccessKeyID)
assert.Equal(t, ExpectedSecretAccessKey+"Minio", v.SecretAccessKey)
checkCredentials(t, cfg, "Minio")
})
t.Run("EnvAWS", func(t *testing.T) {
t.Setenv("AWS_ACCESS_KEY", ExpectedAccessKey+"AWS")
t.Setenv("AWS_SECRET_KEY", ExpectedSecretAccessKey+"AWS")
creds := buildMinioCredentials(cfg)
v, err := creds.Get()
assert.NoError(t, err)
assert.Equal(t, ExpectedAccessKey+"AWS", v.AccessKeyID)
assert.Equal(t, ExpectedSecretAccessKey+"AWS", v.SecretAccessKey)
checkCredentials(t, cfg, "AWS")
})
t.Run("FileMinio", func(t *testing.T) {
@@ -100,12 +93,7 @@ func TestMinioCredentials(t *testing.T) {
t.Setenv("MINIO_SHARED_CREDENTIALS_FILE", "testdata/minio.json")
t.Setenv("AWS_SHARED_CREDENTIALS_FILE", "testdata/fake")
creds := buildMinioCredentials(cfg)
v, err := creds.Get()
assert.NoError(t, err)
assert.Equal(t, ExpectedAccessKey+"MinioFile", v.AccessKeyID)
assert.Equal(t, ExpectedSecretAccessKey+"MinioFile", v.SecretAccessKey)
checkCredentials(t, cfg, "MinioFile")
})
t.Run("FileAWS", func(t *testing.T) {
@@ -113,12 +101,7 @@ func TestMinioCredentials(t *testing.T) {
t.Setenv("MINIO_SHARED_CREDENTIALS_FILE", "testdata/fake.json")
t.Setenv("AWS_SHARED_CREDENTIALS_FILE", "testdata/aws_credentials")
creds := buildMinioCredentials(cfg)
v, err := creds.Get()
assert.NoError(t, err)
assert.Equal(t, ExpectedAccessKey+"AWSFile", v.AccessKeyID)
assert.Equal(t, ExpectedSecretAccessKey+"AWSFile", v.SecretAccessKey)
checkCredentials(t, cfg, "AWSFile")
})
t.Run("IAM", func(t *testing.T) {
@@ -139,14 +122,9 @@ func TestMinioCredentials(t *testing.T) {
defer server.Close()
// Use the provided EC2 Instance Metadata server
creds := buildMinioCredentials(setting.MinioStorageConfig{
checkCredentials(t, setting.MinioStorageConfig{
IamEndpoint: server.URL,
})
v, err := creds.Get()
assert.NoError(t, err)
assert.Equal(t, ExpectedAccessKey+"IAM", v.AccessKeyID)
assert.Equal(t, ExpectedSecretAccessKey+"IAM", v.SecretAccessKey)
}, "IAM")
})
})
}
+16 -31
View File
@@ -15,37 +15,22 @@ import (
)
func TestObjectStoragePath(t *testing.T) {
base := ""
assert.Empty(t, buildObjectStorePath(base, "/"))
assert.Empty(t, buildObjectStorePath(base, "."))
assert.Equal(t, "a", buildObjectStorePath(base, "/a"))
assert.Equal(t, "a/b", buildObjectStorePath(base, "/a/b/"))
assert.Empty(t, buildObjectStorePathPrefix(base, ""))
assert.Equal(t, "a/", buildObjectStorePathPrefix(base, "/a/"))
base = "/"
assert.Empty(t, buildObjectStorePath(base, "/"))
assert.Empty(t, buildObjectStorePath(base, "."))
assert.Equal(t, "a", buildObjectStorePath(base, "/a"))
assert.Equal(t, "a/b", buildObjectStorePath(base, "/a/b/"))
assert.Empty(t, buildObjectStorePathPrefix(base, ""))
assert.Equal(t, "a/", buildObjectStorePathPrefix(base, "/a/"))
base = "/base"
assert.Equal(t, "base", buildObjectStorePath(base, "/"))
assert.Equal(t, "base", buildObjectStorePath(base, "."))
assert.Equal(t, "base/a", buildObjectStorePath(base, "/a"))
assert.Equal(t, "base/a/b", buildObjectStorePath(base, "/a/b/"))
assert.Equal(t, "base/", buildObjectStorePathPrefix(base, ""))
assert.Equal(t, "base/a/", buildObjectStorePathPrefix(base, "/a/"))
base = "/base/"
assert.Equal(t, "base", buildObjectStorePath(base, "/"))
assert.Equal(t, "base", buildObjectStorePath(base, "."))
assert.Equal(t, "base/a", buildObjectStorePath(base, "/a"))
assert.Equal(t, "base/a/b", buildObjectStorePath(base, "/a/b/"))
assert.Equal(t, "base/", buildObjectStorePathPrefix(base, ""))
assert.Equal(t, "base/a/", buildObjectStorePathPrefix(base, "/a/"))
for _, base := range []string{"", "/"} {
assert.Empty(t, buildObjectStorePath(base, "/"))
assert.Empty(t, buildObjectStorePath(base, "."))
assert.Equal(t, "a", buildObjectStorePath(base, "/a"))
assert.Equal(t, "a/b", buildObjectStorePath(base, "/a/b/"))
assert.Empty(t, buildObjectStorePathPrefix(base, ""))
assert.Equal(t, "a/", buildObjectStorePathPrefix(base, "/a/"))
}
for _, base := range []string{"/base", "/base/"} {
assert.Equal(t, "base", buildObjectStorePath(base, "/"))
assert.Equal(t, "base", buildObjectStorePath(base, "."))
assert.Equal(t, "base/a", buildObjectStorePath(base, "/a"))
assert.Equal(t, "base/a/b", buildObjectStorePath(base, "/a/b/"))
assert.Equal(t, "base/", buildObjectStorePathPrefix(base, ""))
assert.Equal(t, "base/a/", buildObjectStorePathPrefix(base, "/a/"))
}
}
func testStorageAccess(t *testing.T, objStore ObjectStorage) {
+26 -33
View File
@@ -12,21 +12,33 @@ import (
"github.com/stretchr/testify/require"
)
func TestPullRequestPayloadSynchronizeBeforeAfter(t *testing.T) {
payload := &PullRequestPayload{
Action: HookIssueSynchronized,
Before: "1111111111111111111111111111111111111111",
After: "2222222222222222222222222222222222222222",
Index: 12,
}
data, err := json.Marshal(payload)
require.NoError(t, err)
assert.JSONEq(t, `{
func TestPullRequestPayload(t *testing.T) {
for _, tt := range []struct {
payload PullRequestPayload
want string
}{
{
payload: PullRequestPayload{
Action: HookIssueSynchronized,
Before: "1111111111111111111111111111111111111111",
After: "2222222222222222222222222222222222222222",
Index: 12,
},
want: `
"action": "synchronized",
"before": "1111111111111111111111111111111111111111",
"after": "2222222222222222222222222222222222222222",
"after": "2222222222222222222222222222222222222222",`,
},
{
payload: PullRequestPayload{Action: HookIssueOpened, Index: 12},
want: `
"action": "opened",`,
},
} {
t.Run(string(tt.payload.Action), func(t *testing.T) {
data, err := json.Marshal(&tt.payload)
require.NoError(t, err)
assert.JSONEq(t, `{`+tt.want+`
"number": 12,
"commit_id": "",
"pull_request": null,
@@ -35,25 +47,6 @@ func TestPullRequestPayloadSynchronizeBeforeAfter(t *testing.T) {
"review": null,
"sender": null
}`, string(data))
}
func TestPullRequestPayloadNonSynchronizeOmitsBeforeAfter(t *testing.T) {
payload := &PullRequestPayload{
Action: HookIssueOpened,
Index: 12,
})
}
data, err := json.Marshal(payload)
require.NoError(t, err)
assert.JSONEq(t, `{
"action": "opened",
"number": 12,
"commit_id": "",
"pull_request": null,
"repository": null,
"requested_reviewer": null,
"review": null,
"sender": null
}`, string(data))
}
+9 -23
View File
@@ -46,39 +46,22 @@ func TestIssueTemplateStringSlice_UnmarshalYAML(t *testing.T) {
tests := []struct {
name string
content string
tmpl *IssueTemplate
want *IssueTemplate
labels []string
wantErr string
}{
{
name: "array",
content: `labels: ["a", "b", "c"]`,
tmpl: &IssueTemplate{
Labels: []string{"should_be_overwrote"},
},
want: &IssueTemplate{
Labels: []string{"a", "b", "c"},
},
labels: []string{"a", "b", "c"},
},
{
name: "string",
content: `labels: "a,b,c"`,
tmpl: &IssueTemplate{
Labels: []string{"should_be_overwrote"},
},
want: &IssueTemplate{
Labels: []string{"a", "b", "c"},
},
labels: []string{"a", "b", "c"},
},
{
name: "empty",
content: `labels:`,
tmpl: &IssueTemplate{
Labels: []string{"should_be_overwrote"},
},
want: &IssueTemplate{
Labels: nil,
},
},
{
name: "error",
@@ -87,18 +70,21 @@ labels:
a: aa
b: bb
`,
tmpl: &IssueTemplate{},
wantErr: "yaml: construct errors: line 3: cannot unmarshal !!map into IssueTemplateStringSlice",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
err := yaml.Unmarshal([]byte(tt.content), tt.tmpl)
tmpl := &IssueTemplate{}
if tt.wantErr == "" {
tmpl.Labels = []string{"should_be_overwrote"}
}
err := yaml.Unmarshal([]byte(tt.content), tmpl)
if tt.wantErr != "" {
assert.EqualError(t, err, tt.wantErr)
} else {
assert.NoError(t, err)
assert.Equal(t, tt.want, tt.tmpl)
assert.Equal(t, &IssueTemplate{Labels: tt.labels}, tmpl)
}
})
}
+33 -64
View File
@@ -15,47 +15,29 @@ import (
)
func TestSubjectBodySeparator(t *testing.T) {
test := func(input, subject, body string) {
loc := mailSubjectSplit.FindStringIndex(input)
for _, testCase := range []struct {
input, subject, body string
}{
{"Simple\n---------------\nCase", "Simple\n", "\nCase"},
{"Only\nBody", "", "Only\nBody"},
{"Minimal\n---\nseparator", "Minimal\n", "\nseparator"},
{"False --- separator", "", "False --- separator"},
{"False\n--- separator", "", "False\n--- separator"},
{"False ---\nseparator", "", "False ---\nseparator"},
{"With extra spaces\n----- \t \nBody", "With extra spaces\n", "\nBody"},
{"With leading spaces\n -------\nOnly body", "", "With leading spaces\n -------\nOnly body"},
{"Multiple\n---\n-------\n---\nSeparators", "Multiple\n", "\n-------\n---\nSeparators"},
{"Insufficient\n--\nSeparators", "", "Insufficient\n--\nSeparators"},
} {
loc := mailSubjectSplit.FindStringIndex(testCase.input)
if loc == nil {
assert.Empty(t, subject, "no subject found, but one expected")
assert.Equal(t, body, input)
assert.Empty(t, testCase.subject, "no subject found, but one expected")
assert.Equal(t, testCase.body, testCase.input)
} else {
assert.Equal(t, subject, input[0:loc[0]])
assert.Equal(t, body, input[loc[1]:])
assert.Equal(t, testCase.subject, testCase.input[0:loc[0]])
assert.Equal(t, testCase.body, testCase.input[loc[1]:])
}
}
test("Simple\n---------------\nCase",
"Simple\n",
"\nCase")
test("Only\nBody",
"",
"Only\nBody")
test("Minimal\n---\nseparator",
"Minimal\n",
"\nseparator")
test("False --- separator",
"",
"False --- separator")
test("False\n--- separator",
"",
"False\n--- separator")
test("False ---\nseparator",
"",
"False ---\nseparator")
test("With extra spaces\n----- \t \nBody",
"With extra spaces\n",
"\nBody")
test("With leading spaces\n -------\nOnly body",
"",
"With leading spaces\n -------\nOnly body")
test("Multiple\n---\n-------\n---\nSeparators",
"Multiple\n",
"\n-------\n---\nSeparators")
test("Insufficient\n--\nSeparators",
"",
"Insufficient\n--\nSeparators")
}
func TestSanitizeHTML(t *testing.T) {
@@ -148,33 +130,20 @@ func TestQueryBuild(t *testing.T) {
assert.Equal(t, "a=1&b=2&", string(QueryBuild("a=1&", "b", 2)))
})
t.Run("replace", func(t *testing.T) {
assert.Equal(t, "a=1&c=d&e=f", string(QueryBuild("a=b&c=d&e=f", "a", 1)))
assert.Equal(t, "a=b&c=1&e=f", string(QueryBuild("a=b&c=d&e=f", "c", 1)))
assert.Equal(t, "a=b&c=d&e=1", string(QueryBuild("a=b&c=d&e=f", "e", 1)))
assert.Equal(t, "a=b&c=d&e=f&k=1", string(QueryBuild("a=b&c=d&e=f", "k", 1)))
})
t.Run("replace-&", func(t *testing.T) {
assert.Equal(t, "&a=1&c=d&e=f", string(QueryBuild("&a=b&c=d&e=f", "a", 1)))
assert.Equal(t, "&a=b&c=1&e=f", string(QueryBuild("&a=b&c=d&e=f", "c", 1)))
assert.Equal(t, "&a=b&c=d&e=1", string(QueryBuild("&a=b&c=d&e=f", "e", 1)))
assert.Equal(t, "&a=b&c=d&e=f&k=1", string(QueryBuild("&a=b&c=d&e=f", "k", 1)))
})
t.Run("delete", func(t *testing.T) {
assert.Equal(t, "c=d&e=f", string(QueryBuild("a=b&c=d&e=f", "a", "")))
assert.Equal(t, "a=b&e=f", string(QueryBuild("a=b&c=d&e=f", "c", "")))
assert.Equal(t, "a=b&c=d", string(QueryBuild("a=b&c=d&e=f", "e", "")))
assert.Equal(t, "a=b&c=d&e=f", string(QueryBuild("a=b&c=d&e=f", "k", "")))
})
t.Run("delete-&", func(t *testing.T) {
assert.Equal(t, "&c=d&e=f", string(QueryBuild("&a=b&c=d&e=f", "a", "")))
assert.Equal(t, "&a=b&e=f", string(QueryBuild("&a=b&c=d&e=f", "c", "")))
assert.Equal(t, "&a=b&c=d", string(QueryBuild("&a=b&c=d&e=f", "e", "")))
assert.Equal(t, "&a=b&c=d&e=f", string(QueryBuild("&a=b&c=d&e=f", "k", "")))
})
for _, prefix := range []string{"", "&"} {
t.Run("replace"+prefix, func(t *testing.T) {
assert.Equal(t, prefix+"a=1&c=d&e=f", string(QueryBuild(prefix+"a=b&c=d&e=f", "a", 1)))
assert.Equal(t, prefix+"a=b&c=1&e=f", string(QueryBuild(prefix+"a=b&c=d&e=f", "c", 1)))
assert.Equal(t, prefix+"a=b&c=d&e=1", string(QueryBuild(prefix+"a=b&c=d&e=f", "e", 1)))
assert.Equal(t, prefix+"a=b&c=d&e=f&k=1", string(QueryBuild(prefix+"a=b&c=d&e=f", "k", 1)))
})
t.Run("delete"+prefix, func(t *testing.T) {
assert.Equal(t, prefix+"c=d&e=f", string(QueryBuild(prefix+"a=b&c=d&e=f", "a", "")))
assert.Equal(t, prefix+"a=b&e=f", string(QueryBuild(prefix+"a=b&c=d&e=f", "c", "")))
assert.Equal(t, prefix+"a=b&c=d", string(QueryBuild(prefix+"a=b&c=d&e=f", "e", "")))
assert.Equal(t, prefix+"a=b&c=d&e=f", string(QueryBuild(prefix+"a=b&c=d&e=f", "k", "")))
})
}
}
const queryNonASCII = " !\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~" // all non-letter & non-number chars
+1 -12
View File
@@ -39,21 +39,10 @@ func TestDateTime(t *testing.T) {
actual = du.FullTime(refTimeStamp)
assert.EqualValues(t, `<relative-time weekday="" year="numeric" format="datetime" month="short" day="numeric" hour="numeric" minute="numeric" second="numeric" data-tooltip-content data-tooltip-interactive="true" datetime="2017-12-31T19:00:00-05:00">2017-12-31 19:00:00 -05:00</relative-time>`, actual)
}
func TestTimeSince(t *testing.T) {
testTz, _ := time.LoadLocation("America/New_York")
defer test.MockVariableValue(&setting.DefaultUILocation, testTz)()
defer test.MockVariableValue(&setting.IsProd, true)()
defer test.MockVariableValue(&setting.IsInTesting, false)()
du := NewDateUtils()
assert.EqualValues(t, "-", du.TimeSince(nil))
refTimeStr := "2018-01-01T00:00:00Z"
refTime, _ := time.Parse(time.RFC3339, refTimeStr)
actual := du.TimeSince(refTime)
actual = du.TimeSince(refTime)
assert.EqualValues(t, `<relative-time prefix="" tense="past" datetime="2018-01-01T00:00:00Z" data-tooltip-content data-tooltip-interactive="true">2018-01-01 00:00:00 +00:00</relative-time>`, actual)
actual = timeSinceTo(&refTime, time.Time{})
+5 -27
View File
@@ -77,40 +77,18 @@ func TestRenderRepoComment(t *testing.T) {
}
t.Run("RenderCommitBody", func(t *testing.T) {
defer test.MockVariableValue(&markup.RenderBehaviorForTesting.DisableAdditionalAttributes, true)()
type args struct {
msg string
}
tests := []struct {
name string
args args
want template.HTML
msg string
}{
{
name: "multiple lines",
args: args{
msg: "first line\nsecond line",
},
want: "second line",
},
{
name: "multiple lines with leading newlines",
args: args{
msg: "\n\n\n\nfirst line\nsecond line",
},
want: "second line",
},
{
name: "multiple lines with trailing newlines",
args: args{
msg: "first line\nsecond line\n\n\n",
},
want: "second line",
},
{"multiple lines", "first line\nsecond line"},
{"multiple lines with leading newlines", "\n\n\n\nfirst line\nsecond line"},
{"multiple lines with trailing newlines", "first line\nsecond line\n\n\n"},
}
ut := newTestRenderUtils(t)
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
assert.Equalf(t, tt.want, ut.RenderCommitBody(tt.args.msg, mockRepo), "RenderCommitBody(%v, %v)", tt.args.msg, nil)
assert.Equalf(t, template.HTML("second line"), ut.RenderCommitBody(tt.msg, mockRepo), "RenderCommitBody(%v, %v)", tt.msg, nil)
})
}
+32 -61
View File
@@ -10,65 +10,36 @@ import (
)
func TestDiffSliceBasic(t *testing.T) {
// Typical integer cases
t.Run("additions", func(t *testing.T) {
added, removed := DiffSlice([]int{1, 2}, []int{1, 2, 3})
assert.Equal(t, []int{3}, added)
assert.Empty(t, removed)
})
t.Run("removals", func(t *testing.T) {
added, removed := DiffSlice([]int{1, 2, 3}, []int{1, 2})
assert.Empty(t, added)
assert.Equal(t, []int{3}, removed)
})
t.Run("no changes", func(t *testing.T) {
added, removed := DiffSlice([]int{1, 2}, []int{1, 2})
assert.Empty(t, added)
assert.Empty(t, removed)
})
t.Run("empty slices", func(t *testing.T) {
added, removed := DiffSlice([]int{}, []int{})
assert.Empty(t, added)
assert.Empty(t, removed)
})
t.Run("overlapping elements", func(t *testing.T) {
added, removed := DiffSlice([]int{1, 2, 4}, []int{2, 3, 4})
assert.Equal(t, []int{3}, added)
assert.Equal(t, []int{1}, removed)
})
}
func TestDiffSliceOrderAndDuplicates(t *testing.T) {
oldSlice := []int{1, 2, 2, 3}
newSlice := []int{2, 4, 2, 5}
added, removed := DiffSlice(oldSlice, newSlice)
assert.Equal(t, []int{4, 5}, added)
assert.Equal(t, []int{1, 3}, removed)
}
func TestDiffSliceDeduplicatesOutput(t *testing.T) {
// Test case from issue: newSlice contains [4, 4, 5] and oldSlice is [1]
// added should return [4, 5], not [4, 4, 5]
t.Run("deduplicates added", func(t *testing.T) {
added, removed := DiffSlice([]int{1}, []int{4, 4, 5})
assert.Equal(t, []int{4, 5}, added)
assert.Equal(t, []int{1}, removed)
})
t.Run("deduplicates removed", func(t *testing.T) {
added, removed := DiffSlice([]int{1, 1, 2}, []int{3})
assert.Equal(t, []int{3}, added)
assert.Equal(t, []int{1, 2}, removed)
})
t.Run("deduplicates both", func(t *testing.T) {
added, removed := DiffSlice([]int{1, 1, 2, 2}, []int{3, 3, 4, 4})
assert.Equal(t, []int{3, 4}, added)
assert.Equal(t, []int{1, 2}, removed)
})
for _, testCase := range []struct {
name string
oldSlice, newSlice []int
expectedAdded, expectedRemoved []int
}{
// Typical integer cases
{"additions", []int{1, 2}, []int{1, 2, 3}, []int{3}, nil},
{"removals", []int{1, 2, 3}, []int{1, 2}, nil, []int{3}},
{"no changes", []int{1, 2}, []int{1, 2}, nil, nil},
{"empty slices", []int{}, []int{}, nil, nil},
{"overlapping elements", []int{1, 2, 4}, []int{2, 3, 4}, []int{3}, []int{1}},
{"order and duplicates", []int{1, 2, 2, 3}, []int{2, 4, 2, 5}, []int{4, 5}, []int{1, 3}},
// Test case from issue: newSlice contains [4, 4, 5] and oldSlice is [1]
// added should return [4, 5], not [4, 4, 5]
{"deduplicates added", []int{1}, []int{4, 4, 5}, []int{4, 5}, []int{1}},
{"deduplicates removed", []int{1, 1, 2}, []int{3}, []int{3}, []int{1, 2}},
{"deduplicates both", []int{1, 1, 2, 2}, []int{3, 3, 4, 4}, []int{3, 4}, []int{1, 2}},
} {
t.Run(testCase.name, func(t *testing.T) {
added, removed := DiffSlice(testCase.oldSlice, testCase.newSlice)
if testCase.expectedAdded == nil {
assert.Empty(t, added)
} else {
assert.Equal(t, testCase.expectedAdded, added)
}
if testCase.expectedRemoved == nil {
assert.Empty(t, removed)
} else {
assert.Equal(t, testCase.expectedRemoved, removed)
}
})
}
}
@@ -12,24 +12,16 @@ import (
)
func TestFileBackedBuffer(t *testing.T) {
cases := []struct {
MaxMemorySize int
Data string
}{
{5, "test"},
{5, "testtest"},
}
for _, c := range cases {
buf := New(c.MaxMemorySize, t.TempDir())
_, err := io.Copy(buf, strings.NewReader(c.Data))
for _, content := range []string{"test", "testtest"} {
buf := New(5, t.TempDir())
_, err := io.Copy(buf, strings.NewReader(content))
assert.NoError(t, err)
assert.EqualValues(t, len(c.Data), buf.Size())
assert.EqualValues(t, len(content), buf.Size())
data, err := io.ReadAll(buf)
assert.NoError(t, err)
assert.Equal(t, c.Data, string(data))
assert.Equal(t, content, string(data))
assert.NoError(t, buf.Close())
}
+15 -20
View File
@@ -26,28 +26,23 @@ func TestReadWithLimit(t *testing.T) {
bs := []byte("0123456789abcdef")
// normal test
buf, err := readWithLimit(bytes.NewBuffer(bs), 5, 2)
assert.NoError(t, err)
assert.Equal(t, []byte("01"), buf)
buf, err = readWithLimit(bytes.NewBuffer(bs), 5, 5)
assert.NoError(t, err)
assert.Equal(t, []byte("01234"), buf)
buf, err = readWithLimit(bytes.NewBuffer(bs), 5, 6)
assert.NoError(t, err)
assert.Equal(t, []byte("012345"), buf)
buf, err = readWithLimit(bytes.NewBuffer(bs), 5, len(bs))
assert.NoError(t, err)
assert.Equal(t, []byte("0123456789abcdef"), buf)
buf, err = readWithLimit(bytes.NewBuffer(bs), 5, 100)
assert.NoError(t, err)
assert.Equal(t, []byte("0123456789abcdef"), buf)
for _, testCase := range []struct {
limit int
expected string
}{
{2, "01"},
{5, "01234"},
{6, "012345"},
{len(bs), "0123456789abcdef"},
{100, "0123456789abcdef"},
} {
buf, err := readWithLimit(bytes.NewBuffer(bs), 5, testCase.limit)
assert.NoError(t, err)
assert.Equal(t, []byte(testCase.expected), buf)
}
// test with error
buf, err = readWithLimit(&readerWithError{bytes.NewBuffer(bs)}, 5, 10)
buf, err := readWithLimit(&readerWithError{bytes.NewBuffer(bs)}, 5, 10)
assert.NoError(t, err)
assert.Equal(t, []byte("0123456789"), buf)
-5
View File
@@ -25,11 +25,6 @@ func TestKeygen(t *testing.T) {
assert.Regexp(t, "^-----BEGIN RSA PRIVATE KEY-----.*", priv)
assert.Regexp(t, "^-----BEGIN PUBLIC KEY-----.*", pub)
}
func TestSignUsingKeys(t *testing.T) {
priv, pub, err := GenerateKeyPair(2048)
assert.NoError(t, err)
privPem, _ := pem.Decode([]byte(priv))
if privPem == nil || privPem.Type != "RSA PRIVATE KEY" {
+4 -19
View File
@@ -159,34 +159,19 @@ func TestCleanPath(t *testing.T) {
{[]string{`a`}, `a`},
{[]string{`/a/`}, `a`},
{[]string{`../a/`, `../b`, `c/..`, `d`}, `a/b/d`},
{[]string{`a\..\b`}, `a\..\b`},
{[]string{`a`, ``, `b`}, `a/b`},
{[]string{`a`, `..`, `b`}, `a/b`},
{[]string{`lfs`, `repo/..`, `user/../path`}, `lfs/path`},
}
for _, c := range cases {
assert.Equal(t, c.expected, PathJoinRel(c.elems...), "case: %v", c.elems)
}
cases = []struct {
elems []string
expected string
}{
{[]string{}, ``},
{[]string{``}, ``},
{[]string{`..`}, `.`},
{[]string{`a`}, `a`},
{[]string{`/a/`}, `a`},
{[]string{`../a/`, `../b`, `c/..`, `d`}, `a/b/d`},
{[]string{`a\..\b`}, `b`},
{[]string{`a`, ``, `b`}, `a/b`},
{[]string{`a`, `..`, `b`}, `a/b`},
{[]string{`lfs`, `repo/..`, `user/../path`}, `lfs/path`},
}
for _, c := range cases {
assert.Equal(t, c.expected, PathJoinRelX(c.elems...), "case: %v", c.elems)
}
backslashPath := []string{`a\..\b`}
assert.Equal(t, `a\..\b`, PathJoinRel(backslashPath...), "case: %v", backslashPath)
assert.Equal(t, `b`, PathJoinRelX(backslashPath...), "case: %v", backslashPath)
// for POSIX only, but the result is similar on Windows, because the first element must be an absolute path
if consts.IsWindows {
cases = []struct {
-2
View File
@@ -27,7 +27,6 @@ func TestSliceSortedEqual(t *testing.T) {
assert.True(t, SliceSortedEqual([]int{}, []int{}))
assert.True(t, SliceSortedEqual([]int(nil), nil))
assert.True(t, SliceSortedEqual([]int(nil), []int{}))
assert.True(t, SliceSortedEqual([]int{}, []int{}))
assert.True(t, SliceSortedEqual([]string{"2", "0", "2", "3"}, []string{"2", "0", "2", "3"}))
assert.True(t, SliceSortedEqual([]float64{2, 0, 2, 3}, []float64{2, 0, 2, 3}))
@@ -47,7 +46,6 @@ func TestSliceRemoveAll(t *testing.T) {
assert.ElementsMatch(t, []int{2, 0, 2, 3}, SliceRemoveAll([]int{2, 0, 2, 3}, 4))
assert.Empty(t, SliceRemoveAll([]int{}, 0))
assert.ElementsMatch(t, []int(nil), SliceRemoveAll([]int(nil), 0))
assert.Empty(t, SliceRemoveAll([]int{}, 0))
assert.ElementsMatch(t, []string{"2", "2", "3"}, SliceRemoveAll([]string{"2", "0", "2", "3"}, "0"))
assert.ElementsMatch(t, []float64{2, 2, 3}, SliceRemoveAll([]float64{2, 0, 2, 3}, 0))
+25 -34
View File
@@ -10,40 +10,31 @@ import (
)
func TestOnceValue(t *testing.T) {
t.Run("RepeatCall", func(t *testing.T) {
callCount := 0
o := OnceValue[int]{Func: func() int {
callCount++
return 42
}}
assert.Equal(t, 42, o.Value())
assert.Equal(t, 42, o.Value())
assert.Equal(t, 1, callCount)
o.Reset()
assert.Equal(t, 42, o.Value())
assert.Equal(t, 2, callCount)
assert.Equal(t, 42, o.Value())
assert.Equal(t, 2, callCount)
})
t.Run("Panic", func(t *testing.T) {
callCount := 0
doPanic := true
o := OnceValue[int]{Func: func() int {
callCount++
for _, name := range []string{"RepeatCall", "Panic"} {
t.Run(name, func(t *testing.T) {
callCount := 0
doPanic := name == "Panic"
o := OnceValue[int]{Func: func() int {
callCount++
if doPanic {
panic("some error")
}
return 42
}}
if doPanic {
panic("some error")
assert.PanicsWithValue(t, "some error", func() { o.Value() })
assert.PanicsWithValue(t, "some error", func() { o.Value() })
} else {
assert.Equal(t, 42, o.Value())
assert.Equal(t, 42, o.Value())
}
return 42
}}
assert.PanicsWithValue(t, "some error", func() { o.Value() })
assert.PanicsWithValue(t, "some error", func() { o.Value() })
assert.Equal(t, 1, callCount)
doPanic = false
o.Reset()
assert.Equal(t, 42, o.Value())
assert.Equal(t, 2, callCount)
assert.Equal(t, 42, o.Value())
assert.Equal(t, 2, callCount)
})
assert.Equal(t, 1, callCount)
doPanic = false
o.Reset()
assert.Equal(t, 42, o.Value())
assert.Equal(t, 2, callCount)
assert.Equal(t, 42, o.Value())
assert.Equal(t, 2, callCount)
})
}
}
+10 -29
View File
@@ -40,26 +40,13 @@ func Test_NormalizeEOL(t *testing.T) {
"Ends without EOLtoo.",
}
buildEOLData := func(data []string, eol string) []byte {
return []byte(strings.Join(data, eol))
for _, data := range [][]string{data1, data2} {
unix := []byte(strings.Join(data, "\n"))
for _, input := range [][]byte{[]byte(strings.Join(data, "\r\n")), []byte(strings.Join(data, "\r")), unix} {
assert.Equal(t, unix, NormalizeEOL(input))
}
}
dos := buildEOLData(data1, "\r\n")
unix := buildEOLData(data1, "\n")
mac := buildEOLData(data1, "\r")
assert.Equal(t, unix, NormalizeEOL(dos))
assert.Equal(t, unix, NormalizeEOL(mac))
assert.Equal(t, unix, NormalizeEOL(unix))
dos = buildEOLData(data2, "\r\n")
unix = buildEOLData(data2, "\n")
mac = buildEOLData(data2, "\r")
assert.Equal(t, unix, NormalizeEOL(dos))
assert.Equal(t, unix, NormalizeEOL(mac))
assert.Equal(t, unix, NormalizeEOL(unix))
assert.Equal(t, []byte("one liner"), NormalizeEOL([]byte("one liner")))
assert.Equal(t, []byte("\n"), NormalizeEOL([]byte("\n")))
assert.Equal(t, []byte("\ntwo liner"), NormalizeEOL([]byte("\ntwo liner")))
@@ -103,17 +90,11 @@ func Test_RandomString(t *testing.T) {
}
func Test_RandomBytes(t *testing.T) {
bytes1 := CryptoRandomBytes(32)
bytes2 := CryptoRandomBytes(32)
assert.NotEqual(t, bytes1, bytes2)
bytes3 := CryptoRandomBytes(256)
bytes4 := CryptoRandomBytes(256)
assert.NotEqual(t, bytes3, bytes4)
for _, length := range []int64{32, 256} {
bytes1 := CryptoRandomBytes(length)
bytes2 := CryptoRandomBytes(length)
assert.NotEqual(t, bytes1, bytes2)
}
}
// Test case for any function which accepts and returns a single string.
+27 -243
View File
@@ -8,249 +8,33 @@ import (
)
func Test_GitRefNameValidation(t *testing.T) {
gitRefNameValidationTestCases := []validationTestCase{
{
description: "Reference name contains only characters",
data: &TestForm{
BranchName: "test",
},
},
{
description: "Reference name contains single slash",
data: &TestForm{
BranchName: "feature/test",
},
},
{
description: "Reference name has allowed special characters",
data: &TestForm{
BranchName: "debian/1%1.6.0-2",
},
},
{
description: "Reference name contains backslash",
data: &TestForm{
BranchName: "feature\\test",
},
expectedErrors: BindingErrors{
BindingError{
FieldNames: []string{"BranchName"},
Classification: ErrGitRefName,
Message: "GitRefName",
},
},
},
{
description: "Reference name starts with dot",
data: &TestForm{
BranchName: ".test",
},
expectedErrors: BindingErrors{
BindingError{
FieldNames: []string{"BranchName"},
Classification: ErrGitRefName,
Message: "GitRefName",
},
},
},
{
description: "Reference name ends with dot",
data: &TestForm{
BranchName: "test.",
},
expectedErrors: BindingErrors{
BindingError{
FieldNames: []string{"BranchName"},
Classification: ErrGitRefName,
Message: "GitRefName",
},
},
},
{
description: "Reference name starts with slash",
data: &TestForm{
BranchName: "/test",
},
expectedErrors: BindingErrors{
BindingError{
FieldNames: []string{"BranchName"},
Classification: ErrGitRefName,
Message: "GitRefName",
},
},
},
{
description: "Reference name ends with slash",
data: &TestForm{
BranchName: "test/",
},
expectedErrors: BindingErrors{
BindingError{
FieldNames: []string{"BranchName"},
Classification: ErrGitRefName,
Message: "GitRefName",
},
},
},
{
description: "Reference name ends with .lock",
data: &TestForm{
BranchName: "test.lock",
},
expectedErrors: BindingErrors{
BindingError{
FieldNames: []string{"BranchName"},
Classification: ErrGitRefName,
Message: "GitRefName",
},
},
},
{
description: "Reference name contains multiple consecutive dots",
data: &TestForm{
BranchName: "te..st",
},
expectedErrors: BindingErrors{
BindingError{
FieldNames: []string{"BranchName"},
Classification: ErrGitRefName,
Message: "GitRefName",
},
},
},
{
description: "Reference name contains multiple consecutive slashes",
data: &TestForm{
BranchName: "te//st",
},
expectedErrors: BindingErrors{
BindingError{
FieldNames: []string{"BranchName"},
Classification: ErrGitRefName,
Message: "GitRefName",
},
},
},
{
description: "Reference name is single @",
data: &TestForm{
BranchName: "@",
},
expectedErrors: BindingErrors{
BindingError{
FieldNames: []string{"BranchName"},
Classification: ErrGitRefName,
Message: "GitRefName",
},
},
},
{
description: "Reference name has @{",
data: &TestForm{
BranchName: "branch@{",
},
expectedErrors: BindingErrors{
BindingError{
FieldNames: []string{"BranchName"},
Classification: ErrGitRefName,
Message: "GitRefName",
},
},
},
{
description: "Reference name has unallowed special character ~",
data: &TestForm{
BranchName: "~debian/1%1.6.0-2",
},
expectedErrors: BindingErrors{
BindingError{
FieldNames: []string{"BranchName"},
Classification: ErrGitRefName,
Message: "GitRefName",
},
},
},
{
description: "Reference name has unallowed special character *",
data: &TestForm{
BranchName: "*debian/1%1.6.0-2",
},
expectedErrors: BindingErrors{
BindingError{
FieldNames: []string{"BranchName"},
Classification: ErrGitRefName,
Message: "GitRefName",
},
},
},
{
description: "Reference name has unallowed special character ?",
data: &TestForm{
BranchName: "?debian/1%1.6.0-2",
},
expectedErrors: BindingErrors{
BindingError{
FieldNames: []string{"BranchName"},
Classification: ErrGitRefName,
Message: "GitRefName",
},
},
},
{
description: "Reference name has unallowed special character ^",
data: &TestForm{
BranchName: "^debian/1%1.6.0-2",
},
expectedErrors: BindingErrors{
BindingError{
FieldNames: []string{"BranchName"},
Classification: ErrGitRefName,
Message: "GitRefName",
},
},
},
{
description: "Reference name has unallowed special character :",
data: &TestForm{
BranchName: "debian:jessie",
},
expectedErrors: BindingErrors{
BindingError{
FieldNames: []string{"BranchName"},
Classification: ErrGitRefName,
Message: "GitRefName",
},
},
},
{
description: "Reference name has unallowed special character (whitespace)",
data: &TestForm{
BranchName: "debian jessie",
},
expectedErrors: BindingErrors{
BindingError{
FieldNames: []string{"BranchName"},
Classification: ErrGitRefName,
Message: "GitRefName",
},
},
},
{
description: "Reference name has unallowed special character [",
data: &TestForm{
BranchName: "debian[jessie",
},
expectedErrors: BindingErrors{
BindingError{
FieldNames: []string{"BranchName"},
Classification: ErrGitRefName,
Message: "GitRefName",
},
},
},
}
for _, testCase := range gitRefNameValidationTestCases {
expectedErrors := BindingErrors{{
FieldNames: []string{"BranchName"},
Classification: ErrGitRefName,
Message: "GitRefName",
}}
for _, testCase := range []validationTestCase{
{"Reference name contains only characters", &TestForm{BranchName: "test"}, nil},
{"Reference name contains single slash", &TestForm{BranchName: "feature/test"}, nil},
{"Reference name has allowed special characters", &TestForm{BranchName: "debian/1%1.6.0-2"}, nil},
{"Reference name contains backslash", &TestForm{BranchName: "feature\\test"}, expectedErrors},
{"Reference name starts with dot", &TestForm{BranchName: ".test"}, expectedErrors},
{"Reference name ends with dot", &TestForm{BranchName: "test."}, expectedErrors},
{"Reference name starts with slash", &TestForm{BranchName: "/test"}, expectedErrors},
{"Reference name ends with slash", &TestForm{BranchName: "test/"}, expectedErrors},
{"Reference name ends with .lock", &TestForm{BranchName: "test.lock"}, expectedErrors},
{"Reference name contains multiple consecutive dots", &TestForm{BranchName: "te..st"}, expectedErrors},
{"Reference name contains multiple consecutive slashes", &TestForm{BranchName: "te//st"}, expectedErrors},
{"Reference name is single @", &TestForm{BranchName: "@"}, expectedErrors},
{"Reference name has @{", &TestForm{BranchName: "branch@{"}, expectedErrors},
{"Reference name has unallowed special character ~", &TestForm{BranchName: "~debian/1%1.6.0-2"}, expectedErrors},
{"Reference name has unallowed special character *", &TestForm{BranchName: "*debian/1%1.6.0-2"}, expectedErrors},
{"Reference name has unallowed special character ?", &TestForm{BranchName: "?debian/1%1.6.0-2"}, expectedErrors},
{"Reference name has unallowed special character ^", &TestForm{BranchName: "^debian/1%1.6.0-2"}, expectedErrors},
{"Reference name has unallowed special character :", &TestForm{BranchName: "debian:jessie"}, expectedErrors},
{"Reference name has unallowed special character (whitespace)", &TestForm{BranchName: "debian jessie"}, expectedErrors},
{"Reference name has unallowed special character [", &TestForm{BranchName: "debian[jessie"}, expectedErrors},
} {
t.Run(testCase.description, func(t *testing.T) {
performValidationTest(t, testCase)
})
+16 -86
View File
@@ -8,92 +8,22 @@ import (
)
func Test_ValidURLValidation(t *testing.T) {
urlValidationTestCases := []validationTestCase{
{
description: "Empty URL",
data: &TestForm{
URL: "",
},
},
{
description: "URL without port",
data: &TestForm{
URL: "http://test.lan/",
},
},
{
description: "URL with port",
data: &TestForm{
URL: "http://test.lan:3000/",
},
},
{
description: "URL with IPv6 address without port",
data: &TestForm{
URL: "http://[::1]/",
},
},
{
description: "URL with IPv6 address with port",
data: &TestForm{
URL: "http://[::1]:3000/",
},
},
{
description: "Invalid URL",
data: &TestForm{
URL: "http//test.lan/",
},
expectedErrors: BindingErrors{
BindingError{
FieldNames: []string{"URL"},
Classification: "UrlError",
Message: "Url",
},
},
},
{
description: "Invalid schema",
data: &TestForm{
URL: "ftp://test.lan/",
},
expectedErrors: BindingErrors{
BindingError{
FieldNames: []string{"URL"},
Classification: "UrlError",
Message: "Url",
},
},
},
{
description: "Invalid port",
data: &TestForm{
URL: "http://test.lan:3x4/",
},
expectedErrors: BindingErrors{
BindingError{
FieldNames: []string{"URL"},
Classification: "UrlError",
Message: "Url",
},
},
},
{
description: "Invalid port with IPv6 address",
data: &TestForm{
URL: "http://[::1]:3x4/",
},
expectedErrors: BindingErrors{
BindingError{
FieldNames: []string{"URL"},
Classification: "UrlError",
Message: "Url",
},
},
},
}
for _, testCase := range urlValidationTestCases {
expectedErrors := BindingErrors{{
FieldNames: []string{"URL"},
Classification: "UrlError",
Message: "Url",
}}
for _, testCase := range []validationTestCase{
{"Empty URL", &TestForm{URL: ""}, nil},
{"URL without port", &TestForm{URL: "http://test.lan/"}, nil},
{"URL with port", &TestForm{URL: "http://test.lan:3000/"}, nil},
{"URL with IPv6 address without port", &TestForm{URL: "http://[::1]/"}, nil},
{"URL with IPv6 address with port", &TestForm{URL: "http://[::1]:3000/"}, nil},
{"Invalid URL", &TestForm{URL: "http//test.lan/"}, expectedErrors},
{"Invalid schema", &TestForm{URL: "ftp://test.lan/"}, expectedErrors},
{"Invalid port", &TestForm{URL: "http://test.lan:3x4/"}, expectedErrors},
{"Invalid port with IPv6 address", &TestForm{URL: "http://[::1]:3x4/"}, expectedErrors},
} {
t.Run(testCase.description, func(t *testing.T) {
performValidationTest(t, testCase)
})
+27 -39
View File
@@ -28,43 +28,31 @@ func TestRouteMock(t *testing.T) {
}
r.Get("/foo", middleware1, RouterMockPoint("mock-point"), middleware2, handler)
// normal request
recorder := httptest.NewRecorder()
req, err := http.NewRequest(http.MethodGet, "http://localhost:8000/foo", nil)
assert.NoError(t, err)
r.ServeHTTP(recorder, req)
assert.Len(t, recorder.Header(), 3)
assert.Equal(t, "m1", recorder.Header().Get("X-Test-Middleware1"))
assert.Equal(t, "m2", recorder.Header().Get("X-Test-Middleware2"))
assert.Equal(t, "h", recorder.Header().Get("X-Test-Handler"))
RouteMockReset()
// mock at "mock-point"
RouteMock("mock-point", func(resp http.ResponseWriter, req *http.Request) {
resp.Header().Set("X-Test-MockPoint", "a")
resp.WriteHeader(http.StatusOK)
})
recorder = httptest.NewRecorder()
req, err = http.NewRequest(http.MethodGet, "http://localhost:8000/foo", nil)
assert.NoError(t, err)
r.ServeHTTP(recorder, req)
assert.Len(t, recorder.Header(), 2)
assert.Equal(t, "m1", recorder.Header().Get("X-Test-Middleware1"))
assert.Equal(t, "a", recorder.Header().Get("X-Test-MockPoint"))
RouteMockReset()
// mock at MockAfterMiddlewares
RouteMock(MockAfterMiddlewares, func(resp http.ResponseWriter, req *http.Request) {
resp.Header().Set("X-Test-MockPoint", "b")
resp.WriteHeader(http.StatusOK)
})
recorder = httptest.NewRecorder()
req, err = http.NewRequest(http.MethodGet, "http://localhost:8000/foo", nil)
assert.NoError(t, err)
r.ServeHTTP(recorder, req)
assert.Len(t, recorder.Header(), 3)
assert.Equal(t, "m1", recorder.Header().Get("X-Test-Middleware1"))
assert.Equal(t, "m2", recorder.Header().Get("X-Test-Middleware2"))
assert.Equal(t, "b", recorder.Header().Get("X-Test-MockPoint"))
RouteMockReset()
for _, tc := range []struct {
mockPoint, mockValue string
headers [][2]string
}{
// normal request
{headers: [][2]string{{"X-Test-Middleware1", "m1"}, {"X-Test-Middleware2", "m2"}, {"X-Test-Handler", "h"}}},
// mock at "mock-point"
{mockPoint: "mock-point", mockValue: "a", headers: [][2]string{{"X-Test-Middleware1", "m1"}, {"X-Test-MockPoint", "a"}}},
// mock at MockAfterMiddlewares
{mockPoint: MockAfterMiddlewares, mockValue: "b", headers: [][2]string{{"X-Test-Middleware1", "m1"}, {"X-Test-Middleware2", "m2"}, {"X-Test-MockPoint", "b"}}},
} {
if tc.mockPoint != "" {
RouteMock(tc.mockPoint, func(resp http.ResponseWriter, req *http.Request) {
resp.Header().Set("X-Test-MockPoint", tc.mockValue)
resp.WriteHeader(http.StatusOK)
})
}
recorder := httptest.NewRecorder()
req, err := http.NewRequest(http.MethodGet, "http://localhost:8000/foo", nil)
assert.NoError(t, err)
r.ServeHTTP(recorder, req)
assert.Len(t, recorder.Header(), len(tc.headers))
for _, header := range tc.headers {
assert.Equal(t, header[1], recorder.Header().Get(header[0]))
}
RouteMockReset()
}
}
+12 -24
View File
@@ -208,30 +208,18 @@ func TestRouter(t *testing.T) {
method: "GET",
handlerMarks: []string{"not-found:/api/v1"},
})
testRoute(t, "GET /api/v1/repos/the-user/the-repo/branches", resultStruct{
method: "GET",
pathParams: map[string]string{"username": "the-user", "reponame": "the-repo"},
})
testRoute(t, "POST /api/v1/repos/the-user/the-repo/branches", resultStruct{
method: "POST",
pathParams: map[string]string{"username": "the-user", "reponame": "the-repo"},
})
testRoute(t, "GET /api/v1/repos/the-user/the-repo/branches/master", resultStruct{
method: "GET",
pathParams: map[string]string{"username": "the-user", "reponame": "the-repo", "name": "master"},
})
testRoute(t, "PATCH /api/v1/repos/the-user/the-repo/branches/master", resultStruct{
method: "PATCH",
pathParams: map[string]string{"username": "the-user", "reponame": "the-repo", "name": "master"},
})
testRoute(t, "DELETE /api/v1/repos/the-user/the-repo/branches/master", resultStruct{
method: "DELETE",
pathParams: map[string]string{"username": "the-user", "reponame": "the-repo", "name": "master"},
})
for _, method := range []string{"GET", "POST"} {
testRoute(t, method+" /api/v1/repos/the-user/the-repo/branches", resultStruct{
method: method,
pathParams: map[string]string{"username": "the-user", "reponame": "the-repo"},
})
}
for _, method := range []string{"GET", "PATCH", "DELETE"} {
testRoute(t, method+" /api/v1/repos/the-user/the-repo/branches/master", resultStruct{
method: method,
pathParams: map[string]string{"username": "the-user", "reponame": "the-repo", "name": "master"},
})
}
})
t.Run("MatchPath", func(t *testing.T) {
+33 -83
View File
@@ -21,47 +21,35 @@ func TestWriterReader(t *testing.T) {
result := bytes.NewBuffer(nil)
t.Run("regular", func(t *testing.T) {
result.Reset()
writer, err := NewWriter(result)
require.NoError(t, err)
for _, testCase := range []struct {
name string
writerOptions []WriterOption
readerOptions []ReaderOption
}{
{"regular", nil, nil},
{"with options", []WriterOption{WithEncoderLevel(SpeedBestCompression)}, []ReaderOption{WithDecoderLowmem(true)}},
} {
t.Run(testCase.name, func(t *testing.T) {
result.Reset()
writer, err := NewWriter(result, testCase.writerOptions...)
require.NoError(t, err)
_, err = io.Copy(writer, bytes.NewReader(testData))
require.NoError(t, err)
require.NoError(t, writer.Close())
_, err = io.Copy(writer, bytes.NewReader(testData))
require.NoError(t, err)
require.NoError(t, writer.Close())
t.Logf("original size: %d, compressed size: %d, rate: %.2f%%", len(testData), result.Len(), float64(result.Len())/float64(len(testData))*100)
t.Logf("original size: %d, compressed size: %d, rate: %.2f%%", len(testData), result.Len(), float64(result.Len())/float64(len(testData))*100)
reader, err := NewReader(result)
require.NoError(t, err)
reader, err := NewReader(result, testCase.readerOptions...)
require.NoError(t, err)
data, err := io.ReadAll(reader)
require.NoError(t, err)
require.NoError(t, reader.Close())
data, err := io.ReadAll(reader)
require.NoError(t, err)
require.NoError(t, reader.Close())
assert.Equal(t, testData, data)
})
t.Run("with options", func(t *testing.T) {
result.Reset()
writer, err := NewWriter(result, WithEncoderLevel(SpeedBestCompression))
require.NoError(t, err)
_, err = io.Copy(writer, bytes.NewReader(testData))
require.NoError(t, err)
require.NoError(t, writer.Close())
t.Logf("original size: %d, compressed size: %d, rate: %.2f%%", len(testData), result.Len(), float64(result.Len())/float64(len(testData))*100)
reader, err := NewReader(result, WithDecoderLowmem(true))
require.NoError(t, err)
data, err := io.ReadAll(reader)
require.NoError(t, err)
require.NoError(t, reader.Close())
assert.Equal(t, testData, data)
})
assert.Equal(t, testData, data)
})
}
t.Run("rejects window above 128 MiB", func(t *testing.T) {
frameWith256MiBWindow := []byte{0x28, 0xb5, 0x2f, 0xfd, 0x00, 0x90, 0x01, 0x00, 0x00}
@@ -77,10 +65,8 @@ func TestSeekableWriterReader(t *testing.T) {
result := bytes.NewBuffer(nil)
t.Run("regular", func(t *testing.T) {
write := func(t *testing.T, testData []byte, blockSize int) {
result.Reset()
blockSize := 10000
writer, err := NewSeekableWriter(result, blockSize)
require.NoError(t, err)
@@ -89,6 +75,10 @@ func TestSeekableWriterReader(t *testing.T) {
require.NoError(t, writer.Close())
t.Logf("original size: %d, compressed size: %d, rate: %.2f%%", len(testData), result.Len(), float64(result.Len())/float64(len(testData))*100)
}
t.Run("regular", func(t *testing.T) {
write(t, testData, 10000)
reader, err := NewSeekableReader(bytes.NewReader(result.Bytes()))
require.NoError(t, err)
@@ -101,17 +91,8 @@ func TestSeekableWriterReader(t *testing.T) {
})
t.Run("seek read", func(t *testing.T) {
result.Reset()
blockSize := 10000
writer, err := NewSeekableWriter(result, blockSize)
require.NoError(t, err)
_, err = io.Copy(writer, bytes.NewReader(testData))
require.NoError(t, err)
require.NoError(t, writer.Close())
t.Logf("original size: %d, compressed size: %d, rate: %.2f%%", len(testData), result.Len(), float64(result.Len())/float64(len(testData))*100)
write(t, testData, blockSize)
assertReader := &assertReadSeeker{r: bytes.NewReader(result.Bytes())}
@@ -141,18 +122,7 @@ func TestSeekableWriterReader(t *testing.T) {
t.Run("tidy data", func(t *testing.T) {
testData := prepareTestData(t, 1000) // data size is less than a block
result.Reset()
blockSize := 10000
writer, err := NewSeekableWriter(result, blockSize)
require.NoError(t, err)
_, err = io.Copy(writer, bytes.NewReader(testData))
require.NoError(t, err)
require.NoError(t, writer.Close())
t.Logf("original size: %d, compressed size: %d, rate: %.2f%%", len(testData), result.Len(), float64(result.Len())/float64(len(testData))*100)
write(t, testData, 10000)
reader, err := NewSeekableReader(bytes.NewReader(result.Bytes()))
require.NoError(t, err)
@@ -165,17 +135,7 @@ func TestSeekableWriterReader(t *testing.T) {
})
t.Run("tidy block", func(t *testing.T) {
result.Reset()
blockSize := 100
writer, err := NewSeekableWriter(result, blockSize)
require.NoError(t, err)
_, err = io.Copy(writer, bytes.NewReader(testData))
require.NoError(t, err)
require.NoError(t, writer.Close())
t.Logf("original size: %d, compressed size: %d, rate: %.2f%%", len(testData), result.Len(), float64(result.Len())/float64(len(testData))*100)
write(t, testData, 100)
// A too small block size will cause a bad compression rate,
// even the compressed data is larger than the original data.
assert.Greater(t, result.Len(), len(testData))
@@ -191,17 +151,7 @@ func TestSeekableWriterReader(t *testing.T) {
})
t.Run("compatible reader", func(t *testing.T) {
result.Reset()
blockSize := 10000
writer, err := NewSeekableWriter(result, blockSize)
require.NoError(t, err)
_, err = io.Copy(writer, bytes.NewReader(testData))
require.NoError(t, err)
require.NoError(t, writer.Close())
t.Logf("original size: %d, compressed size: %d, rate: %.2f%%", len(testData), result.Len(), float64(result.Len())/float64(len(testData))*100)
write(t, testData, 10000)
// It should be able to read the data with a regular reader.
reader, err := NewReader(bytes.NewReader(result.Bytes()))