http://scons.tigris.org/issues/show_bug.cgi?id=2345
[scons.git] / src / engine / SCons / ExecutorTests.py
index d52853c903e96fcf01002a16488ab9fb1cd2b167..8e067426fbe7d6c5000f577d4af3f338cf4daaad 100644 (file)
@@ -23,7 +23,6 @@
 
 __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
 
-import string
 import sys
 import unittest
 
@@ -39,24 +38,22 @@ class MyEnvironment:
     def Override(self, overrides):
         d = self._dict.copy()
         d.update(overrides)
-        return apply(MyEnvironment, (), d)
+        return MyEnvironment(**d)
     def _update(self, dict):
         self._dict.update(dict)
 
 class MyAction:
     def __init__(self, actions=['action1', 'action2']):
         self.actions = actions
-    def __call__(self, target, source, env, errfunc, **kw):
+    def __call__(self, target, source, env, **kw):
         for action in self.actions:
-            action(target, source, env, errfunc)
-    def strfunction(self, target, source, env):
-        return string.join(['STRFUNCTION'] + map(str, self.actions) + target + source)
+            action(target, source, env, **kw)
     def genstring(self, target, source, env):
-        return string.join(['GENSTRING'] + map(str, self.actions) + target + source)
-    def get_raw_contents(self, target, source, env):
-        return string.join(['RAW'] + self.actions + target + source)
+        return ' '.join(['GENSTRING'] + list(map(str, self.actions)) + target + source)
     def get_contents(self, target, source, env):
-        return string.join(self.actions + target + source)
+        return ' '.join(self.actions + target + source)
+    def get_implicit_deps(self, target, source, env):
+        return []
 
 class MyBuilder:
     def __init__(self, env, overrides):
@@ -65,10 +62,43 @@ class MyBuilder:
         self.action = MyAction()
 
 class MyNode:
-    def __init__(self, pre, post):
+    def __init__(self, name=None, pre=[], post=[]):
+        self.name = name
+        self.implicit = []
         self.pre_actions = pre
         self.post_actions = post
-        
+        self.missing_val = None
+    def __str__(self):
+        return self.name
+    def build(self):
+        executor = SCons.Executor.Executor(MyAction(self.pre_actions +
+                                                    [self.builder.action] +
+                                                    self.post_actions),
+                                           self.builder.env,
+                                           [],
+                                           [self],
+                                           ['s1', 's2'])
+        executor(self)
+    def get_env_scanner(self, env, kw):
+        return MyScanner('dep-')
+    def get_implicit_deps(self, env, scanner, path):
+        return [scanner.prefix + str(self)]
+    def add_to_implicit(self, deps):
+        self.implicit.extend(deps)
+    def missing(self):
+        return self.missing_val
+    def calc_signature(self, calc):
+        return 'cs-'+calc+'-'+self.name
+    def disambiguate(self):
+        return self
+
+class MyScanner:
+    def __init__(self, prefix):
+        self.prefix = prefix
+    def path(self, env, cwd, target, source):
+        return ()
+    def select(self, node):
+        return self
 
 class ExecutorTestCase(unittest.TestCase):
 
@@ -76,25 +106,48 @@ class ExecutorTestCase(unittest.TestCase):
         """Test creating an Executor"""
         source_list = ['s1', 's2']
         x = SCons.Executor.Executor('a', 'e', ['o'], 't', source_list)
-        assert x.action == 'a', x.builder
+        assert x.action_list == ['a'], x.action_list
         assert x.env == 'e', x.env
         assert x.overridelist == ['o'], x.overridelist
-        assert x.targets == 't', x.targets
+        targets = x.get_all_targets()
+        assert targets == ['t'], targets
         source_list.append('s3')
-        assert x.sources == ['s1', 's2'], x.sources
+        sources = x.get_all_sources()
+        assert sources == ['s1', 's2'], sources
         try:
             x = SCons.Executor.Executor(None, 'e', ['o'], 't', source_list)
         except SCons.Errors.UserError:
             pass
         else:
-            raise "Did not catch expected UserError"
+            raise Exception("Did not catch expected UserError")
+
+    def test__action_list(self):
+        """Test the {get,set}_action_list() methods"""
+        x = SCons.Executor.Executor('a', 'e', 'o', 't', ['s1', 's2'])
+
+        l = x.get_action_list()
+        assert l == ['a'], l
+
+        x.add_pre_action('pre')
+        x.add_post_action('post')
+        l = x.get_action_list()
+        assert l == ['pre', 'a', 'post'], l
+
+        x.set_action_list('b')
+        l = x.get_action_list()
+        assert l == ['pre', 'b', 'post'], l
+
+        x.set_action_list(['c'])
+        l = x.get_action_list()
+        assert l == ['pre', 'c', 'post'], l
 
     def test_get_build_env(self):
         """Test fetching and generating a build environment"""
-        x = SCons.Executor.Executor(MyAction(), 'e', [], 't', ['s1', 's2'])
-        x.build_env = 'eee'
+        x = SCons.Executor.Executor(MyAction(), MyEnvironment(e=1), [],
+                                    't', ['s1', 's2'])
+        x.env = MyEnvironment(eee=1)
         be = x.get_build_env()
-        assert be == 'eee', be
+        assert be['eee'] == 1, be
 
         env = MyEnvironment(X='xxx')
         x = SCons.Executor.Executor(MyAction(),
@@ -108,93 +161,172 @@ class ExecutorTestCase(unittest.TestCase):
 
         env = MyEnvironment(Y='yyy')
         overrides = [{'O':'ob3'}, {'O':'oo3'}]
-        x = SCons.Executor.Executor(MyAction(), env, overrides, 't', 's')
+        x = SCons.Executor.Executor(MyAction(), env, overrides, ['t'], ['s'])
         be = x.get_build_env()
         assert be['O'] == 'oo3', be['O']
         assert be['Y'] == 'yyy', be['Y']
         overrides = [{'O':'ob3'}]
-        x = SCons.Executor.Executor(MyAction(), env, overrides, 't', 's')
+        x = SCons.Executor.Executor(MyAction(), env, overrides, ['t'], ['s'])
         be = x.get_build_env()
         assert be['O'] == 'ob3', be['O']
         assert be['Y'] == 'yyy', be['Y']
 
-    def test_get_action_list(self):
-        """Test fetching and generating an action list"""
-        x = SCons.Executor.Executor('b', 'e', 'o', 't', 's')
-        al = x.get_action_list(MyNode([], []))
-        assert al == ['b'], al
-        al = x.get_action_list(MyNode(['PRE'], ['POST']))
-        assert al == ['PRE', 'b', 'POST'], al
+    def test_get_build_scanner_path(self):
+        """Test fetching the path for the specified scanner."""
+        t = MyNode('t')
+        t.cwd = 'here'
+        x = SCons.Executor.Executor(MyAction(),
+                                    MyEnvironment(SCANNERVAL='sss'),
+                                    [],
+                                    [t],
+                                    ['s1', 's2'])
+
+        class LocalScanner:
+            def path(self, env, dir, target, source):
+                target = list(map(str, target))
+                source = list(map(str, source))
+                return "scanner: %s, %s, %s, %s" % (env['SCANNERVAL'], dir, target, source)
+        s = LocalScanner()
 
-        a = MyAction()
-        x = SCons.Executor.Executor(a, None, {}, 't', 's')
-        al = x.get_action_list(MyNode(['pre'], ['post']))
-        assert al == ['pre', a, 'post'], al
+        p = x.get_build_scanner_path(s)
+        assert p == "scanner: sss, here, ['t'], ['s1', 's2']", p
+
+    def test_get_kw(self):
+        """Test the get_kw() method"""
+        t = MyNode('t')
+        x = SCons.Executor.Executor(MyAction(),
+                                    MyEnvironment(),
+                                    [],
+                                    [t],
+                                    ['s1', 's2'],
+                                    builder_kw={'X':1, 'Y':2})
+        kw = x.get_kw()
+        assert kw == {'X':1, 'Y':2, 'executor':x}, kw
+        kw = x.get_kw({'Z':3})
+        assert kw == {'X':1, 'Y':2, 'Z':3, 'executor':x}, kw
+        kw = x.get_kw({'X':4})
+        assert kw == {'X':4, 'Y':2, 'executor':x}, kw
 
     def test__call__(self):
         """Test calling an Executor"""
         result = []
-        def pre(target, source, env, errfunc, result=result, **kw):
+        def pre(target, source, env, result=result, **kw):
             result.append('pre')
-        def action1(target, source, env, errfunc, result=result, **kw):
+        def action1(target, source, env, result=result, **kw):
             result.append('action1')
-        def action2(target, source, env, errfunc, result=result, **kw):
+        def action2(target, source, env, result=result, **kw):
             result.append('action2')
-        def post(target, source, env, errfunc, result=result, **kw):
+        def post(target, source, env, result=result, **kw):
             result.append('post')
 
         env = MyEnvironment()
         a = MyAction([action1, action2])
-        x = SCons.Executor.Executor(a, env, [], ['t1', 't2'], ['s1', 's2'])
+        t = MyNode('t')
 
-        x(MyNode([pre], [post]), None)
+        x = SCons.Executor.Executor(a, env, [], [t], ['s1', 's2'])
+        x.add_pre_action(pre)
+        x.add_post_action(post)
+        x(t)
         assert result == ['pre', 'action1', 'action2', 'post'], result
         del result[:]
 
-        def pre_err(target, source, env, errfunc, result=result, **kw):
+        def pre_err(target, source, env, result=result, **kw):
             result.append('pre_err')
-            if errfunc:
-                errfunc(1)
             return 1
 
-        x(MyNode([pre_err], [post]), None)
-        assert result == ['pre_err', 'action1', 'action2', 'post'], result
-        del result[:]
-
-        def errfunc(stat):
-            raise "errfunc %s" % stat
-
+        x = SCons.Executor.Executor(a, env, [], [t], ['s1', 's2'])
+        x.add_pre_action(pre_err)
+        x.add_post_action(post)
         try:
-            x(MyNode([pre_err], [post]), errfunc)
-        except:
-            assert sys.exc_type == "errfunc 1", sys.exc_type
+            x(t)
+        except SCons.Errors.BuildError:
+            pass
         else:
-            assert 0, "did not catch expected exception"
+            raise Exception("Did not catch expected BuildError")
         assert result == ['pre_err'], result
         del result[:]
 
     def test_cleanup(self):
         """Test cleaning up an Executor"""
-        x = SCons.Executor.Executor('b', 'e', 'o', 't', ['s1', 's2'])
+        orig_env = MyEnvironment(e=1)
+        x = SCons.Executor.Executor('b', orig_env, [{'o':1}],
+                                    't', ['s1', 's2'])
 
+        be = x.get_build_env()
+        assert be['e'] == 1, be['e']
+        
         x.cleanup()
 
-        x.build_env = 'eee'
+        x.env = MyEnvironment(eee=1)
         be = x.get_build_env()
-        assert be == 'eee', be
+        assert be['eee'] == 1, be['eee']
 
         x.cleanup()
 
-        assert not hasattr(x, 'build_env')
+        be = x.get_build_env()
+        assert be['eee'] == 1, be['eee']
 
     def test_add_sources(self):
         """Test adding sources to an Executor"""
         x = SCons.Executor.Executor('b', 'e', 'o', 't', ['s1', 's2'])
-        assert x.sources == ['s1', 's2'], x.sources
+        sources = x.get_all_sources()
+        assert sources == ['s1', 's2'], sources
+
         x.add_sources(['s1', 's2'])
-        assert x.sources == ['s1', 's2'], x.sources
+        sources = x.get_all_sources()
+        assert sources == ['s1', 's2'], sources
+
         x.add_sources(['s3', 's1', 's4'])
-        assert x.sources == ['s1', 's2', 's3', 's4'], x.sources
+        sources = x.get_all_sources()
+        assert sources == ['s1', 's2', 's3', 's4'], sources
+
+    def test_get_sources(self):
+        """Test getting sources from an Executor"""
+        x = SCons.Executor.Executor('b', 'e', 'o', 't', ['s1', 's2'])
+        sources = x.get_sources()
+        assert sources == ['s1', 's2'], sources
+
+        x.add_sources(['s1', 's2'])
+        sources = x.get_sources()
+        assert sources == ['s1', 's2'], sources
+
+        x.add_sources(['s3', 's1', 's4'])
+        sources = x.get_sources()
+        assert sources == ['s1', 's2', 's3', 's4'], sources
+
+    def test_prepare(self):
+        """Test the Executor's prepare() method"""
+        env = MyEnvironment()
+        t1 = MyNode('t1')
+        s1 = MyNode('s1')
+        s2 = MyNode('s2')
+        s3 = MyNode('s3')
+        x = SCons.Executor.Executor('b', env, [{}], [t1], [s1, s2, s3])
+
+        s2.missing_val = True
+
+        try:
+            r = x.prepare()
+        except SCons.Errors.StopError, e:
+            assert str(e) == "Source `s2' not found, needed by target `t1'.", e
+        else:
+            raise AssertionError("did not catch expected StopError: %s" % r)
+
+    def test_add_pre_action(self):
+        """Test adding pre-actions to an Executor"""
+        x = SCons.Executor.Executor('b', 'e', 'o', 't', ['s1', 's2'])
+        x.add_pre_action('a1')
+        assert x.pre_actions == ['a1']
+        x.add_pre_action('a2')
+        assert x.pre_actions == ['a1', 'a2']
+
+    def test_add_post_action(self):
+        """Test adding post-actions to an Executor"""
+        x = SCons.Executor.Executor('b', 'e', 'o', 't', ['s1', 's2'])
+        x.add_post_action('a1')
+        assert x.post_actions == ['a1']
+        x.add_post_action('a2')
+        assert x.post_actions == ['a1', 'a2']
 
     def test___str__(self):
         """Test the __str__() method"""
@@ -204,81 +336,130 @@ class ExecutorTestCase(unittest.TestCase):
         c = str(x)
         assert c == 'GENSTRING action1 action2 t s', c
 
-    def test_strfunction(self):
-        """Test the strfunction() method"""
-        env = MyEnvironment(S='string')
-
         x = SCons.Executor.Executor(MyAction(), env, [], ['t'], ['s'])
-        s = x.strfunction()
-        assert s == 'STRFUNCTION action1 action2 t s', s
+        x.add_pre_action(MyAction(['pre']))
+        x.add_post_action(MyAction(['post']))
+        c = str(x)
+        expect = 'GENSTRING pre t s\n' + \
+                 'GENSTRING action1 action2 t s\n' + \
+                 'GENSTRING post t s'
+        assert c == expect, c
 
     def test_nullify(self):
         """Test the nullify() method"""
         env = MyEnvironment(S='string')
 
         result = []
-        def action1(target, source, env, errfunc, result=result, **kw):
+        def action1(target, source, env, result=result, **kw):
             result.append('action1')
 
         env = MyEnvironment()
         a = MyAction([action1])
         x = SCons.Executor.Executor(a, env, [], ['t1', 't2'], ['s1', 's2'])
 
-        x(MyNode([], []), None)
+        x(MyNode('', [], []))
         assert result == ['action1'], result
         s = str(x)
         assert s[:10] == 'GENSTRING ', s
-        s = x.strfunction()
-        assert s[:12] == 'STRFUNCTION ', s
 
         del result[:]
         x.nullify()
 
-        x(MyNode([], []), None)
+        assert result == [], result
+        x(MyNode('', [], []))
         assert result == [], result
         s = str(x)
-        assert s == None, s
-        s = x.strfunction()
-        assert s == None, s
-
-    def test_get_raw_contents(self):
-        """Test fetching the raw signatures contents"""
-        env = MyEnvironment(RC='raw contents')
-
-        x = SCons.Executor.Executor(MyAction(), env, [], ['t'], ['s'])
-        x.raw_contents = 'raw raw raw'
-        rc = x.get_raw_contents()
-        assert rc == 'raw raw raw', rc
-
-        x = SCons.Executor.Executor(MyAction(), env, [], ['t'], ['s'])
-        rc = x.get_raw_contents()
-        assert rc == 'RAW action1 action2 t s', rc
+        assert s == '', s
 
     def test_get_contents(self):
         """Test fetching the signatures contents"""
         env = MyEnvironment(C='contents')
 
         x = SCons.Executor.Executor(MyAction(), env, [], ['t'], ['s'])
-        x.contents = 'contents'
         c = x.get_contents()
-        assert c == 'contents', c
+        assert c == 'action1 action2 t s', c
 
-        x = SCons.Executor.Executor(MyAction(), env, [], ['t'], ['s'])
+        x = SCons.Executor.Executor(MyAction(actions=['grow']), env, [],
+                                    ['t'], ['s'])
+        x.add_pre_action(MyAction(['pre']))
+        x.add_post_action(MyAction(['post']))
         c = x.get_contents()
-        assert c == 'action1 action2 t s', c
+        assert c == 'pre t sgrow t spost t s', c
 
-    def test_get_timetstamp(self):
+    def test_get_timestamp(self):
         """Test fetching the "timestamp" """
         x = SCons.Executor.Executor('b', 'e', 'o', 't', ['s1', 's2'])
         ts = x.get_timestamp()
         assert ts == 0, ts
 
+    def test_scan_targets(self):
+        """Test scanning the targets for implicit dependencies"""
+        env = MyEnvironment(S='string')
+        t1 = MyNode('t1')
+        t2 = MyNode('t2')
+        sources = [MyNode('s1'), MyNode('s2')]
+        x = SCons.Executor.Executor(MyAction(), env, [{}], [t1, t2], sources)
+
+        deps = x.scan_targets(None)
+        assert t1.implicit == ['dep-t1', 'dep-t2'], t1.implicit
+        assert t2.implicit == ['dep-t1', 'dep-t2'], t2.implicit
+
+        t1.implicit = []
+        t2.implicit = []
+
+        deps = x.scan_targets(MyScanner('scanner-'))
+        assert t1.implicit == ['scanner-t1', 'scanner-t2'], t1.implicit
+        assert t2.implicit == ['scanner-t1', 'scanner-t2'], t2.implicit
+
+    def test_scan_sources(self):
+        """Test scanning the sources for implicit dependencies"""
+        env = MyEnvironment(S='string')
+        t1 = MyNode('t1')
+        t2 = MyNode('t2')
+        sources = [MyNode('s1'), MyNode('s2')]
+        x = SCons.Executor.Executor(MyAction(), env, [{}], [t1, t2], sources)
+
+        deps = x.scan_sources(None)
+        assert t1.implicit == ['dep-s1', 'dep-s2'], t1.implicit
+        assert t2.implicit == ['dep-s1', 'dep-s2'], t2.implicit
+
+        t1.implicit = []
+        t2.implicit = []
+
+        deps = x.scan_sources(MyScanner('scanner-'))
+        assert t1.implicit == ['scanner-s1', 'scanner-s2'], t1.implicit
+        assert t2.implicit == ['scanner-s1', 'scanner-s2'], t2.implicit
+
+    def test_get_unignored_sources(self):
+        """Test fetching the unignored source list"""
+        env = MyEnvironment()
+        s1 = MyNode('s1')
+        s2 = MyNode('s2')
+        s3 = MyNode('s3')
+        x = SCons.Executor.Executor('b', env, [{}], [], [s1, s2, s3])
+
+        r = x.get_unignored_sources(None, [])
+        assert r == [s1, s2, s3], list(map(str, r))
+
+        r = x.get_unignored_sources(None, [s2])
+        assert r == [s1, s3], list(map(str, r))
+
+        r = x.get_unignored_sources(None, [s1, s3])
+        assert r == [s2], list(map(str, r))
+
+
 
 if __name__ == "__main__":
     suite = unittest.TestSuite()
     tclasses = [ ExecutorTestCase ]
     for tclass in tclasses:
         names = unittest.getTestCaseNames(tclass, 'test_')
-        suite.addTests(map(tclass, names))
+        suite.addTests(list(map(tclass, names)))
     if not unittest.TextTestRunner().run(suite).wasSuccessful():
         sys.exit(1)
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4: