1--
2-- tests/testfx.lua
3-- Automated test framework for Premake.
4-- Copyright (c) 2008-2009 Jason Perkins and the Premake project
5--
6
7
8--
9-- Define a namespace for the testing functions
10--
11
12	test = { }
13
14
15--
16-- Assertion functions
17--
18	function test.string_contains(buffer, expected)
19		if not string.find(buffer,expected) then
20			test.fail("\n==Fail==: Expected to find :\n%s\nyet it was not found in buffer:\n%s\n", expected,buffer)
21		end
22	end
23
24	function test.string_does_not_contain(buffer, expected)
25		if string.find(buffer,expected) then
26			test.fail("\n==Fail==: Did not expected to find :\n%s\nyet it was found in buffer:\n%s\n", expected,buffer)
27		end
28	end
29
30	function test.capture(expected)
31		local actual = io.endcapture()
32
33		local ait = actual:gfind("(.-)" .. io.eol)
34		local eit = expected:gfind("(.-)\n")
35
36		local linenum = 1
37		local atxt = ait()
38		local etxt = eit()
39		while etxt do
40			if (etxt ~= atxt) then
41				test.fail("(%d) expected:\n%s\n...but was:\n%s", linenum, etxt, atxt)
42			end
43
44			linenum = linenum + 1
45			atxt = ait()
46			etxt = eit()
47		end
48	end
49
50
51	function test.closedfile(expected)
52		if expected and not test.value_closedfile then
53			test.fail("expected file to be closed")
54		elseif not expected and test.value_closedfile then
55			test.fail("expected file to remain open")
56		end
57	end
58
59
60	function test.contains(value, expected)
61		if not table.contains(value, expected) then
62			test.fail("expected value %s not found", expected)
63		end
64	end
65
66
67	function test.fail(format, ...)
68		-- convert nils into something more usefuls
69		for i = 1, arg.n do
70			if (arg[i] == nil) then
71				arg[i] = "(nil)"
72			elseif (type(arg[i]) == "table") then
73				arg[i] = "{" .. table.concat(arg[i], ", ") .. "}"
74			end
75		end
76		error(string.format(format, unpack(arg)), 3)
77	end
78
79
80	function test.filecontains(expected, fn)
81		local f = io.open(fn)
82		local actual = f:read("*a")
83		f:close()
84		if (expected ~= actual) then
85			test.fail("expected %s but was %s", expected, actual)
86		end
87	end
88
89
90	function test.isemptycapture()
91		local actual = io.endcapture()
92		if actual ~= "" then
93			test.fail("expected empty capture, but was %s", actual);
94		end
95	end
96
97
98	function test.isequal(expected, actual)
99		if (type(expected) == "table") then
100			for k,v in pairs(expected) do
101				if not (test.isequal(expected[k], actual[k])) then
102					test.fail("expected %s but was %s", expected, actual)
103				end
104			end
105		else
106			if (expected ~= actual) then
107				test.fail("expected %s but was %s", expected, actual)
108			end
109		end
110		return true
111	end
112
113
114	function test.isfalse(value)
115		if (value) then
116			test.fail("expected false but was true")
117		end
118	end
119
120
121	function test.isnil(value)
122		if (value ~= nil) then
123			test.fail("expected nil but was " .. tostring(value))
124		end
125	end
126
127
128	function test.isnotnil(value)
129		if (value == nil) then
130			test.fail("expected not nil")
131		end
132	end
133
134
135	function test.istrue(value)
136		if (not value) then
137			test.fail("expected true but was false")
138		end
139	end
140
141
142	function test.openedfile(fname)
143		if fname ~= test.value_openedfilename then
144			local msg = "expected to open file '" .. fname .. "'"
145			if test.value_openedfilename then
146				msg = msg .. ", got '" .. test.value_openedfilename .. "'"
147			end
148			test.fail(msg)
149		end
150	end
151
152
153	function test.success(fn, ...)
154		local ok, err = pcall(fn, unpack(arg))
155		if not ok then
156			test.fail("call failed: " .. err)
157		end
158	end
159
160
161
162--
163-- Test stubs
164--
165
166	local function stub_io_open(fname, mode)
167		test.value_openedfilename = fname
168		test.value_openedfilemode = mode
169		return {
170			close = function()
171				test.value_closedfile = true
172			end
173		}
174	end
175
176	local function stub_io_output(f)
177	end
178
179	local function stub_print(s)
180	end
181
182
183--
184-- Define a collection for the test suites
185--
186
187	T = { }
188
189
190
191--
192-- Test execution function
193--
194	local _OS_host = _OS
195	local function test_setup(suite, fn)
196		-- clear out some important globals
197		_ACTION = "test"
198		_ARGS = { }
199		_OPTIONS = { }
200		_OS = _OS_host
201		premake.solution.list = { }
202		io.indent = nil
203		io.eol = "\n"
204
205		-- reset captured I/O values
206		test.value_openedfilename = nil
207		test.value_openedfilemode = nil
208		test.value_closedfile = false
209
210		if suite.setup then
211			return pcall(suite.setup)
212		else
213			return true
214		end
215	end
216
217
218	local function test_run(suite, fn)
219		io.capture()
220		return pcall(fn)
221	end
222
223
224	local function test_teardown(suite, fn)
225		if suite.teardown then
226			return pcall(suite.teardown)
227		else
228			return true
229		end
230	end
231
232
233	function test.runall(suitename, testname)
234		test.print = print
235
236		print      = stub_print
237		io.open    = stub_io_open
238		io.output  = stub_io_output
239
240		local numpassed = 0
241		local numfailed = 0
242		local start_time = os.clock()
243
244		function runtest(suitename, suitetests, testname, testfunc)
245			if suitetests.setup ~= testfunc and suitetests.teardown ~= testfunc then
246				local ok, err = test_setup(suitetests, testfunc)
247
248				if ok then
249					ok, err = test_run(suitetests, testfunc)
250				end
251
252				local tok, terr = test_teardown(suitetests, testfunc)
253				ok = ok and tok
254				err = err or terr
255
256				if (not ok) then
257					test.print(string.format("%s.%s: %s", suitename, testname, err))
258					numfailed = numfailed + 1
259				else
260					numpassed = numpassed + 1
261				end
262			end
263		end
264
265		function runsuite(suitename, suitetests, testname)
266			if testname then
267				runtest(suitename, suitetests, testname, suitetests[testname])
268			else
269				for testname, testfunc in pairs(suitetests) do
270					runtest(suitename, suitetests, testname, testfunc)
271				end
272			end
273		end
274
275		if suitename then
276			runsuite(suitename, T[suitename], testname)
277		else
278			for suitename, suitetests in pairs(T) do
279				runsuite(suitename, suitetests, testname)
280			end
281		end
282
283        io.write('running time : ',  os.clock() - start_time,'\n')
284		print = test.print
285		return numpassed, numfailed
286	end
287
288