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 }