Add a QT tool. (Christoph Wiedemann)
[scons.git] / src / engine / SCons / Node / NodeTests.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 os
27 import sys
28 import types
29 import unittest
30
31 import SCons.Errors
32 import SCons.Node
33
34
35
36 built_it = None
37 built_target =  None
38 built_source =  None
39 cycle_detected = None
40 built_order = 0
41
42 class MyAction:
43     def __init__(self):
44         self.order = 0
45         
46     def __call__(self, target, source, env):
47         global built_it, built_target, built_source, built_args, built_order
48         built_it = 1
49         built_target = target
50         built_source = source
51         built_args = env
52         built_order = built_order + 1
53         self.order = built_order
54         return 0
55
56     def get_actions(self):
57         return [self]
58
59 class MyNonGlobalAction:
60     def __init__(self):
61         self.order = 0
62         self.built_it = None
63         self.built_target =  None
64         self.built_source =  None
65
66     def __call__(self, target, source, env):
67         # Okay, so not ENTIRELY non-global...
68         global built_order
69         self.built_it = 1
70         self.built_target = target
71         self.built_source = source
72         self.built_args = env
73         built_order = built_order + 1
74         self.order = built_order
75         return 0
76
77     def get_actions(self):
78         return [self]
79
80 class Environment:
81     def Dictionary(self, *args):
82         return {}
83     def Override(self, overrides):
84         return overrides
85
86 class Builder:
87     def __init__(self):
88         self.env = Environment()
89         self.overrides = {}
90         self.action = MyAction()
91     def targets(self, t):
92         return [t]
93     def get_actions(self):
94         return [self.action]
95     def get_contents(self, target, source, env):
96         return 7
97
98 class NoneBuilder(Builder):
99     def execute(self, target, source, env):
100         Builder.execute(self, target, source, env)
101         return None
102
103 class ListBuilder(Builder):
104     def __init__(self, *nodes):
105         Builder.__init__(self)
106         self.nodes = nodes
107     def execute(self, target, source, env):
108         if hasattr(self, 'status'):
109             return self.status
110         for n in self.nodes:
111             n.prepare()
112         target = self.nodes[0]
113         self.status = Builder.execute(self, target, source, env)
114
115 class FailBuilder:
116     def execute(self, target, source, env):
117         return 1
118
119 class ExceptBuilder:
120     def execute(self, target, source, env):
121         raise SCons.Errors.BuildError
122
123 class ExceptBuilder2:
124     def execute(self, target, source, env):
125         raise "foo"
126
127 class Scanner:
128     called = None
129     def __call__(self, node):
130         self.called = 1
131         return node.found_includes
132
133 class MyNode(SCons.Node.Node):
134     """The base Node class contains a number of do-nothing methods that
135     we expect to be overridden by real, functional Node subclasses.  So
136     simulate a real, functional Node subclass.
137     """
138     def __init__(self, name):
139         SCons.Node.Node.__init__(self)
140         self.name = name
141         self.found_includes = []
142     def __str__(self):
143         return self.name
144     def get_found_includes(self, env, scanner, target):
145         return scanner(self)
146
147
148
149 class NodeTestCase(unittest.TestCase):
150
151     def test_build(self):
152         """Test building a node
153         """
154         global built_it, built_order
155
156         # Make sure it doesn't blow up if no builder is set.
157         node = MyNode("www")
158         node.build()
159         assert built_it == None
160
161         node = MyNode("xxx")
162         node.builder_set(Builder())
163         node.env_set(Environment())
164         node.path = "xxx"
165         node.sources = ["yyy", "zzz"]
166         node.build()
167         assert built_it
168         assert built_target == [node], built_target
169         assert built_source == ["yyy", "zzz"], built_source
170
171         built_it = None
172         node = MyNode("qqq")
173         node.builder_set(NoneBuilder())
174         node.env_set(Environment())
175         node.path = "qqq"
176         node.sources = ["rrr", "sss"]
177         node.builder.overrides = { "foo" : 1, "bar" : 2 }
178         node.build()
179         assert built_it
180         assert built_target == [node], built_target
181         assert built_source == ["rrr", "sss"], built_source
182         assert built_args["foo"] == 1, built_args
183         assert built_args["bar"] == 2, built_args
184
185         fff = MyNode("fff")
186         ggg = MyNode("ggg")
187         lb = ListBuilder(fff, ggg)
188         e = Environment()
189         fff.builder_set(lb)
190         fff.env_set(e)
191         fff.path = "fff"
192         ggg.builder_set(lb)
193         ggg.env_set(e)
194         ggg.path = "ggg"
195         fff.sources = ["hhh", "iii"]
196         ggg.sources = ["hhh", "iii"]
197         # [Charles C. 1/7/2002] Uhhh, why are there no asserts here?
198         # [SK, 15 May 2003] I dunno, let's add some...
199         built_it = None
200         fff.build()
201         assert built_it
202         assert built_target == [fff], built_target
203         assert built_source == ["hhh", "iii"], built_source
204         built_it = None
205         ggg.build()
206         assert built_it
207         assert built_target == [ggg], built_target
208         assert built_source == ["hhh", "iii"], built_source
209
210         built_it = None
211         jjj = MyNode("jjj")
212         b = Builder()
213         jjj.builder_set(b)
214         # NOTE:  No env_set()!  We should pull the environment from the builder.
215         b.env = Environment()
216         b.overrides = { "on" : 3, "off" : 4 }
217         e.builder = b
218         jjj.build()
219         assert built_it
220         assert built_target[0] == jjj, built_target[0]
221         assert built_source == [], built_source
222         assert built_args["on"] == 3, built_args
223         assert built_args["off"] == 4, built_args
224
225         built_it = None
226         built_order = 0
227         node = MyNode("xxx")
228         node.builder_set(Builder())
229         node.env_set(Environment())
230         node.sources = ["yyy", "zzz"]
231         pre1 = MyNonGlobalAction()
232         pre2 = MyNonGlobalAction()
233         post1 = MyNonGlobalAction()
234         post2 = MyNonGlobalAction()
235         node.add_pre_action(pre1)
236         node.add_pre_action(pre2)
237         node.add_post_action(post1)
238         node.add_post_action(post2)
239         node.build()
240         assert built_it
241         assert pre1.built_it
242         assert pre2.built_it
243         assert post1.built_it
244         assert post2.built_it
245         assert pre1.order == 1, pre1.order
246         assert pre2.order == 2, pre1.order
247         # The action of the builder itself is order 3...
248         assert post1.order == 4, pre1.order
249         assert post2.order == 5, pre1.order
250
251         for act in [ pre1, pre2, post1, post2 ]:
252             assert type(act.built_target[0]) == type(MyNode("bar")), type(act.built_target[0])
253             assert str(act.built_target[0]) == "xxx", str(act.built_target[0])
254             assert act.built_source == ["yyy", "zzz"], act.built_source
255
256     def test_visited(self):
257         """Test the base visited() method
258
259         Just make sure it's there and we can call it.
260         """
261         n = SCons.Node.Node()
262         n.visited()
263             
264     def test_depends_on(self):
265         """Test the depends_on() method
266         """
267         parent = SCons.Node.Node()
268         child = SCons.Node.Node()
269         parent.add_dependency([child])
270         assert parent.depends_on([child])
271         
272     def test_builder_set(self):
273         """Test setting a Node's Builder
274         """
275         node = SCons.Node.Node()
276         b = Builder()
277         node.builder_set(b)
278         assert node.builder == b
279
280     def test_has_builder(self):
281         """Test the has_builder() method
282         """
283         n1 = SCons.Node.Node()
284         assert n1.has_builder() == 0
285         n1.builder_set(Builder())
286         assert n1.has_builder() == 1
287
288     def test_is_derived(self):
289         """Test the is_derived() method
290         """
291         n1 = SCons.Node.Node()
292         n2 = SCons.Node.Node()
293         n3 = SCons.Node.Node()
294
295         n2.builder_set(Builder())
296         n3.side_effect = 1
297
298         assert n1.is_derived() == 0
299         assert n2.is_derived() == 1
300         assert n3.is_derived() == 1
301
302     def test_alter_targets(self):
303         """Test the alter_targets() method
304         """
305         n = SCons.Node.Node()
306         t, m = n.alter_targets()
307         assert t == [], t
308         assert m == None, m
309
310     def test_current(self):
311         """Test the default current() method
312         """
313         node = SCons.Node.Node()
314         assert node.current() is None
315
316     def test_env_set(self):
317         """Test setting a Node's Environment
318         """
319         node = SCons.Node.Node()
320         e = Environment()
321         node.env_set(e)
322         assert node.env == e
323
324     def test_get_actions(self):
325         """Test fetching a Node's action list
326         """
327         node = SCons.Node.Node()
328         node.builder_set(Builder())
329         a = node.builder.get_actions()
330         assert isinstance(a[0], MyAction), a[0]
331
332     def test_set_bsig(self):
333         """Test setting a Node's signature
334         """
335         node = SCons.Node.Node()
336         node.set_bsig('www')
337         assert node.bsig == 'www'
338
339     def test_get_bsig(self):
340         """Test fetching a Node's signature
341         """
342         node = SCons.Node.Node()
343         node.set_bsig('xxx')
344         assert node.get_bsig() == 'xxx'
345
346     def test_set_csig(self):
347         """Test setting a Node's signature
348         """
349         node = SCons.Node.Node()
350         node.set_csig('yyy')
351         assert node.csig == 'yyy'
352
353     def test_get_csig(self):
354         """Test fetching a Node's signature
355         """
356         node = SCons.Node.Node()
357         node.set_csig('zzz')
358         assert node.get_csig() == 'zzz'
359
360     def test_store_bsig(self):
361         """Test calling the method to store a build signature
362         """
363         node = SCons.Node.Node()
364         node.store_bsig()
365
366     def test_store_csig(self):
367         """Test calling the method to store a content signature
368         """
369         node = SCons.Node.Node()
370         node.store_csig()
371
372     def test_get_timestamp(self):
373         """Test calling the method to fetch a Node's timestamp
374         """
375         node = SCons.Node.Node()
376         assert node.get_timestamp() == 0
377
378     def test_store_timestamp(self):
379         """Test calling the method to store a timestamp
380         """
381         node = SCons.Node.Node()
382         node.store_timestamp()
383
384     def test_set_always_build(self):
385         """Test setting a Node's always_build value
386         """
387         node = SCons.Node.Node()
388         node.set_always_build()
389         assert node.always_build
390         node.set_always_build(3)
391         assert node.always_build == 3
392
393     def test_set_precious(self):
394         """Test setting a Node's precious value
395         """
396         node = SCons.Node.Node()
397         node.set_precious()
398         assert node.precious
399         node.set_precious(7)
400         assert node.precious == 7
401
402     def test_exists(self):
403         """Test evaluating whether a Node exists.
404         """
405         node = SCons.Node.Node()
406         e = node.exists()
407         assert e == 1, e
408
409     def test_exists(self):
410         """Test evaluating whether a Node exists locally or in a repository.
411         """
412         node = SCons.Node.Node()
413         e = node.rexists()
414         assert e == 1, e
415
416         class MyNode(SCons.Node.Node):
417             def exists(self):
418                 return 'xyz'
419
420         node = MyNode()
421         e = node.rexists()
422         assert e == 'xyz', e
423
424     def test_prepare(self):
425         """Test preparing a node to be built
426         """
427         node = SCons.Node.Node()
428
429         n1 = SCons.Node.Node()
430         n1.builder_set(Builder())
431         node.implicit = []
432         node.implicit_dict = {}
433         node._add_child(node.implicit, node.implicit_dict, [n1])
434
435         node.prepare()  # should not throw an exception
436
437         n2 = SCons.Node.Node()
438         n2.linked = 1
439         node.implicit = []
440         node.implicit_dict = {}
441         node._add_child(node.implicit, node.implicit_dict, [n2])
442
443         node.prepare()  # should not throw an exception
444
445         n3 = SCons.Node.Node()
446         node.implicit = []
447         node.implicit_dict = {}
448         node._add_child(node.implicit, node.implicit_dict, [n3])
449
450         node.prepare()  # should not throw an exception
451
452         class MyNode(SCons.Node.Node):
453             def rexists(self):
454                 return None
455         n4 = MyNode()
456         node.implicit = []
457         node.implicit_dict = {}
458         node._add_child(node.implicit, node.implicit_dict, [n4]) 
459         exc_caught = 0
460         try:
461             node.prepare()
462         except SCons.Errors.StopError:
463             exc_caught = 1
464         assert exc_caught, "did not catch expected StopError"
465
466     def test_add_dependency(self):
467         """Test adding dependencies to a Node's list.
468         """
469         node = SCons.Node.Node()
470         assert node.depends == []
471
472         zero = SCons.Node.Node()
473         try:
474             node.add_dependency(zero)
475         except TypeError:
476             pass
477         else:
478             assert 0
479
480         one = SCons.Node.Node()
481         two = SCons.Node.Node()
482         three = SCons.Node.Node()
483         four = SCons.Node.Node()
484
485         node.add_dependency([one])
486         assert node.depends == [one]
487         node.add_dependency([two, three])
488         assert node.depends == [one, two, three]
489         node.add_dependency([three, four, one])
490         assert node.depends == [one, two, three, four]
491
492         assert zero.get_parents() == []
493         assert one.get_parents() == [node]
494         assert two.get_parents() == [node]
495         assert three.get_parents() == [node]
496         assert four.get_parents() == [node]
497
498
499     def test_add_source(self):
500         """Test adding sources to a Node's list.
501         """
502         node = SCons.Node.Node()
503         assert node.sources == []
504
505         zero = SCons.Node.Node()
506         try:
507             node.add_source(zero)
508         except TypeError:
509             pass
510         else:
511             assert 0
512
513         one = SCons.Node.Node()
514         two = SCons.Node.Node()
515         three = SCons.Node.Node()
516         four = SCons.Node.Node()
517
518         node.add_source([one])
519         assert node.sources == [one]
520         node.add_source([two, three])
521         assert node.sources == [one, two, three]
522         node.add_source([three, four, one])
523         assert node.sources == [one, two, three, four]
524
525         assert zero.get_parents() == []
526         assert one.get_parents() == [node]
527         assert two.get_parents() == [node]
528         assert three.get_parents() == [node]
529         assert four.get_parents() == [node]
530
531     def test_add_ignore(self):
532         """Test adding files whose dependencies should be ignored.
533         """
534         node = SCons.Node.Node()
535         assert node.ignore == []
536
537         zero = SCons.Node.Node()
538         try:
539             node.add_ignore(zero)
540         except TypeError:
541             pass
542         else:
543             assert 0
544
545         one = SCons.Node.Node()
546         two = SCons.Node.Node()
547         three = SCons.Node.Node()
548         four = SCons.Node.Node()
549
550         node.add_ignore([one])
551         assert node.ignore == [one]
552         node.add_ignore([two, three])
553         assert node.ignore == [one, two, three]
554         node.add_ignore([three, four, one])
555         assert node.ignore == [one, two, three, four]
556
557         assert zero.get_parents() == []
558         assert one.get_parents() == [node]
559         assert two.get_parents() == [node]
560         assert three.get_parents() == [node]
561         assert four.get_parents() == [node]
562
563     def test_get_found_includes(self):
564         """Test the default get_found_includes() method
565         """
566         node = SCons.Node.Node()
567         target = SCons.Node.Node()
568         e = Environment()
569         deps = node.get_found_includes(e, None, target)
570         assert deps == [], deps
571
572     def test_get_implicit_deps(self):
573         """Test get_implicit_deps()
574         """
575         node = MyNode("nnn")
576         target = MyNode("ttt")
577         env = Environment()
578
579         # No scanner at all returns []
580         deps = node.get_implicit_deps(env, None, target)
581         assert deps == [], deps
582
583         s = Scanner()
584         d = MyNode("ddd")
585         node.found_includes = [d]
586
587         # Simple return of the found includes
588         deps = node.get_implicit_deps(env, s, target)
589         assert deps == [d], deps
590
591         # No "recursive" attribute on scanner doesn't recurse
592         e = MyNode("eee")
593         d.found_includes = [e]
594         deps = node.get_implicit_deps(env, s, target)
595         assert deps == [d], map(str, deps)
596
597         # Explicit "recursive" attribute on scanner doesn't recurse
598         s.recursive = None
599         deps = node.get_implicit_deps(env, s, target)
600         assert deps == [d], map(str, deps)
601
602         # Explicit "recursive" attribute on scanner which does recurse
603         s.recursive = 1
604         deps = node.get_implicit_deps(env, s, target)
605         assert deps == [d, e], map(str, deps)
606
607         # Recursive scanning eliminates duplicates
608         f = MyNode("fff")
609         d.found_includes = [e, f]
610         e.found_includes = [f]
611         deps = node.get_implicit_deps(env, s, target)
612         assert deps == [d, e, f], map(str, deps)
613
614     def test_scan(self):
615         """Test Scanner functionality
616         """
617         node = MyNode("nnn")
618         node.builder = Builder()
619         node.env_set(Environment())
620         s = Scanner()
621
622         d = MyNode("ddd")
623         node.found_includes = [d]
624
625         assert node.target_scanner == None, node.target_scanner
626         node.target_scanner = s
627         assert node.implicit is None
628
629         node.scan()
630         assert s.called
631         assert node.implicit == [d], node.implicit
632
633         # Check that scanning a node with some stored implicit
634         # dependencies resets internal attributes appropriately
635         # if the stored dependencies need recalculation.
636         class StoredNode(MyNode):
637             def get_stored_implicit(self):
638                 return ['implicit1', 'implicit2']
639
640         class NotCurrent:
641             def current(self, node, sig):
642                 return None
643             def bsig(self, node):
644                 return 0
645
646         import SCons.Sig
647
648         save_default_calc = SCons.Sig.default_calc
649         save_implicit_cache = SCons.Node.implicit_cache
650         save_implicit_deps_changed = SCons.Node.implicit_deps_changed
651         save_implicit_deps_unchanged = SCons.Node.implicit_deps_unchanged
652         SCons.Sig.default_calc = NotCurrent()
653         SCons.Node.implicit_cache = 1
654         SCons.Node.implicit_deps_changed = None
655         SCons.Node.implicit_deps_unchanged = None
656         try:
657             sn = StoredNode("eee")
658             sn._children = ['fake']
659             sn.target_scanner = s
660
661             sn.scan()
662
663             assert sn.implicit == [], sn.implicit
664             assert not hasattr(sn, '_children'), "unexpected _children attribute"
665         finally:
666             SCons.Sig.default_calc = save_default_calc
667             SCons.Node.implicit_cache = save_implicit_cache
668             SCons.Node.implicit_deps_changed = save_implicit_deps_changed
669             SCons.Node.implicit_deps_unchanged = save_implicit_deps_unchanged
670
671     def test_scanner_key(self):
672         """Test that a scanner_key() method exists"""
673         assert SCons.Node.Node().scanner_key() == None
674
675     def test_children(self):
676         """Test fetching the non-ignored "children" of a Node.
677         """
678         node = SCons.Node.Node()
679         n1 = SCons.Node.Node()
680         n2 = SCons.Node.Node()
681         n3 = SCons.Node.Node()
682         n4 = SCons.Node.Node()
683         n5 = SCons.Node.Node()
684         n6 = SCons.Node.Node()
685         n7 = SCons.Node.Node()
686         n8 = SCons.Node.Node()
687         n9 = SCons.Node.Node()
688         n10 = SCons.Node.Node()
689         n11 = SCons.Node.Node()
690         n12 = SCons.Node.Node()
691
692         node.add_source([n1, n2, n3])
693         node.add_dependency([n4, n5, n6])
694         node.implicit = []
695         node.implicit_dict = {}
696         node._add_child(node.implicit, node.implicit_dict, [n7, n8, n9])
697         node._add_child(node.implicit, node.implicit_dict, [n10, n11, n12])
698         node.add_ignore([n2, n5, n8, n11])
699
700         kids = node.children()
701         for kid in [n1, n3, n4, n6, n7, n9, n10, n12]:
702             assert kid in kids, kid
703         for kid in [n2, n5, n8, n11]:
704             assert not kid in kids, kid
705
706     def test_all_children(self):
707         """Test fetching all the "children" of a Node.
708         """
709         node = SCons.Node.Node()
710         n1 = SCons.Node.Node()
711         n2 = SCons.Node.Node()
712         n3 = SCons.Node.Node()
713         n4 = SCons.Node.Node()
714         n5 = SCons.Node.Node()
715         n6 = SCons.Node.Node()
716         n7 = SCons.Node.Node()
717         n8 = SCons.Node.Node()
718         n9 = SCons.Node.Node()
719         n10 = SCons.Node.Node()
720         n11 = SCons.Node.Node()
721         n12 = SCons.Node.Node()
722
723         node.add_source([n1, n2, n3])
724         node.add_dependency([n4, n5, n6])
725         node.implicit = []
726         node.implicit_dict = {}
727         node._add_child(node.implicit, node.implicit_dict, [n7, n8, n9])
728         node._add_child(node.implicit, node.implicit_dict, [n10, n11, n12])
729         node.add_ignore([n2, n5, n8, n11])
730
731         kids = node.all_children()
732         for kid in [n1, n2, n3, n4, n5, n6, n7, n8, n9, n10, n11, n12]:
733             assert kid in kids, kid
734
735     def test_state(self):
736         """Test setting and getting the state of a node
737         """
738         node = SCons.Node.Node()
739         assert node.get_state() == None
740         node.set_state(SCons.Node.executing)
741         assert node.get_state() == SCons.Node.executing
742         assert SCons.Node.pending < SCons.Node.executing
743         assert SCons.Node.executing < SCons.Node.up_to_date
744         assert SCons.Node.up_to_date < SCons.Node.executed
745         assert SCons.Node.executed < SCons.Node.failed
746
747     def test_walker(self):
748         """Test walking a Node tree.
749         """
750
751         n1 = MyNode("n1")
752
753         nw = SCons.Node.Walker(n1)
754         assert not nw.is_done()
755         assert nw.next().name ==  "n1"
756         assert nw.is_done()
757         assert nw.next() == None
758
759         n2 = MyNode("n2")
760         n3 = MyNode("n3")
761         n1.add_source([n2, n3])
762
763         nw = SCons.Node.Walker(n1)
764         n = nw.next()
765         assert n.name ==  "n2", n.name
766         n = nw.next()
767         assert n.name ==  "n3", n.name
768         n = nw.next()
769         assert n.name ==  "n1", n.name
770         n = nw.next()
771         assert n == None, n
772
773         n4 = MyNode("n4")
774         n5 = MyNode("n5")
775         n6 = MyNode("n6")
776         n7 = MyNode("n7")
777         n2.add_source([n4, n5])
778         n3.add_dependency([n6, n7])
779
780         nw = SCons.Node.Walker(n1)
781         assert nw.next().name ==  "n4"
782         assert nw.next().name ==  "n5"
783         assert nw.history.has_key(n2)
784         assert nw.next().name ==  "n2"
785         assert nw.next().name ==  "n6"
786         assert nw.next().name ==  "n7"
787         assert nw.history.has_key(n3)
788         assert nw.next().name ==  "n3"
789         assert nw.history.has_key(n1)
790         assert nw.next().name ==  "n1"
791         assert nw.next() == None
792
793         n8 = MyNode("n8")
794         n8.add_dependency([n3])
795         n7.add_dependency([n8])
796
797         def cycle(node, stack):
798             global cycle_detected
799             cycle_detected = 1
800
801         global cycle_detected
802
803         nw = SCons.Node.Walker(n3, cycle_func = cycle)
804         n = nw.next()
805         assert n.name == "n6", n.name
806         n = nw.next()
807         assert n.name == "n8", n.name
808         assert cycle_detected
809         cycle_detected = None
810         n = nw.next()
811         assert n.name == "n7", n.name
812         n = nw.next()
813         assert nw.next() == None
814
815     def test_rstr(self):
816         """Test the rstr() method."""
817         n1 = MyNode("n1")
818         assert n1.rstr() == 'n1', n1.rstr()
819
820     def test_abspath(self):
821         """Test the get_abspath() method."""
822         n = MyNode("foo")
823         assert n.get_abspath() == str(n), n.get_abspath()
824
825     def test_for_signature(self):
826         """Test the for_signature() method."""
827         n = MyNode("foo")
828         assert n.for_signature() == str(n), n.get_abspath()
829
830     def test_get_string(self):
831         """Test the get_string() method."""
832         class TestNode(MyNode):
833             def __init__(self, name, sig):
834                 MyNode.__init__(self, name)
835                 self.sig = sig
836
837             def for_signature(self):
838                 return self.sig
839             
840         n = TestNode("foo", "bar")
841         assert n.get_string(0) == "foo", n.get_string(0)
842         assert n.get_string(1) == "bar", n.get_string(1)
843
844     def test_arg2nodes(self):
845         """Test the arg2nodes function."""
846         dict = {}
847         class X(SCons.Node.Node):
848             pass
849         def Factory(name, directory = None, create = 1, dict=dict, X=X):
850             if not dict.has_key(name):
851                 dict[name] = X()
852                 dict[name].name = name
853             return dict[name]
854
855         nodes = SCons.Node.arg2nodes("Util.py UtilTests.py", Factory)
856         assert len(nodes) == 1, nodes
857         assert isinstance(nodes[0], X)
858         assert nodes[0].name == "Util.py UtilTests.py"
859
860         if hasattr(types, 'UnicodeType'):
861             code = """if 1:
862                 nodes = SCons.Node.arg2nodes(u"Util.py UtilTests.py", Factory)
863                 assert len(nodes) == 1, nodes
864                 assert isinstance(nodes[0], X)
865                 assert nodes[0].name == u"Util.py UtilTests.py"
866                 \n"""
867             exec code in globals(), locals()
868
869         nodes = SCons.Node.arg2nodes(["Util.py", "UtilTests.py"], Factory)
870         assert len(nodes) == 2, nodes
871         assert isinstance(nodes[0], X)
872         assert isinstance(nodes[1], X)
873         assert nodes[0].name == "Util.py"
874         assert nodes[1].name == "UtilTests.py"
875
876         n1 = Factory("Util.py")
877         nodes = SCons.Node.arg2nodes([n1, "UtilTests.py"], Factory)
878         assert len(nodes) == 2, nodes
879         assert isinstance(nodes[0], X)
880         assert isinstance(nodes[1], X)
881         assert nodes[0].name == "Util.py"
882         assert nodes[1].name == "UtilTests.py"
883
884         class SConsNode(SCons.Node.Node):
885             pass
886         nodes = SCons.Node.arg2nodes(SConsNode())
887         assert len(nodes) == 1, nodes
888         assert isinstance(nodes[0], SConsNode), node
889
890         class OtherNode:
891             pass
892         nodes = SCons.Node.arg2nodes(OtherNode())
893         assert len(nodes) == 1, nodes
894         assert isinstance(nodes[0], OtherNode), node
895
896         def lookup_a(str, F=Factory):
897             if str[0] == 'a':
898                 n = F(str)
899                 n.a = 1
900                 return n
901             else:
902                 return None
903
904         def lookup_b(str, F=Factory):
905             if str[0] == 'b':
906                 n = F(str)
907                 n.b = 1
908                 return n
909             else:
910                 return None
911
912         SCons.Node.arg2nodes_lookups.append(lookup_a)
913         SCons.Node.arg2nodes_lookups.append(lookup_b)
914
915         nodes = SCons.Node.arg2nodes(['aaa', 'bbb', 'ccc'], Factory)
916         assert len(nodes) == 3, nodes
917
918         assert nodes[0].name == 'aaa', nodes[0]
919         assert nodes[0].a == 1, nodes[0]
920         assert not hasattr(nodes[0], 'b'), nodes[0]
921
922         assert nodes[1].name == 'bbb'
923         assert not hasattr(nodes[1], 'a'), nodes[1]
924         assert nodes[1].b == 1, nodes[1]
925
926         assert nodes[2].name == 'ccc'
927         assert not hasattr(nodes[2], 'a'), nodes[1]
928         assert not hasattr(nodes[2], 'b'), nodes[1]
929
930         def lookup_bbbb(str, F=Factory):
931             if str == 'bbbb':
932                 n = F(str)
933                 n.bbbb = 1
934                 return n
935             else:
936                 return None
937
938         def lookup_c(str, F=Factory):
939             if str[0] == 'c':
940                 n = F(str)
941                 n.c = 1
942                 return n
943             else:
944                 return None
945
946         nodes = SCons.Node.arg2nodes(['bbbb', 'ccc'], Factory,
947                                      [lookup_c, lookup_bbbb, lookup_b])
948         assert len(nodes) == 2, nodes
949
950         assert nodes[0].name == 'bbbb'
951         assert not hasattr(nodes[0], 'a'), nodes[1]
952         assert not hasattr(nodes[0], 'b'), nodes[1]
953         assert nodes[0].bbbb == 1, nodes[1]
954         assert not hasattr(nodes[0], 'c'), nodes[0]
955
956         assert nodes[1].name == 'ccc'
957         assert not hasattr(nodes[1], 'a'), nodes[1]
958         assert not hasattr(nodes[1], 'b'), nodes[1]
959         assert not hasattr(nodes[1], 'bbbb'), nodes[0]
960         assert nodes[1].c == 1, nodes[1]
961         
962     def test_literal(self):
963         """Test the is_literal() function."""
964         n=SCons.Node.Node()
965         assert n.is_literal()
966         
967     def test_Annotate(self):
968         """Test using an interface-specific Annotate function."""
969         def my_annotate(node, self=self):
970             node.annotation = self.node_string
971
972         save_Annotate = SCons.Node.Annotate
973         SCons.Node.Annotate = my_annotate
974
975         try:
976             self.node_string = '#1'
977             n = SCons.Node.Node()
978             assert n.annotation == '#1', n.annotation
979
980             self.node_string = '#2'
981             n = SCons.Node.Node()
982             assert n.annotation == '#2', n.annotation
983         finally:
984             SCons.Node.Annotate = save_Annotate
985
986     def test_clear(self):
987         """Test clearing all cached state information."""
988         n = SCons.Node.Node()
989
990         n.set_state(3)
991         n.set_bsig('bsig')
992         n.set_csig('csig')
993         n.includes = 'testincludes'
994         n.found_include = {'testkey':'testvalue'}
995         n.implicit = 'testimplicit'
996
997         n.clear()
998
999         assert n.get_state() is None, n.get_state()
1000         assert not hasattr(n, 'bsig'), n.bsig
1001         assert not hasattr(n, 'csig'), n.csig
1002         assert n.includes is None, n.includes
1003         assert n.found_includes == {}, n.found_includes
1004         assert n.implicit is None, n.implicit
1005
1006     def test_get_subst_proxy(self):
1007         """Test the get_subst_proxy method."""
1008         n = MyNode("test")
1009
1010         assert n.get_subst_proxy() == n, n.get_subst_proxy()
1011
1012     def test_get_prevsiginfo(self):
1013         """Test the base Node get_prevsiginfo() method"""
1014         n = SCons.Node.Node()
1015         siginfo = n.get_prevsiginfo()
1016         assert siginfo == (None, None, None), siginfo
1017
1018
1019
1020 if __name__ == "__main__":
1021     suite = unittest.makeSuite(NodeTestCase, 'test_')
1022     if not unittest.TextTestRunner().run(suite).wasSuccessful():
1023         sys.exit(1)