diff options
Diffstat (limited to 'test')
65 files changed, 2594 insertions, 341 deletions
diff --git a/test/AR/AR.py b/test/AR/AR.py index cb11175..4048340 100644 --- a/test/AR/AR.py +++ b/test/AR/AR.py @@ -79,6 +79,9 @@ test.write('main.c', r""" #include <stdio.h> #include <stdlib.h> +extern void +library_function(void); + int main(int argc, char *argv[]) { diff --git a/test/AR/ARFLAGS.py b/test/AR/ARFLAGS.py index d4d122e..fbca0ff 100644 --- a/test/AR/ARFLAGS.py +++ b/test/AR/ARFLAGS.py @@ -78,6 +78,9 @@ library_function(void) test.write('main.c', r""" #include <stdlib.h> +extern void +library_function(); + int main(int argc, char *argv[]) { diff --git a/test/BuildDir/Clean.py b/test/BuildDir/Clean.py new file mode 100644 index 0000000..f4a8c48 --- /dev/null +++ b/test/BuildDir/Clean.py @@ -0,0 +1,71 @@ +#!/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__" + +""" +Verify that we can Clean() files in a BuildDir() that's underneath us. +(At one point this didn't work because we were using str() instead of +abspath to remove the files, which would interfere with the removal by +returning a path relative to the BuildDir(), not the top-level SConstruct +directory, if the source directory was the top-level directory.) +""" + +import TestSCons + +test = TestSCons.TestSCons() + +test.write('SConstruct', """\ +BuildDir('build0', '.', duplicate=0) +BuildDir('build1', '.', duplicate=1) + +def build_sample(target, source, env): + targetdir = str(target[0].dir) + target = str(target[0]) + open(target, 'wb').write(open(str(source[0]), 'rb').read()) + open(targetdir+'/sample.junk', 'wb').write('Side effect!\\n') + +t0 = Command("build0/sample.out", "sample.in", build_sample) +t1 = Command("build1/sample.out", "sample.in", build_sample) + +Clean(t0, 'build0/sample.junk') +Clean(t1, 'build1/sample.junk') +""") + +test.write('sample.in', "sample.in\n") + +test.run(arguments = '.') + +test.must_match(['build0', 'sample.out'], "sample.in\n") +test.must_exist(['build0', 'sample.junk']) + +test.must_match(['build1', 'sample.out'], "sample.in\n") +test.must_exist(['build1', 'sample.junk']) + +test.run(arguments = '-c .') + +test.must_not_exist(['build', 'sample.out']) +test.must_not_exist(['build', 'sample.junk']) + +test.pass_test() diff --git a/test/BuildDir/File-create.py b/test/BuildDir/File-create.py new file mode 100644 index 0000000..0a838be --- /dev/null +++ b/test/BuildDir/File-create.py @@ -0,0 +1,70 @@ +#!/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__" + +""" +Verify that explicit use of File() Nodes in a BuildDir, followed by +*direct* creation of the file by Python in the SConscript file itself, +works correctly, with both duplicate=0 and duplicate=1. + +Right now it only works if you explicitly str() the Node before the file +is created on disk, but we at least want to make sure that continues +to work. The non-str() case, which doesn't currently work, is captured +here but commented out. +""" + +import TestSCons + +test = TestSCons.TestSCons() + +test.subdir('src') + +test.write('SConstruct', """\ +SConscript('src/SConscript', build_dir='build0', chdir=1, duplicate=0) +SConscript('src/SConscript', build_dir='build1', chdir=1, duplicate=1) +""") + +test.write(['src', 'SConscript'], """\ +#f1_in = File('f1.in') +#Command('f1.out', f1_in, Copy('$TARGET', '$SOURCE')) +#open('f1.in', 'wb').write("f1.in\\n") + +f2_in = File('f2.in') +str(f2_in) +Command('f2.out', f2_in, Copy('$TARGET', '$SOURCE')) +open('f2.in', 'wb').write("f2.in\\n") +""") + +test.run(arguments = '--tree=all .') + +#test.must_match(['build0', 'f1.out'], "f1.in\n") +test.must_match(['build0', 'f2.out'], "f2.in\n") + +#test.must_match(['build1', 'f1.out'], "f1.in\n") +test.must_match(['build1', 'f2.out'], "f2.in\n") + +test.up_to_date(arguments = '.') + +test.pass_test() diff --git a/test/BuildDir/Sconscript-build_dir.py b/test/BuildDir/Sconscript-build_dir.py index 685011d..50e2c4f 100644 --- a/test/BuildDir/Sconscript-build_dir.py +++ b/test/BuildDir/Sconscript-build_dir.py @@ -225,6 +225,9 @@ test.write(['test2', 'foo.c'], r""" #include <stdio.h> #include <stdlib.h> +extern void +bar(void); + int main(int argc, char *argv[]) { bar(); diff --git a/test/CC/SHCCCOMSTR.py b/test/CC/SHCCCOMSTR.py index 4d240ae..562961a 100644 --- a/test/CC/SHCCCOMSTR.py +++ b/test/CC/SHCCCOMSTR.py @@ -58,6 +58,7 @@ else: test.write('SConstruct', """ env = Environment(SHCCCOM = r'%(_python_)s mycc.py $TARGET $SOURCE', SHCCCOMSTR = 'Building $TARGET from $SOURCE', + SHOBJPREFIX='', SHOBJSUFFIX='.obj') env.SharedObject(target = 'test1', source = 'test1.c') env.SharedObject(target = 'test2', source = 'test2%(alt_c_suffix)s') diff --git a/test/CXX/CXX.py b/test/CXX/CXX.py index a1b4c2a..f537ee8 100644 --- a/test/CXX/CXX.py +++ b/test/CXX/CXX.py @@ -199,7 +199,7 @@ test.write('foo.cxx', r""" int main(int argc, char *argv[]) { - argv[argc++] = "--"; + argv[argc++] = (char *)"--"; printf("foo.cxx\n"); exit (0); } @@ -211,7 +211,7 @@ test.write('bar.cxx', r""" int main(int argc, char *argv[]) { - argv[argc++] = "--"; + argv[argc++] = (char *)"--"; printf("foo.cxx\n"); exit (0); } diff --git a/test/CXX/SHCXX.py b/test/CXX/SHCXX.py index c02086b..abfc19d 100644 --- a/test/CXX/SHCXX.py +++ b/test/CXX/SHCXX.py @@ -55,7 +55,7 @@ test.write('foo.cpp', r""" int main(int argc, char *argv[]) { - argv[argc++] = "--"; + argv[argc++] = (char *)"--"; printf("foo.c\n"); exit (0); } @@ -67,7 +67,7 @@ test.write('bar.cpp', r""" int main(int argc, char *argv[]) { - argv[argc++] = "--"; + argv[argc++] = (char *)"--"; printf("foo.c\n"); exit (0); } diff --git a/test/CXX/SHCXXCOMSTR.py b/test/CXX/SHCXXCOMSTR.py index 33beae7..8e55441 100644 --- a/test/CXX/SHCXXCOMSTR.py +++ b/test/CXX/SHCXXCOMSTR.py @@ -58,7 +58,7 @@ else: test.write('SConstruct', """ env = Environment(SHCXXCOM = r'%(_python_)s mycc.py $TARGET $SOURCE', SHCXXCOMSTR = 'Building shared object $TARGET from $SOURCE', - SHOBJSUFFIX='.obj') + SHOBJPREFIX='', SHOBJSUFFIX='.obj') env.SharedObject(target = 'test1', source = 'test1.cpp') env.SharedObject(target = 'test2', source = 'test2.cc') env.SharedObject(target = 'test3', source = 'test3.cxx') diff --git a/test/CacheDir/timestamp.py b/test/CacheDir/timestamp-content.py index b0d45b6..6434d0c 100644 --- a/test/CacheDir/timestamp.py +++ b/test/CacheDir/timestamp-content.py @@ -25,7 +25,8 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" """ -Verify that CacheDir() works even when using timestamp signatures. +Verify that CacheDir() works when using SourceSignatures('timestamp') +and TargetSignatures 'content'. """ import TestSCons @@ -41,8 +42,20 @@ Command('file.out', 'file.in', Copy('$TARGET', '$SOURCE')) test.write('file.in', "file.in\n") -test.run() +test.run(arguments = '.') test.must_match('file.out', "file.in\n") +test.up_to_date(options = '--cache-show --debug=explain', arguments = '.') + +test.sleep() + +test.touch('file.in') + +test.not_up_to_date(options = '--cache-show --debug=explain', arguments = '.') + +test.up_to_date(options = '--cache-show --debug=explain', arguments = '.') + +test.up_to_date(options = '--cache-show --debug=explain', arguments = '.') + test.pass_test() diff --git a/test/CacheDir/timestamp-match.py b/test/CacheDir/timestamp-match.py new file mode 100644 index 0000000..0e0074d --- /dev/null +++ b/test/CacheDir/timestamp-match.py @@ -0,0 +1,59 @@ +#!/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__" + +""" +Verify that CAcheDir() works when using 'timestamp-match' decisions. +""" + +import TestSCons + +test = TestSCons.TestSCons() + +test.write(['SConstruct'], """\ +Decider('timestamp-match') +CacheDir('cache') +Command('file.out', 'file.in', Copy('$TARGET', '$SOURCE')) +""") + +test.write('file.in', "file.in\n") + +test.run(arguments = '--cache-show --debug=explain .') + +test.must_match('file.out', "file.in\n") + +test.up_to_date(options = '--cache-show --debug=explain', arguments = '.') + +test.sleep() + +test.touch('file.in') + +test.not_up_to_date(options = '--cache-show --debug=explain', arguments = '.') + +test.up_to_date(options = '--cache-show --debug=explain', arguments = '.') + +test.up_to_date(options = '--cache-show --debug=explain', arguments = '.') + +test.pass_test() diff --git a/test/CacheDir/timestamp-newer.py b/test/CacheDir/timestamp-newer.py new file mode 100644 index 0000000..36267f8 --- /dev/null +++ b/test/CacheDir/timestamp-newer.py @@ -0,0 +1,59 @@ +#!/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__" + +""" +Verify that CAcheDir() works when using 'timestamp-newer' decisions. +""" + +import TestSCons + +test = TestSCons.TestSCons() + +test.write(['SConstruct'], """\ +Decider('timestamp-newer') +CacheDir('cache') +Command('file.out', 'file.in', Copy('$TARGET', '$SOURCE')) +""") + +test.write('file.in', "file.in\n") + +test.run(arguments = '--cache-show --debug=explain .') + +test.must_match('file.out', "file.in\n") + +test.up_to_date(options = '--cache-show --debug=explain', arguments = '.') + +test.sleep() + +test.touch('file.in') + +test.not_up_to_date(options = '--cache-show --debug=explain', arguments = '.') + +test.up_to_date(options = '--cache-show --debug=explain', arguments = '.') + +test.up_to_date(options = '--cache-show --debug=explain', arguments = '.') + +test.pass_test() diff --git a/test/CacheDir/timestamp-timestamp.py b/test/CacheDir/timestamp-timestamp.py new file mode 100644 index 0000000..2bef1cd --- /dev/null +++ b/test/CacheDir/timestamp-timestamp.py @@ -0,0 +1,61 @@ +#!/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__" + +""" +Verify that CacheDir() works when using both SourceSignatures() +and TargetSignatures values of 'timestamp'. +""" + +import TestSCons + +test = TestSCons.TestSCons() + +test.write(['SConstruct'], """\ +SourceSignatures('timestamp') +TargetSignatures('timestamp') +CacheDir('cache') +Command('file.out', 'file.in', Copy('$TARGET', '$SOURCE')) +""") + +test.write('file.in', "file.in\n") + +test.run(arguments = '--cache-show --debug=explain .') + +test.must_match('file.out', "file.in\n") + +test.up_to_date(options = '--cache-show --debug=explain', arguments = '.') + +test.sleep() + +test.touch('file.in') + +test.not_up_to_date(options = '--cache-show --debug=explain', arguments = '.') + +test.up_to_date(options = '--cache-show --debug=explain', arguments = '.') + +test.up_to_date(options = '--cache-show --debug=explain', arguments = '.') + +test.pass_test() diff --git a/test/Chmod.py b/test/Chmod.py index eb0b6c1..92fa639 100644 --- a/test/Chmod.py +++ b/test/Chmod.py @@ -41,7 +41,9 @@ test = TestSCons.TestSCons() # oscillate between those values. test.write('SConstruct', """ Execute(Chmod('f1', 0666)) +Execute(Chmod(('f1-File'), 0666)) Execute(Chmod('d2', 0777)) +Execute(Chmod(Dir('d2-Dir'), 0777)) def cat(env, source, target): target = str(target[0]) source = map(str, source) @@ -62,8 +64,11 @@ env.Command('f7.out', 'f7.in', [Cat, """) test.write('f1', "f1\n") +test.write('f1-File', "f1-File\n") test.subdir('d2') test.write(['d2', 'file'], "d2/file\n") +test.subdir('d2-Dir') +test.write(['d2-Dir', 'file'], "d2-Dir/file\n") test.write('bar.in', "bar.in\n") test.write('f3', "f3\n") test.subdir('d4') @@ -75,14 +80,21 @@ test.write('Chmod-f7.in', "Chmod-f7.in\n") test.write('f7.out-Chmod', "f7.out-Chmod\n") os.chmod(test.workpath('f1'), 0444) +os.chmod(test.workpath('f1-File'), 0444) os.chmod(test.workpath('d2'), 0555) +os.chmod(test.workpath('d2-Dir'), 0555) os.chmod(test.workpath('f3'), 0444) os.chmod(test.workpath('d4'), 0555) os.chmod(test.workpath('f5'), 0444) os.chmod(test.workpath('Chmod-f7.in'), 0444) os.chmod(test.workpath('f7.out-Chmod'), 0444) -expect = test.wrap_stdout(read_str = 'Chmod("f1", 0666)\nChmod("d2", 0777)\n', +expect = test.wrap_stdout(read_str = """\ +Chmod("f1", 0666) +Chmod("f1-File", 0666) +Chmod("d2", 0777) +Chmod("d2-Dir", 0777) +""", build_str = """\ cat(["bar.out"], ["bar.in"]) Chmod("f3", 0666) @@ -97,8 +109,12 @@ test.run(options = '-n', arguments = '.', stdout = expect) s = stat.S_IMODE(os.stat(test.workpath('f1'))[stat.ST_MODE]) test.fail_test(s != 0444) +s = stat.S_IMODE(os.stat(test.workpath('f1-File'))[stat.ST_MODE]) +test.fail_test(s != 0444) s = stat.S_IMODE(os.stat(test.workpath('d2'))[stat.ST_MODE]) test.fail_test(s != 0555) +s = stat.S_IMODE(os.stat(test.workpath('d2-Dir'))[stat.ST_MODE]) +test.fail_test(s != 0555) test.must_not_exist('bar.out') s = stat.S_IMODE(os.stat(test.workpath('f3'))[stat.ST_MODE]) test.fail_test(s != 0444) @@ -117,8 +133,12 @@ test.run() s = stat.S_IMODE(os.stat(test.workpath('f1'))[stat.ST_MODE]) test.fail_test(s != 0666) +s = stat.S_IMODE(os.stat(test.workpath('f1-File'))[stat.ST_MODE]) +test.fail_test(s != 0666) s = stat.S_IMODE(os.stat(test.workpath('d2'))[stat.ST_MODE]) test.fail_test(s != 0777) +s = stat.S_IMODE(os.stat(test.workpath('d2-Dir'))[stat.ST_MODE]) +test.fail_test(s != 0777) test.must_match('bar.out', "bar.in\n") s = stat.S_IMODE(os.stat(test.workpath('f3'))[stat.ST_MODE]) test.fail_test(s != 0666) diff --git a/test/Configure/clean.py b/test/Configure/clean.py index 5b8e43d..a6ba7c1 100644 --- a/test/Configure/clean.py +++ b/test/Configure/clean.py @@ -39,7 +39,7 @@ test.write('SConstruct', """\ env = Environment() import os env.AppendENVPath('PATH', os.environ['PATH']) -conf = Configure(env) +conf = Configure(env, clean=int(ARGUMENTS['clean'])) r1 = conf.CheckCHeader( 'math.h' ) r2 = conf.CheckCHeader( 'no_std_c_header.h' ) # leads to compile error env = conf.Finish() @@ -65,32 +65,16 @@ lines = [ "Checking for C header file no_std_c_header.h... " ] -unexpected = [] +test.run(arguments = '-c clean=0') +test.must_not_contain_lines(lines, test.stdout()) -test.run(arguments = '-c') +test.run(arguments = '-c clean=1') +test.must_contain_lines(lines, test.stdout()) -for line in lines: - if string.find(test.stdout(), line) != -1: - unexpected.append(line) +test.run(arguments = '--clean clean=0') +test.must_not_contain_lines(lines, test.stdout()) -if unexpected: - print "Unexpected lines in standard output:" - print string.join(unexpected, '\n') - print "STDOUT ============================================================" - print test.stdout() - test.fail_test() - -test.run(arguments = '--clean') - -for line in lines: - if string.find(test.stdout(), line) != -1: - unexpected.append(line) - -if unexpected: - print "Unexpected lines in standard output:" - print string.join(unexpected, '\n') - print "STDOUT ============================================================" - print test.stdout() - test.fail_test() +test.run(arguments = '--clean clean=1') +test.must_contain_lines(lines, test.stdout()) test.pass_test() diff --git a/test/Configure/help.py b/test/Configure/help.py index f79831c..32c68eb 100644 --- a/test/Configure/help.py +++ b/test/Configure/help.py @@ -39,7 +39,7 @@ test.write('SConstruct', """\ env = Environment() import os env.AppendENVPath('PATH', os.environ['PATH']) -conf = Configure(env) +conf = Configure(env, help=int(ARGUMENTS['help'])) r1 = conf.CheckCHeader( 'math.h' ) r2 = conf.CheckCHeader( 'no_std_c_header.h' ) # leads to compile error env = conf.Finish() @@ -65,45 +65,26 @@ lines = [ "Checking for C header file no_std_c_header.h... " ] -unexpected = [] +# The help setting should have no effect on -H, so the -H output +# should never contain the lines. +test.run(arguments = '-H help=0') +test.must_not_contain_lines(lines, test.stdout()) -test.run(arguments = '-H') +test.run(arguments = '-H help=1') +test.must_not_contain_lines(lines, test.stdout()) -for line in lines: - if string.find(test.stdout(), line) != -1: - unexpected.append(line) +# For -h and --help, the lines appear or not depending on how Configure() +# is initialized. +test.run(arguments = '-h help=0') +test.must_not_contain_lines(lines, test.stdout()) -if unexpected: - print "Unexpected lines in standard output:" - print string.join(unexpected, '\n') - print "STDOUT ============================================================" - print test.stdout() - test.fail_test() +test.run(arguments = '-h help=1') +test.must_contain_lines(lines, test.stdout()) -test.run(arguments = '-h') +test.run(arguments = '--help help=0') +test.must_not_contain_lines(lines, test.stdout()) -for line in lines: - if string.find(test.stdout(), line) != -1: - unexpected.append(line) - -if unexpected: - print "Unexpected lines in standard output:" - print string.join(unexpected, '\n') - print "STDOUT ============================================================" - print test.stdout() - test.fail_test() - -test.run(arguments = '--help') - -for line in lines: - if string.find(test.stdout(), line) != -1: - unexpected.append(line) - -if unexpected: - print "Unexpected lines in standard output:" - print string.join(unexpected, '\n') - print "STDOUT ============================================================" - print test.stdout() - test.fail_test() +test.run(arguments = '--help help=1') +test.must_contain_lines(lines, test.stdout()) test.pass_test() diff --git a/test/Copy.py b/test/Copy.py index 6659d93..827b912 100644 --- a/test/Copy.py +++ b/test/Copy.py @@ -36,8 +36,8 @@ test = TestSCons.TestSCons() test.write('SConstruct', """ Execute(Copy('f1.out', 'f1.in')) -Execute(Copy('d2.out', 'd2.in')) -Execute(Copy('d3.out', 'f3.in')) +Execute(Copy(File('d2.out'), 'd2.in')) +Execute(Copy('d3.out', File('f3.in'))) def cat(env, source, target): target = str(target[0]) source = map(str, source) diff --git a/test/Errors/preparation.py b/test/Errors/preparation.py index 9857f99..597216a 100644 --- a/test/Errors/preparation.py +++ b/test/Errors/preparation.py @@ -25,8 +25,15 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" """ -Verify that we print a useful message (and exit non-zero) if an external -error occurs while deciding if a Node is current or not. +A currently disabled test that used to verify that we print a useful +message (and exit non-zero) if an external error occurs while deciding +if a Node is current or not. + +This behavior changed when the Big Signature Refactoring changed when +signature calculation happens to *after* a Node has been visited (and +therefore visiting source Nodes in turn). Creating an analogous situation +in the new code isn't obvious, and It's not clear whether we need it +anyway, so we're going to leave this checked in but disabled for now. """ import sys @@ -35,6 +42,8 @@ import TestSCons test = TestSCons.TestSCons() +test.skip_test('Test not useful with current code; skipping.\n') + work_file_out = test.workpath('work', 'file.out') test.subdir('install', 'work') diff --git a/test/Fortran/SHF77COMSTR.py b/test/Fortran/SHF77COMSTR.py index 9085570..2bedb48 100644 --- a/test/Fortran/SHF77COMSTR.py +++ b/test/Fortran/SHF77COMSTR.py @@ -56,7 +56,7 @@ env = Environment(SHF77COM = r'%(_python_)s myfc.py f77 $TARGET $SOURCES', SHF77COMSTR = 'Building f77 $TARGET from $SOURCES', SHF77PPCOM = r'%(_python_)s myfc.py f77pp $TARGET $SOURCES', SHF77PPCOMSTR = 'Building f77pp $TARGET from $SOURCES', - SHOBJSUFFIX='.shobj') + SHOBJPREFIX='', SHOBJSUFFIX='.shobj') env.SharedObject(source = 'test01.f') env.SharedObject(source = 'test02.F') env.SharedObject(source = 'test03.for') diff --git a/test/Fortran/SHF90COMSTR.py b/test/Fortran/SHF90COMSTR.py index 9633d45..08208fa 100644 --- a/test/Fortran/SHF90COMSTR.py +++ b/test/Fortran/SHF90COMSTR.py @@ -56,7 +56,7 @@ env = Environment(SHF90COM = r'%(_python_)s myfc.py f90 $TARGET $SOURCES', SHF90COMSTR = 'Building f90 $TARGET from $SOURCES', SHF90PPCOM = r'%(_python_)s myfc.py f90pp $TARGET $SOURCES', SHF90PPCOMSTR = 'Building f90pp $TARGET from $SOURCES', - SHOBJSUFFIX='.shobj') + SHOBJPREFIX='', SHOBJSUFFIX='.shobj') env.SharedObject(source = 'test01.f90') env.SharedObject(source = 'test02.F90') """ % locals()) diff --git a/test/Fortran/SHF95COMSTR.py b/test/Fortran/SHF95COMSTR.py index eaa24ae..71a5627 100644 --- a/test/Fortran/SHF95COMSTR.py +++ b/test/Fortran/SHF95COMSTR.py @@ -56,7 +56,7 @@ env = Environment(SHF95COM = r'%(_python_)s myfc.py f95 $TARGET $SOURCES', SHF95COMSTR = 'Building f95 $TARGET from $SOURCES', SHF95PPCOM = r'%(_python_)s myfc.py f95pp $TARGET $SOURCES', SHF95PPCOMSTR = 'Building f95pp $TARGET from $SOURCES', - SHOBJSUFFIX='.shobj') + SHOBJPREFIX='', SHOBJSUFFIX='.shobj') env.SharedObject(source = 'test01.f95') env.SharedObject(source = 'test02.F95') """ % locals()) diff --git a/test/Fortran/SHFORTRANCOMSTR.py b/test/Fortran/SHFORTRANCOMSTR.py index 69a1eba..52b20c2 100644 --- a/test/Fortran/SHFORTRANCOMSTR.py +++ b/test/Fortran/SHFORTRANCOMSTR.py @@ -56,7 +56,7 @@ env = Environment(SHFORTRANCOM = r'%(_python_)s myfc.py fortran $TARGET $SOURCES SHFORTRANCOMSTR = 'Building fortran $TARGET from $SOURCES', SHFORTRANPPCOM = r'%(_python_)s myfc.py fortranpp $TARGET $SOURCES', SHFORTRANPPCOMSTR = 'Building fortranpp $TARGET from $SOURCES', - SHOBJSUFFIX='.shobj') + SHOBJPREFIX='', SHOBJSUFFIX='.shobj') env.SharedObject(source = 'test01.f') env.SharedObject(source = 'test02.F') env.SharedObject(source = 'test03.for') diff --git a/test/GetBuildFailures/option-k.py b/test/GetBuildFailures/option-k.py new file mode 100644 index 0000000..5246f31 --- /dev/null +++ b/test/GetBuildFailures/option-k.py @@ -0,0 +1,112 @@ +#!/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. +# + +""" +Verify that a failed build action with -j works as expected. +""" + +__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" + +import TestSCons + +_python_ = TestSCons._python_ + +try: + import threading +except ImportError: + # if threads are not supported, then + # there is nothing to test + TestCmd.no_result() + sys.exit() + + +test = TestSCons.TestSCons() + +contents = r"""\ +import sys +if sys.argv[0] == 'mypass.py': + open(sys.argv[3], 'wb').write(open(sys.argv[4], 'rb').read()) + exit_value = 0 +elif sys.argv[0] == 'myfail.py': + exit_value = 1 +sys.exit(exit_value) +""" + +test.write('mypass.py', contents) +test.write('myfail.py', contents) + +test.write('SConstruct', """\ +Command('f3', 'f3.in', r'@%(_python_)s mypass.py - f3 $TARGET $SOURCE') +Command('f4', 'f4.in', r'@%(_python_)s myfail.py f3 f4 $TARGET $SOURCE') +Command('f5', 'f5.in', r'@%(_python_)s myfail.py f4 f5 $TARGET $SOURCE') +Command('f6', 'f6.in', r'@%(_python_)s mypass.py f5 - $TARGET $SOURCE') + +def print_build_failures(): + from SCons.Script import GetBuildFailures + bf_list = GetBuildFailures() + bf_list.sort(lambda a,b: cmp(a.filename, b.filename)) + for bf in bf_list: + print "%%s failed: %%s" %% (bf.node, bf.errstr) + +try: + import atexit +except ImportError: + import sys + sys.exitfunc = print_build_failures +else: + atexit.register(print_build_failures) +""" % locals()) + +test.write('f3.in', "f3.in\n") +test.write('f4.in', "f4.in\n") +test.write('f5.in', "f5.in\n") +test.write('f6.in', "f6.in\n") + +expect_stdout = """\ +scons: Reading SConscript files ... +scons: done reading SConscript files. +scons: Building targets ... +scons: done building targets (errors occurred during build). +f4 failed: Error 1 +f5 failed: Error 1 +""" % locals() + +expect_stderr = """\ +scons: *** [f4] Error 1 +scons: *** [f5] Error 1 +""" + +test.run(arguments = '-k .', + status = 2, + stdout = expect_stdout, + stderr = expect_stderr) + +test.must_match(test.workpath('f3'), 'f3.in\n') +test.must_not_exist(test.workpath('f4')) +test.must_not_exist(test.workpath('f5')) +test.must_match(test.workpath('f6'), 'f6.in\n') + + + +test.pass_test() diff --git a/test/GetBuildFailures/parallel.py b/test/GetBuildFailures/parallel.py new file mode 100644 index 0000000..cfadd0d --- /dev/null +++ b/test/GetBuildFailures/parallel.py @@ -0,0 +1,127 @@ +#!/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. +# + +""" +Verify that a failed build action with -j works as expected. +""" + +__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" + +import TestSCons + +_python_ = TestSCons._python_ + +try: + import threading +except ImportError: + # if threads are not supported, then + # there is nothing to test + TestCmd.no_result() + sys.exit() + + +test = TestSCons.TestSCons() + +# We want to verify that -j 4 starts all four jobs, the first and last of +# which fail and the second and third of which succeed, and then stops +# processing due to the build failures. To try to control the timing, +# the created build scripts use marker directories to avoid doing their +# processing until the previous script has finished. + +contents = r"""\ +import os.path +import sys +import time +wait_marker = sys.argv[1] + '.marker' +write_marker = sys.argv[2] + '.marker' +if wait_marker != '-.marker': + while not os.path.exists(wait_marker): + time.sleep(1) +if sys.argv[0] == 'mypass.py': + open(sys.argv[3], 'wb').write(open(sys.argv[4], 'rb').read()) + exit_value = 0 +elif sys.argv[0] == 'myfail.py': + exit_value = 1 +if write_marker != '-.marker': + os.mkdir(write_marker) +sys.exit(exit_value) +""" + +test.write('mypass.py', contents) +test.write('myfail.py', contents) + +test.write('SConstruct', """\ +Command('f3', 'f3.in', r'@%(_python_)s mypass.py - f3 $TARGET $SOURCE') +Command('f4', 'f4.in', r'@%(_python_)s myfail.py f3 f4 $TARGET $SOURCE') +Command('f5', 'f5.in', r'@%(_python_)s myfail.py f4 f5 $TARGET $SOURCE') +Command('f6', 'f6.in', r'@%(_python_)s mypass.py f5 - $TARGET $SOURCE') + +def print_build_failures(): + from SCons.Script import GetBuildFailures + bf_list = GetBuildFailures() + bf_list.sort(lambda a,b: cmp(a.filename, b.filename)) + for bf in bf_list: + print "%%s failed: %%s" %% (bf.node, bf.errstr) + +try: + import atexit +except ImportError: + import sys + sys.exitfunc = print_build_failures +else: + atexit.register(print_build_failures) +""" % locals()) + +test.write('f3.in', "f3.in\n") +test.write('f4.in', "f4.in\n") +test.write('f5.in', "f5.in\n") +test.write('f6.in', "f6.in\n") + +expect_stdout = """\ +scons: Reading SConscript files ... +scons: done reading SConscript files. +scons: Building targets ... +scons: building terminated because of errors. +f4 failed: Error 1 +f5 failed: Error 1 +""" % locals() + +expect_stderr = """\ +scons: *** [f4] Error 1 +scons: *** [f5] Error 1 +""" + +test.run(arguments = '-j 4 .', + status = 2, + stdout = expect_stdout, + stderr = expect_stderr) + +test.must_match(test.workpath('f3'), 'f3.in\n') +test.must_not_exist(test.workpath('f4')) +test.must_not_exist(test.workpath('f5')) +test.must_match(test.workpath('f6'), 'f6.in\n') + + + +test.pass_test() diff --git a/test/GetBuildFailures/serial.py b/test/GetBuildFailures/serial.py new file mode 100644 index 0000000..c8205ed --- /dev/null +++ b/test/GetBuildFailures/serial.py @@ -0,0 +1,115 @@ +#!/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. +# + +""" +Verify that the GetBuildFailures() function returns a list of +BuildError exceptions. Also verify printing the BuildError +attributes we expect to be most commonly used. +""" + +__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" + +import TestSCons + +_python_ = TestSCons._python_ + +try: + import threading +except ImportError: + # if threads are not supported, then + # there is nothing to test + TestCmd.no_result() + sys.exit() + + +test = TestSCons.TestSCons() + +contents = r"""\ +import sys +if sys.argv[0] == 'mypass.py': + open(sys.argv[3], 'wb').write(open(sys.argv[4], 'rb').read()) + exit_value = 0 +elif sys.argv[0] == 'myfail.py': + exit_value = 1 +sys.exit(exit_value) +""" + +test.write('mypass.py', contents) +test.write('myfail.py', contents) + +test.write('SConstruct', """\ +Command('f3', 'f3.in', r'@%(_python_)s mypass.py - f3 $TARGET $SOURCE') +Command('f4', 'f4.in', r'@%(_python_)s myfail.py f3 f4 $TARGET $SOURCE') +Command('f5', 'f5.in', r'@%(_python_)s myfail.py f4 f5 $TARGET $SOURCE') +Command('f6', 'f6.in', r'@%(_python_)s mypass.py f5 - $TARGET $SOURCE') + +def print_build_failures(): + from SCons.Script import GetBuildFailures + import string + bf_list = GetBuildFailures() + bf_list.sort(lambda a,b: cmp(a.filename, b.filename)) + for bf in bf_list: + print "%%s failed (%%s): %%s" %% (bf.node, bf.status, bf.errstr) + print " %%s" %% string.join(bf.command) + +try: + import atexit +except ImportError: + import sys + sys.exitfunc = print_build_failures +else: + atexit.register(print_build_failures) +""" % locals()) + +test.write('f3.in', "f3.in\n") +test.write('f4.in', "f4.in\n") +test.write('f5.in', "f5.in\n") +test.write('f6.in', "f6.in\n") + +expect_stdout = """\ +scons: Reading SConscript files ... +scons: done reading SConscript files. +scons: Building targets ... +scons: building terminated because of errors. +f4 failed (1): Error 1 + %(_python_)s myfail.py f3 f4 "f4" "f4.in" +""" % locals() + +expect_stderr = """\ +scons: *** [f4] Error 1 +""" + +test.run(arguments = '.', + status = 2, + stdout = expect_stdout, + stderr = expect_stderr) + +test.must_match(test.workpath('f3'), 'f3.in\n') +test.must_not_exist(test.workpath('f4')) +test.must_not_exist(test.workpath('f5')) +test.must_not_exist(test.workpath('f6')) + + + +test.pass_test() diff --git a/test/Glob/BuildDir.py b/test/Glob/BuildDir.py new file mode 100644 index 0000000..274ca49 --- /dev/null +++ b/test/Glob/BuildDir.py @@ -0,0 +1,71 @@ +#!/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__" + +""" +Verify that default use of the Glob() function within a BuildDir() +finds the local file Nodes. +""" + +import TestSCons + +test = TestSCons.TestSCons() + +test.subdir('src') + +test.write('SConstruct', """\ +BuildDir('var1', 'src') +BuildDir('var2', 'src') + +SConscript('var1/SConscript') +SConscript('var2/SConscript') +""") + +test.write(['src', 'SConscript'], """\ +env = Environment() + +def concatenate(target, source, env): + fp = open(str(target[0]), 'wb') + for s in source: + fp.write(open(str(s), 'rb').read()) + fp.close() + +env['BUILDERS']['Concatenate'] = Builder(action=concatenate) + +f_in = Glob('f*.in') +f_in.sort(lambda a,b: cmp(a.name, b.name)) +env.Concatenate('f.out', f_in) +""") + +test.write(['src', 'f1.in'], "src/f1.in\n") +test.write(['src', 'f2.in'], "src/f2.in\n") +test.write(['src', 'f3.in'], "src/f3.in\n") + +test.run(arguments = '.') + +test.must_match(['var1', 'f.out'], "src/f1.in\nsrc/f2.in\nsrc/f3.in\n") +test.must_match(['var2', 'f.out'], "src/f1.in\nsrc/f2.in\nsrc/f3.in\n") + +test.pass_test() diff --git a/test/Glob/Repository.py b/test/Glob/Repository.py new file mode 100644 index 0000000..6cef443 --- /dev/null +++ b/test/Glob/Repository.py @@ -0,0 +1,117 @@ +#!/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__" + +""" +Verify that the Glob() function finds files in repositories. +""" + +import TestSCons + +test = TestSCons.TestSCons() + +test.subdir('work', + 'repository', + ['repository', 'src'], + ['repository', 'src', 'sub1'], + ['repository', 'src', 'sub2']) + +work_aaa = test.workpath('work', 'aaa') +work_bbb = test.workpath('work', 'bbb') +work_ccc = test.workpath('work', 'ccc') +work_src_xxx = test.workpath('work', 'src', 'xxx') +work_src_yyy = test.workpath('work', 'src', 'yyy') + +opts = "-Y " + test.workpath('repository') + +test.write(['repository', 'SConstruct'], """\ +def cat(env, source, target): + target = str(target[0]) + source = map(str, source) + f = open(target, "wb") + for src in source: + f.write(open(src, "rb").read()) + f.close() + +env = Environment(BUILDERS={'Build':Builder(action=cat)}) +env.Build('aaa.out', Glob('a*.in')) +env.Build('bbb.out', Glob('b*.in')) +env.Build('ccc.out', Glob('c*.in')) +SConscript('src/SConscript', "env") +""") + +test.write(['repository', 'aaa.in'], "repository/aaa.in\n") +test.write(['repository', 'bbb.in'], "repository/bbb.in\n") +test.write(['repository', 'ccc.in'], "repository/ccc.in\n") + +test.write(['repository', 'src', 'SConscript'], """ +Import("env") +env.Build('xxx.out', Glob('x*.in')) +env.Build('yyy.out', Glob('yy?.in')) +zzz_in = Glob('*/zzz.in') +zzz_in.sort(lambda a,b: cmp(a.abspath, b.abspath)) +env.Build('zzz.out', zzz_in) +""") + +test.write(['repository', 'src', 'xxx.in'], "repository/src/xxx.in\n") +test.write(['repository', 'src', 'yyy.in'], "repository/src/yyy.in\n") +test.write(['repository', 'src', 'sub1', 'zzz.in'], "repository/src/sub1/zzz.in\n") +test.write(['repository', 'src', 'sub2', 'zzz.in'], "repository/src/sub2/zzz.in\n") + +# +# Make the repository non-writable, +# so we'll detect if we try to write into it accidentally. +test.writable('repository', 0) + +# +test.run(chdir = 'work', options = opts, arguments = 'aaa.out') + +test.must_match(['work', 'aaa.out'], "repository/aaa.in\n") +test.must_not_exist(test.workpath('work', 'bbb.out')) +test.must_not_exist(test.workpath('work', 'ccc.out')) +test.must_not_exist(test.workpath('work', 'src', 'xxx.out')) +test.must_not_exist(test.workpath('work', 'src', 'yyy.out')) + +test.run(chdir = 'work', options = opts, arguments = 'bbb.out src') + +test.must_match(['work', 'bbb.out'], "repository/bbb.in\n") +test.must_not_exist(test.workpath('work', 'ccc.out')) +test.must_match(['work', 'src', 'xxx.out'], "repository/src/xxx.in\n") +test.must_match(['work', 'src', 'yyy.out'], "repository/src/yyy.in\n") + +expect = """\ +repository/src/sub1/zzz.in +repository/src/sub2/zzz.in +""" + +test.must_match(['work', 'src', 'zzz.out'], expect) + +# +test.run(chdir = 'work', options = opts, arguments = '.') + +test.must_match(['work', 'ccc.out'], "repository/ccc.in\n") + +# +test.pass_test() diff --git a/test/Glob/basic.py b/test/Glob/basic.py new file mode 100644 index 0000000..2e7427a --- /dev/null +++ b/test/Glob/basic.py @@ -0,0 +1,59 @@ +#!/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__" + +""" +Verify basic operation of the Glob() function. +""" + +import TestSCons + +test = TestSCons.TestSCons() + +test.write('SConstruct', """\ +env = Environment() + +def concatenate(target, source, env): + fp = open(str(target[0]), 'wb') + for s in source: + fp.write(open(str(s), 'rb').read()) + fp.close() + +env['BUILDERS']['Concatenate'] = Builder(action=concatenate) + +f_in = Glob('f*.in') +f_in.sort(lambda a,b: cmp(a.name, b.name)) +env.Concatenate('f.out', f_in) +""") + +test.write('f1.in', "f1.in\n") +test.write('f2.in', "f2.in\n") +test.write('f3.in', "f3.in\n") + +test.run(arguments = '.') + +test.must_match('f.out', "f1.in\nf2.in\nf3.in\n") + +test.pass_test() diff --git a/test/Glob/source.py b/test/Glob/source.py new file mode 100644 index 0000000..b82e1d9 --- /dev/null +++ b/test/Glob/source.py @@ -0,0 +1,88 @@ +#!/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__" + +""" +Verify that use of the Glob() function within a BuildDir() returns the +file Nodes in the source directory when the source= keyword argument is +specified (and duplicate=0 is specified for the BuildDir()). +""" + +import TestSCons + +test = TestSCons.TestSCons() + +test.subdir('src', 'var1', 'var2') + +test.write('SConstruct', """\ +env = Environment() + +def concatenate(target, source, env): + fp = open(str(target[0]), 'wb') + for s in source: + fp.write(open(str(s), 'rb').read()) + fp.close() + +env['BUILDERS']['Concatenate'] = Builder(action=concatenate) + +Export("env") + +BuildDir('var1', 'src', duplicate=0) +BuildDir('var2', 'src', duplicate=0) + +SConscript('var1/SConscript') +SConscript('var2/SConscript') +""") + +test.write(['var1', 'SConscript'], """\ +Import("env") + +f_in = Glob('f[45].in', source=True) +f_in.sort(lambda a,b: cmp(a.name, b.name)) +env.Concatenate('f.out', f_in) +""") + +test.write(['var2', 'SConscript'], """\ +Import("env") + +f_in = Glob('f[67].in') +f_in.sort(lambda a,b: cmp(a.name, b.name)) +env.Concatenate('f.out', f_in) +""") + +test.write(['src', 'f1.in'], "src/f1.in\n") +test.write(['src', 'f2.in'], "src/f2.in\n") + +test.write(['src', 'f4.in'], "src/f4.in\n") +test.write(['src', 'f5.in'], "src/f5.in\n") +test.write(['src', 'f6.in'], "src/f6.in\n") +test.write(['src', 'f7.in'], "src/f7.in\n") + +test.run(arguments = '.') + +test.must_match(['var1', 'f.out'], "src/f4.in\nsrc/f5.in\n") +test.must_match(['var2', 'f.out'], "src/f6.in\nsrc/f7.in\n") + +test.pass_test() diff --git a/test/Glob/strings.py b/test/Glob/strings.py new file mode 100644 index 0000000..d9f8ff1 --- /dev/null +++ b/test/Glob/strings.py @@ -0,0 +1,72 @@ +#!/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__" + +""" +Verify that use of the Glob() function with the strings= option works +when they're used in the same SConscript file (and therefore the same +directory) as input to a Builder call. +""" + +import TestSCons + +test = TestSCons.TestSCons() + +test.subdir('src') + +test.write('SConstruct', """\ +BuildDir('var1', 'src') +BuildDir('var2', 'src') + +SConscript('var1/SConscript') +SConscript('var2/SConscript') +""") + +test.write(['src', 'SConscript'], """\ +env = Environment() + +def concatenate(target, source, env): + fp = open(str(target[0]), 'wb') + for s in source: + fp.write(open(str(s), 'rb').read()) + fp.close() + +env['BUILDERS']['Concatenate'] = Builder(action=concatenate) + +f_in = Glob('f*.in', strings=True) +f_in.sort() +env.Concatenate('f.out', f_in) +""") + +test.write(['src', 'f1.in'], "src/f1.in\n") +test.write(['src', 'f2.in'], "src/f2.in\n") +test.write(['src', 'f3.in'], "src/f3.in\n") + +test.run(arguments = '.') + +test.must_match(['var1', 'f.out'], "src/f1.in\nsrc/f2.in\nsrc/f3.in\n") +test.must_match(['var2', 'f.out'], "src/f1.in\nsrc/f2.in\nsrc/f3.in\n") + +test.pass_test() diff --git a/test/Glob/subdir.py b/test/Glob/subdir.py new file mode 100644 index 0000000..b4e89e8 --- /dev/null +++ b/test/Glob/subdir.py @@ -0,0 +1,60 @@ +#!/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__" + +""" +Verify that Glob() works to find Nodes underneath an explicitly- +named subdirectory. +""" + +import TestSCons + +test = TestSCons.TestSCons() + +test.subdir('subdir') + +test.write('SConstruct', """\ +env = Environment() + +def concatenate(target, source, env): + fp = open(str(target[0]), 'wb') + for s in source: + fp.write(open(str(s), 'rb').read()) + fp.close() + +env['BUILDERS']['Concatenate'] = Builder(action=concatenate) + +f_in = Glob('subdir/*.in') +f_in.sort(lambda a,b: cmp(a.name, b.name)) +env.Concatenate('f.out', f_in) +""") + +test.write(['subdir', 'file.in'], "subdir/file.in\n") + +test.run(arguments = '.') + +test.must_match('f.out', "subdir/file.in\n") + +test.pass_test() diff --git a/test/Glob/subst.py b/test/Glob/subst.py new file mode 100644 index 0000000..e6aa3ca --- /dev/null +++ b/test/Glob/subst.py @@ -0,0 +1,60 @@ +#!/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__" + +""" +Verify the ability to Glob() using a pattern from a construction variable +expansion. +""" + +import TestSCons + +test = TestSCons.TestSCons() + +test.write('SConstruct', """\ +env = Environment(PATTERN = 'f*.in') + +def copy(target, source, env): + fp = open(str(target[0]), 'wb') + for s in source: + fp.write(open(str(s), 'rb').read()) + fp.close() + +env['BUILDERS']['Copy'] = Builder(action=copy) + +f_in = env.Glob('$PATTERN') +f_in.sort(lambda a,b: cmp(a.name, b.name)) +env.Copy('f.out', f_in) +""") + +test.write('f1.in', "f1.in\n") +test.write('f2.in', "f2.in\n") +test.write('f3.in', "f3.in\n") + +test.run(arguments = '.') + +test.must_match('f.out', "f1.in\nf2.in\nf3.in\n") + +test.pass_test() diff --git a/test/Install/Clone.py b/test/Install/Clone.py new file mode 100644 index 0000000..65770d2 --- /dev/null +++ b/test/Install/Clone.py @@ -0,0 +1,69 @@ +#!/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__" + +""" +Verify that we can Install() and InstallAs() from a construction +environment cloned from a clone. +""" + +import TestSCons + +test = TestSCons.TestSCons() + +test.write('SConstruct', """ +env1 = Environment(DESTDIR='sub1', tools=[]) + +# Call env1.Install() but not env1.InstallAs() *before* we clone it. +# This is to verify that re-initializing the Install() attribute on the +# construction environment doesn't mess up the environment settings in +# a way that leaves the InstallAs() intializer in place, which leads to +# infinite recursion. +env1.Install('$DESTDIR', 'foo.in') + +env2 = env1.Clone(DESTDIR='sub2') +env3 = env2.Clone(DESTDIR='sub3') + +env2.Install('$DESTDIR', 'foo.in') +env3.Install('$DESTDIR', 'foo.in') + +env1.InstallAs('$DESTDIR/foo.out', 'foo.in') +env2.InstallAs('$DESTDIR/foo.out', 'foo.in') +env3.InstallAs('$DESTDIR/foo.out', 'foo.in') +""") + +test.write('foo.in', "foo.in\n") + +test.run(arguments = '.') + +test.must_match(['sub1', 'foo.in'], "foo.in\n") +test.must_match(['sub2', 'foo.in'], "foo.in\n") +test.must_match(['sub3', 'foo.in'], "foo.in\n") + +test.must_match(['sub1', 'foo.out'], "foo.in\n") +test.must_match(['sub2', 'foo.out'], "foo.in\n") +test.must_match(['sub3', 'foo.out'], "foo.in\n") + +test.pass_test() diff --git a/test/LINK/SHLINKCOMSTR.py b/test/LINK/SHLINKCOMSTR.py index cf31813..94740b8 100644 --- a/test/LINK/SHLINKCOMSTR.py +++ b/test/LINK/SHLINKCOMSTR.py @@ -64,6 +64,7 @@ test.write('SConstruct', """ env = Environment(SHCCCOM = r'%(_python_)s mycc.py $TARGET $SOURCES', SHLINKCOM = r'%(_python_)s mylink.py $TARGET $SOURCES', SHLINKCOMSTR = 'Linking shared $TARGET from $SOURCES', + SHOBJPREFIX = '', SHOBJSUFFIX = '.obj', SHLIBPREFIX = '', SHLIBSUFFIX = '.dll') diff --git a/test/Library.py b/test/Library.py index 3a04b9c..4bcb2c7 100644 --- a/test/Library.py +++ b/test/Library.py @@ -114,7 +114,7 @@ void f3c(void); int main(int argc, char *argv[]) { - argv[argc++] = "--"; + argv[argc++] = (char *)"--"; f1(); f2a(); f2b(); diff --git a/test/MSVC/multiple-pdb.py b/test/MSVC/multiple-pdb.py index f359fb9..feb3fd9 100644 --- a/test/MSVC/multiple-pdb.py +++ b/test/MSVC/multiple-pdb.py @@ -46,7 +46,7 @@ if sys.platform != 'win32': test.skip_test(msg)
test.write('SConstruct', """\
-env = Environment(PDB = '${TARGET}.pdb')
+env = Environment(PDB = '${TARGET.base}.pdb')
env.Program('test1.cpp')
env.Program('test2.cpp')
""")
@@ -75,9 +75,9 @@ main(int argc, char *argv) test.run(arguments = '.')
-test.must_exist('test1%s' % _exe)
-test.must_exist('test1%s.pdb' % _exe)
-test.must_exist('test2%s' % _exe)
-test.must_exist('test2%s.pdb' % _exe)
+test.must_exist('test1%s' % _exe)
+test.must_exist('test1.pdb')
+test.must_exist('test2%s' % _exe)
+test.must_exist('test2.pdb')
test.pass_test()
diff --git a/test/Mkdir.py b/test/Mkdir.py index cbf465e..00b222b 100644 --- a/test/Mkdir.py +++ b/test/Mkdir.py @@ -38,6 +38,7 @@ test.subdir('work1', 'work2') test.write(['work1', 'SConstruct'], """ Execute(Mkdir('d1')) +Execute(Mkdir(Dir('#d1-Dir'))) def cat(env, source, target): target = str(target[0]) source = map(str, source) @@ -64,7 +65,7 @@ test.write(['work1', 'f2.in'], "f2.in\n") test.write(['work1', 'f5.in'], "f5.in\n") test.write(['work1', 'f6.in'], "f6.in\n") -expect = test.wrap_stdout(read_str = 'Mkdir("d1")\n', +expect = test.wrap_stdout(read_str = 'Mkdir("d1")\nMkdir("d1-Dir")\n', build_str = """\ cat(["f2.out"], ["f2.in"]) Mkdir("d3") @@ -79,6 +80,7 @@ Touch("%s") test.run(chdir = 'work1', options = '-n', arguments = '.', stdout = expect) test.must_not_exist(['work1', 'd1']) +test.must_not_exist(['work1', 'd1-Dir']) test.must_not_exist(['work1', 'f2.out']) test.must_not_exist(['work1', 'd3']) test.must_not_exist(['work1', 'd4']) @@ -90,6 +92,7 @@ test.must_not_exist(['work1', 'f6.out-Mkdir']) test.run(chdir = 'work1') test.must_exist(['work1', 'd1']) +test.must_exist(['work1', 'd1-Dir']) test.must_match(['work1', 'f2.out'], "f2.in\n") test.must_exist(['work1', 'd3']) test.must_exist(['work1', 'd4']) diff --git a/test/Move.py b/test/Move.py index c1cdcfd..ba55581 100644 --- a/test/Move.py +++ b/test/Move.py @@ -34,6 +34,7 @@ test = TestSCons.TestSCons() test.write('SConstruct', """ Execute(Move('f1.out', 'f1.in')) +Execute(Move('File-f1.out', File('f1.in-File'))) def cat(env, source, target): target = str(target[0]) source = map(str, source) @@ -50,6 +51,7 @@ env.Command('f6.out', 'f6.in', [Cat, Move("Move-$TARGET", "$SOURCE-Move")]) """) test.write('f1.in', "f1.in\n") +test.write('f1.in-File', "f1.in-File\n") test.write('f2.in', "f2.in\n") test.write('f3.in', "f3.in\n") test.write('f4.in', "f4.in\n") @@ -57,7 +59,10 @@ test.write('f5.in', "f5.in\n") test.write('f6.in', "f6.in\n") test.write('f6.in-Move', "f6.in-Move\n") -expect = test.wrap_stdout(read_str = 'Move("f1.out", "f1.in")\n', +expect = test.wrap_stdout(read_str = """\ +Move("f1.out", "f1.in") +Move("File-f1.out", "f1.in-File") +""", build_str = """\ cat(["f2.out"], ["f2.in"]) Move("f3.out", "f3.in") @@ -69,6 +74,7 @@ Move("Move-f6.out", "f6.in-Move") test.run(options = '-n', arguments = '.', stdout = expect) test.must_not_exist('f1.out') +test.must_not_exist('File-f1.out') test.must_not_exist('f2.out') test.must_not_exist('f3.out') test.must_not_exist('f4.out') @@ -79,6 +85,7 @@ test.must_not_exist('Move-f6.out') test.run() test.must_match('f1.out', "f1.in\n") +test.must_match('File-f1.out', "f1.in-File\n") test.must_match('f2.out', "f2.in\n") test.must_not_exist('f3.in') test.must_match('f3.out', "f3.in\n") diff --git a/test/NodeOps.py b/test/NodeOps.py index 7e656f7..b23a8d4 100644 --- a/test/NodeOps.py +++ b/test/NodeOps.py @@ -59,8 +59,8 @@ barflags = e['SHCXXFLAGS'] + ' -DBAR' test.subdir('bld', 'src', ['src', 'subsrcdir']) sconstruct = r""" -foo = Environment(SHCXXFLAGS = '%(fooflags)s', WINDOWS_INSERT_DEF=1) -bar = Environment(SHCXXFLAGS = '%(barflags)s', WINDOWS_INSERT_DEF=1) +foo = Environment(SHOBJPREFIX='', SHCXXFLAGS = '%(fooflags)s', WINDOWS_INSERT_DEF=1) +bar = Environment(SHOBJPREFIX='', SHCXXFLAGS = '%(barflags)s', WINDOWS_INSERT_DEF=1) src = Dir('src') BuildDir('bld', src, duplicate=1) Nodes=[] diff --git a/test/Object.py b/test/Object.py index da945e3..108960d 100644 --- a/test/Object.py +++ b/test/Object.py @@ -100,7 +100,7 @@ extern "C" void f3(void); int main(int argc, char *argv[]) { - argv[argc++] = "--"; + argv[argc++] = (char *)"--"; f1(); f2(); f3(); diff --git a/test/Options/chdir.py b/test/Options/chdir.py new file mode 100644 index 0000000..7ba85ea --- /dev/null +++ b/test/Options/chdir.py @@ -0,0 +1,71 @@ +#!/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__" + +""" +Verify that we can chdir() to the directory in which an Options +file lives by using the __name__ value. +""" + +import TestSCons + +test = TestSCons.TestSCons() + +test.subdir('bin', 'subdir') + +test.write('SConstruct', """\ +opts = Options('../bin/opts.cfg', ARGUMENTS) +opts.Add('VARIABLE') +Export("opts") +SConscript('subdir/SConscript') +""") + +SConscript_contents = """\ +Import("opts") +env = Environment() +opts.Update(env) +print "VARIABLE =", repr(env['VARIABLE']) +""" + +test.write(['bin', 'opts.cfg'], """\ +import os +import os.path +os.chdir(os.path.split(__name__)[0]) +execfile('opts2.cfg') +""") + +test.write(['bin', 'opts2.cfg'], """\ +VARIABLE = 'opts2.cfg value' +""") + +test.write(['subdir', 'SConscript'], SConscript_contents) + +expect = """\ +VARIABLE = 'opts2.cfg value' +""" + +test.run(arguments = '-q -Q .', stdout=expect) + +test.pass_test() diff --git a/test/Options/import.py b/test/Options/import.py new file mode 100644 index 0000000..0a3d367 --- /dev/null +++ b/test/Options/import.py @@ -0,0 +1,69 @@ +#!/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__" + +""" +Verify that an Options file in a different directory can import +a module in that directory. +""" + +import TestSCons + +test = TestSCons.TestSCons() + +workpath = test.workpath('') + +test.subdir('bin', 'subdir') + +test.write('SConstruct', """\ +opts = Options('../bin/opts.cfg', ARGUMENTS) +opts.Add('VARIABLE') +Export("opts") +SConscript('subdir/SConscript') +""") + +SConscript_contents = """\ +Import("opts") +env = Environment() +opts.Update(env) +print "VARIABLE =", env.get('VARIABLE') +""" + +test.write(['bin', 'opts.cfg'], """\ +import sys +from local_options import VARIABLE +""" % locals()) + +test.write(['bin', 'local_options.py'], """\ +VARIABLE = 'bin/local_options.py' +""") + +test.write(['subdir', 'SConscript'], SConscript_contents) + +expect = "VARIABLE = bin/local_options.py\n" + +test.run(arguments = '-q -Q .', stdout = expect) + +test.pass_test() diff --git a/test/Parallel/duplicate-target.py b/test/Parallel/duplicate-target.py index 5d4f5e1..43015fe 100644 --- a/test/Parallel/duplicate-target.py +++ b/test/Parallel/duplicate-target.py @@ -41,34 +41,58 @@ _python_ = TestSCons._python_ test = TestSCons.TestSCons() -test.subdir('work') +test.subdir('work', ['work', 'sub']) tar_output = test.workpath('work.tar') -test.write(['work', 'copy.py'], """\ +test.write(['work', 'mycopy.py'], """\ import sys import time time.sleep(int(sys.argv[1])) open(sys.argv[2], 'wb').write(open(sys.argv[3], 'rb').read()) """) +test.write(['work', 'mytar.py'], """\ +import sys +import os.path + +def visit(arg, dirname, fnames): + fnames.sort() + for fn in fnames: + p = os.path.join(dirname, fn) + if os.path.isfile(p): + arg.write(open(p, 'rb').read()) + +fp = open(sys.argv[1], 'wb') +for s in sys.argv[2:]: + os.path.walk(s, visit, fp) +""") + test.write(['work', 'SConstruct'], """\ env = Environment() -out1 = File('f1.out') -out2 = File('f2.out') -env.Command([out1, out1], 'f1.in', r'%(_python_)s copy.py 3 $TARGET $SOURCE') -env.Command([out2, out2], 'f2.in', r'%(_python_)s copy.py 3 $TARGET $SOURCE') +out1 = File('sub/f1.out') +out2 = File('sub/f2.out') +env.Command([out1, out1], 'sub/f1.in', + r'%(_python_)s mycopy.py 3 $TARGET $SOURCE') +env.Command([out2, out2], 'sub/f2.in', + r'%(_python_)s mycopy.py 3 $TARGET $SOURCE') -env.Tar(r'%(tar_output)s', Dir('.')) +env.Command(r'%(tar_output)s', Dir('sub'), + r'%(_python_)s mytar.py $TARGET $SOURCE') """ % locals()) -test.write(['work', 'f1.in'], "work/f1.in\n") -test.write(['work', 'f2.in'], "work/f2.in\n") +test.write(['work', 'sub', 'f1.in'], "work/sub/f1.in\n") +test.write(['work', 'sub', 'f2.in'], "work/sub/f2.in\n") test.run(chdir = 'work', arguments = tar_output + ' -j2') -test.must_match(['work', 'f1.out'], "work/f1.in\n") -test.must_match(['work', 'f2.out'], "work/f2.in\n") -test.must_exist(tar_output) +test.must_match(['work', 'sub', 'f1.out'], "work/sub/f1.in\n") +test.must_match(['work', 'sub', 'f2.out'], "work/sub/f2.in\n") +test.must_match(tar_output, """\ +work/sub/f1.in +work/sub/f1.in +work/sub/f2.in +work/sub/f2.in +""") test.pass_test() diff --git a/test/Parallel/failed-build.py b/test/Parallel/failed-build.py new file mode 100644 index 0000000..64e90c9 --- /dev/null +++ b/test/Parallel/failed-build.py @@ -0,0 +1,111 @@ +#!/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. +# + +""" +Verify that a failed build action with -j works as expected. +""" + +__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" + +import TestSCons + +_python_ = TestSCons._python_ + +try: + import threading +except ImportError: + # if threads are not supported, then + # there is nothing to test + TestCmd.no_result() + sys.exit() + + +test = TestSCons.TestSCons() + +# We want to verify that -j 2 starts precisely two jobs, the first of +# which fails and the second of which succeeds, and then stops processing +# due to the first build failure. To try to control the timing, the two +# created build scripts use a pair of marker directories. +# +# The failure script waits until it sees the 'mycopy.started' directory +# that indicates the successful script has, in fact, gotten started. +# If we don't wait, then SCons could detect our script failure early +# (typically if a high system load happens to delay SCons' ability to +# start the next script) and then not start the successful script at all. +# +# The successful script waits until it sees the 'myfail.exiting' directory +# that indicates the failure script has finished (with everything except +# the final sys.exit(), that is). If we don't wait for that, then SCons +# could detect our successful exit first (typically if a high system +# load happens to delay the failure script) and start another job before +# it sees the failure from the first script. + +test.write('myfail.py', r"""\ +import os.path +import sys +import time +while not os.path.exists('mycopy.started'): + time.sleep(1) +os.mkdir('myfail.exiting') +sys.exit(1) +""") + +test.write('mycopy.py', r"""\ +import os +import sys +import time +os.mkdir('mycopy.started') +open(sys.argv[1], 'wb').write(open(sys.argv[2], 'rb').read()) +while not os.path.exists('myfail.exiting'): + time.sleep(1) +sys.exit(0) +""") + +test.write('SConstruct', """ +MyCopy = Builder(action = r'%(_python_)s mycopy.py $TARGET $SOURCE') +Fail = Builder(action = r'%(_python_)s myfail.py $TARGETS $SOURCE') +env = Environment(BUILDERS = { 'MyCopy' : MyCopy, 'Fail' : Fail }) +env.Fail(target = 'f3', source = 'f3.in') +env.MyCopy(target = 'f4', source = 'f4.in') +env.MyCopy(target = 'f5', source = 'f5.in') +env.MyCopy(target = 'f6', source = 'f6.in') +""" % locals()) + +test.write('f3.in', "f3.in\n") +test.write('f4.in', "f4.in\n") +test.write('f5.in', "f5.in\n") +test.write('f6.in', "f6.in\n") + +test.run(arguments = '-j 2 .', + status = 2, + stderr = "scons: *** [f3] Error 1\n") + +test.must_not_exist(test.workpath('f3')) +test.must_match(test.workpath('f4'), 'f4.in\n') +test.must_not_exist(test.workpath('f5')) +test.must_not_exist(test.workpath('f6')) + + + +test.pass_test() diff --git a/test/Repository/variants.py b/test/Repository/variants.py index cd4c24a..d124431 100644 --- a/test/Repository/variants.py +++ b/test/Repository/variants.py @@ -204,7 +204,8 @@ test.write(['repository', 'src2', 'xxx', 'main.c'], r""" #ifdef BAR #define MAIN_OS "BAR" #endif -main() +int +main(int argc, char *argv[]) { printf(INCLUDE_STRING, INCLUDE_OS); printf(XXX_STRING, XXX_OS); diff --git a/test/Requires/basic.py b/test/Requires/basic.py new file mode 100644 index 0000000..59cdd37 --- /dev/null +++ b/test/Requires/basic.py @@ -0,0 +1,95 @@ +#!/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__" + +""" +Verify basic operation of the env.Requires() method for specifying +order-only prerequisites. +""" + +import TestSCons + +test = TestSCons.TestSCons() + +test.write('SConstruct', """ +def append_prereq_func(target, source, env): + fp = open(str(target[0]), 'wb') + for s in map(str, source): + fp.write(open(s, 'rb').read()) + fp.write(open('prereq.out', 'rb').read()) + fp.close() + return None +append_prereq = Action(append_prereq_func) +env = Environment() +env.Requires('file.out', 'prereq.out') +env.Command('file.out', 'file.in', append_prereq) +env.Command('prereq.out', 'prereq.in', Copy('$TARGET', '$SOURCES')) +""") + +test.write('file.in', "file.in 1\n") +test.write('prereq.in', "prereq.in 1\n") + +# First: build file.out. prereq.out should be built first, and if +# not, we'll get an error when the build action tries to use it to +# build file.out. + +test.run(arguments = 'file.out') + +test.must_match('prereq.out', "prereq.in 1\n") +test.must_match('file.out', "file.in 1\nprereq.in 1\n") + +# Update the prereq.out file. file.out should still be up to date because +# prereq.out is not actually a dependency, so we don't detect the +# underlying change. + +test.write('prereq.out', "prereq.out 2\n") + +test.up_to_date(arguments = 'file.out') + +# Now update the prereq.in file. Trying to rebuild file.out should +# cause prereq.out to be updated because of the change, but file.out +# should *not* be rebuilt because, again, prereq.out isn't actually +# a dependency that causes rebuilds. + +test.write('prereq.in', "prereq.in 3\n") + +test.run(arguments = 'file.out') + +test.must_match('prereq.out', "prereq.in 3\n") +test.must_match('file.out', "file.in 1\nprereq.in 1\n") + +# Now update file.in, which will cause file.out to be rebuilt, picking +# up the change(s) to prereq.out of which we were previously oblivious. + +test.write('file.in', 'file.in 4\n') + +test.run(arguments = 'file.out') + +test.must_match('prereq.out', "prereq.in 3\n") +test.must_match('file.out', "file.in 4\nprereq.in 3\n") + + + +test.pass_test() diff --git a/test/Scanner/no-Dir-node.py b/test/Scanner/no-Dir-node.py new file mode 100644 index 0000000..b5706e3 --- /dev/null +++ b/test/Scanner/no-Dir-node.py @@ -0,0 +1,136 @@ +#!/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__" + +""" +Verify that use of a Scanner that searches a *PATH list doesn't create +nodes for directories that don't exist, so they don't get picked up +by DirScanner. + +Under the covers, this tests the behavior of the SCons.Node.FS.find_file() +utility function that is used by the Scanner.Classic class to search +directories in variables such as $CPPPATH. +""" + +import os.path + +import TestSCons + +_python_ = TestSCons._python_ + +test = TestSCons.TestSCons() + +subdir_SConscript = os.path.join('subdir', 'SConscript') +subdir_foo = os.path.join('subdir', 'foo') +subdir_foo_k = os.path.join('subdir', 'foo.k') + +test.subdir('subdir', 'inc1', 'inc2') + +inc2_include_h = test.workpath('inc2', 'include.h') + +test.write('build.py', r""" +import os.path +import string +import sys +path = string.split(sys.argv[1]) +input = open(sys.argv[2], 'rb') +output = open(sys.argv[3], 'wb') + +def find_file(f): + if os.path.isabs(f): + return open(f, 'rb') + for dir in path: + p = dir + os.sep + f + if os.path.exists(p): + return open(p, 'rb') + return None + +def process(infp, outfp): + for line in infp.readlines(): + if line[:8] == 'include ': + file = line[8:-1] + process(find_file(file), outfp) + else: + outfp.write(line) + +process(input, output) + +sys.exit(0) +""") + +test.write('SConstruct', """\ +def foo(target, source, env): + children = source[0].children() + children.sort(lambda a,b: cmp(a.name, b.name)) + fp = open(str(target[0]), 'wb') + for c in children: + fp.write('%s\\n' % c) + fp.close() +Command('list.out', 'subdir', foo, source_scanner = DirScanner) +SConscript('subdir/SConscript') +""") + +test.write(['subdir', 'SConscript'], """\ +import SCons.Scanner +kscan = SCons.Scanner.Classic(name = 'kfile', + suffixes = ['.k'], + path_variable = 'KPATH', + regex = r'^include\s+(\S+)$') + +env = Environment(KPATH=['.', '..']) +env.Append(SCANNERS = kscan) + +env.Command('foo', 'foo.k', r'%(_python_)s build.py "$KPATH" $SOURCES $TARGET') +""" % locals()) + +test.write(['subdir', 'foo.k'], """\ +subdir/foo.k +include inc1/include.h +include %(inc2_include_h)s +""" % locals()) + +test.write(['inc1', 'include.h'], """\ +inc1/include.h +""") + +test.write(['inc2', 'include.h'], """\ +inc2/include.h +""") + +test.run(arguments = '.') + +test.must_match('subdir/foo', """\ +subdir/foo.k +inc1/include.h +inc2/include.h +""") + +test.must_match('list.out', """\ +%(subdir_SConscript)s +%(subdir_foo)s +%(subdir_foo_k)s +""" % locals()) + +test.pass_test() diff --git a/test/Touch.py b/test/Touch.py index b41db25..6ecc3ff 100644 --- a/test/Touch.py +++ b/test/Touch.py @@ -36,6 +36,7 @@ test = TestSCons.TestSCons() test.write('SConstruct', """ Execute(Touch('f1')) +Execute(Touch(File('f1-File'))) def cat(env, source, target): target = str(target[0]) source = map(str, source) @@ -54,13 +55,18 @@ env.Command('f6.out', 'f6.in', [Cat, """) test.write('f1', "f1\n") +test.write('f1-File', "f1-File\n") test.write('f2.in', "f2.in\n") test.write('f5.in', "f5.in\n") test.write('f6.in', "f6.in\n") -oldtime = os.path.getmtime(test.workpath('f1')) +old_f1_time = os.path.getmtime(test.workpath('f1')) +old_f1_File_time = os.path.getmtime(test.workpath('f1-File')) -expect = test.wrap_stdout(read_str = 'Touch("f1")\n', +expect = test.wrap_stdout(read_str = """\ +Touch("f1") +Touch("f1-File") +""", build_str = """\ cat(["f2.out"], ["f2.in"]) Touch("f3") @@ -74,8 +80,10 @@ test.run(options = '-n', arguments = '.', stdout = expect) test.sleep(2) -newtime = os.path.getmtime(test.workpath('f1')) -test.fail_test(oldtime != newtime) +new_f1_time = os.path.getmtime(test.workpath('f1')) +test.fail_test(old_f1_time != new_f1_time) +new_f1_File_time = os.path.getmtime(test.workpath('f1-File')) +test.fail_test(old_f1_File_time != new_f1_File_time) test.must_not_exist(test.workpath('f2.out')) test.must_not_exist(test.workpath('f3')) @@ -87,8 +95,10 @@ test.must_not_exist(test.workpath('f6.out-Touch')) test.run() -newtime = os.path.getmtime(test.workpath('f1')) -test.fail_test(oldtime == newtime) +new_f1_time = os.path.getmtime(test.workpath('f1')) +test.fail_test(old_f1_time == new_f1_time) +new_f1_File_time = os.path.getmtime(test.workpath('f1-File')) +test.fail_test(old_f1_File_time == new_f1_File_time) test.must_match('f2.out', "f2.in\n") test.must_exist(test.workpath('f3')) diff --git a/test/implicit-cache/DualTargets.py b/test/implicit-cache/DualTargets.py new file mode 100644 index 0000000..cf41640 --- /dev/null +++ b/test/implicit-cache/DualTargets.py @@ -0,0 +1,137 @@ +#!/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__" + +""" +Test that --implicit-cache works correctly in conjonction with a +builder that produces multiple targets. +""" + +import string + +import TestSCons + +test = TestSCons.TestSCons() + +test.write('SConstruct', """\ +import os.path + +def emitter(target, source, env): + tgt0 = target[0].abspath + base,ext = os.path.splitext(tgt0) + target.append(base + '.b') + return(target, source) + + +def source_scan(node, env, path): + path = node.abspath + base,ext = os.path.splitext(path) + return [base + '.lib'] + + +env = Environment() +env['BUILDERS']['DualTarget'] = Builder( + action = Action( + [ + Copy( '$TARGET', '$SOURCE' ), + Copy( '${TARGET.base}.b', '$SOURCE' ), + ], + ), + suffix = '.a', + src_suffix = '.cpp', + single_source = True, + emitter=emitter, + source_scanner=Scanner(source_scan), + ) + +env.Command( 'x.cpp', '', Touch('$TARGET') ) +env.Command( 'x.lib', '', Touch('$TARGET') ) + +env.DualTarget('x.cpp') +""" % locals()) + +test.must_not_exist('x.cpp') +test.must_not_exist('x.lib') +test.must_not_exist('x.a') +test.must_not_exist('x.b') + +# Build everything first. +test.run(arguments = '.') +test.must_exist('x.cpp') +test.must_exist('x.lib') +test.must_exist('x.a') +test.must_exist('x.b') + +test.fail_test(string.find(test.stdout(), 'Copy') == -1) + +# Double check that targets are not rebuilt. +test.run(arguments = '.') +test.must_exist('x.cpp') +test.must_exist('x.lib') +test.must_exist('x.a') +test.must_exist('x.b') + +test.fail_test(string.find(test.stdout(), 'Copy') != -1) + +# Double check that targets are not rebuilt even with --implicit-cache +test.run(arguments = '--implicit-cache x.a') +test.must_exist('x.cpp') +test.must_exist('x.lib') +test.must_exist('x.a') +test.must_exist('x.b') + +test.fail_test(string.find(test.stdout(), 'Copy') != -1) + +# Double check that targets are not rebuilt even with --implicit-cache +# a second time. +test.run(arguments = '--implicit-cache x.a') +test.must_exist('x.cpp') +test.must_exist('x.lib') +test.must_exist('x.a') +test.must_exist('x.b') + +test.fail_test(string.find(test.stdout(), 'Copy') != -1) + +# Double check that targets are not rebuilt if we reran without +# --implicit-cache +test.run(arguments = '.') +test.must_exist('x.cpp') +test.must_exist('x.lib') +test.must_exist('x.a') +test.must_exist('x.b') + +test.fail_test(string.find(test.stdout(), 'Copy') != -1) + +# Double check again +test.run(arguments = '.') +test.must_exist('x.cpp') +test.must_exist('x.lib') +test.must_exist('x.a') +test.must_exist('x.b') + +test.fail_test(string.find(test.stdout(), 'Copy') != -1) + +# Then only of the targets using --implicit-cache +test.pass_test() diff --git a/test/no-global-dependencies.py b/test/no-global-dependencies.py new file mode 100644 index 0000000..3cdea1b --- /dev/null +++ b/test/no-global-dependencies.py @@ -0,0 +1,170 @@ +#!/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__" + +""" +Test that files are correctly located in the build directory even when +Scons does not have a global view of all targets. + +Sometimes, it might be interesting to not tell scons about every +targets. For example, one might not read in all the SConscipts of a +hierarchical build for a particular invocation of scons. This would be +done to speed-up a partial rebuild when the developer knows that only +a subset of the targets need to be rebuilt. +""" + +import string + +import TestSCons + +test = TestSCons.TestSCons() + +test.subdir('dir1') +test.subdir('dir2') + +test.write('SConstruct', """\ +opts = Options() +opts.AddOptions( + BoolOption('view_all_dependencies', 'View all dependencies', True), + BoolOption('duplicate', 'Duplicate sources to build dir', True) +) + +env = Environment(options=opts) +Export('env') + +SConscript(dirs='.', build_dir='build', duplicate=env['duplicate']) +""" % locals()) + + +test.write('SConscript', """\ +Import('env') + +if env['view_all_dependencies']: + SConscript(dirs='dir1') + +SConscript(dirs='dir2') +""" % locals()) + +test.write('dir1/SConscript', """\ +Import('env') + +env.Command('x.cpp', '', Touch('$TARGET')) + +env.Object(env.File('x.cpp')) +""" % locals()) + +test.write('dir2/SConscript', """\ +Import('env') + +env.Object(env.File('#/build/dir1/x.cpp')) +""" % locals()) + +test.must_not_exist('build/dir1/x.cpp') + + +############################################################ +# +# Test without duplication +# + +# Build everything first. +test.run(arguments = 'duplicate=False view_all_dependencies=True .') +test.must_exist('build/dir1/x.cpp') +test.fail_test(string.find(test.stdout(), "`.' is up to date.") != -1) + +# Double check that targets are not rebuilt. +test.run(arguments = 'duplicate=False view_all_dependencies=True .') +test.must_exist('build/dir1/x.cpp') +test.fail_test(string.find(test.stdout(), "`.' is up to date.") == -1) + +# Clean-up only the object file +test.run(arguments = 'duplicate=False view_all_dependencies=False -c .') +test.must_exist('build/dir1/x.cpp') + +# Rebuild the only object file without seeing all the dependencies. +test.run(arguments = 'duplicate=False view_all_dependencies=False .') +test.must_exist('build/dir1/x.cpp') +test.fail_test(string.find(test.stdout(), "`.' is up to date.") != -1) + +# Double check that targets are not rebuilt without and with all the +# dependencies. +test.run(arguments = 'duplicate=False view_all_dependencies=False .') +test.must_exist('build/dir1/x.cpp') +test.fail_test(string.find(test.stdout(), "`.' is up to date.") == -1) + +test.run(arguments = 'duplicate=False view_all_dependencies=True .') +test.must_exist('build/dir1/x.cpp') +test.fail_test(string.find(test.stdout(), "`.' is up to date.") == -1) + +# Clean-up everything. +test.run(arguments = 'duplicate=False view_all_dependencies=True -c .') +test.must_not_exist('build/dir1/x.cpp') + + +############################################################ +# +# Test with duplication +# +# FIXME: This can not work for now because there is no way that SCons +# can differentiate between a source that no longer exists and a file +# that has a builder that scons does not know about because scons has +# not parsed all the SConscript of a given project. +# + +# # Build everything first. +# test.run(arguments = 'duplicate=True view_all_dependencies=True .') +# test.must_exist('build/dir1/x.cpp') +# test.fail_test(string.find(test.stdout(), "`.' is up to date.") != -1) + +# # Double check that targets are not rebuilt. +# test.run(arguments = 'duplicate=True view_all_dependencies=True .') +# test.must_exist('build/dir1/x.cpp') +# test.fail_test(string.find(test.stdout(), "`.' is up to date.") == -1) + +# # Clean-up only the object file +# test.run(arguments = 'duplicate=True view_all_dependencies=False -c .') +# test.must_exist('build/dir1/x.cpp') + +# # Rebuild the only object file without seeing all the dependencies. +# test.run(arguments = 'duplicate=True view_all_dependencies=False .') +# test.must_exist('build/dir1/x.cpp') +# test.fail_test(string.find(test.stdout(), "`.' is up to date.") != -1) + +# # Double check that targets are not rebuilt without and with all the +# # dependencies. +# test.run(arguments = 'duplicate=True view_all_dependencies=False .') +# test.must_exist('build/dir1/x.cpp') +# test.fail_test(string.find(test.stdout(), "`.' is up to date.") == -1) + +# test.run(arguments = 'duplicate=True view_all_dependencies=True .') +# test.must_exist('build/dir1/x.cpp') +# test.fail_test(string.find(test.stdout(), "`.' is up to date.") == -1) + +# # Clean-up everything. +# test.run(arguments = 'duplicate=True view_all_dependencies=True -c .') +# test.must_not_exist('build/dir1/x.cpp') + + +test.pass_test() diff --git a/test/option-j.py b/test/option-j.py index bc36f08..ffb290c 100644 --- a/test/option-j.py +++ b/test/option-j.py @@ -218,42 +218,5 @@ start2, finish1 = RunTest('-j 1 f1 f2', "fourth") test.fail_test(start2 < finish1) -# Test that a failed build with -j works properly. - -test.write('mycopy.py', r"""\ -import sys -import time -time.sleep(1) -open(sys.argv[1], 'wb').write(open(sys.argv[2], 'rb').read()) -""") - -test.write('myfail.py', r"""\ -import sys -sys.exit(1) -""") - -test.write('SConstruct', """ -MyCopy = Builder(action = r'%(_python_)s mycopy.py $TARGET $SOURCE') -Fail = Builder(action = r'%(_python_)s myfail.py $TARGETS $SOURCE') -env = Environment(BUILDERS = { 'MyCopy' : MyCopy, 'Fail' : Fail }) -env.Fail(target = 'f3', source = 'f3.in') -env.MyCopy(target = 'f4', source = 'f4.in') -env.MyCopy(target = 'f5', source = 'f5.in') -env.MyCopy(target = 'f6', source = 'f6.in') -""" % locals()) - -test.write('f3.in', "f3.in\n") -test.write('f4.in', "f4.in\n") -test.write('f5.in', "f5.in\n") -test.write('f6.in', "f6.in\n") - -test.run(arguments = '-j 2 .', - status = 2, - stderr = "scons: *** [f3] Error 1\n") - -test.fail_test(os.path.exists(test.workpath('f3'))) -test.fail_test(test.read(test.workpath('f4')) != 'f4.in\n') -test.fail_test(os.path.exists(test.workpath('f5'))) -test.fail_test(os.path.exists(test.workpath('f6'))) test.pass_test() diff --git a/test/option/debug-dtree.py b/test/option/debug-dtree.py index 06296b9..3ef396e 100644 --- a/test/option/debug-dtree.py +++ b/test/option/debug-dtree.py @@ -56,6 +56,7 @@ int main(int argc, char *argv[]) test.write('bar.c', """ #include "bar.h" +int local = 1; """) test.write('foo.h', """ diff --git a/test/option/debug-includes.py b/test/option/debug-includes.py index 52d64a9..172cbb0 100644 --- a/test/option/debug-includes.py +++ b/test/option/debug-includes.py @@ -56,6 +56,7 @@ int main(int argc, char *argv[]) test.write('bar.c', """ #include "bar.h" +int local = 1; """) test.write('foo.h', """ diff --git a/test/option/debug-stree.py b/test/option/debug-stree.py index d25b7fa..bf65dbb 100644 --- a/test/option/debug-stree.py +++ b/test/option/debug-stree.py @@ -60,6 +60,7 @@ int main(int argc, char *argv[]) test.write('bar.c', """ #include "bar.h" +int local = 1; """) test.write('foo.h', """ diff --git a/test/option/debug-tree.py b/test/option/debug-tree.py index 09cdffb..f581bc4 100644 --- a/test/option/debug-tree.py +++ b/test/option/debug-tree.py @@ -64,6 +64,7 @@ int main(int argc, char *argv[]) test.write('Bar.c', """ #include "Bar.h" +int local = 1; """) test.write('Foo.h', """ diff --git a/test/option/tree-all.py b/test/option/tree-all.py index 7940d47..163d286 100644 --- a/test/option/tree-all.py +++ b/test/option/tree-all.py @@ -64,6 +64,7 @@ int main(int argc, char *argv[]) test.write('Bar.c', """ #include "Bar.h" +int local = 1; """) test.write('Foo.h', """ diff --git a/test/option/tree-derived.py b/test/option/tree-derived.py index 3ccada8..43735f8 100644 --- a/test/option/tree-derived.py +++ b/test/option/tree-derived.py @@ -56,6 +56,7 @@ int main(int argc, char *argv[]) test.write('bar.c', """ #include "bar.h" +int local = 1; """) test.write('foo.h', """ diff --git a/test/packaging/multiple-packages-at-once.py b/test/packaging/multiple-packages-at-once.py index 3151c05..bbf273f 100644 --- a/test/packaging/multiple-packages-at-once.py +++ b/test/packaging/multiple-packages-at-once.py @@ -79,4 +79,21 @@ test.run(arguments='', stderr = None) test.must_exist( 'src-1.0.zip' ) test.must_exist( 'src-1.0.tar.gz' ) +test.write('SConstruct', """ +Program( 'src/main.c' ) +env=Environment(tools=['default', 'packaging']) +env.Package( PACKAGETYPE = ['src_zip', 'src_targz'], + NAME = "src", VERSION = "1.0", + PACKAGEROOT = 'test', + source = [ 'src/main.c', 'SConstruct' ], + target = 'src.zip' ) +""") + +test.run(arguments='', stderr = None) + +test.must_exist( 'src.zip' ) +test.must_exist( 'src-1.0.tar.gz' ) + + + test.pass_test() diff --git a/test/packaging/rpm/explicit-target.py b/test/packaging/rpm/explicit-target.py index 12a6c6c..b9fcc0f 100644 --- a/test/packaging/rpm/explicit-target.py +++ b/test/packaging/rpm/explicit-target.py @@ -31,7 +31,6 @@ Test the ability to create a rpm package from a explicit target name. import os import TestSCons -machine = TestSCons.machine _python_ = TestSCons._python_ test = TestSCons.TestSCons() @@ -81,15 +80,10 @@ env.Package( NAME = 'foo', ) """ % locals()) -test.run(arguments='', stderr = None) +expect = """ +scons: *** Setting target is not supported for rpm. +""" + test.python_file_line(test.workpath('SConstruct'), 24) -src_rpm = 'foo-1.2.3-0.src.rpm' -machine_rpm = 'foo-1.2.3-0.%s.rpm' % machine - -test.must_exist( machine_rpm ) -test.must_exist( src_rpm ) -test.must_not_exist( 'bin/main' ) -test.fail_test( not os.popen('rpm -qpl %s' % machine_rpm).read()=='/bin/main\n') -test.fail_test( not os.popen('rpm -qpl %s' % src_rpm).read()=='foo-1.2.3.spec\nfoo-1.2.3.tar.gz\n') +test.run(arguments='', status=2, stderr=expect) test.pass_test() diff --git a/test/sconsign/ghost-entries.py b/test/sconsign/ghost-entries.py new file mode 100644 index 0000000..45426ad --- /dev/null +++ b/test/sconsign/ghost-entries.py @@ -0,0 +1,111 @@ +#!/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__" + +""" +Verify that "ghost" entries in the .sconsign file don't have Nodes +created for them on subsequent runs (which would cause errors +when scanning directories). +""" + +import os.path + +d_current_txt = os.path.join('d', 'current.txt') + +import TestSCons + +test = TestSCons.TestSCons() + +# This test case is from Morten Elo Petersen. It's harder because +# blib-case1only actually exists in the build dir after the -c, so the +# Dir scanner finds it and adds it to the dir's entries. +# Unfortunately FS.py's File.exists() method checks it later and finds +# it looks like a stale build copy of a missing source, so it deletes +# it. And then it's later discovered to be missing since it's still +# in the dir's entries list. The fix for this is to test for missing +# source files in the dir scanner (Scanner/Dir.py), and delete them +# (just like File.exists() does if they're found in the build dir +# rather than making entries for them. + +test.write('SConstruct', """\ +def cat(target, source, env): + fp = open(str(target[0]), 'wb') + for s in source: + fp.write(open(str(s), 'rb').read()) + fp.close() +env=Environment() +Export('env') +env['BUILDERS']['Cat']=Builder(action=cat, multi=1) +SConscript('src/SConscript',build_dir='build') +""") + +test.subdir('src') +test.write(['src', 'SConscript'], """\ +Import('env') +if ARGUMENTS['case']=='1': + A=env.Cat('#build/lib/blib-case1only','src.txt') + B=env.Cat('#build/lib/blibB','#build/lib/blib-case1only') +if ARGUMENTS['case']=='2': + A=env.Cat('case2only','src.txt') + B=env.Cat('#build/lib/blibB.txt','case2only') +env.Alias('go','#build/lib') +""") + +test.write(['src', 'src.txt'], "anything") + +test.run(arguments="-Q go case=1") +test.must_exist('build/lib/blib-case1only') +test.run(arguments="-Q go case=2") +test.run(arguments="-Q go case=2 -c") +test.run(arguments="-Q go case=2") + + +############################################################################# +# This test case is from Jason Orendorff. +# Checking for existence before making nodes for things found in the +# .sconsign fixes this one. + +test.write('SConstruct', """\ +Command("d/current.txt", [], [Touch("$TARGET")]) +if ARGUMENTS.has_key('pass') and ARGUMENTS['pass'] == '1': + Command("d/obsolete.txt", [], [Touch("$TARGET")]) +Command("installer.exe", ['d'], [Touch("$TARGET")]) +""") + +test.run(arguments='-Q pass=1') + +# Now delete the created files +test.unlink(['d', 'obsolete.txt']) +test.unlink(['d', 'current.txt']) +test.rmdir(['d']) + +# Run again, as pass 2 +expect = """Touch("%(d_current_txt)s") +Touch("installer.exe") +""" % locals() + +test.run(arguments='-Q pass=2', stdout=expect) + +test.pass_test() diff --git a/test/sconsign/script/Configure.py b/test/sconsign/script/Configure.py index 8e17e95..19c8a1c 100644 --- a/test/sconsign/script/Configure.py +++ b/test/sconsign/script/Configure.py @@ -30,6 +30,7 @@ info in them (which have different BuildInfo entries). """ import os.path +import re import TestSCons import TestSConsign @@ -40,6 +41,8 @@ test = TestSConsign.TestSConsign(match = TestSConsign.match_re) CC = test.detect('CC', norm=1) CC_dir, CC_file = os.path.split(CC) +CC_dir = re.escape(os.path.normcase(CC_dir)) +CC_file = re.escape(CC_file) # Note: We don't use os.path.join() representations of the file names # in the expected output because paths in the .sconsign files are diff --git a/test/sconsign/script/SConsignFile.py b/test/sconsign/script/SConsignFile.py index 99845e3..54ecaaa 100644 --- a/test/sconsign/script/SConsignFile.py +++ b/test/sconsign/script/SConsignFile.py @@ -29,19 +29,61 @@ Verify that the sconsign script works with files generated when using the signatures in an SConsignFile(). """ -import os.path - +import TestSCons import TestSConsign -test = TestSConsign.TestSConsign(match = TestSConsign.match_re) +_python_ = TestSCons._python_ -CC = test.detect('CC', norm=1) -CC_dir, CC_file = os.path.split(CC) -LINK = test.detect('LINK', norm=1) -if LINK is None: LINK = CC +test = TestSConsign.TestSConsign(match = TestSConsign.match_re) test.subdir('sub1', 'sub2') +test.write('fake_cc.py', r""" +import os.path +import re +import string +import sys + +path = string.split(sys.argv[1]) +output = open(sys.argv[2], 'wb') +input = open(sys.argv[3], 'rb') + +output.write('fake_cc.py: %s\n' % sys.argv) + +def find_file(f): + for dir in path: + p = dir + os.sep + f + if os.path.exists(p): + return open(p, 'rb') + return None + +def process(infp, outfp): + for line in infp.readlines(): + m = re.match('#include <(.*)>', line) + if m: + file = m.group(1) + process(find_file(file), outfp) + else: + outfp.write(line) + +process(input, output) + +sys.exit(0) +""") + +test.write('fake_link.py', r""" +import sys + +output = open(sys.argv[1], 'wb') +input = open(sys.argv[2], 'rb') + +output.write('fake_link.py: %s\n' % sys.argv) + +output.write(input.read()) + +sys.exit(0) +""") + # Note: We don't use os.path.join() representations of the file names # in the expected output because paths in the .sconsign files are # canonicalized to use / as the separator. @@ -55,27 +97,20 @@ sub2_inc2_h = 'sub2/inc2.h' test.write(['SConstruct'], """\ SConsignFile() -env1 = Environment(PROGSUFFIX = '.exe', OBJSUFFIX = '.obj') +env1 = Environment(PROGSUFFIX = '.exe', + OBJSUFFIX = '.obj', + CCCOM = r'%(_python_)s fake_cc.py sub2 $TARGET $SOURCE', + LINKCOM = r'%(_python_)s fake_link.py $TARGET $SOURCE') env1.Program('sub1/hello.c') env2 = env1.Clone(CPPPATH = ['sub2']) env2.Program('sub2/hello.c') -""") +""" % locals()) -test.write(['sub1', 'hello.c'], r"""\ -#include <stdio.h> -#include <stdlib.h> -int -main(int argc, char *argv[]) -{ - argv[argc++] = "--"; - printf("sub1/hello.c\n"); - exit (0); -} +test.write(['sub1', 'hello.c'], r""" +sub1/hello.c """) -test.write(['sub2', 'hello.c'], r"""\ -#include <stdio.h> -#include <stdlib.h> +test.write(['sub2', 'hello.c'], r""" #include <inc1.h> #include <inc2.h> int @@ -102,29 +137,23 @@ sig_re = r'[0-9a-fA-F]{32}' test.run_sconsign(arguments = ".sconsign", stdout = r"""=== .: SConstruct: None \d+ \d+ -=== %(CC_dir)s: -%(CC_file)s: %(sig_re)s \d+ \d+ === sub1: hello.c: %(sig_re)s \d+ \d+ hello.exe: %(sig_re)s \d+ \d+ %(sub1_hello_obj)s: %(sig_re)s \d+ \d+ - %(LINK)s: %(sig_re)s \d+ \d+ %(sig_re)s \[.*\] hello.obj: %(sig_re)s \d+ \d+ %(sub1_hello_c)s: %(sig_re)s \d+ \d+ - %(CC)s: %(sig_re)s \d+ \d+ %(sig_re)s \[.*\] === sub2: hello.c: %(sig_re)s \d+ \d+ hello.exe: %(sig_re)s \d+ \d+ %(sub2_hello_obj)s: %(sig_re)s \d+ \d+ - %(LINK)s: %(sig_re)s \d+ \d+ %(sig_re)s \[.*\] hello.obj: %(sig_re)s \d+ \d+ %(sub2_hello_c)s: %(sig_re)s \d+ \d+ %(sub2_inc1_h)s: %(sig_re)s \d+ \d+ %(sub2_inc2_h)s: %(sig_re)s \d+ \d+ - %(CC)s: %(sig_re)s \d+ \d+ %(sig_re)s \[.*\] inc1.h: %(sig_re)s \d+ \d+ inc2.h: %(sig_re)s \d+ \d+ @@ -133,29 +162,23 @@ inc2.h: %(sig_re)s \d+ \d+ test.run_sconsign(arguments = "--raw .sconsign", stdout = r"""=== .: SConstruct: {'csig': None, 'timestamp': \d+, 'size': \d+L?, '_version_id': 1} -=== %(CC_dir)s: -%(CC_file)s: {'csig': '%(sig_re)s', 'timestamp': \d+, 'size': \d+L?, '_version_id': 1} === sub1: hello.c: {'csig': '%(sig_re)s', 'timestamp': \d+, 'size': \d+L?, '_version_id': 1} hello.exe: {'csig': '%(sig_re)s', 'timestamp': \d+, 'size': \d+L?, '_version_id': 1} %(sub1_hello_obj)s: {'csig': '%(sig_re)s', 'timestamp': \d+, 'size': \d+L?, '_version_id': 1} - %(LINK)s: {'csig': '%(sig_re)s', 'timestamp': \d+, 'size': \d+L?, '_version_id': 1} %(sig_re)s \[.*\] hello.obj: {'csig': '%(sig_re)s', 'timestamp': \d+, 'size': \d+L?, '_version_id': 1} %(sub1_hello_c)s: {'csig': '%(sig_re)s', 'timestamp': \d+, 'size': \d+L?, '_version_id': 1} - %(CC)s: {'csig': '%(sig_re)s', 'timestamp': \d+, 'size': \d+L?, '_version_id': 1} %(sig_re)s \[.*\] === sub2: hello.c: {'csig': '%(sig_re)s', 'timestamp': \d+, 'size': \d+L?, '_version_id': 1} hello.exe: {'csig': '%(sig_re)s', 'timestamp': \d+, 'size': \d+L?, '_version_id': 1} %(sub2_hello_obj)s: {'csig': '%(sig_re)s', 'timestamp': \d+, 'size': \d+L?, '_version_id': 1} - %(LINK)s: {'csig': '%(sig_re)s', 'timestamp': \d+, 'size': \d+L?, '_version_id': 1} %(sig_re)s \[.*\] hello.obj: {'csig': '%(sig_re)s', 'timestamp': \d+, 'size': \d+L?, '_version_id': 1} %(sub2_hello_c)s: {'csig': '%(sig_re)s', 'timestamp': \d+, 'size': \d+L?, '_version_id': 1} %(sub2_inc1_h)s: {'csig': '%(sig_re)s', 'timestamp': \d+, 'size': \d+L?, '_version_id': 1} %(sub2_inc2_h)s: {'csig': '%(sig_re)s', 'timestamp': \d+, 'size': \d+L?, '_version_id': 1} - %(CC)s: {'csig': '%(sig_re)s', 'timestamp': \d+, 'size': \d+L?, '_version_id': 1} %(sig_re)s \[.*\] inc1.h: {'csig': '%(sig_re)s', 'timestamp': \d+, 'size': \d+L?, '_version_id': 1} inc2.h: {'csig': '%(sig_re)s', 'timestamp': \d+, 'size': \d+L?, '_version_id': 1} @@ -166,11 +189,6 @@ SConstruct: csig: None timestamp: \d+ size: \d+ -=== %(CC_dir)s: -%(CC_file)s: - csig: %(sig_re)s - timestamp: \d+ - size: \d+ === sub1: hello.c: csig: %(sig_re)s @@ -185,10 +203,6 @@ hello.exe: csig: %(sig_re)s timestamp: \d+ size: \d+ - %(LINK)s: - csig: %(sig_re)s - timestamp: \d+ - size: \d+ action: %(sig_re)s \[.*\] hello.obj: csig: %(sig_re)s @@ -199,10 +213,6 @@ hello.obj: csig: %(sig_re)s timestamp: \d+ size: \d+ - %(CC)s: - csig: %(sig_re)s - timestamp: \d+ - size: \d+ action: %(sig_re)s \[.*\] === sub2: hello.c: @@ -218,10 +228,6 @@ hello.exe: csig: %(sig_re)s timestamp: \d+ size: \d+ - %(LINK)s: - csig: %(sig_re)s - timestamp: \d+ - size: \d+ action: %(sig_re)s \[.*\] hello.obj: csig: %(sig_re)s @@ -240,10 +246,6 @@ hello.obj: csig: %(sig_re)s timestamp: \d+ size: \d+ - %(CC)s: - csig: %(sig_re)s - timestamp: \d+ - size: \d+ action: %(sig_re)s \[.*\] inc1.h: csig: %(sig_re)s @@ -261,9 +263,6 @@ test.run_sconsign(arguments = "-c -v .sconsign", stdout = r"""=== .: SConstruct: csig: None -=== %(CC_dir)s: -%(CC_file)s: - csig: %(sig_re)s === sub1: hello.c: csig: %(sig_re)s @@ -288,9 +287,6 @@ test.run_sconsign(arguments = "-s -v .sconsign", stdout = r"""=== .: SConstruct: size: \d+ -=== %(CC_dir)s: -%(CC_file)s: - size: \d+ === sub1: hello.c: size: \d+ @@ -315,9 +311,6 @@ test.run_sconsign(arguments = "-t -v .sconsign", stdout = r"""=== .: SConstruct: timestamp: \d+ -=== %(CC_dir)s: -%(CC_file)s: - timestamp: \d+ === sub1: hello.c: timestamp: \d+ @@ -340,64 +333,50 @@ inc2.h: test.run_sconsign(arguments = "-e hello.obj .sconsign", stdout = r"""=== .: -=== %(CC_dir)s: === sub1: hello.obj: %(sig_re)s \d+ \d+ %(sub1_hello_c)s: %(sig_re)s \d+ \d+ - %(CC)s: %(sig_re)s \d+ \d+ %(sig_re)s \[.*\] === sub2: hello.obj: %(sig_re)s \d+ \d+ %(sub2_hello_c)s: %(sig_re)s \d+ \d+ %(sub2_inc1_h)s: %(sig_re)s \d+ \d+ %(sub2_inc2_h)s: %(sig_re)s \d+ \d+ - %(CC)s: %(sig_re)s \d+ \d+ %(sig_re)s \[.*\] """ % locals(), - stderr = r"""sconsign: no entry `hello.obj' in `\.' -sconsign: no entry `hello.obj' in `%(CC_dir)s' -""" % locals()) + stderr = r"""sconsign: no entry `hello.obj' in `\.' +""") test.run_sconsign(arguments = "-e hello.obj -e hello.exe -e hello.obj .sconsign", stdout = r"""=== .: -=== %(CC_dir)s: === sub1: hello.obj: %(sig_re)s \d+ \d+ %(sub1_hello_c)s: %(sig_re)s \d+ \d+ - %(CC)s: %(sig_re)s \d+ \d+ %(sig_re)s \[.*\] hello.exe: %(sig_re)s \d+ \d+ %(sub1_hello_obj)s: %(sig_re)s \d+ \d+ - %(LINK)s: %(sig_re)s \d+ \d+ %(sig_re)s \[.*\] hello.obj: %(sig_re)s \d+ \d+ %(sub1_hello_c)s: %(sig_re)s \d+ \d+ - %(CC)s: %(sig_re)s \d+ \d+ %(sig_re)s \[.*\] === sub2: hello.obj: %(sig_re)s \d+ \d+ %(sub2_hello_c)s: %(sig_re)s \d+ \d+ %(sub2_inc1_h)s: %(sig_re)s \d+ \d+ %(sub2_inc2_h)s: %(sig_re)s \d+ \d+ - %(CC)s: %(sig_re)s \d+ \d+ %(sig_re)s \[.*\] hello.exe: %(sig_re)s \d+ \d+ %(sub2_hello_obj)s: %(sig_re)s \d+ \d+ - %(LINK)s: %(sig_re)s \d+ \d+ %(sig_re)s \[.*\] hello.obj: %(sig_re)s \d+ \d+ %(sub2_hello_c)s: %(sig_re)s \d+ \d+ %(sub2_inc1_h)s: %(sig_re)s \d+ \d+ %(sub2_inc2_h)s: %(sig_re)s \d+ \d+ - %(CC)s: %(sig_re)s \d+ \d+ %(sig_re)s \[.*\] """ % locals(), stderr = r"""sconsign: no entry `hello.obj' in `\.' sconsign: no entry `hello.exe' in `\.' sconsign: no entry `hello.obj' in `\.' -sconsign: no entry `hello.obj' in `%(CC_dir)s' -sconsign: no entry `hello.exe' in `%(CC_dir)s' -sconsign: no entry `hello.obj' in `%(CC_dir)s' """ % locals()) #test.run_sconsign(arguments = "-i -v .sconsign", diff --git a/test/sconsign/script/Signatures.py b/test/sconsign/script/Signatures.py index fc85133..27e4867 100644 --- a/test/sconsign/script/Signatures.py +++ b/test/sconsign/script/Signatures.py @@ -31,13 +31,12 @@ SourceSignatures() and TargetSignatures() values (timestamp and content, respectively). """ +import TestSCons import TestSConsign -test = TestSConsign.TestSConsign(match = TestSConsign.match_re) +_python_ = TestSCons._python_ -CC = test.detect('CC', norm=1) -LINK = test.detect('LINK', norm=1) -if LINK is None: LINK = CC +test = TestSConsign.TestSConsign(match = TestSConsign.match_re) # Note: We don't use os.path.join() representations of the file names # in the expected output because paths in the .sconsign files are @@ -46,47 +45,75 @@ if LINK is None: LINK = CC sub1_hello_c = 'sub1/hello.c' sub1_hello_obj = 'sub1/hello.obj' -def re_sep(*args): - import os.path - import re - return re.escape(apply(os.path.join, args)) - test.subdir('sub1', 'sub2') +test.write('fake_cc.py', r""" +import os.path +import re +import string +import sys + +path = string.split(sys.argv[1]) +output = open(sys.argv[2], 'wb') +input = open(sys.argv[3], 'rb') + +output.write('fake_cc.py: %s\n' % sys.argv) + +def find_file(f): + for dir in path: + p = dir + os.sep + f + if os.path.exists(p): + return open(p, 'rb') + return None + +def process(infp, outfp): + for line in infp.readlines(): + m = re.match('#include <(.*)>', line) + if m: + file = m.group(1) + process(find_file(file), outfp) + else: + outfp.write(line) + +process(input, output) + +sys.exit(0) +""") + +test.write('fake_link.py', r""" +import sys + +output = open(sys.argv[1], 'wb') +input = open(sys.argv[2], 'rb') + +output.write('fake_link.py: %s\n' % sys.argv) + +output.write(input.read()) + +sys.exit(0) +""") + test.write('SConstruct', """ SConsignFile(None) SourceSignatures('timestamp') TargetSignatures('content') -env1 = Environment(PROGSUFFIX = '.exe', OBJSUFFIX = '.obj') +env1 = Environment(PROGSUFFIX = '.exe', + OBJSUFFIX = '.obj', + CCCOM = r'%(_python_)s fake_cc.py sub2 $TARGET $SOURCE', + LINKCOM = r'%(_python_)s fake_link.py $TARGET $SOURCE') env1.Program('sub1/hello.c') env2 = env1.Clone(CPPPATH = ['sub2']) env2.Program('sub2/hello.c') -""") +""" % locals()) test.write(['sub1', 'hello.c'], r"""\ -#include <stdio.h> -#include <stdlib.h> -int -main(int argc, char *argv[]) -{ - argv[argc++] = "--"; - printf("sub1/hello.c\n"); - exit (0); -} +sub1/hello.c """) test.write(['sub2', 'hello.c'], r"""\ -#include <stdio.h> -#include <stdlib.h> #include <inc1.h> #include <inc2.h> -int -main(int argc, char *argv[]) -{ - argv[argc++] = "--"; - printf("sub2/goodbye.c\n"); - exit (0); -} +sub2/hello.c """) test.write(['sub2', 'inc1.h'], r"""\ @@ -107,22 +134,18 @@ date_re = r'\S+ \S+ [ \d]\d \d\d:\d\d:\d\d \d\d\d\d' test.run_sconsign(arguments = "-e hello.exe -e hello.obj sub1/.sconsign", stdout = r"""hello.exe: %(sig_re)s \d+ \d+ %(sub1_hello_obj)s: %(sig_re)s \d+ \d+ - %(LINK)s: None \d+ \d+ %(sig_re)s \[.*\] hello.obj: %(sig_re)s \d+ \d+ %(sub1_hello_c)s: None \d+ \d+ - %(CC)s: None \d+ \d+ %(sig_re)s \[.*\] """ % locals()) test.run_sconsign(arguments = "-e hello.exe -e hello.obj -r sub1/.sconsign", stdout = r"""hello.exe: %(sig_re)s '%(date_re)s' \d+ %(sub1_hello_obj)s: %(sig_re)s '%(date_re)s' \d+ - %(LINK)s: None '%(date_re)s' \d+ %(sig_re)s \[.*\] hello.obj: %(sig_re)s '%(date_re)s' \d+ %(sub1_hello_c)s: None '%(date_re)s' \d+ - %(CC)s: None '%(date_re)s' \d+ %(sig_re)s \[.*\] """ % locals()) diff --git a/test/sconsign/script/no-SConsignFile.py b/test/sconsign/script/no-SConsignFile.py index 1fcfbfd..6aede19 100644 --- a/test/sconsign/script/no-SConsignFile.py +++ b/test/sconsign/script/no-SConsignFile.py @@ -29,16 +29,61 @@ Verify that the sconsign script works when using an individual .sconsign file in each directory (SConsignFile(None)). """ +import TestSCons import TestSConsign -test = TestSConsign.TestSConsign(match = TestSConsign.match_re) +_python_ = TestSCons._python_ -CC = test.detect('CC', norm=1) -LINK = test.detect('LINK', norm=1) -if LINK is None: LINK = CC +test = TestSConsign.TestSConsign(match = TestSConsign.match_re) test.subdir('sub1', 'sub2') +test.write('fake_cc.py', r""" +import os.path +import re +import string +import sys + +path = string.split(sys.argv[1]) +output = open(sys.argv[2], 'wb') +input = open(sys.argv[3], 'rb') + +output.write('fake_cc.py: %s\n' % sys.argv) + +def find_file(f): + for dir in path: + p = dir + os.sep + f + if os.path.exists(p): + return open(p, 'rb') + return None + +def process(infp, outfp): + for line in infp.readlines(): + m = re.match('#include <(.*)>', line) + if m: + file = m.group(1) + process(find_file(file), outfp) + else: + outfp.write(line) + +process(input, output) + +sys.exit(0) +""") + +test.write('fake_link.py', r""" +import sys + +output = open(sys.argv[1], 'wb') +input = open(sys.argv[2], 'rb') + +output.write('fake_link.py: %s\n' % sys.argv) + +output.write(input.read()) + +sys.exit(0) +""") + # Note: We don't use os.path.join() representations of the file names # in the expected output because paths in the .sconsign files are # canonicalized to use / as the separator. @@ -52,36 +97,23 @@ sub2_inc2_h = 'sub2/inc2.h' test.write(['SConstruct'], """ SConsignFile(None) -env1 = Environment(PROGSUFFIX = '.exe', OBJSUFFIX = '.obj') +env1 = Environment(PROGSUFFIX = '.exe', + OBJSUFFIX = '.obj', + CCCOM = r'%(_python_)s fake_cc.py sub2 $TARGET $SOURCE', + LINKCOM = r'%(_python_)s fake_link.py $TARGET $SOURCE') env1.Program('sub1/hello.c') env2 = env1.Clone(CPPPATH = ['sub2']) env2.Program('sub2/hello.c') -""") +""" % locals()) test.write(['sub1', 'hello.c'], r"""\ -#include <stdio.h> -#include <stdlib.h> -int -main(int argc, char *argv[]) -{ - argv[argc++] = "--"; - printf("sub1/hello.c\n"); - exit (0); -} +sub1/hello.c """) test.write(['sub2', 'hello.c'], r"""\ -#include <stdio.h> -#include <stdlib.h> #include <inc1.h> #include <inc2.h> -int -main(int argc, char *argv[]) -{ - argv[argc++] = "--"; - printf("sub2/goodbye.c\n"); - exit (0); -} +sub2/hello.c """) test.write(['sub2', 'inc1.h'], r"""\ @@ -99,11 +131,9 @@ sig_re = r'[0-9a-fA-F]{32}' expect = r"""hello.c: %(sig_re)s \d+ \d+ hello.exe: %(sig_re)s \d+ \d+ %(sub1_hello_obj)s: %(sig_re)s \d+ \d+ - %(LINK)s: %(sig_re)s \d+ \d+ %(sig_re)s \[.*\] hello.obj: %(sig_re)s \d+ \d+ %(sub1_hello_c)s: %(sig_re)s \d+ \d+ - %(CC)s: %(sig_re)s \d+ \d+ %(sig_re)s \[.*\] """ % locals() @@ -115,11 +145,9 @@ test.run_sconsign(arguments = "--raw sub1/.sconsign", stdout = r"""hello.c: {'csig': '%(sig_re)s', 'timestamp': \d+, 'size': \d+L?, '_version_id': 1} hello.exe: {'csig': '%(sig_re)s', 'timestamp': \d+, 'size': \d+L?, '_version_id': 1} %(sub1_hello_obj)s: {'csig': '%(sig_re)s', 'timestamp': \d+, 'size': \d+L?, '_version_id': 1} - %(LINK)s: {'csig': '%(sig_re)s', 'timestamp': \d+, 'size': \d+L?, '_version_id': 1} %(sig_re)s \[.*\] hello.obj: {'csig': '%(sig_re)s', 'timestamp': \d+, 'size': \d+L?, '_version_id': 1} %(sub1_hello_c)s: {'csig': '%(sig_re)s', 'timestamp': \d+, 'size': \d+L?, '_version_id': 1} - %(CC)s: {'csig': '%(sig_re)s', 'timestamp': \d+, 'size': \d+L?, '_version_id': 1} %(sig_re)s \[.*\] """ % locals()) @@ -137,10 +165,6 @@ hello.exe: csig: %(sig_re)s timestamp: \d+ size: \d+ - %(LINK)s: - csig: %(sig_re)s - timestamp: \d+ - size: \d+ action: %(sig_re)s \[.*\] hello.obj: csig: %(sig_re)s @@ -151,10 +175,6 @@ hello.obj: csig: %(sig_re)s timestamp: \d+ size: \d+ - %(CC)s: - csig: %(sig_re)s - timestamp: \d+ - size: \d+ action: %(sig_re)s \[.*\] """ % locals()) @@ -188,22 +208,18 @@ hello.obj: test.run_sconsign(arguments = "-e hello.obj sub1/.sconsign", stdout = r"""hello.obj: %(sig_re)s \d+ \d+ %(sub1_hello_c)s: %(sig_re)s \d+ \d+ - %(CC)s: %(sig_re)s \d+ \d+ %(sig_re)s \[.*\] """ % locals()) test.run_sconsign(arguments = "-e hello.obj -e hello.exe -e hello.obj sub1/.sconsign", stdout = r"""hello.obj: %(sig_re)s \d+ \d+ %(sub1_hello_c)s: %(sig_re)s \d+ \d+ - %(CC)s: %(sig_re)s \d+ \d+ %(sig_re)s \[.*\] hello.exe: %(sig_re)s \d+ \d+ %(sub1_hello_obj)s: %(sig_re)s \d+ \d+ - %(LINK)s: %(sig_re)s \d+ \d+ %(sig_re)s \[.*\] hello.obj: %(sig_re)s \d+ \d+ %(sub1_hello_c)s: %(sig_re)s \d+ \d+ - %(CC)s: %(sig_re)s \d+ \d+ %(sig_re)s \[.*\] """ % locals()) @@ -211,13 +227,11 @@ test.run_sconsign(arguments = "sub2/.sconsign", stdout = r"""hello.c: %(sig_re)s \d+ \d+ hello.exe: %(sig_re)s \d+ \d+ %(sub2_hello_obj)s: %(sig_re)s \d+ \d+ - %(LINK)s: %(sig_re)s \d+ \d+ %(sig_re)s \[.*\] hello.obj: %(sig_re)s \d+ \d+ %(sub2_hello_c)s: %(sig_re)s \d+ \d+ %(sub2_inc1_h)s: %(sig_re)s \d+ \d+ %(sub2_inc2_h)s: %(sig_re)s \d+ \d+ - %(CC)s: %(sig_re)s \d+ \d+ %(sig_re)s \[.*\] inc1.h: %(sig_re)s \d+ \d+ inc2.h: %(sig_re)s \d+ \d+ @@ -240,11 +254,9 @@ test.run_sconsign(arguments = "-e hello.obj sub2/.sconsign sub1/.sconsign", %(sub2_hello_c)s: %(sig_re)s \d+ \d+ %(sub2_inc1_h)s: %(sig_re)s \d+ \d+ %(sub2_inc2_h)s: %(sig_re)s \d+ \d+ - %(CC)s: %(sig_re)s \d+ \d+ %(sig_re)s \[.*\] hello.obj: %(sig_re)s \d+ \d+ %(sub1_hello_c)s: %(sig_re)s \d+ \d+ - %(CC)s: %(sig_re)s \d+ \d+ %(sig_re)s \[.*\] """ % locals()) diff --git a/test/subdivide.py b/test/subdivide.py index a816957..72c7766 100644 --- a/test/subdivide.py +++ b/test/subdivide.py @@ -34,6 +34,8 @@ import os.path import TestSCons +_python_ = TestSCons._python_ + test = TestSCons.TestSCons() #if os.path.exists('sconsign.py'): @@ -46,58 +48,79 @@ test = TestSCons.TestSCons() test.subdir('src', ['src', 'sub']) +test.write('fake_cc.py', """\ +import sys +ofp = open(sys.argv[1], 'wb') +ofp.write('fake_cc.py: %s\\n' % sys.argv) +for s in sys.argv[2:]: + ofp.write(open(s, 'rb').read()) +""") + +test.write('fake_link.py', """\ +import sys +ofp = open(sys.argv[1], 'wb') +ofp.write('fake_link.py: %s\\n' % sys.argv) +for s in sys.argv[2:]: + ofp.write(open(s, 'rb').read()) +""") + test.write('SConstruct', """\ SConsignFile(None) TargetSignatures('content') -env = Environment() +env = Environment(PROGSUFFIX = '.exe', + OBJSUFFIX = '.obj', + CCCOM = r'%(_python_)s fake_cc.py $TARGET $SOURCES', + LINKCOM = r'%(_python_)s fake_link.py $TARGET $SOURCES') env.SConscript('src/SConstruct', exports=['env']) env.Object('foo.c') -""") +""" % locals()) test.write(['src', 'SConstruct'], """\ SConsignFile(None) TargetSignatures('content') -env = Environment() -p = env.Program('prog', ['main.c', '../foo%s', 'sub/bar.c']) +env = Environment(PROGSUFFIX = '.exe', + OBJSUFFIX = '.obj', + CCCOM = r'%(_python_)s fake_cc.py $TARGET $SOURCES', + LINKCOM = r'%(_python_)s fake_link.py $TARGET $SOURCES') +p = env.Program('prog', ['main.c', '../foo$OBJSUFFIX', 'sub/bar.c']) env.Default(p) -""" % TestSCons._obj) +""" % locals()) test.write('foo.c', """\ -#include <stdio.h> -#include <stdlib.h> -void -foo(void) { - printf("foo.c\\n"); -} +foo.c """) test.write(['src', 'main.c'], """\ -#include <stdio.h> -#include <stdlib.h> -extern void foo(void); -extern void bar(void); -int -main(int argc, char *argv[]) { - foo(); - bar(); - printf("src/main.c\\n"); - exit (0); -} +src/main.c """) test.write(['src', 'sub', 'bar.c'], """\ -#include <stdio.h> -#include <stdlib.h> -void -bar(void) { - printf("bar.c\\n"); -} +src/sub/bar.c """) test.run() -test.run(program=test.workpath('src', 'prog'), - stdout="foo.c\nbar.c\nsrc/main.c\n") +src_prog_exe = os.path.join('src', 'prog.exe') +src_main_c = os.path.join('src', 'main.c') +src_main_obj = os.path.join('src', 'main.obj') +src_sub_bar_c = os.path.join('src', 'sub', 'bar.c') +src_sub_bar_obj = os.path.join('src', 'sub', 'bar.obj') + +expect = """\ +fake_link.py: ['fake_link.py', '%(src_prog_exe)s', '%(src_main_obj)s', 'foo.obj', '%(src_sub_bar_obj)s'] +fake_cc.py: ['fake_cc.py', '%(src_main_obj)s', '%(src_main_c)s'] +src/main.c +fake_cc.py: ['fake_cc.py', 'foo.obj', 'foo.c'] +foo.c +fake_cc.py: ['fake_cc.py', '%(src_sub_bar_obj)s', '%(src_sub_bar_c)s'] +src/sub/bar.c +""" % locals() + +if os.sep == '\\': + import string + expect = string.replace(expect, '\\', '\\\\') + +test.must_match(['src', 'prog.exe'], expect) test.up_to_date(chdir='src', arguments = test.workpath()) |