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