refactor(forgery): CreateProject helper to reduce dependency on global fixture when testing (#12796)

While working on #11356, I noticed https://codeberg.org/forgejo/forgejo/pulls/9906#issuecomment-10826066 which could have benefited from a `forgery.CreateProject` helper.
Since this helper wasn't available, the PR had to:
- adjust the global `project.yml` fixture
- fix the unrelated `models/project/project_test.go`, because of the fixture update

So 2/4 changed files in the PR were due to the usage of global fixtures.

This PR attempts at fixing this.

Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/12796
Reviewed-by: Gusted <gusted@noreply.codeberg.org>
Reviewed-by: Antonin Delpeuch <wetneb@noreply.codeberg.org>
This commit is contained in:
oliverpool
2026-05-31 16:46:54 +02:00
committed by Gusted
parent ff38c2ba7c
commit 8c3c3ca5db
2 changed files with 107 additions and 70 deletions
+50 -70
View File
@@ -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)
})
}
+57
View File
@@ -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
}