code.gitea.io/gitea@v1.22.3/models/issues/label_test.go (about)

     1  // Copyright 2017 The Gitea Authors. All rights reserved.
     2  // SPDX-License-Identifier: MIT
     3  
     4  package issues_test
     5  
     6  import (
     7  	"testing"
     8  
     9  	"code.gitea.io/gitea/models/db"
    10  	issues_model "code.gitea.io/gitea/models/issues"
    11  	repo_model "code.gitea.io/gitea/models/repo"
    12  	"code.gitea.io/gitea/models/unittest"
    13  	user_model "code.gitea.io/gitea/models/user"
    14  	"code.gitea.io/gitea/modules/timeutil"
    15  
    16  	"github.com/stretchr/testify/assert"
    17  )
    18  
    19  func TestLabel_CalOpenIssues(t *testing.T) {
    20  	assert.NoError(t, unittest.PrepareTestDatabase())
    21  	label := unittest.AssertExistsAndLoadBean(t, &issues_model.Label{ID: 1})
    22  	label.CalOpenIssues()
    23  	assert.EqualValues(t, 2, label.NumOpenIssues)
    24  }
    25  
    26  func TestLabel_ExclusiveScope(t *testing.T) {
    27  	assert.NoError(t, unittest.PrepareTestDatabase())
    28  	label := unittest.AssertExistsAndLoadBean(t, &issues_model.Label{ID: 7})
    29  	assert.Equal(t, "scope", label.ExclusiveScope())
    30  
    31  	label = unittest.AssertExistsAndLoadBean(t, &issues_model.Label{ID: 9})
    32  	assert.Equal(t, "scope/subscope", label.ExclusiveScope())
    33  }
    34  
    35  func TestNewLabels(t *testing.T) {
    36  	assert.NoError(t, unittest.PrepareTestDatabase())
    37  	labels := []*issues_model.Label{
    38  		{RepoID: 2, Name: "labelName2", Color: "#123456"},
    39  		{RepoID: 3, Name: "labelName3", Color: "#123"},
    40  		{RepoID: 4, Name: "labelName4", Color: "ABCDEF"},
    41  		{RepoID: 5, Name: "labelName5", Color: "DEF"},
    42  	}
    43  	assert.Error(t, issues_model.NewLabel(db.DefaultContext, &issues_model.Label{RepoID: 3, Name: "invalid Color", Color: ""}))
    44  	assert.Error(t, issues_model.NewLabel(db.DefaultContext, &issues_model.Label{RepoID: 3, Name: "invalid Color", Color: "#45G"}))
    45  	assert.Error(t, issues_model.NewLabel(db.DefaultContext, &issues_model.Label{RepoID: 3, Name: "invalid Color", Color: "#12345G"}))
    46  	assert.Error(t, issues_model.NewLabel(db.DefaultContext, &issues_model.Label{RepoID: 3, Name: "invalid Color", Color: "45G"}))
    47  	assert.Error(t, issues_model.NewLabel(db.DefaultContext, &issues_model.Label{RepoID: 3, Name: "invalid Color", Color: "12345G"}))
    48  	for _, label := range labels {
    49  		unittest.AssertNotExistsBean(t, label)
    50  	}
    51  	assert.NoError(t, issues_model.NewLabels(db.DefaultContext, labels...))
    52  	for _, label := range labels {
    53  		unittest.AssertExistsAndLoadBean(t, label, unittest.Cond("id = ?", label.ID))
    54  	}
    55  	unittest.CheckConsistencyFor(t, &issues_model.Label{}, &repo_model.Repository{})
    56  }
    57  
    58  func TestGetLabelByID(t *testing.T) {
    59  	assert.NoError(t, unittest.PrepareTestDatabase())
    60  	label, err := issues_model.GetLabelByID(db.DefaultContext, 1)
    61  	assert.NoError(t, err)
    62  	assert.EqualValues(t, 1, label.ID)
    63  
    64  	_, err = issues_model.GetLabelByID(db.DefaultContext, unittest.NonexistentID)
    65  	assert.True(t, issues_model.IsErrLabelNotExist(err))
    66  }
    67  
    68  func TestGetLabelInRepoByName(t *testing.T) {
    69  	assert.NoError(t, unittest.PrepareTestDatabase())
    70  	label, err := issues_model.GetLabelInRepoByName(db.DefaultContext, 1, "label1")
    71  	assert.NoError(t, err)
    72  	assert.EqualValues(t, 1, label.ID)
    73  	assert.Equal(t, "label1", label.Name)
    74  
    75  	_, err = issues_model.GetLabelInRepoByName(db.DefaultContext, 1, "")
    76  	assert.True(t, issues_model.IsErrRepoLabelNotExist(err))
    77  
    78  	_, err = issues_model.GetLabelInRepoByName(db.DefaultContext, unittest.NonexistentID, "nonexistent")
    79  	assert.True(t, issues_model.IsErrRepoLabelNotExist(err))
    80  }
    81  
    82  func TestGetLabelInRepoByNames(t *testing.T) {
    83  	assert.NoError(t, unittest.PrepareTestDatabase())
    84  	labelIDs, err := issues_model.GetLabelIDsInRepoByNames(db.DefaultContext, 1, []string{"label1", "label2"})
    85  	assert.NoError(t, err)
    86  
    87  	assert.Len(t, labelIDs, 2)
    88  
    89  	assert.Equal(t, int64(1), labelIDs[0])
    90  	assert.Equal(t, int64(2), labelIDs[1])
    91  }
    92  
    93  func TestGetLabelInRepoByNamesDiscardsNonExistentLabels(t *testing.T) {
    94  	assert.NoError(t, unittest.PrepareTestDatabase())
    95  	// label3 doesn't exists.. See labels.yml
    96  	labelIDs, err := issues_model.GetLabelIDsInRepoByNames(db.DefaultContext, 1, []string{"label1", "label2", "label3"})
    97  	assert.NoError(t, err)
    98  
    99  	assert.Len(t, labelIDs, 2)
   100  
   101  	assert.Equal(t, int64(1), labelIDs[0])
   102  	assert.Equal(t, int64(2), labelIDs[1])
   103  	assert.NoError(t, err)
   104  }
   105  
   106  func TestGetLabelInRepoByID(t *testing.T) {
   107  	assert.NoError(t, unittest.PrepareTestDatabase())
   108  	label, err := issues_model.GetLabelInRepoByID(db.DefaultContext, 1, 1)
   109  	assert.NoError(t, err)
   110  	assert.EqualValues(t, 1, label.ID)
   111  
   112  	_, err = issues_model.GetLabelInRepoByID(db.DefaultContext, 1, -1)
   113  	assert.True(t, issues_model.IsErrRepoLabelNotExist(err))
   114  
   115  	_, err = issues_model.GetLabelInRepoByID(db.DefaultContext, unittest.NonexistentID, unittest.NonexistentID)
   116  	assert.True(t, issues_model.IsErrRepoLabelNotExist(err))
   117  }
   118  
   119  func TestGetLabelsInRepoByIDs(t *testing.T) {
   120  	assert.NoError(t, unittest.PrepareTestDatabase())
   121  	labels, err := issues_model.GetLabelsInRepoByIDs(db.DefaultContext, 1, []int64{1, 2, unittest.NonexistentID})
   122  	assert.NoError(t, err)
   123  	if assert.Len(t, labels, 2) {
   124  		assert.EqualValues(t, 1, labels[0].ID)
   125  		assert.EqualValues(t, 2, labels[1].ID)
   126  	}
   127  }
   128  
   129  func TestGetLabelsByRepoID(t *testing.T) {
   130  	assert.NoError(t, unittest.PrepareTestDatabase())
   131  	testSuccess := func(repoID int64, sortType string, expectedIssueIDs []int64) {
   132  		labels, err := issues_model.GetLabelsByRepoID(db.DefaultContext, repoID, sortType, db.ListOptions{})
   133  		assert.NoError(t, err)
   134  		assert.Len(t, labels, len(expectedIssueIDs))
   135  		for i, label := range labels {
   136  			assert.EqualValues(t, expectedIssueIDs[i], label.ID)
   137  		}
   138  	}
   139  	testSuccess(1, "leastissues", []int64{2, 1})
   140  	testSuccess(1, "mostissues", []int64{1, 2})
   141  	testSuccess(1, "reversealphabetically", []int64{2, 1})
   142  	testSuccess(1, "default", []int64{1, 2})
   143  }
   144  
   145  // Org versions
   146  
   147  func TestGetLabelInOrgByName(t *testing.T) {
   148  	assert.NoError(t, unittest.PrepareTestDatabase())
   149  	label, err := issues_model.GetLabelInOrgByName(db.DefaultContext, 3, "orglabel3")
   150  	assert.NoError(t, err)
   151  	assert.EqualValues(t, 3, label.ID)
   152  	assert.Equal(t, "orglabel3", label.Name)
   153  
   154  	_, err = issues_model.GetLabelInOrgByName(db.DefaultContext, 3, "")
   155  	assert.True(t, issues_model.IsErrOrgLabelNotExist(err))
   156  
   157  	_, err = issues_model.GetLabelInOrgByName(db.DefaultContext, 0, "orglabel3")
   158  	assert.True(t, issues_model.IsErrOrgLabelNotExist(err))
   159  
   160  	_, err = issues_model.GetLabelInOrgByName(db.DefaultContext, -1, "orglabel3")
   161  	assert.True(t, issues_model.IsErrOrgLabelNotExist(err))
   162  
   163  	_, err = issues_model.GetLabelInOrgByName(db.DefaultContext, unittest.NonexistentID, "nonexistent")
   164  	assert.True(t, issues_model.IsErrOrgLabelNotExist(err))
   165  }
   166  
   167  func TestGetLabelInOrgByID(t *testing.T) {
   168  	assert.NoError(t, unittest.PrepareTestDatabase())
   169  	label, err := issues_model.GetLabelInOrgByID(db.DefaultContext, 3, 3)
   170  	assert.NoError(t, err)
   171  	assert.EqualValues(t, 3, label.ID)
   172  
   173  	_, err = issues_model.GetLabelInOrgByID(db.DefaultContext, 3, -1)
   174  	assert.True(t, issues_model.IsErrOrgLabelNotExist(err))
   175  
   176  	_, err = issues_model.GetLabelInOrgByID(db.DefaultContext, 0, 3)
   177  	assert.True(t, issues_model.IsErrOrgLabelNotExist(err))
   178  
   179  	_, err = issues_model.GetLabelInOrgByID(db.DefaultContext, -1, 3)
   180  	assert.True(t, issues_model.IsErrOrgLabelNotExist(err))
   181  
   182  	_, err = issues_model.GetLabelInOrgByID(db.DefaultContext, unittest.NonexistentID, unittest.NonexistentID)
   183  	assert.True(t, issues_model.IsErrOrgLabelNotExist(err))
   184  }
   185  
   186  func TestGetLabelsInOrgByIDs(t *testing.T) {
   187  	assert.NoError(t, unittest.PrepareTestDatabase())
   188  	labels, err := issues_model.GetLabelsInOrgByIDs(db.DefaultContext, 3, []int64{3, 4, unittest.NonexistentID})
   189  	assert.NoError(t, err)
   190  	if assert.Len(t, labels, 2) {
   191  		assert.EqualValues(t, 3, labels[0].ID)
   192  		assert.EqualValues(t, 4, labels[1].ID)
   193  	}
   194  }
   195  
   196  func TestGetLabelsByOrgID(t *testing.T) {
   197  	assert.NoError(t, unittest.PrepareTestDatabase())
   198  	testSuccess := func(orgID int64, sortType string, expectedIssueIDs []int64) {
   199  		labels, err := issues_model.GetLabelsByOrgID(db.DefaultContext, orgID, sortType, db.ListOptions{})
   200  		assert.NoError(t, err)
   201  		assert.Len(t, labels, len(expectedIssueIDs))
   202  		for i, label := range labels {
   203  			assert.EqualValues(t, expectedIssueIDs[i], label.ID)
   204  		}
   205  	}
   206  	testSuccess(3, "leastissues", []int64{3, 4})
   207  	testSuccess(3, "mostissues", []int64{4, 3})
   208  	testSuccess(3, "reversealphabetically", []int64{4, 3})
   209  	testSuccess(3, "default", []int64{3, 4})
   210  
   211  	var err error
   212  	_, err = issues_model.GetLabelsByOrgID(db.DefaultContext, 0, "leastissues", db.ListOptions{})
   213  	assert.True(t, issues_model.IsErrOrgLabelNotExist(err))
   214  
   215  	_, err = issues_model.GetLabelsByOrgID(db.DefaultContext, -1, "leastissues", db.ListOptions{})
   216  	assert.True(t, issues_model.IsErrOrgLabelNotExist(err))
   217  }
   218  
   219  //
   220  
   221  func TestGetLabelsByIssueID(t *testing.T) {
   222  	assert.NoError(t, unittest.PrepareTestDatabase())
   223  	labels, err := issues_model.GetLabelsByIssueID(db.DefaultContext, 1)
   224  	assert.NoError(t, err)
   225  	if assert.Len(t, labels, 1) {
   226  		assert.EqualValues(t, 1, labels[0].ID)
   227  	}
   228  
   229  	labels, err = issues_model.GetLabelsByIssueID(db.DefaultContext, unittest.NonexistentID)
   230  	assert.NoError(t, err)
   231  	assert.Len(t, labels, 0)
   232  }
   233  
   234  func TestUpdateLabel(t *testing.T) {
   235  	assert.NoError(t, unittest.PrepareTestDatabase())
   236  	label := unittest.AssertExistsAndLoadBean(t, &issues_model.Label{ID: 1})
   237  	// make sure update wont overwrite it
   238  	update := &issues_model.Label{
   239  		ID:           label.ID,
   240  		Color:        "#ffff00",
   241  		Name:         "newLabelName",
   242  		Description:  label.Description,
   243  		Exclusive:    false,
   244  		ArchivedUnix: timeutil.TimeStamp(0),
   245  	}
   246  	label.Color = update.Color
   247  	label.Name = update.Name
   248  	assert.NoError(t, issues_model.UpdateLabel(db.DefaultContext, update))
   249  	newLabel := unittest.AssertExistsAndLoadBean(t, &issues_model.Label{ID: 1})
   250  	assert.EqualValues(t, label.ID, newLabel.ID)
   251  	assert.EqualValues(t, label.Color, newLabel.Color)
   252  	assert.EqualValues(t, label.Name, newLabel.Name)
   253  	assert.EqualValues(t, label.Description, newLabel.Description)
   254  	assert.EqualValues(t, newLabel.ArchivedUnix, 0)
   255  	unittest.CheckConsistencyFor(t, &issues_model.Label{}, &repo_model.Repository{})
   256  }
   257  
   258  func TestDeleteLabel(t *testing.T) {
   259  	assert.NoError(t, unittest.PrepareTestDatabase())
   260  	label := unittest.AssertExistsAndLoadBean(t, &issues_model.Label{ID: 1})
   261  	assert.NoError(t, issues_model.DeleteLabel(db.DefaultContext, label.RepoID, label.ID))
   262  	unittest.AssertNotExistsBean(t, &issues_model.Label{ID: label.ID, RepoID: label.RepoID})
   263  
   264  	assert.NoError(t, issues_model.DeleteLabel(db.DefaultContext, label.RepoID, label.ID))
   265  	unittest.AssertNotExistsBean(t, &issues_model.Label{ID: label.ID})
   266  
   267  	assert.NoError(t, issues_model.DeleteLabel(db.DefaultContext, unittest.NonexistentID, unittest.NonexistentID))
   268  	unittest.CheckConsistencyFor(t, &issues_model.Label{}, &repo_model.Repository{})
   269  }
   270  
   271  func TestHasIssueLabel(t *testing.T) {
   272  	assert.NoError(t, unittest.PrepareTestDatabase())
   273  	assert.True(t, issues_model.HasIssueLabel(db.DefaultContext, 1, 1))
   274  	assert.False(t, issues_model.HasIssueLabel(db.DefaultContext, 1, 2))
   275  	assert.False(t, issues_model.HasIssueLabel(db.DefaultContext, unittest.NonexistentID, unittest.NonexistentID))
   276  }
   277  
   278  func TestNewIssueLabel(t *testing.T) {
   279  	assert.NoError(t, unittest.PrepareTestDatabase())
   280  	label := unittest.AssertExistsAndLoadBean(t, &issues_model.Label{ID: 2})
   281  	issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 1})
   282  	doer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
   283  
   284  	// add new IssueLabel
   285  	prevNumIssues := label.NumIssues
   286  	assert.NoError(t, issues_model.NewIssueLabel(db.DefaultContext, issue, label, doer))
   287  	unittest.AssertExistsAndLoadBean(t, &issues_model.IssueLabel{IssueID: issue.ID, LabelID: label.ID})
   288  	unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{
   289  		Type:     issues_model.CommentTypeLabel,
   290  		PosterID: doer.ID,
   291  		IssueID:  issue.ID,
   292  		LabelID:  label.ID,
   293  		Content:  "1",
   294  	})
   295  	label = unittest.AssertExistsAndLoadBean(t, &issues_model.Label{ID: 2})
   296  	assert.EqualValues(t, prevNumIssues+1, label.NumIssues)
   297  
   298  	// re-add existing IssueLabel
   299  	assert.NoError(t, issues_model.NewIssueLabel(db.DefaultContext, issue, label, doer))
   300  	unittest.CheckConsistencyFor(t, &issues_model.Issue{}, &issues_model.Label{})
   301  }
   302  
   303  func TestNewIssueExclusiveLabel(t *testing.T) {
   304  	assert.NoError(t, unittest.PrepareTestDatabase())
   305  	issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 18})
   306  	doer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
   307  
   308  	otherLabel := unittest.AssertExistsAndLoadBean(t, &issues_model.Label{ID: 6})
   309  	exclusiveLabelA := unittest.AssertExistsAndLoadBean(t, &issues_model.Label{ID: 7})
   310  	exclusiveLabelB := unittest.AssertExistsAndLoadBean(t, &issues_model.Label{ID: 8})
   311  
   312  	// coexisting regular and exclusive label
   313  	assert.NoError(t, issues_model.NewIssueLabel(db.DefaultContext, issue, otherLabel, doer))
   314  	assert.NoError(t, issues_model.NewIssueLabel(db.DefaultContext, issue, exclusiveLabelA, doer))
   315  	unittest.AssertExistsAndLoadBean(t, &issues_model.IssueLabel{IssueID: issue.ID, LabelID: otherLabel.ID})
   316  	unittest.AssertExistsAndLoadBean(t, &issues_model.IssueLabel{IssueID: issue.ID, LabelID: exclusiveLabelA.ID})
   317  
   318  	// exclusive label replaces existing one
   319  	assert.NoError(t, issues_model.NewIssueLabel(db.DefaultContext, issue, exclusiveLabelB, doer))
   320  	unittest.AssertExistsAndLoadBean(t, &issues_model.IssueLabel{IssueID: issue.ID, LabelID: otherLabel.ID})
   321  	unittest.AssertExistsAndLoadBean(t, &issues_model.IssueLabel{IssueID: issue.ID, LabelID: exclusiveLabelB.ID})
   322  	unittest.AssertNotExistsBean(t, &issues_model.IssueLabel{IssueID: issue.ID, LabelID: exclusiveLabelA.ID})
   323  
   324  	// exclusive label replaces existing one again
   325  	assert.NoError(t, issues_model.NewIssueLabel(db.DefaultContext, issue, exclusiveLabelA, doer))
   326  	unittest.AssertExistsAndLoadBean(t, &issues_model.IssueLabel{IssueID: issue.ID, LabelID: otherLabel.ID})
   327  	unittest.AssertExistsAndLoadBean(t, &issues_model.IssueLabel{IssueID: issue.ID, LabelID: exclusiveLabelA.ID})
   328  	unittest.AssertNotExistsBean(t, &issues_model.IssueLabel{IssueID: issue.ID, LabelID: exclusiveLabelB.ID})
   329  }
   330  
   331  func TestNewIssueLabels(t *testing.T) {
   332  	assert.NoError(t, unittest.PrepareTestDatabase())
   333  	label1 := unittest.AssertExistsAndLoadBean(t, &issues_model.Label{ID: 1})
   334  	label2 := unittest.AssertExistsAndLoadBean(t, &issues_model.Label{ID: 2})
   335  	issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 5})
   336  	doer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
   337  
   338  	assert.NoError(t, issues_model.NewIssueLabels(db.DefaultContext, issue, []*issues_model.Label{label1, label2}, doer))
   339  	unittest.AssertExistsAndLoadBean(t, &issues_model.IssueLabel{IssueID: issue.ID, LabelID: label1.ID})
   340  	unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{
   341  		Type:     issues_model.CommentTypeLabel,
   342  		PosterID: doer.ID,
   343  		IssueID:  issue.ID,
   344  		LabelID:  label1.ID,
   345  		Content:  "1",
   346  	})
   347  	unittest.AssertExistsAndLoadBean(t, &issues_model.IssueLabel{IssueID: issue.ID, LabelID: label1.ID})
   348  	label1 = unittest.AssertExistsAndLoadBean(t, &issues_model.Label{ID: 1})
   349  	assert.EqualValues(t, 3, label1.NumIssues)
   350  	assert.EqualValues(t, 1, label1.NumClosedIssues)
   351  	label2 = unittest.AssertExistsAndLoadBean(t, &issues_model.Label{ID: 2})
   352  	assert.EqualValues(t, 1, label2.NumIssues)
   353  	assert.EqualValues(t, 1, label2.NumClosedIssues)
   354  
   355  	// corner case: test empty slice
   356  	assert.NoError(t, issues_model.NewIssueLabels(db.DefaultContext, issue, []*issues_model.Label{}, doer))
   357  
   358  	unittest.CheckConsistencyFor(t, &issues_model.Issue{}, &issues_model.Label{})
   359  }
   360  
   361  func TestDeleteIssueLabel(t *testing.T) {
   362  	assert.NoError(t, unittest.PrepareTestDatabase())
   363  	testSuccess := func(labelID, issueID, doerID int64) {
   364  		label := unittest.AssertExistsAndLoadBean(t, &issues_model.Label{ID: labelID})
   365  		issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: issueID})
   366  		doer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: doerID})
   367  
   368  		expectedNumIssues := label.NumIssues
   369  		expectedNumClosedIssues := label.NumClosedIssues
   370  		if unittest.BeanExists(t, &issues_model.IssueLabel{IssueID: issueID, LabelID: labelID}) {
   371  			expectedNumIssues--
   372  			if issue.IsClosed {
   373  				expectedNumClosedIssues--
   374  			}
   375  		}
   376  
   377  		ctx, committer, err := db.TxContext(db.DefaultContext)
   378  		defer committer.Close()
   379  		assert.NoError(t, err)
   380  		assert.NoError(t, issues_model.DeleteIssueLabel(ctx, issue, label, doer))
   381  		assert.NoError(t, committer.Commit())
   382  
   383  		unittest.AssertNotExistsBean(t, &issues_model.IssueLabel{IssueID: issueID, LabelID: labelID})
   384  		unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{
   385  			Type:     issues_model.CommentTypeLabel,
   386  			PosterID: doerID,
   387  			IssueID:  issueID,
   388  			LabelID:  labelID,
   389  		}, `content=""`)
   390  		label = unittest.AssertExistsAndLoadBean(t, &issues_model.Label{ID: labelID})
   391  		assert.EqualValues(t, expectedNumIssues, label.NumIssues)
   392  		assert.EqualValues(t, expectedNumClosedIssues, label.NumClosedIssues)
   393  	}
   394  	testSuccess(1, 1, 2)
   395  	testSuccess(2, 5, 2)
   396  	testSuccess(1, 1, 2) // delete non-existent IssueLabel
   397  
   398  	unittest.CheckConsistencyFor(t, &issues_model.Issue{}, &issues_model.Label{})
   399  }