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:
12 # The above copyright notice and this permission notice shall be included
13 # in all copies or substantial portions of the Software.
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.
24 __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
46 def __call__(self, target, source, env):
47 global built_it, built_target, built_source, built_args, built_order
52 built_order = built_order + 1
53 self.order = built_order
56 class MyNonGlobalAction:
60 self.built_target = None
61 self.built_source = None
63 def __call__(self, target, source, env):
64 # Okay, so not ENTIRELY non-global...
67 self.built_target = target
68 self.built_source = source
70 built_order = built_order + 1
71 self.order = built_order
77 def get_actions(self):
79 def get_contents(self, target, source, env):
82 class NoneBuilder(Builder):
83 def execute(self, target, source, env):
84 Builder.execute(self, target, source, env)
87 class ListBuilder(Builder):
88 def __init__(self, *nodes):
90 def execute(self, target, source, env):
91 if hasattr(self, 'status'):
95 target = self.nodes[0]
96 self.status = Builder.execute(self, target, source, env)
99 def execute(self, target, source, env):
103 def execute(self, target, source, env):
104 raise SCons.Errors.BuildError
106 class ExceptBuilder2:
107 def execute(self, target, source, env):
111 def Dictionary(self, *args):
113 def Override(selv, overrides):
118 def __call__(self, node):
120 return node.found_includes
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.
127 def __init__(self, name):
128 SCons.Node.Node.__init__(self)
130 self.found_includes = []
133 def get_found_includes(self, env, scanner, target):
138 class NodeTestCase(unittest.TestCase):
140 def test_build(self):
141 """Test building a node
143 global built_it, built_order
145 # Make sure it doesn't blow up if no builder is set.
148 assert built_it == None
151 node.builder_set(Builder())
152 node.env_set(Environment())
154 node.sources = ["yyy", "zzz"]
157 assert built_target[0] == node, built_target[0]
158 assert built_source == ["yyy", "zzz"], built_source
162 node.builder_set(NoneBuilder())
163 node.env_set(Environment())
165 node.sources = ["rrr", "sss"]
166 node.overrides = { "foo" : 1, "bar" : 2 }
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
176 lb = ListBuilder(fff, ggg)
184 fff.sources = ["hhh", "iii"]
185 ggg.sources = ["hhh", "iii"]
186 # [Charles C. 1/7/2002] Uhhh, why are there no asserts here?
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)
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
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
219 def test_visited(self):
220 """Test the base visited() method
222 Just make sure it's there and we can call it.
224 n = SCons.Node.Node()
227 def test_depends_on(self):
228 """Test the depends_on() method
230 parent = SCons.Node.Node()
231 child = SCons.Node.Node()
232 parent.add_dependency([child])
233 assert parent.depends_on([child])
235 def test_builder_set(self):
236 """Test setting a Node's Builder
238 node = SCons.Node.Node()
241 assert node.builder == b
243 def test_builder_sig_adapter(self):
244 """Test the node's adapter for builder signatures
246 node = SCons.Node.Node()
247 node.builder_set(Builder())
248 node.env_set(Environment())
249 c = node.builder_sig_adapter().get_contents()
252 def test_current(self):
253 """Test the default current() method
255 node = SCons.Node.Node()
256 assert node.current() is None
258 def test_env_set(self):
259 """Test setting a Node's Environment
261 node = SCons.Node.Node()
266 def test_get_actions(self):
267 """Test fetching a Node's action list
269 node = SCons.Node.Node()
270 node.builder_set(Builder())
271 a = node.builder.get_actions()
272 assert isinstance(a[0], MyAction), a[0]
274 def test_set_bsig(self):
275 """Test setting a Node's signature
277 node = SCons.Node.Node()
279 assert node.bsig == 'www'
281 def test_get_bsig(self):
282 """Test fetching a Node's signature
284 node = SCons.Node.Node()
286 assert node.get_bsig() == 'xxx'
288 def test_set_csig(self):
289 """Test setting a Node's signature
291 node = SCons.Node.Node()
293 assert node.csig == 'yyy'
295 def test_get_csig(self):
296 """Test fetching a Node's signature
298 node = SCons.Node.Node()
300 assert node.get_csig() == 'zzz'
302 def test_store_bsig(self):
303 """Test calling the method to store a build signature
305 node = SCons.Node.Node()
308 def test_store_csig(self):
309 """Test calling the method to store a content signature
311 node = SCons.Node.Node()
314 def test_get_timestamp(self):
315 """Test calling the method to fetch a Node's timestamp
317 node = SCons.Node.Node()
318 assert node.get_timestamp() == 0
320 def test_store_timestamp(self):
321 """Test calling the method to store a timestamp
323 node = SCons.Node.Node()
324 node.store_timestamp()
326 def test_set_precious(self):
327 """Test setting a Node's precious value
329 node = SCons.Node.Node()
333 assert node.precious == 7
335 def test_add_dependency(self):
336 """Test adding dependencies to a Node's list.
338 node = SCons.Node.Node()
339 assert node.depends == []
341 zero = SCons.Node.Node()
343 node.add_dependency(zero)
349 one = SCons.Node.Node()
350 two = SCons.Node.Node()
351 three = SCons.Node.Node()
352 four = SCons.Node.Node()
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]
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]
368 def test_add_source(self):
369 """Test adding sources to a Node's list.
371 node = SCons.Node.Node()
372 assert node.sources == []
374 zero = SCons.Node.Node()
376 node.add_source(zero)
382 one = SCons.Node.Node()
383 two = SCons.Node.Node()
384 three = SCons.Node.Node()
385 four = SCons.Node.Node()
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]
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]
400 def test_add_ignore(self):
401 """Test adding files whose dependencies should be ignored.
403 node = SCons.Node.Node()
404 assert node.ignore == []
406 zero = SCons.Node.Node()
408 node.add_ignore(zero)
414 one = SCons.Node.Node()
415 two = SCons.Node.Node()
416 three = SCons.Node.Node()
417 four = SCons.Node.Node()
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]
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]
432 def test_get_found_includes(self):
433 """Test the default get_found_includes() method
435 node = SCons.Node.Node()
436 target = SCons.Node.Node()
438 deps = node.get_found_includes(e, None, target)
439 assert deps == [], deps
441 def test_get_implicit_deps(self):
442 """Test get_implicit_deps()
445 target = MyNode("ttt")
448 # No scanner at all returns []
449 deps = node.get_implicit_deps(env, None, target)
450 assert deps == [], deps
454 node.found_includes = [d]
456 # Simple return of the found includes
457 deps = node.get_implicit_deps(env, s, target)
458 assert deps == [d], deps
460 # No "recursive" attribute on scanner doesn't recurse
462 d.found_includes = [e]
463 deps = node.get_implicit_deps(env, s, target)
464 assert deps == [d], map(str, deps)
466 # Explicit "recursive" attribute on scanner doesn't recurse
468 deps = node.get_implicit_deps(env, s, target)
469 assert deps == [d], map(str, deps)
471 # Explicit "recursive" attribute on scanner which does recurse
473 deps = node.get_implicit_deps(env, s, target)
474 assert deps == [d, e], map(str, deps)
476 # Recursive scanning eliminates duplicates
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)
484 """Test Scanner functionality
488 node.env_set(Environment())
492 node.found_includes = [d]
494 assert node.target_scanner == None, node.target_scanner
495 node.target_scanner = s
496 assert node.implicit is None
500 assert node.implicit == [d], node.implicit
502 def test_scanner_key(self):
503 """Test that a scanner_key() method exists"""
504 assert SCons.Node.Node().scanner_key() == None
506 def test_children(self):
507 """Test fetching the non-ignored "children" of a Node.
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()
523 node.add_source([n1, n2, n3])
524 node.add_dependency([n4, n5, n6])
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])
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
536 def test_all_children(self):
537 """Test fetching all the "children" of a Node.
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()
553 node.add_source([n1, n2, n3])
554 node.add_dependency([n4, n5, n6])
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])
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
564 def test_state(self):
565 """Test setting and getting the state of a node
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
576 def test_walker(self):
577 """Test walking a Node tree.
582 nw = SCons.Node.Walker(n1)
583 assert not nw.is_done()
584 assert nw.next().name == "n1"
586 assert nw.next() == None
590 n1.add_source([n2, n3])
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
602 n2.add_source([n4, n5])
603 n3.add_dependency([n6, n7])
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
619 n8.add_dependency([n3])
620 n7.add_dependency([n8])
622 def cycle(node, stack):
623 global cycle_detected
626 global cycle_detected
628 nw = SCons.Node.Walker(n3, cycle_func = cycle)
630 assert n.name == "n6", n.name
632 assert n.name == "n8", n.name
633 assert cycle_detected
634 cycle_detected = None
636 assert n.name == "n7", n.name
638 assert nw.next() == None
641 """Test the rstr() method."""
643 assert n1.rstr() == 'n1', n1.rstr()
645 def test_arg2nodes(self):
646 """Test the arg2nodes function."""
648 class X(SCons.Node.Node):
650 def Factory(name, directory = None, create = 1, dict=dict, X=X):
651 if not dict.has_key(name):
653 dict[name].name = name
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"
661 if hasattr(types, 'UnicodeType'):
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"
668 exec code in globals(), locals()
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"
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"
685 class SConsNode(SCons.Node.Node):
687 nodes = SCons.Node.arg2nodes(SConsNode())
688 assert len(nodes) == 1, nodes
689 assert isinstance(nodes[0], SConsNode), node
693 nodes = SCons.Node.arg2nodes(OtherNode())
694 assert len(nodes) == 1, nodes
695 assert isinstance(nodes[0], OtherNode), node
697 def lookup_a(str, F=Factory):
705 def lookup_b(str, F=Factory):
713 SCons.Node.arg2nodes_lookups.append(lookup_a)
714 SCons.Node.arg2nodes_lookups.append(lookup_b)
716 nodes = SCons.Node.arg2nodes(['aaa', 'bbb', 'ccc'], Factory)
717 assert len(nodes) == 3, nodes
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]
723 assert nodes[1].name == 'bbb'
724 assert not hasattr(nodes[1], 'a'), nodes[1]
725 assert nodes[1].b == 1, nodes[1]
727 assert nodes[2].name == 'ccc'
728 assert not hasattr(nodes[2], 'a'), nodes[1]
729 assert not hasattr(nodes[2], 'b'), nodes[1]
731 def lookup_bbbb(str, F=Factory):
739 def lookup_c(str, F=Factory):
747 nodes = SCons.Node.arg2nodes(['bbbb', 'ccc'], Factory,
748 [lookup_c, lookup_bbbb, lookup_b])
749 assert len(nodes) == 2, nodes
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]
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]
763 def test_literal(self):
764 """Test the is_literal() function."""
766 assert n.is_literal()
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
773 save_Annotate = SCons.Node.Annotate
774 SCons.Node.Annotate = my_annotate
777 self.node_string = '#1'
778 n = SCons.Node.Node()
779 assert n.annotation == '#1', n.annotation
781 self.node_string = '#2'
782 n = SCons.Node.Node()
783 assert n.annotation == '#2', n.annotation
785 SCons.Node.Annotate = save_Annotate
788 if __name__ == "__main__":
789 suite = unittest.makeSuite(NodeTestCase, 'test_')
790 if not unittest.TextTestRunner().run(suite).wasSuccessful():