# # __COPYRIGHT__ # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" import os import sys import types import unittest import SCons.Errors import SCons.Node built_it = None built_target = None built_source = None cycle_detected = None built_order = 0 class MyAction: def __init__(self): self.order = 0 def __call__(self, target, source, env, errfunc): global built_it, built_target, built_source, built_args, built_order built_it = 1 built_target = target built_source = source built_args = env built_order = built_order + 1 self.order = built_order return 0 def get_actions(self): return [self] class MyNonGlobalAction: def __init__(self): self.order = 0 self.built_it = None self.built_target = None self.built_source = None def __call__(self, target, source, env, errfunc): # Okay, so not ENTIRELY non-global... global built_order self.built_it = 1 self.built_target = target self.built_source = source self.built_args = env built_order = built_order + 1 self.order = built_order return 0 def get_actions(self): return [self] class Environment: def __init__(self, **kw): self._dict = {} self._dict.update(kw) def __getitem__(self, key): return self._dict[key] def Dictionary(self, *args): return {} def Override(self, overrides): d = self._dict.copy() d.update(overrides) return apply(Environment, (), d) def _update(self, dict): self._dict.update(dict) class Builder: def __init__(self): self.env = Environment() self.overrides = {} self.action = MyAction() def targets(self, t): return [t] def get_actions(self): return [self.action] def get_contents(self, target, source, env): return 7 class NoneBuilder(Builder): def execute(self, target, source, env): Builder.execute(self, target, source, env) return None class ListBuilder(Builder): def __init__(self, *nodes): Builder.__init__(self) self.nodes = nodes def execute(self, target, source, env): if hasattr(self, 'status'): return self.status for n in self.nodes: n.prepare() target = self.nodes[0] self.status = Builder.execute(self, target, source, env) class FailBuilder: def execute(self, target, source, env): return 1 class ExceptBuilder: def execute(self, target, source, env): raise SCons.Errors.BuildError class ExceptBuilder2: def execute(self, target, source, env): raise "foo" class Scanner: called = None def __call__(self, node): self.called = 1 return node.found_includes class MyNode(SCons.Node.Node): """The base Node class contains a number of do-nothing methods that we expect to be overridden by real, functional Node subclasses. So simulate a real, functional Node subclass. """ def __init__(self, name): SCons.Node.Node.__init__(self) self.name = name self.found_includes = [] def __str__(self): return self.name def get_found_includes(self, env, scanner, target): return scanner(self) class NodeTestCase(unittest.TestCase): def test_build(self): """Test building a node """ global built_it, built_order # Make sure it doesn't blow up if no builder is set. node = MyNode("www") node.build() assert built_it == None node.build(extra_kw_argument = 1) assert built_it == None node = MyNode("xxx") node.builder_set(Builder()) node.env_set(Environment()) node.path = "xxx" node.sources = ["yyy", "zzz"] node.build() assert built_it assert built_target == [node], built_target assert built_source == ["yyy", "zzz"], built_source built_it = None node = MyNode("qqq") node.builder_set(NoneBuilder()) node.env_set(Environment()) node.path = "qqq" node.sources = ["rrr", "sss"] node.builder.overrides = { "foo" : 1, "bar" : 2 } node.build() assert built_it assert built_target == [node], built_target assert built_source == ["rrr", "sss"], built_source assert built_args["foo"] == 1, built_args assert built_args["bar"] == 2, built_args fff = MyNode("fff") ggg = MyNode("ggg") lb = ListBuilder(fff, ggg) e = Environment() fff.builder_set(lb) fff.env_set(e) fff.path = "fff" ggg.builder_set(lb) ggg.env_set(e) ggg.path = "ggg" fff.sources = ["hhh", "iii"] ggg.sources = ["hhh", "iii"] # [Charles C. 1/7/2002] Uhhh, why are there no asserts here? # [SK, 15 May 2003] I dunno, let's add some... built_it = None fff.build() assert built_it assert built_target == [fff], built_target assert built_source == ["hhh", "iii"], built_source built_it = None ggg.build() assert built_it assert built_target == [ggg], built_target assert built_source == ["hhh", "iii"], built_source built_it = None jjj = MyNode("jjj") b = Builder() jjj.builder_set(b) # NOTE: No env_set()! We should pull the environment from the builder. b.env = Environment() b.overrides = { "on" : 3, "off" : 4 } e.builder = b jjj.build() assert built_it assert built_target[0] == jjj, built_target[0] assert built_source == [], built_source assert built_args["on"] == 3, built_args assert built_args["off"] == 4, built_args built_it = None built_order = 0 node = MyNode("xxx") node.builder_set(Builder()) node.env_set(Environment()) node.sources = ["yyy", "zzz"] pre1 = MyNonGlobalAction() pre2 = MyNonGlobalAction() post1 = MyNonGlobalAction() post2 = MyNonGlobalAction() node.add_pre_action(pre1) node.add_pre_action(pre2) node.add_post_action(post1) node.add_post_action(post2) node.build() assert built_it assert pre1.built_it assert pre2.built_it assert post1.built_it assert post2.built_it assert pre1.order == 1, pre1.order assert pre2.order == 2, pre1.order # The action of the builder itself is order 3... assert post1.order == 4, pre1.order assert post2.order == 5, pre1.order for act in [ pre1, pre2, post1, post2 ]: assert type(act.built_target[0]) == type(MyNode("bar")), type(act.built_target[0]) assert str(act.built_target[0]) == "xxx", str(act.built_target[0]) assert act.built_source == ["yyy", "zzz"], act.built_source def test_retrieve_from_cache(self): """Test the base retrieve_from_cache() method""" n = SCons.Node.Node() r = n.retrieve_from_cache() assert r == 0, r def test_visited(self): """Test the base visited() method Just make sure it's there and we can call it. """ n = SCons.Node.Node() n.visited() def test_depends_on(self): """Test the depends_on() method """ parent = SCons.Node.Node() child = SCons.Node.Node() parent.add_dependency([child]) assert parent.depends_on([child]) def test_builder_set(self): """Test setting a Node's Builder """ node = SCons.Node.Node() b = Builder() node.builder_set(b) assert node.builder == b def test_has_builder(self): """Test the has_builder() method """ n1 = SCons.Node.Node() assert n1.has_builder() == 0 n1.builder_set(Builder()) assert n1.has_builder() == 1 def test_is_derived(self): """Test the is_derived() method """ n1 = SCons.Node.Node() n2 = SCons.Node.Node() n3 = SCons.Node.Node() n2.builder_set(Builder()) n3.side_effect = 1 assert n1.is_derived() == 0 assert n2.is_derived() == 1 assert n3.is_derived() == 1 def test_alter_targets(self): """Test the alter_targets() method """ n = SCons.Node.Node() t, m = n.alter_targets() assert t == [], t assert m == None, m def test_current(self): """Test the default current() method """ node = SCons.Node.Node() assert node.current() is None def test_env_set(self): """Test setting a Node's Environment """ node = SCons.Node.Node() e = Environment() node.env_set(e) assert node.env == e def test_get_actions(self): """Test fetching a Node's action list """ node = SCons.Node.Node() node.builder_set(Builder()) a = node.builder.get_actions() assert isinstance(a[0], MyAction), a[0] def test_set_binfo(self): """Test setting a Node's build information """ node = SCons.Node.Node() node.set_binfo('www', ['w1'], ['w2'], 'w act', 'w actsig') assert node.bsig == 'www', node.bsig assert node.bkids == ['w1'], node.bkdids assert node.bkidsigs == ['w2'], node.bkidsigs assert node.bact == 'w act', node.bkdid assert node.bactsig == 'w actsig', node.bkidsig def test_get_binfo(self): """Test fetching a Node's build information """ node = SCons.Node.Node() node.set_binfo('yyy', ['y1'], ['y2'], 'y act', 'y actsig') bsig, bkids, bkidsigs, bact, bactsig = node.get_binfo() assert bsig == 'yyy', bsig assert bkids == ['y1'], bkdids assert bkidsigs == ['y2'], bkidsigs assert bact == 'y act', bkdid assert bactsig == 'y actsig', bkidsig def test_get_bsig(self): """Test fetching a Node's signature """ node = SCons.Node.Node() node.set_binfo('xxx', ['x1'], ['x2'], 'x act', 'x actsig') assert node.get_bsig() == 'xxx' def test_set_csig(self): """Test setting a Node's signature """ node = SCons.Node.Node() node.set_csig('yyy') assert node.csig == 'yyy' def test_get_csig(self): """Test fetching a Node's signature """ node = SCons.Node.Node() node.set_csig('zzz') assert node.get_csig() == 'zzz' def test_store_binfo(self): """Test calling the method to store build information """ node = SCons.Node.Node() node.store_binfo() def test_store_csig(self): """Test calling the method to store a content signature """ node = SCons.Node.Node() node.store_csig() def test_get_timestamp(self): """Test calling the method to fetch a Node's timestamp """ node = SCons.Node.Node() assert node.get_timestamp() == 0 def test_store_timestamp(self): """Test calling the method to store a timestamp """ node = SCons.Node.Node() node.store_timestamp() def test_set_always_build(self): """Test setting a Node's always_build value """ node = SCons.Node.Node() node.set_always_build() assert node.always_build node.set_always_build(3) assert node.always_build == 3 def test_set_precious(self): """Test setting a Node's precious value """ node = SCons.Node.Node() node.set_precious() assert node.precious node.set_precious(7) assert node.precious == 7 def test_exists(self): """Test evaluating whether a Node exists. """ node = SCons.Node.Node() e = node.exists() assert e == 1, e def test_exists(self): """Test evaluating whether a Node exists locally or in a repository. """ node = SCons.Node.Node() e = node.rexists() assert e == 1, e class MyNode(SCons.Node.Node): def exists(self): return 'xyz' node = MyNode() e = node.rexists() assert e == 'xyz', e def test_prepare(self): """Test preparing a node to be built """ node = SCons.Node.Node() n1 = SCons.Node.Node() n1.builder_set(Builder()) node.implicit = [] node.implicit_dict = {} node._add_child(node.implicit, node.implicit_dict, [n1]) node.prepare() # should not throw an exception n2 = SCons.Node.Node() n2.linked = 1 node.implicit = [] node.implicit_dict = {} node._add_child(node.implicit, node.implicit_dict, [n2]) node.prepare() # should not throw an exception n3 = SCons.Node.Node() node.implicit = [] node.implicit_dict = {} node._add_child(node.implicit, node.implicit_dict, [n3]) node.prepare() # should not throw an exception class MyNode(SCons.Node.Node): def rexists(self): return None n4 = MyNode() node.implicit = [] node.implicit_dict = {} node._add_child(node.implicit, node.implicit_dict, [n4]) exc_caught = 0 try: node.prepare() except SCons.Errors.StopError: exc_caught = 1 assert exc_caught, "did not catch expected StopError" def test_add_dependency(self): """Test adding dependencies to a Node's list. """ node = SCons.Node.Node() assert node.depends == [] zero = SCons.Node.Node() one = SCons.Node.Node() two = SCons.Node.Node() three = SCons.Node.Node() four = SCons.Node.Node() five = SCons.Node.Node() six = SCons.Node.Node() node.add_dependency(zero) assert node.depends == [zero] node.add_dependency([one]) assert node.depends == [zero, one] node.add_dependency([two, three]) assert node.depends == [zero, one, two, three] node.add_dependency([three, four, one]) assert node.depends == [zero, one, two, three, four] assert zero.get_parents() == [node] assert one.get_parents() == [node] assert two.get_parents() == [node] assert three.get_parents() == [node] assert four.get_parents() == [node] try: node.add_depends([[five, six]]) except: pass else: raise "did not catch expected exception" assert node.depends == [zero, one, two, three, four] assert five.get_parents() == [] assert six.get_parents() == [] def test_add_source(self): """Test adding sources to a Node's list. """ node = SCons.Node.Node() assert node.sources == [] zero = SCons.Node.Node() one = SCons.Node.Node() two = SCons.Node.Node() three = SCons.Node.Node() four = SCons.Node.Node() five = SCons.Node.Node() six = SCons.Node.Node() node.add_source(zero) assert node.sources == [zero] node.add_source([one]) assert node.sources == [zero, one] node.add_source([two, three]) assert node.sources == [zero, one, two, three] node.add_source([three, four, one]) assert node.sources == [zero, one, two, three, four] assert zero.get_parents() == [node] assert one.get_parents() == [node] assert two.get_parents() == [node] assert three.get_parents() == [node] assert four.get_parents() == [node] try: node.add_source([[five, six]]) except: pass else: raise "did not catch expected exception" assert node.sources == [zero, one, two, three, four] assert five.get_parents() == [] assert six.get_parents() == [] def test_add_ignore(self): """Test adding files whose dependencies should be ignored. """ node = SCons.Node.Node() assert node.ignore == [] zero = SCons.Node.Node() one = SCons.Node.Node() two = SCons.Node.Node() three = SCons.Node.Node() four = SCons.Node.Node() five = SCons.Node.Node() six = SCons.Node.Node() node.add_ignore(zero) assert node.ignore == [zero] node.add_ignore([one]) assert node.ignore == [zero, one] node.add_ignore([two, three]) assert node.ignore == [zero, one, two, three] node.add_ignore([three, four, one]) assert node.ignore == [zero, one, two, three, four] assert zero.get_parents() == [node] assert one.get_parents() == [node] assert two.get_parents() == [node] assert three.get_parents() == [node] assert four.get_parents() == [node] try: node.add_ignore([[five, six]]) except: pass else: raise "did not catch expected exception" assert node.ignore == [zero, one, two, three, four] assert five.get_parents() == [] assert six.get_parents() == [] def test_get_found_includes(self): """Test the default get_found_includes() method """ node = SCons.Node.Node() target = SCons.Node.Node() e = Environment() deps = node.get_found_includes(e, None, target) assert deps == [], deps def test_get_implicit_deps(self): """Test get_implicit_deps() """ node = MyNode("nnn") target = MyNode("ttt") env = Environment() # No scanner at all returns [] deps = node.get_implicit_deps(env, None, target) assert deps == [], deps s = Scanner() d = MyNode("ddd") node.found_includes = [d] # Simple return of the found includes deps = node.get_implicit_deps(env, s, target) assert deps == [d], deps # No "recursive" attribute on scanner doesn't recurse e = MyNode("eee") d.found_includes = [e] deps = node.get_implicit_deps(env, s, target) assert deps == [d], map(str, deps) # Explicit "recursive" attribute on scanner doesn't recurse s.recursive = None deps = node.get_implicit_deps(env, s, target) assert deps == [d], map(str, deps) # Explicit "recursive" attribute on scanner which does recurse s.recursive = 1 deps = node.get_implicit_deps(env, s, target) assert deps == [d, e], map(str, deps) # Recursive scanning eliminates duplicates f = MyNode("fff") d.found_includes = [e, f] e.found_includes = [f] deps = node.get_implicit_deps(env, s, target) assert deps == [d, e, f], map(str, deps) def test_scan(self): """Test Scanner functionality """ node = MyNode("nnn") node.builder = Builder() node.env_set(Environment()) s = Scanner() d = MyNode("ddd") node.found_includes = [d] assert node.target_scanner == None, node.target_scanner node.target_scanner = s assert node.implicit is None node.scan() assert s.called assert node.implicit == [d], node.implicit # Check that scanning a node with some stored implicit # dependencies resets internal attributes appropriately # if the stored dependencies need recalculation. class StoredNode(MyNode): def get_stored_implicit(self): return ['implicit1', 'implicit2'] class NotCurrent: def current(self, node, sig): return None def bsig(self, node): return 0 import SCons.Sig save_default_calc = SCons.Sig.default_calc save_implicit_cache = SCons.Node.implicit_cache save_implicit_deps_changed = SCons.Node.implicit_deps_changed save_implicit_deps_unchanged = SCons.Node.implicit_deps_unchanged SCons.Sig.default_calc = NotCurrent() SCons.Node.implicit_cache = 1 SCons.Node.implicit_deps_changed = None SCons.Node.implicit_deps_unchanged = None try: sn = StoredNode("eee") sn._children = ['fake'] sn.target_scanner = s sn.scan() assert sn.implicit == [], sn.implicit assert not hasattr(sn, '_children'), "unexpected _children attribute" finally: SCons.Sig.default_calc = save_default_calc SCons.Node.implicit_cache = save_implicit_cache SCons.Node.implicit_deps_changed = save_implicit_deps_changed SCons.Node.implicit_deps_unchanged = save_implicit_deps_unchanged def test_scanner_key(self): """Test that a scanner_key() method exists""" assert SCons.Node.Node().scanner_key() == None def test_children(self): """Test fetching the non-ignored "children" of a Node. """ node = SCons.Node.Node() n1 = SCons.Node.Node() n2 = SCons.Node.Node() n3 = SCons.Node.Node() n4 = SCons.Node.Node() n5 = SCons.Node.Node() n6 = SCons.Node.Node() n7 = SCons.Node.Node() n8 = SCons.Node.Node() n9 = SCons.Node.Node() n10 = SCons.Node.Node() n11 = SCons.Node.Node() n12 = SCons.Node.Node() node.add_source([n1, n2, n3]) node.add_dependency([n4, n5, n6]) node.implicit = [] node.implicit_dict = {} node._add_child(node.implicit, node.implicit_dict, [n7, n8, n9]) node._add_child(node.implicit, node.implicit_dict, [n10, n11, n12]) node.add_ignore([n2, n5, n8, n11]) kids = node.children() for kid in [n1, n3, n4, n6, n7, n9, n10, n12]: assert kid in kids, kid for kid in [n2, n5, n8, n11]: assert not kid in kids, kid def test_all_children(self): """Test fetching all the "children" of a Node. """ node = SCons.Node.Node() n1 = SCons.Node.Node() n2 = SCons.Node.Node() n3 = SCons.Node.Node() n4 = SCons.Node.Node() n5 = SCons.Node.Node() n6 = SCons.Node.Node() n7 = SCons.Node.Node() n8 = SCons.Node.Node() n9 = SCons.Node.Node() n10 = SCons.Node.Node() n11 = SCons.Node.Node() n12 = SCons.Node.Node() node.add_source([n1, n2, n3]) node.add_dependency([n4, n5, n6]) node.implicit = [] node.implicit_dict = {} node._add_child(node.implicit, node.implicit_dict, [n7, n8, n9]) node._add_child(node.implicit, node.implicit_dict, [n10, n11, n12]) node.add_ignore([n2, n5, n8, n11]) kids = node.all_children() for kid in [n1, n2, n3, n4, n5, n6, n7, n8, n9, n10, n11, n12]: assert kid in kids, kid def test_state(self): """Test setting and getting the state of a node """ node = SCons.Node.Node() assert node.get_state() == None node.set_state(SCons.Node.executing) assert node.get_state() == SCons.Node.executing assert SCons.Node.pending < SCons.Node.executing assert SCons.Node.executing < SCons.Node.up_to_date assert SCons.Node.up_to_date < SCons.Node.executed assert SCons.Node.executed < SCons.Node.failed def test_walker(self): """Test walking a Node tree. """ n1 = MyNode("n1") nw = SCons.Node.Walker(n1) assert not nw.is_done() assert nw.next().name == "n1" assert nw.is_done() assert nw.next() == None n2 = MyNode("n2") n3 = MyNode("n3") n1.add_source([n2, n3]) nw = SCons.Node.Walker(n1) n = nw.next() assert n.name == "n2", n.name n = nw.next() assert n.name == "n3", n.name n = nw.next() assert n.name == "n1", n.name n = nw.next() assert n == None, n n4 = MyNode("n4") n5 = MyNode("n5") n6 = MyNode("n6") n7 = MyNode("n7") n2.add_source([n4, n5]) n3.add_dependency([n6, n7]) nw = SCons.Node.Walker(n1) assert nw.next().name == "n4" assert nw.next().name == "n5" assert nw.history.has_key(n2) assert nw.next().name == "n2" assert nw.next().name == "n6" assert nw.next().name == "n7" assert nw.history.has_key(n3) assert nw.next().name == "n3" assert nw.history.has_key(n1) assert nw.next().name == "n1" assert nw.next() == None n8 = MyNode("n8") n8.add_dependency([n3]) n7.add_dependency([n8]) def cycle(node, stack): global cycle_detected cycle_detected = 1 global cycle_detected nw = SCons.Node.Walker(n3, cycle_func = cycle) n = nw.next() assert n.name == "n6", n.name n = nw.next() assert n.name == "n8", n.name assert cycle_detected cycle_detected = None n = nw.next() assert n.name == "n7", n.name n = nw.next() assert nw.next() == None def test_rstr(self): """Test the rstr() method.""" n1 = MyNode("n1") assert n1.rstr() == 'n1', n1.rstr() def test_abspath(self): """Test the get_abspath() method.""" n = MyNode("foo") assert n.get_abspath() == str(n), n.get_abspath() def test_for_signature(self): """Test the for_signature() method.""" n = MyNode("foo") assert n.for_signature() == str(n), n.get_abspath() def test_get_string(self): """Test the get_string() method.""" class TestNode(MyNode): def __init__(self, name, sig): MyNode.__init__(self, name) self.sig = sig def for_signature(self): return self.sig n = TestNode("foo", "bar") assert n.get_string(0) == "foo", n.get_string(0) assert n.get_string(1) == "bar", n.get_string(1) def test_literal(self): """Test the is_literal() function.""" n=SCons.Node.Node() assert n.is_literal() def test_Annotate(self): """Test using an interface-specific Annotate function.""" def my_annotate(node, self=self): node.annotation = self.node_string save_Annotate = SCons.Node.Annotate SCons.Node.Annotate = my_annotate try: self.node_string = '#1' n = SCons.Node.Node() assert n.annotation == '#1', n.annotation self.node_string = '#2' n = SCons.Node.Node() assert n.annotation == '#2', n.annotation finally: SCons.Node.Annotate = save_Annotate def test_clear(self): """Test clearing all cached state information.""" n = SCons.Node.Node() n.set_state(3) n.set_binfo('bbb', ['b1'], ['b2'], 'b act', 'b actsig') n.set_csig('csig') n.includes = 'testincludes' n.found_include = {'testkey':'testvalue'} n.implicit = 'testimplicit' n.clear() assert n.get_state() is None, n.get_state() assert not hasattr(n, 'bsig'), n.bsig assert not hasattr(n, 'bkids'), n.bkids assert not hasattr(n, 'bkidsigs'), n.bkidsigs assert not hasattr(n, 'bact'), n.bact assert not hasattr(n, 'bactsig'), n.bactsig assert not hasattr(n, 'csig'), n.csig assert n.includes is None, n.includes assert n.found_includes == {}, n.found_includes assert n.implicit is None, n.implicit def test_get_subst_proxy(self): """Test the get_subst_proxy method.""" n = MyNode("test") assert n.get_subst_proxy() == n, n.get_subst_proxy() def test_get_prevsiginfo(self): """Test the base Node get_prevsiginfo() method""" n = SCons.Node.Node() siginfo = n.get_prevsiginfo() assert siginfo == (None, None, None), siginfo def test_get_suffix(self): """Test the base Node get_suffix() method""" n = SCons.Node.Node() s = n.get_suffix() assert s == '', s def test_generate_build_dict(self): """Test the base Node generate_build_dict() method""" n = SCons.Node.Node() dict = n.generate_build_dict() assert dict == {}, dict def test_postprocess(self): """Test calling the base Node postprocess() method""" n = SCons.Node.Node() n.postprocess() if __name__ == "__main__": suite = unittest.makeSuite(NodeTestCase, 'test_') if not unittest.TextTestRunner().run(suite).wasSuccessful(): sys.exit(1)