返回 DeepSeek-Reasonix
metadata_identity_test.go
根目录 / internal / worktree / metadata_identity_test.go
1 package worktree
2
3 import (
4 "context"
5 "encoding/json"
6 "os"
7 "path/filepath"
8 "strings"
9 "testing"
10 )
11
12 // metadata.json keeps the shape older builds decode strictly, so a worktree
13 // this build creates stays mergeable after a downgrade.
14 func TestMergeMetadataStaysReadableByStrictOlderDecoder(t *testing.T) {
15 requireGit(t)
16 repo := initRepo(t)
17 created, err := Create(context.Background(), opened(t, repo), t.TempDir())
18 if err != nil {
19 t.Fatal(err)
20 }
21 raw, err := os.ReadFile(metadataPath(created.WorktreeRoot))
22 if err != nil {
23 t.Fatal(err)
24 }
25 type olderMetadata struct {
26 Version int `json:"version"`
27 SourceRoot string `json:"sourceRoot"`
28 TargetBranch string `json:"targetBranch"`
29 CreatedHead string `json:"createdHead"`
30 WorktreeRoot string `json:"worktreeRoot"`
31 WorktreeBranch string `json:"worktreeBranch"`
32 }
33 decoder := json.NewDecoder(strings.NewReader(string(raw)))
34 decoder.DisallowUnknownFields()
35 var older olderMetadata
36 if err := decoder.Decode(&older); err != nil {
37 t.Fatalf("older decoder: %v", err)
38 }
39 if _, err := os.Stat(identityPath(metadataPath(created.WorktreeRoot))); err != nil {
40 t.Fatalf("pinned identity was not recorded beside the metadata: %v", err)
41 }
42 }
43
44 // A worktree created before identities were recorded resolves them from the
45 // recorded roots and still merges back and finalizes.
46 func TestMergeBackWithoutRecordedIdentity(t *testing.T) {
47 requireGit(t)
48 repo := initRepo(t)
49 managed := t.TempDir()
50 created, err := Create(context.Background(), opened(t, repo), managed)
51 if err != nil {
52 t.Fatal(err)
53 }
54 if err := os.Remove(identityPath(metadataPath(created.WorktreeRoot))); err != nil {
55 t.Fatal(err)
56 }
57 if err := os.WriteFile(filepath.Join(created.WorktreeRoot, "feature.go"), []byte("package feature\n"), 0o644); err != nil {
58 t.Fatal(err)
59 }
60 inspection := inspectMergeTest(t, created.WorkspaceRoot, managed)
61 request := requestFromInspection(inspection)
62 request.AutoCommitDirty = true
63 result, err := MergeBack(context.Background(), managed, request)
64 if err != nil || !result.Merged {
65 t.Fatalf("MergeBack: %v (%+v)", err, result)
66 }
67 if _, err := FinalizeMerge(context.Background(), managed, cleanupFromMerge(result)); err != nil {
68 t.Fatalf("FinalizeMerge: %v", err)
69 }
70 }
71
72 // A recorded identity naming another checkout's git dir is refused, not used.
73 func TestInspectMergeRefusesForgedRecordedIdentity(t *testing.T) {
74 requireGit(t)
75 repo := initRepo(t)
76 other := initRepo(t)
77 managed := t.TempDir()
78 created, err := Create(context.Background(), opened(t, repo), managed)
79 if err != nil {
80 t.Fatal(err)
81 }
82 forged := created.WorktreeRepo
83 forged.GitDir = opened(t, other).GitDir
84 body, err := json.Marshal(mergeIdentity{SourceRepo: created.SourceRepo, WorktreeRepo: forged})
85 if err != nil {
86 t.Fatal(err)
87 }
88 if err := os.WriteFile(identityPath(metadataPath(created.WorktreeRoot)), body, 0o600); err != nil {
89 t.Fatal(err)
90 }
91 if _, err := InspectMerge(context.Background(), created.WorkspaceRoot, managed); err == nil {
92 t.Fatal("InspectMerge accepted a recorded identity naming another checkout")
93 }
94 }
95
95 lines GO