aaafa0704550a5403ec7b400b8f75989c874997d
[scons.git] / src / engine / SCons / ExecutorTests.py
1 #
2 # __COPYRIGHT__
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__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
25
26 import sys
27 import unittest
28
29 import SCons.Executor
30
31
32 class MyEnvironment:
33     def __init__(self, **kw):
34         self._dict = {}
35         self._dict.update(kw)
36     def __getitem__(self, key):
37         return self._dict[key]
38     def Override(self, overrides):
39         d = self._dict.copy()
40         d.update(overrides)
41         return MyEnvironment(**d)
42     def _update(self, dict):
43         self._dict.update(dict)
44
45 class MyAction:
46     def __init__(self, actions=['action1', 'action2']):
47         self.actions = actions
48     def __call__(self, target, source, env, **kw):
49         for action in self.actions:
50             action(target, source, env, **kw)
51     def genstring(self, target, source, env):
52         return ' '.join(['GENSTRING'] + list(map(str, self.actions)) + target + source)
53     def get_contents(self, target, source, env):
54         return ' '.join(self.actions + target + source)
55     def get_implicit_deps(self, target, source, env):
56         return []
57
58 class MyBuilder:
59     def __init__(self, env, overrides):
60         self.env = env
61         self.overrides = overrides
62         self.action = MyAction()
63
64 class MyNode:
65     def __init__(self, name=None, pre=[], post=[]):
66         self.name = name
67         self.implicit = []
68         self.pre_actions = pre
69         self.post_actions = post
70         self.missing_val = None
71     def __str__(self):
72         return self.name
73     def build(self):
74         executor = SCons.Executor.Executor(MyAction(self.pre_actions +
75                                                     [self.builder.action] +
76                                                     self.post_actions),
77                                            self.builder.env,
78                                            [],
79                                            [self],
80                                            ['s1', 's2'])
81         executor(self)
82     def get_env_scanner(self, env, kw):
83         return MyScanner('dep-')
84     def get_implicit_deps(self, env, scanner, path):
85         return [scanner.prefix + str(self)]
86     def add_to_implicit(self, deps):
87         self.implicit.extend(deps)
88     def missing(self):
89         return self.missing_val
90     def calc_signature(self, calc):
91         return 'cs-'+calc+'-'+self.name
92     def disambiguate(self):
93         return self
94
95 class MyScanner:
96     def __init__(self, prefix):
97         self.prefix = prefix
98     def path(self, env, cwd, target, source):
99         return ()
100     def select(self, node):
101         return self
102
103 class ExecutorTestCase(unittest.TestCase):
104
105     def test__init__(self):
106         """Test creating an Executor"""
107         source_list = ['s1', 's2']
108         x = SCons.Executor.Executor('a', 'e', ['o'], 't', source_list)
109         assert x.action_list == ['a'], x.action_list
110         assert x.env == 'e', x.env
111         assert x.overridelist == ['o'], x.overridelist
112         targets = x.get_all_targets()
113         assert targets == ['t'], targets
114         source_list.append('s3')
115         sources = x.get_all_sources()
116         assert sources == ['s1', 's2'], sources
117         try:
118             x = SCons.Executor.Executor(None, 'e', ['o'], 't', source_list)
119         except SCons.Errors.UserError:
120             pass
121         else:
122             raise "Did not catch expected UserError"
123
124     def test__action_list(self):
125         """Test the {get,set}_action_list() methods"""
126         x = SCons.Executor.Executor('a', 'e', 'o', 't', ['s1', 's2'])
127
128         l = x.get_action_list()
129         assert l == ['a'], l
130
131         x.add_pre_action('pre')
132         x.add_post_action('post')
133         l = x.get_action_list()
134         assert l == ['pre', 'a', 'post'], l
135
136         x.set_action_list('b')
137         l = x.get_action_list()
138         assert l == ['pre', 'b', 'post'], l
139
140         x.set_action_list(['c'])
141         l = x.get_action_list()
142         assert l == ['pre', 'c', 'post'], l
143
144     def test_get_build_env(self):
145         """Test fetching and generating a build environment"""
146         x = SCons.Executor.Executor(MyAction(), MyEnvironment(e=1), [],
147                                     't', ['s1', 's2'])
148         x.env = MyEnvironment(eee=1)
149         be = x.get_build_env()
150         assert be['eee'] == 1, be
151
152         env = MyEnvironment(X='xxx')
153         x = SCons.Executor.Executor(MyAction(),
154                                     env,
155                                     [{'O':'o2'}],
156                                     't',
157                                     ['s1', 's2'])
158         be = x.get_build_env()
159         assert be['O'] == 'o2', be['O']
160         assert be['X'] == 'xxx', be['X']
161
162         env = MyEnvironment(Y='yyy')
163         overrides = [{'O':'ob3'}, {'O':'oo3'}]
164         x = SCons.Executor.Executor(MyAction(), env, overrides, ['t'], ['s'])
165         be = x.get_build_env()
166         assert be['O'] == 'oo3', be['O']
167         assert be['Y'] == 'yyy', be['Y']
168         overrides = [{'O':'ob3'}]
169         x = SCons.Executor.Executor(MyAction(), env, overrides, ['t'], ['s'])
170         be = x.get_build_env()
171         assert be['O'] == 'ob3', be['O']
172         assert be['Y'] == 'yyy', be['Y']
173
174     def test_get_build_scanner_path(self):
175         """Test fetching the path for the specified scanner."""
176         t = MyNode('t')
177         t.cwd = 'here'
178         x = SCons.Executor.Executor(MyAction(),
179                                     MyEnvironment(SCANNERVAL='sss'),
180                                     [],
181                                     [t],
182                                     ['s1', 's2'])
183
184         class LocalScanner:
185             def path(self, env, dir, target, source):
186                 target = list(map(str, target))
187                 source = list(map(str, source))
188                 return "scanner: %s, %s, %s, %s" % (env['SCANNERVAL'], dir, target, source)
189         s = LocalScanner()
190
191         p = x.get_build_scanner_path(s)
192         assert p == "scanner: sss, here, ['t'], ['s1', 's2']", p
193
194     def test_get_kw(self):
195         """Test the get_kw() method"""
196         t = MyNode('t')
197         x = SCons.Executor.Executor(MyAction(),
198                                     MyEnvironment(),
199                                     [],
200                                     [t],
201                                     ['s1', 's2'],
202                                     builder_kw={'X':1, 'Y':2})
203         kw = x.get_kw()
204         assert kw == {'X':1, 'Y':2, 'executor':x}, kw
205         kw = x.get_kw({'Z':3})
206         assert kw == {'X':1, 'Y':2, 'Z':3, 'executor':x}, kw
207         kw = x.get_kw({'X':4})
208         assert kw == {'X':4, 'Y':2, 'executor':x}, kw
209
210     def test__call__(self):
211         """Test calling an Executor"""
212         result = []
213         def pre(target, source, env, result=result, **kw):
214             result.append('pre')
215         def action1(target, source, env, result=result, **kw):
216             result.append('action1')
217         def action2(target, source, env, result=result, **kw):
218             result.append('action2')
219         def post(target, source, env, result=result, **kw):
220             result.append('post')
221
222         env = MyEnvironment()
223         a = MyAction([action1, action2])
224         t = MyNode('t')
225
226         x = SCons.Executor.Executor(a, env, [], [t], ['s1', 's2'])
227         x.add_pre_action(pre)
228         x.add_post_action(post)
229         x(t)
230         assert result == ['pre', 'action1', 'action2', 'post'], result
231         del result[:]
232
233         def pre_err(target, source, env, result=result, **kw):
234             result.append('pre_err')
235             return 1
236
237         x = SCons.Executor.Executor(a, env, [], [t], ['s1', 's2'])
238         x.add_pre_action(pre_err)
239         x.add_post_action(post)
240         try:
241             x(t)
242         except SCons.Errors.BuildError:
243             pass
244         else:
245             raise Exception, "Did not catch expected BuildError"
246         assert result == ['pre_err'], result
247         del result[:]
248
249     def test_cleanup(self):
250         """Test cleaning up an Executor"""
251         orig_env = MyEnvironment(e=1)
252         x = SCons.Executor.Executor('b', orig_env, [{'o':1}],
253                                     't', ['s1', 's2'])
254
255         be = x.get_build_env()
256         assert be['e'] == 1, be['e']
257         
258         x.cleanup()
259
260         x.env = MyEnvironment(eee=1)
261         be = x.get_build_env()
262         assert be['eee'] == 1, be['eee']
263
264         x.cleanup()
265
266         be = x.get_build_env()
267         assert be['eee'] == 1, be['eee']
268
269     def test_add_sources(self):
270         """Test adding sources to an Executor"""
271         x = SCons.Executor.Executor('b', 'e', 'o', 't', ['s1', 's2'])
272         sources = x.get_all_sources()
273         assert sources == ['s1', 's2'], sources
274
275         x.add_sources(['s1', 's2'])
276         sources = x.get_all_sources()
277         assert sources == ['s1', 's2'], sources
278
279         x.add_sources(['s3', 's1', 's4'])
280         sources = x.get_all_sources()
281         assert sources == ['s1', 's2', 's3', 's4'], sources
282
283     def test_get_sources(self):
284         """Test getting sources from an Executor"""
285         x = SCons.Executor.Executor('b', 'e', 'o', 't', ['s1', 's2'])
286         sources = x.get_sources()
287         assert sources == ['s1', 's2'], sources
288
289         x.add_sources(['s1', 's2'])
290         sources = x.get_sources()
291         assert sources == ['s1', 's2'], sources
292
293         x.add_sources(['s3', 's1', 's4'])
294         sources = x.get_sources()
295         assert sources == ['s1', 's2', 's3', 's4'], sources
296
297     def test_prepare(self):
298         """Test the Executor's prepare() method"""
299         env = MyEnvironment()
300         t1 = MyNode('t1')
301         s1 = MyNode('s1')
302         s2 = MyNode('s2')
303         s3 = MyNode('s3')
304         x = SCons.Executor.Executor('b', env, [{}], [t1], [s1, s2, s3])
305
306         s2.missing_val = True
307
308         try:
309             r = x.prepare()
310         except SCons.Errors.StopError, e:
311             assert str(e) == "Source `s2' not found, needed by target `t1'.", e
312         else:
313             raise AssertionError, "did not catch expected StopError: %s" % r
314
315     def test_add_pre_action(self):
316         """Test adding pre-actions to an Executor"""
317         x = SCons.Executor.Executor('b', 'e', 'o', 't', ['s1', 's2'])
318         x.add_pre_action('a1')
319         assert x.pre_actions == ['a1']
320         x.add_pre_action('a2')
321         assert x.pre_actions == ['a1', 'a2']
322
323     def test_add_post_action(self):
324         """Test adding post-actions to an Executor"""
325         x = SCons.Executor.Executor('b', 'e', 'o', 't', ['s1', 's2'])
326         x.add_post_action('a1')
327         assert x.post_actions == ['a1']
328         x.add_post_action('a2')
329         assert x.post_actions == ['a1', 'a2']
330
331     def test___str__(self):
332         """Test the __str__() method"""
333         env = MyEnvironment(S='string')
334
335         x = SCons.Executor.Executor(MyAction(), env, [], ['t'], ['s'])
336         c = str(x)
337         assert c == 'GENSTRING action1 action2 t s', c
338
339         x = SCons.Executor.Executor(MyAction(), env, [], ['t'], ['s'])
340         x.add_pre_action(MyAction(['pre']))
341         x.add_post_action(MyAction(['post']))
342         c = str(x)
343         expect = 'GENSTRING pre t s\n' + \
344                  'GENSTRING action1 action2 t s\n' + \
345                  'GENSTRING post t s'
346         assert c == expect, c
347
348     def test_nullify(self):
349         """Test the nullify() method"""
350         env = MyEnvironment(S='string')
351
352         result = []
353         def action1(target, source, env, result=result, **kw):
354             result.append('action1')
355
356         env = MyEnvironment()
357         a = MyAction([action1])
358         x = SCons.Executor.Executor(a, env, [], ['t1', 't2'], ['s1', 's2'])
359
360         x(MyNode('', [], []))
361         assert result == ['action1'], result
362         s = str(x)
363         assert s[:10] == 'GENSTRING ', s
364
365         del result[:]
366         x.nullify()
367
368         assert result == [], result
369         x(MyNode('', [], []))
370         assert result == [], result
371         s = str(x)
372         assert s == '', s
373
374     def test_get_contents(self):
375         """Test fetching the signatures contents"""
376         env = MyEnvironment(C='contents')
377
378         x = SCons.Executor.Executor(MyAction(), env, [], ['t'], ['s'])
379         c = x.get_contents()
380         assert c == 'action1 action2 t s', c
381
382         x = SCons.Executor.Executor(MyAction(actions=['grow']), env, [],
383                                     ['t'], ['s'])
384         x.add_pre_action(MyAction(['pre']))
385         x.add_post_action(MyAction(['post']))
386         c = x.get_contents()
387         assert c == 'pre t sgrow t spost t s', c
388
389     def test_get_timestamp(self):
390         """Test fetching the "timestamp" """
391         x = SCons.Executor.Executor('b', 'e', 'o', 't', ['s1', 's2'])
392         ts = x.get_timestamp()
393         assert ts == 0, ts
394
395     def test_scan_targets(self):
396         """Test scanning the targets for implicit dependencies"""
397         env = MyEnvironment(S='string')
398         t1 = MyNode('t1')
399         t2 = MyNode('t2')
400         sources = [MyNode('s1'), MyNode('s2')]
401         x = SCons.Executor.Executor(MyAction(), env, [{}], [t1, t2], sources)
402
403         deps = x.scan_targets(None)
404         assert t1.implicit == ['dep-t1', 'dep-t2'], t1.implicit
405         assert t2.implicit == ['dep-t1', 'dep-t2'], t2.implicit
406
407         t1.implicit = []
408         t2.implicit = []
409
410         deps = x.scan_targets(MyScanner('scanner-'))
411         assert t1.implicit == ['scanner-t1', 'scanner-t2'], t1.implicit
412         assert t2.implicit == ['scanner-t1', 'scanner-t2'], t2.implicit
413
414     def test_scan_sources(self):
415         """Test scanning the sources for implicit dependencies"""
416         env = MyEnvironment(S='string')
417         t1 = MyNode('t1')
418         t2 = MyNode('t2')
419         sources = [MyNode('s1'), MyNode('s2')]
420         x = SCons.Executor.Executor(MyAction(), env, [{}], [t1, t2], sources)
421
422         deps = x.scan_sources(None)
423         assert t1.implicit == ['dep-s1', 'dep-s2'], t1.implicit
424         assert t2.implicit == ['dep-s1', 'dep-s2'], t2.implicit
425
426         t1.implicit = []
427         t2.implicit = []
428
429         deps = x.scan_sources(MyScanner('scanner-'))
430         assert t1.implicit == ['scanner-s1', 'scanner-s2'], t1.implicit
431         assert t2.implicit == ['scanner-s1', 'scanner-s2'], t2.implicit
432
433     def test_get_unignored_sources(self):
434         """Test fetching the unignored source list"""
435         env = MyEnvironment()
436         s1 = MyNode('s1')
437         s2 = MyNode('s2')
438         s3 = MyNode('s3')
439         x = SCons.Executor.Executor('b', env, [{}], [], [s1, s2, s3])
440
441         r = x.get_unignored_sources(None, [])
442         assert r == [s1, s2, s3], list(map(str, r))
443
444         r = x.get_unignored_sources(None, [s2])
445         assert r == [s1, s3], list(map(str, r))
446
447         r = x.get_unignored_sources(None, [s1, s3])
448         assert r == [s2], list(map(str, r))
449
450
451
452 if __name__ == "__main__":
453     suite = unittest.TestSuite()
454     tclasses = [ ExecutorTestCase ]
455     for tclass in tclasses:
456         names = unittest.getTestCaseNames(tclass, 'test_')
457         suite.addTests(list(map(tclass, names)))
458     if not unittest.TextTestRunner().run(suite).wasSuccessful():
459         sys.exit(1)
460
461 # Local Variables:
462 # tab-width:4
463 # indent-tabs-mode:nil
464 # End:
465 # vim: set expandtab tabstop=4 shiftwidth=4: