github.com/hattya/nazuna@v0.7.1-0.20240331055452-55e14c275c1c/wc_test.go (about) 1 // 2 // nazuna :: wc_test.go 3 // 4 // Copyright (c) 2013-2022 Akinori Hattori <hattya@gmail.com> 5 // 6 // SPDX-License-Identifier: MIT 7 // 8 9 package nazuna_test 10 11 import ( 12 "fmt" 13 "os" 14 "path/filepath" 15 "reflect" 16 "strings" 17 "testing" 18 19 "github.com/hattya/nazuna" 20 ) 21 22 func TestOpenWC(t *testing.T) { 23 repo := init_(t) 24 25 wc, err := repo.WC() 26 if err != nil { 27 t.Fatal(err) 28 } 29 if err := wc.Flush(); err != nil { 30 t.Error(err) 31 } 32 data, err := os.ReadFile(filepath.Join(".nzn", "state.json")) 33 if err != nil { 34 t.Fatal(err) 35 } 36 if g, e := string(data), "{}\n"; g != e { 37 t.Errorf("expected %q, got %q", e, g) 38 } 39 } 40 41 func TestOpenWCError(t *testing.T) { 42 repo := init_(t) 43 44 // unmarshal error 45 if err := mkdir(".nzn", "state.json"); err != nil { 46 t.Fatal(err) 47 } 48 if _, err := repo.WC(); err == nil { 49 t.Error("expected error") 50 } 51 } 52 53 func TestWCPaths(t *testing.T) { 54 repo := init_(t) 55 56 wc, err := repo.WC() 57 if err != nil { 58 t.Fatal(err) 59 } 60 if g, e := wc.PathFor("file"), filepath.Join(repo.Root(), "file"); g != e { 61 t.Errorf("WC.PathFor(%q) = %q, expected %q", "file", g, e) 62 } 63 if wc.Exists("file") { 64 t.Errorf("WC.Exists(%q) = true, expected false", "file") 65 } 66 // base: / 67 base := '/' 68 if rel, err := wc.Rel(base, filepath.Join(repo.Root(), "file")); err != nil { 69 t.Error(err) 70 } else if g, e := rel, "file"; g != e { 71 t.Errorf("WC.Rel('%q', ...) = %q, expected %q", base, g, e) 72 } 73 if rel, err := wc.Rel(base, "file"); err != nil { 74 t.Error(err) 75 } else if g, e := rel, "file"; g != e { 76 t.Errorf("WC.Rel('%q', ...) = %q, expected %q", base, g, e) 77 } 78 // base: . 79 base = '.' 80 if rel, err := wc.Rel(base, "file"); err != nil { 81 t.Error(err) 82 } else if g, e := rel, "file"; g != e { 83 t.Errorf("WC.Rel('%q', ...) = %q, expected %q", base, g, e) 84 } 85 if rel, err := wc.Rel(base, "$var"); err != nil { 86 t.Error(err) 87 } else if g, e := rel, "$var"; g != e { 88 t.Errorf("WC.Rel('%q', ...) = %q, expected %q", base, g, e) 89 } 90 // unknown base 91 if _, err := wc.Rel('_', ""); err == nil { 92 t.Error("expected error") 93 } 94 // not under root 95 if _, err := wc.Rel('/', filepath.Dir(repo.Root())); err == nil { 96 t.Error("expected error") 97 } 98 if _, err := wc.Rel('/', filepath.Join(filepath.Dir(repo.Root()), "file")); err == nil { 99 t.Error("expected error") 100 } 101 } 102 103 func TestWCLinks(t *testing.T) { 104 repo := init_(t) 105 106 wc, err := repo.WC() 107 if err != nil { 108 t.Fatal(err) 109 } 110 // file 111 dst := "link" 112 src := repo.PathFor(nil, dst) 113 if err := touch(src); err != nil { 114 t.Fatal(err) 115 } 116 if err := wc.Link(src, dst); err != nil { 117 t.Fatal(err) 118 } 119 if err := testLink(wc, src, dst); err != nil { 120 t.Error(err) 121 } 122 if err := wc.Unlink(dst); err != nil { 123 t.Fatal(err) 124 } 125 // file in directory 126 dst = filepath.Join("dir", "link") 127 src = repo.PathFor(nil, dst) 128 if err := mkdir(filepath.Dir(src)); err != nil { 129 t.Fatal(err) 130 } 131 if err := touch(src); err != nil { 132 t.Fatal(err) 133 } 134 if err := wc.Link(src, dst); err != nil { 135 t.Fatal(err) 136 } 137 if err := testLink(wc, src, dst); err != nil { 138 t.Error(err) 139 } 140 if err := wc.Unlink(dst); err != nil { 141 t.Fatal(err) 142 } 143 if _, err := os.Stat(filepath.Dir(dst)); err == nil { 144 t.Fatal("expected to remove parent directories") 145 } 146 // directory 147 dst = "dir" 148 src = repo.PathFor(nil, dst) 149 if err := wc.Link(src, dst); err != nil { 150 t.Fatal(err) 151 } 152 if err := testLink(wc, src, dst); err != nil { 153 t.Error(err) 154 } 155 if err := wc.Unlink(dst); err != nil { 156 t.Fatal(err) 157 } 158 // keep non-empty directory 159 dst = filepath.Join("dir", "link") 160 src = repo.PathFor(nil, dst) 161 if err := wc.Link(src, dst); err != nil { 162 t.Fatal(err) 163 } 164 if err := touch(filepath.Join("dir", "file")); err != nil { 165 t.Fatal(err) 166 } 167 if err := wc.Unlink(dst); err != nil { 168 t.Error(err) 169 } 170 if _, err := os.Stat("dir"); err != nil { 171 t.Error("expected to keep parent directories") 172 } 173 if err := os.RemoveAll("dir"); err != nil { 174 t.Fatal(err) 175 } 176 // parent path is link 177 dst = "dir" 178 src = repo.PathFor(nil, dst) 179 if err := wc.Link(src, dst); err != nil { 180 t.Fatal(err) 181 } 182 dst = filepath.Join("dir", "file") 183 src = repo.PathFor(nil, dst) 184 switch err := wc.Link(src, dst).(type) { 185 case *os.PathError: 186 if g, e := err.Err, nazuna.ErrLink; g != e { 187 t.Errorf("expected %q, got %q", e, g) 188 } 189 default: 190 t.Errorf("expected *os.PathError, got %T", err) 191 } 192 if err := wc.Unlink(filepath.Join("dir", "file")); err == nil { 193 t.Error("expected error") 194 } 195 if err := wc.Unlink("dir"); err != nil { 196 t.Fatal(err) 197 } 198 } 199 200 func testLink(wc *nazuna.WC, src, dst string) error { 201 if !wc.IsLink(dst) { 202 return fmt.Errorf("wc.IsLink(%q) = false, expected true", dst) 203 } 204 if !wc.LinksTo(dst, src) { 205 return fmt.Errorf("wc.LinksTo(%q) = false, expected true", dst) 206 } 207 if err := wc.Link(src, dst); err == nil { 208 return fmt.Errorf("expected error") 209 } 210 return nil 211 } 212 213 func TestSelectLayer(t *testing.T) { 214 repo := init_(t) 215 216 wc, err := repo.WC() 217 if err != nil { 218 t.Fatal(err) 219 } 220 a, err := repo.NewLayer("a") 221 if err != nil { 222 t.Fatal(err) 223 } 224 b1, err := repo.NewLayer("b/1") 225 if err != nil { 226 t.Fatal(err) 227 } 228 b2, err := repo.NewLayer("b/2") 229 if err != nil { 230 t.Fatal(err) 231 } 232 // cannot resolve 233 switch _, err := wc.LayerFor("b"); { 234 case err == nil: 235 t.Error("expected error") 236 case !strings.HasPrefix(err.Error(), "cannot resolve layer "): 237 t.Error("unexpected error:", err) 238 } 239 switch _, err := wc.Layers(); { 240 case err == nil: 241 t.Error("expected error") 242 case !strings.HasPrefix(err.Error(), "cannot resolve layer "): 243 t.Error("unexpected error:", err) 244 } 245 // cannot select 246 for _, s := range []string{"_", "a", "b"} { 247 if err := wc.SelectLayer(s); err == nil { 248 t.Errorf("%v: expected error", s) 249 } 250 } 251 252 if err := wc.SelectLayer(b2.Path()); err != nil { 253 t.Error(err) 254 } 255 if err := wc.SelectLayer(b1.Path()); err != nil { 256 t.Error(err) 257 } 258 if _, err := wc.LayerFor("b"); err != nil { 259 t.Error(err) 260 } 261 if ll, err := wc.Layers(); err != nil { 262 t.Error(err) 263 } else if g, e := ll, []*nazuna.Layer{b1, a}; !reflect.DeepEqual(g, e) { 264 t.Errorf("WC.Layers() = {%q, %q}, expected {%q, %q}", g[0].Path(), g[1].Path(), e[0].Path(), e[1].Path()) 265 } 266 // already selected 267 if err := wc.SelectLayer(b1.Path()); err == nil { 268 t.Error("expected error") 269 } 270 } 271 272 func TestMergeLayers(t *testing.T) { 273 repo := init_(t) 274 275 wc, err := repo.WC() 276 if err != nil { 277 t.Fatal(err) 278 } 279 a, err := repo.NewLayer("a") 280 if err != nil { 281 t.Fatal(err) 282 } 283 b1, err := repo.NewLayer("b/1") 284 if err != nil { 285 t.Fatal(err) 286 } 287 b2, err := repo.NewLayer("b/2") 288 if err != nil { 289 t.Fatal(err) 290 } 291 292 ui := new(testUI) 293 git, err := nazuna.VCSFor(ui, filepath.Join(".nzn", "r")) 294 if err != nil { 295 t.Fatal(err) 296 } 297 alias := func(l *nazuna.Layer, src, dst string) { 298 t.Helper() 299 if err := l.NewAlias(src, dst); err != nil { 300 t.Fatal(err) 301 } 302 } 303 file := func(l *nazuna.Layer, n string) { 304 t.Helper() 305 if err := mkdir(filepath.Dir(repo.PathFor(l, n))); err != nil { 306 t.Fatal(err) 307 } 308 if err := touch(repo.PathFor(l, n)); err != nil { 309 t.Fatal(err) 310 } 311 } 312 link := func(l *nazuna.Layer, src, dst string) { 313 t.Helper() 314 if _, err := l.NewLink(nil, repo.PathFor(l, src), dst+"a"); err != nil { 315 t.Fatal(err) 316 } 317 if _, err := l.NewLink([]string{repo.PathFor(l, ".")}, src, dst+"b"); err != nil { 318 t.Fatal(err) 319 } 320 } 321 subrepo := func(l *nazuna.Layer, dst string) { 322 t.Helper() 323 src := "github.com/hattya/" + filepath.Base(dst) 324 if _, err := l.NewSubrepo(src+"a", dst+"a"); err != nil { 325 t.Fatal(err) 326 } 327 repo, err := l.NewSubrepo(src+"b", dst+"b") 328 if err != nil { 329 t.Fatal(err) 330 } 331 repo.Name = filepath.Base(repo.Src) 332 } 333 // file 334 file(a, "file1") 335 // file :: → alias 336 file(a, "file2") 337 alias(b1, "file2", "file2_") 338 alias(b2, "file2", "file2_") 339 // :: file 340 file(b1, "file3") 341 file(b2, "file3") 342 // dir 343 file(a, filepath.Join("dir1", "file1")) 344 // dir/file 345 file(a, filepath.Join("dir2", "file1")) 346 // file :: → alias 347 file(a, "file4") 348 alias(b1, "file4", filepath.Join("dir2", "file2")) 349 alias(b2, "file4", filepath.Join("dir2", "file2")) 350 // dir/dir/file 351 file(a, filepath.Join("dir2", "dir1", "file1")) 352 // file :: → alias 353 file(a, "file5") 354 alias(b1, "file5", filepath.Join("dir2", "dir1", "file2")) 355 alias(b2, "file5", filepath.Join("dir2", "dir1", "file2")) 356 // dir/[file :: → alias] 357 file(a, filepath.Join("dir2", "file3")) 358 alias(b1, filepath.Join("dir2", "file3"), filepath.Join("dir2", "file3_")) 359 alias(b2, filepath.Join("dir2", "file3"), filepath.Join("dir2", "file3_")) 360 // dir/file :: → alias 361 file(a, filepath.Join("dir3", "file1")) 362 alias(b1, filepath.Join("dir3", "file1"), filepath.Join("dir2", "file4")) 363 alias(b2, filepath.Join("dir3", "file1"), filepath.Join("dir2", "file4")) 364 // [dir :: → alias]/file 365 file(a, filepath.Join("dir4", "file5")) 366 alias(b1, "dir4", "dir2") 367 alias(b2, "dir4", "dir2") 368 // :: dir/file 369 file(b1, filepath.Join("dir2", "file6")) 370 file(b2, filepath.Join("dir2", "file6")) 371 // dir/file :: → alias 372 file(a, filepath.Join("dir5", "file1")) 373 alias(b1, filepath.Join("dir5", "file1"), "file6") 374 alias(b2, filepath.Join("dir5", "file1"), "file6") 375 // dir exists 376 if err := mkdir(wc.PathFor("dir6")); err != nil { 377 t.Fatal(err) 378 } 379 file(a, filepath.Join("dir6", "file1")) 380 // link 381 link(a, "file1", "link1") 382 // link :: → alias 383 link(a, "file2", "link2") 384 alias(b1, "link2a", "link2a_") 385 alias(b1, "link2b", "link2b_") 386 alias(b2, "link2a", "link2a_") 387 alias(b2, "link2b", "link2b_") 388 // :: link 389 link(b1, "file3", "link3") 390 link(b2, "file3", "link3") 391 // link :: → alias 392 link(a, "file4", "link4") 393 alias(b1, "link4a", filepath.Join("dir2", "link2a")) 394 alias(b1, "link4b", filepath.Join("dir2", "link2b")) 395 alias(b2, "link4a", filepath.Join("dir2", "link2a")) 396 alias(b2, "link4b", filepath.Join("dir2", "link2b")) 397 // dir/[link :: → alias] 398 link(a, filepath.Join("dir2", "file3"), filepath.Join("dir2", "link3")) 399 alias(b1, filepath.Join("dir2", "link3a"), filepath.Join("dir2", "link3a_")) 400 alias(b1, filepath.Join("dir2", "link3b"), filepath.Join("dir2", "link3b_")) 401 alias(b2, filepath.Join("dir2", "link3a"), filepath.Join("dir2", "link3a_")) 402 alias(b2, filepath.Join("dir2", "link3b"), filepath.Join("dir2", "link3b_")) 403 // dir/link :: → alias 404 link(a, filepath.Join("dir3", "file1"), filepath.Join("dir3", "link1")) 405 alias(b1, filepath.Join("dir3", "link1a"), filepath.Join("dir2", "link4a")) 406 alias(b1, filepath.Join("dir3", "link1b"), filepath.Join("dir2", "link4b")) 407 alias(b2, filepath.Join("dir3", "link1a"), filepath.Join("dir2", "link4a")) 408 alias(b2, filepath.Join("dir3", "link1b"), filepath.Join("dir2", "link4b")) 409 // [dir :: → alias]/link 410 link(a, filepath.Join("dir4", "file5"), filepath.Join("dir4", "link5")) 411 // :: dir/link 412 link(b1, filepath.Join("dir2", "file6"), filepath.Join("dir2", "link6")) 413 link(b2, filepath.Join("dir2", "file6"), filepath.Join("dir2", "link6")) 414 // dir/link :: → alias 415 link(a, filepath.Join("dir5", "file1"), filepath.Join("dir5", "link1")) 416 alias(b1, filepath.Join("dir5", "link1a"), "link6a") 417 alias(b1, filepath.Join("dir5", "link1b"), "link6b") 418 alias(b2, filepath.Join("dir5", "link1a"), "link6a") 419 alias(b2, filepath.Join("dir5", "link1b"), "link6b") 420 // subrepo 421 subrepo(a, "repo1") 422 // subrepo :: → alias 423 subrepo(a, "repo2") 424 alias(b1, "repo2a", "repo2a_") 425 alias(b1, "repo2b", "repo2b_") 426 alias(b2, "repo2a", "repo2a_") 427 alias(b2, "repo2b", "repo2b_") 428 // :: subrepo 429 subrepo(b1, "repo3") 430 subrepo(b2, "repo3") 431 // subrepo :: → alias 432 subrepo(a, "repo4") 433 alias(b1, "repo4a", filepath.Join("dir2", "repo1a")) 434 alias(b1, "repo4b", filepath.Join("dir2", "repo1b")) 435 alias(b2, "repo4a", filepath.Join("dir2", "repo1a")) 436 alias(b2, "repo4b", filepath.Join("dir2", "repo1b")) 437 // dir[subrepo :: → alias] 438 subrepo(a, filepath.Join("dir2", "repo3")) 439 alias(b1, filepath.Join("dir2", "repo3a"), filepath.Join("dir2", "repo3a_")) 440 alias(b1, filepath.Join("dir2", "repo3b"), filepath.Join("dir2", "repo3b_")) 441 alias(b2, filepath.Join("dir2", "repo3a"), filepath.Join("dir2", "repo3a_")) 442 alias(b2, filepath.Join("dir2", "repo3b"), filepath.Join("dir2", "repo3b_")) 443 // dir/subrepo → alias 444 subrepo(a, filepath.Join("dir3", "repo1")) 445 alias(b1, filepath.Join("dir3", "repo1a"), filepath.Join("dir2", "repo4a")) 446 alias(b1, filepath.Join("dir3", "repo1b"), filepath.Join("dir2", "repo4b")) 447 alias(b2, filepath.Join("dir3", "repo1a"), filepath.Join("dir2", "repo4a")) 448 alias(b2, filepath.Join("dir3", "repo1b"), filepath.Join("dir2", "repo4b")) 449 // [dir :: → alias]/subrepo 450 subrepo(a, filepath.Join("dir4", "repo5")) 451 // :: dir/subrepo 452 subrepo(b1, filepath.Join("dir2", "repo6")) 453 subrepo(b2, filepath.Join("dir2", "repo6")) 454 // dir/subrepo :: → alias 455 subrepo(a, filepath.Join("dir5", "repo1")) 456 alias(b1, filepath.Join("dir5", "repo1a"), "repo6a") 457 alias(b1, filepath.Join("dir5", "repo1b"), "repo6b") 458 alias(b2, filepath.Join("dir5", "repo1a"), "repo6a") 459 alias(b2, filepath.Join("dir5", "repo1b"), "repo6b") 460 461 if err := git.Add("."); err != nil { 462 t.Fatal(err) 463 } 464 465 wc.State.WC = []*nazuna.Entry{ 466 { 467 Layer: a.Path(), 468 Path: "dir2", 469 IsDir: true, 470 }, 471 } 472 e := []*nazuna.Entry{ 473 { 474 Layer: a.Path(), 475 Path: "dir1", 476 IsDir: true, 477 }, 478 { 479 Layer: a.Path(), 480 Path: "dir2/dir1/file1", 481 }, 482 { 483 Layer: a.Path(), 484 Path: "dir2/dir1/file2", 485 Origin: "file5", 486 }, 487 { 488 Layer: a.Path(), 489 Path: "dir2/file1", 490 }, 491 { 492 Layer: a.Path(), 493 Path: "dir2/file2", 494 Origin: "file4", 495 }, 496 { 497 Layer: a.Path(), 498 Path: "dir2/file3_", 499 Origin: "dir2/file3", 500 }, 501 { 502 Layer: a.Path(), 503 Path: "dir2/file4", 504 Origin: "dir3/file1", 505 }, 506 { 507 Layer: a.Path(), 508 Path: "dir2/file5", 509 Origin: "dir4/file5", 510 }, 511 { 512 Layer: b1.Path(), 513 Path: "dir2/file6", 514 }, 515 { 516 Layer: a.Path(), 517 Path: "dir2/link2a", 518 Origin: repo.PathFor(a, "file4"), 519 Type: "link", 520 }, 521 { 522 Layer: a.Path(), 523 Path: "dir2/link2b", 524 Origin: repo.PathFor(a, "file4"), 525 Type: "link", 526 }, 527 { 528 Layer: a.Path(), 529 Path: "dir2/link3a_", 530 Origin: repo.PathFor(a, filepath.Join("dir2", "file3")), 531 Type: "link", 532 }, 533 { 534 Layer: a.Path(), 535 Path: "dir2/link3b_", 536 Origin: repo.PathFor(a, filepath.Join("dir2", "file3")), 537 Type: "link", 538 }, 539 { 540 Layer: a.Path(), 541 Path: "dir2/link4a", 542 Origin: repo.PathFor(a, filepath.Join("dir3", "file1")), 543 Type: "link", 544 }, 545 { 546 Layer: a.Path(), 547 Path: "dir2/link4b", 548 Origin: repo.PathFor(a, filepath.Join("dir3", "file1")), 549 Type: "link", 550 }, 551 { 552 Layer: a.Path(), 553 Path: "dir2/link5a", 554 Origin: repo.PathFor(a, filepath.Join("dir4", "file5")), 555 Type: "link", 556 }, 557 { 558 Layer: a.Path(), 559 Path: "dir2/link5b", 560 Origin: repo.PathFor(a, filepath.Join("dir4", "file5")), 561 Type: "link", 562 }, 563 { 564 Layer: b1.Path(), 565 Path: "dir2/link6a", 566 Origin: repo.PathFor(b1, filepath.Join("dir2", "file6")), 567 Type: "link", 568 }, 569 { 570 Layer: b1.Path(), 571 Path: "dir2/link6b", 572 Origin: repo.PathFor(b1, filepath.Join("dir2", "file6")), 573 Type: "link", 574 }, 575 { 576 Layer: a.Path(), 577 Path: "dir2/repo1a", 578 Origin: "github.com/hattya/repo4a", 579 Type: "subrepo", 580 }, 581 { 582 Layer: a.Path(), 583 Path: "dir2/repo1b", 584 Origin: "github.com/hattya/repo4b", 585 Type: "subrepo", 586 }, 587 { 588 Layer: a.Path(), 589 Path: "dir2/repo3a_", 590 Origin: "github.com/hattya/repo3a", 591 Type: "subrepo", 592 }, 593 { 594 Layer: a.Path(), 595 Path: "dir2/repo3b_", 596 Origin: "github.com/hattya/repo3b", 597 Type: "subrepo", 598 }, 599 { 600 Layer: a.Path(), 601 Path: "dir2/repo4a", 602 Origin: "github.com/hattya/repo1a", 603 Type: "subrepo", 604 }, 605 { 606 Layer: a.Path(), 607 Path: "dir2/repo4b", 608 Origin: "github.com/hattya/repo1b", 609 Type: "subrepo", 610 }, 611 { 612 Layer: a.Path(), 613 Path: "dir2/repo5a", 614 Origin: "github.com/hattya/repo5a", 615 Type: "subrepo", 616 }, 617 { 618 Layer: a.Path(), 619 Path: "dir2/repo5b", 620 Origin: "github.com/hattya/repo5b", 621 Type: "subrepo", 622 }, 623 { 624 Layer: b1.Path(), 625 Path: "dir2/repo6a", 626 Origin: "github.com/hattya/repo6a", 627 Type: "subrepo", 628 }, 629 { 630 Layer: b1.Path(), 631 Path: "dir2/repo6b", 632 Origin: "github.com/hattya/repo6b", 633 Type: "subrepo", 634 }, 635 { 636 Layer: a.Path(), 637 Path: "dir6/file1", 638 }, 639 { 640 Layer: a.Path(), 641 Path: "file1", 642 }, 643 { 644 Layer: a.Path(), 645 Path: "file2_", 646 Origin: "file2", 647 }, 648 { 649 Layer: b1.Path(), 650 Path: "file3", 651 }, 652 { 653 Layer: a.Path(), 654 Path: "file6", 655 Origin: "dir5/file1", 656 }, 657 { 658 Layer: a.Path(), 659 Path: "link1a", 660 Origin: repo.PathFor(a, "file1"), 661 Type: "link", 662 }, 663 { 664 Layer: a.Path(), 665 Path: "link1b", 666 Origin: repo.PathFor(a, "file1"), 667 Type: "link", 668 }, 669 { 670 Layer: a.Path(), 671 Path: "link2a_", 672 Origin: repo.PathFor(a, "file2"), 673 Type: "link", 674 }, 675 { 676 Layer: a.Path(), 677 Path: "link2b_", 678 Origin: repo.PathFor(a, "file2"), 679 Type: "link", 680 }, 681 { 682 Layer: b1.Path(), 683 Path: "link3a", 684 Origin: repo.PathFor(b1, "file3"), 685 Type: "link", 686 }, 687 { 688 Layer: b1.Path(), 689 Path: "link3b", 690 Origin: repo.PathFor(b1, "file3"), 691 Type: "link", 692 }, 693 { 694 Layer: a.Path(), 695 Path: "link6a", 696 Origin: repo.PathFor(a, filepath.Join("dir5", "file1")), 697 Type: "link", 698 }, 699 { 700 Layer: a.Path(), 701 Path: "link6b", 702 Origin: repo.PathFor(a, filepath.Join("dir5", "file1")), 703 Type: "link", 704 }, 705 { 706 Layer: a.Path(), 707 Path: "repo1a", 708 Origin: "github.com/hattya/repo1a", 709 Type: "subrepo", 710 }, 711 { 712 Layer: a.Path(), 713 Path: "repo1b", 714 Origin: "github.com/hattya/repo1b", 715 Type: "subrepo", 716 }, 717 { 718 Layer: a.Path(), 719 Path: "repo2a_", 720 Origin: "github.com/hattya/repo2a", 721 Type: "subrepo", 722 }, 723 { 724 Layer: a.Path(), 725 Path: "repo2b_", 726 Origin: "github.com/hattya/repo2b", 727 Type: "subrepo", 728 }, 729 { 730 Layer: b1.Path(), 731 Path: "repo3a", 732 Origin: "github.com/hattya/repo3a", 733 Type: "subrepo", 734 }, 735 { 736 Layer: b1.Path(), 737 Path: "repo3b", 738 Origin: "github.com/hattya/repo3b", 739 Type: "subrepo", 740 }, 741 { 742 Layer: a.Path(), 743 Path: "repo6a", 744 Origin: "github.com/hattya/repo1a", 745 Type: "subrepo", 746 }, 747 { 748 Layer: a.Path(), 749 Path: "repo6b", 750 Origin: "github.com/hattya/repo1b", 751 Type: "subrepo", 752 }, 753 } 754 if err := wc.SelectLayer(b1.Path()); err != nil { 755 t.Fatal(err) 756 } 757 switch _, err := wc.MergeLayers(); { 758 case err != nil: 759 t.Error(err) 760 case !reflect.DeepEqual(wc.State.WC, e): 761 t.Error("unexpected result") 762 } 763 764 if err := mkdir(wc.PathFor("dir1")); err != nil { 765 t.Fatal(err) 766 } 767 e[0].Path = "dir1/file1" 768 e[0].IsDir = false 769 for i := range e { 770 if e[i].Layer == b1.Path() { 771 e[i].Layer = b2.Path() 772 if e[i].Type == "link" { 773 e[i].Origin = repo.PathFor(b2, e[i].Origin[len(repo.PathFor(b1, "."))+1:]) 774 } 775 } 776 } 777 if err := wc.SelectLayer(b2.Path()); err != nil { 778 t.Fatal(err) 779 } 780 switch _, err := wc.MergeLayers(); { 781 case err != nil: 782 t.Error(err) 783 case !reflect.DeepEqual(wc.State.WC, e): 784 t.Error("unexpected result") 785 } 786 } 787 788 func TestMergeLayersError(t *testing.T) { 789 repo := init_(t) 790 791 wc, err := repo.WC() 792 if err != nil { 793 t.Fatal(err) 794 } 795 a, err := repo.NewLayer("a") 796 if err != nil { 797 t.Fatal(err) 798 } 799 b1, err := repo.NewLayer("b/1") 800 if err != nil { 801 t.Fatal(err) 802 } 803 if _, err := repo.NewLayer("b/2"); err != nil { 804 t.Fatal(err) 805 } 806 // cannot resolve 807 if _, err := wc.MergeLayers(); err == nil { 808 t.Error("expected error") 809 } 810 811 ui := new(testUI) 812 git, err := nazuna.VCSFor(ui, filepath.Join(".nzn", "r")) 813 if err != nil { 814 t.Fatal(err) 815 } 816 reset := func() { 817 a.Links = nil 818 a.Subrepos = nil 819 b1.Aliases = nil 820 } 821 alias := func(l *nazuna.Layer, src, dst string) { 822 t.Helper() 823 if err := l.NewAlias(src, dst); err != nil { 824 t.Fatal(err) 825 } 826 } 827 link := func(l *nazuna.Layer, path []string, src, dst string) { 828 t.Helper() 829 if _, err := l.NewLink(path, src, dst); err != nil { 830 t.Fatal(err) 831 } 832 } 833 subrepo := func(l *nazuna.Layer, dst string) { 834 t.Helper() 835 if _, err := l.NewSubrepo("github.com/hattya/"+filepath.Base(dst), dst); err != nil { 836 t.Fatal(err) 837 } 838 } 839 if err := touch(repo.PathFor(a, "file1")); err != nil { 840 t.Fatal(err) 841 } 842 if err := touch(repo.PathFor(a, "file2")); err != nil { 843 t.Fatal(err) 844 } 845 if err := git.Add("."); err != nil { 846 t.Fatal(err) 847 } 848 if err := wc.SelectLayer(b1.Path()); err != nil { 849 t.Fatal(err) 850 } 851 // file: file not found 852 if err := os.Remove(repo.PathFor(a, "file2")); err != nil { 853 t.Fatal(err) 854 } 855 if _, err := wc.MergeLayers(); err == nil { 856 t.Error("expected error") 857 } 858 if err := touch(repo.PathFor(a, "file2")); err != nil { 859 t.Fatal(err) 860 } 861 // file: alias error 862 alias(b1, "file1", filepath.Join("..", "file01")) 863 if _, err := wc.MergeLayers(); err == nil { 864 t.Error("expected error") 865 } 866 // link: file not found 867 reset() 868 link(a, nil, repo.PathFor(a, "file3"), "file03") 869 if _, err := wc.MergeLayers(); err != nil { 870 t.Error(err) 871 } 872 // link: alias error 873 reset() 874 link(a, nil, repo.PathFor(a, "file1"), "file01") 875 alias(b1, "file01", filepath.Join("..", "file001")) 876 if _, err := wc.MergeLayers(); err == nil { 877 t.Error("expected error") 878 } 879 // link: alias error 880 reset() 881 link(a, []string{repo.PathFor(a, ".")}, "file1", "file01") 882 alias(b1, "file01", filepath.Join("..", "file001")) 883 if _, err := wc.MergeLayers(); err == nil { 884 t.Error("expected error") 885 } 886 // link: warning 887 reset() 888 a.Links = map[string][]*nazuna.Link{ 889 "": { 890 { 891 Src: repo.PathFor(a, "file1"), 892 Dst: "file1", 893 }, 894 }, 895 } 896 if _, err := wc.MergeLayers(); err != nil { 897 t.Error(err) 898 } 899 // subrepo: alias error 900 reset() 901 subrepo(a, "repo1") 902 alias(b1, "repo1", filepath.Join("..", "repo01")) 903 if _, err := wc.MergeLayers(); err == nil { 904 t.Error("expected error") 905 } 906 // subrepo: warning 907 reset() 908 a.Subrepos = map[string][]*nazuna.Subrepo{ 909 "": { 910 { 911 Src: "github.com/hattya/repo1", 912 Name: "file1", 913 }, 914 }, 915 } 916 if _, err := wc.MergeLayers(); err != nil { 917 t.Error(err) 918 } 919 } 920 921 func TestWCErrorf(t *testing.T) { 922 repo := init_(t) 923 924 wc, err := repo.WC() 925 if err != nil { 926 t.Fatal(err) 927 } 928 929 err = fmt.Errorf("error") 930 if g, e := wc.Errorf(err).Error(), "error"; g != e { 931 t.Errorf("expected %q, got %q", e, g) 932 } 933 934 err = &os.LinkError{ 935 New: filepath.Join(repo.Root(), "link"), 936 Err: fmt.Errorf("link error"), 937 } 938 if g, e := wc.Errorf(err).Error(), "link: link error"; g != e { 939 t.Errorf("expected %q, got %q", e, g) 940 } 941 942 err = &os.PathError{ 943 Path: filepath.Join(repo.Root(), "link"), 944 Err: fmt.Errorf("path error"), 945 } 946 if g, e := wc.Errorf(err).Error(), "link: path error"; g != e { 947 t.Errorf("expected %q, got %q", e, g) 948 } 949 } 950 951 var entryTests = []struct { 952 e *nazuna.Entry 953 s string 954 }{ 955 { 956 &nazuna.Entry{}, 957 "!", 958 }, 959 { 960 &nazuna.Entry{ 961 IsDir: true, 962 }, 963 "!", 964 }, 965 { 966 &nazuna.Entry{ 967 Layer: "layer", 968 }, 969 "!layer", 970 }, 971 { 972 &nazuna.Entry{ 973 Layer: "layer", 974 IsDir: true, 975 }, 976 "!layer", 977 }, 978 { 979 &nazuna.Entry{ 980 Path: "path", 981 }, 982 "path!", 983 }, 984 { 985 &nazuna.Entry{ 986 Path: "path", 987 IsDir: true, 988 }, 989 "path/!", 990 }, 991 { 992 &nazuna.Entry{ 993 Layer: "layer", 994 Path: "path", 995 }, 996 "path!layer", 997 }, 998 { 999 &nazuna.Entry{ 1000 Layer: "layer", 1001 Path: "path", 1002 IsDir: true, 1003 }, 1004 "path/!layer", 1005 }, 1006 { 1007 &nazuna.Entry{ 1008 Layer: "layer", 1009 Path: "path", 1010 Origin: "origin", 1011 }, 1012 "path!layer:origin", 1013 }, 1014 { 1015 &nazuna.Entry{ 1016 Layer: "layer", 1017 Path: "path", 1018 Origin: "origin", 1019 IsDir: true, 1020 }, 1021 "path/!layer:origin/", 1022 }, 1023 { 1024 &nazuna.Entry{ 1025 Layer: "layer", 1026 Path: "path", 1027 Origin: "origin", 1028 Type: "link", 1029 }, 1030 "path!origin", 1031 }, 1032 { 1033 &nazuna.Entry{ 1034 Layer: "layer", 1035 Path: "path", 1036 Origin: "origin", 1037 IsDir: true, 1038 Type: "link", 1039 }, 1040 "path/!origin" + string(os.PathSeparator), 1041 }, 1042 { 1043 &nazuna.Entry{ 1044 Layer: "layer", 1045 Path: "path", 1046 Origin: "github.com/hattya/nazuna", 1047 Type: "subrepo", 1048 }, 1049 "path!github.com/hattya/nazuna", 1050 }, 1051 { 1052 &nazuna.Entry{ 1053 Layer: "layer", 1054 Path: "path", 1055 Origin: "github.com/hattya/nazuna", 1056 IsDir: true, 1057 Type: "subrepo", 1058 }, 1059 "path/!github.com/hattya/nazuna", 1060 }, 1061 } 1062 1063 func TestEntry(t *testing.T) { 1064 for _, tt := range entryTests { 1065 if g, e := tt.e.Format("%v!%v"), tt.s; g != e { 1066 t.Errorf("expected %q, got %q", e, g) 1067 } 1068 } 1069 }