Fix specifying only the source argument to a MultiStepBuilder (such as Program).
[scons.git] / src / engine / SCons / BuilderTests.py
1 #
2 # Copyright (c) 2001, 2002 Steven Knight
3 #
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:
11 #
12 # The above copyright notice and this permission notice shall be included
13 # in all copies or substantial portions of the Software.
14 #
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.
22 #
23
24 __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
25
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.
30 def Func():
31     pass
32
33 import os.path
34 import sys
35 import types
36 import unittest
37
38 import TestCmd
39
40 import SCons.Action
41 import SCons.Builder
42 import SCons.Errors
43 import SCons.Node.FS
44 import SCons.Warnings
45 import SCons.Environment
46
47 # Initial setup of the common environment for all tests,
48 # a temporary working directory containing a
49 # script for writing arguments to an output file.
50 #
51 # We don't do this as a setUp() method because it's
52 # unnecessary to create a separate directory and script
53 # for each test, they can just use the one.
54 test = TestCmd.TestCmd(workdir = '')
55
56 outfile = test.workpath('outfile')
57 outfile2 = test.workpath('outfile2')
58
59 show_string = None
60 env_scanner = None
61
62 scons_env = SCons.Environment.Environment()
63
64 class Environment:
65     def __init__(self, **kw):
66         self.d = {}
67         self.d['SHELL'] = scons_env['SHELL']
68         self.d['SPAWN'] = scons_env['SPAWN']
69         self.d['ESCAPE'] = scons_env['ESCAPE']
70         for k, v in kw.items():
71             self.d[k] = v
72     def subst(self, s):
73         if not SCons.Util.is_String(s):
74             return s
75         try:
76             if s[0] == '$':
77                 return self.d.get(s[1:], '')
78         except IndexError:
79             pass
80         return self.d.get(s, s)
81     def get_scanner(self, ext):
82         return env_scanner
83     def Dictionary(self):
84         return {}
85     def autogenerate(self, dir=''):
86         return {}
87     def __getitem__(self, item):
88         return self.d[item]
89     def has_key(self, item):
90         return self.d.has_key(item)
91     def keys(self):
92         return self.d.keys()
93     def get(self, key, value):
94         return self.d.get(key, value)
95     def Override(self, overrides):
96         env = apply(Environment, (), self.d)
97         env.d.update(overrides)
98         return env
99     def items(self):
100         return self.d.items()
101     
102 env = Environment()
103
104 class BuilderTestCase(unittest.TestCase):
105
106     def test__call__(self):
107         """Test calling a builder to establish source dependencies
108         """
109         class Node:
110             def __init__(self, name):
111                 self.name = name
112                 self.sources = []
113                 self.builder = None
114                 self.side_effect = 0
115             def __str__(self):
116                 return self.name
117             def builder_set(self, builder):
118                 self.builder = builder
119             def has_builder(self):
120                 return not self.builder is None
121             def env_set(self, env, safe=0):
122                 self.env = env
123             def add_source(self, source):
124                 self.sources.extend(source)
125             def scanner_key(self):
126                 return self.name
127         builder = SCons.Builder.Builder(name="builder", action="foo", node_factory=Node)
128
129         n1 = Node("n1");
130         n2 = Node("n2");
131         builder(env, target = n1, source = n2)
132         assert n1.env == env
133         assert n1.builder == builder
134         assert n1.sources == [n2]
135         assert not hasattr(n2, 'env')
136
137         target = builder(env, target = 'n3', source = 'n4')
138         assert target.name == 'n3'
139         assert target.sources[0].name == 'n4'
140
141         target = builder(env, target = 'n4 n5', source = ['n6 n7'])
142         assert target.name == 'n4 n5'
143         assert target.sources[0].name == 'n6 n7'
144
145         target = builder(env, target = ['n8 n9'], source = 'n10 n11')
146         assert target.name == 'n8 n9'
147         assert target.sources[0].name == 'n10 n11'
148
149         if not hasattr(types, 'UnicodeType'):
150             uni = str
151         else:
152             uni = unicode
153
154         target = builder(env, target = uni('n12 n13'),
155                           source = [uni('n14 n15')])
156         assert target.name == uni('n12 n13')
157         assert target.sources[0].name == uni('n14 n15')
158
159         target = builder(env, target = [uni('n16 n17')],
160                          source = uni('n18 n19'))
161         assert target.name == uni('n16 n17')
162         assert target.sources[0].name == uni('n18 n19')
163
164     def test_noname(self):
165         """Test deprecated warning for Builder name.
166
167         Using the name argument for Builder() is deprectaed and the
168         user should receive a warning.
169         """
170         SCons.Warnings.enableWarningClass(SCons.Warnings.DeprecatedWarning)
171         SCons.Warnings.warningAsException(1)
172
173         try:
174             try:
175                 b = SCons.Builder.Builder(name='foo')
176             except SCons.Warnings.DeprecatedWarning:
177                 pass
178             else:
179                 assert 0
180         finally:
181             SCons.Warnings.suppressWarningClass(SCons.Warnings.DeprecatedWarning)
182             SCons.Warnings.warningAsException(0)
183
184     def test_action(self):
185         """Test Builder creation
186
187         Verify that we can retrieve the supplied action attribute.
188         """
189         builder = SCons.Builder.Builder(name="builder", action="foo")
190         assert builder.action.cmd_list == ["foo"]
191
192         def func():
193             pass
194         builder = SCons.Builder.Builder(name="builder", action=func)
195         assert isinstance(builder.action, SCons.Action.FunctionAction)
196         # Preserve the following so that the baseline test will fail.
197         # Remove it in favor of the previous test at some convenient
198         # point in the future.
199         assert builder.action.execfunction == func
200
201     def test_generator(self):
202         """Test Builder creation given a generator function."""
203
204         def generator():
205             pass
206
207         builder = SCons.Builder.Builder(name="builder", generator=generator)
208         assert builder.action.generator == generator
209
210     def test_cmp(self):
211         """Test simple comparisons of Builder objects
212         """
213         b1 = SCons.Builder.Builder(name="b1", src_suffix = '.o')
214         b2 = SCons.Builder.Builder(name="b1", src_suffix = '.o')
215         assert b1 == b2
216         b3 = SCons.Builder.Builder(name="b3", src_suffix = '.x')
217         assert b1 != b3
218         assert b2 != b3
219
220     def test_get_actions(self):
221         """Test fetching the Builder's Action list
222         """
223         def func():
224             pass
225         builder = SCons.Builder.Builder(name="builder",
226                                         action=SCons.Action.ListAction(["x",
227                                                                         func,
228                                                                         "z"]))
229         a = builder.get_actions()
230         assert len(a) == 3, a
231         assert isinstance(a[0], SCons.Action.CommandAction), a[0]
232         assert isinstance(a[1], SCons.Action.FunctionAction), a[1]
233         assert isinstance(a[2], SCons.Action.CommandAction), a[2]
234
235     def test_get_contents(self):
236         """Test returning the signature contents of a Builder
237         """
238
239         b1 = SCons.Builder.Builder(name = "b1", action = "foo")
240         contents = b1.get_contents([],[],Environment())
241         assert contents == "foo", contents
242
243         b2 = SCons.Builder.Builder(name = "b2", action = Func)
244         contents = b2.get_contents([],[],Environment())
245         assert contents == "\177\036\000\177\037\000d\000\000S", repr(contents)
246
247         b3 = SCons.Builder.Builder(name = "b3", action = SCons.Action.ListAction(["foo", Func, "bar"]))
248         contents = b3.get_contents([],[],Environment())
249         assert contents == "foo\177\036\000\177\037\000d\000\000Sbar", repr(contents)
250
251     def test_node_factory(self):
252         """Test a Builder that creates nodes of a specified class
253         """
254         class Foo:
255             pass
256         def FooFactory(target):
257             global Foo
258             return Foo(target)
259         builder = SCons.Builder.Builder(name = "builder", node_factory = FooFactory)
260         assert builder.target_factory is FooFactory
261         assert builder.source_factory is FooFactory
262
263     def test_target_factory(self):
264         """Test a Builder that creates target nodes of a specified class
265         """
266         class Foo:
267             pass
268         def FooFactory(target):
269             global Foo
270             return Foo(target)
271         builder = SCons.Builder.Builder(name = "builder", target_factory = FooFactory)
272         assert builder.target_factory is FooFactory
273         assert not builder.source_factory is FooFactory
274
275     def test_source_factory(self):
276         """Test a Builder that creates source nodes of a specified class
277         """
278         class Foo:
279             pass
280         def FooFactory(source):
281             global Foo
282             return Foo(source)
283         builder = SCons.Builder.Builder(name = "builder", source_factory = FooFactory)
284         assert not builder.target_factory is FooFactory
285         assert builder.source_factory is FooFactory
286
287     def test_prefix(self):
288         """Test Builder creation with a specified target prefix
289
290         Make sure that there is no '.' separator appended.
291         """
292         builder = SCons.Builder.Builder(name = "builder", prefix = 'lib.')
293         assert builder.get_prefix(env) == 'lib.'
294         builder = SCons.Builder.Builder(name = "builder", prefix = 'lib')
295         assert builder.get_prefix(env) == 'lib'
296         tgt = builder(env, target = 'tgt1', source = 'src1')
297         assert tgt.path == 'libtgt1', \
298                 "Target has unexpected name: %s" % tgt.path
299         tgt = builder(env, target = 'tgt2a tgt2b', source = 'src2')
300         assert tgt.path == 'libtgt2a tgt2b', \
301                 "Target has unexpected name: %s" % tgt.path
302
303     def test_src_suffix(self):
304         """Test Builder creation with a specified source file suffix
305         
306         Make sure that the '.' separator is appended to the
307         beginning if it isn't already present.
308         """
309         env = Environment(XSUFFIX = '.x', YSUFFIX = '.y')
310
311         b1 = SCons.Builder.Builder(name = "builder", src_suffix = '.c')
312         assert b1.src_suffixes(env) == ['.c'], b1.src_suffixes(env)
313
314         tgt = b1(env, target = 'tgt2', source = 'src2')
315         assert tgt.sources[0].path == 'src2.c', \
316                 "Source has unexpected name: %s" % tgt.sources[0].path
317
318         tgt = b1(env, target = 'tgt3', source = 'src3a src3b')
319         assert len(tgt.sources) == 1
320         assert tgt.sources[0].path == 'src3a src3b.c', \
321                 "Unexpected tgt.sources[0] name: %s" % tgt.sources[0].path
322
323         b2 = SCons.Builder.Builder(name = "b2",
324                                    src_suffix = '.2',
325                                    src_builder = b1)
326         assert b2.src_suffixes(env) == ['.2', '.c'], b2.src_suffixes(env)
327
328         b3 = SCons.Builder.Builder(name = "b3",
329                                    action = {'.3a' : '', '.3b' : ''})
330         s = b3.src_suffixes(env)
331         s.sort()
332         assert s == ['.3a', '.3b'], s
333
334         b4 = SCons.Builder.Builder(name = "b4", src_suffix = '$XSUFFIX')
335         assert b4.src_suffixes(env) == ['.x'], b4.src_suffixes(env)
336
337         b5 = SCons.Builder.Builder(name = "b5", action = { '.y' : ''})
338         assert b5.src_suffixes(env) == ['.y'], b5.src_suffixes(env)
339
340     def test_suffix(self):
341         """Test Builder creation with a specified target suffix
342
343         Make sure that the '.' separator is appended to the
344         beginning if it isn't already present.
345         """
346         builder = SCons.Builder.Builder(name = "builder", suffix = '.o')
347         assert builder.get_suffix(env) == '.o', builder.get_suffix(env)
348         builder = SCons.Builder.Builder(name = "builder", suffix = 'o')
349         assert builder.get_suffix(env) == '.o', builder.get_suffix(env)
350         tgt = builder(env, target = 'tgt3', source = 'src3')
351         assert tgt.path == 'tgt3.o', \
352                 "Target has unexpected name: %s" % tgt.path
353         tgt = builder(env, target = 'tgt4a tgt4b', source = 'src4')
354         assert tgt.path == 'tgt4a tgt4b.o', \
355                 "Target has unexpected name: %s" % tgt.path
356
357     def test_ListBuilder(self):
358         """Testing ListBuilder class."""
359         def function2(target, source, env, tlist = [outfile, outfile2], **kw):
360             for t in target:
361                 open(str(t), 'w').write("function2\n")
362             for t in tlist:
363                 if not t in map(str, target):
364                     open(t, 'w').write("function2\n")
365             return 1
366
367         builder = SCons.Builder.Builder(action = function2, name = "function2")
368         tgts = builder(env, target = [outfile, outfile2], source = 'foo')
369         for t in tgts:
370             t.prepare()
371         try:
372             tgts[0].build()
373         except SCons.Errors.BuildError:
374             pass
375         c = test.read(outfile, 'r')
376         assert c == "function2\n", c
377         c = test.read(outfile2, 'r')
378         assert c == "function2\n", c
379
380         sub1_out = test.workpath('sub1', 'out')
381         sub2_out = test.workpath('sub2', 'out')
382
383         def function3(target, source, env, tlist = [sub1_out, sub2_out]):
384             for t in target:
385                 open(str(t), 'w').write("function3\n")
386             for t in tlist:
387                 if not t in map(str, target):
388                     open(t, 'w').write("function3\n")
389             return 1
390
391         builder = SCons.Builder.Builder(action = function3, name = "function3")
392         tgts = builder(env, target = [sub1_out, sub2_out], source = 'foo')
393         for t in tgts:
394             t.prepare()
395         try:
396             tgts[0].build()
397         except SCons.Errors.BuildError:
398             pass
399         c = test.read(sub1_out, 'r')
400         assert c == "function3\n", c
401         c = test.read(sub2_out, 'r')
402         assert c == "function3\n", c
403         assert os.path.exists(test.workpath('sub1'))
404         assert os.path.exists(test.workpath('sub2'))
405
406     def test_MultiStepBuilder(self):
407         """Testing MultiStepBuilder class."""
408         builder1 = SCons.Builder.Builder(name = "builder1",
409                                          action='foo',
410                                          src_suffix='.bar',
411                                          suffix='.foo')
412         builder2 = SCons.Builder.MultiStepBuilder(name = "builder2",
413                                                   action='bar',
414                                                   src_builder = builder1,
415                                                   src_suffix = '.foo')
416         tgt = builder2(env, target='baz', source=['test.bar', 'test2.foo', 'test3.txt'])
417         assert str(tgt.sources[0]) == 'test.foo', str(tgt.sources[0])
418         assert str(tgt.sources[0].sources[0]) == 'test.bar', \
419                str(tgt.sources[0].sources[0])
420         assert str(tgt.sources[1]) == 'test2.foo', str(tgt.sources[1])
421         assert str(tgt.sources[2]) == 'test3.txt', str(tgt.sources[2])
422
423         tgt = builder2(env, 'aaa.bar')
424         assert str(tgt) == 'aaa', str(tgt)
425         assert str(tgt.sources[0]) == 'aaa.foo', str(tgt.sources[0])
426         assert str(tgt.sources[0].sources[0]) == 'aaa.bar', \
427                str(tgt.sources[0].sources[0])
428
429         builder3 = SCons.Builder.MultiStepBuilder(name = "builder3",
430                                                   action = 'foo',
431                                                   src_builder = 'xyzzy',
432                                                   src_suffix = '.xyzzy')
433         assert builder3.get_src_builders(Environment()) == []
434         
435     def test_CompositeBuilder(self):
436         """Testing CompositeBuilder class."""
437         def func_action(target, source, env):
438             return 0
439         
440         builder = SCons.Builder.Builder(name = "builder",
441                                         action={ '.foo' : func_action,
442                                                  '.bar' : func_action })
443         
444         assert isinstance(builder, SCons.Builder.CompositeBuilder)
445         assert isinstance(builder.action, SCons.Action.CommandGeneratorAction)
446         tgt = builder(env, target='test1', source='test1.foo')
447         assert isinstance(tgt.builder, SCons.Builder.BuilderBase)
448         assert tgt.builder.action is builder.action
449         tgt = builder(env, target='test2', source='test1.bar')
450         assert isinstance(tgt.builder, SCons.Builder.BuilderBase)
451         assert tgt.builder.action is builder.action
452         flag = 0
453         tgt = builder(env, target='test3', source=['test2.bar', 'test1.foo'])
454         try:
455             tgt.build()
456         except SCons.Errors.UserError:
457             flag = 1
458         assert flag, "UserError should be thrown when we build targets with files of different suffixes."
459
460         foo_bld = SCons.Builder.Builder(name = "foo_bld",
461                                         action = 'a-foo',
462                                         src_suffix = '.ina',
463                                         suffix = '.foo')
464         assert isinstance(foo_bld, SCons.Builder.BuilderBase)
465         builder = SCons.Builder.Builder(name = "builder",
466                                         action = { '.foo' : 'foo',
467                                                    '.bar' : 'bar' },
468                                         src_builder = foo_bld)
469         assert isinstance(builder, SCons.Builder.CompositeBuilder)
470         assert isinstance(builder.action, SCons.Action.CommandGeneratorAction)
471
472         tgt = builder(env, target='t1', source='t1a.ina t1b.ina')
473         assert isinstance(tgt.builder, SCons.Builder.BuilderBase)
474
475         tgt = builder(env, target='t2', source='t2a.foo t2b.ina')
476         assert isinstance(tgt.builder, SCons.Builder.MultiStepBuilder), tgt.builder.__dict__
477
478         bar_bld = SCons.Builder.Builder(name = "bar_bld",
479                                         action = 'a-bar',
480                                         src_suffix = '.inb',
481                                         suffix = '.bar')
482         assert isinstance(bar_bld, SCons.Builder.BuilderBase)
483         builder = SCons.Builder.Builder(name = "builder",
484                                         action = { '.foo' : 'foo'},
485                                         src_builder = [foo_bld, bar_bld])
486         assert isinstance(builder, SCons.Builder.CompositeBuilder)
487         assert isinstance(builder.action, SCons.Action.CommandGeneratorAction)
488
489         builder.add_action('.bar', 'bar')
490
491         tgt = builder(env, target='t3-foo', source='t3a.foo t3b.ina')
492         assert isinstance(tgt.builder, SCons.Builder.MultiStepBuilder)
493
494         tgt = builder(env, target='t3-bar', source='t3a.bar t3b.inb')
495         assert isinstance(tgt.builder, SCons.Builder.MultiStepBuilder)
496
497         flag = 0
498         tgt = builder(env, target='t5', source='test5a.foo test5b.inb')
499         try:
500             tgt.build()
501         except SCons.Errors.UserError:
502             flag = 1
503         assert flag, "UserError should be thrown when we build targets with files of different suffixes."
504
505         flag = 0
506         tgt = builder(env, target='t6', source='test6a.bar test6b.ina')
507         try:
508             tgt.build()
509         except SCons.Errors.UserError:
510             flag = 1
511         assert flag, "UserError should be thrown when we build targets with files of different suffixes."
512
513         flag = 0
514         tgt = builder(env, target='t4', source='test4a.ina test4b.inb')
515         try:
516             tgt.build()
517         except SCons.Errors.UserError:
518             flag = 1
519         assert flag, "UserError should be thrown when we build targets with files of different suffixes."
520
521     def test_build_scanner(self):
522         """Testing ability to set a target scanner through a builder."""
523         global instanced
524         class TestScanner:
525             pass
526         scn = TestScanner()
527         builder = SCons.Builder.Builder(name = "builder", scanner=scn)
528         tgt = builder(env, target='foo2', source='bar')
529         assert tgt.target_scanner == scn, tgt.target_scanner
530
531         builder1 = SCons.Builder.Builder(name = "builder1",
532                                          action='foo',
533                                          src_suffix='.bar',
534                                          suffix='.foo')
535         builder2 = SCons.Builder.Builder(name = "builder2",
536                                          action='foo',
537                                          src_builder = builder1,
538                                          scanner = scn)
539         tgt = builder2(env, target='baz2', source='test.bar test2.foo test3.txt')
540         assert tgt.target_scanner == scn, tgt.target_scanner
541
542     def test_src_scanner(slf):
543         """Testing ability to set a source file scanner through a builder."""
544         global env_scanner
545         class TestScanner:
546             def key(self, env):
547                  return 'TestScannerkey'
548             def instance(self, env):
549                  return self
550         env_scanner = TestScanner()
551         builder = SCons.Builder.Builder(name = "builder", action='action')
552         tgt = builder(env, target='foo.x', source='bar')
553         src = tgt.sources[0]
554         assert tgt.target_scanner != env_scanner, tgt.target_scanner
555         assert src.source_scanner == env_scanner
556
557     def test_Builder_Args(self):
558         """Testing passing extra args to a builder."""
559         def buildFunc(target, source, env, s=self):
560             s.foo=env['foo']
561             s.bar=env['bar']
562             assert env['CC'] == 'mycc'
563
564         env=Environment(CC='cc')
565
566         builder = SCons.Builder.Builder(name="builder", action=buildFunc)
567         tgt = builder(env, target='foo', source='bar', foo=1, bar=2, CC='mycc')
568         tgt.build()
569         assert self.foo == 1, self.foo
570         assert self.bar == 2, self.bar
571
572     def test_emitter(self):
573         """Test emitter functions."""
574         def emit(target, source, env):
575             foo = env.get('foo', 0)
576             bar = env.get('bar', 0)
577             if foo:
578                 target.append("bar%d"%foo)
579             if bar:
580                 source.append("baz")
581             return ( target, source )
582
583         builder = SCons.Builder.Builder(name="builder", action='foo',
584                                         emitter=emit)
585         tgt = builder(env, target='foo2', source='bar')
586         assert str(tgt) == 'foo2', str(tgt)
587         assert str(tgt.sources[0]) == 'bar', str(tgt.sources[0])
588
589         tgt = builder(env, target='foo3', source='bar', foo=1)
590         assert len(tgt) == 2, len(tgt)
591         assert 'foo3' in map(str, tgt), map(str, tgt)
592         assert 'bar1' in map(str, tgt), map(str, tgt)
593
594         tgt = builder(env, target='foo4', source='bar', bar=1)
595         assert str(tgt) == 'foo4', str(tgt)
596         assert len(tgt.sources) == 2, len(tgt.sources)
597         assert 'baz' in map(str, tgt.sources), map(str, tgt.sources)
598         assert 'bar' in map(str, tgt.sources), map(str, tgt.sources)
599
600         env2=Environment(FOO=emit)
601         builder2=SCons.Builder.Builder(name="builder2", action='foo',
602                                        emitter="$FOO")
603
604         tgt = builder2(env2, target='foo5', source='bar')
605         assert str(tgt) == 'foo5', str(tgt)
606         assert str(tgt.sources[0]) == 'bar', str(tgt.sources[0])
607
608         tgt = builder2(env2, target='foo6', source='bar', foo=2)
609         assert len(tgt) == 2, len(tgt)
610         assert 'foo6' in map(str, tgt), map(str, tgt)
611         assert 'bar2' in map(str, tgt), map(str, tgt)
612
613         tgt = builder2(env2, target='foo7', source='bar', bar=1)
614         assert str(tgt) == 'foo7', str(tgt)
615         assert len(tgt.sources) == 2, len(tgt.sources)
616         assert 'baz' in map(str, tgt.sources), map(str, tgt.sources)
617         assert 'bar' in map(str, tgt.sources), map(str, tgt.sources)
618
619         builder2a=SCons.Builder.Builder(name="builder2", action='foo',
620                                         emitter="$FOO")
621         assert builder2 == builder2a, repr(builder2.__dict__) + "\n" + repr(builder2a.__dict__)
622
623     def test_no_target(self):
624         """Test deducing the target from the source."""
625
626         b = SCons.Builder.Builder(action='foo', suffix='.o')
627
628         tgt = b(env, 'aaa')
629         assert str(tgt) == 'aaa.o', str(tgt)
630         assert len(tgt.sources) == 1, map(str, tgt.sources)
631         assert str(tgt.sources[0]) == 'aaa', map(str, tgt.sources)
632
633         tgt = b(env, 'bbb.c')
634         assert str(tgt) == 'bbb.o', str(tgt)
635         assert len(tgt.sources) == 1, map(str, tgt.sources)
636         assert str(tgt.sources[0]) == 'bbb.c', map(str, tgt.sources)
637
638         tgt = b(env, 'ccc.x.c')
639         assert str(tgt) == 'ccc.x.o', str(tgt)
640         assert len(tgt.sources) == 1, map(str, tgt.sources)
641         assert str(tgt.sources[0]) == 'ccc.x.c', map(str, tgt.sources)
642
643         tgt = b(env, ['d0.c', 'd1.c'])
644         assert len(tgt) == 2, map(str, tgt)
645         assert str(tgt[0]) == 'd0.o', map(str, tgt)
646         assert str(tgt[1]) == 'd1.o', map(str, tgt)
647         assert len(tgt[0].sources) == 2,  map(str, tgt[0].sources)
648         assert str(tgt[0].sources[0]) == 'd0.c', map(str, tgt[0].sources)
649         assert str(tgt[0].sources[1]) == 'd1.c', map(str, tgt[0].sources)
650         assert len(tgt[1].sources) == 2,  map(str, tgt[1].sources)
651         assert str(tgt[1].sources[0]) == 'd0.c', map(str, tgt[1].sources)
652         assert str(tgt[1].sources[1]) == 'd1.c', map(str, tgt[1].sources)
653
654         tgt = b(env, source='eee')
655         assert str(tgt) == 'eee.o', str(tgt)
656         assert len(tgt.sources) == 1, map(str, tgt.sources)
657         assert str(tgt.sources[0]) == 'eee', map(str, tgt.sources)
658
659         tgt = b(env, source='fff.c')
660         assert str(tgt) == 'fff.o', str(tgt)
661         assert len(tgt.sources) == 1, map(str, tgt.sources)
662         assert str(tgt.sources[0]) == 'fff.c', map(str, tgt.sources)
663
664         tgt = b(env, source='ggg.x.c')
665         assert str(tgt) == 'ggg.x.o', str(tgt)
666         assert len(tgt.sources) == 1, map(str, tgt.sources)
667         assert str(tgt.sources[0]) == 'ggg.x.c', map(str, tgt.sources)
668
669         tgt = b(env, source=['h0.c', 'h1.c'])
670         assert len(tgt) == 2, map(str, tgt)
671         assert str(tgt[0]) == 'h0.o', map(str, tgt)
672         assert str(tgt[1]) == 'h1.o', map(str, tgt)
673         assert len(tgt[0].sources) == 2,  map(str, tgt[0].sources)
674         assert str(tgt[0].sources[0]) == 'h0.c', map(str, tgt[0].sources)
675         assert str(tgt[0].sources[1]) == 'h1.c', map(str, tgt[0].sources)
676         assert len(tgt[1].sources) == 2,  map(str, tgt[1].sources)
677         assert str(tgt[1].sources[0]) == 'h0.c', map(str, tgt[1].sources)
678         assert str(tgt[1].sources[1]) == 'h1.c', map(str, tgt[1].sources)
679
680         w = b(env, target='i0.w', source=['i0.x'])
681         y = b(env, target='i1.y', source=['i1.z'])
682         tgt = b(env, source=[w, y])
683         assert len(tgt) == 2, map(str, tgt)
684         assert str(tgt[0]) == 'i0.o'
685         assert str(tgt[1]) == 'i1.o'
686         assert len(tgt[0].sources) == 2, map(str, tgt[0].sources)
687         assert str(tgt[0].sources[0]) == 'i0.w', map(str, tgt[0].sources)
688         assert str(tgt[0].sources[1]) == 'i1.y', map(str, tgt[0].sources)
689         assert len(tgt[1].sources) == 2, map(str, tgt[1].sources)
690         assert str(tgt[1].sources[0]) == 'i0.w', map(str, tgt[1].sources)
691         assert str(tgt[1].sources[1]) == 'i1.y', map(str, tgt[1].sources)
692
693
694 if __name__ == "__main__":
695     suite = unittest.makeSuite(BuilderTestCase, 'test_')
696     if not unittest.TextTestRunner().run(suite).wasSuccessful():
697         sys.exit(1)