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

     1  package git
     2  
     3  import (
     4  	"fmt"
     5  	"io/ioutil"
     6  	"os"
     7  	"testing"
     8  )
     9  
    10  type expectedStatus struct {
    11  	Long, Short, ShortBranch, PorcelainV2 string
    12  }
    13  
    14  func compareStatus(c *Client, opts StatusOptions, expected expectedStatus) error {
    15  	opts.Short = false
    16  	opts.Branch = false
    17  	opts.Porcelain = 0
    18  	opts.Long = true
    19  	s, err := Status(c, opts, nil)
    20  	if err != nil {
    21  		return fmt.Errorf("Long status: %v", err)
    22  	}
    23  	if expected.Long != s {
    24  		return fmt.Errorf("Long status: got `%v` want `%v`", s, expected.Long)
    25  	}
    26  	opts.Long = false
    27  	opts.Short = true
    28  	s, err = Status(c, opts, nil)
    29  	if err != nil {
    30  		return fmt.Errorf("Short status: %v", err)
    31  	}
    32  	if expected.Short != s {
    33  		return fmt.Errorf("Short status: got `%v` want `%v`", s, expected.Short)
    34  	}
    35  	opts.Branch = true
    36  	s, err = Status(c, opts, nil)
    37  	if err != nil {
    38  		return fmt.Errorf("Short branch status: `%v`", err)
    39  	}
    40  	if expected.ShortBranch != s {
    41  		return fmt.Errorf("Short branch status: got `%v` want `%v`", s, expected.ShortBranch)
    42  	}
    43  	return nil
    44  	/*
    45  		// Porcelain=2 isn't supported yet, so this is commented out
    46  		opts.Porcelain = 2
    47  		opts.Short = false
    48  		opts.Long = false
    49  		s, err = Status(c, opts, nil)
    50  		if err != nil {
    51  			return fmt.Errorf("Porcelain v2 status: %v", err)
    52  		}
    53  		if expected.ShortBranch != s {
    54  			return fmt.Errorf("Porcelain v2 status: got %v want %v", s, expected.PorcelainV2)
    55  		}
    56  	*/
    57  }
    58  
    59  // TestSimpleCommits tests that an initial commit works,
    60  // and that a second commit using it as a parent works.
    61  // It also tests that the second commit can be done while
    62  // in a detached head mode.
    63  func TestStatus(t *testing.T) {
    64  	if os.Getenv("SkipKnownFailures") == "true" {
    65  		fmt.Printf("Skipping known failure.\n")
    66  		return
    67  	}
    68  
    69  	dir, err := ioutil.TempDir("", "gitstatus")
    70  	if err != nil {
    71  		t.Fatal(err)
    72  	}
    73  	defer os.RemoveAll(dir)
    74  
    75  	// Init a repo to test an initial commit in.
    76  	c, err := Init(nil, InitOptions{Quiet: true}, dir)
    77  	if err != nil {
    78  		t.Fatal(err)
    79  	}
    80  	if err := os.Chdir(dir); err != nil {
    81  		t.Fatal(err)
    82  	}
    83  
    84  	if err := compareStatus(c, StatusOptions{}, expectedStatus{
    85  		Long: `On branch master
    86  
    87  No commits yet
    88  
    89  nothing to commit (create/copy files and use "git add" to track)
    90  `,
    91  		Short:       "",
    92  		ShortBranch: "## No commits yet on master\n",
    93  		PorcelainV2: `# branch.oid (initial)
    94  # branch.head master
    95  `,
    96  	}); err != nil {
    97  		t.Error(err)
    98  	}
    99  
   100  	if ioutil.WriteFile("foo.txt", []byte("foo\n"), 0644); err != nil {
   101  		t.Fatal(err)
   102  	}
   103  
   104  	if err := compareStatus(c, StatusOptions{
   105  		UntrackedMode: StatusUntrackedNormal}, expectedStatus{
   106  		Long: `On branch master
   107  
   108  No commits yet
   109  
   110  Untracked files:
   111    (use "git add <file>..." to include in what will be committed)
   112  
   113  	foo.txt
   114  
   115  nothing added to commit but untracked files present (use "git add" to track)
   116  `,
   117  		Short: "?? foo.txt\n",
   118  		ShortBranch: `## No commits yet on master
   119  ?? foo.txt
   120  `,
   121  		PorcelainV2: `# branch.oid (initial)
   122  # branch.head master
   123  ? foo.txt
   124  `,
   125  	}); err != nil {
   126  		t.Error(err)
   127  	}
   128  
   129  	if _, err := Add(c, AddOptions{}, []File{"foo.txt"}); err != nil {
   130  		t.Fatal(err)
   131  	}
   132  
   133  	if err := compareStatus(c, StatusOptions{
   134  		UntrackedMode: StatusUntrackedNormal}, expectedStatus{
   135  		Long: `On branch master
   136  
   137  No commits yet
   138  
   139  Changes to be committed:
   140    (use "git rm --cached <file>..." to unstage)
   141  
   142  	new file:	foo.txt
   143  
   144  `,
   145  		Short: "A  foo.txt\n",
   146  		ShortBranch: `## No commits yet on master
   147  A  foo.txt
   148  `,
   149  		PorcelainV2: `# branch.oid (initial)
   150  # branch.head master
   151  1 A. N... 000000 100644 100644 00000000000000000000000000000000000000 257cc5642cb1a054f08cc83f2d943e56fd3ebe99 foo.txt
   152  `,
   153  	}); err != nil {
   154  		t.Error(err)
   155  	}
   156  
   157  	if ioutil.WriteFile("foo.txt", []byte("bar\n"), 0644); err != nil {
   158  		t.Fatal(err)
   159  	}
   160  
   161  	if err := compareStatus(c, StatusOptions{
   162  		UntrackedMode: StatusUntrackedNormal}, expectedStatus{
   163  		Long: `On branch master
   164  
   165  No commits yet
   166  
   167  Changes to be committed:
   168    (use "git rm --cached <file>..." to unstage)
   169  
   170  	new file:	foo.txt
   171  
   172  Changes not staged for commit:
   173    (use "git add <file>..." to update what will be committed)
   174    (use "git checkout -- <file>..." to discard changes in working directory)
   175  
   176  	modified:	foo.txt
   177  
   178  `,
   179  		Short: "AM foo.txt\n",
   180  		ShortBranch: `## No commits yet on master
   181  AM foo.txt
   182  `,
   183  		PorcelainV2: `# branch.oid (initial)
   184  # branch.head master
   185  1 AM N... 000000 100644 100644 00000000000000000000000000000000000000 257cc5642cb1a054f08cc83f2d943e56fd3ebe99 foo.txt
   186  `,
   187  	}); err != nil {
   188  		t.Error(err)
   189  	}
   190  
   191  	initial, err := Commit(c, CommitOptions{}, "Status test", nil)
   192  	if err != nil {
   193  		t.Fatal(err)
   194  	}
   195  	if err := compareStatus(c, StatusOptions{
   196  		UntrackedMode: StatusUntrackedNormal}, expectedStatus{
   197  		Long: `On branch master
   198  Changes not staged for commit:
   199    (use "git add <file>..." to update what will be committed)
   200    (use "git checkout -- <file>..." to discard changes in working directory)
   201  
   202  	modified:	foo.txt
   203  
   204  no changes added to commit (use "git add" and/or "git commit -a")
   205  `,
   206  		Short: " M foo.txt\n",
   207  		ShortBranch: `## master
   208   M foo.txt
   209  `,
   210  		PorcelainV2: `# branch.oid (initial)
   211  # branch.head master
   212  1 .M N... 000000 100644 100644 257cc5642cb1a054f08cc83f2d943e56fd3ebe99 257cc5642cb1a054f08cc83f2d943e56fd3ebe99 foo.txt
   213  `,
   214  	}); err != nil {
   215  		t.Error(err)
   216  	}
   217  
   218  	if _, err := Add(c, AddOptions{}, []File{"foo.txt"}); err != nil {
   219  		t.Fatal(err)
   220  	}
   221  	c2, err := Commit(c, CommitOptions{}, "Status test2", nil)
   222  	if err != nil {
   223  		t.Fatal(err)
   224  	}
   225  	if err := compareStatus(c, StatusOptions{
   226  		UntrackedMode: StatusUntrackedNormal}, expectedStatus{
   227  		Long: `On branch master
   228  nothing to commit, working tree clean
   229  `,
   230  		Short: "",
   231  		ShortBranch: `## master
   232  `,
   233  		// FIXME: Need to make the commit ID deterministic
   234  		// in order for this to work.
   235  		PorcelainV2: `# branch.oid deadbeefdeadbeefdeadbeefetc
   236  # branch.head master
   237  `,
   238  	}); err != nil {
   239  		t.Error(err)
   240  	}
   241  
   242  	if err := CheckoutCommit(c, CheckoutOptions{}, initial); err != nil {
   243  		t.Fatal(err)
   244  	}
   245  
   246  	var cid string
   247  	if comm, err := initial.CommitID(c); err != nil && err != DetachedHead {
   248  		t.Fatal(err)
   249  	} else {
   250  		cid = comm.String()
   251  	}
   252  
   253  	if err := compareStatus(c, StatusOptions{
   254  		UntrackedMode: StatusUntrackedNormal}, expectedStatus{
   255  		Long: `HEAD detached at ` + cid + `
   256  nothing to commit, working tree clean
   257  `,
   258  		Short: "",
   259  		ShortBranch: `## HEAD (no branch)
   260  `,
   261  		PorcelainV2: `# branch.oid ` + cid + `
   262  # branch.head (detached)
   263  `,
   264  	}); err != nil {
   265  		t.Error(err)
   266  	}
   267  
   268  	// Make a third commit so that we can use readtree to produce a conflict.
   269  	if ioutil.WriteFile("foo.txt", []byte("baz\n"), 0644); err != nil {
   270  		t.Fatal(err)
   271  	}
   272  	if _, err := Add(c, AddOptions{}, []File{"foo.txt"}); err != nil {
   273  		t.Fatal(err)
   274  	}
   275  	c3, err := Commit(c, CommitOptions{}, "Status test3", nil)
   276  	if err != nil {
   277  		t.Fatal(err)
   278  	}
   279  	if _, err := ReadTreeThreeWay(c, ReadTreeOptions{}, initial, c2, c3); err != nil {
   280  		t.Fatal(err)
   281  	}
   282  	cid = c3.String()
   283  	if err := compareStatus(c, StatusOptions{
   284  		UntrackedMode: StatusUntrackedNormal}, expectedStatus{
   285  		Long: `HEAD detached at ` + cid + `
   286  Unmerged paths:
   287    (use "git reset HEAD <file>..." to unstage)
   288    (use "git add <file>..." to mark resolution)
   289  
   290  	both modified:	foo.txt
   291  
   292  no changes added to commit (use "git add" and/or "git commit -a")
   293  `,
   294  		Short: "UU foo.txt\n",
   295  		ShortBranch: `## HEAD (no branch)
   296  UU foo.txt
   297  `,
   298  		PorcelainV2: ``, // FIXME: Check what this should be.
   299  	}); err != nil {
   300  		t.Error(err)
   301  	}
   302  
   303  	// Finally, put some things in subdirectories and have a mixed status
   304  	// to make sure things work when we're in a subdirectory and to try
   305  	// the different untracked modes.
   306  	if ioutil.WriteFile("bar.txt", []byte("bar\n"), 0644); err != nil {
   307  		t.Fatal(err)
   308  	}
   309  	if _, err := Add(c, AddOptions{}, []File{"bar.txt"}); err != nil {
   310  		t.Fatal(err)
   311  	}
   312  	if err := ioutil.WriteFile("bar.txt", []byte("baz\n"), 0644); err != nil {
   313  		t.Fatal(err)
   314  	}
   315  	if err := os.Mkdir("baz", 0755); err != nil {
   316  		t.Fatal(err)
   317  	}
   318  	if err := os.Mkdir("baz2", 0755); err != nil {
   319  		t.Fatal(err)
   320  	}
   321  	if err := ioutil.WriteFile("baz/bar.txt", []byte("bar\n"), 0644); err != nil {
   322  		t.Fatal(err)
   323  	}
   324  	if err := ioutil.WriteFile("baz/foo.txt", []byte("bar\n"), 0644); err != nil {
   325  		t.Fatal(err)
   326  	}
   327  	if err := ioutil.WriteFile("baz2/bar.txt", []byte("bar\n"), 0644); err != nil {
   328  		t.Fatal(err)
   329  	}
   330  	if err := ioutil.WriteFile("baz2/foo.txt", []byte("bar\n"), 0644); err != nil {
   331  		t.Fatal(err)
   332  	}
   333  	if _, err := Add(c, AddOptions{}, []File{"baz/foo.txt"}); err != nil {
   334  		t.Fatal(err)
   335  	}
   336  	if err := compareStatus(c, StatusOptions{
   337  		UntrackedMode: StatusUntrackedNo}, expectedStatus{
   338  		Long: `HEAD detached at ` + cid + `
   339  Changes to be committed:
   340    (use "git reset HEAD <file>..." to unstage)
   341  
   342  	new file:	bar.txt
   343  	new file:	baz/foo.txt
   344  
   345  Unmerged paths:
   346    (use "git reset HEAD <file>..." to unstage)
   347    (use "git add <file>..." to mark resolution)
   348  
   349  	both modified:	foo.txt
   350  
   351  Changes not staged for commit:
   352    (use "git add <file>..." to update what will be committed)
   353    (use "git checkout -- <file>..." to discard changes in working directory)
   354  
   355  	modified:	bar.txt
   356  
   357  Untracked files not listed (use -u option to show untracked files)
   358  `,
   359  		Short: `AM bar.txt
   360  A  baz/foo.txt
   361  UU foo.txt
   362  `,
   363  		ShortBranch: `## HEAD (no branch)
   364  AM bar.txt
   365  A  baz/foo.txt
   366  UU foo.txt
   367  `,
   368  		PorcelainV2: ``, // FIXME: Check what this should be.
   369  	}); err != nil {
   370  		t.Error(err)
   371  	}
   372  	if os.Chdir("baz2"); err != nil {
   373  		t.Fatal(err)
   374  	}
   375  
   376  	// Try it in a subdirectory with -unormal
   377  	if err := compareStatus(c, StatusOptions{
   378  		UntrackedMode: StatusUntrackedNormal}, expectedStatus{
   379  		Long: `HEAD detached at ` + cid + `
   380  Changes to be committed:
   381    (use "git reset HEAD <file>..." to unstage)
   382  
   383  	new file:	../bar.txt
   384  	new file:	../baz/foo.txt
   385  
   386  Unmerged paths:
   387    (use "git reset HEAD <file>..." to unstage)
   388    (use "git add <file>..." to mark resolution)
   389  
   390  	both modified:	../foo.txt
   391  
   392  Changes not staged for commit:
   393    (use "git add <file>..." to update what will be committed)
   394    (use "git checkout -- <file>..." to discard changes in working directory)
   395  
   396  	modified:	../bar.txt
   397  
   398  Untracked files:
   399    (use "git add <file>..." to include in what will be committed)
   400  
   401  	../baz/bar.txt
   402  	./
   403  
   404  `,
   405  		Short: `AM ../bar.txt
   406  A  ../baz/foo.txt
   407  UU ../foo.txt
   408  ?? ../baz/bar.txt
   409  ?? ./
   410  `,
   411  		ShortBranch: `## HEAD (no branch)
   412  AM ../bar.txt
   413  A  ../baz/foo.txt
   414  UU ../foo.txt
   415  ?? ../baz/bar.txt
   416  ?? ./
   417  `,
   418  		PorcelainV2: ``, // FIXME: Check what this should be.
   419  	}); err != nil {
   420  		t.Error(err)
   421  	}
   422  
   423  	// Try the same thing with -uall
   424  	if err := compareStatus(c, StatusOptions{
   425  		UntrackedMode: StatusUntrackedAll}, expectedStatus{
   426  		Long: `HEAD detached at ` + cid + `
   427  Changes to be committed:
   428    (use "git reset HEAD <file>..." to unstage)
   429  
   430  	new file:	../bar.txt
   431  	new file:	../baz/foo.txt
   432  
   433  Unmerged paths:
   434    (use "git reset HEAD <file>..." to unstage)
   435    (use "git add <file>..." to mark resolution)
   436  
   437  	both modified:	../foo.txt
   438  
   439  Changes not staged for commit:
   440    (use "git add <file>..." to update what will be committed)
   441    (use "git checkout -- <file>..." to discard changes in working directory)
   442  
   443  	modified:	../bar.txt
   444  
   445  Untracked files:
   446    (use "git add <file>..." to include in what will be committed)
   447  
   448  	../baz/bar.txt
   449  	bar.txt
   450  	foo.txt
   451  
   452  `,
   453  		Short: `AM ../bar.txt
   454  A  ../baz/foo.txt
   455  UU ../foo.txt
   456  ?? ../baz/bar.txt
   457  ?? bar.txt
   458  ?? foo.txt
   459  `,
   460  		ShortBranch: `## HEAD (no branch)
   461  AM ../bar.txt
   462  A  ../baz/foo.txt
   463  UU ../foo.txt
   464  ?? ../baz/bar.txt
   465  ?? bar.txt
   466  ?? foo.txt
   467  `,
   468  		PorcelainV2: ``, // FIXME: Check what this should be.
   469  	}); err != nil {
   470  		t.Error(err)
   471  	}
   472  }