1package.path = package.path .. ";./?.lua"
2local wt = dofile("src/main.lua")
3
4describe("hook permission system", function()
5 local temp_dir
6
7 setup(function()
8 local handle = io.popen("mktemp -d")
9 if handle then
10 temp_dir = handle:read("*l")
11 handle:close()
12 end
13 end)
14
15 teardown(function()
16 if temp_dir then
17 os.execute("rm -rf " .. temp_dir)
18 end
19 end)
20
21 describe("load_hook_permissions", function()
22 it("returns empty table when file does not exist", function()
23 local perms = wt.load_hook_permissions(temp_dir .. "/nonexistent")
24 assert.are.same({}, perms)
25 end)
26
27 it("loads valid permissions file", function()
28 if not temp_dir then
29 pending("temp_dir not available")
30 return
31 end
32 local perm_dir = temp_dir .. "/perms1/.local/share/wt"
33 os.execute("mkdir -p " .. perm_dir)
34
35 local f = io.open(perm_dir .. "/hook-dirs.lua", "w")
36 if f then
37 f:write('{\n\t["/home/user/project1"] = true,\n\t["/home/user/project2"] = false,\n}\n')
38 f:close()
39
40 local perms = wt.load_hook_permissions(temp_dir .. "/perms1")
41 assert.are.equal(true, perms["/home/user/project1"])
42 assert.are.equal(false, perms["/home/user/project2"])
43 else
44 pending("could not write test file")
45 end
46 end)
47
48 it("returns empty table for malformed file", function()
49 if not temp_dir then
50 pending("temp_dir not available")
51 return
52 end
53 local perm_dir = temp_dir .. "/perms2/.local/share/wt"
54 os.execute("mkdir -p " .. perm_dir)
55
56 local f = io.open(perm_dir .. "/hook-dirs.lua", "w")
57 if f then
58 f:write('this is not valid lua {{{}')
59 f:close()
60
61 local perms = wt.load_hook_permissions(temp_dir .. "/perms2")
62 assert.are.same({}, perms)
63 else
64 pending("could not write test file")
65 end
66 end)
67 end)
68
69 describe("save_hook_permissions", function()
70 it("creates directory if it does not exist", function()
71 if not temp_dir then
72 pending("temp_dir not available")
73 return
74 end
75 local home = temp_dir .. "/save1"
76 wt.save_hook_permissions({ ["/test/project"] = true }, home)
77
78 local f = io.open(home .. "/.local/share/wt/hook-dirs.lua", "r")
79 assert.is_not_nil(f)
80 if f then
81 f:close()
82 end
83 end)
84
85 it("saves permissions correctly", function()
86 if not temp_dir then
87 pending("temp_dir not available")
88 return
89 end
90 local home = temp_dir .. "/save2"
91 wt.save_hook_permissions({
92 ["/project/a"] = true,
93 ["/project/b"] = false,
94 }, home)
95
96 local perms = wt.load_hook_permissions(home)
97 assert.are.equal(true, perms["/project/a"])
98 assert.are.equal(false, perms["/project/b"])
99 end)
100
101 it("overwrites existing permissions", function()
102 if not temp_dir then
103 pending("temp_dir not available")
104 return
105 end
106 local home = temp_dir .. "/save3"
107 wt.save_hook_permissions({ ["/old"] = true }, home)
108 wt.save_hook_permissions({ ["/new"] = false }, home)
109
110 local perms = wt.load_hook_permissions(home)
111 assert.is_nil(perms["/old"])
112 assert.are.equal(false, perms["/new"])
113 end)
114 end)
115end)
116
117describe("run_hooks", function()
118 local temp_dir
119
120 setup(function()
121 local handle = io.popen("mktemp -d")
122 if handle then
123 temp_dir = handle:read("*l")
124 handle:close()
125 end
126 end)
127
128 teardown(function()
129 if temp_dir then
130 os.execute("rm -rf " .. temp_dir)
131 end
132 end)
133
134 describe("copy hooks", function()
135 it("copies files from source to target", function()
136 if not temp_dir then
137 pending("temp_dir not available")
138 return
139 end
140 local source = temp_dir .. "/source1"
141 local target = temp_dir .. "/target1"
142 local home = temp_dir .. "/home1"
143 os.execute("mkdir -p " .. source)
144 os.execute("mkdir -p " .. target)
145
146 local f = io.open(source .. "/config.json", "w")
147 if f then
148 f:write('{"key": "value"}\n')
149 f:close()
150 end
151
152 wt.save_hook_permissions({ ["/project"] = true }, home)
153
154 local hooks = { copy = { "config.json" } }
155 wt.run_hooks(source, target, hooks, "/project", home)
156
157 local copied = io.open(target .. "/config.json", "r")
158 assert.is_not_nil(copied)
159 if copied then
160 local content = copied:read("*a")
161 copied:close()
162 assert.is_truthy(content:match("key"))
163 end
164 end)
165
166 it("creates parent directories for nested paths", function()
167 if not temp_dir then
168 pending("temp_dir not available")
169 return
170 end
171 local source = temp_dir .. "/source2"
172 local target = temp_dir .. "/target2"
173 local home = temp_dir .. "/home2"
174 os.execute("mkdir -p " .. source .. "/nested/path")
175 os.execute("mkdir -p " .. target)
176
177 local f = io.open(source .. "/nested/path/file.txt", "w")
178 if f then
179 f:write("nested content\n")
180 f:close()
181 end
182
183 wt.save_hook_permissions({ ["/project2"] = true }, home)
184
185 local hooks = { copy = { "nested/path/file.txt" } }
186 wt.run_hooks(source, target, hooks, "/project2", home)
187
188 local copied = io.open(target .. "/nested/path/file.txt", "r")
189 assert.is_not_nil(copied)
190 if copied then
191 copied:close()
192 end
193 end)
194 end)
195
196 describe("symlink hooks", function()
197 it("creates symlinks from target to source", function()
198 if not temp_dir then
199 pending("temp_dir not available")
200 return
201 end
202 local source = temp_dir .. "/source3"
203 local target = temp_dir .. "/target3"
204 local home = temp_dir .. "/home3"
205 os.execute("mkdir -p " .. source .. "/node_modules")
206 os.execute("mkdir -p " .. target)
207
208 local f = io.open(source .. "/node_modules/package.json", "w")
209 if f then
210 f:write('{"name": "test"}\n')
211 f:close()
212 end
213
214 wt.save_hook_permissions({ ["/project3"] = true }, home)
215
216 local hooks = { symlink = { "node_modules" } }
217 wt.run_hooks(source, target, hooks, "/project3", home)
218
219 local link_check, _ = wt.run_cmd("test -L " .. target .. "/node_modules && echo yes")
220 assert.is_truthy(link_check:match("yes"))
221 end)
222 end)
223
224 describe("run hooks", function()
225 it("executes commands in target directory", function()
226 if not temp_dir then
227 pending("temp_dir not available")
228 return
229 end
230 local source = temp_dir .. "/source4"
231 local target = temp_dir .. "/target4"
232 local home = temp_dir .. "/home4"
233 os.execute("mkdir -p " .. source)
234 os.execute("mkdir -p " .. target)
235
236 wt.save_hook_permissions({ ["/project4"] = true }, home)
237
238 local hooks = { run = { "touch ran-hook.txt" } }
239 wt.run_hooks(source, target, hooks, "/project4", home)
240
241 local ran = io.open(target .. "/ran-hook.txt", "r")
242 assert.is_not_nil(ran)
243 if ran then
244 ran:close()
245 end
246 end)
247 end)
248
249 describe("permission denied", function()
250 it("skips hooks when permission is false", function()
251 if not temp_dir then
252 pending("temp_dir not available")
253 return
254 end
255 local source = temp_dir .. "/source5"
256 local target = temp_dir .. "/target5"
257 local home = temp_dir .. "/home5"
258 os.execute("mkdir -p " .. source)
259 os.execute("mkdir -p " .. target)
260
261 local f = io.open(source .. "/shouldnt-copy.txt", "w")
262 if f then
263 f:write("content\n")
264 f:close()
265 end
266
267 wt.save_hook_permissions({ ["/project5"] = false }, home)
268
269 local hooks = { copy = { "shouldnt-copy.txt" } }
270 wt.run_hooks(source, target, hooks, "/project5", home)
271
272 local not_copied = io.open(target .. "/shouldnt-copy.txt", "r")
273 assert.is_nil(not_copied)
274 end)
275 end)
276end)