Several bug fixes from Charles Crain.
[scons.git] / src / engine / SCons / ActionTests.py
1 #
2 # Copyright (c) 2001, 2002 Steven Knight
3 #
4 # Permission is hereby granted, free of charge, to any person obtaining
5 # a copy of this software and associated documentation files (the
6 # "Software"), to deal in the Software without restriction, including
7 # without limitation the rights to use, copy, modify, merge, publish,
8 # distribute, sublicense, and/or sell copies of the Software, and to
9 # permit persons to whom the Software is furnished to do so, subject to
10 # the following conditions:
11  
12 # The above copyright notice and this permission notice shall be included
13 # in all copies or substantial portions of the Software.
14 #
15 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
16 # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
17 # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19 # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20 # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21 # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 #
23
24 __revision__ = "src/engine/SCons/ActionTests.py __REVISION__ __DATE__ __DEVELOPER__"
25
26 # Define a null function for use as a builder action.
27 # Where this is defined in the file seems to affect its
28 # byte-code contents, so try to minimize changes by
29 # defining it here, before we even import anything.
30 def Func():
31     pass
32
33 import sys
34 import types
35 import unittest
36
37 import SCons.Action
38 import TestCmd
39
40 class ActionTestCase(unittest.TestCase):
41
42     def runTest(self):
43         """Test the Action factory
44         """
45         def foo():
46             pass
47         a1 = SCons.Action.Action(foo)
48         assert isinstance(a1, SCons.Action.FunctionAction), a1
49
50         a2 = SCons.Action.Action("string")
51         assert isinstance(a2, SCons.Action.CommandAction), a2
52
53         if hasattr(types, 'UnicodeType'):
54             exec "a3 = SCons.Action.Action(u'string')"
55             exec "assert isinstance(a3, SCons.Action.CommandAction), a3"
56
57         a4 = SCons.Action.Action(["x", "y", "z", [ "a", "b", "c"]])
58         assert isinstance(a4, SCons.Action.ListAction), a4
59         assert isinstance(a4.list[0], SCons.Action.CommandAction), a4.list[0]
60         assert isinstance(a4.list[1], SCons.Action.CommandAction), a4.list[1]
61         assert isinstance(a4.list[2], SCons.Action.CommandAction), a4.list[2]
62         assert isinstance(a4.list[3], SCons.Action.CommandAction), a4.list[3]
63         assert a4.list[3].cmd_list == [ "a", "b", "c" ], a4.list[3].cmd_list
64
65         a5 = SCons.Action.Action(1)
66         assert a5 is None, a5
67
68         a6 = SCons.Action.Action(a1)
69         assert a6 is a1, a6
70
71         a7 = SCons.Action.Action([[ "explicit", "command", "line" ]])
72         assert isinstance(a7, SCons.Action.CommandAction), a7
73         assert a7.cmd_list == [ "explicit", "command", "line" ], a7.cmd_list
74
75         a8 = SCons.Action.Action(["a8"])
76         assert isinstance(a8, SCons.Action.CommandAction), a8
77         assert a8.cmd_list == [ "a8" ], a8.cmd_list
78
79 class ActionBaseTestCase(unittest.TestCase):
80
81     def test_cmp(self):
82         """Test Action comparison
83         """
84         a1 = SCons.Action.Action("x")
85         a2 = SCons.Action.Action("x")
86         assert a1 == a2
87         a3 = SCons.Action.Action("y")
88         assert a1 != a3
89         assert a2 != a3
90
91     def test_subst_dict(self):
92         """Test substituting dictionary values in an Action
93         """
94         a = SCons.Action.Action("x")
95
96         d = a.subst_dict(env = {'a' : 'A', 'b' : 'B'})
97         assert d['a'] == 'A', d
98         assert d['b'] == 'B', d
99
100         d = a.subst_dict(target = 't', source = 's')
101         assert str(d['TARGETS']) == 't', d['TARGETS']
102         assert str(d['TARGET']) == 't', d['TARGET']
103         assert str(d['SOURCES']) == 's', d['SOURCES']
104         assert str(d['SOURCE']) == 's', d['SOURCE']
105
106
107         d = a.subst_dict(target = ['t1', 't2'], source = ['s1', 's2'])
108         TARGETS = map(lambda x: str(x), d['TARGETS'])
109         TARGETS.sort()
110         assert TARGETS == ['t1', 't2'], d['TARGETS']
111         assert str(d['TARGET']) == 't1', d['TARGET']
112         SOURCES = map(lambda x: str(x), d['SOURCES'])
113         SOURCES.sort()
114         assert SOURCES == ['s1', 's2'], d['SOURCES']
115         assert str(d['SOURCE']) == 's1', d['SOURCE']
116
117 class CommandActionTestCase(unittest.TestCase):
118
119     def test_init(self):
120         """Test creation of a command Action
121         """
122         a = SCons.Action.CommandAction(["xyzzy"])
123         assert a.cmd_list == [ "xyzzy" ], a.cmd_list
124
125     def test_execute(self):
126         """Test executing a command Action
127         """
128         self.test_set_handler()
129         pass
130
131     def test_set_handler(self):
132         """Test setting the command handler...
133         """
134         class Test:
135             def __init__(self):
136                 self.executed = 0
137         t=Test()
138         def func(cmd, args, env, test=t):
139             test.executed = 1
140             return 0
141         SCons.Action.SetCommandHandler(func)
142         assert SCons.Action.spawn is func
143         a = SCons.Action.CommandAction(["xyzzy"])
144         a.execute()
145         assert t.executed == 1
146
147     def test_get_raw_contents(self):
148         """Test fetching the contents of a command Action
149         """
150         a = SCons.Action.CommandAction(["|", "$(", "$foo", "|", "$bar",
151                                         "$)", "|"])
152         c = a.get_contents(target=[], source=[],
153                            foo = 'FFF', bar = 'BBB')
154         assert c == "| $( FFF | BBB $) |"
155
156     def test_get_contents(self):
157         """Test fetching the contents of a command Action
158         """
159         a = SCons.Action.CommandAction(["|", "$(", "$foo", "|", "$bar",
160                                         "$)", "|"])
161         c = a.get_contents(target=[], source=[],
162                            foo = 'FFF', bar = 'BBB')
163         assert c == "| |", c
164
165 class CommandGeneratorActionTestCase(unittest.TestCase):
166
167     def test_init(self):
168         """Test creation of a command generator Action
169         """
170         def f(target, source, env):
171             pass
172         a = SCons.Action.CommandGeneratorAction(f)
173         assert a.generator == f
174
175     def test_execute(self):
176         """Test executing a command generator Action
177         """
178
179         def f(dummy, env, self=self):
180             self.dummy = dummy
181             assert env.subst("$FOO $( bar $) baz") == 'foo baz\nbar ack bar baz', env.subst("$FOO $( bar $) baz")
182             assert env.subst("$FOO $( bar $) baz", raw=1) == 'foo baz\nbar ack $( bar $) baz', env.subst("$FOO $( bar $) baz", raw=1)
183             assert env.subst_list("$FOO $( bar $) baz") == [ [ 'foo', 'baz' ],
184                                                              [ 'bar', 'ack', 'bar', 'baz' ] ], env.subst_list("$FOO $( bar $) baz")
185             assert env.subst_list("$FOO $( bar $) baz",
186                                   raw=1) == [ [ 'foo', 'baz' ],
187                                               [ 'bar', 'ack', '$(', 'bar', '$)', 'baz' ] ], env.subst_list("$FOO $( bar $) baz", raw=1)
188             return "$FOO"
189         def func_action(env, dummy, self=self):
190             assert env.subst('$foo $( bar $)') == 'bar bar', env.subst('$foo $( bar $)')
191             assert env.subst('$foo $( bar $)',
192                              raw=1) == 'bar $( bar $)', env.subst('$foo $( bar $)', raw=1)
193             assert env.subst_list([ '$foo', '$(', 'bar', '$)' ]) == [[ 'bar', 'bar' ]], env.subst_list([ '$foo', '$(', 'bar', '$)' ])
194             assert env.subst_list([ '$foo', '$(', 'bar', '$)' ],
195                                   raw=1) == [[ 'bar', '$(', 'bar', '$)' ]], env.subst_list([ '$foo', '$(', 'bar', '$)' ], raw=1)
196             self.dummy=dummy
197         def f2(dummy, env, f=func_action):
198             return f
199         def ch(cmd, args, env, self=self):
200             self.cmd.append(cmd)
201             self.args.append(args)
202
203         a = SCons.Action.CommandGeneratorAction(f)
204         self.dummy = 0
205         old_hdl = SCons.Action.GetCommandHandler()
206         self.cmd = []
207         self.args = []
208         try:
209             SCons.Action.SetCommandHandler(ch)
210             a.execute(dummy=1, env={ 'FOO' : 'foo baz\nbar ack' })
211         finally:
212             SCons.Action.SetCommandHandler(old_hdl)
213         assert self.dummy == 1
214         assert self.cmd == [ 'foo', 'bar'], self.cmd
215         assert self.args == [ [ 'foo', 'baz' ], [ 'bar', 'ack' ] ], self.args
216
217         b=SCons.Action.CommandGeneratorAction(f2)
218         self.dummy = 0
219         b.execute(dummy=2, env={ 'foo' : 'bar' })
220         assert self.dummy==2, self.dummy
221         del self.dummy
222
223     def test_get_contents(self):
224         """Test fetching the contents of a command generator Action
225         """
226         def f(target, source, foo, bar):
227             return [["guux", foo, "$(", "ignore", "$)", bar]]
228
229         a = SCons.Action.CommandGeneratorAction(f)
230         c = a.get_contents(target=[], source=[],
231                            foo = 'FFF', bar = 'BBB')
232         assert c == "guux FFF BBB", c
233
234
235 class FunctionActionTestCase(unittest.TestCase):
236
237     def test_init(self):
238         """Test creation of a function Action
239         """
240         def func():
241             pass
242         a = SCons.Action.FunctionAction(func)
243         assert a.function == func
244
245     def test_execute(self):
246         """Test executing a function Action
247         """
248         self.inc = 0
249         def f(s, target, source, env):
250             s.inc = s.inc + 1
251             s.target = target
252             s.source=source
253             assert env.subst("foo$BAR") == 'foofoo bar', env.subst("foo$BAR")
254             assert env.subst_list("foo$BAR") == [ [ 'foofoo', 'bar' ] ], \
255                    env.subst_list("foo$BAR")
256             return 0
257         a = SCons.Action.FunctionAction(f)
258         a.execute(s = self, target=1, source=2, env={'BAR':'foo bar'})
259         assert self.inc == 1, self.inc
260         assert self.source == [2], self.source
261         assert self.target == [1], self.target
262
263     def test_get_contents(self):
264         """Test fetching the contents of a function Action
265         """
266         a = SCons.Action.FunctionAction(Func)
267         c = a.get_contents(target=[], source=[])
268         assert c == "\177\036\000\177\037\000d\000\000S", repr(c)
269
270 class ListActionTestCase(unittest.TestCase):
271
272     def test_init(self):
273         """Test creation of a list of subsidiary Actions
274         """
275         def func():
276             pass
277         a = SCons.Action.ListAction(["x", func, ["y", "z"]])
278         assert isinstance(a.list[0], SCons.Action.CommandAction)
279         assert isinstance(a.list[1], SCons.Action.FunctionAction)
280         assert isinstance(a.list[2], SCons.Action.ListAction)
281         assert a.list[2].list[0].cmd_list == [ 'y' ]
282
283     def test_execute(self):
284         """Test executing a list of subsidiary Actions
285         """
286         self.inc = 0
287         def f(s):
288             s.inc = s.inc + 1
289             return 0
290         a = SCons.Action.ListAction([f, f, f])
291         a.execute(s = self)
292         assert self.inc == 3, self.inc
293
294     def test_get_contents(self):
295         """Test fetching the contents of a list of subsidiary Actions
296         """
297         a = SCons.Action.ListAction(["x", "y", "z"])
298         c = a.get_contents(target=[], source=[])
299         assert c == "xyz", c
300
301 class LazyActionTestCase(unittest.TestCase):
302     def test_init(self):
303         """Test creation of a lazy-evaluation Action
304         """
305         # Environment variable references should create a special
306         # type of CommandGeneratorAction that lazily evaluates the
307         # variable.
308         a9 = SCons.Action.Action('$FOO')
309         assert isinstance(a9, SCons.Action.CommandGeneratorAction), a9
310         assert a9.generator.var == 'FOO', a9.generator.var
311
312         a10 = SCons.Action.Action('${FOO}')
313         assert isinstance(a9, SCons.Action.CommandGeneratorAction), a10
314         assert a10.generator.var == 'FOO', a10.generator.var
315
316     def test_execute(self):
317         """Test executing a lazy-evalueation Action
318         """
319         def f(s, env):
320             s.test=1
321             return 0
322         a = SCons.Action.Action('$BAR')
323         a.execute(s = self, env={'BAR':f})
324         assert self.test == 1, self.test
325
326     def test_get_contents(self):
327         """Test fetching the contents of a lazy-evaluation Action
328         """
329         a = SCons.Action.Action("${FOO}")
330         c = a.get_contents(target=[], source=[],
331                            env={'FOO':[["This", "is", "$(", "a", "$)", "test"]]})
332         assert c == "This is test", c
333
334
335 if __name__ == "__main__":
336     suite = unittest.TestSuite()
337     suite.addTest(ActionTestCase())
338     suite.addTest(ActionBaseTestCase("test_cmp"))
339     suite.addTest(ActionBaseTestCase("test_subst_dict"))
340     for tclass in [CommandActionTestCase,
341                    CommandGeneratorActionTestCase,
342                    FunctionActionTestCase,
343                    ListActionTestCase,
344                    LazyActionTestCase]:
345         for func in ["test_init", "test_execute", "test_get_contents"]:
346             suite.addTest(tclass(func))
347     if not unittest.TextTestRunner().run(suite).wasSuccessful():
348         sys.exit(1)