diff --git a/routers/web/repo/issue_test.go b/routers/web/repo/issue_test.go index e2c812084d..8c4991678b 100644 --- a/routers/web/repo/issue_test.go +++ b/routers/web/repo/issue_test.go @@ -7,8 +7,11 @@ import ( "fmt" "testing" + project_model "forgejo.org/models/project" + repo_model "forgejo.org/models/repo" "forgejo.org/models/unittest" "forgejo.org/services/contexttest" + "forgejo.org/tests/forgery" "github.com/stretchr/testify/assert" ) @@ -16,77 +19,54 @@ import ( func TestNewIssueValidateProject(t *testing.T) { unittest.PrepareTestEnv(t) - for _, testCase := range []struct { - name string - projectID int64 - userName string - userID int64 - repoName string - repoID int64 - isFound bool - }{ - { - name: "Project belongs to repository", - projectID: 1, - userName: "user2", - userID: 2, - repoName: "repo1", - repoID: 1, - isFound: true, - }, - { - name: "Project belongs to user", - projectID: 4, - userName: "user2", - userID: 2, - repoName: "repo1", - repoID: 1, - isFound: true, - }, - { - name: "Project belongs to org", - projectID: 7, - userName: "org3", - userID: 3, - repoName: "repo3", - repoID: 3, - isFound: true, - }, - { - name: "Project neither belongs to repo nor the user", - projectID: 2, - userName: "user2", - userID: 2, - repoName: "repo1", - repoID: 1, - isFound: false, - }, - } { - t.Run(testCase.name, func(t *testing.T) { - ctx, _ := contexttest.MockContext( - t, fmt.Sprintf( - "/%s/%s/issues/new?project=%d", - testCase.userName, - testCase.repoName, - testCase.projectID, - ), - ) - contexttest.LoadUser(t, ctx, testCase.userID) - contexttest.LoadRepo(t, ctx, testCase.repoID) - contexttest.LoadGitRepo(t, ctx) - if ctx.Repo.Owner.IsOrganization() { - contexttest.LoadOrganization(t, ctx, ctx.Repo.Owner.ID) - } + user := forgery.CreateUser(t, &forgery.CreateUserOptions{ + IsAdmin: true, // to allow creating organisation + }) - NewIssue(ctx) + chooseProject := func(t *testing.T, repo *repo_model.Repository, p *project_model.Project, isFound bool) { + ctx, _ := contexttest.MockContext( + t, fmt.Sprintf( + "%s/issues/new?project=%d", + repo.Link(), + p.ID, + ), + ) + contexttest.LoadUser(t, ctx, user.ID) + contexttest.LoadRepo(t, ctx, repo.ID) + contexttest.LoadGitRepo(t, ctx) + if ctx.Repo.Owner.IsOrganization() { + contexttest.LoadOrganization(t, ctx, ctx.Repo.Owner.ID) + } - if testCase.isFound { - assert.Equal(t, testCase.projectID, ctx.Data["project_id"]) - assert.NotNil(t, ctx.Data["Project"]) - } else { - assert.Nil(t, ctx.Data["project_id"]) - assert.Nil(t, ctx.Data["Project"]) - } - }) + NewIssue(ctx) + + if isFound { + assert.Equal(t, p.ID, ctx.Data["project_id"]) + assert.NotNil(t, ctx.Data["Project"]) + } else { + assert.Nil(t, ctx.Data["project_id"]) + assert.Nil(t, ctx.Data["Project"]) + } } + + userRepo := forgery.CreateRepository(t, user, nil) + userOrg := forgery.CreateOrganisation(t, user) + orgRepo := forgery.CreateRepository(t, userOrg.AsUser(), nil) + t.Run("Project belongs to repository", func(t *testing.T) { + p := forgery.CreateProject(t, userRepo, nil) + chooseProject(t, userRepo, p, true) + }) + t.Run("Project belongs to user", func(t *testing.T) { + p := forgery.CreateProject(t, user, nil) + chooseProject(t, userRepo, p, true) + }) + t.Run("Project belongs to org", func(t *testing.T) { + p := forgery.CreateProject(t, userOrg, nil) + chooseProject(t, orgRepo, p, true) + }) + t.Run("Project neither belongs to repo nor the user", func(t *testing.T) { + otherUser := forgery.CreateUser(t, nil) + p := forgery.CreateProject(t, otherUser, nil) + chooseProject(t, userRepo, p, false) + }) } diff --git a/tests/forgery/project.go b/tests/forgery/project.go new file mode 100644 index 0000000000..2c63618b11 --- /dev/null +++ b/tests/forgery/project.go @@ -0,0 +1,57 @@ +// Copyright 2026 The Forgejo Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package forgery + +import ( + "testing" + + org_model "forgejo.org/models/organization" + project_model "forgejo.org/models/project" + repo_model "forgejo.org/models/repo" + user_model "forgejo.org/models/user" + + "github.com/stretchr/testify/require" +) + +type CreateProjectOptions struct { + TemplateType project_model.TemplateType + CardType project_model.CardType +} + +func CreateProject[T org_model.Organization | user_model.User | repo_model.Repository](t testing.TB, owner *T, opts *CreateProjectOptions) *project_model.Project { + t.Helper() + + if opts == nil { + opts = &CreateProjectOptions{} + } + + p := &project_model.Project{ + Title: t.Name(), + Description: "Test project", + TemplateType: opts.TemplateType, + CardType: opts.CardType, + } + switch o := any(owner).(type) { + case *org_model.Organization: + p.Owner = o.AsUser() + p.OwnerID = o.ID + p.Type = project_model.TypeOrganization + case *user_model.User: + p.Owner = o + p.OwnerID = o.ID + p.Type = project_model.TypeIndividual + case *repo_model.Repository: + p.Repo = o + p.RepoID = o.ID + p.Type = project_model.TypeRepository + default: + t.Fatalf("unexpected owner type %T", o) + } + err := project_model.NewProject(t.Context(), p) + require.NoError(t, err) + t.Cleanup(func() { + _ = project_model.DeleteProjectByID(t.Context(), p.ID) + }) + return p +}