| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427 |
- // Copyright 2025 The Gitea Authors. All rights reserved.
- // SPDX-License-Identifier: MIT
-
- package gitdiff
-
- import (
- "strings"
- "testing"
-
- "code.gitea.io/gitea/modules/git"
-
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/require"
- )
-
- func TestGitDiffTree(t *testing.T) {
- test := []struct {
- Name string
- RepoPath string
- BaseSha string
- HeadSha string
- useMergeBase bool
- Expected *DiffTree
- }{
- {
- Name: "happy path",
- RepoPath: "../../modules/git/tests/repos/repo5_pulls",
- BaseSha: "72866af952e98d02a73003501836074b286a78f6",
- HeadSha: "d8e0bbb45f200e67d9a784ce55bd90821af45ebd",
- Expected: &DiffTree{
- Files: []*DiffTreeRecord{
- {
- Status: "modified",
- HeadPath: "LICENSE",
- BasePath: "LICENSE",
- HeadMode: git.EntryModeBlob,
- BaseMode: git.EntryModeBlob,
- HeadBlobID: "ee469963e76ae1bb7ee83d7510df2864e6c8c640",
- BaseBlobID: "c996f4725be8fc8c1d1c776e58c97ddc5d03b336",
- },
- {
- Status: "modified",
- HeadPath: "README.md",
- BasePath: "README.md",
- HeadMode: git.EntryModeBlob,
- BaseMode: git.EntryModeBlob,
- HeadBlobID: "9dfc0a6257d8eff526f0cfaf6a8ea950f55a9dba",
- BaseBlobID: "074e590b8e64898b02beef03ece83f962c94f54c",
- },
- },
- },
- },
- {
- Name: "first commit (no parent)",
- RepoPath: "../../modules/git/tests/repos/repo5_pulls",
- HeadSha: "72866af952e98d02a73003501836074b286a78f6",
- Expected: &DiffTree{
- Files: []*DiffTreeRecord{
- {
- Status: "added",
- HeadPath: ".gitignore",
- BasePath: ".gitignore",
- HeadMode: git.EntryModeBlob,
- BaseMode: git.EntryModeNoEntry,
- HeadBlobID: "f1c181ec9c5c921245027c6b452ecfc1d3626364",
- BaseBlobID: "0000000000000000000000000000000000000000",
- },
- {
- Status: "added",
- HeadPath: "LICENSE",
- BasePath: "LICENSE",
- HeadMode: git.EntryModeBlob,
- BaseMode: git.EntryModeNoEntry,
- HeadBlobID: "c996f4725be8fc8c1d1c776e58c97ddc5d03b336",
- BaseBlobID: "0000000000000000000000000000000000000000",
- },
- {
- Status: "added",
- HeadPath: "README.md",
- BasePath: "README.md",
- HeadMode: git.EntryModeBlob,
- BaseMode: git.EntryModeNoEntry,
- HeadBlobID: "074e590b8e64898b02beef03ece83f962c94f54c",
- BaseBlobID: "0000000000000000000000000000000000000000",
- },
- },
- },
- },
- {
- Name: "first commit (no parent), merge base = true",
- RepoPath: "../../modules/git/tests/repos/repo5_pulls",
- HeadSha: "72866af952e98d02a73003501836074b286a78f6",
- useMergeBase: true,
- Expected: &DiffTree{
- Files: []*DiffTreeRecord{
- {
- Status: "added",
- HeadPath: ".gitignore",
- BasePath: ".gitignore",
- HeadMode: git.EntryModeBlob,
- BaseMode: git.EntryModeNoEntry,
- HeadBlobID: "f1c181ec9c5c921245027c6b452ecfc1d3626364",
- BaseBlobID: "0000000000000000000000000000000000000000",
- },
- {
- Status: "added",
- HeadPath: "LICENSE",
- BasePath: "LICENSE",
- HeadMode: git.EntryModeBlob,
- BaseMode: git.EntryModeNoEntry,
- HeadBlobID: "c996f4725be8fc8c1d1c776e58c97ddc5d03b336",
- BaseBlobID: "0000000000000000000000000000000000000000",
- },
- {
- Status: "added",
- HeadPath: "README.md",
- BasePath: "README.md",
- HeadMode: git.EntryModeBlob,
- BaseMode: git.EntryModeNoEntry,
- HeadBlobID: "074e590b8e64898b02beef03ece83f962c94f54c",
- BaseBlobID: "0000000000000000000000000000000000000000",
- },
- },
- },
- },
- {
- Name: "base and head same",
- RepoPath: "../../modules/git/tests/repos/repo5_pulls",
- BaseSha: "ed8f4d2fa5b2420706580d191f5dd50c4e491f3f",
- HeadSha: "ed8f4d2fa5b2420706580d191f5dd50c4e491f3f",
- Expected: &DiffTree{
- Files: []*DiffTreeRecord{},
- },
- },
- {
- Name: "useMergeBase false",
- RepoPath: "../../modules/git/tests/repos/repo5_pulls",
- BaseSha: "ed8f4d2fa5b2420706580d191f5dd50c4e491f3f",
- HeadSha: "111cac04bd7d20301964e27a93698aabb5781b80", // this commit can be found on the update-readme branch
- useMergeBase: false,
- Expected: &DiffTree{
- Files: []*DiffTreeRecord{
- {
- Status: "modified",
- HeadPath: "LICENSE",
- BasePath: "LICENSE",
- HeadMode: git.EntryModeBlob,
- BaseMode: git.EntryModeBlob,
- HeadBlobID: "c996f4725be8fc8c1d1c776e58c97ddc5d03b336",
- BaseBlobID: "ed5119b3c1f45547b6785bc03eac7f87570fa17f",
- },
-
- {
- Status: "modified",
- HeadPath: "README.md",
- BasePath: "README.md",
- HeadMode: git.EntryModeBlob,
- BaseMode: git.EntryModeBlob,
- HeadBlobID: "fb39771a8865c9a67f2ab9b616c854805664553c",
- BaseBlobID: "9dfc0a6257d8eff526f0cfaf6a8ea950f55a9dba",
- },
- },
- },
- },
- {
- Name: "useMergeBase true",
- RepoPath: "../../modules/git/tests/repos/repo5_pulls",
- BaseSha: "ed8f4d2fa5b2420706580d191f5dd50c4e491f3f",
- HeadSha: "111cac04bd7d20301964e27a93698aabb5781b80", // this commit can be found on the update-readme branch
- useMergeBase: true,
- Expected: &DiffTree{
- Files: []*DiffTreeRecord{
- {
- Status: "modified",
- HeadPath: "README.md",
- BasePath: "README.md",
- HeadMode: git.EntryModeBlob,
- BaseMode: git.EntryModeBlob,
- HeadBlobID: "fb39771a8865c9a67f2ab9b616c854805664553c",
- BaseBlobID: "9dfc0a6257d8eff526f0cfaf6a8ea950f55a9dba",
- },
- },
- },
- },
- {
- Name: "no base set",
- RepoPath: "../../modules/git/tests/repos/repo5_pulls",
- HeadSha: "d8e0bbb45f200e67d9a784ce55bd90821af45ebd", // this commit can be found on the update-readme branch
- useMergeBase: false,
- Expected: &DiffTree{
- Files: []*DiffTreeRecord{
- {
- Status: "modified",
- HeadPath: "LICENSE",
- BasePath: "LICENSE",
- HeadMode: git.EntryModeBlob,
- BaseMode: git.EntryModeBlob,
- HeadBlobID: "ee469963e76ae1bb7ee83d7510df2864e6c8c640",
- BaseBlobID: "ed5119b3c1f45547b6785bc03eac7f87570fa17f",
- },
- },
- },
- },
- }
-
- for _, tt := range test {
- t.Run(tt.Name, func(t *testing.T) {
- gitRepo, err := git.OpenRepository(t.Context(), tt.RepoPath)
- assert.NoError(t, err)
- defer gitRepo.Close()
-
- diffPaths, err := GetDiffTree(t.Context(), gitRepo, tt.useMergeBase, tt.BaseSha, tt.HeadSha)
- require.NoError(t, err)
-
- assert.Equal(t, tt.Expected, diffPaths)
- })
- }
- }
-
- func TestParseGitDiffTree(t *testing.T) {
- test := []struct {
- Name string
- GitOutput string
- Expected []*DiffTreeRecord
- }{
- {
- Name: "file change",
- GitOutput: ":100644 100644 64e43d23bcd08db12563a0a4d84309cadb437e1a 5dbc7792b5bb228647cfcc8dfe65fc649119dedc M\tResources/views/curriculum/edit.blade.php",
- Expected: []*DiffTreeRecord{
- {
- Status: "modified",
- HeadPath: "Resources/views/curriculum/edit.blade.php",
- BasePath: "Resources/views/curriculum/edit.blade.php",
- HeadMode: git.EntryModeBlob,
- BaseMode: git.EntryModeBlob,
- HeadBlobID: "5dbc7792b5bb228647cfcc8dfe65fc649119dedc",
- BaseBlobID: "64e43d23bcd08db12563a0a4d84309cadb437e1a",
- },
- },
- },
- {
- Name: "file added",
- GitOutput: ":000000 100644 0000000000000000000000000000000000000000 0063162fb403db15ceb0517b34ab782e4e58b619 A\tResources/views/class/index.blade.php",
- Expected: []*DiffTreeRecord{
- {
- Status: "added",
- HeadPath: "Resources/views/class/index.blade.php",
- BasePath: "Resources/views/class/index.blade.php",
- HeadMode: git.EntryModeBlob,
- BaseMode: git.EntryModeNoEntry,
- HeadBlobID: "0063162fb403db15ceb0517b34ab782e4e58b619",
- BaseBlobID: "0000000000000000000000000000000000000000",
- },
- },
- },
- {
- Name: "file deleted",
- GitOutput: ":100644 000000 bac4286303c8c0017ea2f0a48c561ddcc0330a14 0000000000000000000000000000000000000000 D\tResources/views/classes/index.blade.php",
- Expected: []*DiffTreeRecord{
- {
- Status: "deleted",
- HeadPath: "Resources/views/classes/index.blade.php",
- BasePath: "Resources/views/classes/index.blade.php",
- HeadMode: git.EntryModeNoEntry,
- BaseMode: git.EntryModeBlob,
- HeadBlobID: "0000000000000000000000000000000000000000",
- BaseBlobID: "bac4286303c8c0017ea2f0a48c561ddcc0330a14",
- },
- },
- },
- {
- Name: "file renamed",
- GitOutput: ":100644 100644 c8a055cfb45cd39747292983ad1797ceab40f5b1 97248f79a90aaf81fe7fd74b33c1cb182dd41783 R087\tDatabase/Seeders/AdminDatabaseSeeder.php\tDatabase/Seeders/AcademicDatabaseSeeder.php",
- Expected: []*DiffTreeRecord{
- {
- Status: "renamed",
- Score: 87,
- HeadPath: "Database/Seeders/AcademicDatabaseSeeder.php",
- BasePath: "Database/Seeders/AdminDatabaseSeeder.php",
- HeadMode: git.EntryModeBlob,
- BaseMode: git.EntryModeBlob,
- HeadBlobID: "97248f79a90aaf81fe7fd74b33c1cb182dd41783",
- BaseBlobID: "c8a055cfb45cd39747292983ad1797ceab40f5b1",
- },
- },
- },
- {
- Name: "no changes",
- GitOutput: ``,
- Expected: []*DiffTreeRecord{},
- },
- {
- Name: "multiple changes",
- GitOutput: ":000000 100644 0000000000000000000000000000000000000000 db736b44533a840981f1f17b7029d0f612b69550 A\tHttp/Controllers/ClassController.php\n" +
- ":100644 000000 9a4d2344d4d0145db7c91b3f3e123c74367d4ef4 0000000000000000000000000000000000000000 D\tHttp/Controllers/ClassesController.php\n" +
- ":100644 100644 f060d6aede65d423f49e7dc248dfa0d8835ef920 b82c8e39a3602dedadb44669956d6eb5b6a7cc86 M\tHttp/Controllers/ProgramDirectorController.php\n",
- Expected: []*DiffTreeRecord{
- {
- Status: "added",
- HeadPath: "Http/Controllers/ClassController.php",
- BasePath: "Http/Controllers/ClassController.php",
- HeadMode: git.EntryModeBlob,
- BaseMode: git.EntryModeNoEntry,
- HeadBlobID: "db736b44533a840981f1f17b7029d0f612b69550",
- BaseBlobID: "0000000000000000000000000000000000000000",
- },
- {
- Status: "deleted",
- HeadPath: "Http/Controllers/ClassesController.php",
- BasePath: "Http/Controllers/ClassesController.php",
- HeadMode: git.EntryModeNoEntry,
- BaseMode: git.EntryModeBlob,
- HeadBlobID: "0000000000000000000000000000000000000000",
- BaseBlobID: "9a4d2344d4d0145db7c91b3f3e123c74367d4ef4",
- },
- {
- Status: "modified",
- HeadPath: "Http/Controllers/ProgramDirectorController.php",
- BasePath: "Http/Controllers/ProgramDirectorController.php",
- HeadMode: git.EntryModeBlob,
- BaseMode: git.EntryModeBlob,
- HeadBlobID: "b82c8e39a3602dedadb44669956d6eb5b6a7cc86",
- BaseBlobID: "f060d6aede65d423f49e7dc248dfa0d8835ef920",
- },
- },
- },
- {
- Name: "spaces in file path",
- GitOutput: ":000000 100644 0000000000000000000000000000000000000000 db736b44533a840981f1f17b7029d0f612b69550 A\tHttp /Controllers/Class Controller.php\n" +
- ":100644 000000 9a4d2344d4d0145db7c91b3f3e123c74367d4ef4 0000000000000000000000000000000000000000 D\tHttp/Cont rollers/Classes Controller.php\n" +
- ":100644 100644 f060d6aede65d423f49e7dc248dfa0d8835ef920 b82c8e39a3602dedadb44669956d6eb5b6a7cc86 R010\tHttp/Controllers/Program Director Controller.php\tHttp/Cont rollers/ProgramDirectorController.php\n",
- Expected: []*DiffTreeRecord{
- {
- Status: "added",
- HeadPath: "Http /Controllers/Class Controller.php",
- BasePath: "Http /Controllers/Class Controller.php",
- HeadMode: git.EntryModeBlob,
- BaseMode: git.EntryModeNoEntry,
- HeadBlobID: "db736b44533a840981f1f17b7029d0f612b69550",
- BaseBlobID: "0000000000000000000000000000000000000000",
- },
- {
- Status: "deleted",
- HeadPath: "Http/Cont rollers/Classes Controller.php",
- BasePath: "Http/Cont rollers/Classes Controller.php",
- HeadMode: git.EntryModeNoEntry,
- BaseMode: git.EntryModeBlob,
- HeadBlobID: "0000000000000000000000000000000000000000",
- BaseBlobID: "9a4d2344d4d0145db7c91b3f3e123c74367d4ef4",
- },
- {
- Status: "renamed",
- Score: 10,
- HeadPath: "Http/Cont rollers/ProgramDirectorController.php",
- BasePath: "Http/Controllers/Program Director Controller.php",
- HeadMode: git.EntryModeBlob,
- BaseMode: git.EntryModeBlob,
- HeadBlobID: "b82c8e39a3602dedadb44669956d6eb5b6a7cc86",
- BaseBlobID: "f060d6aede65d423f49e7dc248dfa0d8835ef920",
- },
- },
- },
- {
- Name: "file type changed",
- GitOutput: ":100644 120000 344e0ca8aa791cc4164fb0ea645f334fd40d00f0 a7c2973de00bfdc6ca51d315f401b5199fe01dc3 T\twebpack.mix.js",
- Expected: []*DiffTreeRecord{
- {
- Status: "typechanged",
- HeadPath: "webpack.mix.js",
- BasePath: "webpack.mix.js",
- HeadMode: git.EntryModeSymlink,
- BaseMode: git.EntryModeBlob,
- HeadBlobID: "a7c2973de00bfdc6ca51d315f401b5199fe01dc3",
- BaseBlobID: "344e0ca8aa791cc4164fb0ea645f334fd40d00f0",
- },
- },
- },
- }
-
- for _, tt := range test {
- t.Run(tt.Name, func(t *testing.T) {
- entries, err := parseGitDiffTree(strings.NewReader(tt.GitOutput))
- assert.NoError(t, err)
- assert.Equal(t, tt.Expected, entries)
- })
- }
- }
-
- func TestGitDiffTreeErrors(t *testing.T) {
- test := []struct {
- Name string
- RepoPath string
- BaseSha string
- HeadSha string
- }{
- {
- Name: "head doesn't exist",
- RepoPath: "../../modules/git/tests/repos/repo5_pulls",
- BaseSha: "f32b0a9dfd09a60f616f29158f772cedd89942d2",
- HeadSha: "asdfasdfasdf",
- },
- {
- Name: "base doesn't exist",
- RepoPath: "../../modules/git/tests/repos/repo5_pulls",
- BaseSha: "asdfasdfasdf",
- HeadSha: "f32b0a9dfd09a60f616f29158f772cedd89942d2",
- },
- {
- Name: "head not set",
- RepoPath: "../../modules/git/tests/repos/repo5_pulls",
- BaseSha: "f32b0a9dfd09a60f616f29158f772cedd89942d2",
- },
- }
-
- for _, tt := range test {
- t.Run(tt.Name, func(t *testing.T) {
- gitRepo, err := git.OpenRepository(t.Context(), tt.RepoPath)
- assert.NoError(t, err)
- defer gitRepo.Close()
-
- diffPaths, err := GetDiffTree(t.Context(), gitRepo, true, tt.BaseSha, tt.HeadSha)
- assert.Error(t, err)
- assert.Nil(t, diffPaths)
- })
- }
- }
|