#!/usr/bin/env python # # __COPYRIGHT__ # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" import os import re import sys import shutil import TestCmd import TestSCons if sys.platform == 'win32': lib = 'msvcrt' else: lib = 'm' # to use cygwin compilers on cmd.exe -> uncomment following line #lib = 'm' work_cnt = 0 work_dir = None python = TestSCons.python test = TestSCons.TestSCons() def reset(match = 1): global test, work_dir, work_cnt work_cnt = work_cnt + 1 work_dir='test%d' % work_cnt test.subdir(work_dir) if match == 0: test.match_func = TestCmd.match_re elif match == 1: test.match_func = TestCmd.match_re_dotall elif match == 2: test.match_func = TestCmd.match_exact def checkFiles(test, files): global work_dir for f in files: test.fail_test( not os.path.isfile( test.workpath(work_dir,f) ) ) def checkLog( test, logfile, numUpToDate, numCache ): test.fail_test(not os.path.exists(test.workpath(work_dir, logfile))) log = test.read(test.workpath(work_dir, logfile)) try: test.fail_test( len( re.findall( "is up to date", log ) ) != numUpToDate ) test.fail_test( len( re.findall( "\(cached\): Building \S+ failed in a previous run.", log ) ) != numCache ) except: print "contents of log ", test.workpath(work_dir, logfile), "\n", log raise try: # 1.1 if checks are ok, the cache mechanism should work reset(match=2) test.write([work_dir, 'SConstruct'], """ env = Environment() import os env['ENV']['PATH'] = os.environ['PATH'] conf = Configure(env) r1 = conf.CheckLibWithHeader( '%s', 'math.h', 'c' ) r2 = conf.CheckLibWithHeader( None, 'math.h', 'c' ) r3 = conf.CheckLib( '%s', autoadd=0 ) r4 = conf.CheckLib( None, autoadd=0 ) r5 = conf.CheckCHeader( 'math.h' ) r6 = conf.CheckCXXHeader( 'vector' ) env = conf.Finish() if not (r1 and r2 and r3 and r4 and r5 and r6): Exit(1) """ % (lib,lib)) required_stdout = test.wrap_stdout(build_str="scons: `.' is up to date.\n", read_str= """Checking for main() in C library %s... yes Checking for main() in C library None... yes Checking for main() in C library %s... yes Checking for main() in C library None... yes Checking for C header file math.h... yes Checking for C++ header file vector... yes """ % (lib, lib)) test.run(chdir=work_dir, stdout = required_stdout) checkLog(test,'config.log', 0, 0 ) test.run(chdir=work_dir, stdout = required_stdout) checkLog(test,'config.log',12, 0 ) # 1.2 if checks are not ok, the cache mechanism should work as well # (via explicit cache) reset(match=2) # match exactly, "()" is a regexp thing test.write([work_dir, 'SConstruct'], """ env = Environment() import os env['ENV']['PATH'] = os.environ['PATH'] conf = env.Configure() r1 = conf.CheckCHeader( 'no_std_c_header.h' ) # leads to compile error r2 = conf.CheckLib( 'no_c_library_SAFFDG' ) # leads to link error env = conf.Finish() if not (not r1 and not r2): print "FAIL: ", r1, r2 Exit(1) """) required_stdout = test.wrap_stdout(build_str="scons: `.' is up to date.\n", read_str= """Checking for C header file no_std_c_header.h... no Checking for main() in C library no_c_library_SAFFDG... no """) test.run(chdir=work_dir, stdout = required_stdout) checkLog(test, 'config.log', 0, 0 ) test.run(chdir=work_dir, stdout = required_stdout) checkLog(test, 'config.log', 2, 2 ) # 2.1 test that normal builds work together with Sconf reset() test.write([work_dir, 'SConstruct'], """ env = Environment() import os env['ENV']['PATH'] = os.environ['PATH'] conf = Configure(env) r1 = conf.CheckCHeader( 'math.h' ) r2 = conf.CheckCHeader( 'no_std_c_header.h' ) # leads to compile error env = conf.Finish() Export( 'env' ) SConscript( 'SConscript' ) """) test.write([work_dir, 'SConscript'], """ Import( 'env' ) env.Program( 'TestProgram', 'TestProgram.c' ) """) test.write([work_dir, 'TestProgram.c'], """ #include int main() { printf( "Hello\\n" ); } """) required_stdout = test.wrap_stdout(build_str='.*', read_str= """Checking for C header file math.h... yes Checking for C header file no_std_c_header.h... no """) test.run(chdir=work_dir, stdout = required_stdout ) checkLog( test, 'config.log', 0, 0 ) test.run(chdir=work_dir, stdout = required_stdout ) checkLog( test, 'config.log', 3, 1 ) # 2.2 test that BuildDir builds work together with Sconf reset() test.write([work_dir, 'SConstruct'], """ env = Environment(LOGFILE='build/config.log') import os env['ENV']['PATH'] = os.environ['PATH'] BuildDir( 'build', '.' ) conf = env.Configure(conf_dir='build/config.tests', log_file='$LOGFILE') r1 = conf.CheckCHeader( 'math.h' ) r2 = conf.CheckCHeader( 'no_std_c_header.h' ) # leads to compile error env = conf.Finish() Export( 'env' ) # print open( 'build/config.log' ).readlines() SConscript( 'build/SConscript' ) """) test.write([work_dir, 'SConscript'], """ Import( 'env' ) env.Program( 'TestProgram', 'TestProgram.c' ) """) test.write([work_dir, 'TestProgram.c'], """ #include int main() { printf( "Hello\\n" ); } """) required_stdout = test.wrap_stdout(build_str='.*', read_str= """Checking for C header file math.h... yes Checking for C header file no_std_c_header.h... no """) test.run(chdir=work_dir, stdout = required_stdout ) checkLog( test, 'build/config.log', 0, 0 ) test.run(chdir=work_dir, stdout = required_stdout ) checkLog( test, 'build/config.log', 3, 1 ) # 2.3 test that Configure calls in SConscript files work # even if BuildDir is set reset() test.subdir( [work_dir, 'sub'], [work_dir, 'sub', 'local'] ) test.write([work_dir, 'SConstruct'], """ opts = Options() opts.Add('chdir') env = Environment(options=opts) if env['chdir'] == 'yes': SConscriptChdir(1) else: SConscriptChdir(0) BuildDir( 'build', '.' ) SConscript( 'build/SConscript' ) """) test.write([work_dir, 'sub', 'local', 'local_header.h'], "/* Hello World */" ) test.write([work_dir, 'SConscript'], """ SConscript( 'sub/SConscript' ) """) test.write([work_dir, 'sub', 'SConscript'], """ def CustomTest(context): context.Message('Executing Custom Test ... ') ret = context.TryCompile('#include "local_header.h"', '.c') context.Result(ret) return ret env = Environment(FOO='fff') env.Append( CPPPATH='local' ) import os env['ENV']['PATH'] = os.environ['PATH'] conf = Configure( env, custom_tests = {'CustomTest' : CustomTest, '$FOO' : CustomTest} ) if hasattr(conf, 'fff'): conf.Message('$FOO should not have been expanded!') Exit(1) if not conf.CheckCHeader( 'math.h' ): Exit(1) if conf.CheckCHeader( 'no_std_c_header.h' ): Exit(1) if not conf.CustomTest(): Exit(1) env = conf.Finish() env.Program( 'TestProgram', 'TestProgram.c' ) """) test.write([work_dir, 'sub', 'TestProgram.h'], """ /* Just a test header */ """) test.write([work_dir, 'sub', 'TestProgram.c'], """ #include "TestProgram.h" #include int main() { printf( "Hello\\n" ); } """) required_stdout = test.wrap_stdout(build_str='.*', read_str= """Checking for C header file math.h... yes Checking for C header file no_std_c_header.h... no Executing Custom Test ... ok """) # first with SConscriptChdir(0) test.run(chdir=work_dir, stdout = required_stdout, arguments='chdir=no') checkFiles( test, [".sconf_temp/.cache", "config.log"] ) checkLog( test, 'config.log', 0, 0 ) test.run(chdir=work_dir, stdout = required_stdout, arguments='chdir=no') checkFiles( test, [".sconf_temp/.cache", "config.log"] ) checkLog( test, 'config.log', 5, 1 ) shutil.rmtree(test.workpath(work_dir, ".sconf_temp")) # now with SConscriptChdir(1) test.run(chdir=work_dir, stdout = required_stdout, arguments='chdir=yes') checkFiles( test, [".sconf_temp/.cache", "config.log"] ) checkLog( test, 'config.log', 0, 0 ) test.run(chdir=work_dir, stdout = required_stdout, arguments='chdir=yes') checkFiles( test, [".sconf_temp/.cache", "config.log"] ) checkLog( test, 'config.log', 5, 1 ) # 3.1 test custom tests reset() compileOK = '#include \\nint main() {printf("Hello");return 0;}' compileFAIL = "syntax error" linkOK = compileOK linkFAIL = "void myFunc(); int main() { myFunc(); }" runOK = compileOK runFAIL = "int main() { return 1; }" test.write([work_dir, 'pyAct.py'], 'import sys\nprint sys.argv[1]\nsys.exit(int(sys.argv[1]))\n') test.write([work_dir, 'SConstruct'], """ def CheckCustom(test): test.Message( 'Executing MyTest ... ' ) retCompileOK = test.TryCompile( '%s', '.c' ) retCompileFAIL = test.TryCompile( '%s', '.c' ) retLinkOK = test.TryLink( '%s', '.c' ) retLinkFAIL = test.TryLink( '%s', '.c' ) (retRunOK, outputRunOK) = test.TryRun( '%s', '.c' ) (retRunFAIL, outputRunFAIL) = test.TryRun( '%s', '.c' ) (retActOK, outputActOK) = test.TryAction( '%s pyAct.py 0 > $TARGET' ) (retActFAIL, outputActFAIL) = test.TryAction( '%s pyAct.py 1 > $TARGET' ) resOK = retCompileOK and retLinkOK and retRunOK and outputRunOK=="Hello" resOK = resOK and retActOK and int(outputActOK)==0 resFAIL = retCompileFAIL or retLinkFAIL or retRunFAIL or outputRunFAIL!="" resFAIL = resFAIL or retActFAIL or outputActFAIL!="" test.Result( resOK and not resFAIL ) return resOK and not resFAIL env = Environment() import os env['ENV']['PATH'] = os.environ['PATH'] conf = Configure( env, custom_tests={'CheckCustom' : CheckCustom} ) conf.CheckCustom() env = conf.Finish() """ % (compileOK, compileFAIL, linkOK, linkFAIL, runOK, runFAIL, python, python ) ) required_stdout = test.wrap_stdout(build_str='.*', read_str="Executing MyTest ... ok\n") test.run(chdir=work_dir, stdout = required_stdout) checkLog( test, 'config.log', 0, 0 ) test.run(chdir=work_dir, stdout = required_stdout) checkLog( test, 'config.log', 12, 4 ) # 4.1 test that calling normal builders from an actual configuring # environment works reset() test.write([work_dir, 'cmd.py'], r""" import sys sys.stderr.write( 'Hello World on stderr\n' ) sys.stdout.write( 'Hello World on stdout\n' ) open(sys.argv[1], 'w').write( 'Hello World\n' ) """) test.write([work_dir, 'SConstruct'], """ env = Environment() def CustomTest(*args): return 0 conf = env.Configure(custom_tests = {'MyTest' : CustomTest}) if not conf.MyTest(): env.Command("hello", [], "%s cmd.py $TARGET") env = conf.Finish() """ % python) test.run(chdir=work_dir, stderr="Hello World on stderr\n") # 4.2 test that calling Configure from a builder results in a # readable Error reset(match=2) test.write([work_dir, 'SConstruct'], """ def ConfigureAction(target, source, env): env.Configure() return 0 env = Environment(BUILDERS = {'MyAction' : Builder(action=Action(ConfigureAction))}) env.MyAction('target', []) """) test.run(chdir=work_dir, status=2, stderr="scons: *** Calling Configure from Builders is not supported.\n") test.pass_test() finally: pass #os.system( 'find . -type f -exec ls -l {} \;' ) #print "-------------config.log------------------" #print test.read( test.workpath('config.log' )) #print "-------------build/config.log------------" #print test.read( test.workpath('build/config.log' ))