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 }