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__"
26 # Define a null function for use as a builder action.
27 # Where this is defined in the file seems to affect its
28 # byte-code contents, so try to minimize changes by
29 # defining it here, before we even import anything.
42 import SCons.Environment
45 # Initial setup of the common environment for all tests,
46 # a temporary working directory containing a
47 # script for writing arguments to an output file.
49 # We don't do this as a setUp() method because it's
50 # unnecessary to create a separate directory and script
51 # for each test, they can just use the one.
52 test = TestCmd.TestCmd(workdir = '')
54 outfile = test.workpath('outfile')
55 outfile2 = test.workpath('outfile2')
59 scons_env = SCons.Environment.Environment()
61 env_arg2nodes_called = None
64 def __init__(self, **kw):
66 self.d['SHELL'] = scons_env['SHELL']
67 self.d['SPAWN'] = scons_env['SPAWN']
68 self.d['ESCAPE'] = scons_env['ESCAPE']
69 for k, v in kw.items():
71 global env_arg2nodes_called
72 env_arg2nodes_called = None
75 if not SCons.Util.is_String(s):
79 return self.d.get(s[1:], '')
81 return s[0] + self.d.get(s[2:], '')
84 return self.d.get(s, s)
85 def arg2nodes(self, args, factory):
86 global env_arg2nodes_called
87 env_arg2nodes_called = 1
88 if not SCons.Util.is_List(args):
92 if SCons.Util.is_String(a):
96 def get_scanner(self, ext):
100 def autogenerate(self, dir=''):
102 def __setitem__(self, item, var):
104 def __getitem__(self, item):
106 def has_key(self, item):
107 return self.d.has_key(item)
110 def get(self, key, value):
111 return self.d.get(key, value)
112 def Override(self, overrides):
113 env = apply(Environment, (), self.d)
114 env.d.update(overrides)
116 def _update(self, dict):
119 return self.d.items()
122 for k,v in self.items(): d[k] = v
123 d['TARGETS'] = ['__t1__', '__t2__', '__t3__', '__t4__', '__t5__', '__t6__']
124 d['TARGET'] = d['TARGETS'][0]
125 d['SOURCES'] = ['__s1__', '__s2__', '__s3__', '__s4__', '__s5__', '__s6__']
126 d['SOURCE'] = d['SOURCES'][0]
129 class MyNode_without_target_from_source:
130 def __init__(self, name):
135 self.source_scanner = None
136 self.backup_source_scanner = None
139 def builder_set(self, builder):
140 self.builder = builder
141 def has_builder(self):
142 return not self.builder is None
143 def env_set(self, env, safe=0):
145 def add_source(self, source):
146 self.sources.extend(source)
147 def scanner_key(self):
149 def is_derived(self):
150 return self.has_builder()
151 def generate_build_env(self, env):
153 def get_build_env(self):
154 return self.executor.get_build_env()
155 def set_executor(self, executor):
156 self.executor = executor
157 def get_executor(self, create=1):
160 class MyNode(MyNode_without_target_from_source):
161 def target_from_source(self, prefix, suffix, stripext):
162 return MyNode(prefix + stripext(str(self))[0] + suffix)
164 class BuilderTestCase(unittest.TestCase):
166 def test__init__(self):
167 """Test simple Builder creation
169 builder = SCons.Builder.Builder(action="foo")
170 assert not builder is None, builder
171 builder = SCons.Builder.Builder(action="foo", OVERRIDE='x')
172 x = builder.overrides['OVERRIDE']
175 def test__nonzero__(self):
176 """Test a builder raising an exception when __nonzero__ is called
178 builder = SCons.Builder.Builder(action="foo")
181 builder.__nonzero__()
182 except SCons.Errors.InternalError:
184 assert exc_caught, "did not catch expected InternalError exception"
195 except SCons.Errors.InternalError:
197 assert exc_caught, "did not catch expected InternalError exception"
199 def test__call__(self):
200 """Test calling a builder to establish source dependencies
203 builder = SCons.Builder.Builder(action="foo",
204 target_factory=MyNode,
205 source_factory=MyNode)
209 builder(env, target = n1, source = n2)
210 assert env_arg2nodes_called
211 assert n1.env == env, n1.env
212 assert n1.builder == builder, n1.builder
213 assert n1.sources == [n2], n1.sources
214 assert n1.executor, "no executor found"
215 assert not hasattr(n2, 'env')
217 target = builder(env, target = 'n3', source = 'n4')
218 assert target.name == 'n3'
219 assert target.sources[0].name == 'n4'
221 target = builder(env, target = 'n4 n5', source = ['n6 n7'])
222 assert target.name == 'n4 n5'
223 assert target.sources[0].name == 'n6 n7'
225 target = builder(env, target = ['n8 n9'], source = 'n10 n11')
226 assert target.name == 'n8 n9'
227 assert target.sources[0].name == 'n10 n11'
229 # A test to be uncommented when we freeze the environment
230 # as part of calling the builder.
231 #env1 = Environment(VAR='foo')
232 #target = builder(env1, target = 'n12', source = 'n13')
234 #be = target.get_build_env()
235 #assert be['VAR'] == 'foo', be['VAR']
237 if not hasattr(types, 'UnicodeType'):
242 target = builder(env, target = uni('n12 n13'),
243 source = [uni('n14 n15')])
244 assert target.name == uni('n12 n13')
245 assert target.sources[0].name == uni('n14 n15')
247 target = builder(env, target = [uni('n16 n17')],
248 source = uni('n18 n19'))
249 assert target.name == uni('n16 n17')
250 assert target.sources[0].name == uni('n18 n19')
252 n20 = MyNode_without_target_from_source('n20')
255 target = builder(env, source=n20)
256 except SCons.Errors.UserError, e:
258 assert flag, "UserError should be thrown if a source node can't create a target."
260 builder = SCons.Builder.Builder(action="foo",
261 target_factory=MyNode,
262 source_factory=MyNode,
265 target = builder(env, source='n21')
266 assert target.name == 'p-n21.s', target
268 def test_mistaken_variables(self):
269 """Test keyword arguments that are often mistakes
271 import SCons.Warnings
273 builder = SCons.Builder.Builder(action="foo")
275 save_warn = SCons.Warnings.warn
277 def my_warn(exception, warning, warned=warned):
278 warned.append(warning)
279 SCons.Warnings.warn = my_warn
282 target = builder(env, 'mistaken1', sources='mistaken1.c')
283 assert warned == ["Did you mean to use `source' instead of `sources'?"], warned
286 target = builder(env, 'mistaken2', targets='mistaken2.c')
287 assert warned == ["Did you mean to use `target' instead of `targets'?"], warned
290 target = builder(env, 'mistaken3', targets='mistaken3', sources='mistaken3.c')
291 assert "Did you mean to use `source' instead of `sources'?" in warned, warned
292 assert "Did you mean to use `target' instead of `targets'?" in warned, warned
295 SCons.Warnings.warn = save_warn
297 def test_action(self):
298 """Test Builder creation
300 Verify that we can retrieve the supplied action attribute.
302 builder = SCons.Builder.Builder(action="foo")
303 assert builder.action.cmd_list == "foo"
307 builder = SCons.Builder.Builder(action=func)
308 assert isinstance(builder.action, SCons.Action.FunctionAction)
309 # Preserve the following so that the baseline test will fail.
310 # Remove it in favor of the previous test at some convenient
311 # point in the future.
312 assert builder.action.execfunction == func
314 def test_generator(self):
315 """Test Builder creation given a generator function."""
320 builder = SCons.Builder.Builder(generator=generator)
321 assert builder.action.generator == generator
324 """Test simple comparisons of Builder objects
326 b1 = SCons.Builder.Builder(src_suffix = '.o')
327 b2 = SCons.Builder.Builder(src_suffix = '.o')
329 b3 = SCons.Builder.Builder(src_suffix = '.x')
333 def test_target_factory(self):
334 """Test a Builder that creates target nodes of a specified class
338 def FooFactory(target):
341 builder = SCons.Builder.Builder(target_factory = FooFactory)
342 assert builder.target_factory is FooFactory
343 assert not builder.source_factory is FooFactory
345 def test_source_factory(self):
346 """Test a Builder that creates source nodes of a specified class
350 def FooFactory(source):
353 builder = SCons.Builder.Builder(source_factory = FooFactory)
354 assert not builder.target_factory is FooFactory
355 assert builder.source_factory is FooFactory
357 def test_splitext(self):
358 """Test the splitext() method attached to a Builder."""
359 b = SCons.Builder.Builder()
360 assert b.splitext('foo') == ('foo','')
361 assert b.splitext('foo.bar') == ('foo','.bar')
362 assert b.splitext(os.path.join('foo.bar', 'blat')) == (os.path.join('foo.bar', 'blat'),'')
364 class MyBuilder(SCons.Builder.BuilderBase):
365 def splitext(self, path):
366 return "called splitext()"
369 ret = b.splitext('xyz.c')
370 assert ret == "called splitext()", ret
372 def test_adjust_suffix(self):
373 """Test how a Builder adjusts file suffixes
375 b = SCons.Builder.Builder()
376 assert b.adjust_suffix('.foo') == '.foo'
377 assert b.adjust_suffix('foo') == '.foo'
378 assert b.adjust_suffix('$foo') == '$foo'
380 class MyBuilder(SCons.Builder.BuilderBase):
381 def adjust_suffix(self, suff):
382 return "called adjust_suffix()"
385 ret = b.adjust_suffix('.foo')
386 assert ret == "called adjust_suffix()", ret
388 def test_prefix(self):
389 """Test Builder creation with a specified target prefix
391 Make sure that there is no '.' separator appended.
394 builder = SCons.Builder.Builder(prefix = 'lib.')
395 assert builder.get_prefix(env) == 'lib.'
396 builder = SCons.Builder.Builder(prefix = 'lib')
397 assert builder.get_prefix(env) == 'lib'
398 tgt = builder(env, target = 'tgt1', source = 'src1')
399 assert tgt.path == 'libtgt1', \
400 "Target has unexpected name: %s" % tgt.path
401 tgt = builder(env, target = 'tgt2a tgt2b', source = 'src2')
402 assert tgt.path == 'libtgt2a tgt2b', \
403 "Target has unexpected name: %s" % tgt.path
404 tgt = builder(env, source = 'src3')
405 assert tgt.path == 'libsrc3', \
406 "Target has unexpected name: %s" % tgt.path
407 tgt = builder(env, source = 'lib/src4')
408 assert tgt.path == os.path.join('lib', 'libsrc4'), \
409 "Target has unexpected name: %s" % tgt.path
410 tgt = builder(env, target = 'lib/tgt5', source = 'lib/src5')
411 assert tgt.path == os.path.join('lib', 'libtgt5'), \
412 "Target has unexpected name: %s" % tgt.path
414 def gen_prefix(env, sources):
415 return "gen_prefix() says " + env['FOO']
416 my_env = Environment(FOO = 'xyzzy')
417 builder = SCons.Builder.Builder(prefix = gen_prefix)
418 assert builder.get_prefix(my_env) == "gen_prefix() says xyzzy"
419 my_env['FOO'] = 'abracadabra'
420 assert builder.get_prefix(my_env) == "gen_prefix() says abracadabra"
422 def my_emit(env, sources):
423 return env.subst('$EMIT')
424 my_env = Environment(FOO = '.foo', EMIT = 'emit-')
425 builder = SCons.Builder.Builder(prefix = {None : 'default-',
430 tgt = builder(my_env, source = 'f1')
431 assert tgt.path == 'default-f1', tgt.path
432 tgt = builder(my_env, source = 'f2.c')
433 assert tgt.path == 'default-f2', tgt.path
434 tgt = builder(my_env, source = 'f3.in')
435 assert tgt.path == 'out-f3', tgt.path
436 tgt = builder(my_env, source = 'f4.x')
437 assert tgt.path == 'y-f4', tgt.path
438 tgt = builder(my_env, source = 'f5.foo')
439 assert tgt.path == 'foo-f5', tgt.path
440 tgt = builder(my_env, source = 'f6.zzz')
441 assert tgt.path == 'emit-f6', tgt.path
443 def test_src_suffix(self):
444 """Test Builder creation with a specified source file suffix
446 Make sure that the '.' separator is appended to the
447 beginning if it isn't already present.
449 env = Environment(XSUFFIX = '.x', YSUFFIX = '.y')
451 b1 = SCons.Builder.Builder(src_suffix = '.c')
452 assert b1.src_suffixes(env) == ['.c'], b1.src_suffixes(env)
454 tgt = b1(env, target = 'tgt2', source = 'src2')
455 assert tgt.sources[0].path == 'src2.c', \
456 "Source has unexpected name: %s" % tgt.sources[0].path
458 tgt = b1(env, target = 'tgt3', source = 'src3a src3b')
459 assert len(tgt.sources) == 1
460 assert tgt.sources[0].path == 'src3a src3b.c', \
461 "Unexpected tgt.sources[0] name: %s" % tgt.sources[0].path
463 b2 = SCons.Builder.Builder(src_suffix = '.2', src_builder = b1)
464 assert b2.src_suffixes(env) == ['.2', '.c'], b2.src_suffixes(env)
466 b3 = SCons.Builder.Builder(action = {'.3a' : '', '.3b' : ''})
467 s = b3.src_suffixes(env)
469 assert s == ['.3a', '.3b'], s
471 b4 = SCons.Builder.Builder(src_suffix = '$XSUFFIX')
472 assert b4.src_suffixes(env) == ['.x'], b4.src_suffixes(env)
474 b5 = SCons.Builder.Builder(action = { '.y' : ''})
475 assert b5.src_suffixes(env) == ['.y'], b5.src_suffixes(env)
477 def test_suffix(self):
478 """Test Builder creation with a specified target suffix
480 Make sure that the '.' separator is appended to the
481 beginning if it isn't already present.
484 builder = SCons.Builder.Builder(suffix = '.o')
485 assert builder.get_suffix(env) == '.o', builder.get_suffix(env)
486 builder = SCons.Builder.Builder(suffix = 'o')
487 assert builder.get_suffix(env) == '.o', builder.get_suffix(env)
488 tgt = builder(env, target = 'tgt3', source = 'src3')
489 assert tgt.path == 'tgt3.o', \
490 "Target has unexpected name: %s" % tgt.path
491 tgt = builder(env, target = 'tgt4a tgt4b', source = 'src4')
492 assert tgt.path == 'tgt4a tgt4b.o', \
493 "Target has unexpected name: %s" % tgt.path
494 tgt = builder(env, source = 'src5')
495 assert tgt.path == 'src5.o', \
496 "Target has unexpected name: %s" % tgt.path
498 def gen_suffix(env, sources):
499 return "gen_suffix() says " + env['BAR']
500 my_env = Environment(BAR = 'hocus pocus')
501 builder = SCons.Builder.Builder(suffix = gen_suffix)
502 assert builder.get_suffix(my_env) == "gen_suffix() says hocus pocus", builder.get_suffix(my_env)
503 my_env['BAR'] = 'presto chango'
504 assert builder.get_suffix(my_env) == "gen_suffix() says presto chango"
506 def my_emit(env, sources):
507 return env.subst('$EMIT')
508 my_env = Environment(BAR = '.bar', EMIT = '.emit')
509 builder = SCons.Builder.Builder(suffix = {None : '.default',
514 tgt = builder(my_env, source = 'f1')
515 assert tgt.path == 'f1.default', tgt.path
516 tgt = builder(my_env, source = 'f2.c')
517 assert tgt.path == 'f2.default', tgt.path
518 tgt = builder(my_env, source = 'f3.in')
519 assert tgt.path == 'f3.out', tgt.path
520 tgt = builder(my_env, source = 'f4.x')
521 assert tgt.path == 'f4.y', tgt.path
522 tgt = builder(my_env, source = 'f5.bar')
523 assert tgt.path == 'f5.new', tgt.path
524 tgt = builder(my_env, source = 'f6.zzz')
525 assert tgt.path == 'f6.emit', tgt.path
527 def test_ListBuilder(self):
528 """Testing ListBuilder class."""
529 def function2(target, source, env, tlist = [outfile, outfile2], **kw):
531 open(str(t), 'w').write("function2\n")
533 if not t in map(str, target):
534 open(t, 'w').write("function2\n")
538 builder = SCons.Builder.Builder(action = function2)
539 tgts = builder(env, target = [outfile, outfile2], source = 'foo')
544 except SCons.Errors.BuildError:
546 c = test.read(outfile, 'r')
547 assert c == "function2\n", c
548 c = test.read(outfile2, 'r')
549 assert c == "function2\n", c
551 sub1_out = test.workpath('sub1', 'out')
552 sub2_out = test.workpath('sub2', 'out')
554 def function3(target, source, env, tlist = [sub1_out, sub2_out]):
556 open(str(t), 'w').write("function3\n")
558 if not t in map(str, target):
559 open(t, 'w').write("function3\n")
562 builder = SCons.Builder.Builder(action = function3)
563 tgts = builder(env, target = [sub1_out, sub2_out], source = 'foo')
568 except SCons.Errors.BuildError:
570 c = test.read(sub1_out, 'r')
571 assert c == "function3\n", c
572 c = test.read(sub2_out, 'r')
573 assert c == "function3\n", c
574 assert os.path.exists(test.workpath('sub1'))
575 assert os.path.exists(test.workpath('sub2'))
577 def test_MultiStepBuilder(self):
578 """Testing MultiStepBuilder class."""
580 builder1 = SCons.Builder.Builder(action='foo',
583 builder2 = SCons.Builder.MultiStepBuilder(action='bar',
584 src_builder = builder1,
587 tgt = builder2(env, target='baz', source=['test.bar', 'test2.foo', 'test3.txt'])
588 assert str(tgt.sources[0]) == 'test.foo', str(tgt.sources[0])
589 assert str(tgt.sources[0].sources[0]) == 'test.bar', \
590 str(tgt.sources[0].sources[0])
591 assert str(tgt.sources[1]) == 'test2.foo', str(tgt.sources[1])
592 assert str(tgt.sources[2]) == 'test3.txt', str(tgt.sources[2])
594 tgt = builder2(env, 'aaa.bar')
595 assert str(tgt) == 'aaa', str(tgt)
596 assert str(tgt.sources[0]) == 'aaa.foo', str(tgt.sources[0])
597 assert str(tgt.sources[0].sources[0]) == 'aaa.bar', \
598 str(tgt.sources[0].sources[0])
600 builder3 = SCons.Builder.MultiStepBuilder(action = 'foo',
601 src_builder = 'xyzzy',
602 src_suffix = '.xyzzy')
603 assert builder3.get_src_builders(Environment()) == []
605 builder4 = SCons.Builder.Builder(action='bld4',
608 builder5 = SCons.Builder.MultiStepBuilder(action='bld5',
609 src_builder=builder4,
612 builder6 = SCons.Builder.MultiStepBuilder(action='bld6',
613 src_builder=builder5,
616 tgt = builder6(env, 'test', 'test.i')
617 assert str(tgt) == 'test.exe', str(tgt)
618 assert str(tgt.sources[0]) == 'test_wrap.obj', str(tgt.sources[0])
619 assert str(tgt.sources[0].sources[0]) == 'test_wrap.c', \
620 str(tgt.sources[0].sources[0])
621 assert str(tgt.sources[0].sources[0].sources[0]) == 'test.i', \
622 str(tgt.sources[0].sources[0].sources[0])
624 def test_CompositeBuilder(self):
625 """Testing CompositeBuilder class."""
626 def func_action(target, source, env):
629 env = Environment(BAR_SUFFIX = '.BAR2', FOO_SUFFIX = '.FOO2')
630 builder = SCons.Builder.Builder(action={ '.foo' : func_action,
631 '.bar' : func_action,
632 '$BAR_SUFFIX' : func_action,
633 '$FOO_SUFFIX' : func_action })
635 assert isinstance(builder, SCons.Builder.CompositeBuilder)
636 assert isinstance(builder.action, SCons.Action.CommandGeneratorAction)
637 tgt = builder(env, target='test1', source='test1.foo')
638 assert isinstance(tgt.builder, SCons.Builder.BuilderBase)
639 assert tgt.builder.action is builder.action
640 tgt = builder(env, target='test2', source='test1.bar')
641 assert isinstance(tgt.builder, SCons.Builder.BuilderBase)
642 assert tgt.builder.action is builder.action
644 tgt = builder(env, target='test3', source=['test2.bar', 'test1.foo'])
647 except SCons.Errors.UserError, e:
649 assert flag, "UserError should be thrown when we build targets with files of different suffixes."
650 match = str(e) == "While building `['test3']' from `test1.foo': Cannot build multiple sources with different extensions: .bar, .foo"
653 tgt = builder(env, target='test4', source=['test4.BAR2'])
654 assert isinstance(tgt.builder, SCons.Builder.BuilderBase)
658 except SCons.Errors.UserError, e:
661 assert flag, "It should be possible to define actions in composite builders using variables."
662 env['FOO_SUFFIX'] = '.BAR2'
663 builder.add_action('$NEW_SUFFIX', func_action)
665 tgt = builder(env, target='test5', source=['test5.BAR2'])
668 except SCons.Errors.UserError:
670 assert flag, "UserError should be thrown when we build targets with ambigous suffixes."
671 del env.d['FOO_SUFFIX']
672 del env.d['BAR_SUFFIX']
674 foo_bld = SCons.Builder.Builder(action = 'a-foo',
677 assert isinstance(foo_bld, SCons.Builder.BuilderBase)
678 builder = SCons.Builder.Builder(action = { '.foo' : 'foo',
680 src_builder = foo_bld)
681 assert isinstance(builder, SCons.Builder.CompositeBuilder)
682 assert isinstance(builder.action, SCons.Action.CommandGeneratorAction)
684 tgt = builder(env, target='t1', source='t1a.ina t1b.ina')
685 assert isinstance(tgt.builder, SCons.Builder.BuilderBase)
687 tgt = builder(env, target='t2', source='t2a.foo t2b.ina')
688 assert isinstance(tgt.builder, SCons.Builder.MultiStepBuilder), tgt.builder.__dict__
690 bar_bld = SCons.Builder.Builder(action = 'a-bar',
693 assert isinstance(bar_bld, SCons.Builder.BuilderBase)
694 builder = SCons.Builder.Builder(action = { '.foo' : 'foo'},
695 src_builder = [foo_bld, bar_bld])
696 assert isinstance(builder, SCons.Builder.CompositeBuilder)
697 assert isinstance(builder.action, SCons.Action.CommandGeneratorAction)
699 builder.add_action('.bar', 'bar')
701 tgt = builder(env, target='t3-foo', source='t3a.foo t3b.ina')
702 assert isinstance(tgt.builder, SCons.Builder.MultiStepBuilder)
704 tgt = builder(env, target='t3-bar', source='t3a.bar t3b.inb')
705 assert isinstance(tgt.builder, SCons.Builder.MultiStepBuilder)
708 tgt = builder(env, target='t5', source=['test5a.foo', 'test5b.inb'])
711 except SCons.Errors.UserError, e:
713 assert flag, "UserError should be thrown when we build targets with files of different suffixes."
714 match = str(e) == "While building `['t5']' from `test5b.bar': Cannot build multiple sources with different extensions: .foo, .bar"
718 tgt = builder(env, target='t6', source=['test6a.bar', 'test6b.ina'])
721 except SCons.Errors.UserError, e:
723 assert flag, "UserError should be thrown when we build targets with files of different suffixes."
724 match = str(e) == "While building `['t6']' from `test6b.foo': Cannot build multiple sources with different extensions: .bar, .foo"
728 tgt = builder(env, target='t4', source=['test4a.ina', 'test4b.inb'])
731 except SCons.Errors.UserError, e:
733 assert flag, "UserError should be thrown when we build targets with files of different suffixes."
734 match = str(e) == "While building `['t4']' from `test4b.bar': Cannot build multiple sources with different extensions: .foo, .bar"
738 tgt = builder(env, target='t7', source=['test7'])
741 except SCons.Errors.UserError, e:
743 assert flag, "UserError should be thrown when we build targets with files of different suffixes."
744 match = str(e) == "While building `['t7']': Cannot deduce file extension from source files: ['test7']"
748 tgt = builder(env, target='t8', source=['test8.unknown'])
751 except SCons.Errors.UserError, e:
753 assert flag, "UserError should be thrown when we build targets with files of different suffixes."
754 match = str(e) == "While building `['t8']': Don't know how to build a file with suffix `.unknown'."
757 def test_target_scanner(self):
758 """Testing ability to set target and source scanners through a builder."""
762 tscan = TestScanner()
763 sscan = TestScanner()
765 builder = SCons.Builder.Builder(target_scanner=tscan,
766 source_scanner=sscan)
767 tgt = builder(env, target='foo2', source='bar')
768 assert tgt.target_scanner == tscan, tgt.target_scanner
769 assert tgt.source_scanner == sscan, tgt.source_scanner
771 builder1 = SCons.Builder.Builder(action='foo',
774 builder2 = SCons.Builder.Builder(action='foo',
775 src_builder = builder1,
776 target_scanner = tscan,
777 source_scanner = tscan)
778 tgt = builder2(env, target='baz2', source='test.bar test2.foo test3.txt')
779 assert tgt.target_scanner == tscan, tgt.target_scanner
780 assert tgt.source_scanner == tscan, tgt.source_scanner
782 def test_src_scanner(slf):
783 """Testing ability to set a source file scanner through a builder."""
786 return 'TestScannerkey'
787 def instance(self, env):
790 scanner = TestScanner()
791 builder = SCons.Builder.Builder(action='action')
793 # With no scanner specified, source_scanner and
794 # backup_source_scanner are None.
796 tgt = builder(env1, target='foo1.x', source='bar.y')
798 assert tgt.target_scanner != scanner, tgt.target_scanner
799 assert src.source_scanner is None, src.source_scanner
800 assert src.backup_source_scanner is None, src.backup_source_scanner
802 # Later use of the same source file with an environment that
803 # has a scanner must still set the scanner.
805 env2.scanner = scanner
806 tgt = builder(env2, target='foo2.x', source='bar.y')
808 assert tgt.target_scanner != scanner, tgt.target_scanner
809 assert src.source_scanner is None, src.source_scanner
810 assert src.backup_source_scanner == scanner, src.backup_source_scanner
812 def test_Builder_Args(self):
813 """Testing passing extra args to a builder."""
814 def buildFunc(target, source, env, s=self):
817 assert env['CC'] == 'mycc'
819 env=Environment(CC='cc')
821 builder = SCons.Builder.Builder(action=buildFunc)
822 tgt = builder(env, target='foo', source='bar', foo=1, bar=2, CC='mycc')
824 assert self.foo == 1, self.foo
825 assert self.bar == 2, self.bar
827 def test_emitter(self):
828 """Test emitter functions."""
829 def emit(target, source, env):
830 foo = env.get('foo', 0)
831 bar = env.get('bar', 0)
833 assert isinstance(t, MyNode)
834 assert t.has_builder()
836 assert isinstance(s, MyNode)
838 target.append("bar%d"%foo)
841 return ( target, source )
844 builder = SCons.Builder.Builder(action='foo',
846 target_factory=MyNode,
847 source_factory=MyNode)
848 tgt = builder(env, target='foo2', source='bar')
849 assert str(tgt) == 'foo2', str(tgt)
850 assert str(tgt.sources[0]) == 'bar', str(tgt.sources[0])
852 tgt = builder(env, target='foo3', source='bar', foo=1)
853 assert len(tgt) == 2, len(tgt)
854 assert 'foo3' in map(str, tgt), map(str, tgt)
855 assert 'bar1' in map(str, tgt), map(str, tgt)
857 tgt = builder(env, target='foo4', source='bar', bar=1)
858 assert str(tgt) == 'foo4', str(tgt)
859 assert len(tgt.sources) == 2, len(tgt.sources)
860 assert 'baz' in map(str, tgt.sources), map(str, tgt.sources)
861 assert 'bar' in map(str, tgt.sources), map(str, tgt.sources)
863 env2=Environment(FOO=emit)
864 builder2=SCons.Builder.Builder(action='foo',
866 target_factory=MyNode,
867 source_factory=MyNode)
869 tgt = builder2(env2, target='foo5', source='bar')
870 assert str(tgt) == 'foo5', str(tgt)
871 assert str(tgt.sources[0]) == 'bar', str(tgt.sources[0])
873 tgt = builder2(env2, target='foo6', source='bar', foo=2)
874 assert len(tgt) == 2, len(tgt)
875 assert 'foo6' in map(str, tgt), map(str, tgt)
876 assert 'bar2' in map(str, tgt), map(str, tgt)
878 tgt = builder2(env2, target='foo7', source='bar', bar=1)
879 assert str(tgt) == 'foo7', str(tgt)
880 assert len(tgt.sources) == 2, len(tgt.sources)
881 assert 'baz' in map(str, tgt.sources), map(str, tgt.sources)
882 assert 'bar' in map(str, tgt.sources), map(str, tgt.sources)
884 builder2a=SCons.Builder.Builder(action='foo',
886 target_factory=MyNode,
887 source_factory=MyNode)
888 assert builder2 == builder2a, repr(builder2.__dict__) + "\n" + repr(builder2a.__dict__)
890 # Test that, if an emitter sets a builder on the passed-in
891 # targets and passes back new targets, the new builder doesn't
893 new_builder = SCons.Builder.Builder(action='new')
894 node = MyNode('foo8')
895 new_node = MyNode('foo8.new')
896 def emit3(target, source, env, nb=new_builder, nn=new_node):
901 builder3=SCons.Builder.Builder(action='foo',
903 target_factory=MyNode,
904 source_factory=MyNode)
905 tgt = builder3(env, target=node, source='bar')
906 assert tgt is new_node, tgt
907 assert tgt.builder is builder3, tgt.builder
908 assert node.builder is new_builder, node.builder
910 # Test use of a dictionary mapping file suffixes to
912 def emit4a(target, source, env):
913 source = map(str, source)
914 target = map(lambda x: 'emit4a-' + x[:-3], source)
915 return (target, source)
916 def emit4b(target, source, env):
917 source = map(str, source)
918 target = map(lambda x: 'emit4b-' + x[:-3], source)
919 return (target, source)
920 builder4 = SCons.Builder.Builder(action='foo',
921 emitter={'.4a':emit4a,
923 target_factory=MyNode,
924 source_factory=MyNode)
925 tgt = builder4(env, source='aaa.4a')
926 assert str(tgt) == 'emit4a-aaa', str(tgt)
927 tgt = builder4(env, source='bbb.4b')
928 assert str(tgt) == 'emit4b-bbb', str(tgt)
929 tgt = builder4(env, source='ccc.4c')
930 assert str(tgt) == 'ccc', str(tgt)
932 def emit4c(target, source, env):
933 source = map(str, source)
934 target = map(lambda x: 'emit4c-' + x[:-3], source)
935 return (target, source)
936 builder4.add_emitter('.4c', emit4c)
937 tgt = builder4(env, source='ccc.4c')
938 assert str(tgt) == 'emit4c-ccc', str(tgt)
940 # Test a list of emitter functions.
941 def emit5a(target, source, env):
942 source = map(str, source)
943 target = target + map(lambda x: 'emit5a-' + x[:-2], source)
944 return (target, source)
945 def emit5b(target, source, env):
946 source = map(str, source)
947 target = target + map(lambda x: 'emit5b-' + x[:-2], source)
948 return (target, source)
949 builder5 = SCons.Builder.Builder(action='foo',
950 emitter=[emit5a, emit5b],
953 tgts = builder5(env, target='target-5', source='aaa.5')
954 tgts = map(str, tgts)
955 assert tgts == ['target-5', 'emit5a-aaa', 'emit5b-aaa'], tgts
957 # Test a list of emitter functions through the environment.
958 def emit6a(target, source, env):
959 source = map(str, source)
960 target = target + map(lambda x: 'emit6a-' + x[:-2], source)
961 return (target, source)
962 def emit6b(target, source, env):
963 source = map(str, source)
964 target = target + map(lambda x: 'emit6b-' + x[:-2], source)
965 return (target, source)
966 builder6 = SCons.Builder.Builder(action='foo',
967 emitter='$EMITTERLIST',
970 env = Environment(EMITTERLIST = [emit6a, emit6b])
972 tgts = builder6(env, target='target-6', source='aaa.6')
973 tgts = map(str, tgts)
974 assert tgts == ['target-6', 'emit6a-aaa', 'emit6b-aaa'], tgts
976 def test_no_target(self):
977 """Test deducing the target from the source."""
980 b = SCons.Builder.Builder(action='foo', suffix='.o')
983 assert str(tgt) == 'aaa.o', str(tgt)
984 assert len(tgt.sources) == 1, map(str, tgt.sources)
985 assert str(tgt.sources[0]) == 'aaa', map(str, tgt.sources)
987 tgt = b(env, 'bbb.c')
988 assert str(tgt) == 'bbb.o', str(tgt)
989 assert len(tgt.sources) == 1, map(str, tgt.sources)
990 assert str(tgt.sources[0]) == 'bbb.c', map(str, tgt.sources)
992 tgt = b(env, 'ccc.x.c')
993 assert str(tgt) == 'ccc.x.o', str(tgt)
994 assert len(tgt.sources) == 1, map(str, tgt.sources)
995 assert str(tgt.sources[0]) == 'ccc.x.c', map(str, tgt.sources)
997 tgt = b(env, ['d0.c', 'd1.c'])
998 assert str(tgt) == 'd0.o', str(tgt)
999 assert len(tgt.sources) == 2, map(str, tgt.sources)
1000 assert str(tgt.sources[0]) == 'd0.c', map(str, tgt.sources)
1001 assert str(tgt.sources[1]) == 'd1.c', map(str, tgt.sources)
1003 tgt = b(env, source='eee')
1004 assert str(tgt) == 'eee.o', str(tgt)
1005 assert len(tgt.sources) == 1, map(str, tgt.sources)
1006 assert str(tgt.sources[0]) == 'eee', map(str, tgt.sources)
1008 tgt = b(env, source='fff.c')
1009 assert str(tgt) == 'fff.o', str(tgt)
1010 assert len(tgt.sources) == 1, map(str, tgt.sources)
1011 assert str(tgt.sources[0]) == 'fff.c', map(str, tgt.sources)
1013 tgt = b(env, source='ggg.x.c')
1014 assert str(tgt) == 'ggg.x.o', str(tgt)
1015 assert len(tgt.sources) == 1, map(str, tgt.sources)
1016 assert str(tgt.sources[0]) == 'ggg.x.c', map(str, tgt.sources)
1018 tgt = b(env, source=['h0.c', 'h1.c'])
1019 assert str(tgt) == 'h0.o', str(tgt)
1020 assert len(tgt.sources) == 2, map(str, tgt.sources)
1021 assert str(tgt.sources[0]) == 'h0.c', map(str, tgt.sources)
1022 assert str(tgt.sources[1]) == 'h1.c', map(str, tgt.sources)
1024 w = b(env, target='i0.w', source=['i0.x'])
1025 y = b(env, target='i1.y', source=['i1.z'])
1026 tgt = b(env, source=[w, y])
1027 assert str(tgt) == 'i0.o', str(tgt)
1028 assert len(tgt.sources) == 2, map(str, tgt.sources)
1029 assert str(tgt.sources[0]) == 'i0.w', map(str, tgt.sources)
1030 assert str(tgt.sources[1]) == 'i1.y', map(str, tgt.sources)
1033 if __name__ == "__main__":
1034 suite = unittest.makeSuite(BuilderTestCase, 'test_')
1035 if not unittest.TextTestRunner().run(suite).wasSuccessful():