github.com/x-motemen/ghq@v1.6.1/vcs_test.go (about)

     1  package main
     2  
     3  import (
     4  	"fmt"
     5  	"os"
     6  	"os/exec"
     7  	"path/filepath"
     8  	"reflect"
     9  	"testing"
    10  
    11  	"github.com/x-motemen/ghq/cmdutil"
    12  )
    13  
    14  var (
    15  	remoteDummyURL = mustParseURL("https://example.com/git/repo")
    16  	dummySvnInfo   = []byte(`Path: trunk
    17  URL: https://svn.apache.org/repos/asf/subversion/trunk
    18  Relative URL: ^/subversion/trunk
    19  Repository Root: https://svn.apache.org/repos/asf
    20  Repository UUID: 13f79535-47bb-0310-9956-ffa450edef68
    21  Revision: 1872085
    22  Node Kind: directory
    23  Last Changed Author: julianfoad
    24  Last Changed Rev: 1872031
    25  Last Changed Date: 2019-08-16 15:16:45 +0900 (Fri, 16 Aug 2019)
    26  `)
    27  )
    28  
    29  func TestVCSBackend(t *testing.T) {
    30  	tempDir := newTempDir(t)
    31  	localDir := filepath.Join(tempDir, "repo")
    32  	var _commands []*exec.Cmd
    33  	lastCommand := func() *exec.Cmd { return _commands[len(_commands)-1] }
    34  	defer func(orig func(cmd *exec.Cmd) error) {
    35  		cmdutil.CommandRunner = orig
    36  	}(cmdutil.CommandRunner)
    37  	cmdutil.CommandRunner = func(cmd *exec.Cmd) error {
    38  		_commands = append(_commands, cmd)
    39  		if reflect.DeepEqual(cmd.Args, []string{"svn", "info", "https://example.com/git/repo/trunk"}) {
    40  			return fmt.Errorf("[test] failed to svn info")
    41  		}
    42  		return nil
    43  	}
    44  
    45  	testCases := []struct {
    46  		name   string
    47  		f      func() error
    48  		expect []string
    49  		dir    string
    50  	}{{
    51  		name: "[git] clone",
    52  		f: func() error {
    53  			return GitBackend.Clone(&vcsGetOption{
    54  				url: remoteDummyURL,
    55  				dir: localDir,
    56  			})
    57  		},
    58  		expect: []string{"git", "clone", remoteDummyURL.String(), localDir},
    59  	}, {
    60  		name: "[git] shallow clone",
    61  		f: func() error {
    62  			return GitBackend.Clone(&vcsGetOption{
    63  				url:     remoteDummyURL,
    64  				dir:     localDir,
    65  				shallow: true,
    66  				silent:  true,
    67  			})
    68  		},
    69  		expect: []string{"git", "clone", "--depth", "1", remoteDummyURL.String(), localDir},
    70  	}, {
    71  		name: "[git] clone specific branch",
    72  		f: func() error {
    73  			return GitBackend.Clone(&vcsGetOption{
    74  				url:    remoteDummyURL,
    75  				dir:    localDir,
    76  				branch: "hello",
    77  			})
    78  		},
    79  		expect: []string{"git", "clone", "--branch", "hello", "--single-branch", remoteDummyURL.String(), localDir},
    80  	}, {
    81  		name: "[git] update",
    82  		f: func() error {
    83  			return GitBackend.Update(&vcsGetOption{
    84  				dir: localDir,
    85  			})
    86  		},
    87  		expect: []string{"git", "pull", "--ff-only"},
    88  		dir:    localDir,
    89  	}, {
    90  		name: "[git] fetch",
    91  		f: func() error {
    92  			defer func(orig func(cmd *exec.Cmd) error) {
    93  				cmdutil.CommandRunner = orig
    94  			}(cmdutil.CommandRunner)
    95  			cmdutil.CommandRunner = func(cmd *exec.Cmd) error {
    96  				_commands = append(_commands, cmd)
    97  				if reflect.DeepEqual(cmd.Args, []string{"git", "rev-parse", "@{upstream}"}) {
    98  					return fmt.Errorf("[test] failed to git rev-parse @{upstream}")
    99  				}
   100  				return nil
   101  			}
   102  			return GitBackend.Update(&vcsGetOption{
   103  				dir: localDir,
   104  			})
   105  		},
   106  		expect: []string{"git", "fetch"},
   107  		dir:    localDir,
   108  	}, {
   109  		name: "[git] recursive",
   110  		f: func() error {
   111  			return GitBackend.Clone(&vcsGetOption{
   112  				url:       remoteDummyURL,
   113  				dir:       localDir,
   114  				recursive: true,
   115  			})
   116  		},
   117  		expect: []string{"git", "clone", "--recursive", remoteDummyURL.String(), localDir},
   118  	}, {
   119  		name: "[git] update recursive",
   120  		f: func() error {
   121  			return GitBackend.Update(&vcsGetOption{
   122  				dir:       localDir,
   123  				recursive: true,
   124  			})
   125  		},
   126  		expect: []string{"git", "submodule", "update", "--init", "--recursive"},
   127  		dir:    localDir,
   128  	}, {
   129  		name: "[git] bare clone",
   130  		f: func() error {
   131  			return GitBackend.Clone(&vcsGetOption{
   132  				url:    remoteDummyURL,
   133  				dir:    localDir,
   134  				bare:   true,
   135  				silent: true,
   136  			})
   137  		},
   138  		expect: []string{"git", "clone", "--bare", remoteDummyURL.String(), localDir},
   139  	}, {
   140  		name: "[git] switch git-svn on update",
   141  		f: func() error {
   142  			err := os.MkdirAll(filepath.Join(localDir, ".git", "svn"), 0755)
   143  			if err != nil {
   144  				return err
   145  			}
   146  			defer os.RemoveAll(filepath.Join(localDir, ".git"))
   147  			return GitBackend.Update(&vcsGetOption{
   148  				dir: localDir,
   149  			})
   150  		},
   151  		expect: []string{"git", "svn", "rebase"},
   152  		dir:    localDir,
   153  	}, {
   154  		name: "[svn] checkout",
   155  		f: func() error {
   156  			return SubversionBackend.Clone(&vcsGetOption{
   157  				url: remoteDummyURL,
   158  				dir: localDir,
   159  			})
   160  		},
   161  		expect: []string{"svn", "checkout", remoteDummyURL.String(), localDir},
   162  	}, {
   163  		name: "[svn] checkout shallow",
   164  		f: func() error {
   165  			return SubversionBackend.Clone(&vcsGetOption{
   166  				url:     remoteDummyURL,
   167  				dir:     localDir,
   168  				shallow: true,
   169  			})
   170  		},
   171  		expect: []string{"svn", "checkout", "--depth", "immediates", remoteDummyURL.String(), localDir},
   172  	}, {
   173  		name: "[svn] checkout specific branch",
   174  		f: func() error {
   175  			return SubversionBackend.Clone(&vcsGetOption{
   176  				url:    remoteDummyURL,
   177  				dir:    localDir,
   178  				branch: "hello",
   179  			})
   180  		},
   181  		expect: []string{"svn", "checkout", remoteDummyURL.String() + "/branches/hello", localDir},
   182  	}, {
   183  		name: "[svn] checkout with filling trunk",
   184  		f: func() error {
   185  			defer func(orig func(cmd *exec.Cmd) error) {
   186  				cmdutil.CommandRunner = orig
   187  			}(cmdutil.CommandRunner)
   188  			cmdutil.CommandRunner = func(cmd *exec.Cmd) error {
   189  				_commands = append(_commands, cmd)
   190  				if reflect.DeepEqual(cmd.Args, []string{"svn", "info", "https://example.com/git/repo/trunk"}) {
   191  					cmd.Stdout.Write(dummySvnInfo)
   192  				}
   193  				return nil
   194  			}
   195  			return SubversionBackend.Clone(&vcsGetOption{
   196  				url: remoteDummyURL,
   197  				dir: localDir,
   198  			})
   199  		},
   200  		expect: []string{"svn", "checkout", remoteDummyURL.String() + "/trunk", localDir},
   201  	}, {
   202  		name: "[svn] update",
   203  		f: func() error {
   204  			return SubversionBackend.Update(&vcsGetOption{
   205  				dir:    localDir,
   206  				silent: true,
   207  			})
   208  		},
   209  		expect: []string{"svn", "update"},
   210  		dir:    localDir,
   211  	}, {
   212  		name: "[git-svn] clone",
   213  		f: func() error {
   214  			return GitsvnBackend.Clone(&vcsGetOption{
   215  				url: remoteDummyURL,
   216  				dir: localDir,
   217  			})
   218  		},
   219  		expect: []string{"git", "svn", "clone", remoteDummyURL.String(), localDir},
   220  	}, {
   221  		name: "[git-svn] update",
   222  		f: func() error {
   223  			return GitsvnBackend.Update(&vcsGetOption{
   224  				dir: localDir,
   225  			})
   226  		},
   227  		expect: []string{"git", "svn", "rebase"},
   228  		dir:    localDir,
   229  	}, {
   230  		name: "[git-svn] clone shallow",
   231  		f: func() error {
   232  			defer func(orig func(cmd *exec.Cmd) error) {
   233  				cmdutil.CommandRunner = orig
   234  			}(cmdutil.CommandRunner)
   235  			cmdutil.CommandRunner = func(cmd *exec.Cmd) error {
   236  				_commands = append(_commands, cmd)
   237  				if reflect.DeepEqual(cmd.Args, []string{"svn", "info", "https://example.com/git/repo/trunk"}) {
   238  					cmd.Stdout.Write(dummySvnInfo)
   239  				}
   240  				return nil
   241  			}
   242  			return GitsvnBackend.Clone(&vcsGetOption{
   243  				url:     remoteDummyURL,
   244  				dir:     localDir,
   245  				shallow: true,
   246  			})
   247  		},
   248  		expect: []string{"git", "svn", "clone", "-s", "-r1872031:HEAD", remoteDummyURL.String(), localDir},
   249  	}, {
   250  		name: "[git-svn] clone specific branch",
   251  		f: func() error {
   252  			return GitsvnBackend.Clone(&vcsGetOption{
   253  				url:    remoteDummyURL,
   254  				dir:    localDir,
   255  				branch: "hello",
   256  			})
   257  		},
   258  		expect: []string{"git", "svn", "clone", remoteDummyURL.String() + "/branches/hello", localDir},
   259  	}, {
   260  		name: "[git-svn] clone specific branch from tagged URL with shallow",
   261  		f: func() error {
   262  			defer func(orig func(cmd *exec.Cmd) error) {
   263  				cmdutil.CommandRunner = orig
   264  			}(cmdutil.CommandRunner)
   265  			cmdutil.CommandRunner = func(cmd *exec.Cmd) error {
   266  				_commands = append(_commands, cmd)
   267  				if reflect.DeepEqual(
   268  					cmd.Args, []string{"svn", "info", "https://example.com/git/repo/branches/develop"},
   269  				) {
   270  					cmd.Stdout.Write(dummySvnInfo)
   271  				}
   272  				return nil
   273  			}
   274  			copied := *remoteDummyURL
   275  			copied.Path += "/tags/v9.9.9"
   276  			return GitsvnBackend.Clone(&vcsGetOption{
   277  				url:     &copied,
   278  				dir:     localDir,
   279  				branch:  "develop",
   280  				shallow: true,
   281  			})
   282  		},
   283  		expect: []string{
   284  			"git", "svn", "clone", "-r1872031:HEAD", remoteDummyURL.String() + "/branches/develop", localDir},
   285  	}, {
   286  		name: "[hg] clone",
   287  		f: func() error {
   288  			return MercurialBackend.Clone(&vcsGetOption{
   289  				url: remoteDummyURL,
   290  				dir: localDir,
   291  			})
   292  		},
   293  		expect: []string{"hg", "clone", remoteDummyURL.String(), localDir},
   294  	}, {
   295  		name: "[hg] update",
   296  		f: func() error {
   297  			return MercurialBackend.Update(&vcsGetOption{
   298  				dir: localDir,
   299  			})
   300  		},
   301  		expect: []string{"hg", "pull", "--update"},
   302  		dir:    localDir,
   303  	}, {
   304  		name: "[hg] clone shallow",
   305  		f: func() error {
   306  			return MercurialBackend.Clone(&vcsGetOption{
   307  				url:     remoteDummyURL,
   308  				dir:     localDir,
   309  				shallow: true,
   310  			})
   311  		},
   312  		expect: []string{"hg", "clone", remoteDummyURL.String(), localDir},
   313  	}, {
   314  		name: "[hg] clone specific branch",
   315  		f: func() error {
   316  			return MercurialBackend.Clone(&vcsGetOption{
   317  				url:    remoteDummyURL,
   318  				dir:    localDir,
   319  				branch: "hello",
   320  			})
   321  		},
   322  		expect: []string{"hg", "clone", "--branch", "hello", remoteDummyURL.String(), localDir},
   323  	}, {
   324  		name: "[darcs] clone",
   325  		f: func() error {
   326  			return DarcsBackend.Clone(&vcsGetOption{
   327  				url: remoteDummyURL,
   328  				dir: localDir,
   329  			})
   330  		},
   331  		expect: []string{"darcs", "get", remoteDummyURL.String(), localDir},
   332  	}, {
   333  		name: "[darcs] clone shallow",
   334  		f: func() error {
   335  			return DarcsBackend.Clone(&vcsGetOption{
   336  				url:     remoteDummyURL,
   337  				dir:     localDir,
   338  				shallow: true,
   339  			})
   340  		},
   341  		expect: []string{"darcs", "get", "--lazy", remoteDummyURL.String(), localDir},
   342  	}, {
   343  		name: "[darcs] update",
   344  		f: func() error {
   345  			return DarcsBackend.Update(&vcsGetOption{
   346  				dir: localDir,
   347  			})
   348  		},
   349  		expect: []string{"darcs", "pull"},
   350  		dir:    localDir,
   351  	}, {
   352  		name: "[pijul] clone",
   353  		f: func() error {
   354  			return PijulBackend.Clone(&vcsGetOption{
   355  				url: remoteDummyURL,
   356  				dir: localDir,
   357  			})
   358  		},
   359  		expect: []string{"pijul", "clone", remoteDummyURL.String(), localDir},
   360  	}, {
   361  		name: "[pijul] update",
   362  		f: func() error {
   363  			return PijulBackend.Update(&vcsGetOption{
   364  				dir: localDir,
   365  			})
   366  		},
   367  		expect: []string{"pijul", "pull"},
   368  		dir:    localDir,
   369  	}, {
   370  		name: "[bzr] clone",
   371  		f: func() error {
   372  			return BazaarBackend.Clone(&vcsGetOption{
   373  				url: remoteDummyURL,
   374  				dir: localDir,
   375  			})
   376  		},
   377  		expect: []string{"bzr", "branch", remoteDummyURL.String(), localDir},
   378  	}, {
   379  		name: "[bzr] update",
   380  		f: func() error {
   381  			return BazaarBackend.Update(&vcsGetOption{
   382  				dir: localDir,
   383  			})
   384  		},
   385  		expect: []string{"bzr", "pull", "--overwrite"},
   386  		dir:    localDir,
   387  	}, {
   388  		name: "[bzr] clone shallow",
   389  		f: func() error {
   390  			return BazaarBackend.Clone(&vcsGetOption{
   391  				url:     remoteDummyURL,
   392  				dir:     localDir,
   393  				shallow: true,
   394  			})
   395  		},
   396  		expect: []string{"bzr", "branch", remoteDummyURL.String(), localDir},
   397  	}, {
   398  		name: "[fossil] clone",
   399  		f: func() error {
   400  			return FossilBackend.Clone(&vcsGetOption{
   401  				url: remoteDummyURL,
   402  				dir: localDir,
   403  			})
   404  		},
   405  		expect: []string{"fossil", "open", fossilRepoName},
   406  		dir:    localDir,
   407  	}, {
   408  		name: "[fossil] update",
   409  		f: func() error {
   410  			return FossilBackend.Update(&vcsGetOption{
   411  				dir: localDir,
   412  			})
   413  		},
   414  		expect: []string{"fossil", "update"},
   415  		dir:    localDir,
   416  	}}
   417  
   418  	for _, tc := range testCases {
   419  		t.Run(tc.name, func(t *testing.T) {
   420  			if err := tc.f(); err != nil {
   421  				t.Errorf("error should be nil, but: %s", err)
   422  			}
   423  			c := lastCommand()
   424  			if !reflect.DeepEqual(c.Args, tc.expect) {
   425  				t.Errorf("\ngot:    %+v\nexpect: %+v", c.Args, tc.expect)
   426  			}
   427  			if c.Dir != tc.dir {
   428  				t.Errorf("got: %s, expect: %s", c.Dir, tc.dir)
   429  			}
   430  		})
   431  	}
   432  }
   433  
   434  func TestCvsDummyBackend(t *testing.T) {
   435  	tempDir := newTempDir(t)
   436  	localDir := filepath.Join(tempDir, "repo")
   437  
   438  	if err := cvsDummyBackend.Clone(&vcsGetOption{
   439  		url: remoteDummyURL,
   440  		dir: localDir,
   441  	}); err == nil {
   442  		t.Error("error should be occurred, but nil")
   443  	}
   444  
   445  	if err := cvsDummyBackend.Clone(&vcsGetOption{
   446  		url:     remoteDummyURL,
   447  		dir:     localDir,
   448  		shallow: true,
   449  	}); err == nil {
   450  		t.Error("error should be occurred, but nil")
   451  	}
   452  
   453  	if err := cvsDummyBackend.Update(&vcsGetOption{
   454  		dir: localDir,
   455  	}); err == nil {
   456  		t.Error("error should be occurred, but nil")
   457  	}
   458  }
   459  
   460  func TestBranchOptionIgnoredErrors(t *testing.T) {
   461  	tempDir := newTempDir(t)
   462  	localDir := filepath.Join(tempDir, "repo")
   463  
   464  	if err := DarcsBackend.Clone(&vcsGetOption{
   465  		url:    remoteDummyURL,
   466  		dir:    localDir,
   467  		branch: "hello",
   468  	}); err == nil {
   469  		t.Error("error should be occurred, but nil")
   470  	}
   471  
   472  	if err := FossilBackend.Clone(&vcsGetOption{
   473  		url:    remoteDummyURL,
   474  		dir:    localDir,
   475  		branch: "hello",
   476  	}); err == nil {
   477  		t.Error("error should be occurred, but nil")
   478  	}
   479  
   480  	if err := BazaarBackend.Clone(&vcsGetOption{
   481  		url:    remoteDummyURL,
   482  		dir:    localDir,
   483  		branch: "hello",
   484  	}); err == nil {
   485  		t.Error("error should be occurred, but nil")
   486  	}
   487  }