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.
28 from types
import ModuleType
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"
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:
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)
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':
63 if isinstance(m
, ModuleType
):
64 # if this is really a scons module, clear its namespace
67 # we only use SCons.Environment and SCons.SConf for these tests.
68 import SCons
.Environment
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)
81 # - msvc on Windows (hopefully)
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++':
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',
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'))
113 res
= checks( self
, sconf
, TryFunc
)
114 assert res
[0] and not res
[1], res
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'))
124 res
= checks( self
, sconf
, TryFunc
)
125 assert res
[0] and not res
[1], res
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" )
145 res
= checks( self
, sconf
, TryFunc
)
146 log
= self
.test
.read( self
.test
.workpath('config.log') )
147 assert res
[0] and res
[1], res
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'))
163 def get_contents(self
, target
, source
, env
) -> str:
164 return 'MyBuilder-MyAction $SOURCE $TARGET'
167 __slots__
= ('shared', '__dict__')
169 class MyBuilder(SCons
.Builder
.BuilderBase
):
170 def __init__(self
) -> None:
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
):
178 def __init__(self
, name
) -> None:
180 self
.state
= SCons
.Node
.no_state
181 self
.waiting_parents
= set()
182 self
.side_effects
= []
184 self
.prerequisites
= None
185 self
.attributes
= Attrs()
186 def disambiguate(self
):
188 def has_builder(self
) -> bool:
190 def add_pre_action(self
, *actions
) -> None:
192 def add_post_action(self
, *actions
) -> None:
194 def children(self
, scan
: int = 1):
198 def set_state(self
, state
) -> None:
200 def alter_targets(self
):
202 def postprocess(self
) -> None:
204 def clear(self
) -> None:
206 def is_up_to_date(self
) -> bool:
208 def prepare(self
) -> None:
210 def push_to_cache(self
) -> bool:
212 def retrieve_from_cache(self
) -> bool:
214 def build(self
, **kw
) -> None:
216 def built(self
) -> None:
218 def get_stored_info(self
) -> None:
220 def is_conftest(self
) -> bool:
222 def get_executor(self
):
224 def __init__(self
, targets
) -> None:
225 self
.targets
= targets
226 def get_all_targets(self
):
228 return Executor([self
])
229 return [MyNode('n1'), MyNode('n2')]
231 self
.scons_env
.Append(BUILDERS
= {'SConfActionBuilder' : MyBuilder()})
232 sconf
.TryBuild(self
.scons_env
.SConfActionBuilder
)
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:
257 res1
= sconf
.TryRun( prog
, ".c" )
258 res2
= sconf
.TryRun( "not a c program\n", ".c" )
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'))
267 assert res
[0][0] and res
[0][1] == "Hello", res
268 assert not res
[1][0] and res
[1][1] == "", res
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'))
280 assert res
[0][0] and res
[0][1] == "Hello", res
281 assert not res
[1][0] and res
[1][1] == "", res
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
:
301 def actionFAIL(target
, source
, env
) -> int:
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'))
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
)
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
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
]
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
] = ''
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'
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'
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'))
358 self
._test
_check
_compilers
('CC', sconf
.CheckCC
, 'CheckCC')
359 except AssertionError:
360 sys
.stderr
.write(self
.test
.read('config.log', mode
='r'))
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'))
374 self
._test
_check
_compilers
('SHCC', sconf
.CheckSHCC
, 'CheckSHCC')
375 except AssertionError:
376 sys
.stderr
.write(self
.test
.read('config.log', mode
='r'))
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'))
390 self
._test
_check
_compilers
('CXX', sconf
.CheckCXX
, 'CheckCXX')
391 except AssertionError:
392 sys
.stderr
.write(self
.test
.read('config.log', mode
='r'))
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'))
406 self
._test
_check
_compilers
('SHCXX', sconf
.CheckSHCXX
, 'CheckSHCXX')
407 except AssertionError:
408 sys
.stderr
.write(self
.test
.read('config.log', mode
='r'))
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'))
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"
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'))
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"
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'))
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"
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'))
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
511 return env
.get('LIBS', [])
513 # CheckLib() with combinations of autoadd, append
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
533 got
= libs(sconf
.env
)
534 assert got
== expect
, "before and after LIBS were not the same"
538 # CheckLib() with unique
539 sconf
.env
.Append(LIBS
=existing_lib
)
541 env
= sconf
.env
.Clone()
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()
553 existing_lib
, "main", autoadd
=True, append
=True, unique
=True
555 assert r
, f
"did not find main in {existing_lib}"
558 got
= libs(sconf
.env
)
559 assert got
== expect
, f
"LIBS: expected {expect}, got {got}"
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'))
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
606 return env
.get('LIBS', [])
608 # CheckLibWithHeader with combinations of autoadd, append
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
634 got
= libs(sconf
.env
)
635 assert got
== expect
, "before and after LIBS were not the same"
639 # CheckLibWithHeader() with unique
640 sconf
.env
.Append(LIBS
=existing_lib
)
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}"
657 got
= libs(sconf
.env
)
658 assert got
== expect
, f
"LIBS: expected {expect}, got {got}"
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'))
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
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"
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'))
710 r
= sconf
.CheckProg('sh')
713 r
= sconf
.CheckProg('cmd.exe')
714 self
.assertIn('cmd.exe',r
)
717 r
= sconf
.CheckProg('hopefully-not-a-program')
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'))
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
= ''
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'
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'))
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 ??"
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')
789 "Checking size of thistypedefhasnotchancetosexist_scons succeeded ?"
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'))
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 ??"
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'))
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
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'))
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"
853 def test_CustomChecks(self
) -> None:
854 """Test Custom Checks
856 def CheckCustom(test
):
857 test
.Message( "Checking UserTest ... " )
866 (ret
, output
) = test
.TryRun( prog
, ".c" )
868 assert ret
and output
== "Hello", (ret
, output
)
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'))
878 ret
= sconf
.CheckCustom()
884 if __name__
== "__main__":
889 # indent-tabs-mode:nil
891 # vim: set expandtab tabstop=4 shiftwidth=4: