Merge pull request #4655 from bdbaddog/fix_new_ninja_package
[scons.git] / SCons / SConfTests.py
blob520b02ff09d0306358ebbb12b8adf1f1a48c1972
1 # MIT License
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.
24 import io
25 import os
26 import re
27 import sys
28 from types import ModuleType
29 import unittest
31 import TestCmd
33 sys.stdout = io.StringIO()
35 # a library that is sure to exist on the platform
36 if sys.platform == 'win32':
37 existing_lib = "msvcrt"
38 else:
39 existing_lib = "m"
41 class SConfTestCase(unittest.TestCase):
43 def setUp(self) -> None:
44 # we always want to start with a clean directory
45 self.save_cwd = os.getcwd()
46 self.test = TestCmd.TestCmd(workdir = '')
47 os.chdir(self.test.workpath(''))
49 def tearDown(self) -> None:
50 self.test.cleanup()
51 import SCons.SConsign
52 SCons.SConsign.Reset()
53 os.chdir(self.save_cwd)
55 def _resetSConfState(self):
56 # Ok, this is tricky, and i do not know, if everything is sane.
57 # We try to reset scons' state (including all global variables)
58 import SCons.SConsign
59 SCons.SConsign.write() # simulate normal scons-finish
60 for n in list(sys.modules.keys()):
61 if n.split('.')[0] == 'SCons' and n[:12] != 'SCons.compat':
62 m = sys.modules[n]
63 if isinstance(m, ModuleType):
64 # if this is really a scons module, clear its namespace
65 del sys.modules[n]
66 m.__dict__.clear()
67 # we only use SCons.Environment and SCons.SConf for these tests.
68 import SCons.Environment
69 import SCons.SConf
70 self.Environment = SCons.Environment
71 self.SConf = SCons.SConf
72 # and we need a new environment, cause references may point to
73 # old modules (well, at least this is safe ...)
74 self.scons_env = self.Environment.Environment()
75 self.scons_env.AppendENVPath('PATH', os.environ['PATH'])
77 # we want to do some autodetection here
78 # this stuff works with
79 # - cygwin on Windows (using cmd.exe, not bash)
80 # - posix
81 # - msvc on Windows (hopefully)
82 if not all(
84 self.scons_env.Detect(self.scons_env.subst('$CXX')),
85 self.scons_env.Detect(self.scons_env.subst('$CC')),
86 self.scons_env.Detect(self.scons_env.subst('$LINK')),
89 raise Exception("This test needs an installed compiler!")
90 if self.scons_env['CXX'] == 'g++':
91 global existing_lib
92 existing_lib = 'm'
94 def _baseTryXXX(self, TryFunc) -> None:
95 # TryCompile and TryLink are much the same, so we can test them
96 # in one method, we pass the function as a string ('TryCompile',
97 # 'TryLink'), so we are aware of reloading modules.
99 def checks(self, sconf, TryFuncString):
100 TryFunc = self.SConf.SConfBase.__dict__[TryFuncString]
101 res1 = TryFunc( sconf, "int main(void) { return 0; }\n", ".c" )
102 res2 = TryFunc( sconf,
103 '#include "no_std_header.h"\nint main(void) {return 0; }\n',
104 '.c' )
105 return (res1,res2)
107 # 1. test initial behaviour (check ok / failed)
108 self._resetSConfState()
109 sconf = self.SConf.SConf(self.scons_env,
110 conf_dir=self.test.workpath('config.tests'),
111 log_file=self.test.workpath('config.log'))
112 try:
113 res = checks( self, sconf, TryFunc )
114 assert res[0] and not res[1], res
115 finally:
116 sconf.Finish()
118 # 2.1 test the error caching mechanism (no dependencies have changed)
119 self._resetSConfState()
120 sconf = self.SConf.SConf(self.scons_env,
121 conf_dir=self.test.workpath('config.tests'),
122 log_file=self.test.workpath('config.log'))
123 try:
124 res = checks( self, sconf, TryFunc )
125 assert res[0] and not res[1], res
126 finally:
127 sconf.Finish()
128 # we should have exactly one one error cached
129 log = str(self.test.read( self.test.workpath('config.log') ))
130 expr = re.compile( ".*failed in a previous run and all", re.DOTALL )
131 firstOcc = expr.match( log )
132 assert firstOcc is not None, log
133 secondOcc = expr.match( log, firstOcc.end(0) )
134 assert secondOcc is None, log
136 # 2.2 test the error caching mechanism (dependencies have changed)
137 self._resetSConfState()
138 sconf = self.SConf.SConf(self.scons_env,
139 conf_dir=self.test.workpath('config.tests'),
140 log_file=self.test.workpath('config.log'))
141 no_std_header_h = self.test.workpath('config.tests', 'no_std_header.h')
142 test_h = self.test.write( no_std_header_h,
143 "/* we are changing a dependency now */\n" )
144 try:
145 res = checks( self, sconf, TryFunc )
146 log = self.test.read( self.test.workpath('config.log') )
147 assert res[0] and res[1], res
148 finally:
149 sconf.Finish()
151 def test_TryBuild(self) -> None:
152 """Test SConf.TryBuild
154 # 1 test that we can try a builder that returns a list of nodes
155 self._resetSConfState()
156 sconf = self.SConf.SConf(self.scons_env,
157 conf_dir=self.test.workpath('config.tests'),
158 log_file=self.test.workpath('config.log'))
159 import SCons.Builder
160 import SCons.Node
162 class MyAction:
163 def get_contents(self, target, source, env) -> str:
164 return 'MyBuilder-MyAction $SOURCE $TARGET'
166 class Attrs:
167 __slots__ = ('shared', '__dict__')
169 class MyBuilder(SCons.Builder.BuilderBase):
170 def __init__(self) -> None:
171 self.prefix = ''
172 self.suffix = ''
173 # need action because temporary file name uses hash of actions get_contents()
174 self.action = MyAction()
176 def __call__(self, env, target, source, *args, **kw):
177 class MyNode:
178 def __init__(self, name) -> None:
179 self.name = name
180 self.state = SCons.Node.no_state
181 self.waiting_parents = set()
182 self.side_effects = []
183 self.builder = None
184 self.prerequisites = None
185 self.attributes = Attrs()
186 def disambiguate(self):
187 return self
188 def has_builder(self) -> bool:
189 return True
190 def add_pre_action(self, *actions) -> None:
191 pass
192 def add_post_action(self, *actions) -> None:
193 pass
194 def children(self, scan: int = 1):
195 return []
196 def get_state(self):
197 return self.state
198 def set_state(self, state) -> None:
199 self.state = state
200 def alter_targets(self):
201 return [], None
202 def postprocess(self) -> None:
203 pass
204 def clear(self) -> None:
205 pass
206 def is_up_to_date(self) -> bool:
207 return False
208 def prepare(self) -> None:
209 pass
210 def push_to_cache(self) -> bool:
211 pass
212 def retrieve_from_cache(self) -> bool:
213 return False
214 def build(self, **kw) -> None:
215 return
216 def built(self) -> None:
217 pass
218 def get_stored_info(self) -> None:
219 pass
220 def is_conftest(self) -> bool:
221 return True
222 def get_executor(self):
223 class Executor:
224 def __init__(self, targets) -> None:
225 self.targets = targets
226 def get_all_targets(self):
227 return self.targets
228 return Executor([self])
229 return [MyNode('n1'), MyNode('n2')]
230 try:
231 self.scons_env.Append(BUILDERS = {'SConfActionBuilder' : MyBuilder()})
232 sconf.TryBuild(self.scons_env.SConfActionBuilder)
233 finally:
234 sconf.Finish()
236 def test_TryCompile(self) -> None:
237 """Test SConf.TryCompile
239 self._baseTryXXX( "TryCompile" ) #self.SConf.SConf.TryCompile )
241 def test_TryLink(self) -> None:
242 """Test SConf.TryLink
244 self._baseTryXXX( "TryLink" ) #self.SConf.SConf.TryLink )
246 def test_TryRun(self) -> None:
247 """Test SConf.TryRun
249 def checks(sconf):
250 prog = """
251 #include <stdio.h>
252 int main(void) {
253 printf( "Hello" );
254 return 0;
257 res1 = sconf.TryRun( prog, ".c" )
258 res2 = sconf.TryRun( "not a c program\n", ".c" )
259 return (res1, res2)
261 self._resetSConfState()
262 sconf = self.SConf.SConf(self.scons_env,
263 conf_dir=self.test.workpath('config.tests'),
264 log_file=self.test.workpath('config.log'))
265 try:
266 res = checks(sconf)
267 assert res[0][0] and res[0][1] == "Hello", res
268 assert not res[1][0] and res[1][1] == "", res
269 finally:
270 sconf.Finish()
271 log = self.test.read( self.test.workpath('config.log') )
273 # test the caching mechanism
274 self._resetSConfState()
275 sconf = self.SConf.SConf(self.scons_env,
276 conf_dir=self.test.workpath('config.tests'),
277 log_file=self.test.workpath('config.log'))
278 try:
279 res = checks(sconf)
280 assert res[0][0] and res[0][1] == "Hello", res
281 assert not res[1][0] and res[1][1] == "", res
282 finally:
283 sconf.Finish()
284 # we should have exactly one error cached
285 # creating string here because it's bytes by default on py3
286 log = str(self.test.read( self.test.workpath('config.log') ))
287 expr = re.compile( ".*failed in a previous run and all", re.DOTALL )
288 firstOcc = expr.match( log )
289 assert firstOcc is not None, log
290 secondOcc = expr.match( log, firstOcc.end(0) )
291 assert secondOcc is None, log
294 def test_TryAction(self) -> None:
295 """Test SConf.TryAction
297 def actionOK(target, source, env):
298 with open(str(target[0]), "w") as f:
299 f.write("RUN OK\n")
300 return None
301 def actionFAIL(target, source, env) -> int:
302 return 1
305 self._resetSConfState()
306 sconf = self.SConf.SConf(self.scons_env,
307 conf_dir=self.test.workpath('config.tests'),
308 log_file=self.test.workpath('config.log'))
309 try:
310 (ret, output) = sconf.TryAction(action=actionOK)
311 assert ret and output.encode('utf-8') == bytearray("RUN OK"+os.linesep, 'utf-8'), (ret, output)
312 (ret, output) = sconf.TryAction(action=actionFAIL)
313 assert not ret and output == "", (ret, output)
316 finally:
317 sconf.Finish()
319 def _test_check_compilers(self, comp, func, name) -> None:
320 """This is the implementation for CheckCC and CheckCXX tests."""
321 from copy import deepcopy
323 # Check that Check* works
324 r = func()
325 assert r, "could not find %s ?" % comp
327 # Check that Check* does fail if comp is not available in env
328 oldcomp = deepcopy(self.scons_env[comp])
329 del self.scons_env[comp]
330 r = func()
331 assert not r, "%s worked wo comp ?" % name
333 # Check that Check* does fail if comp is set but empty
334 self.scons_env[comp] = ''
335 r = func()
336 assert not r, "%s worked with comp = '' ?" % name
338 # Check that Check* does fail if comp is set to buggy executable
339 self.scons_env[comp] = 'thiscccompilerdoesnotexist'
340 r = func()
341 assert not r, "%s worked with comp = thiscompilerdoesnotexist ?" % name
343 # Check that Check* does fail if CFLAGS is buggy
344 self.scons_env[comp] = oldcomp
345 self.scons_env['%sFLAGS' % comp] = '/WX qwertyuiop.c'
346 r = func()
347 assert not r, "%s worked with %sFLAGS = qwertyuiop ?" % (name, comp)
349 def test_CheckCC(self):
350 """Test SConf.CheckCC()
352 self._resetSConfState()
353 sconf = self.SConf.SConf(self.scons_env,
354 conf_dir=self.test.workpath('config.tests'),
355 log_file=self.test.workpath('config.log'))
356 try:
357 try:
358 self._test_check_compilers('CC', sconf.CheckCC, 'CheckCC')
359 except AssertionError:
360 sys.stderr.write(self.test.read('config.log', mode='r'))
361 raise
362 finally:
363 sconf.Finish()
365 def test_CheckSHCC(self):
366 """Test SConf.CheckSHCC()
368 self._resetSConfState()
369 sconf = self.SConf.SConf(self.scons_env,
370 conf_dir=self.test.workpath('config.tests'),
371 log_file=self.test.workpath('config.log'))
372 try:
373 try:
374 self._test_check_compilers('SHCC', sconf.CheckSHCC, 'CheckSHCC')
375 except AssertionError:
376 sys.stderr.write(self.test.read('config.log', mode='r'))
377 raise
378 finally:
379 sconf.Finish()
381 def test_CheckCXX(self):
382 """Test SConf.CheckCXX()
384 self._resetSConfState()
385 sconf = self.SConf.SConf(self.scons_env,
386 conf_dir=self.test.workpath('config.tests'),
387 log_file=self.test.workpath('config.log'))
388 try:
389 try:
390 self._test_check_compilers('CXX', sconf.CheckCXX, 'CheckCXX')
391 except AssertionError:
392 sys.stderr.write(self.test.read('config.log', mode='r'))
393 raise
394 finally:
395 sconf.Finish()
397 def test_CheckSHCXX(self):
398 """Test SConf.CheckSHCXX()
400 self._resetSConfState()
401 sconf = self.SConf.SConf(self.scons_env,
402 conf_dir=self.test.workpath('config.tests'),
403 log_file=self.test.workpath('config.log'))
404 try:
405 try:
406 self._test_check_compilers('SHCXX', sconf.CheckSHCXX, 'CheckSHCXX')
407 except AssertionError:
408 sys.stderr.write(self.test.read('config.log', mode='r'))
409 raise
410 finally:
411 sconf.Finish()
414 def test_CheckHeader(self) -> None:
415 """Test SConf.CheckHeader()
417 self._resetSConfState()
418 sconf = self.SConf.SConf(self.scons_env,
419 conf_dir=self.test.workpath('config.tests'),
420 log_file=self.test.workpath('config.log'))
421 try:
422 # CheckHeader()
423 r = sconf.CheckHeader( "stdio.h", include_quotes="<>", language="C" )
424 assert r, "did not find stdio.h"
425 r = sconf.CheckHeader( "HopefullyNoHeader.noh", language="C" )
426 assert not r, "unexpectedly found HopefullyNoHeader.noh"
427 r = sconf.CheckHeader( "vector", include_quotes="<>", language="C++" )
428 assert r, "did not find vector"
429 r = sconf.CheckHeader( "HopefullyNoHeader.noh", language="C++" )
430 assert not r, "unexpectedly found HopefullyNoHeader.noh"
432 finally:
433 sconf.Finish()
435 def test_CheckCHeader(self) -> None:
436 """Test SConf.CheckCHeader()
438 self._resetSConfState()
439 sconf = self.SConf.SConf(self.scons_env,
440 conf_dir=self.test.workpath('config.tests'),
441 log_file=self.test.workpath('config.log'))
443 try:
444 # CheckCHeader()
445 r = sconf.CheckCHeader( "stdio.h", include_quotes="<>" )
446 assert r, "did not find stdio.h"
447 r = sconf.CheckCHeader( ["math.h", "stdio.h"], include_quotes="<>" )
448 assert r, "did not find stdio.h, #include math.h first"
449 r = sconf.CheckCHeader( "HopefullyNoCHeader.noh" )
450 assert not r, "unexpectedly found HopefullyNoCHeader.noh"
452 finally:
453 sconf.Finish()
455 def test_CheckCXXHeader(self) -> None:
456 """Test SConf.CheckCXXHeader()
458 self._resetSConfState()
459 sconf = self.SConf.SConf(self.scons_env,
460 conf_dir=self.test.workpath('config.tests'),
461 log_file=self.test.workpath('config.log'))
463 try:
464 # CheckCXXHeader()
465 r = sconf.CheckCXXHeader( "vector", include_quotes="<>" )
466 assert r, "did not find vector"
467 r = sconf.CheckCXXHeader( ["stdio.h", "vector"], include_quotes="<>" )
468 assert r, "did not find vector, #include stdio.h first"
469 r = sconf.CheckCXXHeader( "HopefullyNoCXXHeader.noh" )
470 assert not r, "unexpectedly found HopefullyNoCXXHeader.noh"
472 finally:
473 sconf.Finish()
475 def test_CheckLib(self) -> None:
476 """Test SConf.CheckLib()
478 self._resetSConfState()
479 sconf = self.SConf.SConf(self.scons_env,
480 conf_dir=self.test.workpath('config.tests'),
481 log_file=self.test.workpath('config.log'))
483 try:
484 # CheckLib()
485 r = sconf.CheckLib( existing_lib, "main", autoadd=0 )
486 assert r, "did not find %s" % existing_lib
487 r = sconf.CheckLib( "hopefullynolib", "main", autoadd=0 )
488 assert not r, "unexpectedly found hopefullynolib"
490 # CheckLib() with list of libs
491 r = sconf.CheckLib( [existing_lib], "main", autoadd=0 )
492 assert r, "did not find %s" % existing_lib
493 r = sconf.CheckLib( ["hopefullynolib"], "main", autoadd=0 )
494 assert not r, "unexpectedly found hopefullynolib"
495 # This is a check that a null list doesn't find functions
496 # that are in libraries that must be explicitly named.
497 # This works on POSIX systems where you have to -lm to
498 # get the math functions, but it fails on Visual Studio
499 # where you apparently get all those functions for free.
500 # Comment out this check until someone who understands
501 # Visual Studio better can come up with a corresponding
502 # test (if that ever really becomes necessary).
503 #r = sconf.CheckLib( [], "sin", autoadd=0 )
504 #assert not r, "unexpectedly found nonexistent library"
505 r = sconf.CheckLib( [existing_lib,"hopefullynolib"], "main", autoadd=0 )
506 assert r, "did not find %s,%s " % (existing_lib,r)
507 r = sconf.CheckLib( ["hopefullynolib",existing_lib], "main", autoadd=0 )
508 assert r, "did not find %s " % existing_lib
510 def libs(env):
511 return env.get('LIBS', [])
513 # CheckLib() with combinations of autoadd, append
514 try:
515 env = sconf.env.Clone()
516 r = sconf.CheckLib(existing_lib, "main", autoadd=True, append=True)
517 assert r, "did not find main in %s" % existing_lib
518 expect = libs(env) + [existing_lib]
519 got = libs(sconf.env)
520 assert got == expect, "LIBS: expected %s, got %s" % (expect, got)
522 env = sconf.env.Clone()
523 r = sconf.CheckLib(existing_lib, "main", autoadd=True, append=False)
524 assert r, "did not find main in %s" % existing_lib
525 expect = [existing_lib] + libs(env)
526 got = libs(sconf.env)
527 assert got == expect, "LIBS: expected %s, got %s" % (expect, got)
529 sconf.env = env.Clone()
530 r = sconf.CheckLib(existing_lib, "main", autoadd=False)
531 assert r, "did not find main in %s" % existing_lib
532 expect = libs(env)
533 got = libs(sconf.env)
534 assert got == expect, "before and after LIBS were not the same"
535 finally:
536 sconf.env = env
538 # CheckLib() with unique
539 sconf.env.Append(LIBS=existing_lib)
540 try:
541 env = sconf.env.Clone()
542 r = sconf.CheckLib(
543 existing_lib, "main", autoadd=True, append=True, unique=False
545 assert r, f"did not find main in {existing_lib}"
547 expect = libs(env) + [existing_lib]
548 got = libs(sconf.env)
549 assert got == expect, f"LIBS: expected {expect}, got {got}"
551 env = sconf.env.Clone()
552 r = sconf.CheckLib(
553 existing_lib, "main", autoadd=True, append=True, unique=True
555 assert r, f"did not find main in {existing_lib}"
557 expect = libs(env)
558 got = libs(sconf.env)
559 assert got == expect, f"LIBS: expected {expect}, got {got}"
560 finally:
561 sconf.env = env
563 finally:
564 sconf.Finish()
566 def test_CheckLibWithHeader(self) -> None:
567 """Test SConf.CheckLibWithHeader()
569 self._resetSConfState()
570 sconf = self.SConf.SConf(self.scons_env,
571 conf_dir=self.test.workpath('config.tests'),
572 log_file=self.test.workpath('config.log'))
574 try:
575 # CheckLibWithHeader()
576 r = sconf.CheckLibWithHeader( existing_lib, "math.h", "C", autoadd=0 )
577 assert r, "did not find %s" % existing_lib
578 r = sconf.CheckLibWithHeader( existing_lib, ["stdio.h", "math.h"], "C", autoadd=0 )
579 assert r, "did not find %s, #include stdio.h first" % existing_lib
580 r = sconf.CheckLibWithHeader( "hopefullynolib", "math.h", "C", autoadd=0 )
581 assert not r, "unexpectedly found hopefullynolib"
583 # CheckLibWithHeader() with lists of libs
584 r = sconf.CheckLibWithHeader( [existing_lib], "math.h", "C", autoadd=0 )
585 assert r, "did not find %s" % existing_lib
586 r = sconf.CheckLibWithHeader( [existing_lib], ["stdio.h", "math.h"], "C", autoadd=0 )
587 assert r, "did not find %s, #include stdio.h first" % existing_lib
588 # This is a check that a null list doesn't find functions
589 # that are in libraries that must be explicitly named.
590 # This works on POSIX systems where you have to -lm to
591 # get the math functions, but it fails on Visual Studio
592 # where you apparently get all those functions for free.
593 # Comment out this check until someone who understands
594 # Visual Studio better can come up with a corresponding
595 # test (if that ever really becomes necessary).
596 #r = sconf.CheckLibWithHeader( [], "math.h", "C", call="sin(3);", autoadd=0 )
597 #assert not r, "unexpectedly found non-existent library"
598 r = sconf.CheckLibWithHeader( ["hopefullynolib"], "math.h", "C", autoadd=0 )
599 assert not r, "unexpectedly found hopefullynolib"
600 r = sconf.CheckLibWithHeader( ["hopefullynolib",existing_lib], ["stdio.h", "math.h"], "C", autoadd=0 )
601 assert r, "did not find %s, #include stdio.h first" % existing_lib
602 r = sconf.CheckLibWithHeader( [existing_lib,"hopefullynolib"], ["stdio.h", "math.h"], "C", autoadd=0 )
603 assert r, "did not find %s, #include stdio.h first" % existing_lib
605 def libs(env):
606 return env.get('LIBS', [])
608 # CheckLibWithHeader with combinations of autoadd, append
609 try:
610 env = sconf.env.Clone()
611 r = sconf.CheckLibWithHeader(
612 existing_lib, "math.h", "C", autoadd=True, append=True
614 assert r, "did not find math.h with %s" % existing_lib
615 expect = libs(env) + [existing_lib]
616 got = libs(sconf.env)
617 assert got == expect, "LIBS: expected %s, got %s" % (expect, got)
619 sconf.env = env.Clone()
620 r = sconf.CheckLibWithHeader(
621 existing_lib, "math.h", "C", autoadd=True, append=False
623 assert r, "did not find math.h with %s" % existing_lib
624 expect = [existing_lib] + libs(env)
625 got = libs(sconf.env)
626 assert got == expect, "LIBS: expected %s, got %s" % (expect, got)
628 sconf.env = env.Clone()
629 r = sconf.CheckLibWithHeader(
630 existing_lib, "math.h", "C", autoadd=False
632 assert r, "did not find math.h with %s" % existing_lib
633 expect = libs(env)
634 got = libs(sconf.env)
635 assert got == expect, "before and after LIBS were not the same"
636 finally:
637 sconf.env = env
639 # CheckLibWithHeader() with unique
640 sconf.env.Append(LIBS=existing_lib)
641 try:
642 env = sconf.env.Clone()
643 r = sconf.CheckLibWithHeader(
644 existing_lib, "math.h", "C", autoadd=True, append=True, unique=False
646 assert r, f"did not find main in {existing_lib}"
647 expect = libs(env) + [existing_lib]
648 got = libs(sconf.env)
649 assert got == expect, f"LIBS: expected {expect}, got {got}"
651 env = sconf.env.Clone()
652 r = sconf.CheckLibWithHeader(
653 existing_lib, "math.h", "C", autoadd=True, append=True, unique=True
655 assert r, f"did not find main in {existing_lib}"
656 expect = libs(env)
657 got = libs(sconf.env)
658 assert got == expect, f"LIBS: expected {expect}, got {got}"
659 finally:
660 sconf.env = env
662 finally:
663 sconf.Finish()
665 def test_CheckFunc(self) -> None:
666 """Test SConf.CheckFunc()
668 self._resetSConfState()
669 sconf = self.SConf.SConf(self.scons_env,
670 conf_dir=self.test.workpath('config.tests'),
671 log_file=self.test.workpath('config.log'))
673 try:
674 # look for function using default heading
675 r = sconf.CheckFunc('strcpy')
676 assert r, "did not find strcpy"
677 # no default heading, supply dummy signature
678 r = sconf.CheckFunc('strcpy', '/* header */ char strcpy();')
679 assert r, "did not find strcpy"
680 # ... supply complete signature, and function args
681 r = sconf.CheckFunc('strcpy', header='/* header */ char *strcpy(char *dest, char *src);', funcargs='"", ""')
682 # ... supply standard header for prototype, and function args
683 assert r, "did not find strcpy"
684 r = sconf.CheckFunc('strcpy', header='#include <string.h>', funcargs='"", ""')
685 # also try in C++ mode
686 cpp_header = """\
687 #ifdef __cplusplus
688 extern "C"
689 #endif
690 char *strcpy(char *dest, char *src);
692 r = sconf.CheckFunc('strcpy', header=cpp_header, funcargs='"", ""', language="C++")
693 assert r, "did not find strcpy"
694 r = sconf.CheckFunc('hopefullynofunction')
695 assert not r, "unexpectedly found hopefullynofunction"
697 finally:
698 sconf.Finish()
700 def test_CheckProg(self) -> None:
701 """Test SConf.CheckProg()
703 self._resetSConfState()
704 sconf = self.SConf.SConf(self.scons_env,
705 conf_dir=self.test.workpath('config.tests'),
706 log_file=self.test.workpath('config.log'))
708 try:
709 if os.name != 'nt':
710 r = sconf.CheckProg('sh')
711 assert r, "/bin/sh"
712 else:
713 r = sconf.CheckProg('cmd.exe')
714 self.assertIn('cmd.exe',r)
717 r = sconf.CheckProg('hopefully-not-a-program')
718 assert r is None
720 finally:
721 sconf.Finish()
724 def test_Define(self) -> None:
725 """Test SConf.Define()
727 self._resetSConfState()
728 sconf = self.SConf.SConf(self.scons_env,
729 conf_dir=self.test.workpath('config.tests'),
730 log_file=self.test.workpath('config.log'),
731 config_h = self.test.workpath('config.h'))
732 try:
733 # XXX: we test the generated config.h string. This is not so good,
734 # ideally, we would like to test if the generated file included in
735 # a test program does what we want.
737 # Test defining one symbol wo value
738 sconf.config_h_text = ''
739 sconf.Define('YOP')
740 assert sconf.config_h_text == '#define YOP\n'
742 # Test defining one symbol with integer value
743 sconf.config_h_text = ''
744 sconf.Define('YOP', 1)
745 assert sconf.config_h_text == '#define YOP 1\n'
747 # Test defining one symbol with string value
748 sconf.config_h_text = ''
749 sconf.Define('YOP', '"YIP"')
750 assert sconf.config_h_text == '#define YOP "YIP"\n'
752 # Test defining one symbol with string value
753 sconf.config_h_text = ''
754 sconf.Define('YOP', "YIP")
755 assert sconf.config_h_text == '#define YOP YIP\n'
757 finally:
758 sconf.Finish()
760 def test_CheckTypeSize(self) -> None:
761 """Test SConf.CheckTypeSize()
763 self._resetSConfState()
764 sconf = self.SConf.SConf(self.scons_env,
765 conf_dir=self.test.workpath('config.tests'),
766 log_file=self.test.workpath('config.log'))
767 try:
768 # CheckTypeSize()
770 # In ANSI C, sizeof(char) == 1.
771 r = sconf.CheckTypeSize('char', expect = 1)
772 assert r == 1, "sizeof(char) != 1 ??"
773 r = sconf.CheckTypeSize('char', expect = 0)
774 assert r == 0, "sizeof(char) == 0 ??"
775 r = sconf.CheckTypeSize('char', expect = 2)
776 assert r == 0, "sizeof(char) == 2 ??"
777 r = sconf.CheckTypeSize('char')
778 assert r == 1, "sizeof(char) != 1 ??"
779 r = sconf.CheckTypeSize('const unsigned char')
780 assert r == 1, "sizeof(const unsigned char) != 1 ??"
782 # Checking C++
783 r = sconf.CheckTypeSize('const unsigned char', language = 'C++')
784 assert r == 1, "sizeof(const unsigned char) != 1 ??"
786 # Checking Non-existing type
787 r = sconf.CheckTypeSize('thistypedefhasnotchancetosexist_scons')
788 assert r == 0, \
789 "Checking size of thistypedefhasnotchancetosexist_scons succeeded ?"
791 finally:
792 sconf.Finish()
794 def test_CheckDeclaration(self) -> None:
795 """Test SConf.CheckDeclaration()
797 self._resetSConfState()
798 sconf = self.SConf.SConf(self.scons_env,
799 conf_dir=self.test.workpath('config.tests'),
800 log_file=self.test.workpath('config.log'))
801 try:
802 # In ANSI C, malloc should be available in stdlib
803 r = sconf.CheckDeclaration('malloc', includes = "#include <stdlib.h>")
804 assert r, "malloc not declared ??"
805 # For C++, __cplusplus should be declared
806 r = sconf.CheckDeclaration('__cplusplus', language = 'C++')
807 assert r, "__cplusplus not declared in C++ ??"
808 r = sconf.CheckDeclaration('__cplusplus', language = 'C')
809 assert not r, "__cplusplus declared in C ??"
810 r = sconf.CheckDeclaration('unknown', language = 'Unknown')
811 assert not r, "unknown language was supported ??"
812 finally:
813 sconf.Finish()
815 def test_CheckMember(self) -> None:
816 """Test SConf.CheckMember()
818 self._resetSConfState()
819 sconf = self.SConf.SConf(self.scons_env,
820 conf_dir=self.test.workpath('config.tests'),
821 log_file=self.test.workpath('config.log'))
823 try:
824 # CheckMember()
825 r = sconf.CheckMember('struct timespec.tv_sec', '#include <time.h>')
826 assert r, "did not find timespec.tv_sec"
827 r = sconf.CheckMember('struct timespec.tv_nano', '#include <time.h>')
828 assert not r, "unexpectedly found struct timespec.tv_nano"
829 r = sconf.CheckMember('hopefullynomember')
830 assert not r, "unexpectedly found hopefullynomember :%s" % r
832 finally:
833 sconf.Finish()
836 def test_(self) -> None:
837 """Test SConf.CheckType()
839 self._resetSConfState()
840 sconf = self.SConf.SConf(self.scons_env,
841 conf_dir=self.test.workpath('config.tests'),
842 log_file=self.test.workpath('config.log'))
843 try:
844 # CheckType()
845 r = sconf.CheckType('off_t', '#include <sys/types.h>\n')
846 assert r, "did not find off_t"
847 r = sconf.CheckType('hopefullynotypedef_not')
848 assert not r, "unexpectedly found hopefullynotypedef_not"
850 finally:
851 sconf.Finish()
853 def test_CustomChecks(self) -> None:
854 """Test Custom Checks
856 def CheckCustom(test):
857 test.Message( "Checking UserTest ... " )
858 prog = """
859 #include <stdio.h>
861 int main(void) {
862 printf( "Hello" );
863 return 0;
866 (ret, output) = test.TryRun( prog, ".c" )
867 test.Result( ret )
868 assert ret and output == "Hello", (ret, output)
869 return ret
872 self._resetSConfState()
873 sconf = self.SConf.SConf(self.scons_env,
874 custom_tests={'CheckCustom': CheckCustom},
875 conf_dir=self.test.workpath('config.tests'),
876 log_file=self.test.workpath('config.log'))
877 try:
878 ret = sconf.CheckCustom()
879 assert ret, ret
880 finally:
881 sconf.Finish()
884 if __name__ == "__main__":
885 unittest.main()
887 # Local Variables:
888 # tab-width:4
889 # indent-tabs-mode:nil
890 # End:
891 # vim: set expandtab tabstop=4 shiftwidth=4: