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 }