code.gitea.io/gitea@v1.21.7/services/gitdiff/gitdiff_test.go (about)

     1  // Copyright 2014 The Gogs Authors. All rights reserved.
     2  // Copyright 2019 The Gitea Authors. All rights reserved.
     3  // SPDX-License-Identifier: MIT
     4  
     5  package gitdiff
     6  
     7  import (
     8  	"fmt"
     9  	"strconv"
    10  	"strings"
    11  	"testing"
    12  
    13  	"code.gitea.io/gitea/models/db"
    14  	issues_model "code.gitea.io/gitea/models/issues"
    15  	"code.gitea.io/gitea/models/unittest"
    16  	user_model "code.gitea.io/gitea/models/user"
    17  	"code.gitea.io/gitea/modules/git"
    18  	"code.gitea.io/gitea/modules/json"
    19  	"code.gitea.io/gitea/modules/setting"
    20  
    21  	dmp "github.com/sergi/go-diff/diffmatchpatch"
    22  	"github.com/stretchr/testify/assert"
    23  )
    24  
    25  func TestDiffToHTML(t *testing.T) {
    26  	assert.Equal(t, "foo <span class=\"added-code\">bar</span> biz", diffToHTML(nil, []dmp.Diff{
    27  		{Type: dmp.DiffEqual, Text: "foo "},
    28  		{Type: dmp.DiffInsert, Text: "bar"},
    29  		{Type: dmp.DiffDelete, Text: " baz"},
    30  		{Type: dmp.DiffEqual, Text: " biz"},
    31  	}, DiffLineAdd))
    32  
    33  	assert.Equal(t, "foo <span class=\"removed-code\">bar</span> biz", diffToHTML(nil, []dmp.Diff{
    34  		{Type: dmp.DiffEqual, Text: "foo "},
    35  		{Type: dmp.DiffDelete, Text: "bar"},
    36  		{Type: dmp.DiffInsert, Text: " baz"},
    37  		{Type: dmp.DiffEqual, Text: " biz"},
    38  	}, DiffLineDel))
    39  }
    40  
    41  func TestParsePatch_skipTo(t *testing.T) {
    42  	type testcase struct {
    43  		name        string
    44  		gitdiff     string
    45  		wantErr     bool
    46  		addition    int
    47  		deletion    int
    48  		oldFilename string
    49  		filename    string
    50  		skipTo      string
    51  	}
    52  	tests := []testcase{
    53  		{
    54  			name: "readme.md2readme.md",
    55  			gitdiff: `diff --git "a/A \\ B" "b/A \\ B"
    56  --- "a/A \\ B"
    57  +++ "b/A \\ B"
    58  @@ -1,3 +1,6 @@
    59   # gitea-github-migrator
    60  +
    61  + Build Status
    62  - Latest Release
    63   Docker Pulls
    64  + cut off
    65  + cut off
    66  diff --git "\\a/README.md" "\\b/README.md"
    67  --- "\\a/README.md"
    68  +++ "\\b/README.md"
    69  @@ -1,3 +1,6 @@
    70   # gitea-github-migrator
    71  +
    72  + Build Status
    73  - Latest Release
    74   Docker Pulls
    75  + cut off
    76  + cut off
    77  `,
    78  			addition:    4,
    79  			deletion:    1,
    80  			filename:    "README.md",
    81  			oldFilename: "README.md",
    82  			skipTo:      "README.md",
    83  		},
    84  		{
    85  			name: "A \\ B",
    86  			gitdiff: `diff --git "a/A \\ B" "b/A \\ B"
    87  --- "a/A \\ B"
    88  +++ "b/A \\ B"
    89  @@ -1,3 +1,6 @@
    90   # gitea-github-migrator
    91  +
    92  + Build Status
    93  - Latest Release
    94   Docker Pulls
    95  + cut off
    96  + cut off`,
    97  			addition:    4,
    98  			deletion:    1,
    99  			filename:    "A \\ B",
   100  			oldFilename: "A \\ B",
   101  			skipTo:      "A \\ B",
   102  		},
   103  		{
   104  			name: "A \\ B",
   105  			gitdiff: `diff --git "\\a/README.md" "\\b/README.md"
   106  --- "\\a/README.md"
   107  +++ "\\b/README.md"
   108  @@ -1,3 +1,6 @@
   109   # gitea-github-migrator
   110  +
   111  + Build Status
   112  - Latest Release
   113   Docker Pulls
   114  + cut off
   115  + cut off
   116  diff --git "a/A \\ B" "b/A \\ B"
   117  --- "a/A \\ B"
   118  +++ "b/A \\ B"
   119  @@ -1,3 +1,6 @@
   120   # gitea-github-migrator
   121  +
   122  + Build Status
   123  - Latest Release
   124   Docker Pulls
   125  + cut off
   126  + cut off`,
   127  			addition:    4,
   128  			deletion:    1,
   129  			filename:    "A \\ B",
   130  			oldFilename: "A \\ B",
   131  			skipTo:      "A \\ B",
   132  		},
   133  		{
   134  			name: "readme.md2readme.md",
   135  			gitdiff: `diff --git "a/A \\ B" "b/A \\ B"
   136  --- "a/A \\ B"
   137  +++ "b/A \\ B"
   138  @@ -1,3 +1,6 @@
   139   # gitea-github-migrator
   140  +
   141  + Build Status
   142  - Latest Release
   143   Docker Pulls
   144  + cut off
   145  + cut off
   146  diff --git "a/A \\ B" "b/A \\ B"
   147  --- "a/A \\ B"
   148  +++ "b/A \\ B"
   149  @@ -1,3 +1,6 @@
   150   # gitea-github-migrator
   151  +
   152  + Build Status
   153  - Latest Release
   154   Docker Pulls
   155  + cut off
   156  + cut off
   157  diff --git "\\a/README.md" "\\b/README.md"
   158  --- "\\a/README.md"
   159  +++ "\\b/README.md"
   160  @@ -1,3 +1,6 @@
   161   # gitea-github-migrator
   162  +
   163  + Build Status
   164  - Latest Release
   165   Docker Pulls
   166  + cut off
   167  + cut off
   168  `,
   169  			addition:    4,
   170  			deletion:    1,
   171  			filename:    "README.md",
   172  			oldFilename: "README.md",
   173  			skipTo:      "README.md",
   174  		},
   175  	}
   176  	for _, testcase := range tests {
   177  		t.Run(testcase.name, func(t *testing.T) {
   178  			got, err := ParsePatch(setting.Git.MaxGitDiffLines, setting.Git.MaxGitDiffLineCharacters, setting.Git.MaxGitDiffFiles, strings.NewReader(testcase.gitdiff), testcase.skipTo)
   179  			if (err != nil) != testcase.wantErr {
   180  				t.Errorf("ParsePatch(%q) error = %v, wantErr %v", testcase.name, err, testcase.wantErr)
   181  				return
   182  			}
   183  
   184  			gotMarshaled, _ := json.MarshalIndent(got, "", "  ")
   185  			if got.NumFiles != 1 {
   186  				t.Errorf("ParsePath(%q) did not receive 1 file:\n%s", testcase.name, string(gotMarshaled))
   187  				return
   188  			}
   189  			if got.TotalAddition != testcase.addition {
   190  				t.Errorf("ParsePath(%q) does not have correct totalAddition %d, wanted %d", testcase.name, got.TotalAddition, testcase.addition)
   191  			}
   192  			if got.TotalDeletion != testcase.deletion {
   193  				t.Errorf("ParsePath(%q) did not have correct totalDeletion %d, wanted %d", testcase.name, got.TotalDeletion, testcase.deletion)
   194  			}
   195  			file := got.Files[0]
   196  			if file.Addition != testcase.addition {
   197  				t.Errorf("ParsePath(%q) does not have correct file addition %d, wanted %d", testcase.name, file.Addition, testcase.addition)
   198  			}
   199  			if file.Deletion != testcase.deletion {
   200  				t.Errorf("ParsePath(%q) did not have correct file deletion %d, wanted %d", testcase.name, file.Deletion, testcase.deletion)
   201  			}
   202  			if file.OldName != testcase.oldFilename {
   203  				t.Errorf("ParsePath(%q) did not have correct OldName %q, wanted %q", testcase.name, file.OldName, testcase.oldFilename)
   204  			}
   205  			if file.Name != testcase.filename {
   206  				t.Errorf("ParsePath(%q) did not have correct Name %q, wanted %q", testcase.name, file.Name, testcase.filename)
   207  			}
   208  		})
   209  	}
   210  }
   211  
   212  func TestParsePatch_singlefile(t *testing.T) {
   213  	type testcase struct {
   214  		name        string
   215  		gitdiff     string
   216  		wantErr     bool
   217  		addition    int
   218  		deletion    int
   219  		oldFilename string
   220  		filename    string
   221  	}
   222  
   223  	tests := []testcase{
   224  		{
   225  			name: "readme.md2readme.md",
   226  			gitdiff: `diff --git "\\a/README.md" "\\b/README.md"
   227  --- "\\a/README.md"
   228  +++ "\\b/README.md"
   229  @@ -1,3 +1,6 @@
   230   # gitea-github-migrator
   231  +
   232  + Build Status
   233  - Latest Release
   234   Docker Pulls
   235  + cut off
   236  + cut off
   237  `,
   238  			addition:    4,
   239  			deletion:    1,
   240  			filename:    "README.md",
   241  			oldFilename: "README.md",
   242  		},
   243  		{
   244  			name: "A \\ B",
   245  			gitdiff: `diff --git "a/A \\ B" "b/A \\ B"
   246  --- "a/A \\ B"
   247  +++ "b/A \\ B"
   248  @@ -1,3 +1,6 @@
   249   # gitea-github-migrator
   250  +
   251  + Build Status
   252  - Latest Release
   253   Docker Pulls
   254  + cut off
   255  + cut off`,
   256  			addition:    4,
   257  			deletion:    1,
   258  			filename:    "A \\ B",
   259  			oldFilename: "A \\ B",
   260  		},
   261  		{
   262  			name: "really weird filename",
   263  			gitdiff: `diff --git "\\a/a b/file b/a a/file" "\\b/a b/file b/a a/file"
   264  index d2186f1..f5c8ed2 100644
   265  --- "\\a/a b/file b/a a/file"	` + `
   266  +++ "\\b/a b/file b/a a/file"	` + `
   267  @@ -1,3 +1,2 @@
   268   Create a weird file.
   269   ` + `
   270  -and what does diff do here?
   271  \ No newline at end of file`,
   272  			addition:    0,
   273  			deletion:    1,
   274  			filename:    "a b/file b/a a/file",
   275  			oldFilename: "a b/file b/a a/file",
   276  		},
   277  		{
   278  			name: "delete file with blanks",
   279  			gitdiff: `diff --git "\\a/file with blanks" "\\b/file with blanks"
   280  deleted file mode 100644
   281  index 898651a..0000000
   282  --- "\\a/file with blanks" ` + `
   283  +++ /dev/null
   284  @@ -1,5 +0,0 @@
   285  -a blank file
   286  -
   287  -has a couple o line
   288  -
   289  -the 5th line is the last
   290  `,
   291  			addition:    0,
   292  			deletion:    5,
   293  			filename:    "file with blanks",
   294  			oldFilename: "file with blanks",
   295  		},
   296  		{
   297  			name: "rename a—as",
   298  			gitdiff: `diff --git "a/\360\243\220\265b\342\200\240vs" "b/a\342\200\224as"
   299  similarity index 100%
   300  rename from "\360\243\220\265b\342\200\240vs"
   301  rename to "a\342\200\224as"
   302  `,
   303  			addition:    0,
   304  			deletion:    0,
   305  			oldFilename: "𣐵b†vs",
   306  			filename:    "a—as",
   307  		},
   308  		{
   309  			name: "rename with spaces",
   310  			gitdiff: `diff --git "\\a/a b/file b/a a/file" "\\b/a b/a a/file b/b file"
   311  similarity index 100%
   312  rename from a b/file b/a a/file
   313  rename to a b/a a/file b/b file
   314  `,
   315  			oldFilename: "a b/file b/a a/file",
   316  			filename:    "a b/a a/file b/b file",
   317  		},
   318  		{
   319  			name: "ambiguous deleted",
   320  			gitdiff: `diff --git a/b b/b b/b b/b
   321  deleted file mode 100644
   322  index 92e798b..0000000
   323  --- a/b b/b` + "\t" + `
   324  +++ /dev/null
   325  @@ -1 +0,0 @@
   326  -b b/b
   327  `,
   328  			oldFilename: "b b/b",
   329  			filename:    "b b/b",
   330  			addition:    0,
   331  			deletion:    1,
   332  		},
   333  		{
   334  			name: "ambiguous addition",
   335  			gitdiff: `diff --git a/b b/b b/b b/b
   336  new file mode 100644
   337  index 0000000..92e798b
   338  --- /dev/null
   339  +++ b/b b/b` + "\t" + `
   340  @@ -0,0 +1 @@
   341  +b b/b
   342  `,
   343  			oldFilename: "b b/b",
   344  			filename:    "b b/b",
   345  			addition:    1,
   346  			deletion:    0,
   347  		},
   348  		{
   349  			name: "rename",
   350  			gitdiff: `diff --git a/b b/b b/b b/b b/b b/b
   351  similarity index 100%
   352  rename from b b/b b/b b/b b/b
   353  rename to b
   354  `,
   355  			oldFilename: "b b/b b/b b/b b/b",
   356  			filename:    "b",
   357  		},
   358  		{
   359  			name: "ambiguous 1",
   360  			gitdiff: `diff --git a/b b/b b/b b/b b/b b/b
   361  similarity index 100%
   362  rename from b b/b b/b b/b b/b
   363  rename to b
   364  `,
   365  			oldFilename: "b b/b b/b b/b b/b",
   366  			filename:    "b",
   367  		},
   368  		{
   369  			name: "ambiguous 2",
   370  			gitdiff: `diff --git a/b b/b b/b b/b b/b b/b
   371  similarity index 100%
   372  rename from b b/b b/b b/b
   373  rename to b b/b
   374  `,
   375  			oldFilename: "b b/b b/b b/b",
   376  			filename:    "b b/b",
   377  		},
   378  		{
   379  			name: "minuses-and-pluses",
   380  			gitdiff: `diff --git a/minuses-and-pluses b/minuses-and-pluses
   381  index 6961180..9ba1a00 100644
   382  --- a/minuses-and-pluses
   383  +++ b/minuses-and-pluses
   384  @@ -1,4 +1,4 @@
   385  --- 1st line
   386  -++ 2nd line
   387  --- 3rd line
   388  -++ 4th line
   389  +++ 1st line
   390  +-- 2nd line
   391  +++ 3rd line
   392  +-- 4th line
   393  `,
   394  			oldFilename: "minuses-and-pluses",
   395  			filename:    "minuses-and-pluses",
   396  			addition:    4,
   397  			deletion:    4,
   398  		},
   399  	}
   400  
   401  	for _, testcase := range tests {
   402  		t.Run(testcase.name, func(t *testing.T) {
   403  			got, err := ParsePatch(setting.Git.MaxGitDiffLines, setting.Git.MaxGitDiffLineCharacters, setting.Git.MaxGitDiffFiles, strings.NewReader(testcase.gitdiff), "")
   404  			if (err != nil) != testcase.wantErr {
   405  				t.Errorf("ParsePatch(%q) error = %v, wantErr %v", testcase.name, err, testcase.wantErr)
   406  				return
   407  			}
   408  
   409  			gotMarshaled, _ := json.MarshalIndent(got, "", "  ")
   410  			if got.NumFiles != 1 {
   411  				t.Errorf("ParsePath(%q) did not receive 1 file:\n%s", testcase.name, string(gotMarshaled))
   412  				return
   413  			}
   414  			if got.TotalAddition != testcase.addition {
   415  				t.Errorf("ParsePath(%q) does not have correct totalAddition %d, wanted %d", testcase.name, got.TotalAddition, testcase.addition)
   416  			}
   417  			if got.TotalDeletion != testcase.deletion {
   418  				t.Errorf("ParsePath(%q) did not have correct totalDeletion %d, wanted %d", testcase.name, got.TotalDeletion, testcase.deletion)
   419  			}
   420  			file := got.Files[0]
   421  			if file.Addition != testcase.addition {
   422  				t.Errorf("ParsePath(%q) does not have correct file addition %d, wanted %d", testcase.name, file.Addition, testcase.addition)
   423  			}
   424  			if file.Deletion != testcase.deletion {
   425  				t.Errorf("ParsePath(%q) did not have correct file deletion %d, wanted %d", testcase.name, file.Deletion, testcase.deletion)
   426  			}
   427  			if file.OldName != testcase.oldFilename {
   428  				t.Errorf("ParsePath(%q) did not have correct OldName %q, wanted %q", testcase.name, file.OldName, testcase.oldFilename)
   429  			}
   430  			if file.Name != testcase.filename {
   431  				t.Errorf("ParsePath(%q) did not have correct Name %q, wanted %q", testcase.name, file.Name, testcase.filename)
   432  			}
   433  		})
   434  	}
   435  
   436  	// Test max lines
   437  	diffBuilder := &strings.Builder{}
   438  
   439  	diff := `diff --git a/newfile2 b/newfile2
   440  new file mode 100644
   441  index 0000000..6bb8f39
   442  --- /dev/null
   443  +++ b/newfile2
   444  @@ -0,0 +1,35 @@
   445  `
   446  	diffBuilder.WriteString(diff)
   447  
   448  	for i := 0; i < 35; i++ {
   449  		diffBuilder.WriteString("+line" + strconv.Itoa(i) + "\n")
   450  	}
   451  	diff = diffBuilder.String()
   452  	result, err := ParsePatch(20, setting.Git.MaxGitDiffLineCharacters, setting.Git.MaxGitDiffFiles, strings.NewReader(diff), "")
   453  	if err != nil {
   454  		t.Errorf("There should not be an error: %v", err)
   455  	}
   456  	if !result.Files[0].IsIncomplete {
   457  		t.Errorf("Files should be incomplete! %v", result.Files[0])
   458  	}
   459  	result, err = ParsePatch(40, setting.Git.MaxGitDiffLineCharacters, setting.Git.MaxGitDiffFiles, strings.NewReader(diff), "")
   460  	if err != nil {
   461  		t.Errorf("There should not be an error: %v", err)
   462  	}
   463  	if result.Files[0].IsIncomplete {
   464  		t.Errorf("Files should not be incomplete! %v", result.Files[0])
   465  	}
   466  	result, err = ParsePatch(40, 5, setting.Git.MaxGitDiffFiles, strings.NewReader(diff), "")
   467  	if err != nil {
   468  		t.Errorf("There should not be an error: %v", err)
   469  	}
   470  	if !result.Files[0].IsIncomplete {
   471  		t.Errorf("Files should be incomplete! %v", result.Files[0])
   472  	}
   473  
   474  	// Test max characters
   475  	diff = `diff --git a/newfile2 b/newfile2
   476  new file mode 100644
   477  index 0000000..6bb8f39
   478  --- /dev/null
   479  +++ b/newfile2
   480  @@ -0,0 +1,35 @@
   481  `
   482  	diffBuilder.Reset()
   483  	diffBuilder.WriteString(diff)
   484  
   485  	for i := 0; i < 33; i++ {
   486  		diffBuilder.WriteString("+line" + strconv.Itoa(i) + "\n")
   487  	}
   488  	diffBuilder.WriteString("+line33")
   489  	for i := 0; i < 512; i++ {
   490  		diffBuilder.WriteString("0123456789ABCDEF")
   491  	}
   492  	diffBuilder.WriteByte('\n')
   493  	diffBuilder.WriteString("+line" + strconv.Itoa(34) + "\n")
   494  	diffBuilder.WriteString("+line" + strconv.Itoa(35) + "\n")
   495  	diff = diffBuilder.String()
   496  
   497  	result, err = ParsePatch(20, 4096, setting.Git.MaxGitDiffFiles, strings.NewReader(diff), "")
   498  	if err != nil {
   499  		t.Errorf("There should not be an error: %v", err)
   500  	}
   501  	if !result.Files[0].IsIncomplete {
   502  		t.Errorf("Files should be incomplete! %v", result.Files[0])
   503  	}
   504  	result, err = ParsePatch(40, 4096, setting.Git.MaxGitDiffFiles, strings.NewReader(diff), "")
   505  	if err != nil {
   506  		t.Errorf("There should not be an error: %v", err)
   507  	}
   508  	if !result.Files[0].IsIncomplete {
   509  		t.Errorf("Files should be incomplete! %v", result.Files[0])
   510  	}
   511  
   512  	diff = `diff --git "a/README.md" "b/README.md"
   513  --- a/README.md
   514  +++ b/README.md
   515  @@ -1,3 +1,6 @@
   516   # gitea-github-migrator
   517  +
   518  + Build Status
   519  - Latest Release
   520   Docker Pulls
   521  + cut off
   522  + cut off`
   523  	_, err = ParsePatch(setting.Git.MaxGitDiffLines, setting.Git.MaxGitDiffLineCharacters, setting.Git.MaxGitDiffFiles, strings.NewReader(diff), "")
   524  	if err != nil {
   525  		t.Errorf("ParsePatch failed: %s", err)
   526  	}
   527  
   528  	diff2 := `diff --git "a/A \\ B" "b/A \\ B"
   529  --- "a/A \\ B"
   530  +++ "b/A \\ B"
   531  @@ -1,3 +1,6 @@
   532   # gitea-github-migrator
   533  +
   534  + Build Status
   535  - Latest Release
   536   Docker Pulls
   537  + cut off
   538  + cut off`
   539  	_, err = ParsePatch(setting.Git.MaxGitDiffLines, setting.Git.MaxGitDiffLineCharacters, setting.Git.MaxGitDiffFiles, strings.NewReader(diff2), "")
   540  	if err != nil {
   541  		t.Errorf("ParsePatch failed: %s", err)
   542  	}
   543  
   544  	diff2a := `diff --git "a/A \\ B" b/A/B
   545  --- "a/A \\ B"
   546  +++ b/A/B
   547  @@ -1,3 +1,6 @@
   548   # gitea-github-migrator
   549  +
   550  + Build Status
   551  - Latest Release
   552   Docker Pulls
   553  + cut off
   554  + cut off`
   555  	_, err = ParsePatch(setting.Git.MaxGitDiffLines, setting.Git.MaxGitDiffLineCharacters, setting.Git.MaxGitDiffFiles, strings.NewReader(diff2a), "")
   556  	if err != nil {
   557  		t.Errorf("ParsePatch failed: %s", err)
   558  	}
   559  
   560  	diff3 := `diff --git a/README.md b/README.md
   561  --- a/README.md
   562  +++ b/README.md
   563  @@ -1,3 +1,6 @@
   564   # gitea-github-migrator
   565  +
   566  + Build Status
   567  - Latest Release
   568   Docker Pulls
   569  + cut off
   570  + cut off`
   571  	_, err = ParsePatch(setting.Git.MaxGitDiffLines, setting.Git.MaxGitDiffLineCharacters, setting.Git.MaxGitDiffFiles, strings.NewReader(diff3), "")
   572  	if err != nil {
   573  		t.Errorf("ParsePatch failed: %s", err)
   574  	}
   575  }
   576  
   577  func setupDefaultDiff() *Diff {
   578  	return &Diff{
   579  		Files: []*DiffFile{
   580  			{
   581  				Name: "README.md",
   582  				Sections: []*DiffSection{
   583  					{
   584  						Lines: []*DiffLine{
   585  							{
   586  								LeftIdx:  4,
   587  								RightIdx: 4,
   588  							},
   589  						},
   590  					},
   591  				},
   592  			},
   593  		},
   594  	}
   595  }
   596  
   597  func TestDiff_LoadCommentsNoOutdated(t *testing.T) {
   598  	assert.NoError(t, unittest.PrepareTestDatabase())
   599  
   600  	issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 2})
   601  	user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1})
   602  	diff := setupDefaultDiff()
   603  	assert.NoError(t, diff.LoadComments(db.DefaultContext, issue, user, false))
   604  	assert.Len(t, diff.Files[0].Sections[0].Lines[0].Comments, 2)
   605  }
   606  
   607  func TestDiff_LoadCommentsWithOutdated(t *testing.T) {
   608  	assert.NoError(t, unittest.PrepareTestDatabase())
   609  
   610  	issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 2})
   611  	user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1})
   612  	diff := setupDefaultDiff()
   613  	assert.NoError(t, diff.LoadComments(db.DefaultContext, issue, user, true))
   614  	assert.Len(t, diff.Files[0].Sections[0].Lines[0].Comments, 3)
   615  }
   616  
   617  func TestDiffLine_CanComment(t *testing.T) {
   618  	assert.False(t, (&DiffLine{Type: DiffLineSection}).CanComment())
   619  	assert.False(t, (&DiffLine{Type: DiffLineAdd, Comments: []*issues_model.Comment{{Content: "bla"}}}).CanComment())
   620  	assert.True(t, (&DiffLine{Type: DiffLineAdd}).CanComment())
   621  	assert.True(t, (&DiffLine{Type: DiffLineDel}).CanComment())
   622  	assert.True(t, (&DiffLine{Type: DiffLinePlain}).CanComment())
   623  }
   624  
   625  func TestDiffLine_GetCommentSide(t *testing.T) {
   626  	assert.Equal(t, "previous", (&DiffLine{Comments: []*issues_model.Comment{{Line: -3}}}).GetCommentSide())
   627  	assert.Equal(t, "proposed", (&DiffLine{Comments: []*issues_model.Comment{{Line: 3}}}).GetCommentSide())
   628  }
   629  
   630  func TestGetDiffRangeWithWhitespaceBehavior(t *testing.T) {
   631  	gitRepo, err := git.OpenRepository(git.DefaultContext, "./testdata/academic-module")
   632  	if !assert.NoError(t, err) {
   633  		return
   634  	}
   635  	defer gitRepo.Close()
   636  	for _, behavior := range []git.TrustedCmdArgs{{"-w"}, {"--ignore-space-at-eol"}, {"-b"}, nil} {
   637  		diffs, err := GetDiff(gitRepo,
   638  			&DiffOptions{
   639  				AfterCommitID:      "bd7063cc7c04689c4d082183d32a604ed27a24f9",
   640  				BeforeCommitID:     "559c156f8e0178b71cb44355428f24001b08fc68",
   641  				MaxLines:           setting.Git.MaxGitDiffLines,
   642  				MaxLineCharacters:  setting.Git.MaxGitDiffLineCharacters,
   643  				MaxFiles:           setting.Git.MaxGitDiffFiles,
   644  				WhitespaceBehavior: behavior,
   645  			})
   646  		assert.NoError(t, err, fmt.Sprintf("Error when diff with %s", behavior))
   647  		for _, f := range diffs.Files {
   648  			assert.True(t, len(f.Sections) > 0, fmt.Sprintf("%s should have sections", f.Name))
   649  		}
   650  	}
   651  }
   652  
   653  func TestNoCrashes(t *testing.T) {
   654  	type testcase struct {
   655  		gitdiff string
   656  	}
   657  
   658  	tests := []testcase{
   659  		{
   660  			gitdiff: "diff --git \n--- a\t\n",
   661  		},
   662  		{
   663  			gitdiff: "diff --git \"0\n",
   664  		},
   665  	}
   666  	for _, testcase := range tests {
   667  		// It shouldn't crash, so don't care about the output.
   668  		ParsePatch(setting.Git.MaxGitDiffLines, setting.Git.MaxGitDiffLineCharacters, setting.Git.MaxGitDiffFiles, strings.NewReader(testcase.gitdiff), "")
   669  	}
   670  }