// Copyright 2017 The Gitea Authors. All rights reserved. // Use of this source code is governed by a MIT-style // license that can be found in the LICENSE file. package models import ( "sort" "testing" "time" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/timeutil" "github.com/stretchr/testify/assert" ) func TestMilestone_State(t *testing.T) { assert.Equal(t, api.StateOpen, (&Milestone{IsClosed: false}).State()) assert.Equal(t, api.StateClosed, (&Milestone{IsClosed: true}).State()) } func TestMilestone_APIFormat(t *testing.T) { milestone := &Milestone{ ID: 3, RepoID: 4, Name: "milestoneName", Content: "milestoneContent", IsClosed: false, NumOpenIssues: 5, NumClosedIssues: 6, DeadlineUnix: timeutil.TimeStamp(time.Date(2000, time.January, 1, 0, 0, 0, 0, time.UTC).Unix()), } assert.Equal(t, api.Milestone{ ID: milestone.ID, State: api.StateOpen, Title: milestone.Name, Description: milestone.Content, OpenIssues: milestone.NumOpenIssues, ClosedIssues: milestone.NumClosedIssues, Deadline: milestone.DeadlineUnix.AsTimePtr(), }, *milestone.APIFormat()) } func TestNewMilestone(t *testing.T) { assert.NoError(t, PrepareTestDatabase()) milestone := &Milestone{ RepoID: 1, Name: "milestoneName", Content: "milestoneContent", } assert.NoError(t, NewMilestone(milestone)) AssertExistsAndLoadBean(t, milestone) CheckConsistencyFor(t, &Repository{ID: milestone.RepoID}, &Milestone{}) } func TestGetMilestoneByRepoID(t *testing.T) { assert.NoError(t, PrepareTestDatabase()) milestone, err := GetMilestoneByRepoID(1, 1) assert.NoError(t, err) assert.EqualValues(t, 1, milestone.ID) assert.EqualValues(t, 1, milestone.RepoID) _, err = GetMilestoneByRepoID(NonexistentID, NonexistentID) assert.True(t, IsErrMilestoneNotExist(err)) } func TestGetMilestonesByRepoID(t *testing.T) { assert.NoError(t, PrepareTestDatabase()) test := func(repoID int64, state api.StateType) { repo := AssertExistsAndLoadBean(t, &Repository{ID: repoID}).(*Repository) milestones, err := GetMilestonesByRepoID(repo.ID, state) assert.NoError(t, err) var n int switch state { case api.StateClosed: n = repo.NumClosedMilestones case api.StateAll: n = repo.NumMilestones case api.StateOpen: fallthrough default: n = repo.NumOpenMilestones } assert.Len(t, milestones, n) for _, milestone := range milestones { assert.EqualValues(t, repoID, milestone.RepoID) } } test(1, api.StateOpen) test(1, api.StateAll) test(1, api.StateClosed) test(2, api.StateOpen) test(2, api.StateAll) test(2, api.StateClosed) test(3, api.StateOpen) test(3, api.StateClosed) test(3, api.StateAll) milestones, err := GetMilestonesByRepoID(NonexistentID, api.StateOpen) assert.NoError(t, err) assert.Len(t, milestones, 0) } func TestGetMilestones(t *testing.T) { assert.NoError(t, PrepareTestDatabase()) repo := AssertExistsAndLoadBean(t, &Repository{ID: 1}).(*Repository) test := func(sortType string, sortCond func(*Milestone) int) { for _, page := range []int{0, 1} { milestones, err := GetMilestones(repo.ID, page, false, sortType) assert.NoError(t, err) assert.Len(t, milestones, repo.NumMilestones-repo.NumClosedMilestones) values := make([]int, len(milestones)) for i, milestone := range milestones { values[i] = sortCond(milestone) } assert.True(t, sort.IntsAreSorted(values)) milestones, err = GetMilestones(repo.ID, page, true, sortType) assert.NoError(t, err) assert.Len(t, milestones, repo.NumClosedMilestones) values = make([]int, len(milestones)) for i, milestone := range milestones { values[i] = sortCond(milestone) } assert.True(t, sort.IntsAreSorted(values)) } } test("furthestduedate", func(milestone *Milestone) int { return -int(milestone.DeadlineUnix) }) test("leastcomplete", func(milestone *Milestone) int { return milestone.Completeness }) test("mostcomplete", func(milestone *Milestone) int { return -milestone.Completeness }) test("leastissues", func(milestone *Milestone) int { return milestone.NumIssues }) test("mostissues", func(milestone *Milestone) int { return -milestone.NumIssues }) test("soonestduedate", func(milestone *Milestone) int { return int(milestone.DeadlineUnix) }) } func TestUpdateMilestone(t *testing.T) { assert.NoError(t, PrepareTestDatabase()) milestone := AssertExistsAndLoadBean(t, &Milestone{ID: 1}).(*Milestone) milestone.Name = "newMilestoneName" milestone.Content = "newMilestoneContent" assert.NoError(t, UpdateMilestone(milestone)) AssertExistsAndLoadBean(t, milestone) CheckConsistencyFor(t, &Milestone{}) } func TestCountRepoMilestones(t *testing.T) { assert.NoError(t, PrepareTestDatabase()) test := func(repoID int64) { repo := AssertExistsAndLoadBean(t, &Repository{ID: repoID}).(*Repository) count, err := countRepoMilestones(x, repoID) assert.NoError(t, err) assert.EqualValues(t, repo.NumMilestones, count) } test(1) test(2) test(3) count, err := countRepoMilestones(x, NonexistentID) assert.NoError(t, err) assert.EqualValues(t, 0, count) } func TestCountRepoClosedMilestones(t *testing.T) { assert.NoError(t, PrepareTestDatabase()) test := func(repoID int64) { repo := AssertExistsAndLoadBean(t, &Repository{ID: repoID}).(*Repository) count, err := CountRepoClosedMilestones(repoID) assert.NoError(t, err) assert.EqualValues(t, repo.NumClosedMilestones, count) } test(1) test(2) test(3) count, err := CountRepoClosedMilestones(NonexistentID) assert.NoError(t, err) assert.EqualValues(t, 0, count) } func TestMilestoneStats(t *testing.T) { assert.NoError(t, PrepareTestDatabase()) test := func(repoID int64) { repo := AssertExistsAndLoadBean(t, &Repository{ID: repoID}).(*Repository) open, closed, err := MilestoneStats(repoID) assert.NoError(t, err) assert.EqualValues(t, repo.NumMilestones-repo.NumClosedMilestones, open) assert.EqualValues(t, repo.NumClosedMilestones, closed) } test(1) test(2) test(3) open, closed, err := MilestoneStats(NonexistentID) assert.NoError(t, err) assert.EqualValues(t, 0, open) assert.EqualValues(t, 0, closed) } func TestChangeMilestoneStatus(t *testing.T) { assert.NoError(t, PrepareTestDatabase()) milestone := AssertExistsAndLoadBean(t, &Milestone{ID: 1}).(*Milestone) assert.NoError(t, ChangeMilestoneStatus(milestone, true)) AssertExistsAndLoadBean(t, &Milestone{ID: 1}, "is_closed=1") CheckConsistencyFor(t, &Repository{ID: milestone.RepoID}, &Milestone{}) assert.NoError(t, ChangeMilestoneStatus(milestone, false)) AssertExistsAndLoadBean(t, &Milestone{ID: 1}, "is_closed=0") CheckConsistencyFor(t, &Repository{ID: milestone.RepoID}, &Milestone{}) } func TestUpdateMilestoneClosedNum(t *testing.T) { assert.NoError(t, PrepareTestDatabase()) issue := AssertExistsAndLoadBean(t, &Issue{MilestoneID: 1}, "is_closed=0").(*Issue) issue.IsClosed = true issue.ClosedUnix = timeutil.TimeStampNow() _, err := x.Cols("is_closed", "closed_unix").Update(issue) assert.NoError(t, err) assert.NoError(t, updateMilestoneClosedNum(x, issue.MilestoneID)) CheckConsistencyFor(t, &Milestone{}) issue.IsClosed = false issue.ClosedUnix = 0 _, err = x.Cols("is_closed", "closed_unix").Update(issue) assert.NoError(t, err) assert.NoError(t, updateMilestoneClosedNum(x, issue.MilestoneID)) CheckConsistencyFor(t, &Milestone{}) } func TestChangeMilestoneAssign(t *testing.T) { assert.NoError(t, PrepareTestDatabase()) issue := AssertExistsAndLoadBean(t, &Issue{RepoID: 1}).(*Issue) doer := AssertExistsAndLoadBean(t, &User{ID: 2}).(*User) assert.NotNil(t, issue) assert.NotNil(t, doer) oldMilestoneID := issue.MilestoneID issue.MilestoneID = 2 assert.NoError(t, ChangeMilestoneAssign(issue, doer, oldMilestoneID)) AssertExistsAndLoadBean(t, &Comment{ IssueID: issue.ID, Type: CommentTypeMilestone, MilestoneID: issue.MilestoneID, OldMilestoneID: oldMilestoneID, }) CheckConsistencyFor(t, &Milestone{}, &Issue{}) } func TestDeleteMilestoneByRepoID(t *testing.T) { assert.NoError(t, PrepareTestDatabase()) assert.NoError(t, DeleteMilestoneByRepoID(1, 1)) AssertNotExistsBean(t, &Milestone{ID: 1}) CheckConsistencyFor(t, &Repository{ID: 1}) assert.NoError(t, DeleteMilestoneByRepoID(NonexistentID, NonexistentID)) } func TestMilestoneList_LoadTotalTrackedTimes(t *testing.T) { assert.NoError(t, PrepareTestDatabase()) miles := MilestoneList{ AssertExistsAndLoadBean(t, &Milestone{ID: 1}).(*Milestone), } assert.NoError(t, miles.LoadTotalTrackedTimes()) assert.Equal(t, miles[0].TotalTrackedTime, int64(3662)) } func TestCountMilestonesByRepoIDs(t *testing.T) { assert.NoError(t, PrepareTestDatabase()) milestonesCount := func(repoID int64) (int, int) { repo := AssertExistsAndLoadBean(t, &Repository{ID: repoID}).(*Repository) return repo.NumOpenMilestones, repo.NumClosedMilestones } repo1OpenCount, repo1ClosedCount := milestonesCount(1) repo2OpenCount, repo2ClosedCount := milestonesCount(2) openCounts, err := CountMilestonesByRepoIDs([]int64{1, 2}, false) assert.NoError(t, err) assert.EqualValues(t, repo1OpenCount, openCounts[1]) assert.EqualValues(t, repo2OpenCount, openCounts[2]) closedCounts, err := CountMilestonesByRepoIDs([]int64{1, 2}, true) assert.NoError(t, err) assert.EqualValues(t, repo1ClosedCount, closedCounts[1]) assert.EqualValues(t, repo2ClosedCount, closedCounts[2]) } func TestGetMilestonesByRepoIDs(t *testing.T) { assert.NoError(t, PrepareTestDatabase()) repo1 := AssertExistsAndLoadBean(t, &Repository{ID: 1}).(*Repository) repo2 := AssertExistsAndLoadBean(t, &Repository{ID: 2}).(*Repository) test := func(sortType string, sortCond func(*Milestone) int) { for _, page := range []int{0, 1} { openMilestones, err := GetMilestonesByRepoIDs([]int64{repo1.ID, repo2.ID}, page, false, sortType) assert.NoError(t, err) assert.Len(t, openMilestones, repo1.NumOpenMilestones+repo2.NumOpenMilestones) values := make([]int, len(openMilestones)) for i, milestone := range openMilestones { values[i] = sortCond(milestone) } assert.True(t, sort.IntsAreSorted(values)) closedMilestones, err := GetMilestonesByRepoIDs([]int64{repo1.ID, repo2.ID}, page, true, sortType) assert.NoError(t, err) assert.Len(t, closedMilestones, repo1.NumClosedMilestones+repo2.NumClosedMilestones) values = make([]int, len(closedMilestones)) for i, milestone := range closedMilestones { values[i] = sortCond(milestone) } assert.True(t, sort.IntsAreSorted(values)) } } test("furthestduedate", func(milestone *Milestone) int { return -int(milestone.DeadlineUnix) }) test("leastcomplete", func(milestone *Milestone) int { return milestone.Completeness }) test("mostcomplete", func(milestone *Milestone) int { return -milestone.Completeness }) test("leastissues", func(milestone *Milestone) int { return milestone.NumIssues }) test("mostissues", func(milestone *Milestone) int { return -milestone.NumIssues }) test("soonestduedate", func(milestone *Milestone) int { return int(milestone.DeadlineUnix) }) } func TestLoadTotalTrackedTime(t *testing.T) { assert.NoError(t, PrepareTestDatabase()) milestone := AssertExistsAndLoadBean(t, &Milestone{ID: 1}).(*Milestone) assert.NoError(t, milestone.LoadTotalTrackedTime()) assert.Equal(t, milestone.TotalTrackedTime, int64(3662)) } func TestGetMilestonesStats(t *testing.T) { assert.NoError(t, PrepareTestDatabase()) repo1 := AssertExistsAndLoadBean(t, &Repository{ID: 1}).(*Repository) repo2 := AssertExistsAndLoadBean(t, &Repository{ID: 2}).(*Repository) milestoneStats, err := GetMilestonesStats([]int64{repo1.ID, repo2.ID}) assert.NoError(t, err) assert.EqualValues(t, repo1.NumOpenMilestones+repo2.NumOpenMilestones, milestoneStats.OpenCount) assert.EqualValues(t, repo1.NumClosedMilestones+repo2.NumClosedMilestones, milestoneStats.ClosedCount) }