github.com/driusan/dgit@v0.0.0-20221118233547-f39f0c15edbb/git/writetree_test.go (about)

     1  package git
     2  
     3  import (
     4  	"io/ioutil"
     5  	"os"
     6  	"strings"
     7  	"testing"
     8  )
     9  
    10  func unsafeSha1FromString(str string) Sha1 {
    11  	s, err := Sha1FromString(str)
    12  	if err != nil {
    13  		panic(err)
    14  	}
    15  	return s
    16  }
    17  func hashString(str string) Sha1 {
    18  	s, _, err := HashReader("blob", strings.NewReader(str))
    19  	if err != nil {
    20  		panic(err)
    21  	}
    22  	return s
    23  }
    24  
    25  func TestWriteIndex(t *testing.T) {
    26  	testcases := []struct {
    27  		IndexObjects []*IndexEntry
    28  		Sha1         string
    29  		ExpectError  bool
    30  		Prefix       string
    31  	}{
    32  		{
    33  			nil,
    34  			// An empty tree hashes to this, not 0 (even with the official git client), because
    35  			// of the type prefix in the blob.
    36  			"4b825dc642cb6eb9a060e54bf8d69288fbee4904",
    37  			false,
    38  			"",
    39  		},
    40  		// Simple case, a single file
    41  		{
    42  			[]*IndexEntry{&IndexEntry{
    43  				PathName: IndexPath("foo"),
    44  				FixedIndexEntry: FixedIndexEntry{
    45  					Mode:  ModeBlob,
    46  					Fsize: 4,
    47  					Sha1:  hashString("bar\n"),
    48  				},
    49  			},
    50  			},
    51  			"6a09c59ce8eb1b5b4f89450103e67ff9b3a3b1ae",
    52  			false,
    53  			"",
    54  		},
    55  		// Same as case 1, but with the executable bit set.
    56  		{
    57  			[]*IndexEntry{&IndexEntry{
    58  				PathName: IndexPath("foo"),
    59  				FixedIndexEntry: FixedIndexEntry{
    60  					Mode:  ModeExec,
    61  					Fsize: 4,
    62  					Sha1:  hashString("bar\n"),
    63  				},
    64  			},
    65  			},
    66  			"e10d3585c7b4bec6b573e40d6a0c097a7e790abe",
    67  			false,
    68  			"",
    69  		},
    70  		// A symlink from bar to foo.
    71  		{
    72  			[]*IndexEntry{&IndexEntry{
    73  				PathName: IndexPath("bar"),
    74  				FixedIndexEntry: FixedIndexEntry{
    75  					Mode:  ModeSymlink,
    76  					Fsize: 3,
    77  					Sha1:  hashString("foo"),
    78  				},
    79  			},
    80  			},
    81  			"985badfa7a966612b9f9adadbaa6a30aa3e0b1f5",
    82  			false,
    83  			"",
    84  		},
    85  		// Simple case, two files
    86  		{
    87  			[]*IndexEntry{
    88  				&IndexEntry{
    89  					PathName: IndexPath("bar"),
    90  					FixedIndexEntry: FixedIndexEntry{
    91  						Mode:  ModeBlob,
    92  						Fsize: 4,
    93  						Sha1:  hashString("bar\n"),
    94  					},
    95  				},
    96  				&IndexEntry{
    97  					PathName: IndexPath("foo"),
    98  					FixedIndexEntry: FixedIndexEntry{
    99  						Mode:  ModeBlob,
   100  						Fsize: 4,
   101  						Sha1:  hashString("foo\n"),
   102  					},
   103  				},
   104  			},
   105  			"89ff1a2aefcbff0f09197f0fd8beeb19a7b6e51c",
   106  			false,
   107  			"",
   108  		},
   109  		// A single file in a subdirectory
   110  		{
   111  			[]*IndexEntry{&IndexEntry{
   112  				PathName: IndexPath("foo/bar"),
   113  				FixedIndexEntry: FixedIndexEntry{
   114  					Mode:  ModeBlob,
   115  					Fsize: 4,
   116  					Sha1:  hashString("bar\n"),
   117  				},
   118  			},
   119  			},
   120  			"7b74f9ae4e4f7232e386fd8bcb9a240e6713fadf",
   121  			false,
   122  			"",
   123  		},
   124  		// Two files in a subdirectory
   125  		{
   126  			[]*IndexEntry{
   127  				&IndexEntry{
   128  					PathName: IndexPath("foo/bar"),
   129  					FixedIndexEntry: FixedIndexEntry{
   130  						Mode:  ModeBlob,
   131  						Fsize: 4,
   132  						Sha1:  hashString("bar\n"),
   133  					},
   134  				},
   135  				&IndexEntry{
   136  					PathName: IndexPath("foo/foo"),
   137  					FixedIndexEntry: FixedIndexEntry{
   138  						Mode:  ModeBlob,
   139  						Fsize: 4,
   140  						Sha1:  hashString("foo\n"),
   141  					},
   142  				},
   143  			},
   144  			"e3331a4b901802f18658544c4ae320de93ab14ef",
   145  			false,
   146  			"",
   147  		},
   148  		// Both a file and a subtree
   149  		{
   150  			[]*IndexEntry{
   151  				&IndexEntry{
   152  					PathName: IndexPath("bar"),
   153  					FixedIndexEntry: FixedIndexEntry{
   154  						Mode:  ModeBlob,
   155  						Fsize: 4,
   156  						Sha1:  hashString("bar\n"),
   157  					},
   158  				},
   159  				&IndexEntry{
   160  					PathName: IndexPath("foo/foo"),
   161  					FixedIndexEntry: FixedIndexEntry{
   162  						Mode:  ModeBlob,
   163  						Fsize: 4,
   164  						Sha1:  hashString("foo\n"),
   165  					},
   166  				},
   167  			},
   168  			"17278814743a70ed99aca0271ecdf5b544f10e5b",
   169  			false,
   170  			"",
   171  		},
   172  		// A file and a subtree with multiple entries
   173  		{
   174  			[]*IndexEntry{
   175  				&IndexEntry{
   176  					PathName: IndexPath("bar"),
   177  					FixedIndexEntry: FixedIndexEntry{
   178  						Mode:  ModeBlob,
   179  						Fsize: 4,
   180  						Sha1:  hashString("bar\n"),
   181  					},
   182  				},
   183  				&IndexEntry{
   184  					PathName: IndexPath("foo/bar"),
   185  					FixedIndexEntry: FixedIndexEntry{
   186  						Mode:  ModeBlob,
   187  						Fsize: 4,
   188  						Sha1:  hashString("bar\n"),
   189  					},
   190  				},
   191  				&IndexEntry{
   192  					PathName: IndexPath("foo/foo"),
   193  					FixedIndexEntry: FixedIndexEntry{
   194  						Mode:  ModeBlob,
   195  						Fsize: 4,
   196  						Sha1:  hashString("foo\n"),
   197  					},
   198  				},
   199  			},
   200  			"18473c7faa0d4bb4913fd41a6768dbcf5fa70723",
   201  			false,
   202  			"",
   203  		},
   204  		// A deep subtree
   205  		{
   206  			[]*IndexEntry{
   207  				&IndexEntry{
   208  					PathName: IndexPath("foo/bar/baz"),
   209  					FixedIndexEntry: FixedIndexEntry{
   210  						Mode:  ModeBlob,
   211  						Fsize: 4,
   212  						Sha1:  hashString("baz\n"),
   213  					},
   214  				},
   215  			},
   216  			"cc1846d0911b1790fd15859ffdf48598cb46b7b0",
   217  			false,
   218  			"",
   219  		},
   220  		// Two different subtrees
   221  		{
   222  			[]*IndexEntry{
   223  				&IndexEntry{
   224  					PathName: IndexPath("bar/bar"),
   225  					FixedIndexEntry: FixedIndexEntry{
   226  						Mode:  ModeBlob,
   227  						Fsize: 4,
   228  						Sha1:  hashString("bar\n"),
   229  					},
   230  				},
   231  				&IndexEntry{
   232  					PathName: IndexPath("foo/foo"),
   233  					FixedIndexEntry: FixedIndexEntry{
   234  						Mode:  ModeBlob,
   235  						Fsize: 4,
   236  						Sha1:  hashString("foo\n"),
   237  					},
   238  				},
   239  			},
   240  			"65de833961e3dc313b13a2cf0a35a3bab772fc0b",
   241  			false,
   242  			"",
   243  		},
   244  		// Tree followed by a file.
   245  		{
   246  			[]*IndexEntry{
   247  				&IndexEntry{
   248  					PathName: IndexPath("bar/bar"),
   249  					FixedIndexEntry: FixedIndexEntry{
   250  						Mode:  ModeBlob,
   251  						Fsize: 4,
   252  						Sha1:  hashString("bar\n"),
   253  					},
   254  				},
   255  				&IndexEntry{
   256  					PathName: IndexPath("foo"),
   257  					FixedIndexEntry: FixedIndexEntry{
   258  						Mode:  ModeBlob,
   259  						Fsize: 4,
   260  						Sha1:  hashString("foo\n"),
   261  					},
   262  				},
   263  			},
   264  			"615b1bd6b48087f25d16cc78279ea48ce5b1b59d",
   265  			false,
   266  			"",
   267  		},
   268  		{
   269  			[]*IndexEntry{
   270  				&IndexEntry{
   271  					PathName: IndexPath("bar/bar"),
   272  					FixedIndexEntry: FixedIndexEntry{
   273  						Mode:  ModeBlob,
   274  						Fsize: 4,
   275  						Sha1:  hashString("bar\n"),
   276  					},
   277  				},
   278  				&IndexEntry{
   279  					PathName: IndexPath("baz/baz"),
   280  					FixedIndexEntry: FixedIndexEntry{
   281  						Mode:  ModeBlob,
   282  						Fsize: 4,
   283  						Sha1:  hashString("baz\n"),
   284  					},
   285  				},
   286  				&IndexEntry{
   287  					PathName: IndexPath("foo/foo"),
   288  					FixedIndexEntry: FixedIndexEntry{
   289  						Mode:  ModeBlob,
   290  						Fsize: 4,
   291  						Sha1:  hashString("foo\n"),
   292  					},
   293  				},
   294  			},
   295  			"8b9f58ced67de613a7570726233ec83fa56a3d52",
   296  			false,
   297  			"",
   298  		},
   299  		// A file sandwiched between 2 trees
   300  		{
   301  			[]*IndexEntry{
   302  				&IndexEntry{
   303  					PathName: IndexPath("bar/bar"),
   304  					FixedIndexEntry: FixedIndexEntry{
   305  						Mode:  ModeBlob,
   306  						Fsize: 4,
   307  						Sha1:  hashString("bar\n"),
   308  					},
   309  				},
   310  				&IndexEntry{
   311  					PathName: IndexPath("baz"),
   312  					FixedIndexEntry: FixedIndexEntry{
   313  						Mode:  ModeBlob,
   314  						Fsize: 4,
   315  						Sha1:  hashString("baz\n"),
   316  					},
   317  				},
   318  				&IndexEntry{
   319  					PathName: IndexPath("foo/foo"),
   320  					FixedIndexEntry: FixedIndexEntry{
   321  						Mode:  ModeBlob,
   322  						Fsize: 4,
   323  						Sha1:  hashString("foo\n"),
   324  					},
   325  				},
   326  			},
   327  			"18a6e5a95bb59e96dba722025de6abc692661bb6",
   328  			false,
   329  			"",
   330  		},
   331  		// An index with any non-stage0 entry should produce an error
   332  		{
   333  			[]*IndexEntry{
   334  				&IndexEntry{
   335  					PathName: IndexPath("foo"),
   336  					FixedIndexEntry: FixedIndexEntry{
   337  						Mode:  ModeBlob,
   338  						Fsize: 4,
   339  						Sha1:  hashString("bar\n"),
   340  						Flags: uint16(Stage1) << 12,
   341  					},
   342  				},
   343  			},
   344  			"",
   345  			true,
   346  			"",
   347  		},
   348  		{
   349  			[]*IndexEntry{
   350  				&IndexEntry{
   351  					PathName: IndexPath("foo"),
   352  					FixedIndexEntry: FixedIndexEntry{
   353  						Mode:  ModeBlob,
   354  						Fsize: 4,
   355  						Sha1:  hashString("bar\n"),
   356  						Flags: uint16(Stage2) << 12,
   357  					},
   358  				},
   359  			},
   360  			"",
   361  			true,
   362  			"",
   363  		},
   364  		{
   365  			[]*IndexEntry{
   366  				&IndexEntry{
   367  					PathName: IndexPath("foo"),
   368  					FixedIndexEntry: FixedIndexEntry{
   369  						Mode:  ModeBlob,
   370  						Fsize: 4,
   371  						Sha1:  hashString("bar\n"),
   372  						Flags: uint16(Stage3) << 12,
   373  					},
   374  				},
   375  			},
   376  			"",
   377  			true,
   378  			"",
   379  		},
   380  		{
   381  			// Regression from the official git test suite. This was causing
   382  			// an infinite loop in dgit when called with a prefix of path3/
   383  			// First we check that it matches without the prefix, then we check that
   384  			// it matches with the prefix.
   385  			[]*IndexEntry{
   386  				&IndexEntry{
   387  					PathName: IndexPath("path0"),
   388  					FixedIndexEntry: FixedIndexEntry{
   389  						Mode:  ModeBlob,
   390  						Fsize: 12,
   391  						Sha1:  unsafeSha1FromString("f87290f8eb2cbbea7857214459a0739927eab154"),
   392  					},
   393  				},
   394  				&IndexEntry{
   395  					PathName: IndexPath("path2/file2"),
   396  					FixedIndexEntry: FixedIndexEntry{
   397  						Mode:  ModeBlob,
   398  						Fsize: 18,
   399  						Sha1:  unsafeSha1FromString("3feff949ed00a62d9f7af97c15cd8a30595e7ac7"),
   400  					},
   401  				},
   402  				&IndexEntry{
   403  					PathName: IndexPath("path3/file3"),
   404  					FixedIndexEntry: FixedIndexEntry{
   405  						Mode:  ModeBlob,
   406  						Fsize: 18,
   407  						Sha1:  unsafeSha1FromString("0aa34cae68d0878578ad119c86ca2b5ed5b28376"),
   408  					},
   409  				},
   410  				&IndexEntry{
   411  					PathName: IndexPath("path3/subp3/file3"),
   412  					FixedIndexEntry: FixedIndexEntry{
   413  						Mode:  ModeBlob,
   414  						Fsize: 24,
   415  						Sha1:  unsafeSha1FromString("00fb5908cb97c2564a9783c0c64087333b3b464f"),
   416  					},
   417  				},
   418  			},
   419  			"8e18edf7d7edcf4371a3ac6ae5f07c2641db7c46",
   420  			false,
   421  			"",
   422  		},
   423  		{
   424  			// same as above, with a prefix of "path3".
   425  			[]*IndexEntry{
   426  				&IndexEntry{
   427  					PathName: IndexPath("path0"),
   428  					FixedIndexEntry: FixedIndexEntry{
   429  						Mode:  ModeBlob,
   430  						Fsize: 12,
   431  						Sha1:  unsafeSha1FromString("f87290f8eb2cbbea7857214459a0739927eab154"),
   432  					},
   433  				},
   434  				&IndexEntry{
   435  					PathName: IndexPath("path2/file2"),
   436  					FixedIndexEntry: FixedIndexEntry{
   437  						Mode:  ModeBlob,
   438  						Fsize: 18,
   439  						Sha1:  unsafeSha1FromString("3feff949ed00a62d9f7af97c15cd8a30595e7ac7"),
   440  					},
   441  				},
   442  				&IndexEntry{
   443  					PathName: IndexPath("path3/file3"),
   444  					FixedIndexEntry: FixedIndexEntry{
   445  						Mode:  ModeBlob,
   446  						Fsize: 18,
   447  						Sha1:  unsafeSha1FromString("0aa34cae68d0878578ad119c86ca2b5ed5b28376"),
   448  					},
   449  				},
   450  				&IndexEntry{
   451  					PathName: IndexPath("path3/subp3/file3"),
   452  					FixedIndexEntry: FixedIndexEntry{
   453  						Mode:  ModeBlob,
   454  						Fsize: 24,
   455  						Sha1:  unsafeSha1FromString("00fb5908cb97c2564a9783c0c64087333b3b464f"),
   456  					},
   457  				},
   458  			},
   459  			"cfb8591b2f65de8b8cc1020cd7d9e67e7793b325",
   460  			false,
   461  			"path3",
   462  		},
   463  	}
   464  
   465  	gitdir, err := ioutil.TempDir("", "gitwriteindex")
   466  	if err != nil {
   467  		t.Fatal(err)
   468  	}
   469  	defer os.RemoveAll(gitdir)
   470  
   471  	c, err := Init(nil, InitOptions{Quiet: true}, gitdir)
   472  	if err != nil {
   473  		t.Fatal(err)
   474  	}
   475  
   476  	for i, tc := range testcases {
   477  		treeid, err := writeTree(c, tc.Prefix, tc.IndexObjects)
   478  		if err != nil {
   479  			if !tc.ExpectError {
   480  				t.Error(err)
   481  			}
   482  			continue
   483  		}
   484  		if tc.ExpectError && err == nil {
   485  			t.Errorf("Case %d: Expected error, got none", i)
   486  			continue
   487  		}
   488  
   489  		expected, err := Sha1FromString(tc.Sha1)
   490  		if err != nil {
   491  			t.Fatal(err)
   492  		}
   493  		if treeid != TreeID(expected) {
   494  			t.Errorf("Unexpected hash for test case %d: got %v want %v", i, treeid, expected)
   495  		}
   496  	}
   497  }