diff options
author | Steven Knight <knight@baldmt.com> | 2007-12-13 04:25:43 (GMT) |
---|---|---|
committer | Steven Knight <knight@baldmt.com> | 2007-12-13 04:25:43 (GMT) |
commit | 8dfbc4aafc99cd41c9e89b245e0772c862e073a6 (patch) | |
tree | 86299c32c336859f1bf05c6e3800d8c54282ccd8 /test | |
parent | 70591272485606edf2293e7d9fa33113ac9cb00c (diff) | |
download | SCons-8dfbc4aafc99cd41c9e89b245e0772c862e073a6.zip SCons-8dfbc4aafc99cd41c9e89b245e0772c862e073a6.tar.gz SCons-8dfbc4aafc99cd41c9e89b245e0772c862e073a6.tar.bz2 |
Merged revisions 2454-2525 via svnmerge from
http://scons.tigris.org/svn/scons/branches/core
........
r2455 | stevenknight | 2007-09-20 01:27:23 -0500 (Thu, 20 Sep 2007) | 2 lines
Use ${TARGET.base} to make sure $TARGET attributes stay fixed.
........
r2456 | stevenknight | 2007-09-25 11:52:30 -0500 (Tue, 25 Sep 2007) | 5 lines
Issue 1734: Avoid having content signature calculation of Alias Nodes
consume excessive amounts of memory by having an Alias' "contents" be a
concatenation of the children's signatures, not the children's contents.
(Ken Deeter)
........
r2457 | stevenknight | 2007-09-26 12:18:49 -0500 (Wed, 26 Sep 2007) | 2 lines
Add an Options.UnknownOptions() method.
........
r2458 | stevenknight | 2007-09-26 16:26:05 -0500 (Wed, 26 Sep 2007) | 2 lines
Add a compatibility fnmatch.filter() function.
........
r2459 | stevenknight | 2007-09-27 18:26:03 -0500 (Thu, 27 Sep 2007) | 3 lines
Add a new Glob() function that matches in-memory Nodes as well as on-disk
files (including matching repository and source directories).
........
r2460 | stevenknight | 2007-09-28 15:01:37 -0500 (Fri, 28 Sep 2007) | 5 lines
Issue 1020: fix use of Clean() for files created by "side effect"
in BuildDir() by removing the file by absolute path, not by what str()
returns. (It will think that the file is a source file and return a
path to the source directory.)
........
r2461 | stevenknight | 2007-09-29 05:39:09 -0500 (Sat, 29 Sep 2007) | 2 lines
Update to TestCmd 0.28 modules.
........
r2462 | stevenknight | 2007-09-29 05:49:29 -0500 (Sat, 29 Sep 2007) | 3 lines
The RPM packaging can no longer take a "target" argument and produces
an appropriate error message. Update the test accordingly.
........
r2463 | pscholl | 2007-09-30 08:57:01 -0500 (Sun, 30 Sep 2007) | 3 lines
fix documentation issues (issue 1736 on the bugtracker)
........
r2464 | pscholl | 2007-09-30 09:39:49 -0500 (Sun, 30 Sep 2007) | 3 lines
fix target set up if multiple package builders are specified at once.
........
r2465 | stevenknight | 2007-10-01 13:00:44 -0500 (Mon, 01 Oct 2007) | 3 lines
Update to TestCmd 0.29, with new methods for searching for a list
of lines in output.
........
r2466 | stevenknight | 2007-10-01 13:58:41 -0500 (Mon, 01 Oct 2007) | 4 lines
Issue 1737: Fix use of Configure() contexts with the -c (clean) and -h
(help) options by supporting the ability to *configure* whether or no
configure context tests are executed during those modes.
........
r2467 | stevenknight | 2007-10-01 16:58:21 -0500 (Mon, 01 Oct 2007) | 2 lines
Update to TestCmd 0.30, with a new TestCmd.rmdir() method.
........
r2468 | stevenknight | 2007-10-01 17:05:44 -0500 (Mon, 01 Oct 2007) | 4 lines
Issue 1586: Capture a test script for "ghost" entries in .sconsign files.
Test cases by Morten Elo Peterson and Jason Orendorff, packaged by
Gary Oberbrunner.
........
r2469 | stevenknight | 2007-10-04 11:21:12 -0500 (Thu, 04 Oct 2007) | 4 lines
When cloning a construction environment, have the clone record the
re-binding of the methods that were added to the original construction
environment, so that further clones have their methods re-bound as well.
........
r2470 | stevenknight | 2007-10-05 13:02:34 -0500 (Fri, 05 Oct 2007) | 3 lines
Refactor the Glob() code for efficiency and readability. (Greg Noel)
Refactor Glob() unit tests for platform-independence.
........
r2471 | stevenknight | 2007-10-09 10:49:15 -0500 (Tue, 09 Oct 2007) | 2 lines
Back out Glob() refactoring to avoid Repository breakage.
........
r2472 | stevenknight | 2007-10-09 12:16:33 -0500 (Tue, 09 Oct 2007) | 3 lines
Fix ToolInitializer-related infinite recursion when the BUILDERS dict
and the environment attributes can get out of sync.
........
r2473 | stevenknight | 2007-10-10 14:39:19 -0500 (Wed, 10 Oct 2007) | 4 lines
Fix a race condition in the -j sub-test by using marker directories to
make sure (?) that the two build scripts are actually executed in parallel
(regardless of system load).
........
r2474 | stevenknight | 2007-10-11 12:32:07 -0500 (Thu, 11 Oct 2007) | 4 lines
Re-fix globbing on case-insensitive systems like Windows. Slight
efficiency improvements as well (avoiding unnecessary calls to
fnmatch.filter()).
........
r2475 | stevenknight | 2007-10-11 15:04:42 -0500 (Thu, 11 Oct 2007) | 3 lines
Refactor the Node lookup logic to fix handling Windows drive letters
after an initial '#'.
........
r2476 | stevenknight | 2007-10-12 00:01:31 -0500 (Fri, 12 Oct 2007) | 2 lines
Fix nested scope issues (for the benefit of older Python versions).
........
r2477 | stevenknight | 2007-10-12 11:36:21 -0500 (Fri, 12 Oct 2007) | 2 lines
Issue 1743: Document '#' interpretation, with examples.
........
r2478 | stevenknight | 2007-10-12 12:17:50 -0500 (Fri, 12 Oct 2007) | 3 lines
Fix the ability of our default ActionFactory function to handle Nodes
as input.
........
r2479 | stevenknight | 2007-10-12 13:53:37 -0500 (Fri, 12 Oct 2007) | 4 lines
Enhance Options() file execution to add the file's directory to sys.path
(and remove it afterwards) and to add a __name__ variable that can be
used for introspecting on the file's location.
........
r2480 | stevenknight | 2007-10-14 17:57:09 -0500 (Sun, 14 Oct 2007) | 4 lines
Remove unnecessary os.path.normpath() calls when looking up directories
or files by checking for whether we can just tack on a single entry name
to the already-normalized lookup path of the directory Node.
........
r2481 | stevenknight | 2007-10-17 01:08:47 -0500 (Wed, 17 Oct 2007) | 2 lines
Add a GetBuildFailures() function.
........
r2482 | stevenknight | 2007-10-17 09:56:18 -0500 (Wed, 17 Oct 2007) | 2 lines
Fix the GetBuildFailures() example in the man page.
........
r2483 | stevenknight | 2007-10-17 10:54:21 -0500 (Wed, 17 Oct 2007) | 3 lines
Use sys.exitfunc if there's no atexit module (Python 1.5.2).
Sort the failure list for deterministic build output under system load.
........
r2484 | stevenknight | 2007-10-20 12:33:07 -0500 (Sat, 20 Oct 2007) | 2 lines
Use more efficient Decider() defaults instead of {Target,Source}Signatures().
........
r2485 | stevenknight | 2007-10-20 17:42:27 -0500 (Sat, 20 Oct 2007) | 2 lines
Windows portability in GetBuildFailures() test scripts.
........
r2486 | stevenknight | 2007-10-20 20:46:26 -0500 (Sat, 20 Oct 2007) | 2 lines
Windows portability: rename internal copy.py script, use a stub instead of tar.
........
r2487 | stevenknight | 2007-10-24 23:36:24 -0500 (Wed, 24 Oct 2007) | 4 lines
Whenever a script configures SConsignFile(None), make sure it uses
stub compiler and linker scripts, not the system ones, to avoid writing
(or trying to write) .sconsign files in system directories.
........
r2488 | stevenknight | 2007-10-26 13:57:38 -0500 (Fri, 26 Oct 2007) | 2 lines
Issue 1764: Fix test-script portability issues on Solaris.
........
r2489 | stevenknight | 2007-10-27 07:37:37 -0500 (Sat, 27 Oct 2007) | 3 lines
Issue 1757: add a CheckTypeSize() call to Configure contexts
(David Cournapeau).
........
r2490 | stevenknight | 2007-10-28 07:58:30 -0500 (Sun, 28 Oct 2007) | 2 lines
Python 1.5.2 compatibility: no use of +=.
........
r2491 | stevenknight | 2007-10-29 12:13:35 -0500 (Mon, 29 Oct 2007) | 3 lines
Issue 1758: Fix the SCons packaging build for use with shared-lib
versions of Python and to avoid .egg-info naming issues.
........
r2492 | stevenknight | 2007-10-29 14:09:57 -0500 (Mon, 29 Oct 2007) | 2 lines
Document the "expect" argument to CheckTypeSize(). (David Cournapeau)
........
r2493 | stevenknight | 2007-11-05 20:57:27 -0600 (Mon, 05 Nov 2007) | 2 lines
Fix use of Glob() when a pattern is below an explicitly-named subdirectory.
........
r2495 | stevenknight | 2007-11-12 22:58:12 -0600 (Mon, 12 Nov 2007) | 5 lines
Add a get_sources() access method to avoid an O(n^2) problem when adding
sources to an Executor object. The old code weeded out duplicates
whenever a new source was added; the new code only does that when the
source is list going to be used.
........
r2496 | stevenknight | 2007-11-15 12:19:55 -0600 (Thu, 15 Nov 2007) | 4 lines
Redefine the $WINDOWSPROGMANIFESTSUFFIX and
$WINDOWSSHLIBMANIFESTSUFFIX variables so they pick up changes to
the underlying $SHLIBSUFFIX and $PROGSUFFIX variables.
........
r2497 | stevenknight | 2007-11-18 17:11:52 -0600 (Sun, 18 Nov 2007) | 4 lines
Support .status and .command attributes of BuildError exceptions.
Change Action objects to return BuildError objects (not raise them)
when an action fails.
........
r2498 | stevenknight | 2007-11-19 07:27:16 -0600 (Mon, 19 Nov 2007) | 3 lines
When converting .sconsign paths to Nodes, use the more efficient
_lookup_abs() method.
........
r2499 | stevenknight | 2007-11-25 00:18:20 -0600 (Sun, 25 Nov 2007) | 3 lines
Move the reflection-checking is_under() logic from the .srcdir_list()
method to the .srcdir_duplicate() method.
........
r2500 | stevenknight | 2007-11-25 00:31:33 -0600 (Sun, 25 Nov 2007) | 2 lines
Have the .srcnode() method use the .srcdir_list() method.
........
r2501 | stevenknight | 2007-11-28 22:56:39 -0600 (Wed, 28 Nov 2007) | 3 lines
Issue 1845: Have single-source Builders (like Object()) return
NodeList objects even when called with multiple files.
........
r2502 | stevenknight | 2007-11-28 23:00:46 -0600 (Wed, 28 Nov 2007) | 2 lines
Issue 1845: Document the NodeList behavior w.r.t Python's += operator.
........
r2503 | stevenknight | 2007-11-29 09:35:31 -0600 (Thu, 29 Nov 2007) | 3 lines
Issue 1840: Fix a lot of typos in the man page and Users' Guide.
(Malte Helmert)
........
r2504 | stevenknight | 2007-11-29 10:41:44 -0600 (Thu, 29 Nov 2007) | 3 lines
Issue 1841: Fix --implicit-cache spurious rebuilds and inefficiency
when using Builders that produce multiple targets. (Benoit Belley)
........
r2505 | stevenknight | 2007-11-30 17:36:03 -0600 (Fri, 30 Nov 2007) | 3 lines
Unit test fix for Python 1.5.2, which can't .extend() lists with
UserList objects.
........
r2506 | stevenknight | 2007-11-30 20:37:14 -0600 (Fri, 30 Nov 2007) | 2 lines
Python 1.5.2 portability: use string.join(), not ' '.join().
........
r2507 | stevenknight | 2007-11-30 21:42:19 -0600 (Fri, 30 Nov 2007) | 3 lines
When searching directory lists like $CPPPATH, don't make Dir Nodes for
directories that don't exist on disk.
........
r2508 | stevenknight | 2007-12-01 00:14:35 -0600 (Sat, 01 Dec 2007) | 2 lines
Add a Requires() function for specifying order-only prerequisites.
........
r2509 | stevenknight | 2007-12-01 07:32:24 -0600 (Sat, 01 Dec 2007) | 3 lines
Handle absolute paths without infinite recursion in the new code that
searches for implicit dependencies without creating unnecessary Dir Nodes.
........
r2510 | stevenknight | 2007-12-03 15:11:56 -0600 (Mon, 03 Dec 2007) | 2 lines
Restore the rel_path() method, for the benefit of SConscript files using it.
........
r2511 | stevenknight | 2007-12-04 00:34:02 -0600 (Tue, 04 Dec 2007) | 4 lines
User's Guide updates for the Big Signature refactoring, capturing mention
of things that still need documenting, and other changes from re-running
the examples through the latest code.
........
r2512 | stevenknight | 2007-12-04 08:48:51 -0600 (Tue, 04 Dec 2007) | 3 lines
Issue 1846: allow building only part of the dependency graph when
BuildDir(duplicate=0) is used. (Benoit Belley)
........
r2513 | stevenknight | 2007-12-06 05:02:56 -0600 (Thu, 06 Dec 2007) | 3 lines
Have the code that avoids creating unnecessary Dir Nodes when searching
$*PATH variables handle absolute paths with Windows drive letters.
........
r2514 | stevenknight | 2007-12-08 07:44:15 -0600 (Sat, 08 Dec 2007) | 6 lines
Issue 1852: Make the default behavior of
{Source,Target}Signatures('timestamp') equivalent to
'timestamp-match', not 'timestamp-newer'. Fix use of CacheDir with
Decider('timestamp-newer') by updating the modification time when copying
files from the cache.
........
r2515 | stevenknight | 2007-12-08 08:23:02 -0600 (Sat, 08 Dec 2007) | 4 lines
Update the mock compiler inin/sconsoutput to use $CPPPATH.
Capture the ripple effect in the Troubleshooting appendix.
Also add a -t option to the mock "touch" command.
........
r2516 | stevenknight | 2007-12-08 09:16:11 -0600 (Sat, 08 Dec 2007) | 3 lines
Update the Dependencies chapter for use of the Decider() function,
and to now discourage use of SourceSignatures() and TargetSignatures().
........
r2517 | stevenknight | 2007-12-08 12:31:10 -0600 (Sat, 08 Dec 2007) | 4 lines
Issue 1721: On Windows, wrap __builtin__.close() and __builtin__.file()
to disable file handle inheritance on any files opened by SCons during
the run.
........
r2518 | stevenknight | 2007-12-11 17:33:20 -0600 (Tue, 11 Dec 2007) | 4 lines
Prevent the _get_str() method from causing underlying stat() values
to be cached if we're not yet saving the string representations of
FS.Base() Nodes.
........
r2519 | stevenknight | 2007-12-11 23:27:05 -0600 (Tue, 11 Dec 2007) | 4 lines
Add a warning about the unreliability of -j if the pywin32 modules aren't
available or are old and can't suppress file handle inheritance.
Add a release note about the change to open() and file().
........
r2520 | stevenknight | 2007-12-11 23:28:05 -0600 (Tue, 11 Dec 2007) | 2 lines
Add an overlooked update, fix spelling.
........
r2521 | stevenknight | 2007-12-12 09:12:42 -0600 (Wed, 12 Dec 2007) | 3 lines
Use &TargetSignatures; (replace missing ampersand) in the title of
that section. Move the &Depends; section to before the &Ignore; section.
........
r2522 | stevenknight | 2007-12-12 09:20:46 -0600 (Wed, 12 Dec 2007) | 3 lines
Final documentation update for checkpoint release: propagate .in changes
to .xml files.
........
r2523 | stevenknight | 2007-12-12 09:29:11 -0600 (Wed, 12 Dec 2007) | 2 lines
Update release lines for new checkpoint release.
........
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()) |