Files
gitea/routers/web/shared/project/project_test.go
T
silverwind 8abda62312 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.
2026-10-24 13:48:19 +00:00

126 lines
4.5 KiB
Go

// Copyright 2026 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package project
import (
"fmt"
"io"
"net/http"
"strconv"
"strings"
"testing"
"gitea.dev/models/db"
issues_model "gitea.dev/models/issues"
"gitea.dev/models/organization"
"gitea.dev/models/perm"
project_model "gitea.dev/models/project"
repo_model "gitea.dev/models/repo"
"gitea.dev/models/unit"
"gitea.dev/models/unittest"
user_model "gitea.dev/models/user"
"gitea.dev/services/contexttest"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestMain(m *testing.M) {
unittest.MainTest(m)
}
// TestFindColumn covers the scoping rule every board handler depends on: a request only
// resolves projects owned by the scope its route assigned, so an ID belonging to anyone
// else reads as not found rather than leaking across owners.
func TestFindColumn(t *testing.T) {
unittest.PrepareTestEnv(t)
for _, tc := range []struct {
name string
projectID string
columnID string
doerID int64
repoScoped bool
resolves bool
}{
{"repository project", "1", "2", 2, true, true},
{"owner project", "4", "4", 2, false, true},
{"repository board cannot reach an owner project", "4", "1", 2, true, false},
{"owner board cannot reach another owner's project", "4", "4", 1, false, false},
} {
t.Run(tc.name, func(t *testing.T) {
ctx, _ := contexttest.MockContext(t, "user2/-/projects")
contexttest.LoadUser(t, ctx, tc.doerID)
if tc.repoScoped {
contexttest.LoadRepo(t, ctx, 1)
} else {
ctx.ContextUser = ctx.Doer
}
ctx.SetPathParam("id", tc.projectID)
ctx.SetPathParam("columnID", tc.columnID)
project, column := findColumn(ctx)
assert.Equal(t, tc.resolves, project != nil)
assert.Equal(t, tc.resolves, column != nil)
if tc.resolves {
assert.False(t, ctx.Written())
} else {
// a foreign ID must read as not found, never as a 500
assert.Equal(t, http.StatusNotFound, ctx.Resp.WrittenStatus())
}
})
}
}
func TestMoveIssuesNeedsIssueRead(t *testing.T) {
for _, tc := range []struct {
name string
doerID int64
repoBoard bool
archived bool
status int
}{
{"OwnerBoardReader", 2, false, false, http.StatusOK},
{"OwnerBoardWithoutIssueAccess", 15, false, false, http.StatusNotFound},
{"OwnerBoardArchivedRepo", 2, false, true, http.StatusLocked},
{"RepoBoardProjectsWriterWithoutIssueRead", 4, true, false, http.StatusNotFound},
} {
t.Run(tc.name, func(t *testing.T) {
unittest.PrepareTestEnv(t)
if tc.repoBoard {
_, err := db.Exec(t.Context(), "UPDATE team SET authorize = ? WHERE id = ?", perm.AccessModeNone, 2)
require.NoError(t, err)
_, err = db.DeleteByBean(t.Context(), &organization.TeamUnit{TeamID: 2, Type: unit.TypeIssues})
require.NoError(t, err)
}
if tc.archived {
require.NoError(t, repo_model.UpdateRepositoryColsNoAutoTime(t.Context(), &repo_model.Repository{ID: 3, IsArchived: true}, "is_archived"))
}
ctx, _ := contexttest.MockContext(t, "POST /org3/-/projects")
contexttest.LoadUser(t, ctx, tc.doerID)
project := unittest.AssertExistsAndLoadBean(t, &project_model.Project{ID: 2})
if tc.repoBoard {
contexttest.LoadRepo(t, ctx, 3)
} else {
ctx.ContextUser = unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 3})
project = &project_model.Project{Title: "board", OwnerID: 3, CreatorID: 2, Type: project_model.TypeOrganization}
require.NoError(t, project_model.NewProject(ctx, project))
require.NoError(t, project_model.NewColumn(ctx, &project_model.Column{Title: "Backlog", ProjectID: project.ID, Default: true}))
}
column := &project_model.Column{Title: "Done", ProjectID: project.ID}
require.NoError(t, project_model.NewColumn(ctx, column))
issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 6})
_, _, err := issues_model.IssueAssignOrRemoveProject(ctx, issue, unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}), []int64{project.ID})
require.NoError(t, err)
ctx.SetPathParam("id", strconv.FormatInt(project.ID, 10))
ctx.SetPathParam("columnID", strconv.FormatInt(column.ID, 10))
ctx.Req.Body = io.NopCloser(strings.NewReader(fmt.Sprintf(`{"issues":[{"issueID":%d,"sorting":0}]}`, issue.ID)))
MoveIssues(ctx)
assert.Equal(t, tc.status, ctx.Resp.WrittenStatus())
card := unittest.AssertExistsAndLoadBean(t, &project_model.ProjectIssue{IssueID: issue.ID, ProjectID: project.ID})
assert.Equal(t, tc.status == http.StatusOK, card.ProjectColumnID == column.ID)
})
}
}