Add BuildDir(), Export(), and Install() functionality (courtesy Charles Crain).
[scons.git] / src / engine / SCons / Node / NodeTests.py
1 #
2 # Copyright (c) 2001 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__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
25
26 import os
27 import sys
28 import unittest
29
30 import SCons.Errors
31 import SCons.Node
32
33
34
35 built_it = None
36 built_target =  None
37 built_source =  None
38 cycle_detected = None
39
40 class Builder:
41     def execute(self, **kw):
42         global built_it, built_target, built_source
43         built_it = 1
44         built_target = kw['target']
45         built_source = kw['source']
46         return 0
47     def get_contents(self, env, dir):
48         return 7
49
50 class FailBuilder:
51     def execute(self, **kw):
52         return 1
53
54 class Environment:
55     def Dictionary(self, *args):
56         pass
57
58
59
60 class NodeTestCase(unittest.TestCase):
61
62     def test_BuildException(self):
63         """Test throwing an exception on build failure.
64         """
65         node = SCons.Node.Node()
66         node.builder_set(FailBuilder())
67         node.env_set(Environment())
68         try:
69             node.build()
70         except SCons.Errors.BuildError:
71             pass
72         else:
73             raise TestFailed, "did not catch expected BuildError"
74
75     def test_build(self):
76         """Test building a node
77         """
78         class MyNode(SCons.Node.Node):
79             def __str__(self):
80                 return self.path
81         # Make sure it doesn't blow up if no builder is set.
82         node = MyNode()
83         node.build()
84         assert built_it == None
85
86         node = MyNode()
87         node.builder_set(Builder())
88         node.env_set(Environment())
89         node.path = "xxx"
90         node.sources = ["yyy", "zzz"]
91         node.build()
92         assert built_it
93         assert type(built_target) == type(MyNode()), type(built_target)
94         assert str(built_target) == "xxx", str(built_target)
95         assert built_source == ["yyy", "zzz"], built_source
96
97     def test_builder_set(self):
98         """Test setting a Node's Builder
99         """
100         node = SCons.Node.Node()
101         b = Builder()
102         node.builder_set(b)
103         assert node.builder == b
104
105     def test_builder_sig_adapter(self):
106         """Test the node's adapter for builder signatures
107         """
108         node = SCons.Node.Node()
109         node.builder_set(Builder())
110         node.env_set(Environment())
111         c = node.builder_sig_adapter().get_contents()
112         assert c == 7, c
113
114     def test_current(self):
115         """Test the default current() method
116         """
117         node = SCons.Node.Node()
118         assert node.current() is None
119
120     def test_env_set(self):
121         """Test setting a Node's Environment
122         """
123         node = SCons.Node.Node()
124         e = Environment()
125         node.env_set(e)
126         assert node.env == e
127
128     def test_set_bsig(self):
129         """Test setting a Node's signature
130         """
131         node = SCons.Node.Node()
132         node.set_bsig('www')
133         assert node.bsig == 'www'
134
135     def test_get_bsig(self):
136         """Test fetching a Node's signature
137         """
138         node = SCons.Node.Node()
139         node.set_bsig('xxx')
140         assert node.get_bsig() == 'xxx'
141
142     def test_set_csig(self):
143         """Test setting a Node's signature
144         """
145         node = SCons.Node.Node()
146         node.set_csig('yyy')
147         assert node.csig == 'yyy'
148
149     def test_get_csig(self):
150         """Test fetching a Node's signature
151         """
152         node = SCons.Node.Node()
153         node.set_csig('zzz')
154         assert node.get_csig() == 'zzz'
155
156     def test_add_dependency(self):
157         """Test adding dependencies to a Node's list.
158         """
159         node = SCons.Node.Node()
160         assert node.depends == []
161
162         zero = SCons.Node.Node()
163         try:
164             node.add_dependency(zero)
165         except TypeError:
166             pass
167         else:
168             assert 0
169
170         one = SCons.Node.Node()
171         two = SCons.Node.Node()
172         three = SCons.Node.Node()
173         four = SCons.Node.Node()
174
175         node.add_dependency([one])
176         assert node.depends == [one]
177         node.add_dependency([two, three])
178         assert node.depends == [one, two, three]
179         node.add_dependency([three, four, one])
180         assert node.depends == [one, two, three, four]
181
182         assert zero.get_parents() == []
183         assert one.get_parents() == [node]
184         assert two.get_parents() == [node]
185         assert three.get_parents() == [node]
186         assert four.get_parents() == [node]
187
188
189     def test_add_source(self):
190         """Test adding sources to a Node's list.
191         """
192         node = SCons.Node.Node()
193         assert node.sources == []
194
195         zero = SCons.Node.Node()
196         try:
197             node.add_source(zero)
198         except TypeError:
199             pass
200         else:
201             assert 0
202
203         one = SCons.Node.Node()
204         two = SCons.Node.Node()
205         three = SCons.Node.Node()
206         four = SCons.Node.Node()
207
208         node.add_source([one])
209         assert node.sources == [one]
210         node.add_source([two, three])
211         assert node.sources == [one, two, three]
212         node.add_source([three, four, one])
213         assert node.sources == [one, two, three, four]
214
215         assert zero.get_parents() == []
216         assert one.get_parents() == [node]
217         assert two.get_parents() == [node]
218         assert three.get_parents() == [node]
219         assert four.get_parents() == [node]
220
221     def test_add_implicit(self):
222         """Test adding implicit (scanned) dependencies to a Node's list.
223         """
224         node = SCons.Node.Node()
225         assert node.implicit == {}
226
227         zero = SCons.Node.Node()
228         try:
229             node.add_source(zero)
230         except TypeError:
231             pass
232         else:
233             assert 0
234
235         one = SCons.Node.Node()
236         two = SCons.Node.Node()
237         three = SCons.Node.Node()
238         four = SCons.Node.Node()
239
240         node.add_implicit([one], 1)
241         assert node.implicit[1] == [one]
242         node.add_implicit([two, three], 1)
243         assert node.implicit[1] == [one, two, three]
244         node.add_implicit([three, four, one], 1)
245         assert node.implicit[1] == [one, two, three, four]
246
247         assert zero.get_parents() == []
248         assert one.get_parents() == [node]
249         assert two.get_parents() == [node]
250         assert three.get_parents() == [node]
251         assert four.get_parents() == [node]
252
253         node.add_implicit([one], 2)
254         node.add_implicit([two, three], 3)
255         node.add_implicit([three, four, one], 4)
256
257         assert node.implicit[1] == [one, two, three, four]
258         assert node.implicit[2] == [one]
259         assert node.implicit[3] == [two, three]
260         assert node.implicit[4] == [three, four, one]
261
262     def test_scan(self):
263         """Test Scanner functionality"""
264         class DummyScanner:
265             pass
266         ds=DummyScanner()
267         node = SCons.Node.Node()
268         assert node.scanners == [], node.scanners
269         node.scanner_set(ds)
270         assert node.scanners == [ ds ], node.scanners
271         node.scan()
272         assert node.scanned[ds] == 1, node.scanned
273
274     def test_children(self):
275         """Test fetching the "children" of a Node.
276         """
277         node = SCons.Node.Node()
278         one = SCons.Node.Node()
279         two = SCons.Node.Node()
280         three = SCons.Node.Node()
281         four = SCons.Node.Node()
282         five = SCons.Node.Node()
283         six = SCons.Node.Node()
284
285         node.add_source([one, two, three])
286         node.add_dependency([four, five, six])
287         kids = node.children()
288         assert len(kids) == 6
289         assert one in kids
290         assert two in kids
291         assert three in kids
292         assert four in kids
293         assert five in kids
294         assert six in kids
295
296     def test_add_parent(self):
297         """Test adding parents to a Node."""
298         node = SCons.Node.Node()
299         parent = SCons.Node.Node()
300         node._add_parent(parent)
301         assert node.get_parents() == [parent]
302         node._add_parent(parent)
303         assert node.get_parents() == [parent]
304
305     def test_state(self):
306         """Test setting and getting the state of a node
307         """
308         node = SCons.Node.Node()
309         assert node.get_state() == None
310         node.set_state(SCons.Node.executing)
311         assert node.get_state() == SCons.Node.executing
312         assert SCons.Node.pending < SCons.Node.executing
313         assert SCons.Node.executing < SCons.Node.up_to_date
314         assert SCons.Node.up_to_date < SCons.Node.executed
315         assert SCons.Node.executed < SCons.Node.failed
316
317     def test_walker(self):
318         """Test walking a Node tree.
319         """
320
321         class MyNode(SCons.Node.Node):
322             def __init__(self, name):
323                 SCons.Node.Node.__init__(self)
324                 self.name = name
325
326         n1 = MyNode("n1")
327
328         nw = SCons.Node.Walker(n1)
329         assert not nw.is_done()
330         assert nw.next().name ==  "n1"
331         assert nw.is_done()
332         assert nw.next() == None
333
334         n2 = MyNode("n2")
335         n3 = MyNode("n3")
336         n1.add_source([n2, n3])
337
338         nw = SCons.Node.Walker(n1)
339         assert nw.next().name ==  "n2"
340         assert nw.next().name ==  "n3"
341         assert nw.next().name ==  "n1"
342         assert nw.next() == None
343
344         n4 = MyNode("n4")
345         n5 = MyNode("n5")
346         n6 = MyNode("n6")
347         n7 = MyNode("n7")
348         n2.add_source([n4, n5])
349         n3.add_dependency([n6, n7])
350
351         nw = SCons.Node.Walker(n1)
352         assert nw.next().name ==  "n4"
353         assert nw.next().name ==  "n5"
354         assert nw.history.has_key(n2)
355         assert nw.next().name ==  "n2"
356         assert nw.next().name ==  "n6"
357         assert nw.next().name ==  "n7"
358         assert nw.history.has_key(n3)
359         assert nw.next().name ==  "n3"
360         assert nw.history.has_key(n1)
361         assert nw.next().name ==  "n1"
362         assert nw.next() == None
363
364         n8 = MyNode("n8")
365         n8.add_dependency([n3])
366         n7.add_dependency([n8])
367
368         def cycle(node, stack):
369             global cycle_detected
370             cycle_detected = 1
371
372         global cycle_detected
373
374         nw = SCons.Node.Walker(n3, cycle_func = cycle)
375         n = nw.next()
376         assert n.name == "n6", n.name
377         n = nw.next()
378         assert n.name == "n8", n.name
379         assert cycle_detected
380         cycle_detected = None
381         n = nw.next()
382         assert n.name == "n7", n.name
383         n = nw.next()
384         assert nw.next() == None
385
386     def test_children_are_executed(self):
387         n1 = SCons.Node.Node()
388         n2 = SCons.Node.Node()
389         n3 = SCons.Node.Node()
390         n4 = SCons.Node.Node()
391
392         n4.add_source([n3])
393         n3.add_source([n1, n2])
394
395         assert not n4.children_are_executed()
396         assert not n3.children_are_executed()
397         assert n2.children_are_executed()
398         assert n1.children_are_executed()
399
400         n1.set_state(SCons.Node.executed)
401         assert not n4.children_are_executed()
402         assert not n3.children_are_executed()
403         assert n2.children_are_executed()
404         assert n1.children_are_executed()
405
406         n2.set_state(SCons.Node.executed)
407         assert not n4.children_are_executed()
408         assert n3.children_are_executed()
409         assert n2.children_are_executed()
410         assert n1.children_are_executed()
411
412         n3.set_state(SCons.Node.executed)
413         assert n4.children_are_executed()
414         assert n3.children_are_executed()
415         assert n2.children_are_executed()
416         assert n1.children_are_executed()
417
418     def test_rescan(self):
419         """Test that built nodes are rescanned."""
420         class DummyScanner:
421             pass
422         
423         class TestNode(SCons.Node.Node):
424             def scan(self):
425                 for scn in self.scanners:
426                     if not self.scanned.has_key(scn):
427                         n=SCons.Node.Node()
428                         n.scanner_set(scn)
429                         self.add_implicit([ n ], scn)
430                     self.scanned[scn] = 1
431         tn=TestNode()
432         tn.builder_set(Builder())
433         tn.env_set(Environment())
434         ds = DummyScanner()
435         tn.scanner_set(ds)
436         tn.scan()
437         map(lambda x: x.scan(), tn.depends)
438         assert tn.scanned[ds]
439         assert len(tn.implicit[ds]) == 1, tn.implicit
440         tn.build()
441         assert len(tn.implicit[ds]) == 2, tn.implicit
442         for dep in tn.implicit[ds]:
443             assert dep.scanned[ds] == 1
444
445 if __name__ == "__main__":
446     suite = unittest.makeSuite(NodeTestCase, 'test_')
447     if not unittest.TextTestRunner().run(suite).wasSuccessful():
448         sys.exit(1)