config_spec.lua

  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)