github.com/motemen/ghq@v1.0.3/local_repository_test.go (about)

     1  package main
     2  
     3  import (
     4  	"os"
     5  	"path/filepath"
     6  	"reflect"
     7  	"runtime"
     8  	"sort"
     9  	"sync"
    10  	"testing"
    11  
    12  	"github.com/Songmu/gitconfig"
    13  )
    14  
    15  func samePathSlice(lhss, rhss []string) bool {
    16  	sort.Strings(lhss)
    17  	sort.Strings(rhss)
    18  	for i := range lhss {
    19  		if !samePath(lhss[i], rhss[i]) {
    20  			return false
    21  		}
    22  	}
    23  	return true
    24  }
    25  
    26  func TestLocalRepositoryFromFullPath(t *testing.T) {
    27  	defer func(orig []string) { _localRepositoryRoots = orig }(_localRepositoryRoots)
    28  	tmproot := newTempDir(t)
    29  	defer os.RemoveAll(tmproot)
    30  	_localRepositoryRoots = []string{tmproot}
    31  
    32  	testCases := []struct {
    33  		fpath    string
    34  		expect   string
    35  		subpaths []string
    36  	}{{
    37  		fpath:    filepath.Join(tmproot, "github.com/motemen/ghq"),
    38  		expect:   "motemen/ghq",
    39  		subpaths: []string{"ghq", "motemen/ghq", "github.com/motemen/ghq"},
    40  	}, {
    41  		fpath:    filepath.Join(tmproot, "stash.com/scm/motemen/ghq"),
    42  		expect:   "scm/motemen/ghq",
    43  		subpaths: []string{"ghq", "motemen/ghq", "scm/motemen/ghq", "stash.com/scm/motemen/ghq"},
    44  	}}
    45  
    46  	for _, tc := range testCases {
    47  		t.Run(tc.fpath, func(t *testing.T) {
    48  			r, err := LocalRepositoryFromFullPath(tc.fpath, nil)
    49  			if err != nil {
    50  				t.Errorf("error should be nil but: %s", err)
    51  				return
    52  			}
    53  			if r.NonHostPath() != tc.expect {
    54  				t.Errorf("NonHostPath: got: %s, expect: %s", r.NonHostPath(), tc.expect)
    55  			}
    56  			if !reflect.DeepEqual(r.Subpaths(), tc.subpaths) {
    57  				t.Errorf("Subpaths:\ngot:    %+v\nexpect: %+v", r.Subpaths(), tc.subpaths)
    58  			}
    59  		})
    60  	}
    61  }
    62  
    63  func TestNewLocalRepository(t *testing.T) {
    64  	defer func(orig []string) { _localRepositoryRoots = orig }(_localRepositoryRoots)
    65  	tmproot := newTempDir(t)
    66  	defer os.RemoveAll(tmproot)
    67  	_localRepositoryRoots = []string{tmproot}
    68  
    69  	testCases := []struct {
    70  		name, url, expect string
    71  	}{{
    72  		name:   "GitHub",
    73  		url:    "ssh://git@github.com/motemen/ghq.git",
    74  		expect: filepath.Join(tmproot, "github.com/motemen/ghq"),
    75  	}, {
    76  		name:   "stash",
    77  		url:    "ssh://git@stash.com/scm/motemen/ghq.git",
    78  		expect: filepath.Join(tmproot, "stash.com/scm/motemen/ghq"),
    79  	}, {
    80  		name:   "svn Sourceforge",
    81  		url:    "http://svn.code.sf.net/p/ghq/code/trunk",
    82  		expect: filepath.Join(tmproot, "svn.code.sf.net/p/ghq/code/trunk"),
    83  	}, {
    84  		name:   "git Sourceforge",
    85  		url:    "http://git.code.sf.net/p/ghq/code",
    86  		expect: filepath.Join(tmproot, "git.code.sf.net/p/ghq/code"),
    87  	}, {
    88  		name:   "svn Sourceforge JP",
    89  		url:    "http://scm.sourceforge.jp/svnroot/ghq/",
    90  		expect: filepath.Join(tmproot, "scm.sourceforge.jp/svnroot/ghq"),
    91  	}, {
    92  		name:   "git Sourceforge JP",
    93  		url:    "http://scm.sourceforge.jp/gitroot/ghq/ghq.git",
    94  		expect: filepath.Join(tmproot, "scm.sourceforge.jp/gitroot/ghq/ghq"),
    95  	}, {
    96  		name:   "svn Assembla",
    97  		url:    "https://subversion.assembla.com/svn/ghq/",
    98  		expect: filepath.Join(tmproot, "subversion.assembla.com/svn/ghq"),
    99  	}, {
   100  		name:   "git Assembla",
   101  		url:    "https://git.assembla.com/ghq.git",
   102  		expect: filepath.Join(tmproot, "git.assembla.com/ghq"),
   103  	}, {
   104  		name:   "bitbucket host with port",
   105  		url:    "https://bitbucket.local:8888/motemen/ghq.git",
   106  		expect: filepath.Join(tmproot, "bitbucket.local/motemen/ghq"),
   107  	}}
   108  
   109  	for _, tc := range testCases {
   110  		t.Run(tc.name, func(t *testing.T) {
   111  			defer func(orig string) { _home = orig }(_home)
   112  			_home = ""
   113  			homeOnce = &sync.Once{}
   114  			r, err := LocalRepositoryFromURL(mustParseURL(tc.url))
   115  			if err != nil {
   116  				t.Errorf("error should be nil but: %s", err)
   117  			}
   118  			if r.FullPath != tc.expect {
   119  				t.Errorf("got: %s, expect: %s", r.FullPath, tc.expect)
   120  			}
   121  		})
   122  	}
   123  }
   124  
   125  func TestLocalRepositoryRoots(t *testing.T) {
   126  	defer func(orig []string) { _localRepositoryRoots = orig }(_localRepositoryRoots)
   127  	defer func(orig string) { os.Setenv(envGhqRoot, orig) }(os.Getenv(envGhqRoot))
   128  
   129  	wd, err := os.Getwd()
   130  	if err != nil {
   131  		t.Fatal(err)
   132  	}
   133  
   134  	testCases := []struct {
   135  		root   string
   136  		expect []string
   137  	}{{
   138  		root:   "/path/to/ghqroot",
   139  		expect: []string{"/path/to/ghqroot"},
   140  	}, {
   141  		root:   "/path/to/ghqroot1" + string(os.PathListSeparator) + "/path/to/ghqroot2",
   142  		expect: []string{"/path/to/ghqroot1", "/path/to/ghqroot2"},
   143  	}, {
   144  		root:   "/path/to/ghqroot11" + string(os.PathListSeparator) + "vendor",
   145  		expect: []string{"/path/to/ghqroot11", filepath.Join(wd, "vendor")},
   146  	}}
   147  
   148  	for _, tc := range testCases {
   149  		t.Run(tc.root, func(t *testing.T) {
   150  			_localRepositoryRoots = nil
   151  			localRepoOnce = &sync.Once{}
   152  			os.Setenv(envGhqRoot, tc.root)
   153  			got, err := localRepositoryRoots(true)
   154  			if err != nil {
   155  				t.Errorf("error should be nil, but: %s", err)
   156  			}
   157  			if !samePathSlice(got, tc.expect) {
   158  				t.Errorf("\ngot:    %+v\nexpect: %+v", got, tc.expect)
   159  			}
   160  		})
   161  	}
   162  }
   163  
   164  // https://gist.github.com/kyanny/c231f48e5d08b98ff2c3
   165  func TestList_Symlink(t *testing.T) {
   166  	if runtime.GOOS == "windows" {
   167  		t.SkipNow()
   168  	}
   169  	root := newTempDir(t)
   170  	defer os.RemoveAll(root)
   171  
   172  	symDir := newTempDir(t)
   173  	defer os.RemoveAll(symDir)
   174  
   175  	origLocalRepositryRoots := _localRepositoryRoots
   176  	_localRepositoryRoots = []string{root}
   177  	defer func() { _localRepositoryRoots = origLocalRepositryRoots }()
   178  
   179  	if err := os.MkdirAll(filepath.Join(root, "github.com", "atom", "atom", ".git"), 0777); err != nil {
   180  		t.Fatal(err)
   181  	}
   182  
   183  	if err := os.MkdirAll(filepath.Join(root, "github.com", "zabbix", "zabbix", ".git"), 0777); err != nil {
   184  		t.Fatal(err)
   185  	}
   186  
   187  	if err := os.Symlink(symDir, filepath.Join(root, "github.com", "ghq")); err != nil {
   188  		t.Fatal(err)
   189  	}
   190  
   191  	paths := []string{}
   192  	walkAllLocalRepositories(func(repo *LocalRepository) {
   193  		paths = append(paths, repo.RelPath)
   194  	})
   195  
   196  	if len(paths) != 2 {
   197  		t.Errorf("length of paths should be 2, but: %d", len(paths))
   198  	}
   199  }
   200  
   201  func TestList_Symlink_In_Same_Directory(t *testing.T) {
   202  	if runtime.GOOS == "windows" {
   203  		t.SkipNow()
   204  	}
   205  	root := newTempDir(t)
   206  	defer os.RemoveAll(root)
   207  
   208  	symDir := newTempDir(t)
   209  	defer os.RemoveAll(symDir)
   210  
   211  	origLocalRepositryRoots := _localRepositoryRoots
   212  	_localRepositoryRoots = []string{root}
   213  	defer func() { _localRepositoryRoots = origLocalRepositryRoots }()
   214  
   215  	if err := os.MkdirAll(filepath.Join(root, "github.com", "root-user", "a-repository", ".git"), 0777); err != nil {
   216  		t.Fatal(err)
   217  	}
   218  
   219  	if err := os.MkdirAll(filepath.Join(root, "github.com", "root-user", "z-repository", ".git"), 0777); err != nil {
   220  		t.Fatal(err)
   221  	}
   222  
   223  	if err := os.MkdirAll(filepath.Join(symDir, "github.com", "sym-user", "h-repository", ".git"), 0777); err != nil {
   224  		t.Fatal(err)
   225  	}
   226  
   227  	if err := os.Symlink(filepath.Join(symDir, "github.com", "sym-user", "h-repository"), filepath.Join(root, "github.com", "root-user", "h-repository")); err != nil {
   228  		t.Fatal(err)
   229  	}
   230  
   231  	paths := []string{}
   232  	walkAllLocalRepositories(func(repo *LocalRepository) {
   233  		paths = append(paths, repo.RelPath)
   234  	})
   235  
   236  	if len(paths) != 3 {
   237  		t.Errorf("length of paths should be 3, but: %d", len(paths))
   238  	}
   239  }
   240  
   241  func TestFindVCSBackend(t *testing.T) {
   242  	testCases := []struct {
   243  		name   string
   244  		setup  func(t *testing.T) (string, string, func())
   245  		expect *VCSBackend
   246  	}{{
   247  		name: "git",
   248  		setup: func(t *testing.T) (string, string, func()) {
   249  			dir := newTempDir(t)
   250  			os.MkdirAll(filepath.Join(dir, ".git"), 0755)
   251  			return dir, "", func() {
   252  				os.RemoveAll(dir)
   253  			}
   254  		},
   255  		expect: GitBackend,
   256  	}, {
   257  		name: "git svn",
   258  		setup: func(t *testing.T) (string, string, func()) {
   259  			dir := newTempDir(t)
   260  			os.MkdirAll(filepath.Join(dir, ".git", "svn"), 0755)
   261  			return dir, "", func() {
   262  				os.RemoveAll(dir)
   263  			}
   264  		},
   265  		expect: GitBackend,
   266  	}, {
   267  		name: "git with matched vcs",
   268  		setup: func(t *testing.T) (string, string, func()) {
   269  			dir := newTempDir(t)
   270  			os.MkdirAll(filepath.Join(dir, ".git"), 0755)
   271  			return dir, "git", func() {
   272  				os.RemoveAll(dir)
   273  			}
   274  		},
   275  		expect: GitBackend,
   276  	}, {
   277  		name: "git with not matched vcs",
   278  		setup: func(t *testing.T) (string, string, func()) {
   279  			dir := newTempDir(t)
   280  			os.MkdirAll(filepath.Join(dir, ".git"), 0755)
   281  			return dir, "mercurial", func() {
   282  				os.RemoveAll(dir)
   283  			}
   284  		},
   285  		expect: nil,
   286  	}}
   287  
   288  	for _, tc := range testCases {
   289  		t.Run(tc.name, func(t *testing.T) {
   290  			fpath, vcs, teardown := tc.setup(t)
   291  			defer teardown()
   292  			backend := findVCSBackend(fpath, vcs)
   293  			if backend != tc.expect {
   294  				t.Errorf("got: %v, expect: %v", backend, tc.expect)
   295  			}
   296  		})
   297  	}
   298  }
   299  
   300  func TestLocalRepository_VCS(t *testing.T) {
   301  	defer func(orig []string) { _localRepositoryRoots = orig }(_localRepositoryRoots)
   302  	defer func(orig string) { os.Setenv(envGhqRoot, orig) }(os.Getenv(envGhqRoot))
   303  
   304  	_localRepositoryRoots = nil
   305  	localRepoOnce = &sync.Once{}
   306  	tmpdir := newTempDir(t)
   307  	os.Setenv(envGhqRoot, tmpdir)
   308  
   309  	pkg := filepath.Join(tmpdir, "github.com", "motemen", "ghq")
   310  	subpkg := filepath.Join(pkg, "logger")
   311  
   312  	os.MkdirAll(filepath.Join(pkg, ".git"), 0755)
   313  	os.MkdirAll(subpkg, 0755)
   314  
   315  	t.Run("reporoot", func(t *testing.T) {
   316  		repo, err := LocalRepositoryFromFullPath(pkg, nil)
   317  		if err != nil {
   318  			t.Errorf("error should be nil, but: %s (%s)", err, pkg)
   319  			return
   320  		}
   321  		vcs, repoPath := repo.VCS()
   322  		if vcs != GitBackend {
   323  			t.Errorf("repo.VCS() = %+v, expect: GitBackend", vcs)
   324  			return
   325  		}
   326  		if repoPath != pkg {
   327  			t.Errorf("got: %s, expect: %s", repoPath, pkg)
   328  		}
   329  	})
   330  
   331  	t.Run("subdir", func(t *testing.T) {
   332  		repo, err := LocalRepositoryFromFullPath(subpkg, nil)
   333  		if err != nil {
   334  			t.Errorf("error should be nil, but: %s", err)
   335  			return
   336  		}
   337  		vcs, repoPath := repo.VCS()
   338  		if vcs != GitBackend {
   339  			t.Errorf("repo.VCS() = %+v, expect: GitBackend", vcs)
   340  		}
   341  		if repoPath != pkg {
   342  			t.Errorf("got: %s, expect: %s", repoPath, pkg)
   343  		}
   344  	})
   345  }
   346  
   347  func TestURLMatchLocalRepositoryRoots(t *testing.T) {
   348  	if runtime.GOOS == "windows" {
   349  		t.SkipNow()
   350  	}
   351  	defer tmpEnv("HOME", "/home/tmp")()
   352  	defer func(orig string) { _home = orig }(_home)
   353  	_home = ""
   354  	homeOnce = &sync.Once{}
   355  	defer gitconfig.WithConfig(t, `
   356  [ghq]
   357    root = /hoge
   358  [ghq "https://github.com/hatena"]
   359    root = ~/proj/hatena
   360    root = /backups/hatena
   361  [ghq "https://github.com/natureglobal"]
   362    root = ~/proj/natureglobal
   363  `)()
   364  
   365  	want := []string{"/home/tmp/proj/hatena", "/backups/hatena", "/home/tmp/proj/natureglobal"}
   366  	got, err := urlMatchLocalRepositoryRoots()
   367  	if err != nil {
   368  		t.Errorf("error should be nil but: %s", err)
   369  	}
   370  	if !reflect.DeepEqual(want, got) {
   371  		t.Errorf("urlMatchLocalRepositoryRoots() = %+v, want: %+v", got, want)
   372  	}
   373  }