1-- Load main.lua as a module (it exports functions when required)
2package.path = package.path .. ";./?.lua"
3local wt = dofile("src/main.lua")
4
5describe("load_global_config", function()
6 local temp_dir
7
8 setup(function()
9 -- Create temp directory for test configs
10 local handle = io.popen("mktemp -d")
11 if handle then
12 temp_dir = handle:read("*l")
13 handle:close()
14 end
15 end)
16
17 teardown(function()
18 -- Restore HOME and clean up
19 if temp_dir then
20 os.execute("rm -rf " .. temp_dir)
21 end
22 end)
23
24 describe("with no config file", function()
25 it("returns empty table when config file missing", function()
26 local config = wt.load_global_config()
27 assert.is_table(config)
28 end)
29 end)
30
31 describe("config file format", function()
32 -- Note: These tests document expected behavior but can't easily
33 -- override HOME in the running process. They serve as specification.
34
35 it("accepts simple table config", function()
36 -- Expected: { branch_path_style = "flat" }
37 -- The loader prepends "return " so file should NOT have return
38 local config = wt.load_global_config()
39 assert.is_table(config)
40 end)
41 end)
42end)
43
44describe("load_project_config", function()
45 local temp_dir
46
47 setup(function()
48 local handle = io.popen("mktemp -d")
49 if handle then
50 temp_dir = handle:read("*l")
51 handle:close()
52 end
53 end)
54
55 teardown(function()
56 if temp_dir then
57 os.execute("rm -rf " .. temp_dir)
58 end
59 end)
60
61 describe("with no config file", function()
62 it("returns empty table for nonexistent path", function()
63 local config = wt.load_project_config("/nonexistent/path")
64 assert.are.same({}, config)
65 end)
66
67 it("returns empty table for directory without .wt.lua", function()
68 local config = wt.load_project_config(temp_dir)
69 assert.are.same({}, config)
70 end)
71 end)
72
73 describe("with valid config file", function()
74 it("loads hooks configuration", function()
75 if not temp_dir then
76 pending("temp_dir not available")
77 return
78 end
79 -- Write a test config
80 local config_path = temp_dir .. "/.wt.lua"
81 local f = io.open(config_path, "w")
82 if f then
83 f:write([[{
84 hooks = {
85 copy = { ".env.example" },
86 symlink = { "node_modules" },
87 run = { "npm install" },
88 }
89}]])
90 f:close()
91
92 local config = wt.load_project_config(temp_dir)
93 assert.is_table(config.hooks)
94 assert.are.same({ ".env.example" }, config.hooks.copy)
95 assert.are.same({ "node_modules" }, config.hooks.symlink)
96 assert.are.same({ "npm install" }, config.hooks.run)
97
98 os.remove(config_path)
99 else
100 pending("could not write test config")
101 end
102 end)
103
104 it("loads branch_path_style from project config", function()
105 if not temp_dir then
106 pending("temp_dir not available")
107 return
108 end
109 local config_path = temp_dir .. "/.wt.lua"
110 local f = io.open(config_path, "w")
111 if f then
112 f:write([[{ branch_path_style = "flat", flat_separator = "-" }]])
113 f:close()
114
115 local config = wt.load_project_config(temp_dir)
116 assert.are.equal("flat", config.branch_path_style)
117 assert.are.equal("-", config.flat_separator)
118
119 os.remove(config_path)
120 else
121 pending("could not write test config")
122 end
123 end)
124 end)
125
126 describe("error handling", function()
127 it("returns empty table for syntax error in config", function()
128 if not temp_dir then
129 pending("temp_dir not available")
130 return
131 end
132 local config_path = temp_dir .. "/.wt.lua"
133 local f = io.open(config_path, "w")
134 if f then
135 f:write([[{ invalid syntax here !!!]])
136 f:close()
137
138 local config = wt.load_project_config(temp_dir)
139 assert.are.same({}, config)
140
141 os.remove(config_path)
142 else
143 pending("could not write test config")
144 end
145 end)
146
147 it("returns empty table for runtime error in config", function()
148 if not temp_dir then
149 pending("temp_dir not available")
150 return
151 end
152 local config_path = temp_dir .. "/.wt.lua"
153 local f = io.open(config_path, "w")
154 if f then
155 f:write([[{ value = undefined_var + 1 }]])
156 f:close()
157
158 local config = wt.load_project_config(temp_dir)
159 assert.are.same({}, config)
160
161 os.remove(config_path)
162 else
163 pending("could not write test config")
164 end
165 end)
166
167 it("returns empty table when config returns non-table", function()
168 if not temp_dir then
169 pending("temp_dir not available")
170 return
171 end
172 local config_path = temp_dir .. "/.wt.lua"
173 local f = io.open(config_path, "w")
174 if f then
175 f:write([["just a string"]])
176 f:close()
177
178 local config = wt.load_project_config(temp_dir)
179 assert.are.same({}, config)
180
181 os.remove(config_path)
182 else
183 pending("could not write test config")
184 end
185 end)
186
187 it("loads config with leading comment", function()
188 if not temp_dir then
189 pending("temp_dir not available")
190 return
191 end
192 local config_path = temp_dir .. "/.wt.lua"
193 local f = io.open(config_path, "w")
194 if f then
195 f:write([[-- my config comment
196{ branch_path_style = "flat" }]])
197 f:close()
198
199 local config = wt.load_project_config(temp_dir)
200 assert.are.equal("flat", config.branch_path_style)
201
202 os.remove(config_path)
203 else
204 pending("could not write test config")
205 end
206 end)
207
208 it("loads config with explicit return", function()
209 if not temp_dir then
210 pending("temp_dir not available")
211 return
212 end
213 local config_path = temp_dir .. "/.wt.lua"
214 local f = io.open(config_path, "w")
215 if f then
216 f:write([[return { branch_path_style = "flat" }]])
217 f:close()
218
219 local config = wt.load_project_config(temp_dir)
220 assert.are.equal("flat", config.branch_path_style)
221
222 os.remove(config_path)
223 else
224 pending("could not write test config")
225 end
226 end)
227 end)
228
229 describe("sandboxed environment", function()
230 it("cannot access os module in config", function()
231 if not temp_dir then
232 pending("temp_dir not available")
233 return
234 end
235 local config_path = temp_dir .. "/.wt.lua"
236 local f = io.open(config_path, "w")
237 if f then
238 f:write([[{ home = os.getenv("HOME") }]])
239 f:close()
240
241 local config = wt.load_project_config(temp_dir)
242 -- Returns empty table due to runtime error (os is nil)
243 assert.are.same({}, config)
244
245 os.remove(config_path)
246 else
247 pending("could not write test config")
248 end
249 end)
250 end)
251end)