aboutsummaryrefslogtreecommitdiff
path: root/scripts/tests/git-worktree-gate.bats
blob: 7d0d8a118ffb954b913ab104c1dba27665a8ccb7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
#!/usr/bin/env bats

setup() {
    REPO_ROOT="$(cd "$(dirname "$BATS_TEST_FILENAME")/../.." && pwd)"
    GATE="$REPO_ROOT/claude-templates/bin/git-worktree-gate"
    WORK="$(mktemp -d)"
    REPO="$WORK/repo"
    git init -q "$REPO"
    git -C "$REPO" config user.email test@example.com
    git -C "$REPO" config user.name tester
    printf 'base\n' >"$REPO/tracked"
    git -C "$REPO" add tracked
    git -C "$REPO" commit -qm init
}

teardown() {
    rm -rf "$WORK"
}

@test "strict accepts a completely clean worktree" {
    run bash "$GATE" strict "$REPO"
    [ "$status" -eq 0 ]
    [ -z "$output" ]
}

@test "strict rejects unstaged, staged, and untracked changes with paths" {
    printf 'changed\n' >>"$REPO/tracked"
    printf 'new\n' >"$REPO/staged"
    git -C "$REPO" add staged
    printf 'loose\n' >"$REPO/loose"

    run bash "$GATE" strict "$REPO"
    [ "$status" -eq 1 ]
    [[ "$output" == *"wrap blocked"* ]]
    [[ "$output" == *"tracked"* ]]
    [[ "$output" == *"staged"* ]]
    [[ "$output" == *"loose"* ]]
}

@test "sync-safe permits untracked inbox deliveries and strict still rejects them" {
    mkdir -p "$REPO/inbox/nested"
    printf 'handoff\n' >"$REPO/inbox/nested/from-home.org"

    run bash "$GATE" sync-safe "$REPO"
    [ "$status" -eq 0 ]

    run bash "$GATE" strict "$REPO"
    [ "$status" -eq 1 ]
    [[ "$output" == *"inbox/nested/from-home.org"* ]]
}

@test "sync-safe rejects tracked changes even inside inbox" {
    mkdir -p "$REPO/inbox"
    printf 'tracked\n' >"$REPO/inbox/tracked.org"
    git -C "$REPO" add inbox/tracked.org
    git -C "$REPO" commit -qm inbox
    printf 'changed\n' >>"$REPO/inbox/tracked.org"

    run bash "$GATE" sync-safe "$REPO"
    [ "$status" -eq 1 ]
    [[ "$output" == *"inbox/tracked.org"* ]]
}

@test "sync-safe rejects untracked files outside inbox" {
    printf 'scratch\n' >"$REPO/scratch"
    run bash "$GATE" sync-safe "$REPO"
    [ "$status" -eq 1 ]
    [[ "$output" == *"scratch"* ]]
}

@test "ignored files do not block either policy" {
    printf 'cache/\n' >"$REPO/.gitignore"
    git -C "$REPO" add .gitignore
    git -C "$REPO" commit -qm ignore
    mkdir -p "$REPO/cache"
    printf 'generated\n' >"$REPO/cache/output"

    run bash "$GATE" strict "$REPO"
    [ "$status" -eq 0 ]
    run bash "$GATE" sync-safe "$REPO"
    [ "$status" -eq 0 ]
}

@test "reports unusual filenames without losing the entry" {
    odd=$'line break\nname'
    printf 'odd\n' >"$REPO/$odd"
    run bash "$GATE" strict "$REPO"
    [ "$status" -eq 1 ]
    [[ "$output" == *"line"* ]]
    [[ "$output" == *"name"* ]]
}

@test "certify and verify bind a clean worktree to its current HEAD" {
    run bash "$GATE" certify "$REPO"
    [ "$status" -eq 0 ]
    run bash "$GATE" verify "$REPO"
    [ "$status" -eq 0 ]

    git -C "$REPO" commit -q --allow-empty -m later
    run bash "$GATE" verify "$REPO"
    [ "$status" -eq 1 ]
    [[ "$output" == *"HEAD changed"* ]]
}

@test "verify rejects changes made after certification" {
    run bash "$GATE" certify "$REPO"
    [ "$status" -eq 0 ]
    printf 'late\n' >>"$REPO/tracked"
    run bash "$GATE" verify "$REPO"
    [ "$status" -eq 1 ]
    [[ "$output" == *"tracked"* ]]
}

@test "dirty submodule blocks strict and sync-safe" {
    CHILD="$WORK/child"
    git init -q "$CHILD"
    git -C "$CHILD" config user.email test@example.com
    git -C "$CHILD" config user.name tester
    printf 'child\n' >"$CHILD/file"
    git -C "$CHILD" add file
    git -C "$CHILD" commit -qm init
    git -C "$REPO" -c protocol.file.allow=always submodule add -q "$CHILD" sub
    git -C "$REPO" commit -qam submodule
    printf 'dirty\n' >>"$REPO/sub/file"

    run bash "$GATE" strict "$REPO"
    [ "$status" -eq 1 ]
    [[ "$output" == *"sub"* ]]
    run bash "$GATE" sync-safe "$REPO"
    [ "$status" -eq 1 ]
}

@test "a low-level git status failure blocks instead of looking clean" {
    printf 'not an index\n' >"$WORK/bad-index"
    run env GIT_INDEX_FILE="$WORK/bad-index" bash "$GATE" strict "$REPO"
    [ "$status" -eq 1 ]
    [[ "$output" == *"git status failed"* ]]
}

@test "an in-progress sequencer operation blocks a clean-looking tree" {
    gitdir="$(git -C "$REPO" rev-parse --absolute-git-dir)"
    mkdir -p "$gitdir/sequencer"
    run bash "$GATE" strict "$REPO"
    [ "$status" -eq 1 ]
    [[ "$output" == *"sequencer"* ]]
}