# MIT License # # Copyright The SCons Foundation # # 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. import unittest import SCons.Executor class MyEnvironment: def __init__(self, **kw): self._dict = {} self._dict.update(kw) def __getitem__(self, key): return self._dict[key] def Override(self, overrides): d = self._dict.copy() d.update(overrides) 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, **kw): for action in self.actions: action(target, source, env, **kw) def genstring(self, target, source, env): return ' '.join(['GENSTRING'] + list(map(str, self.actions)) + target + source) def get_contents(self, target, source, env): return b' '.join( [SCons.Util.to_bytes(aa) for aa in self.actions] + [SCons.Util.to_bytes(tt) for tt in target] + [SCons.Util.to_bytes(ss) for ss in source] ) def get_implicit_deps(self, target, source, env): return [] class MyBuilder: def __init__(self, env, overrides): self.env = env self.overrides = overrides self.action = MyAction() class MyNode: def __init__(self, name=None, pre=[], post=[]): self.name = name self.implicit = [] self.pre_actions = pre self.post_actions = post self.missing_val = None self.always_build = False self.up_to_date = False 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, kw={}): if not scanner: scanner = self.get_env_scanner(env, kw) 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 def is_up_to_date(self): return self.up_to_date 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): def test__init__(self): """Test creating an Executor""" source_list = ['s1', 's2'] x = SCons.Executor.Executor('a', 'e', ['o'], 't', source_list) assert x.action_list == ['a'], x.action_list assert x.env == 'e', x.env assert x.overridelist == ['o'], x.overridelist targets = x.get_all_targets() assert targets == ['t'], targets source_list.append('s3') 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 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(), MyEnvironment(e=1), [], 't', ['s1', 's2']) x.env = MyEnvironment(eee=1) be = x.get_build_env() assert be['eee'] == 1, be env = MyEnvironment(X='xxx') x = SCons.Executor.Executor(MyAction(), env, [{'O':'o2'}], 't', ['s1', 's2']) be = x.get_build_env() assert be['O'] == 'o2', be['O'] assert be['X'] == 'xxx', be['X'] env = MyEnvironment(Y='yyy') overrides = [{'O':'ob3'}, {'O':'oo3'}] 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']) be = x.get_build_env() assert be['O'] == 'ob3', be['O'] assert be['Y'] == 'yyy', be['Y'] 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() 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, result=result, **kw): result.append('pre') def action1(target, source, env, result=result, **kw): result.append('action1') def action2(target, source, env, result=result, **kw): result.append('action2') def post(target, source, env, result=result, **kw): result.append('post') env = MyEnvironment() a = MyAction([action1, action2]) t = MyNode('t') 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, result=result, **kw): result.append('pre_err') return 1 x = SCons.Executor.Executor(a, env, [], [t], ['s1', 's2']) x.add_pre_action(pre_err) x.add_post_action(post) try: x(t) except SCons.Errors.BuildError: pass else: raise Exception("Did not catch expected BuildError") assert result == ['pre_err'], result del result[:] def test_cleanup(self): """Test cleaning up an Executor""" 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.env = MyEnvironment(eee=1) be = x.get_build_env() assert be['eee'] == 1, be['eee'] x.cleanup() 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']) sources = x.get_all_sources() assert sources == ['s1', 's2'], sources x.add_sources(['s1', 's2']) sources = x.get_all_sources() assert sources == ['s1', 's2'], sources x.add_sources(['s3', 's1', 's4']) 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 as 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""" env = MyEnvironment(S='string') x = SCons.Executor.Executor(MyAction(), env, [], ['t'], ['s']) c = str(x) assert c == 'GENSTRING action1 action2 t s', c x = SCons.Executor.Executor(MyAction(), env, [], ['t'], ['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, result=result, **kw): result.append('action1') env = MyEnvironment() a = MyAction([action1]) x = SCons.Executor.Executor(a, env, [], ['t1', 't2'], ['s1', 's2']) x(MyNode('', [], [])) assert result == ['action1'], result s = str(x) assert s[:10] == 'GENSTRING ', s del result[:] x.nullify() assert result == [], result x(MyNode('', [], [])) assert result == [], result s = str(x) 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']) c = x.get_contents() assert c == b'action1 action2 t s', c 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 == b'pre t sgrow t spost t s', c 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)) def test_changed_sources_for_alwaysBuild(self): """ Ensure if a target is marked always build that the sources are always marked changed sources :return: """ env = MyEnvironment() s1 = MyNode('s1') s2 = MyNode('s2') t1 = MyNode('t1') t1.up_to_date = True t1.always_build = True x = SCons.Executor.Executor('b', env, [{}], [t1], [s1, s2]) changed_sources = x._get_changed_sources() assert changed_sources == [s1, s2], "If target marked AlwaysBuild sources should always be marked changed" if __name__ == "__main__": unittest.main() # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: