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__"
36 sys.stdout = StringIO.StringIO()
38 if sys.platform == 'win32':
39 existing_lib = "msvcrt"
43 class SConfTestCase(unittest.TestCase):
46 # we always want to start with a clean directory
47 self.test = TestCmd.TestCmd(workdir = '')
52 def _resetSConfState(self):
53 # Ok, this is tricky, and i do not know, if everything is sane.
54 # We try to reset scons' state (including all global variables)
56 SCons.SConsign.write() # simulate normal scons-finish
57 for n in sys.modules.keys():
58 if string.split(n, '.')[0] == 'SCons':
60 if type(m) is ModuleType:
61 # if this is really a scons module, clear its namespace
64 # we only use SCons.Environment and SCons.SConf for these tests.
65 import SCons.Environment
67 import SCons.Script.SConscript
68 SCons.Script.SConscript.sconscript_reading = 1
69 self.Environment = SCons.Environment
70 self.SConf = SCons.SConf
71 # and we need a new environment, cause references may point to
72 # old modules (well, at least this is safe ...)
73 self.scons_env = self.Environment.Environment()
74 self.scons_env.AppendENVPath('PATH', os.environ['PATH'])
76 # we want to do some autodetection here
77 # this stuff works with
78 # - cygwin on win32 (using cmd.exe, not bash)
80 # - msvc on win32 (hopefully)
81 if (not self.scons_env.Detect( self.scons_env.subst('$CXX') ) or
82 not self.scons_env.Detect( self.scons_env.subst('$CC') ) or
83 not self.scons_env.Detect( self.scons_env.subst('$LINK') )):
84 raise Exception, "This test needs an installed compiler!"
85 if self.scons_env['CXX'] == 'g++':
89 def _baseTryXXX(self, TryFunc):
90 # TryCompile and TryLink are much the same, so we can test them
91 # in one method, we pass the function as a string ('TryCompile',
92 # 'TryLink'), so we are aware of reloading modules.
94 def checks(self, sconf, TryFuncString):
95 TryFunc = self.SConf.SConf.__dict__[TryFuncString]
96 res1 = TryFunc( sconf, "int main() { return 0; }", ".c" )
97 res2 = TryFunc( sconf,
98 '#include "no_std_header.h"\nint main() {return 0; }',
102 # 1. test initial behaviour (check ok / failed)
103 self._resetSConfState()
104 sconf = self.SConf.SConf(self.scons_env,
105 conf_dir=self.test.workpath('config.tests'),
106 log_file=self.test.workpath('config.log'))
108 res = checks( self, sconf, TryFunc )
109 assert res[0] and not res[1]
113 # 2.1 test the error caching mechanism (no dependencies have changed)
114 self._resetSConfState()
115 sconf = self.SConf.SConf(self.scons_env,
116 conf_dir=self.test.workpath('config.tests'),
117 log_file=self.test.workpath('config.log'))
119 res = checks( self, sconf, TryFunc )
120 assert res[0] and not res[1]
123 # we should have exactly one one error cached
124 log = self.test.read( self.test.workpath('config.log') )
125 expr = re.compile( ".*(\(cached\))", re.DOTALL )
126 firstOcc = expr.match( log )
127 assert firstOcc != None
128 secondOcc = expr.match( log, firstOcc.end(0) )
129 assert secondOcc == None
131 # 2.2 test the error caching mechanism (dependencies have changed)
132 self._resetSConfState()
133 sconf = self.SConf.SConf(self.scons_env,
134 conf_dir=self.test.workpath('config.tests'),
135 log_file=self.test.workpath('config.log'))
136 test_h = self.test.write( self.test.workpath('config.tests', 'no_std_header.h'),
137 "/* we are changing a dependency now */" );
139 res = checks( self, sconf, TryFunc )
140 log = self.test.read( self.test.workpath('config.log') )
141 assert res[0] and res[1]
145 def test_TryBuild(self):
146 """Test SConf.TryBuild
148 # 1 test that we can try a builder that returns a list of nodes
149 self._resetSConfState()
150 sconf = self.SConf.SConf(self.scons_env,
151 conf_dir=self.test.workpath('config.tests'),
152 log_file=self.test.workpath('config.log'))
157 def __call__(self, env, target, source):
159 def __init__(self, name):
162 self.side_effects = []
164 def has_builder(self):
166 def add_pre_action(self, *actions):
168 def add_post_action(self, *actions):
174 def set_state(self, state):
176 def alter_targets(self):
178 def depends_on(self, nodes):
180 def postprocess(self):
184 def current(self, calc=None):
188 def retrieve_from_cache(self):
190 def build(self, **kw):
194 return [MyNode('n1'), MyNode('n2')]
196 self.scons_env.Append(BUILDERS = {'SConfActionBuilder' : MyBuilder()})
197 sconf.TryBuild(self.scons_env.SConfActionBuilder)
201 def test_TryCompile(self):
202 """Test SConf.TryCompile
204 self._baseTryXXX( "TryCompile" ) #self.SConf.SConf.TryCompile )
206 def test_TryLink(self):
207 """Test SConf.TryLink
209 self._baseTryXXX( "TryLink" ) #self.SConf.SConf.TryLink )
211 def test_TryRun(self):
222 res1 = sconf.TryRun( prog, ".c" )
223 res2 = sconf.TryRun( "not a c program", ".c" )
226 self._resetSConfState()
227 sconf = self.SConf.SConf(self.scons_env,
228 conf_dir=self.test.workpath('config.tests'),
229 log_file=self.test.workpath('config.log'))
232 assert res[0][0] and res[0][1] == "Hello"
233 assert not res[1][0] and res[1][1] == ""
237 # test the caching mechanism
238 self._resetSConfState()
239 sconf = self.SConf.SConf(self.scons_env,
240 conf_dir=self.test.workpath('config.tests'),
241 log_file=self.test.workpath('config.log'))
244 assert res[0][0] and res[0][1] == "Hello"
245 assert not res[1][0] and res[1][1] == ""
248 # we should have exactly one one error cached
249 log = self.test.read( self.test.workpath('config.log') )
250 expr = re.compile( ".*(\(cached\))", re.DOTALL )
251 firstOcc = expr.match( log )
252 assert firstOcc != None
253 secondOcc = expr.match( log, firstOcc.end(0) )
254 assert secondOcc == None
257 def test_TryAction(self):
258 """Test SConf.TryAction
260 def actionOK(target, source, env):
261 open(str(target[0]), "w").write( "RUN OK" )
263 def actionFAIL(target, source, env):
265 self._resetSConfState()
266 sconf = self.SConf.SConf(self.scons_env,
267 conf_dir=self.test.workpath('config.tests'),
268 log_file=self.test.workpath('config.log'))
270 (ret, output) = sconf.TryAction(action=actionOK)
271 assert ret and output == "RUN OK"
272 (ret, output) = sconf.TryAction(action=actionFAIL)
273 assert not ret and output == ""
278 def test_CheckHeader(self):
279 """Test SConf.CheckHeader()
281 self._resetSConfState()
282 sconf = self.SConf.SConf(self.scons_env,
283 conf_dir=self.test.workpath('config.tests'),
284 log_file=self.test.workpath('config.log'))
287 r = sconf.CheckHeader( "stdio.h", include_quotes="<>", language="C" )
288 assert r, "did not find stdio.h"
289 r = sconf.CheckHeader( "HopefullyNoHeader.noh", language="C" )
290 assert not r, "unexpectedly found HopefullyNoHeader.noh"
291 r = sconf.CheckHeader( "vector", include_quotes="<>", language="C++" )
292 assert r, "did not find vector"
293 r = sconf.CheckHeader( "HopefullyNoHeader.noh", language="C++" )
294 assert not r, "unexpectedly found HopefullyNoHeader.noh"
299 def test_CheckCHeader(self):
300 """Test SConf.CheckCHeader()
302 self._resetSConfState()
303 sconf = self.SConf.SConf(self.scons_env,
304 conf_dir=self.test.workpath('config.tests'),
305 log_file=self.test.workpath('config.log'))
309 r = sconf.CheckCHeader( "stdio.h", include_quotes="<>" )
310 assert r, "did not find stdio.h"
311 r = sconf.CheckCHeader( ["math.h", "stdio.h"], include_quotes="<>" )
312 assert r, "did not find stdio.h, #include math.h first"
313 r = sconf.CheckCHeader( "HopefullyNoCHeader.noh" )
314 assert not r, "unexpectedly found HopefullyNoCHeader.noh"
319 def test_CheckCXXHeader(self):
320 """Test SConf.CheckCXXHeader()
322 self._resetSConfState()
323 sconf = self.SConf.SConf(self.scons_env,
324 conf_dir=self.test.workpath('config.tests'),
325 log_file=self.test.workpath('config.log'))
329 r = sconf.CheckCXXHeader( "vector", include_quotes="<>" )
330 assert r, "did not find vector"
331 r = sconf.CheckCXXHeader( ["stdio.h", "vector"], include_quotes="<>" )
332 assert r, "did not find vector, #include stdio.h first"
333 r = sconf.CheckCXXHeader( "HopefullyNoCXXHeader.noh" )
334 assert not r, "unexpectedly found HopefullyNoCXXHeader.noh"
339 def test_CheckLib(self):
340 """Test SConf.CheckLib()
342 self._resetSConfState()
343 sconf = self.SConf.SConf(self.scons_env,
344 conf_dir=self.test.workpath('config.tests'),
345 log_file=self.test.workpath('config.log'))
349 r = sconf.CheckLib( existing_lib, "main", autoadd=0 )
350 assert r, "did not find %s" % existing_lib
351 r = sconf.CheckLib( "hopefullynolib", "main", autoadd=0 )
352 assert not r, "unexpectedly found hopefullynolib"
354 # CheckLib() with list of libs
355 r = sconf.CheckLib( [existing_lib], "main", autoadd=0 )
356 assert r, "did not find %s" % existing_lib
357 r = sconf.CheckLib( ["hopefullynolib"], "main", autoadd=0 )
358 assert not r, "unexpectedly found hopefullynolib"
359 # This is a check that a null list doesn't find functions
360 # that are in libraries that must be explicitly named.
361 # This works on POSIX systems where you have to -lm to
362 # get the math functions, but it fails on Visual Studio
363 # where you apparently get all those functions for free.
364 # Comment out this check until someone who understands
365 # Visual Studio better can come up with a corresponding
366 # test (if that ever really becomes necessary).
367 #r = sconf.CheckLib( [], "sin", autoadd=0 )
368 #assert not r, "unexpectedly found nonexistent library"
369 r = sconf.CheckLib( [existing_lib,"hopefullynolib"], "main", autoadd=0 )
370 assert r, "did not find %s,%s " % (existing_lib,r)
371 r = sconf.CheckLib( ["hopefullynolib",existing_lib], "main", autoadd=0 )
372 assert r, "did not find %s " % existing_lib
374 # CheckLib() with autoadd
376 return env.get('LIBS', [])
378 env = sconf.env.Copy()
381 r = sconf.CheckLib( existing_lib, "main", autoadd=1 )
382 assert r, "did not find main in %s" % existing_lib
383 expect = libs(env) + [existing_lib]
384 got = libs(sconf.env)
385 assert got == expect, "LIBS: expected %s, got %s" % (expect, got)
387 sconf.env = env.Copy()
388 r = sconf.CheckLib( existing_lib, "main", autoadd=0 )
389 assert r, "did not find main in %s" % existing_lib
391 got = libs(sconf.env)
392 assert got == expect, "before and after LIBS were not the same"
399 def test_CheckLibWithHeader(self):
400 """Test SConf.CheckLibWithHeader()
402 self._resetSConfState()
403 sconf = self.SConf.SConf(self.scons_env,
404 conf_dir=self.test.workpath('config.tests'),
405 log_file=self.test.workpath('config.log'))
408 # CheckLibWithHeader()
409 r = sconf.CheckLibWithHeader( existing_lib, "math.h", "C", autoadd=0 )
410 assert r, "did not find %s" % existing_lib
411 r = sconf.CheckLibWithHeader( existing_lib, ["stdio.h", "math.h"], "C", autoadd=0 )
412 assert r, "did not find %s, #include stdio.h first" % existing_lib
413 r = sconf.CheckLibWithHeader( "hopefullynolib", "math.h", "C", autoadd=0 )
414 assert not r, "unexpectedly found hopefullynolib"
416 # CheckLibWithHeader() with lists of libs
417 r = sconf.CheckLibWithHeader( [existing_lib], "math.h", "C", autoadd=0 )
418 assert r, "did not find %s" % existing_lib
419 r = sconf.CheckLibWithHeader( [existing_lib], ["stdio.h", "math.h"], "C", autoadd=0 )
420 assert r, "did not find %s, #include stdio.h first" % existing_lib
421 # This is a check that a null list doesn't find functions
422 # that are in libraries that must be explicitly named.
423 # This works on POSIX systems where you have to -lm to
424 # get the math functions, but it fails on Visual Studio
425 # where you apparently get all those functions for free.
426 # Comment out this check until someone who understands
427 # Visual Studio better can come up with a corresponding
428 # test (if that ever really becomes necessary).
429 #r = sconf.CheckLibWithHeader( [], "math.h", "C", call="sin(3);", autoadd=0 )
430 #assert not r, "unexpectedly found non-existent library"
431 r = sconf.CheckLibWithHeader( ["hopefullynolib"], "math.h", "C", autoadd=0 )
432 assert not r, "unexpectedly found hopefullynolib"
433 r = sconf.CheckLibWithHeader( ["hopefullynolib",existing_lib], ["stdio.h", "math.h"], "C", autoadd=0 )
434 assert r, "did not find %s, #include stdio.h first" % existing_lib
435 r = sconf.CheckLibWithHeader( [existing_lib,"hopefullynolib"], ["stdio.h", "math.h"], "C", autoadd=0 )
436 assert r, "did not find %s, #include stdio.h first" % existing_lib
438 # CheckLibWithHeader with autoadd
440 return env.get('LIBS', [])
442 env = sconf.env.Copy()
445 r = sconf.CheckLibWithHeader( existing_lib, "math.h", "C", autoadd=1 )
446 assert r, "did not find math.h with %s" % existing_lib
447 expect = libs(env) + [existing_lib]
448 got = libs(sconf.env)
449 assert got == expect, "LIBS: expected %s, got %s" % (expect, got)
451 sconf.env = env.Copy()
452 r = sconf.CheckLibWithHeader( existing_lib, "math.h", "C", autoadd=0 )
453 assert r, "did not find math.h with %s" % existing_lib
455 got = libs(sconf.env)
456 assert got == expect, "before and after LIBS were not the same"
463 def test_CheckFunc(self):
464 """Test SConf.CheckFunc()
466 self._resetSConfState()
467 sconf = self.SConf.SConf(self.scons_env,
468 conf_dir=self.test.workpath('config.tests'),
469 log_file=self.test.workpath('config.log'))
473 r = sconf.CheckFunc('strcpy')
474 assert r, "did not find strcpy"
475 r = sconf.CheckFunc('hopefullynofunction')
476 assert not r, "unexpectedly found hopefullynofunction"
482 """Test SConf.CheckType()
484 self._resetSConfState()
485 sconf = self.SConf.SConf(self.scons_env,
486 conf_dir=self.test.workpath('config.tests'),
487 log_file=self.test.workpath('config.log'))
490 r = sconf.CheckType('off_t', '#include <sys/types.h>\n')
491 assert r, "did not find off_t"
492 r = sconf.CheckType('hopefullynotypedef_not')
493 assert not r, "unexpectedly found hopefullynotypedef_not"
498 def test_CustomChecks(self):
499 """Test Custom Checks
501 def CheckCustom(test):
502 test.Message( "Checking UserTest ... " )
511 (ret, output) = test.TryRun( prog, ".c" )
513 assert ret and output == "Hello"
517 self._resetSConfState()
518 sconf = self.SConf.SConf(self.scons_env,
519 custom_tests={'CheckCustom': CheckCustom},
520 conf_dir=self.test.workpath('config.tests'),
521 log_file=self.test.workpath('config.log'))
523 ret = sconf.CheckCustom()
529 if __name__ == "__main__":
530 suite = unittest.makeSuite(SConfTestCase, 'test_')
531 res = unittest.TextTestRunner().run(suite)
532 if not res.wasSuccessful():