86dcc56472315c6c40288d10c69a3d85c46b9435
[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 class MyNonGlobalAction:
57     def __init__(self):
58         self.order = 0
59         self.built_it = None
60         self.built_target =  None
61         self.built_source =  None
62
63     def __call__(self, target, source, env):
64         # Okay, so not ENTIRELY non-global...
65         global built_order
66         self.built_it = 1
67         self.built_target = target
68         self.built_source = source
69         self.built_args = env
70         built_order = built_order + 1
71         self.order = built_order
72         return 0
73
74 class Builder:
75     def targets(self, t):
76         return [t]
77     def get_actions(self):
78         return [MyAction()]
79     def get_contents(self, target, source, env):
80         return 7
81
82 class NoneBuilder(Builder):
83     def execute(self, target, source, env):
84         Builder.execute(self, target, source, env)
85         return None
86
87 class ListBuilder(Builder):
88     def __init__(self, *nodes):
89         self.nodes = nodes
90     def execute(self, target, source, env):
91         if hasattr(self, 'status'):
92             return self.status
93         for n in self.nodes:
94             n.prepare()
95         target = self.nodes[0]
96         self.status = Builder.execute(self, target, source, env)
97
98 class FailBuilder:
99     def execute(self, target, source, env):
100         return 1
101
102 class ExceptBuilder:
103     def execute(self, target, source, env):
104         raise SCons.Errors.BuildError
105
106 class ExceptBuilder2:
107     def execute(self, target, source, env):
108         raise "foo"
109
110 class Environment:
111     def Dictionary(self, *args):
112         return {}
113     def Override(selv, overrides):
114         return overrides
115
116 class Scanner:
117     called = None
118     def __call__(self, node):
119         self.called = 1
120         return node.found_includes
121
122 class MyNode(SCons.Node.Node):
123     """The base Node class contains a number of do-nothing methods that
124     we expect to be overridden by real, functional Node subclasses.  So
125     simulate a real, functional Node subclass.
126     """
127     def __init__(self, name):
128         SCons.Node.Node.__init__(self)
129         self.name = name
130         self.found_includes = []
131     def __str__(self):
132         return self.name
133     def get_found_includes(self, env, scanner, target):
134         return scanner(self)
135
136
137
138 class NodeTestCase(unittest.TestCase):
139
140     def test_build(self):
141         """Test building a node
142         """
143         global built_it, built_order
144
145         # Make sure it doesn't blow up if no builder is set.
146         node = MyNode("www")
147         node.build()
148         assert built_it == None
149
150         node = MyNode("xxx")
151         node.builder_set(Builder())
152         node.env_set(Environment())
153         node.path = "xxx"
154         node.sources = ["yyy", "zzz"]
155         node.build()
156         assert built_it
157         assert built_target[0] == node, built_target[0]
158         assert built_source == ["yyy", "zzz"], built_source
159
160         built_it = None
161         node = MyNode("qqq")
162         node.builder_set(NoneBuilder())
163         node.env_set(Environment())
164         node.path = "qqq"
165         node.sources = ["rrr", "sss"]
166         node.overrides = { "foo" : 1, "bar" : 2 }
167         node.build()
168         assert built_it
169         assert built_target[0] == node, build_target[0]
170         assert built_source == ["rrr", "sss"], built_source
171         assert built_args["foo"] == 1, built_args
172         assert built_args["bar"] == 2, built_args
173
174         fff = MyNode("fff")
175         ggg = MyNode("ggg")
176         lb = ListBuilder(fff, ggg)
177         e = Environment()
178         fff.builder_set(lb)
179         fff.env_set(e)
180         fff.path = "fff"
181         ggg.builder_set(lb)
182         ggg.env_set(e)
183         ggg.path = "ggg"
184         fff.sources = ["hhh", "iii"]
185         ggg.sources = ["hhh", "iii"]
186         # [Charles C. 1/7/2002] Uhhh, why are there no asserts here?
187
188         built_it = None
189         built_order = 0
190         node = MyNode("xxx")
191         node.builder_set(Builder())
192         node.env_set(Environment())
193         node.sources = ["yyy", "zzz"]
194         pre1 = MyNonGlobalAction()
195         pre2 = MyNonGlobalAction()
196         post1 = MyNonGlobalAction()
197         post2 = MyNonGlobalAction()
198         node.add_pre_action(pre1)
199         node.add_pre_action(pre2)
200         node.add_post_action(post1)
201         node.add_post_action(post2)
202         node.build()
203         assert built_it
204         assert pre1.built_it
205         assert pre2.built_it
206         assert post1.built_it
207         assert post2.built_it
208         assert pre1.order == 1, pre1.order
209         assert pre2.order == 2, pre1.order
210         # The action of the builder itself is order 3...
211         assert post1.order == 4, pre1.order
212         assert post2.order == 5, pre1.order
213
214         for act in [ pre1, pre2, post1, post2 ]:
215             assert type(act.built_target[0]) == type(MyNode("bar")), type(act.built_target[0])
216             assert str(act.built_target[0]) == "xxx", str(act.built_target[0])
217             assert act.built_source == ["yyy", "zzz"], act.built_source
218
219     def test_visited(self):
220         """Test the base visited() method
221
222         Just make sure it's there and we can call it.
223         """
224         n = SCons.Node.Node()
225         n.visited()
226             
227     def test_depends_on(self):
228         """Test the depends_on() method
229         """
230         parent = SCons.Node.Node()
231         child = SCons.Node.Node()
232         parent.add_dependency([child])
233         assert parent.depends_on([child])
234         
235     def test_builder_set(self):
236         """Test setting a Node's Builder
237         """
238         node = SCons.Node.Node()
239         b = Builder()
240         node.builder_set(b)
241         assert node.builder == b
242
243     def test_builder_sig_adapter(self):
244         """Test the node's adapter for builder signatures
245         """
246         node = SCons.Node.Node()
247         node.builder_set(Builder())
248         node.env_set(Environment())
249         c = node.builder_sig_adapter().get_contents()
250         assert c == 7, c
251
252     def test_current(self):
253         """Test the default current() method
254         """
255         node = SCons.Node.Node()
256         assert node.current() is None
257
258     def test_env_set(self):
259         """Test setting a Node's Environment
260         """
261         node = SCons.Node.Node()
262         e = Environment()
263         node.env_set(e)
264         assert node.env == e
265
266     def test_get_actions(self):
267         """Test fetching a Node's action list
268         """
269         node = SCons.Node.Node()
270         node.builder_set(Builder())
271         a = node.builder.get_actions()
272         assert isinstance(a[0], MyAction), a[0]
273
274     def test_set_bsig(self):
275         """Test setting a Node's signature
276         """
277         node = SCons.Node.Node()
278         node.set_bsig('www')
279         assert node.bsig == 'www'
280
281     def test_get_bsig(self):
282         """Test fetching a Node's signature
283         """
284         node = SCons.Node.Node()
285         node.set_bsig('xxx')
286         assert node.get_bsig() == 'xxx'
287
288     def test_set_csig(self):
289         """Test setting a Node's signature
290         """
291         node = SCons.Node.Node()
292         node.set_csig('yyy')
293         assert node.csig == 'yyy'
294
295     def test_get_csig(self):
296         """Test fetching a Node's signature
297         """
298         node = SCons.Node.Node()
299         node.set_csig('zzz')
300         assert node.get_csig() == 'zzz'
301
302     def test_store_bsig(self):
303         """Test calling the method to store a build signature
304         """
305         node = SCons.Node.Node()
306         node.store_bsig()
307
308     def test_store_csig(self):
309         """Test calling the method to store a content signature
310         """
311         node = SCons.Node.Node()
312         node.store_csig()
313
314     def test_get_timestamp(self):
315         """Test calling the method to fetch a Node's timestamp
316         """
317         node = SCons.Node.Node()
318         assert node.get_timestamp() == 0
319
320     def test_store_timestamp(self):
321         """Test calling the method to store a timestamp
322         """
323         node = SCons.Node.Node()
324         node.store_timestamp()
325
326     def test_set_precious(self):
327         """Test setting a Node's precious value
328         """
329         node = SCons.Node.Node()
330         node.set_precious()
331         assert node.precious
332         node.set_precious(7)
333         assert node.precious == 7
334
335     def test_add_dependency(self):
336         """Test adding dependencies to a Node's list.
337         """
338         node = SCons.Node.Node()
339         assert node.depends == []
340
341         zero = SCons.Node.Node()
342         try:
343             node.add_dependency(zero)
344         except TypeError:
345             pass
346         else:
347             assert 0
348
349         one = SCons.Node.Node()
350         two = SCons.Node.Node()
351         three = SCons.Node.Node()
352         four = SCons.Node.Node()
353
354         node.add_dependency([one])
355         assert node.depends == [one]
356         node.add_dependency([two, three])
357         assert node.depends == [one, two, three]
358         node.add_dependency([three, four, one])
359         assert node.depends == [one, two, three, four]
360
361         assert zero.get_parents() == []
362         assert one.get_parents() == [node]
363         assert two.get_parents() == [node]
364         assert three.get_parents() == [node]
365         assert four.get_parents() == [node]
366
367
368     def test_add_source(self):
369         """Test adding sources to a Node's list.
370         """
371         node = SCons.Node.Node()
372         assert node.sources == []
373
374         zero = SCons.Node.Node()
375         try:
376             node.add_source(zero)
377         except TypeError:
378             pass
379         else:
380             assert 0
381
382         one = SCons.Node.Node()
383         two = SCons.Node.Node()
384         three = SCons.Node.Node()
385         four = SCons.Node.Node()
386
387         node.add_source([one])
388         assert node.sources == [one]
389         node.add_source([two, three])
390         assert node.sources == [one, two, three]
391         node.add_source([three, four, one])
392         assert node.sources == [one, two, three, four]
393
394         assert zero.get_parents() == []
395         assert one.get_parents() == [node]
396         assert two.get_parents() == [node]
397         assert three.get_parents() == [node]
398         assert four.get_parents() == [node]
399
400     def test_add_ignore(self):
401         """Test adding files whose dependencies should be ignored.
402         """
403         node = SCons.Node.Node()
404         assert node.ignore == []
405
406         zero = SCons.Node.Node()
407         try:
408             node.add_ignore(zero)
409         except TypeError:
410             pass
411         else:
412             assert 0
413
414         one = SCons.Node.Node()
415         two = SCons.Node.Node()
416         three = SCons.Node.Node()
417         four = SCons.Node.Node()
418
419         node.add_ignore([one])
420         assert node.ignore == [one]
421         node.add_ignore([two, three])
422         assert node.ignore == [one, two, three]
423         node.add_ignore([three, four, one])
424         assert node.ignore == [one, two, three, four]
425
426         assert zero.get_parents() == []
427         assert one.get_parents() == [node]
428         assert two.get_parents() == [node]
429         assert three.get_parents() == [node]
430         assert four.get_parents() == [node]
431
432     def test_get_found_includes(self):
433         """Test the default get_found_includes() method
434         """
435         node = SCons.Node.Node()
436         target = SCons.Node.Node()
437         e = Environment()
438         deps = node.get_found_includes(e, None, target)
439         assert deps == [], deps
440
441     def test_get_implicit_deps(self):
442         """Test get_implicit_deps()
443         """
444         node = MyNode("nnn")
445         target = MyNode("ttt")
446         env = Environment()
447
448         # No scanner at all returns []
449         deps = node.get_implicit_deps(env, None, target)
450         assert deps == [], deps
451
452         s = Scanner()
453         d = MyNode("ddd")
454         node.found_includes = [d]
455
456         # Simple return of the found includes
457         deps = node.get_implicit_deps(env, s, target)
458         assert deps == [d], deps
459
460         # No "recursive" attribute on scanner doesn't recurse
461         e = MyNode("eee")
462         d.found_includes = [e]
463         deps = node.get_implicit_deps(env, s, target)
464         assert deps == [d], map(str, deps)
465
466         # Explicit "recursive" attribute on scanner doesn't recurse
467         s.recursive = None
468         deps = node.get_implicit_deps(env, s, target)
469         assert deps == [d], map(str, deps)
470
471         # Explicit "recursive" attribute on scanner which does recurse
472         s.recursive = 1
473         deps = node.get_implicit_deps(env, s, target)
474         assert deps == [d, e], map(str, deps)
475
476         # Recursive scanning eliminates duplicates
477         f = MyNode("fff")
478         d.found_includes = [e, f]
479         e.found_includes = [f]
480         deps = node.get_implicit_deps(env, s, target)
481         assert deps == [d, e, f], map(str, deps)
482
483     def test_scan(self):
484         """Test Scanner functionality
485         """
486         node = MyNode("nnn")
487         node.builder = 1
488         node.env_set(Environment())
489         s = Scanner()
490
491         d = MyNode("ddd")
492         node.found_includes = [d]
493
494         assert node.target_scanner == None, node.target_scanner
495         node.target_scanner = s
496         assert node.implicit is None
497
498         node.scan()
499         assert s.called
500         assert node.implicit == [d], node.implicit
501
502     def test_scanner_key(self):
503         """Test that a scanner_key() method exists"""
504         assert SCons.Node.Node().scanner_key() == None
505
506     def test_children(self):
507         """Test fetching the non-ignored "children" of a Node.
508         """
509         node = SCons.Node.Node()
510         n1 = SCons.Node.Node()
511         n2 = SCons.Node.Node()
512         n3 = SCons.Node.Node()
513         n4 = SCons.Node.Node()
514         n5 = SCons.Node.Node()
515         n6 = SCons.Node.Node()
516         n7 = SCons.Node.Node()
517         n8 = SCons.Node.Node()
518         n9 = SCons.Node.Node()
519         n10 = SCons.Node.Node()
520         n11 = SCons.Node.Node()
521         n12 = SCons.Node.Node()
522
523         node.add_source([n1, n2, n3])
524         node.add_dependency([n4, n5, n6])
525         node.implicit = []
526         node._add_child(node.implicit, [n7, n8, n9])
527         node._add_child(node.implicit, [n10, n11, n12])
528         node.add_ignore([n2, n5, n8, n11])
529
530         kids = node.children()
531         for kid in [n1, n3, n4, n6, n7, n9, n10, n12]:
532             assert kid in kids, kid
533         for kid in [n2, n5, n8, n11]:
534             assert not kid in kids, kid
535
536     def test_all_children(self):
537         """Test fetching all the "children" of a Node.
538         """
539         node = SCons.Node.Node()
540         n1 = SCons.Node.Node()
541         n2 = SCons.Node.Node()
542         n3 = SCons.Node.Node()
543         n4 = SCons.Node.Node()
544         n5 = SCons.Node.Node()
545         n6 = SCons.Node.Node()
546         n7 = SCons.Node.Node()
547         n8 = SCons.Node.Node()
548         n9 = SCons.Node.Node()
549         n10 = SCons.Node.Node()
550         n11 = SCons.Node.Node()
551         n12 = SCons.Node.Node()
552
553         node.add_source([n1, n2, n3])
554         node.add_dependency([n4, n5, n6])
555         node.implicit = []
556         node._add_child(node.implicit, [n7, n8, n9])
557         node._add_child(node.implicit, [n10, n11, n12])
558         node.add_ignore([n2, n5, n8, n11])
559
560         kids = node.all_children()
561         for kid in [n1, n2, n3, n4, n5, n6, n7, n8, n9, n10, n11, n12]:
562             assert kid in kids, kid
563
564     def test_state(self):
565         """Test setting and getting the state of a node
566         """
567         node = SCons.Node.Node()
568         assert node.get_state() == None
569         node.set_state(SCons.Node.executing)
570         assert node.get_state() == SCons.Node.executing
571         assert SCons.Node.pending < SCons.Node.executing
572         assert SCons.Node.executing < SCons.Node.up_to_date
573         assert SCons.Node.up_to_date < SCons.Node.executed
574         assert SCons.Node.executed < SCons.Node.failed
575
576     def test_walker(self):
577         """Test walking a Node tree.
578         """
579
580         n1 = MyNode("n1")
581
582         nw = SCons.Node.Walker(n1)
583         assert not nw.is_done()
584         assert nw.next().name ==  "n1"
585         assert nw.is_done()
586         assert nw.next() == None
587
588         n2 = MyNode("n2")
589         n3 = MyNode("n3")
590         n1.add_source([n2, n3])
591
592         nw = SCons.Node.Walker(n1)
593         assert nw.next().name ==  "n2"
594         assert nw.next().name ==  "n3"
595         assert nw.next().name ==  "n1"
596         assert nw.next() == None
597
598         n4 = MyNode("n4")
599         n5 = MyNode("n5")
600         n6 = MyNode("n6")
601         n7 = MyNode("n7")
602         n2.add_source([n4, n5])
603         n3.add_dependency([n6, n7])
604
605         nw = SCons.Node.Walker(n1)
606         assert nw.next().name ==  "n4"
607         assert nw.next().name ==  "n5"
608         assert nw.history.has_key(n2)
609         assert nw.next().name ==  "n2"
610         assert nw.next().name ==  "n6"
611         assert nw.next().name ==  "n7"
612         assert nw.history.has_key(n3)
613         assert nw.next().name ==  "n3"
614         assert nw.history.has_key(n1)
615         assert nw.next().name ==  "n1"
616         assert nw.next() == None
617
618         n8 = MyNode("n8")
619         n8.add_dependency([n3])
620         n7.add_dependency([n8])
621
622         def cycle(node, stack):
623             global cycle_detected
624             cycle_detected = 1
625
626         global cycle_detected
627
628         nw = SCons.Node.Walker(n3, cycle_func = cycle)
629         n = nw.next()
630         assert n.name == "n6", n.name
631         n = nw.next()
632         assert n.name == "n8", n.name
633         assert cycle_detected
634         cycle_detected = None
635         n = nw.next()
636         assert n.name == "n7", n.name
637         n = nw.next()
638         assert nw.next() == None
639
640     def test_rstr(self):
641         """Test the rstr() method."""
642         n1 = MyNode("n1")
643         assert n1.rstr() == 'n1', n1.rstr()
644
645     def test_arg2nodes(self):
646         """Test the arg2nodes function."""
647         dict = {}
648         class X(SCons.Node.Node):
649             pass
650         def Factory(name, directory = None, create = 1, dict=dict, X=X):
651             if not dict.has_key(name):
652                 dict[name] = X()
653                 dict[name].name = name
654             return dict[name]
655
656         nodes = SCons.Node.arg2nodes("Util.py UtilTests.py", Factory)
657         assert len(nodes) == 1, nodes
658         assert isinstance(nodes[0], X)
659         assert nodes[0].name == "Util.py UtilTests.py"
660
661         if hasattr(types, 'UnicodeType'):
662             code = """if 1:
663                 nodes = SCons.Node.arg2nodes(u"Util.py UtilTests.py", Factory)
664                 assert len(nodes) == 1, nodes
665                 assert isinstance(nodes[0], X)
666                 assert nodes[0].name == u"Util.py UtilTests.py"
667                 \n"""
668             exec code in globals(), locals()
669
670         nodes = SCons.Node.arg2nodes(["Util.py", "UtilTests.py"], Factory)
671         assert len(nodes) == 2, nodes
672         assert isinstance(nodes[0], X)
673         assert isinstance(nodes[1], X)
674         assert nodes[0].name == "Util.py"
675         assert nodes[1].name == "UtilTests.py"
676
677         n1 = Factory("Util.py")
678         nodes = SCons.Node.arg2nodes([n1, "UtilTests.py"], Factory)
679         assert len(nodes) == 2, nodes
680         assert isinstance(nodes[0], X)
681         assert isinstance(nodes[1], X)
682         assert nodes[0].name == "Util.py"
683         assert nodes[1].name == "UtilTests.py"
684
685         class SConsNode(SCons.Node.Node):
686             pass
687         nodes = SCons.Node.arg2nodes(SConsNode())
688         assert len(nodes) == 1, nodes
689         assert isinstance(nodes[0], SConsNode), node
690
691         class OtherNode:
692             pass
693         nodes = SCons.Node.arg2nodes(OtherNode())
694         assert len(nodes) == 1, nodes
695         assert isinstance(nodes[0], OtherNode), node
696
697         def lookup_a(str, F=Factory):
698             if str[0] == 'a':
699                 n = F(str)
700                 n.a = 1
701                 return n
702             else:
703                 return None
704
705         def lookup_b(str, F=Factory):
706             if str[0] == 'b':
707                 n = F(str)
708                 n.b = 1
709                 return n
710             else:
711                 return None
712
713         SCons.Node.arg2nodes_lookups.append(lookup_a)
714         SCons.Node.arg2nodes_lookups.append(lookup_b)
715
716         nodes = SCons.Node.arg2nodes(['aaa', 'bbb', 'ccc'], Factory)
717         assert len(nodes) == 3, nodes
718
719         assert nodes[0].name == 'aaa', nodes[0]
720         assert nodes[0].a == 1, nodes[0]
721         assert not hasattr(nodes[0], 'b'), nodes[0]
722
723         assert nodes[1].name == 'bbb'
724         assert not hasattr(nodes[1], 'a'), nodes[1]
725         assert nodes[1].b == 1, nodes[1]
726
727         assert nodes[2].name == 'ccc'
728         assert not hasattr(nodes[2], 'a'), nodes[1]
729         assert not hasattr(nodes[2], 'b'), nodes[1]
730
731         def lookup_bbbb(str, F=Factory):
732             if str == 'bbbb':
733                 n = F(str)
734                 n.bbbb = 1
735                 return n
736             else:
737                 return None
738
739         def lookup_c(str, F=Factory):
740             if str[0] == 'c':
741                 n = F(str)
742                 n.c = 1
743                 return n
744             else:
745                 return None
746
747         nodes = SCons.Node.arg2nodes(['bbbb', 'ccc'], Factory,
748                                      [lookup_c, lookup_bbbb, lookup_b])
749         assert len(nodes) == 2, nodes
750
751         assert nodes[0].name == 'bbbb'
752         assert not hasattr(nodes[0], 'a'), nodes[1]
753         assert not hasattr(nodes[0], 'b'), nodes[1]
754         assert nodes[0].bbbb == 1, nodes[1]
755         assert not hasattr(nodes[0], 'c'), nodes[0]
756
757         assert nodes[1].name == 'ccc'
758         assert not hasattr(nodes[1], 'a'), nodes[1]
759         assert not hasattr(nodes[1], 'b'), nodes[1]
760         assert not hasattr(nodes[1], 'bbbb'), nodes[0]
761         assert nodes[1].c == 1, nodes[1]
762         
763     def test_literal(self):
764         """Test the is_literal() function."""
765         n=SCons.Node.Node()
766         assert n.is_literal()
767         
768     def test_Annotate(self):
769         """Test using an interface-specific Annotate function."""
770         def my_annotate(node, self=self):
771             node.annotation = self.node_string
772
773         save_Annotate = SCons.Node.Annotate
774         SCons.Node.Annotate = my_annotate
775
776         try:
777             self.node_string = '#1'
778             n = SCons.Node.Node()
779             assert n.annotation == '#1', n.annotation
780
781             self.node_string = '#2'
782             n = SCons.Node.Node()
783             assert n.annotation == '#2', n.annotation
784         finally:
785             SCons.Node.Annotate = save_Annotate
786
787
788 if __name__ == "__main__":
789     suite = unittest.makeSuite(NodeTestCase, 'test_')
790     if not unittest.TextTestRunner().run(suite).wasSuccessful():
791         sys.exit(1)