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

     1  // Copyright 2019 The Gitea Authors. All rights reserved.
     2  // SPDX-License-Identifier: MIT
     3  
     4  package issues_test
     5  
     6  import (
     7  	"fmt"
     8  	"testing"
     9  
    10  	"code.gitea.io/gitea/models/db"
    11  	issues_model "code.gitea.io/gitea/models/issues"
    12  	repo_model "code.gitea.io/gitea/models/repo"
    13  	"code.gitea.io/gitea/models/unittest"
    14  	user_model "code.gitea.io/gitea/models/user"
    15  	"code.gitea.io/gitea/modules/references"
    16  
    17  	"github.com/stretchr/testify/assert"
    18  )
    19  
    20  func TestXRef_AddCrossReferences(t *testing.T) {
    21  	assert.NoError(t, unittest.PrepareTestDatabase())
    22  
    23  	// Issue #1 to test against
    24  	itarget := testCreateIssue(t, 1, 2, "title1", "content1", false)
    25  
    26  	// PR to close issue #1
    27  	content := fmt.Sprintf("content2, closes #%d", itarget.Index)
    28  	pr := testCreateIssue(t, 1, 2, "title2", content, true)
    29  	ref := unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{IssueID: itarget.ID, RefIssueID: pr.ID, RefCommentID: 0})
    30  	assert.Equal(t, issues_model.CommentTypePullRef, ref.Type)
    31  	assert.Equal(t, pr.RepoID, ref.RefRepoID)
    32  	assert.True(t, ref.RefIsPull)
    33  	assert.Equal(t, references.XRefActionCloses, ref.RefAction)
    34  
    35  	// Comment on PR to reopen issue #1
    36  	content = fmt.Sprintf("content2, reopens #%d", itarget.Index)
    37  	c := testCreateComment(t, 1, 2, pr.ID, content)
    38  	ref = unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{IssueID: itarget.ID, RefIssueID: pr.ID, RefCommentID: c.ID})
    39  	assert.Equal(t, issues_model.CommentTypeCommentRef, ref.Type)
    40  	assert.Equal(t, pr.RepoID, ref.RefRepoID)
    41  	assert.True(t, ref.RefIsPull)
    42  	assert.Equal(t, references.XRefActionReopens, ref.RefAction)
    43  
    44  	// Issue mentioning issue #1
    45  	content = fmt.Sprintf("content3, mentions #%d", itarget.Index)
    46  	i := testCreateIssue(t, 1, 2, "title3", content, false)
    47  	ref = unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{IssueID: itarget.ID, RefIssueID: i.ID, RefCommentID: 0})
    48  	assert.Equal(t, issues_model.CommentTypeIssueRef, ref.Type)
    49  	assert.Equal(t, pr.RepoID, ref.RefRepoID)
    50  	assert.False(t, ref.RefIsPull)
    51  	assert.Equal(t, references.XRefActionNone, ref.RefAction)
    52  
    53  	// Issue #4 to test against
    54  	itarget = testCreateIssue(t, 3, 3, "title4", "content4", false)
    55  
    56  	// Cross-reference to issue #4 by admin
    57  	content = fmt.Sprintf("content5, mentions org3/repo3#%d", itarget.Index)
    58  	i = testCreateIssue(t, 2, 1, "title5", content, false)
    59  	ref = unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{IssueID: itarget.ID, RefIssueID: i.ID, RefCommentID: 0})
    60  	assert.Equal(t, issues_model.CommentTypeIssueRef, ref.Type)
    61  	assert.Equal(t, i.RepoID, ref.RefRepoID)
    62  	assert.False(t, ref.RefIsPull)
    63  	assert.Equal(t, references.XRefActionNone, ref.RefAction)
    64  
    65  	// Cross-reference to issue #4 with no permission
    66  	content = fmt.Sprintf("content6, mentions org3/repo3#%d", itarget.Index)
    67  	i = testCreateIssue(t, 4, 5, "title6", content, false)
    68  	unittest.AssertNotExistsBean(t, &issues_model.Comment{IssueID: itarget.ID, RefIssueID: i.ID, RefCommentID: 0})
    69  }
    70  
    71  func TestXRef_NeuterCrossReferences(t *testing.T) {
    72  	assert.NoError(t, unittest.PrepareTestDatabase())
    73  
    74  	// Issue #1 to test against
    75  	itarget := testCreateIssue(t, 1, 2, "title1", "content1", false)
    76  
    77  	// Issue mentioning issue #1
    78  	title := fmt.Sprintf("title2, mentions #%d", itarget.Index)
    79  	i := testCreateIssue(t, 1, 2, title, "content2", false)
    80  	ref := unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{IssueID: itarget.ID, RefIssueID: i.ID, RefCommentID: 0})
    81  	assert.Equal(t, issues_model.CommentTypeIssueRef, ref.Type)
    82  	assert.Equal(t, references.XRefActionNone, ref.RefAction)
    83  
    84  	d := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
    85  	i.Title = "title2, no mentions"
    86  	assert.NoError(t, issues_model.ChangeIssueTitle(db.DefaultContext, i, d, title))
    87  
    88  	ref = unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{IssueID: itarget.ID, RefIssueID: i.ID, RefCommentID: 0})
    89  	assert.Equal(t, issues_model.CommentTypeIssueRef, ref.Type)
    90  	assert.Equal(t, references.XRefActionNeutered, ref.RefAction)
    91  }
    92  
    93  func TestXRef_ResolveCrossReferences(t *testing.T) {
    94  	assert.NoError(t, unittest.PrepareTestDatabase())
    95  
    96  	d := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
    97  
    98  	i1 := testCreateIssue(t, 1, 2, "title1", "content1", false)
    99  	i2 := testCreateIssue(t, 1, 2, "title2", "content2", false)
   100  	i3 := testCreateIssue(t, 1, 2, "title3", "content3", false)
   101  	_, err := issues_model.ChangeIssueStatus(db.DefaultContext, i3, d, true)
   102  	assert.NoError(t, err)
   103  
   104  	pr := testCreatePR(t, 1, 2, "titlepr", fmt.Sprintf("closes #%d", i1.Index))
   105  	rp := unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{IssueID: i1.ID, RefIssueID: pr.Issue.ID, RefCommentID: 0})
   106  
   107  	c1 := testCreateComment(t, 1, 2, pr.Issue.ID, fmt.Sprintf("closes #%d", i2.Index))
   108  	r1 := unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{IssueID: i2.ID, RefIssueID: pr.Issue.ID, RefCommentID: c1.ID})
   109  
   110  	// Must be ignored
   111  	c2 := testCreateComment(t, 1, 2, pr.Issue.ID, fmt.Sprintf("mentions #%d", i2.Index))
   112  	unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{IssueID: i2.ID, RefIssueID: pr.Issue.ID, RefCommentID: c2.ID})
   113  
   114  	// Must be superseded by c4/r4
   115  	c3 := testCreateComment(t, 1, 2, pr.Issue.ID, fmt.Sprintf("reopens #%d", i3.Index))
   116  	unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{IssueID: i3.ID, RefIssueID: pr.Issue.ID, RefCommentID: c3.ID})
   117  
   118  	c4 := testCreateComment(t, 1, 2, pr.Issue.ID, fmt.Sprintf("closes #%d", i3.Index))
   119  	r4 := unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{IssueID: i3.ID, RefIssueID: pr.Issue.ID, RefCommentID: c4.ID})
   120  
   121  	refs, err := pr.ResolveCrossReferences(db.DefaultContext)
   122  	assert.NoError(t, err)
   123  	assert.Len(t, refs, 3)
   124  	assert.Equal(t, rp.ID, refs[0].ID, "bad ref rp: %+v", refs[0])
   125  	assert.Equal(t, r1.ID, refs[1].ID, "bad ref r1: %+v", refs[1])
   126  	assert.Equal(t, r4.ID, refs[2].ID, "bad ref r4: %+v", refs[2])
   127  }
   128  
   129  func testCreateIssue(t *testing.T, repo, doer int64, title, content string, ispull bool) *issues_model.Issue {
   130  	r := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: repo})
   131  	d := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: doer})
   132  
   133  	ctx, committer, err := db.TxContext(db.DefaultContext)
   134  	assert.NoError(t, err)
   135  	defer committer.Close()
   136  
   137  	idx, err := db.GetNextResourceIndex(ctx, "issue_index", r.ID)
   138  	assert.NoError(t, err)
   139  	i := &issues_model.Issue{
   140  		RepoID:   r.ID,
   141  		PosterID: d.ID,
   142  		Poster:   d,
   143  		Title:    title,
   144  		Content:  content,
   145  		IsPull:   ispull,
   146  		Index:    idx,
   147  	}
   148  
   149  	err = issues_model.NewIssueWithIndex(ctx, d, issues_model.NewIssueOptions{
   150  		Repo:  r,
   151  		Issue: i,
   152  	})
   153  	assert.NoError(t, err)
   154  	i, err = issues_model.GetIssueByID(ctx, i.ID)
   155  	assert.NoError(t, err)
   156  	assert.NoError(t, i.AddCrossReferences(ctx, d, false))
   157  	assert.NoError(t, committer.Commit())
   158  	return i
   159  }
   160  
   161  func testCreatePR(t *testing.T, repo, doer int64, title, content string) *issues_model.PullRequest {
   162  	r := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: repo})
   163  	d := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: doer})
   164  	i := &issues_model.Issue{RepoID: r.ID, PosterID: d.ID, Poster: d, Title: title, Content: content, IsPull: true}
   165  	pr := &issues_model.PullRequest{HeadRepoID: repo, BaseRepoID: repo, HeadBranch: "head", BaseBranch: "base", Status: issues_model.PullRequestStatusMergeable}
   166  	assert.NoError(t, issues_model.NewPullRequest(db.DefaultContext, r, i, nil, nil, pr))
   167  	pr.Issue = i
   168  	return pr
   169  }
   170  
   171  func testCreateComment(t *testing.T, repo, doer, issue int64, content string) *issues_model.Comment {
   172  	d := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: doer})
   173  	i := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: issue})
   174  	c := &issues_model.Comment{Type: issues_model.CommentTypeComment, PosterID: doer, Poster: d, IssueID: issue, Issue: i, Content: content}
   175  
   176  	ctx, committer, err := db.TxContext(db.DefaultContext)
   177  	assert.NoError(t, err)
   178  	defer committer.Close()
   179  	err = db.Insert(ctx, c)
   180  	assert.NoError(t, err)
   181  	assert.NoError(t, c.AddCrossReferences(ctx, d, false))
   182  	assert.NoError(t, committer.Commit())
   183  	return c
   184  }