3 # Copyright The SCons Foundation
5 # Permission is hereby granted, free of charge, to any person obtaining
6 # a copy of this software and associated documentation files (the
7 # "Software"), to deal in the Software without restriction, including
8 # without limitation the rights to use, copy, modify, merge, publish,
9 # distribute, sublicense, and/or sell copies of the Software, and to
10 # permit persons to whom the Software is furnished to do so, subject to
11 # the following conditions:
13 # The above copyright notice and this permission notice shall be included
14 # in all copies or substantial portions of the Software.
16 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
17 # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
18 # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20 # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21 # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22 # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 def __init__(self
, **kw
) -> None:
33 def __getitem__(self
, key
):
34 return self
._dict
[key
]
35 def Override(self
, overrides
):
38 return MyEnvironment(**d
)
39 def _update(self
, dict) -> None:
40 self
._dict
.update(dict)
43 def __init__(self
, actions
=['action1', 'action2']) -> None:
44 self
.actions
= actions
45 def __call__(self
, target
, source
, env
, **kw
) -> None:
46 for action
in self
.actions
:
47 action(target
, source
, env
, **kw
)
48 def genstring(self
, target
, source
, env
):
49 return ' '.join(['GENSTRING'] + list(map(str, self
.actions
)) + target
+ source
)
50 def get_contents(self
, target
, source
, env
):
52 [SCons
.Util
.to_bytes(aa
) for aa
in self
.actions
] +
53 [SCons
.Util
.to_bytes(tt
) for tt
in target
] +
54 [SCons
.Util
.to_bytes(ss
) for ss
in source
]
56 def get_implicit_deps(self
, target
, source
, env
):
60 def __init__(self
, env
, overrides
) -> None:
62 self
.overrides
= overrides
63 self
.action
= MyAction()
66 def __init__(self
, name
=None, pre
=[], post
=[]) -> None:
69 self
.pre_actions
= pre
70 self
.post_actions
= post
71 self
.missing_val
= None
72 self
.always_build
= False
73 self
.up_to_date
= False
75 def __str__(self
) -> str:
78 def build(self
) -> None:
79 executor
= SCons
.Executor
.Executor(MyAction(self
.pre_actions
+
80 [self
.builder
.action
] +
87 def get_env_scanner(self
, env
, kw
):
88 return MyScanner('dep-')
89 def get_implicit_deps(self
, env
, scanner
, path
, kw
={}):
91 scanner
= self
.get_env_scanner(env
, kw
)
92 return [scanner
.prefix
+ str(self
)]
93 def add_to_implicit(self
, deps
) -> None:
94 self
.implicit
.extend(deps
)
96 return self
.missing_val
97 def calc_signature(self
, calc
):
98 return 'cs-'+calc
+'-'+self
.name
99 def disambiguate(self
):
102 def is_up_to_date(self
) -> bool:
103 return self
.up_to_date
106 def __init__(self
, prefix
) -> None:
108 def path(self
, env
, cwd
, target
, source
):
110 def select(self
, node
):
113 class ExecutorTestCase(unittest
.TestCase
):
115 def test__init__(self
):
116 """Test creating an Executor"""
117 source_list
= ['s1', 's2']
118 x
= SCons
.Executor
.Executor('a', 'e', ['o'], 't', source_list
)
119 assert x
.action_list
== ['a'], x
.action_list
120 assert x
.env
== 'e', x
.env
121 assert x
.overridelist
== ['o'], x
.overridelist
122 targets
= x
.get_all_targets()
123 assert targets
== ['t'], targets
124 source_list
.append('s3')
125 sources
= x
.get_all_sources()
126 assert sources
== ['s1', 's2'], sources
128 x
= SCons
.Executor
.Executor(None, 'e', ['o'], 't', source_list
)
129 except SCons
.Errors
.UserError
:
132 raise Exception("Did not catch expected UserError")
134 def test__action_list(self
) -> None:
135 """Test the {get,set}_action_list() methods"""
136 x
= SCons
.Executor
.Executor('a', 'e', 'o', 't', ['s1', 's2'])
138 l
= x
.get_action_list()
141 x
.add_pre_action('pre')
142 x
.add_post_action('post')
143 l
= x
.get_action_list()
144 assert l
== ['pre', 'a', 'post'], l
146 x
.set_action_list('b')
147 l
= x
.get_action_list()
148 assert l
== ['pre', 'b', 'post'], l
150 x
.set_action_list(['c'])
151 l
= x
.get_action_list()
152 assert l
== ['pre', 'c', 'post'], l
154 def test_get_build_env(self
) -> None:
155 """Test fetching and generating a build environment"""
156 x
= SCons
.Executor
.Executor(MyAction(), MyEnvironment(e
=1), [],
158 x
.env
= MyEnvironment(eee
=1)
159 be
= x
.get_build_env()
160 assert be
['eee'] == 1, be
162 env
= MyEnvironment(X
='xxx')
163 x
= SCons
.Executor
.Executor(MyAction(),
168 be
= x
.get_build_env()
169 assert be
['O'] == 'o2', be
['O']
170 assert be
['X'] == 'xxx', be
['X']
172 env
= MyEnvironment(Y
='yyy')
173 overrides
= [{'O':'ob3'}, {'O':'oo3'}]
174 x
= SCons
.Executor
.Executor(MyAction(), env
, overrides
, ['t'], ['s'])
175 be
= x
.get_build_env()
176 assert be
['O'] == 'oo3', be
['O']
177 assert be
['Y'] == 'yyy', be
['Y']
178 overrides
= [{'O':'ob3'}]
179 x
= SCons
.Executor
.Executor(MyAction(), env
, overrides
, ['t'], ['s'])
180 be
= x
.get_build_env()
181 assert be
['O'] == 'ob3', be
['O']
182 assert be
['Y'] == 'yyy', be
['Y']
184 def test_get_build_scanner_path(self
) -> None:
185 """Test fetching the path for the specified scanner."""
188 x
= SCons
.Executor
.Executor(MyAction(),
189 MyEnvironment(SCANNERVAL
='sss'),
195 def path(self
, env
, dir, target
, source
) -> str:
196 target
= list(map(str, target
))
197 source
= list(map(str, source
))
198 return "scanner: %s, %s, %s, %s" % (env
['SCANNERVAL'], dir, target
, source
)
201 p
= x
.get_build_scanner_path(s
)
202 assert p
== "scanner: sss, here, ['t'], ['s1', 's2']", p
204 def test_get_kw(self
) -> None:
205 """Test the get_kw() method"""
207 x
= SCons
.Executor
.Executor(MyAction(),
212 builder_kw
={'X':1, 'Y':2})
214 assert kw
== {'X':1, 'Y':2, 'executor':x
}, kw
215 kw
= x
.get_kw({'Z':3})
216 assert kw
== {'X':1, 'Y':2, 'Z':3, 'executor':x
}, kw
217 kw
= x
.get_kw({'X':4})
218 assert kw
== {'X':4, 'Y':2, 'executor':x
}, kw
220 def test__call__(self
):
221 """Test calling an Executor"""
223 def pre(target
, source
, env
, result
=result
, **kw
) -> None:
225 def action1(target
, source
, env
, result
=result
, **kw
) -> None:
226 result
.append('action1')
227 def action2(target
, source
, env
, result
=result
, **kw
) -> None:
228 result
.append('action2')
229 def post(target
, source
, env
, result
=result
, **kw
) -> None:
230 result
.append('post')
232 env
= MyEnvironment()
233 a
= MyAction([action1
, action2
])
236 x
= SCons
.Executor
.Executor(a
, env
, [], [t
], ['s1', 's2'])
237 x
.add_pre_action(pre
)
238 x
.add_post_action(post
)
240 assert result
== ['pre', 'action1', 'action2', 'post'], result
243 def pre_err(target
, source
, env
, result
=result
, **kw
) -> int:
244 result
.append('pre_err')
247 x
= SCons
.Executor
.Executor(a
, env
, [], [t
], ['s1', 's2'])
248 x
.add_pre_action(pre_err
)
249 x
.add_post_action(post
)
252 except SCons
.Errors
.BuildError
:
255 raise Exception("Did not catch expected BuildError")
256 assert result
== ['pre_err'], result
259 def test_cleanup(self
) -> None:
260 """Test cleaning up an Executor"""
261 orig_env
= MyEnvironment(e
=1)
262 x
= SCons
.Executor
.Executor('b', orig_env
, [{'o':1}],
265 be
= x
.get_build_env()
266 assert be
['e'] == 1, be
['e']
270 x
.env
= MyEnvironment(eee
=1)
271 be
= x
.get_build_env()
272 assert be
['eee'] == 1, be
['eee']
276 be
= x
.get_build_env()
277 assert be
['eee'] == 1, be
['eee']
279 def test_add_sources(self
) -> None:
280 """Test adding sources to an Executor"""
281 x
= SCons
.Executor
.Executor('b', 'e', 'o', 't', ['s1', 's2'])
282 sources
= x
.get_all_sources()
283 assert sources
== ['s1', 's2'], sources
285 x
.add_sources(['s1', 's2'])
286 sources
= x
.get_all_sources()
287 assert sources
== ['s1', 's2'], sources
289 x
.add_sources(['s3', 's1', 's4'])
290 sources
= x
.get_all_sources()
291 assert sources
== ['s1', 's2', 's3', 's4'], sources
293 def test_get_sources(self
) -> None:
294 """Test getting sources from an Executor"""
295 x
= SCons
.Executor
.Executor('b', 'e', 'o', 't', ['s1', 's2'])
296 sources
= x
.get_sources()
297 assert sources
== ['s1', 's2'], sources
299 x
.add_sources(['s1', 's2'])
300 sources
= x
.get_sources()
301 assert sources
== ['s1', 's2'], sources
303 x
.add_sources(['s3', 's1', 's4'])
304 sources
= x
.get_sources()
305 assert sources
== ['s1', 's2', 's3', 's4'], sources
307 def test_prepare(self
):
308 """Test the Executor's prepare() method"""
309 env
= MyEnvironment()
314 x
= SCons
.Executor
.Executor('b', env
, [{}], [t1
], [s1
, s2
, s3
])
316 s2
.missing_val
= True
320 except SCons
.Errors
.StopError
as e
:
321 assert str(e
) == "Source `s2' not found, needed by target `t1'.", e
323 raise AssertionError("did not catch expected StopError: %s" % r
)
325 def test_add_pre_action(self
) -> None:
326 """Test adding pre-actions to an Executor"""
327 x
= SCons
.Executor
.Executor('b', 'e', 'o', 't', ['s1', 's2'])
328 x
.add_pre_action('a1')
329 assert x
.pre_actions
== ['a1']
330 x
.add_pre_action('a2')
331 assert x
.pre_actions
== ['a1', 'a2']
333 def test_add_post_action(self
) -> None:
334 """Test adding post-actions to an Executor"""
335 x
= SCons
.Executor
.Executor('b', 'e', 'o', 't', ['s1', 's2'])
336 x
.add_post_action('a1')
337 assert x
.post_actions
== ['a1']
338 x
.add_post_action('a2')
339 assert x
.post_actions
== ['a1', 'a2']
341 def test___str__(self
) -> None:
342 """Test the __str__() method"""
343 env
= MyEnvironment(S
='string')
345 x
= SCons
.Executor
.Executor(MyAction(), env
, [], ['t'], ['s'])
347 assert c
== 'GENSTRING action1 action2 t s', c
349 x
= SCons
.Executor
.Executor(MyAction(), env
, [], ['t'], ['s'])
350 x
.add_pre_action(MyAction(['pre']))
351 x
.add_post_action(MyAction(['post']))
353 expect
= 'GENSTRING pre t s\n' + \
354 'GENSTRING action1 action2 t s\n' + \
356 assert c
== expect
, c
358 def test_nullify(self
) -> None:
359 """Test the nullify() method"""
360 env
= MyEnvironment(S
='string')
363 def action1(target
, source
, env
, result
=result
, **kw
) -> None:
364 result
.append('action1')
366 env
= MyEnvironment()
367 a
= MyAction([action1
])
368 x
= SCons
.Executor
.Executor(a
, env
, [], ['t1', 't2'], ['s1', 's2'])
370 x(MyNode('', [], []))
371 assert result
== ['action1'], result
373 assert s
[:10] == 'GENSTRING ', s
378 assert result
== [], result
379 x(MyNode('', [], []))
380 assert result
== [], result
384 def test_get_contents(self
) -> None:
385 """Test fetching the signatures contents"""
386 env
= MyEnvironment(C
='contents')
388 x
= SCons
.Executor
.Executor(MyAction(), env
, [], ['t'], ['s'])
390 assert c
== b
'action1 action2 t s', c
392 x
= SCons
.Executor
.Executor(MyAction(actions
=['grow']), env
, [],
394 x
.add_pre_action(MyAction(['pre']))
395 x
.add_post_action(MyAction(['post']))
397 assert c
== b
'pre t sgrow t spost t s', c
399 def test_get_timestamp(self
) -> None:
400 """Test fetching the "timestamp" """
401 x
= SCons
.Executor
.Executor('b', 'e', 'o', 't', ['s1', 's2'])
402 ts
= x
.get_timestamp()
405 def test_scan_targets(self
) -> None:
406 """Test scanning the targets for implicit dependencies"""
407 env
= MyEnvironment(S
='string')
410 sources
= [MyNode('s1'), MyNode('s2')]
411 x
= SCons
.Executor
.Executor(MyAction(), env
, [{}], [t1
, t2
], sources
)
413 deps
= x
.scan_targets(None)
414 assert t1
.implicit
== ['dep-t1', 'dep-t2'], t1
.implicit
415 assert t2
.implicit
== ['dep-t1', 'dep-t2'], t2
.implicit
420 deps
= x
.scan_targets(MyScanner('scanner-'))
421 assert t1
.implicit
== ['scanner-t1', 'scanner-t2'], t1
.implicit
422 assert t2
.implicit
== ['scanner-t1', 'scanner-t2'], t2
.implicit
424 def test_scan_sources(self
) -> None:
425 """Test scanning the sources for implicit dependencies"""
426 env
= MyEnvironment(S
='string')
429 sources
= [MyNode('s1'), MyNode('s2')]
430 x
= SCons
.Executor
.Executor(MyAction(), env
, [{}], [t1
, t2
], sources
)
432 deps
= x
.scan_sources(None)
433 assert t1
.implicit
== ['dep-s1', 'dep-s2'], t1
.implicit
434 assert t2
.implicit
== ['dep-s1', 'dep-s2'], t2
.implicit
439 deps
= x
.scan_sources(MyScanner('scanner-'))
440 assert t1
.implicit
== ['scanner-s1', 'scanner-s2'], t1
.implicit
441 assert t2
.implicit
== ['scanner-s1', 'scanner-s2'], t2
.implicit
443 def test_get_unignored_sources(self
) -> None:
444 """Test fetching the unignored source list"""
445 env
= MyEnvironment()
449 x
= SCons
.Executor
.Executor('b', env
, [{}], [], [s1
, s2
, s3
])
451 r
= x
.get_unignored_sources(None, [])
452 assert r
== [s1
, s2
, s3
], list(map(str, r
))
454 r
= x
.get_unignored_sources(None, [s2
])
455 assert r
== [s1
, s3
], list(map(str, r
))
457 r
= x
.get_unignored_sources(None, [s1
, s3
])
458 assert r
== [s2
], list(map(str, r
))
460 def test_changed_sources_for_alwaysBuild(self
) -> None:
462 Ensure if a target is marked always build that the sources are always marked changed sources
465 env
= MyEnvironment()
470 t1
.always_build
= True
472 x
= SCons
.Executor
.Executor('b', env
, [{}], [t1
], [s1
, s2
])
474 changed_sources
= x
._get
_changed
_sources
()
475 assert changed_sources
== [s1
, s2
], "If target marked AlwaysBuild sources should always be marked changed"
480 if __name__
== "__main__":
485 # indent-tabs-mode:nil
487 # vim: set expandtab tabstop=4 shiftwidth=4: