Speed up adding children to the various Node lists (depends, ignore, sources, implicit).
[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     def test_scanner_key(self):
634         """Test that a scanner_key() method exists"""
635         assert SCons.Node.Node().scanner_key() == None
636
637     def test_children(self):
638         """Test fetching the non-ignored "children" of a Node.
639         """
640         node = SCons.Node.Node()
641         n1 = SCons.Node.Node()
642         n2 = SCons.Node.Node()
643         n3 = SCons.Node.Node()
644         n4 = SCons.Node.Node()
645         n5 = SCons.Node.Node()
646         n6 = SCons.Node.Node()
647         n7 = SCons.Node.Node()
648         n8 = SCons.Node.Node()
649         n9 = SCons.Node.Node()
650         n10 = SCons.Node.Node()
651         n11 = SCons.Node.Node()
652         n12 = SCons.Node.Node()
653
654         node.add_source([n1, n2, n3])
655         node.add_dependency([n4, n5, n6])
656         node.implicit = []
657         node.implicit_dict = {}
658         node._add_child(node.implicit, node.implicit_dict, [n7, n8, n9])
659         node._add_child(node.implicit, node.implicit_dict, [n10, n11, n12])
660         node.add_ignore([n2, n5, n8, n11])
661
662         kids = node.children()
663         for kid in [n1, n3, n4, n6, n7, n9, n10, n12]:
664             assert kid in kids, kid
665         for kid in [n2, n5, n8, n11]:
666             assert not kid in kids, kid
667
668     def test_all_children(self):
669         """Test fetching all the "children" of a Node.
670         """
671         node = SCons.Node.Node()
672         n1 = SCons.Node.Node()
673         n2 = SCons.Node.Node()
674         n3 = SCons.Node.Node()
675         n4 = SCons.Node.Node()
676         n5 = SCons.Node.Node()
677         n6 = SCons.Node.Node()
678         n7 = SCons.Node.Node()
679         n8 = SCons.Node.Node()
680         n9 = SCons.Node.Node()
681         n10 = SCons.Node.Node()
682         n11 = SCons.Node.Node()
683         n12 = SCons.Node.Node()
684
685         node.add_source([n1, n2, n3])
686         node.add_dependency([n4, n5, n6])
687         node.implicit = []
688         node.implicit_dict = {}
689         node._add_child(node.implicit, node.implicit_dict, [n7, n8, n9])
690         node._add_child(node.implicit, node.implicit_dict, [n10, n11, n12])
691         node.add_ignore([n2, n5, n8, n11])
692
693         kids = node.all_children()
694         for kid in [n1, n2, n3, n4, n5, n6, n7, n8, n9, n10, n11, n12]:
695             assert kid in kids, kid
696
697     def test_state(self):
698         """Test setting and getting the state of a node
699         """
700         node = SCons.Node.Node()
701         assert node.get_state() == None
702         node.set_state(SCons.Node.executing)
703         assert node.get_state() == SCons.Node.executing
704         assert SCons.Node.pending < SCons.Node.executing
705         assert SCons.Node.executing < SCons.Node.up_to_date
706         assert SCons.Node.up_to_date < SCons.Node.executed
707         assert SCons.Node.executed < SCons.Node.failed
708
709     def test_walker(self):
710         """Test walking a Node tree.
711         """
712
713         n1 = MyNode("n1")
714
715         nw = SCons.Node.Walker(n1)
716         assert not nw.is_done()
717         assert nw.next().name ==  "n1"
718         assert nw.is_done()
719         assert nw.next() == None
720
721         n2 = MyNode("n2")
722         n3 = MyNode("n3")
723         n1.add_source([n2, n3])
724
725         nw = SCons.Node.Walker(n1)
726         n = nw.next()
727         assert n.name ==  "n2", n.name
728         n = nw.next()
729         assert n.name ==  "n3", n.name
730         n = nw.next()
731         assert n.name ==  "n1", n.name
732         n = nw.next()
733         assert n == None, n
734
735         n4 = MyNode("n4")
736         n5 = MyNode("n5")
737         n6 = MyNode("n6")
738         n7 = MyNode("n7")
739         n2.add_source([n4, n5])
740         n3.add_dependency([n6, n7])
741
742         nw = SCons.Node.Walker(n1)
743         assert nw.next().name ==  "n4"
744         assert nw.next().name ==  "n5"
745         assert nw.history.has_key(n2)
746         assert nw.next().name ==  "n2"
747         assert nw.next().name ==  "n6"
748         assert nw.next().name ==  "n7"
749         assert nw.history.has_key(n3)
750         assert nw.next().name ==  "n3"
751         assert nw.history.has_key(n1)
752         assert nw.next().name ==  "n1"
753         assert nw.next() == None
754
755         n8 = MyNode("n8")
756         n8.add_dependency([n3])
757         n7.add_dependency([n8])
758
759         def cycle(node, stack):
760             global cycle_detected
761             cycle_detected = 1
762
763         global cycle_detected
764
765         nw = SCons.Node.Walker(n3, cycle_func = cycle)
766         n = nw.next()
767         assert n.name == "n6", n.name
768         n = nw.next()
769         assert n.name == "n8", n.name
770         assert cycle_detected
771         cycle_detected = None
772         n = nw.next()
773         assert n.name == "n7", n.name
774         n = nw.next()
775         assert nw.next() == None
776
777     def test_rstr(self):
778         """Test the rstr() method."""
779         n1 = MyNode("n1")
780         assert n1.rstr() == 'n1', n1.rstr()
781
782     def test_abspath(self):
783         """Test the get_abspath() method."""
784         n = MyNode("foo")
785         assert n.get_abspath() == str(n), n.get_abspath()
786
787     def test_for_signature(self):
788         """Test the for_signature() method."""
789         n = MyNode("foo")
790         assert n.for_signature() == str(n), n.get_abspath()
791
792     def test_get_string(self):
793         """Test the get_string() method."""
794         class TestNode(MyNode):
795             def __init__(self, name, sig):
796                 MyNode.__init__(self, name)
797                 self.sig = sig
798
799             def for_signature(self):
800                 return self.sig
801             
802         n = TestNode("foo", "bar")
803         assert n.get_string(0) == "foo", n.get_string(0)
804         assert n.get_string(1) == "bar", n.get_string(1)
805
806     def test_arg2nodes(self):
807         """Test the arg2nodes function."""
808         dict = {}
809         class X(SCons.Node.Node):
810             pass
811         def Factory(name, directory = None, create = 1, dict=dict, X=X):
812             if not dict.has_key(name):
813                 dict[name] = X()
814                 dict[name].name = name
815             return dict[name]
816
817         nodes = SCons.Node.arg2nodes("Util.py UtilTests.py", Factory)
818         assert len(nodes) == 1, nodes
819         assert isinstance(nodes[0], X)
820         assert nodes[0].name == "Util.py UtilTests.py"
821
822         if hasattr(types, 'UnicodeType'):
823             code = """if 1:
824                 nodes = SCons.Node.arg2nodes(u"Util.py UtilTests.py", Factory)
825                 assert len(nodes) == 1, nodes
826                 assert isinstance(nodes[0], X)
827                 assert nodes[0].name == u"Util.py UtilTests.py"
828                 \n"""
829             exec code in globals(), locals()
830
831         nodes = SCons.Node.arg2nodes(["Util.py", "UtilTests.py"], Factory)
832         assert len(nodes) == 2, nodes
833         assert isinstance(nodes[0], X)
834         assert isinstance(nodes[1], X)
835         assert nodes[0].name == "Util.py"
836         assert nodes[1].name == "UtilTests.py"
837
838         n1 = Factory("Util.py")
839         nodes = SCons.Node.arg2nodes([n1, "UtilTests.py"], Factory)
840         assert len(nodes) == 2, nodes
841         assert isinstance(nodes[0], X)
842         assert isinstance(nodes[1], X)
843         assert nodes[0].name == "Util.py"
844         assert nodes[1].name == "UtilTests.py"
845
846         class SConsNode(SCons.Node.Node):
847             pass
848         nodes = SCons.Node.arg2nodes(SConsNode())
849         assert len(nodes) == 1, nodes
850         assert isinstance(nodes[0], SConsNode), node
851
852         class OtherNode:
853             pass
854         nodes = SCons.Node.arg2nodes(OtherNode())
855         assert len(nodes) == 1, nodes
856         assert isinstance(nodes[0], OtherNode), node
857
858         def lookup_a(str, F=Factory):
859             if str[0] == 'a':
860                 n = F(str)
861                 n.a = 1
862                 return n
863             else:
864                 return None
865
866         def lookup_b(str, F=Factory):
867             if str[0] == 'b':
868                 n = F(str)
869                 n.b = 1
870                 return n
871             else:
872                 return None
873
874         SCons.Node.arg2nodes_lookups.append(lookup_a)
875         SCons.Node.arg2nodes_lookups.append(lookup_b)
876
877         nodes = SCons.Node.arg2nodes(['aaa', 'bbb', 'ccc'], Factory)
878         assert len(nodes) == 3, nodes
879
880         assert nodes[0].name == 'aaa', nodes[0]
881         assert nodes[0].a == 1, nodes[0]
882         assert not hasattr(nodes[0], 'b'), nodes[0]
883
884         assert nodes[1].name == 'bbb'
885         assert not hasattr(nodes[1], 'a'), nodes[1]
886         assert nodes[1].b == 1, nodes[1]
887
888         assert nodes[2].name == 'ccc'
889         assert not hasattr(nodes[2], 'a'), nodes[1]
890         assert not hasattr(nodes[2], 'b'), nodes[1]
891
892         def lookup_bbbb(str, F=Factory):
893             if str == 'bbbb':
894                 n = F(str)
895                 n.bbbb = 1
896                 return n
897             else:
898                 return None
899
900         def lookup_c(str, F=Factory):
901             if str[0] == 'c':
902                 n = F(str)
903                 n.c = 1
904                 return n
905             else:
906                 return None
907
908         nodes = SCons.Node.arg2nodes(['bbbb', 'ccc'], Factory,
909                                      [lookup_c, lookup_bbbb, lookup_b])
910         assert len(nodes) == 2, nodes
911
912         assert nodes[0].name == 'bbbb'
913         assert not hasattr(nodes[0], 'a'), nodes[1]
914         assert not hasattr(nodes[0], 'b'), nodes[1]
915         assert nodes[0].bbbb == 1, nodes[1]
916         assert not hasattr(nodes[0], 'c'), nodes[0]
917
918         assert nodes[1].name == 'ccc'
919         assert not hasattr(nodes[1], 'a'), nodes[1]
920         assert not hasattr(nodes[1], 'b'), nodes[1]
921         assert not hasattr(nodes[1], 'bbbb'), nodes[0]
922         assert nodes[1].c == 1, nodes[1]
923         
924     def test_literal(self):
925         """Test the is_literal() function."""
926         n=SCons.Node.Node()
927         assert n.is_literal()
928         
929     def test_Annotate(self):
930         """Test using an interface-specific Annotate function."""
931         def my_annotate(node, self=self):
932             node.annotation = self.node_string
933
934         save_Annotate = SCons.Node.Annotate
935         SCons.Node.Annotate = my_annotate
936
937         try:
938             self.node_string = '#1'
939             n = SCons.Node.Node()
940             assert n.annotation == '#1', n.annotation
941
942             self.node_string = '#2'
943             n = SCons.Node.Node()
944             assert n.annotation == '#2', n.annotation
945         finally:
946             SCons.Node.Annotate = save_Annotate
947
948     def test_clear(self):
949         """Test clearing all cached state information."""
950         n = SCons.Node.Node()
951
952         n.set_state(3)
953         n.set_bsig('bsig')
954         n.set_csig('csig')
955         n.includes = 'testincludes'
956         n.found_include = {'testkey':'testvalue'}
957         n.implicit = 'testimplicit'
958
959         n.clear()
960
961         assert n.get_state() is None, n.get_state()
962         assert not hasattr(n, 'bsig'), n.bsig
963         assert not hasattr(n, 'csig'), n.csig
964         assert n.includes is None, n.includes
965         assert n.found_includes == {}, n.found_includes
966         assert n.implicit is None, n.implicit
967
968     def test_get_subst_proxy(self):
969         """Test the get_subst_proxy method."""
970         n = MyNode("test")
971
972         assert n.get_subst_proxy() == n, n.get_subst_proxy()
973
974
975 if __name__ == "__main__":
976     suite = unittest.makeSuite(NodeTestCase, 'test_')
977     if not unittest.TextTestRunner().run(suite).wasSuccessful():
978         sys.exit(1)