= str(source[0])
        shutil.copy(src, tgt)
    def AltCopyStage2(target, source, env):
        pass
    MyCopy = Builder(action = [DifferentCopy, AltCopyStage2])

    def ChangingCopy(target, source, env):
        tgt = str(target[0])
        src = str(source[0])
        shutil.copy(src, tgt)
    ChangingCopy = Builder(action = ChangingCopy)
else:
    MyCopy = Builder(action = Copy('$TARGET', '$SOURCE'))
    def ChangingCopy(target, source, env):
        tgt = str(target[0].get_abspath())
        src = str(source[0].get_abspath())
        shutil.copy(src, tgt)
    ChangingCopy = Builder(action = ChangingCopy)

env['BUILDERS']['MyCopy'] = MyCopy
env['BUILDERS']['ChangingCopy'] = ChangingCopy

env.MyCopy('f1.out', 'f1.in')
env.ChangingCopy('f2.out', 'f2.in')
""")

test.write('f1.in', "f1.in\n")
test.write('f2.in', "f2.in\n")

test.run(arguments = "mode=0 .")

test.must_match('f1.out', "f1.in\n")
test.must_match('f2.out', "f2.in\n")

test.run(arguments = "--debug=explain mode=1 .",
         stdout = test.wrap_stdout("""\
scons: rebuilding `f1.out' because the build action changed:
               old: Copy("$TARGET", "$SOURCE")
               new: DifferentCopy(target, source, env)
                    AltCopyStage2(target, source, env)
DifferentCopy(["f1.out"], ["f1.in"])
AltCopyStage2(["f1.out"], ["f1.in"])
scons: rebuilding `f2.out' because the contents of the build action changed
               action: ChangingCopy(target, source, env)
ChangingCopy(["f2.out"], ["f2.in"])
"""))



test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/explain/get_csig.py

#!/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 call get_csig() from a function action without
causing problems.  (This messed up a lot of internal state before
the Big Signature Refactoring.)

Test case courtesy of Damyan Pepper.
"""

import TestSCons

test = TestSCons.TestSCons()

args = "--debug=explain"

test.write('SConstruct', """\
DefaultEnvironment(tools=[])
env = Environment(tools=[])

def action( source, target, env ):
    target[0].get_csig()
    f = open( str(target[0]), 'wb' )
    for s in source:
        f.write( s.get_contents() )
    f.close()

builder = env.Builder( action=action )

builder( env, target = "target.txt", source = "source.txt" )
""")

test.write("source.txt", "source.txt 1\n")

test.run(arguments=args)



test.write("source.txt", "source.txt 2")



expect_rebuild = test.wrap_stdout("""\
scons: rebuilding `target.txt' because `source.txt' changed
action(["target.txt"], ["source.txt"])
""")

test.not_up_to_date(arguments=args)



test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/explain/save-info.py

#!/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 --debug=explain information gets saved by default.
"""

__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"

import TestSCons

_python_ = TestSCons._python_

test = TestSCons.TestSCons()

test.subdir( 'src', ['src', 'subdir'])

cat_py = test.workpath('cat.py')
inc_bbb_k = test.workpath('inc', 'bbb.k')
inc_ddd = test.workpath('inc', 'ddd')
inc_eee = test.workpath('inc', 'eee')

test.write(cat_py, r"""
import sys

def process(outfp, infp):
    for line in infp.readlines():
        if line[:8] == 'include ':
            file = line[8:-1]
            try:
                fp = open(file, 'r')
            except IOError:
                import os
                print("os.getcwd() =", os.getcwd())
                raise
            process(outfp, fp)
            fp.close()
        else:
            outfp.write(line)

with open(sys.argv[1], 'w') as ofp:
    for f in sys.argv[2:]:
        if f != '-':
            with open(f, 'r') as ifp:
                process(ofp, ifp)

sys.exit(0)
""")

test.write(['src', 'SConstruct'], r"""
DefaultEnvironment(tools=[])
import re

include_re = re.compile(r'^include\s+(\S+)$', re.M)

def kfile_scan(node, env, target, arg):
    contents = node.get_text_contents()
    includes = include_re.findall(contents)
    return includes

kscan = Scanner(name = 'kfile',
                function = kfile_scan,
                argument = None,
                skeys = ['.k'])

cat = Builder(action = r'%(_python_)s %(cat_py)s $TARGET $SOURCES')

env = Environment(tools=[])
env.Append(BUILDERS = {'Cat':cat},
           SCANNERS = kscan)

Export("env")
SConscript('SConscript')
env.Install('../inc', 'aaa')
env.InstallAs('../inc/bbb.k', 'bbb.k')
env.Install('../inc', 'ddd')
env.InstallAs('../inc/eee', 'eee.in')
""" % locals())

test.write(['src', 'SConscript'], """\
Import("env")
env.Cat('file1', 'file1.in')
env.Cat('file2', 'file2.k')
env.Cat('file3', ['xxx', 'yyy', 'zzz'])
env.Command('file4', 'file4.in', r'%(_python_)s %(cat_py)s $TARGET - $SOURCES')
env.Cat('file5', 'file5.k')
env.Cat('subdir/file6', 'subdir/file6.in')
""" % locals())

test.write(['src', 'aaa'], "aaa 1\n")
test.write(['src', 'bbb.k'], """\
bbb.k 1
include ccc
include ../inc/ddd
include ../inc/eee
""")
test.write(['src', 'ccc'], "ccc 1\n")
test.write(['src', 'ddd'], "ddd 1\n")
test.write(['src', 'eee.in'], "eee.in 1\n")

test.write(['src', 'file1.in'], "file1.in 1\n")

test.write(['src', 'file2.k'], """\
file2.k 1 line 1
include xxx
include yyy
file2.k 1 line 4
""")

test.write(['src', 'file4.in'], "file4.in 1\n")

test.write(['src', 'xxx'], "xxx 1\n")
test.write(['src', 'yyy'], "yyy 1\n")
test.write(['src', 'zzz'], "zzz 1\n")

test.write(['src', 'file5.k'], """\
file5.k 1 line 1
include ../inc/aaa
include ../inc/bbb.k
file5.k 1 line 4
""")

test.write(['src', 'subdir', 'file6.in'], "subdir/file6.in 1\n")

#
test.run(chdir='src', arguments='..')

test.must_match(['src', 'file1'], "file1.in 1\n", mode='r')
test.must_match(['src', 'file2'], """\
file2.k 1 line 1
xxx 1
yyy 1
file2.k 1 line 4
""", mode='r')
test.must_match(['src', 'file3'], "xxx 1\nyyy 1\nzzz 1\n", mode='r')
test.must_match(['src', 'file4'], "file4.in 1\n", mode='r')
test.must_match(['src', 'file5'], """\
file5.k 1 line 1
aaa 1
bbb.k 1
ccc 1
ddd 1
eee.in 1
file5.k 1 line 4
""", mode='r')

test.write(['src', 'file1.in'], "file1.in 2\n")
test.write(['src', 'yyy'], "yyy 2\n")
test.write(['src', 'zzz'], "zzz 2\n")
test.write(['src', 'bbb.k'], "bbb.k 2\ninclude ccc\n")

expect = test.wrap_stdout("""\
scons: rebuilding `file1' because `file1.in' changed
%(_python_)s %(cat_py)s file1 file1.in
scons: rebuilding `file2' because `yyy' changed
%(_python_)s %(cat_py)s file2 file2.k
scons: rebuilding `file3' because:
           `yyy' changed
           `zzz' changed
%(_python_)s %(cat_py)s file3 xxx yyy zzz
scons: rebuilding `%(inc_bbb_k)s' because `bbb.k' changed
Install file: "bbb.k" as "%(inc_bbb_k)s"
scons: rebuilding `file5' because `%(inc_bbb_k)s' changed
%(_python_)s %(cat_py)s file5 file5.k
""" % locals())

test.run(chdir='src', arguments='--debug=explain .', stdout=expect)

test.must_match(['src', 'file1'], "file1.in 2\n", mode='r')
test.must_match(['src', 'file2'], """\
file2.k 1 line 1
xxx 1
yyy 2
file2.k 1 line 4
""", mode='r')
test.must_match(['src', 'file3'], "xxx 1\nyyy 2\nzzz 2\n", mode='r')
test.must_match(['src', 'file5'], """\
file5.k 1 line 1
aaa 1
bbb.k 2
ccc 1
file5.k 1 line 4
""", mode='r')



test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/fixture/SConstruct_test_main.py

DefaultEnvironment(tools=[])
env = Environment()
env.Program('main.exe', ['main.c'])


# test/fixture/echo.py

import sys
print(sys.argv)


# test/fixture/mycompile.py

"""
Phony compiler for testing SCons.

Copies its source files to the target file, dropping lines that match
a pattern, so we can recognize the tool has made a modification.
Intended for use as a *COM construction variable.

Calling convention is:
  argv[1] the function of the script (cc, c++, as, link etc.)
  argv[2] the output file to write
  argv[3:] one or more input files to "compile"

Invocation often looks like:
  Environment(CCCOM = r'%(_python_)s mycompile.py cc $TARGET $SOURCE', ...
"""

import fileinput
import sys

def fake_compile():
    skipline = f"/*{sys.argv[1]}*/\n".encode("utf-8")
    with open(sys.argv[2], 'wb') as ofp, fileinput.input(files=sys.argv[3:], mode='rb') as ifp:
        for line in ifp:
            if line != skipline:
                ofp.write(line)


if __name__ == '__main__':
    fake_compile()
    sys.exit(0)


# test/fixture/mygcc.py

"""
Phony compiler for testing SCons.

Copies its source file to the target file, dropping lines that match
a pattern, so we can recognize the tool has made a modification.

The first argument is the language (cc, c__, g77, etc.).

Recognizes a -x option to append the language to 'mygcc.out'
for tracing purposes.

Intended for use as $CC, $CXX, etc.
"""

import getopt
import sys

def fake_gcc():
    compiler = sys.argv[1].encode('utf-8')
    opts, args = getopt.getopt(sys.argv[2:], 'co:xf:K:')
    for opt, arg in opts:
        if opt == '-o':
            out = arg
        elif opt == '-x':
            with open('mygcc.out', 'ab') as logfile:
                logfile.write(compiler + b"\n")

    with open(out, 'wb') as ofp, open(args[0], 'rb') as ifp:
        for line in ifp:
            if not line.startswith(b'#' + compiler):
                ofp.write(line)

if __name__ == '__main__':
    fake_gcc()
    sys.exit(0)


# test/fixture/mylex.py

"""
Phony lex for testing SCons.

Writes the contents of input file to stdout,
after "substituting" $LEXFLAGS and $I_ARGS

Intended for use as $LEX
"""

import getopt
import sys

def fake_lex():
    if sys.platform == 'win32':
        longopts = ['nounistd']
    else:
        longopts = []
    cmd_opts, args = getopt.getopt(sys.argv[1:], 'I:tx', longopts)
    opt_string = ''
    i_arguments = ''
    for opt, arg in cmd_opts:
        if opt == '-I':
            i_arguments = f'{i_arguments} {arg}'
        else:
            opt_string = f'{opt_string} {opt}'
    for arg in args:
        with open(arg, 'rb') as ifp:
            contents = ifp.read().decode(encoding='utf-8')
        contents = contents.replace('LEXFLAGS', opt_string)
        contents = contents.replace('LEX', 'mylex.py')
        contents = contents.replace('I_ARGS', i_arguments)
        sys.stdout.write(contents)

if __name__ == '__main__':
    fake_lex()
    sys.exit(0)


# test/fixture/mylink.py

"""
Phony linker for testing SCons.

Copies its source files to the target file, dropping lines that match
a pattern, so we can recognize the tool has made a modification.
Intended for use as the $LINK construction variable.
"""
import fileinput
import getopt
import sys

def fake_link():
    opts, args = getopt.getopt(sys.argv[1:], 'o:s:')
    for opt, arg in opts:
        if opt == '-o':
            out = arg

    with open(out, 'wb') as ofp, fileinput.input(files=args, mode='rb') as ifp:
        for line in ifp:
            if not line.startswith(b'#link'):
                ofp.write(line)

def fake_win32_link():
    args = sys.argv[1:]
    while args:
        arg = args[0]
        if arg == '-o':
            out = args[1]
            args = args[2:]
            continue
        if arg[0] not in '/-':
            break
        args = args[1:]
        if arg.lower().startswith('/out:'):
            out = arg[5:]
    with open(args[0], 'rb') as ifp, open(out, 'wb') as ofp:
        for line in ifp:
            if not line.startswith(b'#link'):
                ofp.write(line)

if __name__ == '__main__':
    if sys.platform == 'win32':
        fake_win32_link()
    else:
        fake_link()
    sys.exit(0)


# test/fixture/myrewrite.py

r"""
Phony tool to modify a file in place for testing SCons.

Drops lines that match a pattern.  Currently used to test
ranlib and ar behavior without actually invoking those tools.
"""

import sys

def rewrite():
    line = ('/*' + sys.argv[1] + '*/\n').encode('utf-8')
    with open(sys.argv[2], 'rb') as ifp:
        lines = [ln for ln in ifp if ln != line]
    with open(sys.argv[2], 'wb') as ofp:
        ofp.writelines(lines)


if __name__ == '__main__':
    rewrite()
    sys.exit(0)


# test/fixture/wrapper.py

"""
Command wrapper, for testing SCons.

Writes the command name to file "wrapper.out",
then passes the command line on to subprocess.
No checking is done.
"""
import os
import sys
import subprocess

if __name__ == '__main__':
    path = os.path.join(os.path.dirname(os.path.relpath(__file__)), 'wrapper.out')
    if '--version' not in sys.argv and '-dumpversion' not in sys.argv:
        with open(path, 'wb') as f:
            f.write(b"wrapper.py\n")
    subprocess.run(sys.argv[1:], check=False)


# test/fixture/wrapper_with_args.py

"""
Command wrapper taking arguments, for testing SCons.

Writes the command name and argument list to file "wrapper.out",
then passes the command line on to subprocess.
No checking is done.
"""
import os
import sys
import subprocess

if __name__ == '__main__':
    path = os.path.join(os.path.dirname(os.path.relpath(__file__)), 'wrapper.out')
    with open(path, 'a') as f:
        f.write("wrapper_with_args.py %s\n" % " ".join(sys.argv[1:]))
    subprocess.run(sys.argv[1:], check=False)


# test/implicit-cache/DualTargets.py

#!/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 TestSCons

test = TestSCons.TestSCons()

test.write('SConstruct', """\
DefaultEnvironment(tools=[])
import os.path

def emitter(target, source, env):
    tgt0 = target[0].get_abspath()
    base,ext = os.path.splitext(tgt0)
    target.append(base + '.b')
    return(target, source)


def source_scan(node, env, path):
    path = node.get_abspath()
    base,ext = os.path.splitext(path)
    return [base + '.lib']


env = Environment(tools=[])
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.must_contain_all_lines(test.stdout(), ['Copy'])

# 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.must_not_contain_any_line(test.stdout(), ['Copy'])

# 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.must_not_contain_any_line(test.stdout(), ['Copy'])

# 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.must_not_contain_any_line(test.stdout(), ['Copy'])

# 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.must_not_contain_any_line(test.stdout(), ['Copy'])

# 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.must_not_contain_any_line(test.stdout(), ['Copy'])

# Then only of the targets using --implicit-cache
test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/implicit-cache/GetOption.py

#!/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 SetOption/GetOption('implicit_cache') works and can
be overridden from the command line.
"""

import TestSCons

test = TestSCons.TestSCons()

test.write('SConstruct', """
DefaultEnvironment(tools=[])
assert not GetOption('implicit_cache')
SetOption('implicit_cache', 1)
assert GetOption('implicit_cache')
""")

test.run()

test.write('SConstruct', """
DefaultEnvironment(tools=[])
assert GetOption('implicit_cache')
SetOption('implicit_cache', 0)
assert GetOption('implicit_cache')
""")

test.run(arguments='--implicit-cache')


test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/implicit-cache/RemoveImplicitDep.py

#!/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__"

"""
A weird case with implicit_cache not working with multiple targets
"""

import TestSCons

_python_ = TestSCons._python_

test = TestSCons.TestSCons()

test.subdir(['src'])

SConstruct_contents = """\
DefaultEnvironment(tools=[])
import SCons.Script

SetOption( 'implicit_cache', 1 )

env = Environment(tools=[])
act = Action([Touch('${TARGETS[0]}'),Touch('${TARGETS[1]}')])
env.Append(BUILDERS = {'BuildMe':Builder(action=act,source_scanner=SCons.Script.SourceFileScanner)} )

env.BuildMe( source='inc.c', target=['a','b'] )
"""

test.write(['src', 'SConstruct'], SConstruct_contents)

test.write(['src', 'inc.c'], """\
#include <f1.h>
#include <f2.h>
""")
test.write(['src', 'f1.h'], 'blah' )
test.write(['src', 'f2.h'], 'blah' )
        
expect = test.wrap_stdout("""\
Touch("a")
Touch("b")
""")

test.run(chdir='src', arguments='', stdout=expect)

test.write(['src', 'inc.c'], """\
#include <f2.h>
""")
test.unlink( ['src', 'f1.h'] )

test.run(chdir='src', arguments='', stdout=expect)

test.pass_test()


# test/implicit-cache/SetOption.py

#!/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 SetOption('implicit_cache', 1) actually enables implicit
caching by detecting the case where implicit caching causes inaccurate
builds:  a same-named file dropped into a directory earlier in the
CPPPATH list will *not* be detected because we use what's in the cache.
"""

import TestSCons

test = TestSCons.TestSCons()

test.write('SConstruct', """
DefaultEnvironment(tools=[])
SetOption('implicit_cache', 1)
env=Environment(CPPPATH=['i1', 'i2'])
env.Object('foo.c')
""")

test.subdir('i1')
test.subdir('i2')

test.write('foo.c', """
#include <foo.h>

void foo(void)
{
    FOO_H_DEFINED
    ++x;  /* reference x */
}
""")

test.write('i2/foo.h', """
#define FOO_H_DEFINED int x = 1;
""")

test.run(arguments = '.')

test.write('i1/foo.h', """
this line will cause a syntax error if it's included by a rebuild
""")

test.up_to_date(arguments = '.')


test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/implicit-cache/basic.py

#!/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 interactions of the --implicit-cache-* options.

We rely on the default Decider('content') behavior and only
check for the rebuild of the object file itself when necessary.
"""

import os.path

import TestSCons

_exe = TestSCons._exe
_obj = TestSCons._obj

prog = 'prog' + _exe
subdir_prog = os.path.join('subdir', 'prog' + _exe)
variant_prog = os.path.join('variant', 'prog' + _exe)
variant_prog_obj = os.path.join('variant', 'prog' + _obj)

args = prog + ' ' + subdir_prog + ' ' + variant_prog

test = TestSCons.TestSCons()

test.subdir('include', 'subdir', ['subdir', 'include'], 'inc2')

test.write('SConstruct', """
DefaultEnvironment(tools=[])
env = Environment(CPPPATH = Split('inc2 include'))
obj = env.Object(target='prog', source='subdir/prog.c')
env.Program(target='prog', source=obj)
SConscript('subdir/SConscript', "env")

VariantDir('variant', 'subdir', 0)
include = Dir('include')
env = Environment(CPPPATH=['inc2', include])
SConscript('variant/SConscript', "env")

def copy(target, source, env):
    with open(str(target[0]), 'wt') as fo, open(str(source[0]), 'rt') as fi:
        fo.write(fi.read())
nodep = env.Command('nodeps.c', 'nodeps.in', action=copy)
env.Program('nodeps', 'nodeps.c')

env.Object(['one', 'two'], ['one.c'])
""")

test.write(['subdir', 'SConscript'],
"""
Import("env")
env.Program(target='prog', source='prog.c')
""")

test.write('nodeps.in', r"""
int
main(int argc, char *argv[])
{
    argv[argc++] = "--";
    return 0;
}
""")


test.write(['include', 'foo.h'], r"""
#define FOO_STRING "include/foo.h 1\n"
#include <bar.h>
""")

test.write(['include', 'bar.h'], r"""
#define BAR_STRING "include/bar.h 1\n"
""")

test.write(['include', 'baz.h'], r"""
#define BAZ_STRING "include/baz.h 1\n"
""")

test.write(['subdir', 'prog.c'], r"""
#include <foo.h>
#include <stdio.h>

int
main(int argc, char *argv[])
{
    argv[argc++] = "--";
    printf("subdir/prog.c\n");
    printf(FOO_STRING);
    printf(BAR_STRING);
    return 0;
}
""")

test.write(['subdir', 'include', 'foo.h'], r"""
#define FOO_STRING "subdir/include/foo.h 1\n"
#include "bar.h"
""")

test.write(['subdir', 'include', 'bar.h'], r"""
#define BAR_STRING "subdir/include/bar.h 1\n"
""")

test.write('one.c' , r"""
#include <foo.h>

void one(void) { }
""")

test.run(arguments = "--implicit-cache " + args)

test.run(program = test.workpath(prog),
         stdout = "subdir/prog.c\ninclude/foo.h 1\ninclude/bar.h 1\n")

test.run(program = test.workpath(subdir_prog),
         stdout = "subdir/prog.c\nsubdir/include/foo.h 1\nsubdir/include/bar.h 1\n")

test.run(program = test.workpath(variant_prog),
         stdout = "subdir/prog.c\ninclude/foo.h 1\ninclude/bar.h 1\n")

test.up_to_date(arguments = args)



# Make sure implicit dependencies work right when one is modifed:
test.write(['include', 'foo.h'], r"""
#define FOO_STRING "include/foo.h 2\n"
#include "bar.h"
""")

test.run(arguments = "--implicit-cache " + args)

test.run(program = test.workpath(prog),
         stdout = "subdir/prog.c\ninclude/foo.h 2\ninclude/bar.h 1\n")

test.run(program = test.workpath(subdir_prog),
         stdout = "subdir/prog.c\nsubdir/include/foo.h 1\nsubdir/include/bar.h 1\n")

test.run(program = test.workpath(variant_prog),
         stdout = "subdir/prog.c\ninclude/foo.h 2\ninclude/bar.h 1\n")

test.up_to_date(arguments = args)



# Make sure that changing the order of includes causes rebuilds and
# doesn't produce redundant rebuilds:
test.write(['include', 'foo.h'], r"""
#define FOO_STRING "include/foo.h 2\n"
#include "bar.h"
#include "baz.h"
""")

test.run(arguments = "--implicit-cache " + args)

test.run(program = test.workpath(prog),
         stdout = "subdir/prog.c\ninclude/foo.h 2\ninclude/bar.h 1\n")

test.run(program = test.workpath(subdir_prog),
         stdout = "subdir/prog.c\nsubdir/include/foo.h 1\nsubdir/include/bar.h 1\n")

test.run(program = test.workpath(variant_prog),
         stdout = "subdir/prog.c\ninclude/foo.h 2\ninclude/bar.h 1\n")

test.up_to_date(arguments = args)



test.write(['include', 'foo.h'], r"""
#define FOO_STRING "include/foo.h 2\n"
#include "baz.h"
#include "bar.h"
""")

test.run(arguments = "--implicit-cache " + args)

test.run(program = test.workpath(prog),
         stdout = "subdir/prog.c\ninclude/foo.h 2\ninclude/bar.h 1\n")

test.run(program = test.workpath(subdir_prog),
         stdout = "subdir/prog.c\nsubdir/include/foo.h 1\nsubdir/include/bar.h 1\n")

test.run(program = test.workpath(variant_prog),
         stdout = "subdir/prog.c\ninclude/foo.h 2\ninclude/bar.h 1\n")

test.up_to_date(arguments = args)



# Add inc2/foo.h that should shadow include/foo.h, but
# because of implicit dependency caching, scons doesn't
# detect this:
test.write(['inc2', 'foo.h'], r"""
#define FOO_STRING "inc2/foo.h 1\n"
#include <bar.h>
""")

test.run(arguments = "--implicit-cache " + args)

test.run(program = test.workpath(prog),
         stdout = "subdir/prog.c\ninclude/foo.h 2\ninclude/bar.h 1\n")

test.run(program = test.workpath(subdir_prog),
         stdout = "subdir/prog.c\nsubdir/include/foo.h 1\nsubdir/include/bar.h 1\n")

test.run(program = test.workpath(variant_prog),
         stdout = "subdir/prog.c\ninclude/foo.h 2\ninclude/bar.h 1\n")



# Now modifying include/foo.h should make scons aware of inc2/foo.h
test.write(['include', 'foo.h'], r"""
#define FOO_STRING "include/foo.h 3\n"
#include "bar.h"
""")

test.run(arguments = "--implicit-cache " + args)

test.run(program = test.workpath(prog),
         stdout = "subdir/prog.c\ninc2/foo.h 1\ninclude/bar.h 1\n")

test.run(program = test.workpath(subdir_prog),
         stdout = "subdir/prog.c\nsubdir/include/foo.h 1\nsubdir/include/bar.h 1\n")

test.run(program = test.workpath(variant_prog),
         stdout = "subdir/prog.c\ninclude/foo.h 3\ninclude/bar.h 1\n")



# test a file with no dependencies where the source file is generated:
test.run(arguments = "--implicit-cache nodeps%s"%_exe)

test.write('nodeps.in', r"""
#include <foo.h>

int
main(int argc, char *argv[])
{
    argv[argc++] = "--";
    return 0;
}
""")

test.run(arguments = "--implicit-cache one%s"%_obj)



# Test forcing of implicit caching:
test.write(['include', 'foo.h'], r"""
#define FOO_STRING "include/foo.h 3\n"
#include "bar.h"
""")

# Cache the dependencies of prog_obj:  foo.h and its included bar.h.
test.run(arguments = "--implicit-cache " + args)

# Now add baz.h to the implicit dependencies in foo.h.
test.write(['include', 'foo.h'], r"""
#define FOO_STRING "include/foo.h 3\n"
#include "baz.h"
#include "bar.h"
""")

# Rebuild variant_prog_obj because the already-cached foo.h changed,
# but use --implicit-deps-unchanged to avoid noticing the addition
# of baz.h to the implicit dependencies.
test.not_up_to_date(options = "--implicit-deps-unchanged",
                    arguments = variant_prog_obj)

test.write(['include', 'baz.h'], r"""
#define BAZ_STRING "include/baz.h 2\n"
""")

# variant_prog_obj is still up to date, because it doesn't know about
# baz.h and therefore the change we just made to it.
test.up_to_date(options = "--implicit-deps-unchanged",
                arguments = variant_prog_obj)

# Now rebuild it normally.
test.not_up_to_date(arguments = variant_prog_obj)

# And rebuild its executable, just so everything's normal.
test.run(arguments = variant_prog)


# Test forcing rescanning:
test.write(['include', 'foo.h'], r"""
#define FOO_STRING "include/foo.h 3\n"
#include "bar.h"
""")

test.run(arguments = "--implicit-cache " + args)

test.write(['include', 'foo.h'], r"""
#define FOO_STRING "include/foo.h 3\n"
#include "baz.h"
#include "bar.h"
""")

test.not_up_to_date(options = "--implicit-deps-unchanged",
                    arguments = variant_prog_obj)

test.write(['include', 'baz.h'], r"""
#define BAZ_STRING "include/baz.h 2\n"
""")

test.up_to_date(options = "--implicit-deps-unchanged",
                arguments = variant_prog_obj)

test.not_up_to_date(options = "--implicit-deps-changed",
                    arguments = variant_prog_obj)



test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/implicit/IMPLICIT_COMMAND_DEPENDENCIES.py

#!/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 $IMPLICIT_COMMAND_DEPENDENCIES variable controls
whether or not the implicit dependency on executed commands
is added to targets.
"""

import TestSCons

# swap slashes because on py3 on win32 inside the generated build.py 
# the backslashes are getting interpretted as unicode which is
# invalid.
python = TestSCons.python.replace('\\','//')
_python_ = TestSCons._python_

test = TestSCons.TestSCons()

test.write('file.in',     "file.in\n")

generate_build_py_py_contents = """\
#!%(python)s
import os
import sys

with open(sys.argv[1], 'w') as f:
    f.write('''\
#!/usr/bin/env %(python)s
import os
import sys
with open(sys.argv[1], 'w') as fp:
    args = [os.path.split(sys.argv[0])[1]] + sys.argv[1:]
    fp.write(" ".join(args) + '\\\\n' + '%(extra)s')
    for infile in sys.argv[2:]:
        with open(infile, 'r') as ifp:
            fp.write(ifp.read())
''')
os.chmod(sys.argv[1], 0o755)

"""

workpath = test.workpath()
test.write('SConstruct', """
DefaultEnvironment(tools=[])
generate = Builder(action = r'%(_python_)s $GENERATE $TARGET')
build = Builder(action = r'%(_python_)s $BUILD_PY $TARGET $SOURCES')
cd_and_build = Builder(action = r'cd %(workpath)s && %(_python_)s $BUILD_PY $TARGET $SOURCES')
env = Environment(tools=[],
                  BUILDERS = {
                        'GenerateBuild' : generate,
                        'BuildFile' : build,
                        'CdAndBuildFile': cd_and_build,
                  },
                  GENERATE = 'generate_build_py.py',
                  BUILD_PY = 'build.py',
                  )
env.PrependENVPath('PATH', '.')
env.PrependENVPath('PATHEXT', '.PY')
env0        = env.Clone(IMPLICIT_COMMAND_DEPENDENCIES = 0)
env1        = env.Clone(IMPLICIT_COMMAND_DEPENDENCIES = 1)
env2        = env.Clone(IMPLICIT_COMMAND_DEPENDENCIES = 2)
envAll      = env.Clone(IMPLICIT_COMMAND_DEPENDENCIES = 'all')
envNone     = env.Clone(IMPLICIT_COMMAND_DEPENDENCIES = None)
envFalse    = env.Clone(IMPLICIT_COMMAND_DEPENDENCIES = False)
envTrue     = env.Clone(IMPLICIT_COMMAND_DEPENDENCIES = True)

build_py = env.GenerateBuild('${BUILD_PY}', [])
AlwaysBuild(build_py)

env.BuildFile('file.out',               'file.in')
env0.BuildFile('file0.out',             'file.in')
env1.BuildFile('file1.out',             'file.in')
env2.BuildFile('file2.out',             'file.in')
envAll.BuildFile('fileall.out',         'file.in')
envNone.BuildFile('fileNone.out',       'file.in')
envFalse.BuildFile('fileFalse.out',     'file.in')
envTrue.BuildFile('fileTrue.out',       'file.in')
envTrue.BuildFile('fileQuote.out',      'file.in', BUILD_PY='"build.py"')

env1.CdAndBuildFile('cd_file1.out',     'file.in')
env2.CdAndBuildFile('cd_file2.out',     'file.in')
envAll.CdAndBuildFile('cd_fileall.out', 'file.in')
""" % locals())



def run_test(extra, python, _python_):
    # Write the generate_build_py.py file. This uses the contents of the
    # variable "extra" while writing build.py.
    test.write('generate_build_py.py',
               generate_build_py_py_contents % locals())

    # Run the SConscript file.
    test.run(arguments = '--tree=all .')

    # Generate some expected data of actions involving build.py. This expected
    # data depends on the value of "extra".
    build_none = 'build.py %s file.in\nfile.in\n'
    build_extra = (build_none if not extra else
        'build.py %s file.in\n{}file.in\n'.format(
            extra.replace('\\\\n', '\n')))
    build_extra_abs = '{} %s file.in\n{}file.in\n'.format(
        test.workpath('build.py'),
        extra.replace('\\\\n', '\n'))

    empty_none = 'empty.py %s file.in\nfile.in\n'

    # Verify that the output matches what is expected.
    test.must_match('file.out',       build_none % 'file.out', mode='r')
    test.must_match('file0.out',      build_none % 'file0.out', mode='r')
    test.must_match('file1.out',      build_none % 'file1.out', mode='r')
    test.must_match('file2.out',      build_extra % 'file2.out', mode='r')
    test.must_match('fileall.out',    build_extra % 'fileall.out', mode='r')
    test.must_match('fileNone.out',   build_none % 'fileNone.out', mode='r')
    test.must_match('fileFalse.out',  build_none % 'fileFalse.out', mode='r')
    test.must_match('fileTrue.out',   build_none % 'fileTrue.out', mode='r')
    test.must_match('fileQuote.out',  build_none % 'fileQuote.out', mode='r')
    test.must_match('cd_file1.out',   build_none % 'cd_file1.out', mode='r')
    test.must_match('cd_file2.out',   build_extra % 'cd_file2.out', mode='r')
    test.must_match('cd_fileall.out', build_extra % 'cd_fileall.out', mode='r')


run_test('', python, _python_)
run_test('xyzzy\\\\n', python, _python_)



test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/implicit/asynchronous-modification.py

#!/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 expected behavior when an implicit dependency is modified
asynchronously (that is, mid-build and without our knowledge).

Test case courtesy Greg Noel.
"""

import TestSCons

_python_ = TestSCons._python_

test = TestSCons.TestSCons()

test.write(['SConstruct'], """\
import SCons.Defaults
DefaultEnvironment(tools=[])
env = Environment(tools=[]) 
env['BUILDERS']['C'] = Builder(action = Copy('$TARGET', '$SOURCE'),
                               source_scanner = SCons.Defaults.CScan)
env['BUILDERS']['Mod'] = Builder(action = r'%(_python_)s mod.py')
Alias('seq', env.C('one.c'))
Alias('seq', env.Mod('mod', 'mod.py'))
Alias('seq', env.C('two.c'))
Default('seq')
""" % locals())

test.write(['hdr.h'], """\
/* empty header */
""")

test.write(['mod.py'], """\
with open('mod', 'w') as f, open('mod.py', 'r') as ifp:
    f.write(ifp.read())
with open('hdr.h', 'w') as f:
    f.write("/* modified */\\n")
""")

test.write(['one.c'], """\
#include "hdr.h"
""")

test.write(['two.c'], """\
#include "hdr.h"
""")

# The first run builds the file 'one', then runs the 'mod' script
# (which update modifies the 'hdr.h' file) then builds the file 'two'.
test.run(arguments = 'seq')

# The 'hdr.h' file had its original contents when 'one' was built,
# and modified contents when 'two' was built.  Because we took a
# look at 'hdr.h' once, up front, we think both files are out of
# date and will rebuild both (even though 'two' is really up to date).
#
# A future enhancement might add some sort of verification mode that
# would examine 'hdr.h' again when 'two' was built, thereby avoiding
# the unnecessary rebuild.  In that case, the second line below
# will need to change to "test.up_to_date(...)".
test.not_up_to_date(arguments = 'one')
test.not_up_to_date(arguments = 'two')

# Regardless of what happened on the middle run(s), both files should
# be up to date now.
test.up_to_date(arguments = 'seq')

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/implicit/changed-node.py

#!/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 don't throw an exception if a stored implicit
dependency has changed
"""

import TestSCons

test = TestSCons.TestSCons()


test.subdir('d',
            ['d', '1'],
            ['d', '2'],
            ['d', '3'])

test.write('SConstruct', """\
DefaultEnvironment(tools=[])
SetOption('implicit_cache', 1)
SetOption('max_drift', 1)

def lister(target, source, env):
    import os
    with open(str(target[0]), 'w') as ofp:
        s = str(source[0])
        if os.path.isdir(s):
            for l in os.listdir(str(source[0])):
                ofp.write(l + '\\n')
        else:
            ofp.write(s + '\\n')

builder = Builder(action=lister,
                  source_factory=Dir,
                  source_scanner=DirScanner)
env = Environment(tools=[])
env['BUILDERS']['builder'] = builder
env.builder('d/xfactor', 'd/1')
env.builder('a', 'd')
""")

test.write(['d', '1', 'x'], "d/1/x\n")
test.write(['d', '1', 'y'], "d/1/y\n")
test.write(['d', '1', 'z'], "d/1/z\n")
test.write(['d', '2', 'x'], "d/2/x\n")
test.write(['d', '2', 'y'], "d/2/y\n")
test.write(['d', '2', 'z'], "d/2/x\n")
test.write(['d', '3', 'x'], "d/3/x\n")
test.write(['d', '3', 'y'], "d/3/y\n")
test.write(['d', '3', 'z'], "d/3/z\n")

test.run('--debug=stacktrace')


test.write('SConstruct', """\
SetOption('implicit_cache', 1)
SetOption('max_drift', 1)

def lister(target, source, env):
    import os.path
    with open(str(target[0]), 'w') as ofp:
        s = str(source[0])
        if os.path.isdir(s):
            for l in os.listdir(str(source[0])):
                ofp.write(l + '\\n')
        else:
            ofp.write(s + '\\n')

builder = Builder(action=lister,
                  source_factory=File)
env = Environment(tools=[])
env['BUILDERS']['builder'] = builder

env.builder('a', 'SConstruct')
""")

test.run('--debug=stacktrace')

test.pass_test()


#from os import system, rmdir, remove, mkdir, listdir
#from os.path import exists, isdir
#import sys
#
#
#def setfile(f, content):
#    with open(f, 'w') as ofp:
#        ofp.write(content)
#
#def checkfile(f, content):
#    with open(f) as fp:
#        assert fp.read().strip() == content
#
#def rm(f):
#    if exists(f):
#        if isdir(f):
#            for name in listdir(f):
#                rm(f+'/'+name)
#            rmdir(f)
#        else: remove(f)
#def clean(full=0):
#    for f in ('d','b','a','SConstruct'):
#        rm(f)
#    database_name = test.get_sconsignname()
#    if full:
#        for f in (database_name + '.dblite', 'build.py'):
#            rm(f)
#
#clean(1)
#
#clean(1)

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/long-lines/live.py

#!/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 correct execution of long command lines with the live utilities
that use TempFileMunge().
"""

import sys

import TestSCons

test = TestSCons.TestSCons()

if sys.platform == 'win32':
    lib_static_lib = 'static.lib'
    lib_shared_dll ='shared.dll'
    arflag_init = '/LIBPATH:' + test.workpath()
    arflag = ' /LIBPATH:' + test.workpath()
    linkflag_init = '/LIBPATH:' + test.workpath()
    linkflag = ' /LIBPATH:' + test.workpath()
    import SCons.Tool.MSCommon as msc
    if not msc.msvc_exists():
        lib_shared_dll = 'shared.dll'
        lib_static_lib = 'libstatic.a'
        arflag_init = 'r'
        arflag = 'o'
        linkflag_init = '-L' + test.workpath()
        linkflag = ' -L' + test.workpath()    
elif sys.platform == 'cygwin':
    lib_static_lib = 'libstatic.a'
    lib_shared_dll ='shared.dll'
    arflag_init = 'r'
    arflag = 'o'
    linkflag_init = '-L' + test.workpath()
    linkflag = ' -L' + test.workpath()
elif sys.platform in ('darwin', 'irix6'):
    lib_shared_dll = 'libshared' + TestSCons._dll
    lib_static_lib = 'libstatic.a'
    arflag_init = 'r'
    arflag = 'v'
    linkflag_init = '-L' + test.workpath()
    linkflag = ' -L' + test.workpath()
else:
    lib_shared_dll = 'libshared.so'
    lib_static_lib = 'libstatic.a'
    arflag_init = 'r'
    arflag = 'o'
    linkflag_init = '-L' + test.workpath()
    linkflag = ' -L' + test.workpath()

test.write('SConstruct', """
arflags = r'%(arflag_init)s'
while len(arflags) <= 8100:
    arflags = arflags + r'%(arflag)s'

linkflags = r'%(linkflag_init)s'
while len(linkflags) <= 8100:
    linkflags = linkflags + r'%(linkflag)s'

env = Environment(ARFLAGS = '$ARXXX', ARXXX = arflags,
                  LINKFLAGS = '$LINKXXX', LINKXXX = linkflags)
env.Program(target = 'foo', source = 'foo.c')

env.StaticLibrary(target = 'static', source = 'static.c')
# SharedLibrary() uses $LINKFLAGS by default.
env.SharedLibrary(target = 'shared', source = 'shared.c', no_import_lib=1)
""" % locals())

test.write('foo.c', r"""
#include <stdio.h>
#include <stdlib.h>
int
main(int argc, char *argv[])
{
        argv[argc++] = "--";
        printf("foo.c\n");
        exit (0);
}
""")

test.write('static.c', r"""
#include <stdio.h>
#include <stdlib.h>
int
main(int argc, char *argv[])
{
        argv[argc++] = "--";
        printf("static.c\n");
        exit (0);
}
""")

test.write('shared.c', r"""
#include <stdio.h>
#include <stdlib.h>
int
main(int argc, char *argv[])
{
        argv[argc++] = "--";
        printf("shared.c\n");
        exit (0);
}
""")


test.run(arguments = '.',
         stderr=TestSCons.noisy_ar,
         match=TestSCons.match_re_dotall)

test.up_to_date(arguments = '.')

test.run(program = test.workpath('foo'), stdout = "foo.c\n")

test.must_exist(lib_static_lib)

test.must_exist(lib_shared_dll)

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/long-lines/signature.py

#!/usr/bin/env python
#
# MIT License
#
# Copyright The SCons Foundation
#
# 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 use of long command lines correctly excludes arguments
surrounded by $( $) from the signature calculation.
"""

import os
import TestSCons

_python_ = TestSCons._python_

test = TestSCons.TestSCons()

build_py = test.workpath('build.py')

# create a dummy command which understands a tempfile syntax
# so it doesn't have to be that platform/compiler's specific syntax.
test.write(build_py, """\
#!%(_python_)s
import sys
if sys.argv[1].startswith('@'):
    tempfile = sys.argv[1][1:]
    with open(tempfile, 'r') as tmp:
        args = tmp.read().split()
else:
    args = sys.argv[1:]

with open(args[0], 'w') as ofp, open(args[1], 'r') as ifp:
    ofp.write(ifp.read())
    ofp.write('FILEFLAG=%%s\\n' %% args[2])
    ofp.write('TIMESTAMP=%%s\\n' %% args[3])
""" % locals())

os.chmod(build_py, 0o755)

test.write('SConstruct', """\
DefaultEnvironment(tools=[])
arg = 'a_long_ignored_argument'
extra_arguments = arg
MAXLINE=1024
while len(extra_arguments) <= MAXLINE:
    extra_arguments = extra_arguments + ' ' + arg
env = Environment(
    tools=[],
    FILECOM=[
        r'%(build_py)s',
        '$TARGET',
        '$SOURCE',
        '$FILEFLAG',
        '$(',
        '$TIMESTAMP',
        '$)',
        '$EXTRA_ARGUMENTS',
    ],
    FILEFLAG=ARGUMENTS.get('FILEFLAG'),
    TIMESTAMP=ARGUMENTS.get('TIMESTAMP'),
    EXTRA_ARGUMENTS=extra_arguments,
    MAXLINELENGTH=MAXLINE,
    TEMPFILEPREFIX='@',
)
env.PrependENVPath('PATHEXT', '.PY')
env.Command('file.out', 'file.in', r'%(_python_)s ${TEMPFILE(FILECOM)}')
""" % locals())

test.write('file.in', "file.in\n", mode='w')

test.run(arguments='FILEFLAG=first TIMESTAMP=20090207 .')

test.must_match('file.out', "file.in\nFILEFLAG=first\nTIMESTAMP=20090207\n", mode='r')

test.up_to_date(options='FILEFLAG=first TIMESTAMP=20090208', arguments = '.')

test.run(arguments='FILEFLAG=second TIMESTAMP=20090208 .')

test.must_match('file.out', "file.in\nFILEFLAG=second\nTIMESTAMP=20090208\n", mode='r')

test.up_to_date(options='FILEFLAG=second TIMESTAMP=20090209', arguments = '.')

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/ninja/build_libraries.py

#!/usr/bin/env python
#
# Copyright The SCons Foundation
#
# 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.

import os

import TestSCons
from TestCmd import IS_WINDOWS, IS_MACOS
from TestSCons import _exe, _lib, lib_, _dll, dll_

test = TestSCons.TestSCons()

try:
    import ninja
except ImportError:
    test.skip_test("Could not find ninja module. Skipping test.\n")

ninja_binary = test.where_is('ninja')
if not ninja_binary:
    test.skip_test("Could not find ninja executable. Skipping test.\n")

ninja_bin = os.path.abspath(os.path.join(
    ninja.__file__,
    os.pardir,
    'data',
    'bin',
    'ninja' + _exe))

test.dir_fixture('ninja-fixture')

win32 = ", 'WIN32'" if IS_WINDOWS else ""

test.write('SConstruct', """
SetOption('experimental', 'ninja')
DefaultEnvironment(tools=[])
env = Environment()
env.Tool('ninja')
env['NINJA'] = r"%(ninja_bin)s"

shared_lib = env.SharedLibrary(target='test_impl', source='test_impl.c', CPPDEFINES=['LIBRARY_BUILD'%(win32)s])
env.Program(target='test', source='test1.c', LIBS=['test_impl'], LIBPATH=['.'], RPATH='.')
static_obj = env.Object(target='test_impl_static', source='test_impl.c')
static_lib = env.StaticLibrary(target='test_impl_static', source=static_obj)
static_obj = env.Object(target='test_static', source='test1.c')
env.Program(target='test_static', source=static_obj, LIBS=[static_lib], LIBPATH=['.'])
""" % locals())

# generate simple build
test.run(stdout=None)
test.must_contain_all_lines(test.stdout(), ['Generating: build.ninja'])
test.must_contain_all(test.stdout(), 'Executing:')
test.must_contain_all(test.stdout(), 'ninja%(_exe)s -f' % locals())
test.run(program=test.workpath('test'), stdout="library_function")
test.run(program=test.workpath('test_static'), stdout="library_function")

# clean build and ninja files
test.run(arguments='-c', stdout=None)
test.must_contain_all_lines(
    test.stdout(),
    [
        ('Removed %stest_impl' % dll_) + _dll,
        'Removed test' + _exe,
        ('Removed %stest_impl_static' % lib_) + _lib,
        'Removed test_static' + _exe,
        'Removed build.ninja',
    ],
)

# only generate the ninja file
test.run(arguments='--disable-execute-ninja', stdout=None)
test.must_contain_all_lines(test.stdout(), ['Generating: build.ninja'])
test.must_not_exist(test.workpath('test'))
test.must_not_exist(test.workpath('test_static'))

# run ninja independently
program = test.workpath('run_ninja_env.bat') if IS_WINDOWS else ninja_bin
test.run(program=program, stdout=None)
test.run(program=test.workpath('test'), stdout="library_function")
test.run(program=test.workpath('test_static'), stdout="library_function")

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/ninja/command_line_targets.py

#!/usr/bin/env python
#
# Copyright The SCons Foundation
#
# 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.
#

import os

import TestSCons

test = TestSCons.TestSCons()

try:
    import ninja
except ImportError:
    test.skip_test("Could not find module in python")

_python_ = TestSCons._python_
_exe = TestSCons._exe

ninja_bin = os.path.abspath(os.path.join(
    ninja.__file__,
    os.pardir,
    'data',
    'bin',
    'ninja' + _exe))

test.dir_fixture('ninja-fixture')

test.file_fixture('ninja_test_sconscripts/sconstruct_default_targets', 'SConstruct')

# generate simple build
test.run(arguments=['out1.txt'], stdout=None)
test.must_contain_all_lines(test.stdout(), ['Generating: build.ninja'])
test.must_contain_all(test.stdout(), 'Executing:')
test.must_contain_all(test.stdout(), 'ninja%(_exe)s -f' % locals())
test.must_contain_all(test.stdout(), 'build.ninja -j1 out1.txt')
test.must_exist([test.workpath('out1.txt')])
test.must_not_exist([test.workpath('out2.txt')])

# clean build and ninja files
test.run(arguments='-c', stdout=None)
test.must_contain_all_lines(test.stdout(), [
    'Removed out1.txt',
    'Removed build.ninja'])

# generate simple build
test.run(arguments=['out2.txt'], stdout=None)
test.must_contain_all_lines(test.stdout(), ['Generating: build.ninja'])
test.must_contain_all(test.stdout(), 'Executing:')
test.must_contain_all(test.stdout(), 'ninja%(_exe)s -f' % locals())
test.must_contain_all(test.stdout(), 'build.ninja -j1 out2.txt')
test.must_not_exist([test.workpath('out1.txt')])
test.must_exist([test.workpath('out2.txt')])

# clean build and ninja files
test.run(arguments='-c', stdout=None)
test.must_contain_all_lines(test.stdout(), [
    'Removed out2.txt',
    'Removed build.ninja'])

test.run(arguments=['out1.txt', 'out2.txt'], stdout=None)
test.must_contain_all_lines(test.stdout(), ['Generating: build.ninja'])
test.must_contain_all(test.stdout(), 'Executing:')
test.must_contain_all(test.stdout(), 'ninja%(_exe)s -f' % locals())
test.must_contain_all(test.stdout(), 'build.ninja -j1 out1.txt out2.txt')
test.must_exist([test.workpath('out1.txt')])
test.must_exist([test.workpath('out2.txt')])

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/ninja/copy_function_command.py

#!/usr/bin/env python
#
# Copyright The SCons Foundation
#
# 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.
#

import os

import TestSCons
from TestCmd import IS_WINDOWS

test = TestSCons.TestSCons()

try:
    import ninja
except ImportError:
    test.skip_test("Could not find module in python")

_python_ = TestSCons._python_
_exe = TestSCons._exe

ninja_bin = os.path.abspath(os.path.join(
    ninja.__file__,
    os.pardir,
    'data',
    'bin',
    'ninja' + _exe))

test.dir_fixture('ninja-fixture')

test.write('SConstruct', """
SetOption('experimental','ninja')
DefaultEnvironment(tools=[])
env = Environment()
env.Tool('ninja')
env.Command('foo2.c', ['foo.c'], Copy('$TARGET','$SOURCE'))
env.Program(target = 'foo', source = 'foo2.c')
""")

# generate simple build
test.run(stdout=None)
test.must_contain_all_lines(test.stdout(), ['Generating: build.ninja'])
test.must_contain_all(test.stdout(), 'Executing:')
test.must_contain_all(test.stdout(), 'ninja%(_exe)s -f' % locals())
test.run(program=test.workpath('foo'), stdout="foo.c")

# clean build and ninja files
test.run(arguments='-c', stdout=None)
test.must_contain_all_lines(test.stdout(), [
    'Removed foo2.o',
    'Removed foo2.c',
    'Removed foo' + _exe,
    'Removed build.ninja'])

# only generate the ninja file
test.run(arguments='--disable-execute-ninja', stdout=None)
test.must_contain_all_lines(test.stdout(), ['Generating: build.ninja'])
test.must_not_exist(test.workpath('foo'))

# run ninja independently
program = test.workpath('run_ninja_env.bat') if IS_WINDOWS else ninja_bin
test.run(program=program, stdout=None)
test.run(program=test.workpath('foo'), stdout="foo.c")

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/ninja/default_targets.py

#!/usr/bin/env python
#
# Copyright The SCons Foundation
#
# 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.
#

import os

import TestSCons
from TestCmd import IS_WINDOWS

test = TestSCons.TestSCons()

try:
    import ninja
except ImportError:
    test.skip_test("Could not find module in python")

_python_ = TestSCons._python_
_exe = TestSCons._exe

ninja_bin = os.path.abspath(os.path.join(
    ninja.__file__,
    os.pardir,
    'data',
    'bin',
    'ninja' + _exe))

test.dir_fixture('ninja-fixture')

test.file_fixture('ninja_test_sconscripts/sconstruct_default_targets', 'SConstruct')

# generate simple build
test.run(stdout=None)
test.must_contain_all_lines(test.stdout(), ['Generating: build.ninja'])
test.must_contain_all(test.stdout(), 'Executing:')
test.must_contain_all(test.stdout(), 'ninja%(_exe)s -f' % locals())
test.must_not_exist([test.workpath('out1.txt')])
test.must_exist([test.workpath('out2.txt')])

# clean build and ninja files
test.run(arguments='-c', stdout=None)
test.must_contain_all_lines(test.stdout(), [
    'Removed out2.txt',
    'Removed build.ninja'])

# only generate the ninja file
test.run(arguments='--disable-execute-ninja', stdout=None)
test.must_contain_all_lines(test.stdout(), ['Generating: build.ninja'])
test.must_not_exist(test.workpath('out1.txt'))
test.must_not_exist(test.workpath('out2.txt'))

# run ninja independently
program = test.workpath('run_ninja_env.bat') if IS_WINDOWS else ninja_bin
test.run(program=program, stdout=None)
test.must_not_exist([test.workpath('out1.txt')])
test.must_exist(test.workpath('out2.txt'))

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/ninja/force_scons_callback.py

#!/usr/bin/env python
#
# Copyright The SCons Foundation
#
# 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.
#

import os

import TestSCons
from TestCmd import IS_WINDOWS

test = TestSCons.TestSCons()

try:
    import ninja
except ImportError:
    test.skip_test("Could not find module in python")

_python_ = TestSCons._python_
_exe = TestSCons._exe

ninja_bin = os.path.abspath(
    os.path.join(ninja.__file__, os.pardir, "data", "bin", "ninja" + _exe)
)

test.dir_fixture("ninja-fixture")

test.file_fixture(
    "ninja_test_sconscripts/sconstruct_force_scons_callback", "SConstruct"
)

# generate simple build
test.run(stdout=None)
test.must_contain_all_lines(test.stdout(), ["Generating: build.ninja"])
test.must_contain_all(test.stdout(), "Executing:")
test.must_contain_all(test.stdout(), "ninja%(_exe)s -f" % locals())
if test.stdout().count("Defer to SCons to build") != 1:
    test.fail_test()
test.must_match("out.txt", "foo.c" + os.linesep)
test.must_match("out2.txt", "test2.cpp" + os.linesep)

# clean build and ninja files
test.run(arguments="-c", stdout=None)
test.must_contain_all_lines(
    test.stdout(), ["Removed out.txt", "Removed out2.txt", "Removed build.ninja"]
)

# only generate the ninja file
test.run(arguments="--disable-execute-ninja", stdout=None)
test.must_contain_all_lines(test.stdout(), ["Generating: build.ninja"])
test.must_not_exist(test.workpath("out.txt"))
test.must_not_exist(test.workpath("out2.txt"))

# run ninja independently
program = test.workpath("run_ninja_env.bat") if IS_WINDOWS else ninja_bin
test.run(program=program, stdout=None)
if test.stdout().count("Defer to SCons to build") != 1:
    test.fail_test()
test.must_match("out.txt", "foo.c" + os.linesep)
test.must_match("out2.txt", "test2.cpp" + os.linesep)

# only generate the ninja file with specific NINJA_SCONS_DAEMON_PORT
test.run(arguments="PORT=9999 --disable-execute-ninja", stdout=None)
# Verify that port # propagates to call to ninja_run_daemon.py
test.must_contain(test.workpath("build.ninja"), "PORT = 9999")

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/ninja/generate_and_build.py

#!/usr/bin/env python
#
# Copyright The SCons Foundation
#
# 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.
#

import os

import TestSCons
from TestCmd import IS_WINDOWS

test = TestSCons.TestSCons()

try:
    import ninja
except ImportError:
    test.skip_test("Could not find module in python")

_python_ = TestSCons._python_
_exe = TestSCons._exe

ninja_bin = os.path.abspath(os.path.join(
    ninja.__file__,
    os.pardir,
    'data',
    'bin',
    'ninja' + _exe))

test.dir_fixture('ninja-fixture')

test.file_fixture('ninja_test_sconscripts/sconstruct_generate_and_build', 'SConstruct')

# generate simple build
test.run(stdout=None, arguments='NINJA_CMD_ARGS=-v')
test.must_contain_all_lines(test.stdout(), ['Generating: build.ninja'])
test.must_contain_all(test.stdout(), 'Executing:')
test.must_contain_all(test.stdout(), 'ninja%(_exe)s -f' % locals())
test.must_contain_all(test.stdout(), ' -j1 -v')
test.run(program=test.workpath('foo' + _exe), stdout="foo.c")

# Test multiple args for NINJA_CMD_ARGS
test.run(stdout=None, arguments={'NINJA_CMD_ARGS':"-v -j3"})
test.must_contain_all(test.stdout(), ' -v -j3')

# clean build and ninja files
test.run(arguments='-c', stdout=None)
test.must_contain_all_lines(test.stdout(), [
    'Removed foo.o',
    'Removed foo',
    'Removed build.ninja'])

# only generate the ninja file
test.run(arguments='--disable-execute-ninja', stdout=None)
test.must_contain_all_lines(test.stdout(), ['Generating: build.ninja'])
test.must_not_exist(test.workpath('foo' + _exe))

# run ninja independently
program = test.workpath('run_ninja_env.bat') if IS_WINDOWS else ninja_bin
test.run(program=program, stdout=None)
test.run(program=test.workpath('foo' + _exe), stdout="foo.c")

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/ninja/generate_and_build_cxx.py

#!/usr/bin/env python
#
# Copyright The SCons Foundation
#
# 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.
#

import os

import TestSCons
from TestCmd import IS_WINDOWS

test = TestSCons.TestSCons()

try:
    import ninja
except ImportError:
    test.skip_test("Could not find module in python")

_python_ = TestSCons._python_
_exe = TestSCons._exe

ninja_bin = os.path.abspath(os.path.join(
    ninja.__file__,
    os.pardir,
    'data',
    'bin',
    'ninja' + _exe))

test.dir_fixture('ninja-fixture')

test.file_fixture('ninja_test_sconscripts/sconstruct_generate_and_build_cxx',
                  'SConstruct')

# generate simple build
test.run()
test.must_contain_all_lines(test.stdout(), ['Generating: build.ninja'])
test.must_contain_all(test.stdout(), 'Executing:')
test.must_contain_all(test.stdout(), 'ninja%(_exe)s -f' % locals())
test.run(program=test.workpath('test2' + _exe), stdout="print_function")

# clean build and ninja files
test.run(arguments='-c', stdout=None)
test.must_contain_all_lines(test.stdout(), [
    'Removed test2.o',
    'Removed test2',
    'Removed build.ninja'])

# only generate the ninja file
test.run(arguments='--disable-execute-ninja', stdout=None)
test.must_contain_all_lines(test.stdout(), ['Generating: build.ninja'])
test.must_not_exist(test.workpath('test2' + _exe))

# run ninja independently
program = test.workpath('run_ninja_env.bat') if IS_WINDOWS else ninja_bin
test.run(program=program, stdout=None)
test.run(program=test.workpath('test2' + _exe), stdout="print_function")

test.write('test2.hpp', """
#include <string>
#include <iostream>

class Foo
{
public:
    int print_function();
    int print_function2(){
        std::cout << "2";
        return 0;
    };
};
""")

# generate simple build
test.run(program=program, stdout=None)
test.run(program=test.workpath('test2' + _exe), stdout="print_function2")

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/ninja/generate_source.py

#!/usr/bin/env python
#
# Copyright The SCons Foundation
#
# 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.
#

import os

import TestSCons
from TestCmd import IS_WINDOWS

test = TestSCons.TestSCons()

try:
    import ninja
except ImportError:
    test.skip_test("Could not find module in python")

_python_ = TestSCons._python_
_exe = TestSCons._exe

ninja_bin = os.path.abspath(os.path.join(
    ninja.__file__,
    os.pardir,
    'data',
    'bin',
    'ninja' + _exe))

test.dir_fixture('ninja-fixture')

shell = '' if IS_WINDOWS else './'

test.write('SConstruct', """
SetOption('experimental','ninja')
DefaultEnvironment(tools=[])

env = Environment()
env.Tool('ninja')
prog = env.Program(target = 'generate_source', source = 'generate_source.c')
env.Command('generated_source.c', prog, '%(shell)sgenerate_source%(_exe)s')
env.Program(target = 'generated_source', source = 'generated_source.c')
""" % locals())

test.write('generate_source.c', """
#include <stdio.h>

int main(int argc, char *argv[]) {
    FILE *fp;

    fp = fopen("generated_source.c", "w");
    fprintf(fp, "#include <stdio.h>\\n");
    fprintf(fp, "#include <stdlib.h>\\n");
    fprintf(fp, "\\n");
    fprintf(fp, "int\\n");
    fprintf(fp, "main(int argc, char *argv[])\\n");
    fprintf(fp, "{\\n");
    fprintf(fp, "        printf(\\"generated_source.c\\");\\n");
    fprintf(fp, "        exit (0);\\n");
    fprintf(fp, "}\\n");
    fclose(fp);
}
""")

# generate simple build
test.run(stdout=None)
test.must_contain_all_lines(test.stdout(), ['Generating: build.ninja'])
test.must_contain_all(test.stdout(), 'Executing:')
test.must_contain_all(test.stdout(), 'ninja%(_exe)s -f' % locals())
test.run(program=test.workpath('generated_source' + _exe), stdout="generated_source.c")

# clean build and ninja files
test.run(arguments='-c', stdout=None)
test.must_contain_all_lines(test.stdout(), [
    'Removed generate_source.o',
    'Removed generate_source' + _exe,
    'Removed generated_source.c',
    'Removed generated_source.o',
    'Removed generated_source' + _exe,
    'Removed build.ninja'])

# only generate the ninja file
test.run(arguments='--disable-execute-ninja', stdout=None)
test.must_contain_all_lines(test.stdout(), ['Generating: build.ninja'])
test.must_not_exist(test.workpath('generated_source' + _exe))

# run ninja independently
program = test.workpath('run_ninja_env.bat') if IS_WINDOWS else ninja_bin
test.run(program=program, stdout=None)
test.run(program=test.workpath('generated_source' + _exe), stdout="generated_source.c")

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/ninja/generated_sources_alias.py

#!/usr/bin/env python
#
# Copyright The SCons Foundation
#
# 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.
#

import os

import TestSCons
from TestCmd import IS_WINDOWS

test = TestSCons.TestSCons()

try:
    import ninja
except ImportError:
    test.skip_test("Could not find module in python")

_python_ = TestSCons._python_
_exe = TestSCons._exe

ninja_bin = os.path.abspath(os.path.join(
    ninja.BIN_DIR,
    'ninja' + _exe))

test.dir_fixture('ninja-fixture')

test.file_fixture('ninja_test_sconscripts/sconstruct_generated_sources_alias', 'SConstruct')

for alias_value in [0, 1]:

    # Gen with source alias
    test.run(arguments=['--disable-execute-ninja', f'USE_GEN_SOURCE_ALIAS={alias_value}'], stdout=None)
    test.must_contain_all_lines(test.stdout(), ['Generating: build.ninja'])
    test.must_not_exist(test.workpath('gen_source' + _exe))

    # run ninja independently
    program = test.workpath('run_ninja_env.bat') if IS_WINDOWS else ninja_bin
    test.run(program=program, stdout=None)
    test.run(program=test.workpath('gen_source' + _exe), stdout="4")

    # generate simple build
    test.run(arguments=[f'USE_GEN_SOURCE_ALIAS={alias_value}'], stdout=None)
    test.must_contain_all_lines(test.stdout(), ['Generating: build.ninja'])
    test.must_contain_all(test.stdout(), 'Executing:')
    test.must_contain_all(test.stdout(), 'ninja%(_exe)s -f' % locals())
    test.run(program=test.workpath('gen_source' + _exe), stdout="4")

    # clean build and ninja files
    test.run(arguments=[f'USE_GEN_SOURCE_ALIAS={alias_value}', '-c'], stdout=None)
    test.must_contain_all_lines(test.stdout(), [
        'Removed generated_header1.htest',
        'Removed generated_header2.htest',
        'Removed generated_header2.c',
        'Removed build.ninja'])


test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/ninja/iterative_speedup.py

#!/usr/bin/env python
#
# Copyright The SCons Foundation
#
# 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.
#

import os
import random
import time

import TestSCons
from TestCmd import IS_WINDOWS

test = TestSCons.TestSCons()

try:
    import ninja
except ImportError:
    test.skip_test("Could not find module in python")

_python_ = TestSCons._python_
_exe = TestSCons._exe

ninja_bin = os.path.abspath(os.path.join(
    ninja.__file__,
    os.pardir,
    'data',
    'bin',
    'ninja' + _exe))

test.dir_fixture('ninja-fixture')

test.write('source_0.c', """
#include <stdio.h>
#include <stdlib.h>
#include "source_0.h"

int
print_function0()
{
    printf("main print");
    return 0;
}
""")

test.write('source_0.h', """
#include <stdio.h>
#include <stdlib.h>

int
print_function0();
""")


def get_num_cpus():
    """
    Function to get the number of CPUs the system has.
    """
    # Linux, Unix and MacOS:
    if hasattr(os, "sysconf"):
        if 'SC_NPROCESSORS_ONLN' in os.sysconf_names:
            # Linux & Unix:
            ncpus = os.sysconf("SC_NPROCESSORS_ONLN")
        if isinstance(ncpus, int) and ncpus > 0:
            return ncpus
        # OSX:
        return int(os.popen("sysctl -n hw.ncpu")[1].read())
    # Windows:
    if 'NUMBER_OF_PROCESSORS' in os.environ:
        ncpus = int(os.environ["NUMBER_OF_PROCESSORS"])
    if ncpus > 0:
        return ncpus
    # Default
    return 1


def generate_source(parent_source, current_source):
    test.write('source_{}.c'.format(current_source), """
        #include <stdio.h>
        #include <stdlib.h>
        #include "source_%(parent_source)s.h"
        #include "source_%(current_source)s.h"

        int
        print_function%(current_source)s()
        {
            return print_function%(parent_source)s();
        }
        """ % locals())

    test.write('source_{}.h'.format(current_source), """
        #include <stdio.h>
        #include <stdlib.h>

        int
        print_function%(current_source)s();
        """ % locals())


def mod_source_return(test_num):
    parent_source = test_num - 1
    test.write('source_{}.c'.format(test_num), """
        #include <stdio.h>
        #include <stdlib.h>
        #include "source_%(parent_source)s.h"
        #include "source_%(test_num)s.h"

        int
        print_function%(test_num)s()
        {
            int test = 5 + 5;
            print_function%(parent_source)s();
            return test;
        }
        """ % locals())


def mod_source_orig(test_num):
    parent_source = test_num - 1
    test.write('source_{}.c'.format(test_num), """
        #include <stdio.h>
        #include <stdlib.h>
        #include "source_%(parent_source)s.h"
        #include "source_%(test_num)s.h"

        int
        print_function%(test_num)s()
        {
            return print_function%(parent_source)s();
        }
        """ % locals())


num_source = 200
for i in range(1, num_source + 1):
    generate_source(i - 1, i)

test.write('main.c', """
#include <stdio.h>
#include <stdlib.h>
#include "source_%(num_source)s.h"
int
main()
{
    print_function%(num_source)s();
    exit(0);
}
""" % locals())

test.write('SConstruct', """
SetOption('experimental','ninja')
DefaultEnvironment(tools=[])

env = Environment()
env.Tool('ninja')
sources = ['main.c'] + env.Glob('source*.c')
env.Program(target = 'print_bin', source = sources)
""")

test.write('SConstruct_no_ninja', """
env = Environment()
sources = ['main.c'] + env.Glob('source*.c')
env.Program(target = 'print_bin', source = sources)
""")

tests_mods = []
ninja_times = []
scons_times = []
for _ in range(10):
    tests_mods += [random.randrange(1, num_source, 1)]
jobs = '-j' + str(get_num_cpus())

ninja_program = [test.workpath('run_ninja_env.bat'), jobs] if IS_WINDOWS else [ninja_bin, jobs]

test.run(arguments='--disable-execute-ninja', stdout=None)
test.run(program=ninja_program, arguments='run-ninja-scons-daemon', stdout=None)
start = time.perf_counter()
test.run(program=ninja_program, stdout=None)
stop = time.perf_counter()
ninja_times += [stop - start]
test.run(program=test.workpath('print_bin'), stdout="main print")


for test_mod in tests_mods:
    mod_source_return(test_mod)
    start = time.perf_counter()
    test.run(program=ninja_program, stdout=None)
    stop = time.perf_counter()
    ninja_times += [stop - start]

for test_mod in tests_mods:
    mod_source_orig(test_mod)

# clean build and ninja files
test.run(arguments='-c', stdout=None)
test.must_contain_all_lines(test.stdout(), [
    'Removed build.ninja'])

start = time.perf_counter()
test.run(arguments=["-f", "SConstruct_no_ninja", jobs], stdout=None)
stop = time.perf_counter()
scons_times += [stop - start]
test.run(program=test.workpath('print_bin'), stdout="main print")

for test_mod in tests_mods:
    mod_source_return(test_mod)
    start = time.perf_counter()
    test.run(arguments=["-f", "SConstruct_no_ninja", jobs], stdout=None)
    stop = time.perf_counter()
    scons_times += [stop - start]

full_build_print = True
for ninja_time, scons_time in zip(ninja_times, scons_times):
    if ninja_time > scons_time:
        test.fail_test(message="Ninja was slower than SCons: SCons: {:.3f}s Ninja: {:.3f}s".format(scons_time, ninja_time))
    if full_build_print:
        full_build_print = False
        print("Clean build {} files - SCons: {:.3f}s Ninja: {:.3f}s".format(num_source, scons_time, ninja_time))
    else:
        print("Single File Rebuild   - SCons: {:.3f}s Ninja: {:.3f}s".format(scons_time, ninja_time))

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/ninja/mingw_command_generator_action.py

#!/usr/bin/env python
#
# Copyright The SCons Foundation
#
# 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.
#

import os
import sys

import TestSCons
from TestCmd import IS_WINDOWS
import SCons
from SCons.Platform.mingw import MINGW_DEFAULT_PATHS
from SCons.Platform.cygwin import CYGWIN_DEFAULT_PATHS

test = TestSCons.TestSCons()

if sys.platform not in ('cygwin', 'win32',):
    test.skip_test("Skipping mingw test on non-Windows platform %s." % sys.platform)

dp = MINGW_DEFAULT_PATHS + CYGWIN_DEFAULT_PATHS
gcc = SCons.Tool.find_program_path(test.Environment(), 'gcc', default_paths=dp)
if not gcc:
    test.skip_test("Skipping mingw test, no MinGW found.\n")

# ninja must have the os environment setup to work properly
os.environ["PATH"] += os.pathsep + os.path.dirname(gcc)

try:
    import ninja
except ImportError:
    test.skip_test("Could not find module in python")

_python_ = TestSCons._python_
_exe = TestSCons._exe

ninja_bin = os.path.abspath(os.path.join(
    ninja.BIN_DIR,
    'ninja' + _exe))

test.dir_fixture('ninja-fixture')

test.file_fixture('ninja_test_sconscripts/sconstruct_mingw_command_generator_action', 'SConstruct')

# generate simple build
test.run(stdout=None)
test.must_contain_all_lines(test.stdout(), ['Generating: build.ninja'])
test.must_contain_all(test.stdout(), 'Executing:')
test.must_contain_all(test.stdout(), 'ninja%(_exe)s -f' % locals())
test.run(program=test.workpath('test' + _exe), stdout="library_function")

# clean build and ninja files
test.run(arguments='-c', stdout=None)

# only generate the ninja file
test.run(arguments='--disable-execute-ninja', stdout=None)
test.must_contain_all_lines(test.stdout(), ['Generating: build.ninja'])
test.must_not_exist(test.workpath('test' + _exe))

# run ninja independently
program = test.workpath('run_ninja_env.bat') if IS_WINDOWS else ninja_bin
test.run(program=program, stdout=None)
test.run(program=test.workpath('test' + _exe), stdout="library_function")

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/ninja/mingw_depfile_format.py

#!/usr/bin/env python
#
# Copyright The SCons Foundation
#
# 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.
#

import os

import TestSCons

test = TestSCons.TestSCons()

try:
    import ninja
except ImportError:
    test.skip_test("Could not find module in python")

_python_ = TestSCons._python_
_exe = TestSCons._exe

ninja_bin = os.path.abspath(os.path.join(
    ninja.BIN_DIR,
    'ninja' + _exe))

test.dir_fixture('ninja-fixture')

test.file_fixture('ninja_test_sconscripts/sconstruct_mingw_depfile_format', 'SConstruct')

# generate simple build
test.run(stdout=None)
test.must_contain_all_lines(test.stdout(), ['Generating: build.ninja'])
test.must_contain_all(test.stdout(), 'Executing:')
test.must_contain_all(test.stdout(), 'ninja%(_exe)s -f' % locals())
test.must_contain(test.workpath('build.ninja'), 'deps = msvc')

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/ninja/mkdir_function_command.py

#!/usr/bin/env python
#
# Copyright The SCons Foundation
#
# 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.
#

import os

import TestSCons
from TestCmd import IS_WINDOWS

test = TestSCons.TestSCons()

try:
    import ninja
except ImportError:
    test.skip_test("Could not find module in python")

_python_ = TestSCons._python_
_exe = TestSCons._exe

ninja_bin = os.path.abspath(os.path.join(
    ninja.__file__,
    os.pardir,
    'data',
    'bin',
    'ninja' + _exe))

test.write('SConstruct', """
SetOption('experimental','ninja')
DefaultEnvironment(tools=[])
env = Environment()
env.Tool('ninja')
env.Dir('test0')
env.Dir('test1/test2')
env.Dir('test3/test4')
env.Command('test5', 'test3/test4', Mkdir('$TARGET'))
env.Command('test6/test7', ['test1/test2', 'test0'], Mkdir('$TARGET'))
""")

# generate simple build
test.run(stdout=None)
test.must_contain_all_lines(test.stdout(), ['Generating: build.ninja'])
test.must_contain_all(test.stdout(), 'Executing:')
test.must_contain_single_instance_of(test.stdout(), ["scons: Building targets ..."])
test.must_contain_all(test.stdout(), 'ninja%(_exe)s -f' % locals())
test.must_exist([
    test.workpath('test0'),
    test.workpath('test1/test2'),
    test.workpath('test3/test4'),
    test.workpath('test5'),
    test.workpath('test6/test7')
])

# clean build and ninja files
test.run(arguments='-c', stdout=None)
test.must_contain_all_lines(test.stdout(), [
    'Removed build.ninja'])
os.rmdir('test0')
os.rmdir('test1/test2')
os.rmdir('test1')
os.rmdir('test3/test4')
os.rmdir('test3')
os.rmdir('test5')
os.rmdir('test6/test7')
os.rmdir('test6')

test.must_not_exist([
    test.workpath('test0'),
    test.workpath('test1/test2'),
    test.workpath('test3/test4'),
    test.workpath('test5'),
    test.workpath('test6/test7')
])

# only generate the ninja file
test.run(arguments='--disable-execute-ninja', stdout=None)
test.must_contain_all_lines(test.stdout(), ['Generating: build.ninja'])
test.must_not_exist([
    test.workpath('test0'),
    test.workpath('test1/test2'),
    test.workpath('test3/test4'),
    test.workpath('test5'),
    test.workpath('test6/test7')
])

# run ninja independently
program = test.workpath('run_ninja_env.bat') if IS_WINDOWS else ninja_bin
test.run(program=program, stdout=None)
test.must_not_contain_any_line(test.stdout(), ["scons: Building targets ..."])
test.must_exist([
    test.workpath('test0'),
    test.workpath('test1/test2'),
    test.workpath('test3/test4'),
    test.workpath('test5'),
    test.workpath('test6/test7')
])

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/ninja/multi_env.py

#!/usr/bin/env python
#
# Copyright The SCons Foundation
#
# 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.
#

import os

import TestSCons
from TestCmd import IS_WINDOWS

test = TestSCons.TestSCons()

try:
    import ninja
except ImportError:
    test.skip_test("Could not find module in python")

_python_ = TestSCons._python_
_exe = TestSCons._exe

ninja_bin = os.path.abspath(os.path.join(
    ninja.__file__,
    os.pardir,
    'data',
    'bin',
    'ninja' + _exe))

test = TestSCons.TestSCons()

test.dir_fixture('ninja-fixture')

test.write('SConstruct', """
SetOption('experimental','ninja')
DefaultEnvironment(tools=[])

env = Environment()
env.Tool('ninja')
env.Program(target = 'foo', source = 'foo.c')

env2 = Environment()
env2.Program(target = 'bar', source = 'bar.c')
""")

# generate simple build
test.run(stdout=None)
test.must_contain_all_lines(test.stdout(), ['Generating: build.ninja'])
test.must_contain_all(test.stdout(), 'Executing:')
test.must_contain_all(test.stdout(), 'ninja%(_exe)s -f' % locals())
test.run(program=test.workpath('foo' + _exe), stdout="foo.c")
test.run(program=test.workpath('bar' + _exe), stdout="bar.c")

# clean build and ninja files
test.run(arguments='-c', stdout=None)
test.must_contain_all_lines(test.stdout(), [
    'Removed foo.o',
    'Removed foo' + _exe,
    'Removed bar.o',
    'Removed bar' + _exe,
    'Removed build.ninja'])

# only generate the ninja file
test.run(arguments='--disable-execute-ninja', stdout=None)
test.must_contain_all_lines(test.stdout(), ['Generating: build.ninja'])
test.must_not_exist(test.workpath('foo' + _exe))
test.must_not_exist(test.workpath('bar' + _exe))

# run ninja independently
program = test.workpath('run_ninja_env.bat') if IS_WINDOWS else ninja_bin
test.run(program=program, stdout=None)
test.run(program=test.workpath('foo' + _exe), stdout="foo.c")
test.run(program=test.workpath('bar' + _exe), stdout="bar.c")

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/ninja/ninja_command_line.py

#!/usr/bin/env python
#
# Copyright The SCons Foundation
#
# 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.
#

import os

import TestSCons
from TestCmd import IS_WINDOWS

test = TestSCons.TestSCons()

try:
    import ninja
except ImportError:
    test.skip_test("Could not find module in python")

_python_ = TestSCons._python_
_exe = TestSCons._exe

ninja_bin = os.path.abspath(os.path.join(
    ninja.__file__,
    os.pardir,
    'data',
    'bin',
    'ninja' + _exe))

test.dir_fixture('ninja-fixture', 'src')

test.file_fixture('ninja_test_sconscripts/sconstruct_ninja_command_line', 'SConstruct')

# generate simple build
test.run(arguments=['BUILD=build', 'OTHER_VAR=$BUILD'], stdout=None)
test.must_contain_all_lines(test.stdout(), ['Generating: build.ninja'])
test.must_contain_all(test.stdout(), 'Executing:')
test.must_contain_all(test.stdout(), 'ninja%(_exe)s -f' % locals())
test.run(program=test.workpath('foo' + _exe), stdout="foo.c")

# clean build and ninja files
test.run(arguments=['-c', 'BUILD=build', 'OTHER_VAR=$BUILD'], stdout=None)
test.must_contain_all_lines(test.stdout(), [
    'Removed build%sbar2.c' % os.sep,
    'Removed build%sbar2.o' % os.sep,
    'Removed foo',
    'Removed build.ninja'])

# only generate the ninja file
test.run(arguments=['--disable-execute-ninja', 'BUILD=build', 'OTHER_VAR=$BUILD'], stdout=None)
test.must_contain_all_lines(test.stdout(), ['Generating: build.ninja'])
test.must_not_exist(test.workpath('foo' + _exe))

# run ninja independently
program = test.workpath('run_ninja_env.bat') if IS_WINDOWS else ninja_bin
test.run(program=program, stdout=None)
test.run(program=test.workpath('foo' + _exe), stdout="foo.c")

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/ninja/ninja_conftest.py

#!/usr/bin/env python
#
# Copyright The SCons Foundation
#
# 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.
#

import os

import TestSCons
from TestCmd import IS_WINDOWS

test = TestSCons.TestSCons()

try:
    import ninja
except ImportError:
    test.skip_test("Could not find module in python")

_python_ = TestSCons._python_
_exe = TestSCons._exe

ninja_bin = os.path.abspath(os.path.join(
    ninja.__file__,
    os.pardir,
    'data',
    'bin',
    'ninja' + _exe))

test.dir_fixture('ninja-fixture')

test.file_fixture('ninja_test_sconscripts/ninja_conftest', 'SConstruct')

# generate simple build
test.run(stdout=None)
test.must_contain_all_lines(test.stdout(), ['Generating: build.ninja'])
test.must_contain_all(test.stdout(), 'Executing:')
test.must_contain_all(test.stdout(), 'ninja%(_exe)s -f' % locals())
test.run(program=test.workpath('foo' + _exe), stdout="foo.c")

# clean build and ninja files
test.run(arguments='-c', stdout=None)
test.must_contain_all_lines(test.stdout(), [
    'Removed foo.o',
    'Removed foo',
    'Removed build.ninja'])

# only generate the ninja file
test.run(arguments='--disable-execute-ninja', stdout=None)
test.must_contain_all_lines(test.stdout(), ['Generating: build.ninja'])
test.must_not_exist(test.workpath('foo' + _exe))

# run ninja independently
program = test.workpath('run_ninja_env.bat') if IS_WINDOWS else ninja_bin
test.run(program=program, stdout=None)
test.run(program=test.workpath('foo' + _exe), stdout="foo.c")

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/ninja/ninja_file_deterministic.py

#!/usr/bin/env python
#
# Copyright The SCons Foundation
#
# 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.
#

import os
import shutil
import filecmp

import TestSCons
from TestCmd import IS_WINDOWS

test = TestSCons.TestSCons()

try:
    import ninja
except ImportError:
    test.skip_test("Could not find module in python")

_python_ = TestSCons._python_
_exe = TestSCons._exe

ninja_bin = os.path.abspath(os.path.join(
    ninja.BIN_DIR,
    'ninja' + _exe))

test.dir_fixture('ninja-fixture')

test.file_fixture('ninja_test_sconscripts/sconstruct_ninja_determinism', 'SConstruct')

# generate simple build
test.run(stdout=None)
test.must_contain_all_lines(test.stdout(), ['Generating: build.ninja'])
test.must_contain_all(test.stdout(), 'Executing:')
test.must_contain_all(test.stdout(), 'ninja%(_exe)s -f' % locals())
test.must_exist([test.workpath('out1.txt'), test.workpath('out2.txt')])
shutil.copyfile(test.workpath('build.ninja'), test.workpath('build.ninja.orig'))

ninja_file_mtime = os.path.getmtime(test.workpath('build.ninja'))

# generate same build again
test.run(stdout=None)
test.must_contain_all_lines(test.stdout(), ['Generating: build.ninja', 'ninja: no work to do.'])
test.must_contain_all(test.stdout(), 'Executing:')
test.must_contain_all(test.stdout(), 'ninja%(_exe)s -f' % locals())
test.must_exist([test.workpath('out1.txt'), test.workpath('out2.txt')])

if os.path.getmtime(test.workpath('build.ninja')) != ninja_file_mtime:
    test.fail_test(message="build.ninja file has been updated (mtime changed) and should not have been")

# make sure the ninja file was deterministic
if not filecmp.cmp(test.workpath('build.ninja'), test.workpath('build.ninja.orig')):
    test.fail_test()

# clean build and ninja files
os.unlink(test.workpath('build.ninja.orig'))
test.run(arguments='-c', stdout=None)

# only generate the ninja file
test.run(arguments='--disable-execute-ninja', stdout=None)
test.must_contain_all_lines(test.stdout(), ['Generating: build.ninja'])
test.must_not_exist([test.workpath('out1.txt'), test.workpath('out2.txt')])

# run ninja independently
program = test.workpath('run_ninja_env.bat') if IS_WINDOWS else ninja_bin
test.run(program=program, stdout=None)
test.must_exist([test.workpath('out1.txt'), test.workpath('out2.txt')])
shutil.copyfile(test.workpath('build.ninja'), test.workpath('build.ninja.orig'))

# only generate the ninja file again
test.run(arguments='--disable-execute-ninja', stdout=None)
test.must_contain_all_lines(test.stdout(), ['Generating: build.ninja'])
test.must_exist([test.workpath('out1.txt'), test.workpath('out2.txt')])

# run ninja independently again
program = test.workpath('run_ninja_env.bat') if IS_WINDOWS else ninja_bin
test.run(program=program, stdout=None)
test.must_contain_all_lines(test.stdout(), ['ninja: no work to do.'])
test.must_exist([test.workpath('out1.txt'), test.workpath('out2.txt')])

# make sure the ninja file was deterministic
if not filecmp.cmp(test.workpath('build.ninja'), test.workpath('build.ninja.orig')):
    test.fail_test()

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/ninja/ninja_handle_control_c_rebuild.py

#!/usr/bin/env python
#
# Copyright The SCons Foundation
#
# 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.
#
"""
This test ensures if ninja gets a control-c (or other interrupting signal) while
regenerating the build.ninja, it doesn't remove the build.ninja leaving it 
in an unworkable state.
"""
import os

import TestSCons
from TestCmd import IS_WINDOWS

test = TestSCons.TestSCons()

try:
    import ninja
except ImportError:
    test.skip_test("Could not find module in python")

_python_ = TestSCons._python_
_exe = TestSCons._exe

ninja_bin = os.path.abspath(
    os.path.join(ninja.__file__, os.pardir, "data", "bin", "ninja" + _exe)
)

test.dir_fixture("ninja-fixture")

test.file_fixture("ninja_test_sconscripts/sconstruct_generate_and_build", "SConstruct")

# generate simple build
test.run(stdout=None)
test.must_contain_all_lines(test.stdout(), ["Generating: build.ninja"])
test.must_contain_all(test.stdout(), "Executing:")
test.must_contain_all(test.stdout(), "ninja%(_exe)s -f" % locals())
test.run(program=test.workpath("foo" + _exe), stdout="foo.c")

# Change the SConstruct
test.file_fixture("ninja_test_sconscripts/sconstruct_control_c_ninja", "SConstruct")

# run ninja independently
program = test.workpath("run_ninja_env.bat") if IS_WINDOWS else ninja_bin
if IS_WINDOWS:
    test.fail_test(
        condition=(test.status in [1, 2]),
        message="Expected exit status to be 1 or 2 was actually:%d" % test.status,
    )
else:
    test.fail_test(
        condition=(test.status == 1),
        message="Expected exit status to be 1 was actually:%d" % test.status,
    )

test.run(program=program, stdout=None, stderr=None, status=None)

if not IS_WINDOWS:
    error_msg = "ninja: error: rebuilding 'build.ninja': interrupted by user"
    test.must_contain_all(test.stderr(), error_msg)

# Verify that Rebuilding build.ninja and sending control-c to ninja doesn't remove build.ninja
test.must_exist("build.ninja")
test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/ninja/no_for_sig_subst.py

#!/usr/bin/env python
#
# Copyright The SCons Foundation
#
# 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.
#

import os

import TestSCons
from TestCmd import IS_WINDOWS

test = TestSCons.TestSCons()

try:
    import ninja
except ImportError:
    test.skip_test("Could not find module in python")

_python_ = TestSCons._python_
_exe = TestSCons._exe

ninja_bin = os.path.abspath(os.path.join(
    ninja.__file__,
    os.pardir,
    'data',
    'bin',
    'ninja' + _exe))

test.dir_fixture('ninja-fixture')

test.file_fixture('ninja_test_sconscripts/sconstruct_no_for_sig_subst', 'SConstruct')

# generate simple build
test.run(stdout=None)
test.must_contain_all_lines(test.stdout(), ['Generating: build.ninja'])
test.must_contain_all(test.stdout(), 'Executing:')
test.must_contain_all(test.stdout(), 'ninja%(_exe)s -f' % locals())
test.must_exist([test.workpath('out.txt')])

# clean build and ninja files
test.run(arguments='-c', stdout=None)
test.must_contain_all_lines(test.stdout(), [
    'Removed out.txt',
    'Removed build.ninja'])

# only generate the ninja file
test.run(arguments='--disable-execute-ninja', stdout=None)
test.must_contain_all_lines(test.stdout(), ['Generating: build.ninja'])
test.must_not_exist(test.workpath('out.txt'))

# run ninja independently
program = test.workpath('run_ninja_env.bat') if IS_WINDOWS else ninja_bin
test.run(program=program, stdout=None)
test.must_exist([test.workpath('out.txt')])

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/ninja/response_file.py

#!/usr/bin/env python
#
# Copyright The SCons Foundation
#
# 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.
#

import os
import sys
import json
from io import StringIO


import TestSCons
from TestCmd import IS_WINDOWS

test = TestSCons.TestSCons()

try:
    import ninja
except ImportError:
    test.skip_test("Could not find module in python")

_python_ = TestSCons._python_
_exe = TestSCons._exe
_obj = TestSCons._obj

ninja_bin = os.path.abspath(os.path.join(
    ninja.__file__,
    os.pardir,
    'data',
    'bin',
    'ninja' + _exe))

test.dir_fixture('ninja-fixture')

test.file_fixture('ninja_test_sconscripts/sconstruct_response_file', 'SConstruct')

# only generate the ninja file
test.run(arguments='--disable-execute-ninja', stdout=None)
test.must_contain_all_lines(test.stdout(), ['Generating: build.ninja'])
test.must_not_exist(test.workpath('foo' + _exe))

# run ninja independently
program = test.workpath('run_ninja_env.bat') if IS_WINDOWS else ninja_bin

# now we must extract the line length for a given command by print the command
# to a StringIO internal buffer and calculating the length of the resulting command.
test.run(program=[program, 'compiledb'], stdout=None)
command_length = None
with open('compile_commands.json') as f:
    comp_commands = json.loads(f.read())
    for cmd in comp_commands:
        if cmd['output'].endswith('1'):
            result = StringIO()
            old_stdout = sys.stdout
            sys.stdout = result
            print(cmd['command'])
            result_string = result.getvalue()
            sys.stdout = old_stdout
            if sys.platform == 'win32':
                command_length = len(result_string)
            else:
                command_length = len(result_string.split(';')[-1])

# now regen the ninja file with the MAXLINELENGTH so we can force the response file in one case.
test.run(arguments=['--disable-execute-ninja', 'MLL='+str(command_length)], stdout=None)
test.run(program=[program, '-v', '-d', 'keeprsp'], stdout=None)
test.must_not_exist(test.workpath('foo' + _obj + '1.rsp'))
test.must_exist(test.workpath('foo' + _obj + '2.rsp'))

test.run(program=test.workpath('foo' + _exe), stdout="foo.c")

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/ninja/shell_command.py

#!/usr/bin/env python
#
# Copyright The SCons Foundation
#
# 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.
#

import os

import TestSCons
from TestCmd import IS_WINDOWS

test = TestSCons.TestSCons()

try:
    import ninja
except ImportError:
    test.skip_test("Could not find module in python")

_python_ = TestSCons._python_
_exe = TestSCons._exe

ninja_bin = os.path.abspath(os.path.join(
    ninja.__file__,
    os.pardir,
    'data',
    'bin',
    'ninja' + _exe))

test.dir_fixture('ninja-fixture')

shell = '' if IS_WINDOWS else './'

test.write('SConstruct', """
SetOption('experimental','ninja')
DefaultEnvironment(tools=[])

env = Environment()
env.Tool('ninja')
prog = env.Program(target = 'foo', source = 'foo.c')
env.Command('foo.out', prog, '%(shell)sfoo%(_exe)s > foo.out')
""" % locals())

# generate simple build
test.run(stdout=None)
test.must_contain_all_lines(test.stdout(), ['Generating: build.ninja'])
test.must_contain_all(test.stdout(), 'Executing:')
test.must_contain_all(test.stdout(), 'ninja%(_exe)s -f' % locals())
test.must_match('foo.out', 'foo.c')

# clean build and ninja files
test.run(arguments='-c', stdout=None)
test.must_contain_all_lines(test.stdout(), [
    'Removed foo.o',
    'Removed foo%(_exe)s' % locals(),
    'Removed foo.out',
    'Removed build.ninja'])

# only generate the ninja file
test.run(arguments='--disable-execute-ninja', stdout=None)
test.must_contain_all_lines(test.stdout(), ['Generating: build.ninja'])
test.must_not_exist(test.workpath('foo.out'))

# run ninja independently
program = test.workpath('run_ninja_env.bat') if IS_WINDOWS else ninja_bin
test.run(program=program, stdout=None)
test.must_match('foo.out', 'foo.c')

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/ninja/shutdown_scons_daemon.py

#!/usr/bin/env python
#
# Copyright The SCons Foundation
#
# 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.
#

import os
from timeit import default_timer as timer

import TestSCons
from TestCmd import IS_WINDOWS

test = TestSCons.TestSCons()

try:
    import ninja
except ImportError:
    test.skip_test("Could not find ninja module in python")

try:
    import psutil
except ImportError:
    test.skip_test("Could not find psutil module in python")


_python_ = TestSCons._python_
_exe = TestSCons._exe

ninja_bin = os.path.abspath(
    os.path.join(ninja.__file__, os.pardir, "data", "bin", "ninja" + _exe)
)

test.dir_fixture("ninja-fixture")

test.file_fixture(
    "ninja_test_sconscripts/sconstruct_force_scons_callback", "SConstruct"
)

test.run(stdout=None)
pid = None
test.must_exist(test.workpath('.ninja/scons_daemon_dirty'))
with open(test.workpath('.ninja/scons_daemon_dirty')) as f:
    pid = int(f.read())
    if pid not in [proc.pid for proc in psutil.process_iter()]:
        test.fail_test(message="daemon not running!")

program = test.workpath("run_ninja_env.bat") if IS_WINDOWS else ninja_bin
test.run(program=program, arguments='shutdown-ninja-scons-daemon', stdout=None)

wait_time = 10
start_time = timer()
while True:
    if wait_time > (timer() - start_time):
        if pid not in [proc.pid for proc in psutil.process_iter()]:
            break
    else:
        test.fail_test(message=f"daemon still not shutdown after {wait_time} seconds.")

test.must_not_exist(test.workpath('.ninja/scons_daemon_dirty'))
test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/option/d.py

#!/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 -d option is ignored.
"""

import TestSCons

test = TestSCons.TestSCons()

test.write('SConstruct', "DefaultEnvironment(tools=[])\n")

test.run(arguments = '-d .',
         stderr = "Warning:  ignoring -d option\n")

test.pass_test()

#

test.subdir('subdir')

test.write('SConstruct', """
DefaultEnvironment(tools=[])
env = Environment()
env.Program(target = 'aaa', source = 'aaa.c')
env.Program(target = 'bbb', source = 'bbb.c')
SConscript('subdir/SConscript')
""")

test.write(['subdir', 'SConscript'], """
env = Environment()
env.Program(target = 'ccc', source = 'ccc.c')
env.Program(target = 'ddd', source = 'ddd.c')
""")

test.write('aaa.c', """
int
main(int argc, char *argv)
{
        argv[argc++] = "--";
        printf("aaa.c\n");
        exit (0);
}
""")

test.write('bbb.c', """
int
main(int argc, char *argv)
{
        argv[argc++] = "--";
        printf("bbb.c\n");
        exit (0);
}
""")

test.write(['subdir', 'ccc.c'], """
int
main(int argc, char *argv)
{
        argv[argc++] = "--";
        printf("subdir/ccc.c\n");
        exit (0);
}
""")

test.write(['subdir', 'ddd.c'], """
int
main(int argc, char *argv)
{
        argv[argc++] = "--";
        printf("subdir/ddd.c\n");
        exit (0);
}
""")

test.run(arguments = '-d .', stdout = """
Target aaa: aaa.o
Checking aaa
  Checking aaa.o
    Checking aaa.c
  Rebuilding aaa.o: out of date.
cc -c -o aaa.o aaa.c
Rebuilding aaa: out of date.
cc -o aaa aaa.o
Target aaa.o: aaa.c
Target bbb: bbb.o
Checking bbb
  Checking bbb.o
    Checking bbb.c
  Rebuilding bbb.o: out of date.
cc -c -o bbb.o bbb.c
Rebuilding bbb: out of date.
cc -o bbb bbb.o
Target bbb.o: bbb.c
Target subdir/ccc/g: subdir/ccc.o
Checking subdir/ccc/g
  Checking subdir/ccc/g.o
    Checking subdir/ccc/g.c
  Rebuilding subdir/ccc/g.o: out of date.
cc -c -o subdir/ccc/g.o subdir/ccc.c
Rebuilding subdir/ccc/g: out of date.
cc -o subdir/ccc/g subdir/ccc.o
Target subdir/ccc/g.o: subdir/ccc.c
Target subdir/ddd/g: subdir/ddd.o
Checking subdir/ddd/g
  Checking subdir/ddd/g.o
    Checking subdir/ddd/g.c
  Rebuilding subdir/ddd/g.o: out of date.
cc -c -o subdir/ddd/g.o subdir/ddd.c
Rebuilding subdir/ddd/g: out of date.
cc -o subdir/ddd/g subdir/ddd.o
Target subdir/ddd/g.o: subdir/ddd.c
""")

test.run(program = test.workpath('aaa'), stdout = "aaa.c\n")
test.run(program = test.workpath('bbb'), stdout = "bbb.c\n")
test.run(program = test.workpath('subdir/ccc'), stdout = "subdir/ccc.c\n")
test.run(program = test.workpath('subdir/ddd'), stdout = "subdir/ddd.c\n")

test.pass_test()
 

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/option/debug-action-timestamps.py

#!/usr/bin/env python
#
# __COPYRIGHT__
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"

import TestSCons
import re

_python_ = TestSCons._python_

def setup_fixtures():
    test.file_fixture('../fixture/test_main.c', 'main.c')
    test.file_fixture('../fixture/SConstruct_test_main.py', 'SConstruct')

def test_help_function():
    # Before anything else, make sure we get valid --debug=action-timestamps results
    # when just running the help option.
    test.run(arguments = "-h --debug=action-timestamps")
    
def build():
    # Execute build
    test.run(arguments='--debug=action-timestamps')
    build_output = test.stdout()
    return build_output

def get_matches_from_output(build_output):
    return [re.findall(pattern, build_output) for pattern in debug_time_patterns]

def test_presence_of_debug_time_strings(build_output):
    # Check presence of duration and timestamps
    if None in get_matches_from_output(build_output):
        print("One or more of the time debug strings were not found in the build output")
        test.fail_test(1)

def test_equal_number_of_debug_time_strings(build_output):
    matches = get_matches_from_output(build_output)
    num_of_matches = [len(match) for match in matches]

    # Check that the number of matches for each pattern is the same
    if num_of_matches.count(num_of_matches[0]) != len(num_of_matches):
        print("Debug time strings differs in quantity")
        test.fail_test(2)

def test_correctness_of_timestamps(build_output):
    # Check if difference between timestamps is equal to duration
    matches = get_matches_from_output(build_output)

    def match_to_float(m): 
        return float(m[1][1])

    execution_time = match_to_float(matches[0])
    start_time = match_to_float(matches[1])
    stop_time = match_to_float(matches[2])
    delta_time = stop_time - start_time

    def within_tolerance(expected, actual, tolerance):
        return abs((expected-actual)/actual) <= tolerance

    if not within_tolerance(execution_time, delta_time, 0.001):
        print("Difference of timestamps differ from action duration")
        print("Execution time = {}. Start time = {}. Stop time = {}. Delta time = {}".format(execution_time, start_time, stop_time, delta_time))
        test.fail_test(3)

debug_time_patterns = [
    r'Command execution time: (.*): (\d+\.\d+) seconds',
    r'Command execution start timestamp: (.*): (\d+\.\d+)',
    r'Command execution end timestamp: (.*): (\d+\.\d+)'
]

test = TestSCons.TestSCons()
setup_fixtures()

test_help_function()

build_output = build()
test_presence_of_debug_time_strings(build_output)
test_equal_number_of_debug_time_strings(build_output)
test_correctness_of_timestamps(build_output)

test.pass_test()


# test/option/debug-count.py

#!/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.

"""
Test that the --debug=count option works.
"""

__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"

import re
import sys

import TestSCons

test = TestSCons.TestSCons()


test.write('SConstruct', """
DefaultEnvironment(tools=[])
def cat(target, source, env):
    with open(str(target[0]), 'wb') as f, open(str(source[0]), 'rb') as infp:
        f.write(infp.read())
env = Environment(BUILDERS={'Cat':Builder(action=Action(cat))})
env.Cat('file.out', 'file.in')
""")

test.write('file.in', "file.in\n")

# Just check that object counts for some representative classes
# show up in the output.

def find_object_count(s, stdout):
    re_string = r'\d+ +\d+   %s' % re.escape(s)
    return re.search(re_string, stdout)

objects = [
    'Action.CommandAction',
    'Builder.BuilderBase',
    'Environment.Base',
    'Executor.Executor',
    'Node.FS',
    'Node.FS.Base',
    'Node.Node',
]

for args in ['-h --debug=count', '--debug=count']:
    test.run(arguments = args)
    stdout = test.stdout()

    missing = [o for o in objects if find_object_count(o, stdout) is None]

    if missing:
        print("Missing the following object lines from '%s' output:" % args)
        print("\t", ' '.join(missing))
        print("STDOUT ==========")
        print(stdout)
        test.fail_test(1)

expect_warning = """
scons: warning: --debug=count is not supported when running SCons
\twith the python -O option or optimized \\(.pyo\\) modules.
""" + TestSCons.file_expr

test.run(
    arguments = '--debug=count -h',
    # Test against current interpreter vs default path option.
    interpreter = [ sys.executable, '-O' ],
    stderr = expect_warning,
    match = TestSCons.match_re
)

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/option/debug-duplicate.py

#!/usr/bin/env python
#
# __COPYRIGHT__
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#

__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"

import TestSCons

_python_ = TestSCons._python_

test = TestSCons.TestSCons()

test.subdir('sub1')

test.write('SConstruct', """\
DefaultEnvironment(tools=[])
env=Environment(tools=[])
Export('env')
env.SConscript('SConscript', variant_dir='Build')
""")

test.write('SConscript', """\
Import('env')
env.Command('foo.out', 'SConscript', Copy('$TARGET', '$SOURCE'))
""")

test.run(arguments = "--debug=duplicate -Q",
         stdout='.*relinking variant.*', match=TestSCons.match_re_dotall)

test.must_exist('Build/foo.out')

test.write('SConscript', """\
# different this time!
Import('env')
env.Command('foo.out', 'SConscript', Copy('$TARGET', '$SOURCE'))
""")

test.run(arguments = "--debug=duplicate -Q",
         stdout='.*relinking variant.*removing existing target.*',
         match=TestSCons.match_re_dotall)

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/option/debug-findlibs.py

#!/usr/bin/env python
#
# __COPYRIGHT__
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#

__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"

import TestSCons

_python_ = TestSCons._python_

test = TestSCons.TestSCons()

test.subdir('sub1', 'sub2')

test.write('cat.py', """\
import sys
with open(sys.argv[1], 'wb') as ofp:
    for f in sys.argv[2:]:
        with open(f, 'rb') as ifp:
            ofp.write(ifp.read())
""")

test.write('SConstruct', """\
DefaultEnvironment(tools=[])
env = Environment(OBJSUFFIX = '.ooo', PROGSUFFIX = '.xxx',
                  LIBPATH = ['sub1', 'sub2', '.'],
                  LIBS = ['iii', 'jjj', 'kkk', 'lll', 'mmm'],
                  LIBPREFIXES = ['a-', 'b-', 'c-'],
                  LIBSUFFIXES = ['.aaa', '.bbb', '.ccc'],
                  LINKCOM = r'%(_python_)s cat.py $TARGET $SOURCES')
env.Program('foo', 'a.ooo',)
""" % locals())

test.write('a.ooo', "a.ooo\n")

test.write('a-iii.aaa', "a-iii.aaa\n")
test.write(['sub1', 'b-jjj.bbb'], "b-jjj.bbb\n")
test.write(['sub2', 'c-kkk.ccc'], "c-kkk.ccc\n")
test.write('a-lll.ccc', "a-lll.ccc\n")

test.run(arguments = "--debug=findlibs foo.xxx",
         stdout = test.wrap_stdout("""\
  findlibs: looking for 'a-iii.aaa' in 'sub1' ...
  findlibs: looking for 'a-iii.aaa' in 'sub2' ...
  findlibs: looking for 'a-iii.aaa' in '.' ...
  findlibs: ... FOUND 'a-iii.aaa' in '.'
  findlibs: looking for 'b-iii.aaa' in 'sub1' ...
  findlibs: looking for 'b-iii.aaa' in 'sub2' ...
  findlibs: looking for 'b-iii.aaa' in '.' ...
  findlibs: looking for 'c-iii.aaa' in 'sub1' ...
  findlibs: looking for 'c-iii.aaa' in 'sub2' ...
  findlibs: looking for 'c-iii.aaa' in '.' ...
  findlibs: looking for 'a-iii.bbb' in 'sub1' ...
  findlibs: looking for 'a-iii.bbb' in 'sub2' ...
  findlibs: looking for 'a-iii.bbb' in '.' ...
  findlibs: looking for 'b-iii.bbb' in 'sub1' ...
  findlibs: looking for 'b-iii.bbb' in 'sub2' ...
  findlibs: looking for 'b-iii.bbb' in '.' ...
  findlibs: looking for 'c-iii.bbb' in 'sub1' ...
  findlibs: looking for 'c-iii.bbb' in 'sub2' ...
  findlibs: looking for 'c-iii.bbb' in '.' ...
  findlibs: looking for 'a-iii.ccc' in 'sub1' ...
  findlibs: looking for 'a-iii.ccc' in 'sub2' ...
  findlibs: looking for 'a-iii.ccc' in '.' ...
  findlibs: looking for 'b-iii.ccc' in 'sub1' ...
  findlibs: looking for 'b-iii.ccc' in 'sub2' ...
  findlibs: looking for 'b-iii.ccc' in '.' ...
  findlibs: looking for 'c-iii.ccc' in 'sub1' ...
  findlibs: looking for 'c-iii.ccc' in 'sub2' ...
  findlibs: looking for 'c-iii.ccc' in '.' ...
  findlibs: looking for 'a-jjj.aaa' in 'sub1' ...
  findlibs: looking for 'a-jjj.aaa' in 'sub2' ...
  findlibs: looking for 'a-jjj.aaa' in '.' ...
  findlibs: looking for 'b-jjj.aaa' in 'sub1' ...
  findlibs: looking for 'b-jjj.aaa' in 'sub2' ...
  findlibs: looking for 'b-jjj.aaa' in '.' ...
  findlibs: looking for 'c-jjj.aaa' in 'sub1' ...
  findlibs: looking for 'c-jjj.aaa' in 'sub2' ...
  findlibs: looking for 'c-jjj.aaa' in '.' ...
  findlibs: looking for 'a-jjj.bbb' in 'sub1' ...
  findlibs: looking for 'a-jjj.bbb' in 'sub2' ...
  findlibs: looking for 'a-jjj.bbb' in '.' ...
  findlibs: looking for 'b-jjj.bbb' in 'sub1' ...
  findlibs: ... FOUND 'b-jjj.bbb' in 'sub1'
  findlibs: looking for 'c-jjj.bbb' in 'sub1' ...
  findlibs: looking for 'c-jjj.bbb' in 'sub2' ...
  findlibs: looking for 'c-jjj.bbb' in '.' ...
  findlibs: looking for 'a-jjj.ccc' in 'sub1' ...
  findlibs: looking for 'a-jjj.ccc' in 'sub2' ...
  findlibs: looking for 'a-jjj.ccc' in '.' ...
  findlibs: looking for 'b-jjj.ccc' in 'sub1' ...
  findlibs: looking for 'b-jjj.ccc' in 'sub2' ...
  findlibs: looking for 'b-jjj.ccc' in '.' ...
  findlibs: looking for 'c-jjj.ccc' in 'sub1' ...
  findlibs: looking for 'c-jjj.ccc' in 'sub2' ...
  findlibs: looking for 'c-jjj.ccc' in '.' ...
  findlibs: looking for 'a-kkk.aaa' in 'sub1' ...
  findlibs: looking for 'a-kkk.aaa' in 'sub2' ...
  findlibs: looking for 'a-kkk.aaa' in '.' ...
  findlibs: looking for 'b-kkk.aaa' in 'sub1' ...
  findlibs: looking for 'b-kkk.aaa' in 'sub2' ...
  findlibs: looking for 'b-kkk.aaa' in '.' ...
  findlibs: looking for 'c-kkk.aaa' in 'sub1' ...
  findlibs: looking for 'c-kkk.aaa' in 'sub2' ...
  findlibs: looking for 'c-kkk.aaa' in '.' ...
  findlibs: looking for 'a-kkk.bbb' in 'sub1' ...
  findlibs: looking for 'a-kkk.bbb' in 'sub2' ...
  findlibs: looking for 'a-kkk.bbb' in '.' ...
  findlibs: looking for 'b-kkk.bbb' in 'sub1' ...
  findlibs: looking for 'b-kkk.bbb' in 'sub2' ...
  findlibs: looking for 'b-kkk.bbb' in '.' ...
  findlibs: looking for 'c-kkk.bbb' in 'sub1' ...
  findlibs: looking for 'c-kkk.bbb' in 'sub2' ...
  findlibs: looking for 'c-kkk.bbb' in '.' ...
  findlibs: looking for 'a-kkk.ccc' in 'sub1' ...
  findlibs: looking for 'a-kkk.ccc' in 'sub2' ...
  findlibs: looking for 'a-kkk.ccc' in '.' ...
  findlibs: looking for 'b-kkk.ccc' in 'sub1' ...
  findlibs: looking for 'b-kkk.ccc' in 'sub2' ...
  findlibs: looking for 'b-kkk.ccc' in '.' ...
  findlibs: looking for 'c-kkk.ccc' in 'sub1' ...
  findlibs: looking for 'c-kkk.ccc' in 'sub2' ...
  findlibs: ... FOUND 'c-kkk.ccc' in 'sub2'
  findlibs: looking for 'a-lll.aaa' in 'sub1' ...
  findlibs: looking for 'a-lll.aaa' in 'sub2' ...
  findlibs: looking for 'a-lll.aaa' in '.' ...
  findlibs: looking for 'b-lll.aaa' in 'sub1' ...
  findlibs: looking for 'b-lll.aaa' in 'sub2' ...
  findlibs: looking for 'b-lll.aaa' in '.' ...
  findlibs: looking for 'c-lll.aaa' in 'sub1' ...
  findlibs: looking for 'c-lll.aaa' in 'sub2' ...
  findlibs: looking for 'c-lll.aaa' in '.' ...
  findlibs: looking for 'a-lll.bbb' in 'sub1' ...
  findlibs: looking for 'a-lll.bbb' in 'sub2' ...
  findlibs: looking for 'a-lll.bbb' in '.' ...
  findlibs: looking for 'b-lll.bbb' in 'sub1' ...
  findlibs: looking for 'b-lll.bbb' in 'sub2' ...
  findlibs: looking for 'b-lll.bbb' in '.' ...
  findlibs: looking for 'c-lll.bbb' in 'sub1' ...
  findlibs: looking for 'c-lll.bbb' in 'sub2' ...
  findlibs: looking for 'c-lll.bbb' in '.' ...
  findlibs: looking for 'a-lll.ccc' in 'sub1' ...
  findlibs: looking for 'a-lll.ccc' in 'sub2' ...
  findlibs: looking for 'a-lll.ccc' in '.' ...
  findlibs: ... FOUND 'a-lll.ccc' in '.'
  findlibs: looking for 'b-lll.ccc' in 'sub1' ...
  findlibs: looking for 'b-lll.ccc' in 'sub2' ...
  findlibs: looking for 'b-lll.ccc' in '.' ...
  findlibs: looking for 'c-lll.ccc' in 'sub1' ...
  findlibs: looking for 'c-lll.ccc' in 'sub2' ...
  findlibs: looking for 'c-lll.ccc' in '.' ...
  findlibs: looking for 'a-mmm.aaa' in 'sub1' ...
  findlibs: looking for 'a-mmm.aaa' in 'sub2' ...
  findlibs: looking for 'a-mmm.aaa' in '.' ...
  findlibs: looking for 'b-mmm.aaa' in 'sub1' ...
  findlibs: looking for 'b-mmm.aaa' in 'sub2' ...
  findlibs: looking for 'b-mmm.aaa' in '.' ...
  findlibs: looking for 'c-mmm.aaa' in 'sub1' ...
  findlibs: looking for 'c-mmm.aaa' in 'sub2' ...
  findlibs: looking for 'c-mmm.aaa' in '.' ...
  findlibs: looking for 'a-mmm.bbb' in 'sub1' ...
  findlibs: looking for 'a-mmm.bbb' in 'sub2' ...
  findlibs: looking for 'a-mmm.bbb' in '.' ...
  findlibs: looking for 'b-mmm.bbb' in 'sub1' ...
  findlibs: looking for 'b-mmm.bbb' in 'sub2' ...
  findlibs: looking for 'b-mmm.bbb' in '.' ...
  findlibs: looking for 'c-mmm.bbb' in 'sub1' ...
  findlibs: looking for 'c-mmm.bbb' in 'sub2' ...
  findlibs: looking for 'c-mmm.bbb' in '.' ...
  findlibs: looking for 'a-mmm.ccc' in 'sub1' ...
  findlibs: looking for 'a-mmm.ccc' in 'sub2' ...
  findlibs: looking for 'a-mmm.ccc' in '.' ...
  findlibs: looking for 'b-mmm.ccc' in 'sub1' ...
  findlibs: looking for 'b-mmm.ccc' in 'sub2' ...
  findlibs: looking for 'b-mmm.ccc' in '.' ...
  findlibs: looking for 'c-mmm.ccc' in 'sub1' ...
  findlibs: looking for 'c-mmm.ccc' in 'sub2' ...
  findlibs: looking for 'c-mmm.ccc' in '.' ...
%(_python_)s cat.py foo.xxx a.ooo
""" % locals()))

test.must_match('foo.xxx', "a.ooo\n")

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/option/debug-includes.py

#!/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 the --debug=includes option prints the implicit
dependencies of a target.
"""

import TestSCons

test = TestSCons.TestSCons()

test.write('SConstruct', """
DefaultEnvironment(tools=[])
env = Environment(OBJSUFFIX = '.obj',
                  SHOBJSUFFIX = '.shobj',
                  LIBPREFIX = '',
                  LIBSUFFIX = '.lib',
                  SHLIBPREFIX = '',
                  SHLIBSUFFIX = '.shlib',
                  )
env.Program('foo.exe', ['foo.c', 'bar.c'])
env.StaticLibrary('foo', ['foo.c', 'bar.c'])
env.SharedLibrary('foo', ['foo.c', 'bar.c'], no_import_lib=True)
""")

test.write('foo.c', r"""
#include <stdio.h>
#include <stdlib.h>
#include "foo.h"
int main(int argc, char *argv[])
{
        argv[argc++] = "--";
        printf("f1.c\n");
        exit (0);
}
""")

test.write('bar.c', """
#include "bar.h"
int local = 1;
""")

test.write('foo.h', """
#ifndef FOO_H
#define FOO_H
#include "bar.h"
#endif
""")

test.write('bar.h', """
#ifndef BAR_H
#define BAR_H
#include "foo.h"
#endif
""")

includes = """
+-foo.c
  +-foo.h
    +-bar.h
"""
test.run(arguments = "--debug=includes foo.obj")

test.must_contain_all_lines(test.stdout(), [includes])



# In an ideal world, --debug=includes would also work when there's a build
# failure, but this would require even more complicated logic to scan
# all of the intermediate nodes that get skipped when the build failure
# occurs.  On the YAGNI theory, we're just not going to worry about this
# until it becomes an issue that someone actually cares enough about.

#test.write('bar.h', """
##ifndef BAR_H
##define BAR_H
##include "foo.h"
##endif
#THIS SHOULD CAUSE A BUILD FAILURE
#""")

#test.run(arguments = "--debug=includes foo.exe",
#         status = 2,
#         stderr = None)
#test.must_contain_all_lines(test.stdout(), [includes])



# These shouldn't print out anything in particular, but
# they shouldn't crash either:
test.run(arguments = "--debug=includes .")
test.run(arguments = "--debug=includes foo.c")
test.run(arguments = "--debug=includes foo.lib")
test.run(arguments = "--debug=includes foo.shlib")



test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/option/debug-memoizer.py

#!/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 calling the --debug=memoizer option.
"""

import os

import TestSCons

test = TestSCons.TestSCons(match = TestSCons.match_re_dotall)


test.write('SConstruct', """
DefaultEnvironment(tools=[])
def cat(target, source, env):
    with open(str(target[0]), 'wb') as f, open(str(source[0]), 'rb') as infp:
        f.write(infp.read())
env = Environment(tools=[], BUILDERS={'Cat':Builder(action=Action(cat))})
env.Cat('file.out', 'file.in')
""")

test.write('file.in', "file.in\n")

# The banner, and a list of representative method names that we expect
# to show up in the output.  Of course, this depends on keeping those
# names in the implementation, so if we change them, we'll have to
# change this test...
expect = [
    "Memoizer (memory cache) hits and misses",
    "Base.stat()",
    "Dir.srcdir_list()",
    "File.exists()",
    "Node._children_get()",
]


for args in ['-h --debug=memoizer', '--debug=memoizer']:
    test.run(arguments = args)
    test.must_contain_any_line(test.stdout(), expect)

test.must_match('file.out', "file.in\n")



test.unlink("file.out")



os.environ['SCONSFLAGS'] = '--debug=memoizer'

test.run(arguments = '')

test.must_contain_any_line(test.stdout(), expect)

test.must_match('file.out', "file.in\n")



test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/option/debug-memory.py

#!/usr/bin/env python
# MIT License
#
# Copyright The SCons Foundation
#
# 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.
#

"""
Test that the --debug=memory option works.
"""

import re

import TestSCons
from TestCmd import IS_WINDOWS

test = TestSCons.TestSCons()

if not IS_WINDOWS:
    try:
        import resource  # noqa: F401
    except ImportError:
        x = "Python version has no 'resource' skipping tests.\n"
        test.skip_test(x)


test.write('SConstruct', """
DefaultEnvironment(tools=[])
def cat(target, source, env):
    with open(str(target[0]), 'wb') as f, open(str(source[0]), 'rb') as ifp:
        f.write(ifp.read())
env = Environment(tools=[], BUILDERS={'Cat':Builder(action=Action(cat))})
env.Cat('file.out', 'file.in')
""")

test.write('file.in', "file.in\n")



test.run(arguments = '--debug=memory')

lines = test.stdout().split('\n')

test.fail_test(re.match(r'Memory before reading SConscript files: +\d+', lines[-5]) is None)
test.fail_test(re.match(r'Memory after reading SConscript files: +\d+', lines[-4]) is None)
test.fail_test(re.match(r'Memory before building targets: +\d+', lines[-3]) is None)
test.fail_test(re.match(r'Memory after building targets: +\d+', lines[-2]) is None)



test.run(arguments = '-h --debug=memory')

lines = test.stdout().split('\n')

test.fail_test(re.match(r'Memory before reading SConscript files: +\d+', lines[-3]) is None)
test.fail_test(re.match(r'Memory after reading SConscript files: +\d+', lines[-2]) is None)



test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/option/debug-multiple.py

#!/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.

"""
Test that --debug can take multiple options
"""

__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"

import re

import TestSCons

test = TestSCons.TestSCons()

test.write('SConstruct', """
DefaultEnvironment(tools=[])
def cat(target, source, env):
    with open(str(target[0]), 'wb') as f, open(str(source[0]), 'rb') as infp:
        f.write(infp.read())
env = Environment(BUILDERS={'Cat':Builder(action=Action(cat))})
env.Cat('file.out', 'file.in')
""")

test.write('file.in', "file.in\n")

# Just check that object counts for some representative classes
# show up in the output.

def find_object_count(s, stdout):
    re_string = r'\d+ +\d+   %s' % re.escape(s)
    return re.search(re_string, stdout)

objects = [
    'Action.CommandAction',
    'Builder.BuilderBase',
    'Environment.Base',
    'Executor.Executor',
    'Node.FS',
    'Node.FS.Base',
    'Node.Node',
]

for args in ['--debug=prepare,count', '--debug=count,prepare']:
    test.run(arguments = args)
    stdout = test.stdout()
    missing = [o for o in objects if find_object_count(o, stdout) is None]

    if missing:
        print("Missing the following object lines from '%s' output:" % args)
        print("\t", ' '.join(missing))
        print("STDOUT ==========")
        print(stdout)
        test.fail_test(1)

    if 'Preparing target file.out...' not in stdout:
        print("Missing 'Preparing' lines from '%s' output:" % args)
        print("STDOUT ==========")
        print(stdout)
        test.fail_test(1)

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/option/debug-objects.py

#!/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 the --debug=objects option works.
"""

import TestSCons

test = TestSCons.TestSCons()


test.write('SConstruct', """
DefaultEnvironment(tools=[])
def cat(target, source, env):
    with open(str(target[0]), 'wb') as f, open(str(source[0]), 'rb') as infp:
        f.write(infp.read())
env = Environment(tools=[], BUILDERS={'Cat':Builder(action=Action(cat))})
env.Cat('file.out', 'file.in')
""")

test.write('file.in', "file.in\n")

# Just check that it runs, we're not overly concerned about the actual
# output at this point.
test.run(arguments = "--debug=objects")



test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/option/debug-pdb.py

#!/usr/bin/env python
#
# __COPYRIGHT__
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#

__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"

import TestSCons

test = TestSCons.TestSCons()

test.write('SConstruct', """\
DefaultEnvironment(tools=[])
env = Environment(tools=[])
""")

test.run(arguments = "--debug=pdb", stdin = "n\ns\nq\n")
test.must_contain_all_lines(test.stdout(), ["(Pdb)", "SCons"])

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/option/debug-prepare.py

#!/usr/bin/env python
#
# __COPYRIGHT__
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#

__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"

import TestSCons

_python_ = TestSCons._python_

test = TestSCons.TestSCons()

test.write('SConstruct', """\
DefaultEnvironment(tools=[])
env=Environment(tools=[])
dest=env.Command('foo.out', 'SConstruct',
   [Copy('$TARGET', '$SOURCE'),
    Copy('${TARGET}.extra', '$SOURCE')])
env.SideEffect('foo.out.extra', dest)
""")

expect = """\
Preparing target foo.out...
...with side-effect foo.out.extra...
...Preparing side-effect foo.out.extra...
Copy("foo.out", "SConstruct")
Copy("foo.out.extra", "SConstruct")
Preparing target ....
"""

test.run(arguments = "--debug=prepare", stdout=test.wrap_stdout(expect))

test.must_exist('foo.out')

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/option/debug-presub.py

#!/usr/bin/env python
#
# __COPYRIGHT__
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#

__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"

import TestSCons

_python_ = TestSCons._python_

test = TestSCons.TestSCons()

test.write('cat.py', """\
import sys
with open(sys.argv[2], "wb") as f, open(sys.argv[1], "rb") as infp:
    f.write(infp.read())
sys.exit(0)
""")

test.write('SConstruct', """\
DefaultEnvironment(tools=[])
def cat(env, source, target):
    target = str(target[0])
    with open(target, "wb") as f:
        for src in source:
            with open(str(src), "rb") as infp:
                f.write(infp.read())
FILE = Builder(action="$FILECOM")
TEMP = Builder(action="$TEMPCOM")
LIST = Builder(action="$LISTCOM")
FUNC = Builder(action=cat)
env = Environment(tools=[],
                  PYTHON=r'%(_python_)s',
                  BUILDERS = {'FILE':FILE, 'TEMP':TEMP, 'LIST':LIST, 'FUNC':FUNC},
                  FILECOM="$PYTHON cat.py $SOURCES $TARGET",
                  TEMPCOM="$PYTHON cat.py $SOURCES temp\\n$PYTHON cat.py temp $TARGET",
                  LISTCOM=["$PYTHON cat.py $SOURCES temp", "$PYTHON cat.py temp $TARGET"],
                  FUNCCOM=cat)
env.Command('file01.out', 'file01.in', "$FILECOM")
env.Command('file02.out', 'file02.in', ["$FILECOM"])
env.Command('file03.out', 'file03.in', "$TEMPCOM")
env.Command('file04.out', 'file04.in', ["$TEMPCOM"])
env.Command('file05.out', 'file05.in', "$LISTCOM")
env.Command('file06.out', 'file06.in', ["$LISTCOM"])
env.Command('file07.out', 'file07.in', cat)
env.Command('file08.out', 'file08.in', "$FUNCCOM")
env.Command('file09.out', 'file09.in', ["$FUNCCOM"])
env.FILE('file11.out', 'file11.in')
env.FILE('file12.out', 'file12.in')
env.TEMP('file13.out', 'file13.in')
env.TEMP('file14.out', 'file14.in')
env.LIST('file15.out', 'file15.in')
env.LIST('file16.out', 'file16.in')
env.FUNC('file17.out', 'file17.in')
env.FUNC('file18.out', 'file18.in')

env2 = Environment(PYTHON=r'%(_python_)s',
                   CCCOM="$PYTHON cat.py $SOURCES $TARGET")
env2.Object('file20.obj', 'file20.c')
""" % locals())

test.write('file01.in', "file01.in\n")
test.write('file02.in', "file02.in\n")
test.write('file03.in', "file03.in\n")
test.write('file04.in', "file04.in\n")
test.write('file05.in', "file05.in\n")
test.write('file06.in', "file06.in\n")
test.write('file07.in', "file07.in\n")
test.write('file08.in', "file08.in\n")
test.write('file09.in', "file09.in\n")
test.write('file11.in', "file11.in\n")
test.write('file12.in', "file12.in\n")
test.write('file13.in', "file13.in\n")
test.write('file14.in', "file14.in\n")
test.write('file15.in', "file15.in\n")
test.write('file16.in', "file16.in\n")
test.write('file17.in', "file17.in\n")
test.write('file18.in', "file18.in\n")

test.write('file20.c', "file20.c\n")

expect = """\
Building file01.out with action:
  $PYTHON cat.py $SOURCES $TARGET
%(_python_)s cat.py file01.in file01.out
Building file02.out with action:
  $PYTHON cat.py $SOURCES $TARGET
%(_python_)s cat.py file02.in file02.out
Building file03.out with action:
  $PYTHON cat.py $SOURCES temp
%(_python_)s cat.py file03.in temp
Building file03.out with action:
  $PYTHON cat.py temp $TARGET
%(_python_)s cat.py temp file03.out
Building file04.out with action:
  $PYTHON cat.py $SOURCES temp
%(_python_)s cat.py file04.in temp
Building file04.out with action:
  $PYTHON cat.py temp $TARGET
%(_python_)s cat.py temp file04.out
Building file05.out with action:
  $PYTHON cat.py $SOURCES temp
%(_python_)s cat.py file05.in temp
Building file05.out with action:
  $PYTHON cat.py temp $TARGET
%(_python_)s cat.py temp file05.out
Building file06.out with action:
  $PYTHON cat.py $SOURCES temp
%(_python_)s cat.py file06.in temp
Building file06.out with action:
  $PYTHON cat.py temp $TARGET
%(_python_)s cat.py temp file06.out
Building file07.out with action:
  cat(target, source, env)
cat(["file07.out"], ["file07.in"])
Building file08.out with action:
  cat(target, source, env)
cat(["file08.out"], ["file08.in"])
Building file09.out with action:
  cat(target, source, env)
cat(["file09.out"], ["file09.in"])
Building file11.out with action:
  $PYTHON cat.py $SOURCES $TARGET
%(_python_)s cat.py file11.in file11.out
Building file12.out with action:
  $PYTHON cat.py $SOURCES $TARGET
%(_python_)s cat.py file12.in file12.out
Building file13.out with action:
  $PYTHON cat.py $SOURCES temp
%(_python_)s cat.py file13.in temp
Building file13.out with action:
  $PYTHON cat.py temp $TARGET
%(_python_)s cat.py temp file13.out
Building file14.out with action:
  $PYTHON cat.py $SOURCES temp
%(_python_)s cat.py file14.in temp
Building file14.out with action:
  $PYTHON cat.py temp $TARGET
%(_python_)s cat.py temp file14.out
Building file15.out with action:
  $PYTHON cat.py $SOURCES temp
%(_python_)s cat.py file15.in temp
Building file15.out with action:
  $PYTHON cat.py temp $TARGET
%(_python_)s cat.py temp file15.out
Building file16.out with action:
  $PYTHON cat.py $SOURCES temp
%(_python_)s cat.py file16.in temp
Building file16.out with action:
  $PYTHON cat.py temp $TARGET
%(_python_)s cat.py temp file16.out
Building file17.out with action:
  cat(target, source, env)
cat(["file17.out"], ["file17.in"])
Building file18.out with action:
  cat(target, source, env)
cat(["file18.out"], ["file18.in"])
Building file20.obj with action:
  $PYTHON cat.py $SOURCES $TARGET
%(_python_)s cat.py file20.c file20.obj
""" % locals()

test.run(arguments = "--debug=presub .", stdout=test.wrap_stdout(expect))

test.must_match('file01.out', "file01.in\n")
test.must_match('file02.out', "file02.in\n")
test.must_match('file03.out', "file03.in\n")
test.must_match('file04.out', "file04.in\n")
test.must_match('file05.out', "file05.in\n")
test.must_match('file06.out', "file06.in\n")
test.must_match('file07.out', "file07.in\n")
test.must_match('file08.out', "file08.in\n")
test.must_match('file09.out', "file09.in\n")
test.must_match('file11.out', "file11.in\n")
test.must_match('file12.out', "file12.in\n")
test.must_match('file13.out', "file13.in\n")
test.must_match('file14.out', "file14.in\n")
test.must_match('file15.out', "file15.in\n")
test.must_match('file16.out', "file16.in\n")
test.must_match('file17.out', "file17.in\n")
test.must_match('file18.out', "file18.in\n")

test.must_match('file20.obj', "file20.c\n")

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/option/debug-stacktrace.py

#!/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 the --debug=stacktrace option.
"""

import TestSCons

test = TestSCons.TestSCons()

test.write('SConstruct', """\
DefaultEnvironment(tools=[])
def kfile_scan(node, env, target):
    raise Exception("kfile_scan error")

kscan = Scanner(name = 'kfile',
                function = kfile_scan,
                skeys = ['.k'])

env = Environment(tools=[])
env.Append(SCANNERS = [kscan])

env.Command('foo', 'foo.k', Copy('$TARGET', '$SOURCE'))
""")

test.write('foo.k', "foo.k\n")

test.run(status = 2, stderr = "scons: *** [foo] Exception : kfile_scan error\n")

test.run(arguments = "--debug=stacktrace",
         status = 2,
         stderr = None)

lines = [
    "scons: *** [foo] Exception : kfile_scan error",
    "scons: internal stack trace:",
    'raise Exception("kfile_scan error")',
]

test.must_contain_all_lines(test.stderr(), lines)



# Test that --debug=stacktrace works for UserError exceptions,
# which are handled by different code than other exceptions.

test.write('SConstruct', """\
import SCons.Errors
raise SCons.Errors.UserError("explicit UserError!")
""")

test.run(arguments = '--debug=stacktrace',
         status = 2,
         stderr = None)

user_error_lines = [
    'UserError: explicit UserError!',
    'scons: *** explicit UserError!',
]

# The "(most recent call last)" message is used by more recent Python
# versions than the "(innermost last)" message, so that's the one
# we report if neither matches.
traceback_lines = [
    "Traceback (most recent call last)",
    "Traceback (innermost last)",
]

test.must_contain_all_lines(test.stderr(), user_error_lines)
test.must_contain_any_line(test.stderr(), traceback_lines)

# Test that full path names to SConscript files show up in stack traces.

test.write('SConstruct', """\
1/0
""")

test.run(arguments = '--debug=stacktrace',
         status = 2,
         stderr = None)

lines = [
    '  File "%s", line 1:' % test.workpath('SConstruct'),
]

test.must_contain_all_lines(test.stderr(), lines)



test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/option/debug-time.py

#!/usr/bin/env python
#
# __COPYRIGHT__
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"

import TestSCons
import re
import time

_python_ = TestSCons._python_

test = TestSCons.TestSCons()

test.write('sleep_cat.py', """\
import sys
import time
time.sleep(int(sys.argv[1]))
with open(sys.argv[2], 'wb') as fp:
    for arg in sys.argv[3:]:
        with open(arg, 'rb') as infp:
            fp.write(infp.read())
sys.exit(0)
""")

test.write('SConstruct', """
DefaultEnvironment(tools=[])
env = Environment(tools=[],
                  PYTHON = r'%(_python_)s',
                  SLEEP_CAT = r'sleep_cat.py',
                  CATCOM = '$PYTHON $SLEEP_CAT $SECONDS $TARGET $SOURCES',
                  SECONDS = ARGUMENTS.get('SLEEP', '0'))
f1 = env.Command('f1.out', 'f1.in', '$CATCOM')
f2 = env.Command('f2.out', 'f2.in', '$CATCOM')
f3 = env.Command('f3.out', 'f3.in', '$CATCOM')
f4 = env.Command('f4.out', 'f4.in', '$CATCOM')
env.Command('output', [f1, f2, f3, f4], '$CATCOM')
""" % locals())

test.write('f1.in', "f1.in\n")
test.write('f2.in', "f2.in\n")
test.write('f3.in', "f3.in\n")
test.write('f4.in', "f4.in\n")

expected_targets = ['f1.out', 'f2.out', 'f3.out', 'f4.out', 'output', '.']

# Before anything else, make sure we get valid --debug=time results
# when just running the help option.
test.run(arguments = "-h --debug=time")



def num(s, match):
    return float(re.search(match, s).group(1))

def within_tolerance(expected, actual, tolerance):
    return abs((expected-actual)/actual) <= tolerance

def get_total_time(stdout):
    return num(stdout, r'Total build time: (\d+\.\d+) seconds')

def get_sconscript_time(stdout):
    return num(stdout, r'Total SConscript file execution time: (\d+\.\d+) seconds')

def get_scons_time(stdout):
    return num(stdout, r'Total SCons execution time: (\d+\.\d+) seconds')

def get_command_time(stdout):
    return num(stdout, r'Total command execution time: (\d+\.\d+) seconds')



# Try to make our results a little more accurate and repeatable by
# measuring Python overhead executing a minimal file, and reading the
# scons.py script itself from disk so that it's already been cached.
test.write('pass.py', "pass\n")
test.read(test.program)

start_time = time.perf_counter()
test.run(program=TestSCons.python, arguments=test.workpath('pass.py'))
overhead = time.perf_counter() - start_time



start_time = time.perf_counter()
test.run(arguments = "-j1 --debug=time . SLEEP=0")
complete_time = time.perf_counter() - start_time



expected_total_time = complete_time - overhead

pattern = r'Command execution time: (.*): (\d+\.\d+) seconds'
targets = []
times = []
for target,time in re.findall(pattern, test.stdout()):
    targets.append(target)
    times.append(float(time))
expected_command_time = 0.0
for t in times:
    expected_command_time += t


stdout = test.stdout()

total_time      = get_total_time(stdout)
sconscript_time = get_sconscript_time(stdout)
scons_time      = get_scons_time(stdout)
command_time    = get_command_time(stdout)

failures = []
warnings = []

if  targets != expected_targets:
    failures.append("""\
Scons reported the targets of timing information as %(targets)s,
but the actual targets should have been %(expected_targets)s.
""" %locals())

if not within_tolerance(expected_command_time, command_time, 0.01):
    failures.append("""\
SCons -j1 reported a total command execution time of %(command_time)s,
but command execution times really totalled %(expected_command_time)s,
outside of the 1%% tolerance.
""" % locals())

added_times = sconscript_time+scons_time+command_time
if not within_tolerance(total_time, added_times, 0.01):
    failures.append("""\
SCons -j1 reported a total build time of %(total_time)s,
but the various execution times actually totalled %(added_times)s,
outside of the 1%% tolerance.
""" % locals())

if not within_tolerance(total_time, expected_total_time, 0.20):
    # This tolerance check seems empirically to work fine if there's
    # a light load on the system, but on a heavily loaded system the
    # timings get screwy and it can fail frequently.  Some obvious
    # attempts to work around the problem didn't, so just treat it as
    # a warning for now.
    warnings.append("""\
Warning:  SCons -j1 reported total build time of %(total_time)s,
but the actual measured build time was %(expected_total_time)s
(end-to-end time of %(complete_time)s less Python overhead of %(overhead)s),
outside of the 15%% tolerance.
""" % locals())

if failures or warnings:
    print('\n'.join([test.stdout()] + failures + warnings))
if failures:
    test.fail_test(1)

test.run(arguments = "--debug=time . SLEEP=0")

command_time = get_command_time(test.stdout())
if command_time != 0.0:
    print("Up-to-date run received non-zero command time of %s" % command_time)
    test.fail_test()



test.run(arguments = "-c")

test.run(arguments = "-j4 --debug=time . SLEEP=1")



stdout = test.stdout()

total_time      = get_total_time(stdout)
sconscript_time = get_sconscript_time(stdout)
scons_time      = get_scons_time(stdout)
command_time    = get_command_time(stdout)

failures = []

added_times = sconscript_time+scons_time+command_time
if not within_tolerance(total_time, added_times, 0.01):
    failures.append("""\
SCons -j4 reported a total build time of %(total_time)s,
but the various execution times actually totalled %(added_times)s,
outside of the 1%% tolerance.
""" % locals())

if failures:
    print('\n'.join([test.stdout()] + failures))
    test.fail_test(1)

test.run(arguments = "-j4 --debug=time . SLEEP=1")

command_time = get_command_time(test.stdout())
if command_time != 0.0:
    print("Up-to-date run received non-zero command time of %s" % command_time)
    test.fail_test()


test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/option/environment-overrides.py

#!/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 -e and --environment-overrides options are ignored.
"""

import TestSCons

test = TestSCons.TestSCons()

test.write('SConstruct', "DefaultEnvironment(tools=[])\n")

test.run(arguments = '-e .',
         stderr = "Warning:  ignoring -e option\n")

test.run(arguments = '--environment-overrides .',
         stderr = "Warning:  ignoring --environment-overrides option\n")

test.pass_test()
 

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/option/h.py

#!/usr/bin/env python
#
# __COPYRIGHT__
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#

__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"

import TestSCons

test = TestSCons.TestSCons()

test.run(arguments = '-h')
test.must_contain_all_lines(test.stdout(), ['-h, --help'])

test.run(arguments = '-u -h')
test.must_contain_all_lines(test.stdout(), ['-h, --help'])

test.run(arguments = '-U -h')
test.must_contain_all_lines(test.stdout(), ['-h, --help'])

test.run(arguments = '-D -h')
test.must_contain_all_lines(test.stdout(), ['-h, --help'])

test.write('SConstruct', "")

test.run(arguments = '-h')
test.must_contain_all_lines(test.stdout(), ['-h, --help'])

test.run(arguments = '-u -h')
test.must_contain_all_lines(test.stdout(), ['-h, --help'])

test.run(arguments = '-U -h')
test.must_contain_all_lines(test.stdout(), ['-h, --help'])

test.run(arguments = '-D -h')
test.must_contain_all_lines(test.stdout(), ['-h, --help'])

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/option/hash-format.py

#!/usr/bin/env python
#
# __COPYRIGHT__
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#

__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"

import hashlib
import os
import TestSCons
from SCons.Util import ALLOWED_HASH_FORMATS, DEFAULT_HASH_FORMATS

# Test passing the hash format by command-line.
INVALID_ALGORITHM = 'testfailure'

for algorithm in [*DEFAULT_HASH_FORMATS, INVALID_ALGORITHM, None]:
    test = TestSCons.TestSCons()
    test.dir_fixture('hash-format')

    # Expect failure due to an unsupported/invalid algorithm.
    # The error message however changes if SCons detects that the host system doesn't support one or more algorithms
    # Primary reason the message changes is so user doesn't have to start with unsupported algorithm A and then attempt
    # to switch to unsupported algorithm B.
    # On normal systems (allowed=default) this will output a fixed message, but on FIPS-enabled or other weird systems
    # that don't have default allowed algorithms, it informs the user of the mismatch _and_ the currently supported
    # algorithms on the system they're using.
    # In Python 3.9 this becomes somewhat obselete as the hashlib is informed we don't use hashing for security but
    # for loose integrity.
    if algorithm == INVALID_ALGORITHM:
        if ALLOWED_HASH_FORMATS == DEFAULT_HASH_FORMATS:
            test.run('--hash-format=%s .' % algorithm, stderr=r"""
scons: \*\*\* Hash format "{}" is not supported by SCons. Only the following hash formats are supported: {}
File "[^"]+", line \d+, in \S+
""".format(algorithm, ', '.join(DEFAULT_HASH_FORMATS)), status=2, match=TestSCons.match_re)
        else:
            test.run('--hash-format=%s .' % algorithm, stderr=r"""
scons: \*\*\* Hash format "{}" is not supported by SCons. SCons supports more hash formats than your local system is reporting; SCons supports: {}. Your local system only supports: {}
File "[^"]+", line \d+, in \S+
""".format(algorithm, ', '.join(DEFAULT_HASH_FORMATS), ', '.join(ALLOWED_HASH_FORMATS)), status=2, match=TestSCons.match_re)
        continue
    elif algorithm is not None:
        if algorithm in ALLOWED_HASH_FORMATS:
            expected_dblite = test.workpath('.sconsign_%s.dblite' % algorithm)
            test.run('--hash-format=%s .' % algorithm)
        else:
            test.run('--hash-format=%s' % algorithm, stderr=r"""
scons: \*\*\* While hash format "{}" is supported by SCons, the local system indicates only the following hash formats are supported by the hashlib library: {}
File "[^"]+", line \d+, in \S+
Error in atexit._run_exitfuncs:
Traceback \(most recent call last\):
  File "[^"]+", line \d+, in \S+
    assert csig == '[a-z0-9]+', csig
AssertionError: [a-z0-9]+
""".format(algorithm, ', '.join(ALLOWED_HASH_FORMATS)), status=2, match=TestSCons.match_re)
            continue
    else:
        # The SConsign file in the hash-format folder has logic to call
        # SCons.Util.set_hash_format('sha256') if the default algorithm is
        # being used. So this test of algorithm==None effectively validates
        # that the sconsign db includes the algorithm name if that function is
        # used instead of --hash-format. This is useful because consumers are
        # expected to call that function if they want to opt into stronger
        # hashes.
        expected_dblite = test.workpath('.sconsign_sha256.dblite')
        test.run('.')

    assert os.path.isfile(expected_dblite), \
        "%s does not exist when running algorithm %s" % (expected_dblite,
                                                         algorithm)

    test.run('-C .')
    os.unlink(expected_dblite)

# In this case, the SConstruct file will use SetOption to override the hash
# format.
test.run()

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/option/help-options.py

#!/usr/bin/env python
# MIT License
#
# Copyright The SCons Foundation
#
# 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 behavior of the -H and --help-options options.
"""


import re

import TestSCons

test = TestSCons.TestSCons()

test.write('SConstruct', "DefaultEnvironment(tools=[])\n")

test.run(arguments = '-H')

expect = [
    '-H, --help-options',
    '--debug=TYPE',
]
test.must_contain_all_lines(test.stdout(), expect)

# Validate that the help output lists the options in case-insensitive
# alphabetical order.

# Don't include in the sorted comparison the options that are ignored
# for compatibility.  They're all printed at the top of the list.
ignored_re = re.compile('.*Ignored for compatibility\\.\n', re.S)
stdout = ignored_re.sub('', test.stdout())

lines = stdout.split('\n')
lines = [x for x in lines if x[:3] == '  -']
lines = [x[3:] for x in lines]
lines = [x[0] == '-' and x[1:] or x for x in lines]
options = [x.split()[0] for x in lines]
options = [x[-1] == ',' and x[:-1] or x for x in options]
lowered = [x.lower() for x in options]
ordered = sorted(lowered)
if lowered != ordered:
    print("lowered =", lowered)
    print("sorted =", ordered)
    test.fail_test()

test.pass_test()
 

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/option/md5-chunksize.py

#!/usr/bin/env python
#
# __COPYRIGHT__
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#

__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"

import TestSCons

_python_ = TestSCons._python_

test = TestSCons.TestSCons()

test.write('build.py', r"""
import sys
with open(sys.argv[1], 'wb') as f, open(sys.argv[2], 'rb') as infp:
    f.write(infp.read())
""")

test.write('SConstruct', """
DefaultEnvironment(tools=[])
SetOption('md5_chunksize', 128)
B = Builder(action = r'%(_python_)s build.py $TARGETS $SOURCES')
env = Environment(tools=[], BUILDERS = { 'B' : B })
f1 = env.B(target = 'f1.out', source = 'f1.in')
f2 = env.B(target = 'f2.out', source = 'f2.in')
Requires(f2, f1)
""" % locals())

test.write('f1.in', str(list(range(10))))
test.write('f2.in', str(list(range(100000))))

expected_stdout = test.wrap_stdout("""\
%(_python_)s build.py f1.out f1.in
%(_python_)s build.py f2.out f2.in
""" % locals())

#
# Test with SetOption('md5_chunksize')
#
test.run(arguments = '.',
         stdout=expected_stdout,
         stderr='')
test.must_exist('f1.out')
test.must_exist('f2.out')

test.run(arguments = '-c .')
test.must_not_exist('f1.out')
test.must_not_exist('f2.out')

#
# Test with both synonyms: --hash-chunksize and --md5-chunksize
#
for name in ['--md5-chunksize', '--hash-chunksize']:
    test.run(arguments = '%s=128 .' % name,
             stdout=expected_stdout,
             stderr='')
    test.must_exist('f1.out')
    test.must_exist('f2.out')

    test.run(arguments = '%s=128 -c .' % name)
    test.must_not_exist('f1.out')
    test.must_not_exist('f2.out')

test.pass_test()

#
# Big-file test
#
test2 = TestSCons.TestSCons()

if sys.platform.find('linux') == -1:
    test2.skip_test("skipping test on non-Linux platform '%s'\n" % sys.platform)

dd = test2.where_is('dd')

if not dd:
    test2.skip_test('dd not found; skipping test\n')

expected_stdout = test2.wrap_stdout("""\
dd if=/dev/zero of=test.big seek=100 bs=1M count=0 2>/dev/null
get_stat(["test.stat"], ["test.big"])
""")

test2.write('SConstruct', """
DefaultEnvironment(tools=[])
import os
def get_stat(target, source, env):
    stat = os.stat(source[0].get_abspath())
    with open(target[0].get_abspath(),'w') as dest:
        dest.write(str(stat))
env = Environment(tools=[])
env.Command('test.big', 'SConstruct', 'dd if=/dev/zero of=test.big seek=100 bs=1M count=0 2>/dev/null')
env.AlwaysBuild('test.big')
env.Command('test.stat', 'test.big', Action(get_stat))
""")

test2.run(arguments='--md5-chunksize=128', stdout=expected_stdout, stderr='')
test2.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/option/no-print-directory.py

#!/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 --no-print-directory option is ignored.
"""

import TestSCons

test = TestSCons.TestSCons()

test.write('SConstruct', "DefaultEnvironment(tools=[])\n")

test.run(arguments = '--no-print-directory .',
         stderr = "Warning:  ignoring --no-print-directory option\n")

test.pass_test()
 

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/option/option--.py

#!/usr/bin/env python
#
# MIT License
#
# Copyright The SCons Foundation
#
# 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.

import os.path

import TestSCons

_python_ = TestSCons._python_

test = TestSCons.TestSCons()

test.write('build.py', r"""
import sys

with open(sys.argv[1], 'w') as file:
    file.write("build.py: %s\n" % sys.argv[1])
sys.exit(0)
""")

test.write('SConstruct', """
MyBuild = Builder(action=r'%(_python_)s build.py $TARGETS')
env = Environment(BUILDERS={'MyBuild': MyBuild})
env.MyBuild(target='-f1.out', source='f1.in')
env.MyBuild(target='-f2.out', source='f2.in')
""" % locals())

test.write('f1.in', "f1.in\n")
test.write('f2.in', "f2.in\n")

expect = test.wrap_stdout('%(_python_)s build.py -f1.out\n%(_python_)s build.py -f2.out\n' % locals())

test.run(arguments='-- -f1.out -f2.out', stdout=expect)

test.fail_test(not os.path.exists(test.workpath('-f1.out')))
test.fail_test(not os.path.exists(test.workpath('-f2.out')))

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/option/option--C.py

#!/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.
#

"""
Test that the -C option changes directory as expected and that
multiple -C options are additive, except if a full path is given
"""

__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"

import os

import TestSCons

def match_normcase(lines, matches):
    if not isinstance(lines, list):
        lines = lines.split("\n")
    if not isinstance(matches, list):
        matches = matches.split("\n")
    if len(lines) != len(matches):
        return None
    for line, match in zip(lines, matches):
        if os.path.normcase(line) != os.path.normcase(match):
            return None
    return 1

test = TestSCons.TestSCons(match=match_normcase)

wpath = test.workpath()
wpath_sub = test.workpath('sub')
wpath_sub_dir = test.workpath('sub', 'dir')
wpath_sub_foo_bar = test.workpath('sub', 'foo', 'bar')

test.subdir('sub', ['sub', 'dir'])

test.write('SConstruct', """
DefaultEnvironment(tools=[])
import os
print("SConstruct " + os.getcwd())
""")

test.write(['sub', 'SConstruct'], """
DefaultEnvironment(tools=[])
import os
print(GetBuildPath('..'))
""")

test.write(['sub', 'dir', 'SConstruct'], """
DefaultEnvironment(tools=[])
import os
env = Environment(FOO='foo', BAR='bar', tools=[])
print(env.GetBuildPath('../$FOO/$BAR'))
""")

# single -C
test.run(arguments='-C sub .',
         stdout="scons: Entering directory `%s'\n" % wpath_sub \
             + test.wrap_stdout(read_str='%s\n' % wpath,
                                build_str="scons: `.' is up to date.\n"))

# multiple -C
test.run(arguments='-C sub -C dir .',
         stdout="scons: Entering directory `%s'\n" % wpath_sub_dir \
             + test.wrap_stdout(read_str='%s\n' % wpath_sub_foo_bar,
                                build_str="scons: `.' is up to date.\n"))

test.run(arguments=".",
         stdout=test.wrap_stdout(read_str='SConstruct %s\n' % wpath,
                                 build_str="scons: `.' is up to date.\n"))

# alternate form
test.run(arguments='--directory=sub/dir .',
         stdout="scons: Entering directory `%s'\n" % wpath_sub_dir \
             + test.wrap_stdout(read_str='%s\n' % wpath_sub_foo_bar,
                                build_str="scons: `.' is up to date.\n"))

# checks that using full paths is not additive
test.run(arguments='-C %s -C %s .' % (wpath_sub_dir, wpath_sub),
         stdout="scons: Entering directory `%s'\n" % wpath_sub \
             + test.wrap_stdout(read_str='%s\n' % wpath,
                                build_str="scons: `.' is up to date.\n"))


test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/option/option--I.py

#!/usr/bin/env python
#
# __COPYRIGHT__
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#

__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"

import TestSCons

test = TestSCons.TestSCons()

test.subdir('sub1', 'sub2')

test.write(['sub1', 'foo.py'], """
variable = "sub1/foo"
""")

test.write(['sub2', 'foo.py'], """
variable = "sub2/foo"
""")

test.write(['sub2', 'bar.py'], """
variable = "sub2/bar"
""")

test.write('SConstruct', """
import foo
print(foo.variable)
import bar
print(bar.variable)
""")

test.run(arguments = '-I sub1 -I sub2 .',
         stdout = test.wrap_stdout(read_str = 'sub1/foo\nsub2/bar\n',
                                   build_str = "scons: `.' is up to date.\n"))

test.run(arguments = '--include-dir=sub2 --include-dir=sub1 .',
         stdout = test.wrap_stdout(read_str = 'sub2/foo\nsub2/bar\n',
                                   build_str = "scons: `.' is up to date.\n"))

test.pass_test()
 

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/option/option--Q.py

#!/usr/bin/env python
#
# MIT License
#
# Copyright The SCons Foundation
#
# 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.

import os.path

import TestSCons

_python_ = TestSCons._python_

test = TestSCons.TestSCons()


test.write('build.py', r"""
import sys

with open(sys.argv[1], 'w') as file:
    file.write("build.py: %s\n" % sys.argv[1])
sys.exit(0)
""")

test.write('SConstruct', """
AddOption('--use_SetOption', action='store_true', dest='setoption', default=False)

use_setoption = GetOption('setoption')

if use_setoption:
    SetOption('no_progress', True)

MyBuild = Builder(action=r'%(_python_)s build.py $TARGET')
env = Environment(BUILDERS={'MyBuild': MyBuild})
env.MyBuild(target='f1.out', source='f1.in')
env.MyBuild(target='f2.out', source='f2.in')
""" % locals())

test.write('f1.in', "f1.in\n")
test.write('f2.in', "f2.in\n")

test.run(arguments = '-Q f1.out f2.out', stdout = """\
%(_python_)s build.py f1.out
%(_python_)s build.py f2.out
""" % locals())
test.fail_test(not os.path.exists(test.workpath('f1.out')))
test.fail_test(not os.path.exists(test.workpath('f2.out')))

# Make sure -q doesn't suppress other messages, too.
test.run(arguments = '-Q -c f1.out f2.out', stdout = """\
Removed f1.out
Removed f2.out
""")
test.fail_test(os.path.exists(test.workpath('f1.out')))
test.fail_test(os.path.exists(test.workpath('f2.out')))


# When set via a SetOption, it will happen after the initial output of
# scons: Reading SConscript files ...
# but remaining status/progress output will not be output
test.run(arguments = '--use_SetOption f1.out f2.out', stdout = """\
scons: Reading SConscript files ...
%(_python_)s build.py f1.out
%(_python_)s build.py f2.out
""" % locals())
test.fail_test(not os.path.exists(test.workpath('f1.out')))
test.fail_test(not os.path.exists(test.workpath('f2.out')))


test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/option/option--R.py

#!/usr/bin/env python
#
# __COPYRIGHT__
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#

__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"

import TestSCons

test = TestSCons.TestSCons()

test.write('SConstruct', "")

test.option_not_yet_implemented('-R', '.')

test.option_not_yet_implemented('--no-builtin-variables', '.')

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/option/option--S.py

#!/usr/bin/env python
#
# __COPYRIGHT__
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#

__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"

import TestSCons

test = TestSCons.TestSCons()

test.write('SConstruct', "")

test.run(arguments = '-S .', stderr = "Warning:  ignoring -S option\n")

test.run(arguments = '--no-keep-going .',
         stderr = "Warning:  ignoring --no-keep-going option\n")

test.run(arguments = '--stop .', stderr = "Warning:  ignoring --stop option\n")

test.pass_test()
 

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/option/option--W.py

#!/usr/bin/env python
#
# __COPYRIGHT__
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#

__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"

import TestSCons

test = TestSCons.TestSCons()

test.write('SConstruct', """\
DefaultEnvironment(tools=[])
""")

test.option_not_yet_implemented('-W', 'foo .')

test.option_not_yet_implemented('--what-if', '=foo .')

test.option_not_yet_implemented('--new-file', '=foo .')

test.option_not_yet_implemented('--assume-new', '=foo .')

test.pass_test()
 
# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/option/option--Y.py

#!/usr/bin/env python
#
# MIT License
#
# Copyright The SCons Foundation
#
# 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.

import sys

from TestSCons import TestSCons, _exe

test = TestSCons()

test.subdir('repository', 'work1')

repository = test.workpath('repository')
repository_foo_c = test.workpath('repository', 'foo.c')
work1_foo = test.workpath('work1', 'foo' + _exe)
work1_foo_c = test.workpath('work1', 'foo.c')

test.write(['repository', 'SConstruct'], r"""
env = Environment()
env.Program(target= 'foo', source = Split('aaa.c bbb.c foo.c'))
""")

test.write(['repository', 'aaa.c'], r"""
#include <stdio.h>
void
aaa(void)
{
      printf("repository/aaa.c\n");
}
""")

test.write(['repository', 'bbb.c'], r"""
#include <stdio.h>
void
bbb(void)
{
      printf("repository/bbb.c\n");
}
""")

test.write(['repository', 'foo.c'], r"""
#include <stdio.h>
#include <stdlib.h>
extern void aaa(void);
extern void bbb(void);
int
main(int argc, char *argv[])
{
      argv[argc++] = "--";
      aaa();
      bbb();
      printf("repository/foo.c\n");
      exit (0);
}
""")

opts = '-Y ' + repository

# Make the entire repository non-writable, so we'll detect
# if we try to write into it accidentally.
test.writable('repository', 0)

test.run(chdir = 'work1', options = opts, arguments = '.')

test.run(program = work1_foo, stdout = """repository/aaa.c
repository/bbb.c
repository/foo.c
""")

test.up_to_date(chdir = 'work1', options = opts, arguments = '.')

#
test.write(['work1', 'bbb.c'], r"""
#include <stdio.h>
#include <stdlib.h>
void
bbb(void)
{
      printf("work1/bbb.c\n");
}
""")

test.run(chdir = 'work1', options = opts, arguments = '.')

test.run(program = work1_foo, stdout = """repository/aaa.c
work1/bbb.c
repository/foo.c
""")

test.up_to_date(chdir = 'work1', options = opts, arguments = '.')

#
test.write(['work1', 'aaa.c'], r"""
#include <stdio.h>
#include <stdlib.h>
void
aaa(void)
{
      printf("work1/aaa.c\n");
}
""")

test.write(['work1', 'foo.c'], r"""
#include <stdio.h>
#include <stdlib.h>
extern void aaa(void);
extern void bbb(void);
int
main(int argc, char *argv[])
{
      argv[argc++] = "--";
      aaa();
      bbb();
      printf("work1/foo.c\n");
      exit (0);
}
""")

test.run(chdir = 'work1', options = opts, arguments = '.')

test.run(program = work1_foo, stdout = """work1/aaa.c
work1/bbb.c
work1/foo.c
""")

test.up_to_date(chdir = 'work1', options = opts, arguments = '.')

#
test.unlink(['work1', 'bbb.c'])
test.unlink(['work1', 'foo.c'])

test.run(chdir = 'work1', options = opts, arguments = '.')

test.run(program = work1_foo, stdout = """work1/aaa.c
repository/bbb.c
repository/foo.c
""")

test.up_to_date(chdir = 'work1', options = opts, arguments = '.')



#
test.subdir('r.NEW', 'r.OLD', 'work2')

workpath_r_NEW = test.workpath('r.NEW')
workpath_r_OLD = test.workpath('r.OLD')
work2_foo = test.workpath('work2', 'foo' + _exe)

SConstruct = """
env = Environment()
env.Program(target = 'foo', source = 'foo.c')
"""

test.write(['r.OLD', 'SConstruct'], SConstruct)

test.write(['r.NEW', 'SConstruct'], SConstruct)

test.write(['r.OLD', 'foo.c'], r"""
#include <stdio.h>
#include <stdlib.h>
int
main(int argc, char *argv[])
{
      argv[argc++] = "--";
      printf("r.OLD/foo.c\n");
      exit (0);
}
""")

opts = '-Y %s -Y %s' % (workpath_r_NEW, workpath_r_OLD)

# Make the repositories non-writable, so we'll detect
# if we try to write into them accidentally.
test.writable('r.OLD', 0)
test.writable('r.NEW', 0)

test.run(chdir = 'work2', options = opts, arguments = '.')

test.run(program = work2_foo, stdout = "r.OLD/foo.c\n")

test.up_to_date(chdir = 'work2', options = opts, arguments = '.')

#
test.writable('r.NEW', 1)

test.write(['r.NEW', 'foo.c'], r"""
#include <stdio.h>
#include <stdlib.h>
int
main(int argc, char *argv[])
{
      argv[argc++] = "--";
      printf("r.NEW/foo.c\n");
      exit (0);
}
""")

test.writable('r.NEW', 0)

test.run(chdir = 'work2', options = opts, arguments = '.')

test.run(program = work2_foo, stdout = "r.NEW/foo.c\n")

test.up_to_date(chdir = 'work2', options = opts, arguments = '.')

#
test.write(['work2', 'foo.c'], r"""
#include <stdio.h>
#include <stdlib.h>
int
main(int argc, char *argv[])
{
      argv[argc++] = "--";
      printf("work2/foo.c\n");
      exit (0);
}
""")

test.run(chdir = 'work2', options = opts, arguments = '.')

test.run(program = work2_foo, stdout = "work2/foo.c\n")

test.up_to_date(chdir = 'work2', options = opts, arguments = '.')

#
test.writable('r.OLD', 1)
test.writable('r.NEW', 1)

test.write(['r.OLD', 'foo.c'], r"""
#include <stdio.h>
#include <stdlib.h>
int
main(int argc, char *argv[])
{
      argv[argc++] = "--";
      printf("r.OLD/foo.c 2\n");
      exit (0);
}
""")

test.write(['r.NEW', 'foo.c'], r"""
#include <stdio.h>
#include <stdlib.h>
int
main(int argc, char *argv[])
{
      argv[argc++] = "--";
      printf("r.NEW/foo.c 2\n");
      exit (0);
}
""")

test.writable('r.OLD', 0)
test.writable('r.NEW', 0)

test.up_to_date(chdir = 'work2', options = opts, arguments = '.')

#
test.unlink(['work2', 'foo.c'])

test.run(chdir = 'work2', options = opts, arguments = '.')

test.run(program = work2_foo, stdout = "r.NEW/foo.c 2\n")

test.up_to_date(chdir = 'work2', options = opts, arguments = '.')

#
test.writable('r.NEW', 1)

test.unlink(['r.NEW', 'foo.c'])

test.writable('r.NEW', 0)

test.run(chdir = 'work2', options = opts, arguments = '.')

test.run(program = work2_foo, stdout = "r.OLD/foo.c 2\n")

test.up_to_date(chdir = 'work2', options = opts, arguments = '.')



#
test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/option/option--duplicate.py

#!/usr/bin/env python
#
# MIT License
#
# Copyright The SCons Foundation
#
# 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.

"""
This tests the --duplicate command line option, and the duplicate
SConscript settable option.
"""

__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"

import os
import sys
import stat
import TestSCons

python = TestSCons.python

test = TestSCons.TestSCons()

test.write('SConstruct', """
DefaultEnvironment(tools=[])
try:
    duplicate = ARGUMENTS['duplicate']
    SetOption('duplicate', duplicate)
except KeyError:
    pass
VariantDir('build', '.', duplicate=1)
SConscript('build/SConscript')
""")

test.write('SConscript', '')

# we don't use links on windows currently as they
# require permissions not usually set
hard = hasattr(os, 'link') and sys.platform != 'win32'
soft = hasattr(os, 'symlink') and sys.platform != 'win32'
copy = 1 # should always work

bss = test.workpath('build/SConscript')

criterion_hardlinks = {
    'hard'      : lambda nl, islink: nl == 2 and not islink,
    'soft'      : lambda nl, islink: nl == 1 and islink,
    'copy'      : lambda nl, islink: nl == 1 and not islink,
}

criterion_no_hardlinks = {
    'hard'      : lambda nl, islink: not islink,
    'soft'      : lambda nl, islink: islink,
    'copy'      : lambda nl, islink: not islink,
}

# On systems without hard linking, it doesn't make sense to check ST_NLINK
if hard:
    criterion = criterion_hardlinks
else:
    criterion = criterion_no_hardlinks

description = {
    'hard'      : 'a hard link',
    'soft'      : 'a soft link',
    'copy'      : 'copied',
}

def testLink(file, type):
    nl = os.stat(file)[stat.ST_NLINK]
    islink = os.path.islink(file)
    assert criterion[type](nl, islink), \
           "Expected %s to be %s (nl %d, islink %d)" \
           % (file, description[type], nl, islink)

def RunTest(order, type, bss):
    # Test the command-line --duplicate option.
    test.run(arguments='--duplicate='+order)
    testLink(bss, type)

    # Test setting the option in the SConstruct file.
    test.run(arguments='duplicate='+order)
    testLink(bss, type)

    # Clean up for next run.
    os.unlink(bss)

# test the default (hard-soft-copy)
if hard:   type='hard'
elif soft: type='soft'
else:      type='copy'
RunTest('hard-soft-copy', type, bss)

if soft:   type='soft'
elif hard: type='hard'
else:      type='copy'
RunTest('soft-hard-copy', type, bss)

if soft:   type='soft'
else:      type='copy'
RunTest('soft-copy', type, bss)

if hard:   type='hard'
else:      type='copy'
RunTest('hard-copy', type, bss)

type='copy'
RunTest('copy', type, bss)

test.run(arguments='--duplicate=nonsense', status=2, stderr="""\
usage: scons [OPTIONS] [VARIABLES] [TARGETS]

SCons Error: `nonsense' is not a valid duplication option type, try:
    hard-soft-copy, soft-hard-copy, hard-copy, soft-copy, copy
""")

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/option/option--experimental.py

#!/usr/bin/env python
#
# MIT License
#
# Copyright The SCons Foundation
#
# 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.

"""
Test the --experimental option.
"""

import TestSCons

test = TestSCons.TestSCons()

test.file_fixture('fixture/SConstruct__experimental', 'SConstruct')

tests = [
    ('.', []),
    ('--experimental=ninja', ['ninja']),
    ('--experimental=all', ['ninja', 'transporter', 'warp_speed']),
    ('--experimental=none', []),
]

for args, exper in tests:
    read_string = """All Features=ninja,transporter,warp_speed
Experimental=%s
""" % (exper)
    test.run(arguments=args,
             stdout=test.wrap_stdout(read_str=read_string, build_str="scons: `.' is up to date.\n"))

test.run(arguments='--experimental=warp_drive',
         stderr="""usage: scons [OPTIONS] [VARIABLES] [TARGETS]

SCons Error: option --experimental: invalid choice: 'warp_drive' (choose from 'all','none','ninja','transporter','warp_speed')
""",
         status=2)

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/option/option--la.py

#!/usr/bin/env python
#
# __COPYRIGHT__
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#

__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"

import TestSCons

test = TestSCons.TestSCons()

test.write('SConstruct', "")

test.option_not_yet_implemented('--list-actions', '.')

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/option/option--ld.py

#!/usr/bin/env python
#
# __COPYRIGHT__
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#

__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"

import TestSCons

test = TestSCons.TestSCons()

test.write('SConstruct', "")

test.option_not_yet_implemented('--list-derived', '.')

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/option/option--lw.py

#!/usr/bin/env python
#
# __COPYRIGHT__
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#

__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"

import TestSCons

test = TestSCons.TestSCons()

test.write('SConstruct', "")

test.option_not_yet_implemented('--list-where', '.')

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/option/option--max-drift.py

#!/usr/bin/env python
#
# __COPYRIGHT__
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#

__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"

import os

import TestSCons

_python_ = TestSCons._python_

test = TestSCons.TestSCons()

test.write('build.py', r"""
import sys
with open(sys.argv[1], 'wb') as f, open(sys.argv[2], 'rb') as ifp:
    f.write(ifp.read())
""")

test.write('SConstruct', """
DefaultEnvironment(tools=[])
B = Builder(action = r'%(_python_)s build.py $TARGETS $SOURCES')
env = Environment(BUILDERS = { 'B' : B }, tools=[])
env.B(target = 'f1.out', source = 'f1.in')
env.B(target = 'f2.out', source = 'f2.in')
""" % locals())

test.write('f1.in', "f1.in\n")
test.write('f2.in', "f2.in\n")



test.run(arguments = 'f1.out')

test.run(arguments = 'f1.out f2.out',
         stdout = test.wrap_stdout(
"""scons: `f1.out' is up to date.
%(_python_)s build.py f2.out f2.in
""" % locals()))

atime = os.path.getatime(test.workpath('f1.in'))
mtime = os.path.getmtime(test.workpath('f1.in'))

test.up_to_date(options='--max-drift=0', arguments='f1.out f2.out')

test.write('f1.in', "f1.in delta\n")
os.utime(test.workpath('f1.in'), (atime,mtime))

test.up_to_date(options='--max-drift=0', arguments='f1.out f2.out')

expect = test.wrap_stdout(
"""%(_python_)s build.py f1.out f1.in
scons: `f2.out' is up to date.
""" % locals())

test.run(arguments = '--max-drift=-1 f1.out f2.out', stdout = expect)

# Test that Set/GetOption('max_drift') works:
test.write('SConstruct', """
DefaultEnvironment(tools=[])
assert GetOption('max_drift') == 2*24*60*60
SetOption('max_drift', 1)
assert GetOption('max_drift') == 1
""")

test.run()

test.write('SConstruct', """
DefaultEnvironment(tools=[])
assert GetOption('max_drift') == 1
SetOption('max_drift', 10)
assert GetOption('max_drift') == 1
""")

test.run(arguments='--max-drift=1')

# Test that SetOption('max_drift') actually sets max_drift
# by mucking with the file timestamps to make SCons not realize the source has changed
test.write('SConstruct', """
DefaultEnvironment(tools=[])
SetOption('max_drift', 0)
B = Builder(action = r'%(_python_)s build.py $TARGETS $SOURCES')
env = Environment(BUILDERS = { 'B' : B }, tools=[])
env.B(target = 'foo.out', source = 'foo.in')
""" % locals())

test.write('foo.in', 'foo.in\n')

atime = os.path.getatime(test.workpath('foo.in'))
mtime = os.path.getmtime(test.workpath('foo.in'))

test.run()
test.must_match('foo.out', 'foo.in\n', mode='r')

test.write('foo.in', 'foo.in delta\n')
os.utime(test.workpath('foo.in'), (atime,mtime))

test.run()

test.must_match('foo.out', 'foo.in\n', mode='r')

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/option/option--override.py

#!/usr/bin/env python
#
# __COPYRIGHT__
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#

__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"

import TestSCons

test = TestSCons.TestSCons()

test.write('SConstruct', "")

test.option_not_yet_implemented('--override', '=foo .')

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/option/option--random.py

#!/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 we build correctly using the --random option.
"""

__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"


import TestSCons

test = TestSCons.TestSCons()

test.write('SConscript', """\
def cat(env, source, target):
    target = str(target[0])
    with open(target, "wb") as f:
        for src in source:
            with open(str(src), "rb") as ifp:
                f.write(ifp.read())
env = Environment(BUILDERS={'Cat':Builder(action=cat)})
env.Cat('aaa.out', 'aaa.in')
env.Cat('bbb.out', 'bbb.in')
env.Cat('ccc.out', 'ccc.in')
env.Cat('all', ['aaa.out', 'bbb.out', 'ccc.out'])
""")

test.write('aaa.in', "aaa.in\n")
test.write('bbb.in', "bbb.in\n")
test.write('ccc.in', "ccc.in\n")



test.write('SConstruct', """\
SetOption('random', 1)
SConscript('SConscript')
""")

test.run(arguments = '-n -Q')
non_random_output = test.stdout()

tries = 0
max_tries = 10
while test.stdout() == non_random_output:
    if tries >= max_tries:
        print("--random generated the non-random output %s times!" % max_tries)
        test.fail_test()
    tries = tries + 1
    test.run(arguments = '-n -Q --random')



test.write('SConstruct', """\
SConscript('SConscript')
""")

test.run(arguments = '-n -Q')
non_random_output = test.stdout()

tries = 0
max_tries = 10
while test.stdout() == non_random_output:
    if tries >= max_tries:
        print("--random generated the non-random output %s times!" % max_tries)
        test.fail_test()
    tries = tries + 1
    test.run(arguments = '-n -Q --random')



test.run(arguments = '-Q --random')

test.must_match('all', "aaa.in\nbbb.in\nccc.in\n")

test.run(arguments = '-q --random .')

test.run(arguments = '-c --random .')

test.must_not_exist(test.workpath('aaa.out'))
test.must_not_exist(test.workpath('bbb.out'))
test.must_not_exist(test.workpath('ccc.out'))
test.must_not_exist(test.workpath('all'))

test.run(arguments = '-q --random .', status = 1)

test.run(arguments = '--random .')

test.must_match('all', "aaa.in\nbbb.in\nccc.in\n")

test.run(arguments = '-c --random .')



test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/option/option--tree.py

#!/usr/bin/env python
#
# MIT License
#
# Copyright The SCons Foundation
#
# 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.

import TestSCons

test = TestSCons.TestSCons()

test.write('SConstruct', "")

test.run(arguments='-Q --tree=prune',
         stdout="""scons: `.' is up to date.
+-.
  +-SConstruct
""")

test.run(arguments='-Q --tree=foofoo',
         stderr="""usage: scons [OPTIONS] [VARIABLES] [TARGETS]

SCons Error: `foofoo' is not a valid --tree option type, try:
    all, derived, prune, status, linedraw
""",
         status=2)


# Test that unicode characters can be printed (escaped) with the --tree option
test.write('SConstruct', """\
env = Environment()
env.Tool("textfile")
name = "français"
env.Textfile("Foo", name)
""")

uchar = chr(0xe7)

expected = """Creating 'Foo.txt'
+-.
  +-Foo.txt
  | +-fran%sais
  +-SConstruct
""" % uchar

test.run(arguments='-Q --tree=all', stdout=expected, status=0)

# Test the "linedraw" option: same basic test as previous.
# With "--tree=linedraw" must default to "all", and use line-drawing chars.
test.write('SConstruct', """\
env = Environment()
env.Tool("textfile")
name = "français"
env.Textfile("LineDraw", name)
""")

expected = """Creating 'LineDraw.txt'
└─┬.
  ├─┬LineDraw.txt
  │ └─fran%sais
  └─SConstruct
""" % uchar


test.run(arguments='-Q --tree=linedraw', stdout=expected, status=0)

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/option/option--wf.py

#!/usr/bin/env python
#
# __COPYRIGHT__
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#

__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"

import TestSCons

test = TestSCons.TestSCons()

test.write('SConstruct', "")

test.option_not_yet_implemented('--write-filenames', '=FILE .')

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/option/option--wuv.py

#!/usr/bin/env python
#
# __COPYRIGHT__
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#

__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"

import TestSCons

test = TestSCons.TestSCons()

# We want to preserve the --warn-undefined-variables option for
# compatibility with GNU Make.  Unfortunately, this conflicts with
# the --warn=type option that we're using for our own warning
# control.  The getopt module reports "--warn not a unique prefix"
# when both are defined.  We may be able to support both in the
# future with a more robust getopt solution.
test.pass_test()        #XXX Short-circuit until then.

test.write('SConstruct', "")

test.option_not_yet_implemented('--warn-undefined-variables')

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/option/option-b.py

#!/usr/bin/env python
#
# __COPYRIGHT__
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#

__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"

import TestSCons

test = TestSCons.TestSCons()

test.write('SConstruct', "")

test.run(arguments = '-b .',
         stderr = "Warning:  ignoring -b option\n")

test.pass_test()
 

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/option/option-f.py

#!/usr/bin/env python
#
# MIT License
#
# Copyright The SCons Foundation
#
# 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.

import os

import TestSCons

test = TestSCons.TestSCons()

test.subdir('subdir')

subdir_BuildThis = os.path.join('subdir', 'Buildthis')

test.write('SConscript', """
DefaultEnvironment(tools=[])
import os
print("SConscript " + os.getcwd())
""")

test.write(subdir_BuildThis, """
DefaultEnvironment(tools=[])
import os
print("subdir/BuildThis "+ os.getcwd())
""")

test.write('Build2', """
DefaultEnvironment(tools=[])
import os
print("Build2 "+ os.getcwd())
""")

wpath = test.workpath()

test.run(
    arguments='-f SConscript .',
    stdout=test.wrap_stdout(
        read_str='SConscript %s\n' % wpath, build_str="scons: `.' is up to date.\n"
    ),
)

test.run(
    arguments='-f %s .' % subdir_BuildThis,
    stdout=test.wrap_stdout(
        read_str='subdir/BuildThis %s\n' % wpath,
        build_str="scons: `.' is up to date.\n",
    ),
)

test.run(
    arguments='--file=SConscript .',
    stdout=test.wrap_stdout(
        read_str='SConscript %s\n' % wpath, build_str="scons: `.' is up to date.\n"
    ),
)

test.run(
    arguments='--file=%s .' % subdir_BuildThis,
    stdout=test.wrap_stdout(
        read_str='subdir/BuildThis %s\n' % wpath,
        build_str="scons: `.' is up to date.\n",
    ),
)

test.run(
    arguments='--makefile=SConscript .',
    stdout=test.wrap_stdout(
        read_str='SConscript %s\n' % wpath, build_str="scons: `.' is up to date.\n"
    ),
)

test.run(
    arguments='--makefile=%s .' % subdir_BuildThis,
    stdout=test.wrap_stdout(
        read_str='subdir/BuildThis %s\n' % wpath,
        build_str="scons: `.' is up to date.\n",
    ),
)

test.run(
    arguments='--sconstruct=SConscript .',
    stdout=test.wrap_stdout(
        read_str='SConscript %s\n' % wpath, build_str="scons: `.' is up to date.\n"
    ),
)

test.run(
    arguments='--sconstruct=%s .' % subdir_BuildThis,
    stdout=test.wrap_stdout(
        read_str='subdir/BuildThis %s\n' % wpath,
        build_str="scons: `.' is up to date.\n",
    ),
)

test.run(
    arguments='-f - .',
    stdin="""
DefaultEnvironment(tools=[])
import os
print("STDIN " + os.getcwd())
""",
    stdout=test.wrap_stdout(
        read_str='STDIN %s\n' % wpath, build_str="scons: `.' is up to date.\n"
    ),
)

expect = test.wrap_stdout(
    read_str='Build2 %s\nSConscript %s\n' % (wpath, wpath),
    build_str="scons: `.' is up to date.\n",
)
test.run(arguments='-f Build2 -f SConscript .', stdout=expect)

test.run(
    arguments='-f no_such_file .',
    stdout=test.wrap_stdout("scons: `.' is up to date.\n"),
    stderr=None,
)

expect = """
scons: warning: Calling missing SConscript without error is deprecated.
Transition by adding must_exist=False to SConscript calls.
Missing SConscript 'no_such_file'"""
stderr = test.stderr()
test.must_contain_all(test.stderr(), expect)

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/option/option-i.py

#!/usr/bin/env python
#
# MIT License
#
# Copyright The SCons Foundation
#
# 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.

import os.path

import TestSCons

_python_ = TestSCons._python_

test = TestSCons.TestSCons()

test.write('succeed.py', r"""
import sys

with open(sys.argv[1], 'w') as file:
    file.write("succeed.py: %s\n" % sys.argv[1])
sys.exit(0)
""")

test.write('fail.py', r"""
import sys

sys.exit(1)
""")

test.write('SConstruct', """
Succeed = Builder(action=r'%(_python_)s succeed.py $TARGETS')
Fail = Builder(action=r'%(_python_)s fail.py $TARGETS')
env = Environment(BUILDERS={'Succeed': Succeed, 'Fail': Fail})
env.Fail(target='aaa.1', source='aaa.in')
env.Succeed(target='aaa.out', source='aaa.1')
env.Fail(target='bbb.1', source='bbb.in')
env.Succeed(target='bbb.out', source='bbb.1')
""" % locals())

test.write('aaa.in', "aaa.in\n")
test.write('bbb.in', "bbb.in\n")

test.run(
    arguments='aaa.1 aaa.out bbb.1 bbb.out',
    stderr='scons: *** [aaa.1] Error 1\n',
    status=2,
)

test.fail_test(os.path.exists(test.workpath('aaa.1')))
test.fail_test(os.path.exists(test.workpath('aaa.out')))
test.fail_test(os.path.exists(test.workpath('bbb.1')))
test.fail_test(os.path.exists(test.workpath('bbb.out')))

test.run(
    arguments='-i aaa.1 aaa.out bbb.1 bbb.out',
    stderr='scons: *** [aaa.1] Error 1\nscons: *** [bbb.1] Error 1\n',
)
         
test.fail_test(os.path.exists(test.workpath('aaa.1')))
test.fail_test(test.read('aaa.out',mode='r') != "succeed.py: aaa.out\n")
test.fail_test(os.path.exists(test.workpath('bbb.1')))
test.fail_test(test.read('bbb.out',mode='r') != "succeed.py: bbb.out\n")

test.unlink("aaa.out")
test.unlink("bbb.out")

test.run(
    arguments='--ignore-errors aaa.1 aaa.out bbb.1 bbb.out',
    stderr='scons: *** [aaa.1] Error 1\nscons: *** [bbb.1] Error 1\n',
)

test.fail_test(os.path.exists(test.workpath('aaa.1')))
test.fail_test(test.read('aaa.out', mode='r') != "succeed.py: aaa.out\n")
test.fail_test(os.path.exists(test.workpath('bbb.1')))
test.fail_test(test.read('bbb.out', mode='r') != "succeed.py: bbb.out\n")

test.pass_test()
 

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/option/option-j.py

#!/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.
#

"""
This tests the -j command line option, and the num_jobs
SConscript settable option.
"""

__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"

import os.path
import sys

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()

test.write('build.py', r"""
import time
import sys
with open(sys.argv[1], 'w') as f:
    f.write(str(time.time()) + '\n')
    time.sleep(1)
    f.write(str(time.time()))
""")

test.subdir('foo')

test.write(['foo','foo.in'], r"""
foo you
""")

test.write('SConstruct', """
DefaultEnvironment(tools=[])
MyBuild = Builder(action = r'%(_python_)s build.py $TARGETS')
env = Environment(BUILDERS={'MyBuild': MyBuild}, tools=[])
env.Tool('install')
env.MyBuild(target='f1', source='f1.in')
env.MyBuild(target='f2', source='f2.in')

def copyn(env, target, source):
    import shutil
    import time
    time.sleep(1)
    for t in target:
        shutil.copy(str(source[0]), str(t))

t = env.Command(target=['foo/foo1.out', 'foo/foo2.out'],
                source='foo/foo.in',
                action=copyn)
env.Install('out', t)
""" % locals())

def RunTest(args, extra):
    """extra is used to make scons rebuild the output file"""
    test.write('f1.in', 'f1.in'+extra)
    test.write('f2.in', 'f2.in'+extra)

    test.run(arguments = args)

    str = test.read("f1", mode='r')
    start1,finish1 = list(map(float, str.split("\n")))

    str = test.read("f2", mode='r')
    start2,finish2 = list(map(float, str.split("\n")))

    return start2, finish1

# Test 2 parallel jobs.
# fail if the second file was not started
# before the first one was finished.
start2, finish1 = RunTest('-j 2 f1 f2', "first")
test.fail_test(not (start2 < finish1))

# re-run the test with the same input, fail if we don't
# get back the same times, which would indicate that
# SCons rebuilt the files even though nothing changed
s2, f1 = RunTest('-j 2 f1 f2', "first")
test.fail_test(start2 != s2)
test.fail_test(finish1 != f1)

# Test a single serial job.
# fail if the second file was started
# before the first one was finished
start2, finish1 = RunTest('f1 f2', "second")
test.fail_test(start2 < finish1)

# Make sure that a parallel build using a list builder
# succeeds.
test.run(arguments='-j 2 out')

if sys.platform != 'win32' and sys.version_info[0] == 2:
    # Test breaks on win32 when using real subprocess is not the only
    # package to import threading
    #
    # Test that we fall back and warn properly if there's no threading.py
    # module (simulated), which is the case if this version of Python wasn't
    # built with threading support.

    test.subdir('pythonlib')

    test.write(['pythonlib', 'threading.py'], "raise ImportError\n")

    save_pythonpath = os.environ.get('PYTHONPATH', '')
    os.environ['PYTHONPATH'] = test.workpath('pythonlib')

    #start2, finish1 = RunTest('-j 2 f1, f2', "fifth")

    test.write('f1.in', 'f1.in pythonlib\n')
    test.write('f2.in', 'f2.in pythonlib\n')

    test.run(arguments = "-j 2 f1 f2", stderr=None)

    warn = """scons: warning: parallel builds are unsupported by this version of Python;
\tignoring -j or num_jobs option."""
    test.must_contain_all_lines(test.stderr(), [warn])

    str = test.read("f1", mode='r')
    start1,finish1 = list(map(float, str.split("\n")))

    str = test.read("f2", mode='r')
    start2,finish2 = list(map(float, str.split("\n")))

    test.fail_test(start2 < finish1)

    os.environ['PYTHONPATH'] = save_pythonpath


# Test SetJobs() with no -j:
test.write('SConstruct', """
DefaultEnvironment(tools=[])
MyBuild = Builder(action=r'%(_python_)s build.py $TARGETS')
env = Environment(BUILDERS={'MyBuild': MyBuild}, tools=[])
env.Tool('install')
env.MyBuild(target = 'f1', source = 'f1.in')
env.MyBuild(target = 'f2', source = 'f2.in')

def copyn(env, target, source):
    import shutil
    import time
    time.sleep(1)
    for t in target:
        shutil.copy(str(source[0]), str(t))

t = env.Command(target=['foo/foo1.out', 'foo/foo2.out'], source='foo/foo.in', action=copyn)
env.Install('out', t)

assert GetOption('num_jobs') == 1
SetOption('num_jobs', 2)
assert GetOption('num_jobs') == 2
""" % locals())

# This should be a parallel build because the SConscript sets jobs to 2.
# fail if the second file was not started
# before the first one was finished
start2, finish1 = RunTest('f1 f2', "third")
test.fail_test(not (start2 < finish1))

# Test SetJobs() with -j:
test.write('SConstruct', """
DefaultEnvironment(tools=[])
MyBuild = Builder(action = r'%(_python_)s build.py $TARGETS')
env = Environment(BUILDERS = {'MyBuild': MyBuild}, tools=[])
env.Tool('install')
env.MyBuild(target='f1', source='f1.in')
env.MyBuild(target='f2', source='f2.in')

def copyn(env, target, source):
    import shutil
    import time
    time.sleep(1)
    for t in target:
        shutil.copy(str(source[0]), str(t))

t = env.Command(target=['foo/foo1.out', 'foo/foo2.out'], source='foo/foo.in', action=copyn)
env.Install('out', t)

assert GetOption('num_jobs') == 1
SetOption('num_jobs', 2)
assert GetOption('num_jobs') == 1
""" % locals())

# This should be a serial build since -j 1 overrides the call to SetJobs().
# fail if the second file was started
# before the first one was finished
start2, finish1 = RunTest('-j 1 f1 f2', "fourth")
test.fail_test(start2 < finish1)



test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/option/option-k.py

#!/usr/bin/env python
#
# MIT License
#
# Copyright The SCons Foundation
#
# 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.


import TestSCons

_python_ = TestSCons._python_

test = TestSCons.TestSCons()

test.subdir('work1', 'work2', 'work3')

test.write('succeed.py', r"""
import sys

with open(sys.argv[1], 'w') as file:
    file.write("succeed.py: %s\n" % sys.argv[1])
sys.exit(0)
""")

test.write('fail.py', r"""
import sys

sys.exit(1)
""")


#
# Test: work1
# 

test.write(['work1', 'SConstruct'], """\
DefaultEnvironment(tools=[])
Succeed = Builder(action=r'%(_python_)s ../succeed.py $TARGETS')
Fail = Builder(action=r'%(_python_)s ../fail.py $TARGETS')
env = Environment(BUILDERS={'Succeed': Succeed, 'Fail': Fail}, tools=[])
env.Fail(target='aaa.1', source='aaa.in')
env.Succeed(target='aaa.out', source='aaa.1')
env.Succeed(target='bbb.out', source='bbb.in')
""" % locals())

test.write(['work1', 'aaa.in'], "aaa.in\n")
test.write(['work1', 'bbb.in'], "bbb.in\n")

test.run(
    chdir='work1',
    arguments='aaa.out bbb.out',
    stderr='scons: *** [aaa.1] Error 1\n',
    status=2,
)

test.must_not_exist(test.workpath('work1', 'aaa.1'))
test.must_not_exist(test.workpath('work1', 'aaa.out'))
test.must_not_exist(test.workpath('work1', 'bbb.out'))

test.run(
    chdir='work1',
    arguments='-k aaa.out bbb.out',
    stderr='scons: *** [aaa.1] Error 1\n',
    status=2,
)

test.must_not_exist(test.workpath('work1', 'aaa.1'))
test.must_not_exist(test.workpath('work1', 'aaa.out'))
test.must_match(['work1', 'bbb.out'], "succeed.py: bbb.out\n", mode='r')

test.unlink(['work1', 'bbb.out'])

test.run(
    chdir='work1',
    arguments='--keep-going aaa.out bbb.out',
    stderr='scons: *** [aaa.1] Error 1\n',
    status=2,
)

test.must_not_exist(test.workpath('work1', 'aaa.1'))
test.must_not_exist(test.workpath('work1', 'aaa.out'))
test.must_match(['work1', 'bbb.out'], "succeed.py: bbb.out\n", mode='r')

expect = """\
scons: Reading SConscript files ...
scons: done reading SConscript files.
scons: Cleaning targets ...
Removed bbb.out
scons: done cleaning targets.
"""

test.run(chdir='work1',
         arguments='--clean --keep-going aaa.out bbb.out',
         stdout=expect)

test.must_not_exist(test.workpath('work1', 'aaa.1'))
test.must_not_exist(test.workpath('work1', 'aaa.out'))
test.must_not_exist(test.workpath('work1', 'bbb.out'))



#
# Test: work2
# 

test.write(['work2', 'SConstruct'], """\
DefaultEnvironment(tools=[])
Succeed = Builder(action=r'%(_python_)s ../succeed.py $TARGETS')
Fail = Builder(action=r'%(_python_)s ../fail.py $TARGETS')
env = Environment(BUILDERS={'Succeed': Succeed, 'Fail': Fail}, tools=[])
env.Fail('aaa.out', 'aaa.in')
env.Succeed('bbb.out', 'aaa.out')
env.Succeed('ccc.out', 'ccc.in')
env.Succeed('ddd.out', 'ccc.in')
""" % locals())

test.write(['work2', 'aaa.in'], "aaa.in\n")
test.write(['work2', 'ccc.in'], "ccc.in\n")

test.run(
    chdir='work2',
    arguments='-k .',
    status=2,
    stderr=None,
    stdout="""\
scons: Reading SConscript files ...
scons: done reading SConscript files.
scons: Building targets ...
%(_python_)s ../fail.py aaa.out
%(_python_)s ../succeed.py ccc.out
%(_python_)s ../succeed.py ddd.out
scons: done building targets (errors occurred during build).
"""
    % locals(),
)

test.must_not_exist(['work2', 'aaa.out'])
test.must_not_exist(['work2', 'bbb.out'])
test.must_match(['work2', 'ccc.out'], "succeed.py: ccc.out\n", mode='r')
test.must_match(['work2', 'ddd.out'], "succeed.py: ddd.out\n", mode='r')



#
# Test: work3
#
# Check that the -k (keep-going) switch works correctly when the Nodes
# forms a DAG. The test case is the following
#
#               all
#                |
#          +-----+-----+-------------+
#          |           |             |
#         a1           a2           a3
#          |           |             |
#          +       +---+---+     +---+---+ 
#          \       |      /      |       |
#           \   bbb.out  /      a4    ccc.out
#            \          /       /        
#             \        /       /  
#              \      /       /  
#              aaa.out (fails)
#

test.write(['work3', 'SConstruct'], """\
DefaultEnvironment(tools=[])
Succeed = Builder(action=r'%(_python_)s ../succeed.py $TARGETS')
Fail = Builder(action=r'%(_python_)s ../fail.py $TARGETS')
env = Environment(BUILDERS={'Succeed': Succeed, 'Fail': Fail}, tools=[])
a = env.Fail('aaa.out', 'aaa.in')
b = env.Succeed('bbb.out', 'bbb.in')
c = env.Succeed('ccc.out', 'ccc.in')

a1 = Alias('a1', a)
a2 = Alias('a2', a + b)
a4 = Alias('a4', c)
a3 = Alias('a3', a4 + c)

Alias('all', a1 + a2 + a3)
""" % locals())

test.write(['work3', 'aaa.in'], "aaa.in\n")
test.write(['work3', 'bbb.in'], "bbb.in\n")
test.write(['work3', 'ccc.in'], "ccc.in\n")


# Test tegular build (i.e. without -k)
test.run(
    chdir='work3',
    arguments='.',
    status=2,
    stderr=None,
    stdout="""\
scons: Reading SConscript files ...
scons: done reading SConscript files.
scons: Building targets ...
%(_python_)s ../fail.py aaa.out
scons: building terminated because of errors.
"""
    % locals(),
)

test.must_not_exist(['work3', 'aaa.out'])
test.must_not_exist(['work3', 'bbb.out'])
test.must_not_exist(['work3', 'ccc.out'])

test.run(chdir='work3', arguments='-c .')
test.must_not_exist(['work3', 'aaa.out'])
test.must_not_exist(['work3', 'bbb.out'])
test.must_not_exist(['work3', 'ccc.out'])

# Current directory
test.run(
    chdir='work3',
    arguments='-k .',
    status=2,
    stderr=None,
    stdout="""\
scons: Reading SConscript files ...
scons: done reading SConscript files.
scons: Building targets ...
%(_python_)s ../fail.py aaa.out
%(_python_)s ../succeed.py bbb.out
%(_python_)s ../succeed.py ccc.out
scons: done building targets (errors occurred during build).
"""
    % locals(),
)

test.must_not_exist(['work3', 'aaa.out'])
test.must_exist(['work3', 'bbb.out'])
test.must_exist(['work3', 'ccc.out'])

test.run(chdir='work3', arguments='-c .')
test.must_not_exist(['work3', 'aaa.out'])
test.must_not_exist(['work3', 'bbb.out'])
test.must_not_exist(['work3', 'ccc.out'])


# Single target
test.run(
    chdir='work3',
    arguments='--keep-going all',
    status=2,
    stderr=None,
    stdout="""\
scons: Reading SConscript files ...
scons: done reading SConscript files.
scons: Building targets ...
%(_python_)s ../fail.py aaa.out
%(_python_)s ../succeed.py bbb.out
%(_python_)s ../succeed.py ccc.out
scons: done building targets (errors occurred during build).
"""
    % locals(),
)

test.must_not_exist(['work3', 'aaa.out'])
test.must_exist(['work3', 'bbb.out'])
test.must_exist(['work3', 'ccc.out'])

test.run(chdir='work3', arguments='-c .')
test.must_not_exist(['work3', 'aaa.out'])
test.must_not_exist(['work3', 'bbb.out'])
test.must_not_exist(['work3', 'ccc.out'])

# Separate top-level targets
test.run(
    chdir='work3',
    arguments='-k a1 a2 a3',
    status=2,
    stderr=None,
    stdout="""\
scons: Reading SConscript files ...
scons: done reading SConscript files.
scons: Building targets ...
%(_python_)s ../fail.py aaa.out
%(_python_)s ../succeed.py bbb.out
%(_python_)s ../succeed.py ccc.out
scons: done building targets (errors occurred during build).
"""
    % locals(),
)

test.must_not_exist(['work3', 'aaa.out'])
test.must_exist(['work3', 'bbb.out'])
test.must_exist(['work3', 'ccc.out'])

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/option/option-l.py

#!/usr/bin/env python
#
# __COPYRIGHT__
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#

__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"

import TestSCons

test = TestSCons.TestSCons()

test.write('SConstruct', "")

test.option_not_yet_implemented('-l', '1 .')

test.option_not_yet_implemented('--load-average', '=1 .')

test.option_not_yet_implemented('--max-load', '=1 .')

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/option/option-m.py

#!/usr/bin/env python
#
# __COPYRIGHT__
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#

__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"

import TestSCons

test = TestSCons.TestSCons()

test.write('SConstruct', "")

test.run(arguments = '-m .',
         stderr = "Warning:  ignoring -m option\n")

test.pass_test()
 

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/option/option-n.py

#!/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.
#

"""
This test verifies:
    1)  that we don't build files when we use the -n, --no-exec,
        --just-print, --dry-run, and --recon options;
    2)  that we don't remove built files when -n is used in
        conjunction with -c;
    3)  that files installed by the Install() method don't get
        installed when -n is used;
    4)  that source files don't get duplicated in a VariantDir
        when -n is used.
    5)  that Configure calls don't build any files. If a file
        needs to be built (i.e. is not up-to-date), a ConfigureError
        is raised.
"""

__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"

import os
import re

import TestSCons
from SCons.Util import get_current_hash_algorithm_used

_python_ = TestSCons._python_

test = TestSCons.TestSCons()

test.subdir('build', 'src')

test.write('build.py', r"""
import sys
with open(sys.argv[1], 'w') as ofp:
    ofp.write("build.py: %s\n" % sys.argv[1])
""")

test.write('SConstruct', """
DefaultEnvironment(tools=[])
MyBuild = Builder(action=r'%(_python_)s build.py $TARGETS')
env = Environment(BUILDERS={'MyBuild': MyBuild}, tools=[])
env.Tool('install')
env.MyBuild(target='f1.out', source='f1.in')
env.MyBuild(target='f2.out', source='f2.in')
env.Install('install', 'f3.in')
VariantDir('build', 'src', duplicate=1)
SConscript('build/SConscript', "env")
""" % locals())

test.write(['src', 'SConscript'], """
Import("env")
env.MyBuild(target='f4.out', source='f4.in')
""")

test.write('f1.in', "f1.in\n")
test.write('f2.in', "f2.in\n")
test.write('f3.in', "f3.in\n")
test.write(['src', 'f4.in'], "src/f4.in\n")

args = 'f1.out f2.out'
expect = test.wrap_stdout("""\
%(_python_)s build.py f1.out
%(_python_)s build.py f2.out
""" % locals())

test.run(arguments=args, stdout=expect)
test.fail_test(not os.path.exists(test.workpath('f1.out')))
test.fail_test(not os.path.exists(test.workpath('f2.out')))

test.unlink('f1.out')
test.unlink('f2.out')

test.run(arguments='-n ' + args, stdout=expect)
test.fail_test(os.path.exists(test.workpath('f1.out')))
test.fail_test(os.path.exists(test.workpath('f2.out')))

test.run(arguments='--no-exec ' + args, stdout=expect)
test.fail_test(os.path.exists(test.workpath('f1.out')))
test.fail_test(os.path.exists(test.workpath('f2.out')))

test.run(arguments='--just-print ' + args, stdout=expect)
test.fail_test(os.path.exists(test.workpath('f1.out')))
test.fail_test(os.path.exists(test.workpath('f2.out')))

test.run(arguments='--dry-run ' + args, stdout=expect)
test.fail_test(os.path.exists(test.workpath('f1.out')))
test.fail_test(os.path.exists(test.workpath('f2.out')))

test.run(arguments='--recon ' + args, stdout=expect)
test.fail_test(os.path.exists(test.workpath('f1.out')))
test.fail_test(os.path.exists(test.workpath('f2.out')))

test.run(arguments=args)
test.fail_test(not os.path.exists(test.workpath('f1.out')))

# Test that SCons does not write a modified .sconsign when -n is used.
expect = test.wrap_stdout("""\
%(_python_)s build.py f1.out
""" % locals())
test.unlink(test.get_sconsignname()+'.dblite')
test.write('f1.out', "X1.out\n")
test.run(arguments='-n f1.out', stdout=expect)
test.run(arguments='-n f1.out', stdout=expect)

expect = test.wrap_stdout("Removed f1.out\nRemoved f2.out\n", cleaning=1)

test.run(arguments='-n -c ' + args, stdout=expect)

test.run(arguments='-c -n ' + args, stdout=expect)

test.fail_test(not os.path.exists(test.workpath('f1.out')))
test.fail_test(not os.path.exists(test.workpath('f2.out')))

#
install_f3_in = os.path.join('install', 'f3.in')
expect = test.wrap_stdout('Install file: "f3.in" as "%s"\n' % install_f3_in)

test.run(arguments='-n install', stdout=expect)
test.fail_test(os.path.exists(test.workpath('install', 'f3.in')))

test.run(arguments='install', stdout=expect)
test.fail_test(not os.path.exists(test.workpath('install', 'f3.in')))

test.write('f3.in', "f3.in again\n")

test.run(arguments='-n install', stdout=expect)
test.fail_test(not os.path.exists(test.workpath('install', 'f3.in')))

# Make sure duplicate source files in a VariantDir aren't created
# when the -n option is used.

# First, make sure none of the previous non-dryrun invocations caused
# the build directory to be populated.  Processing of the
# src/SConscript (actually build/SConscript) will reference f4.in as a
# source, causing a Node object to be built for "build/f4.in".
# Creating the node won't cause "build/f4.in" to be created from
# "src/f4.in", but that *is* a side-effect of calling the exists()
# method on that node, which may happen via other processing.
# Therefore add this conditional removal to ensure  a clean setting
# before running this test.

if os.path.exists(test.workpath('build', 'f4.in')):
    test.unlink(test.workpath('build', 'f4.in'))

test.run(arguments='-n build')
test.fail_test(os.path.exists(test.workpath('build', 'f4.in')))

# test Configure-calls in conjunction with -n
test.subdir('configure')
test.set_match_function(TestSCons.match_re_dotall)
test.set_diff_function(TestSCons.diff_re)
test.write('configure/SConstruct', """\
DefaultEnvironment(tools=[])
def CustomTest(context):
    def userAction(target,source,env):
        import shutil
        shutil.copyfile( str(source[0]), str(target[0]))
    def strAction(target,source,env):
        return "cp " + str(source[0]) + " " + str(target[0])
    context.Message("Executing Custom Test ... " )
    (ok, msg) = context.TryAction(Action(userAction,strAction),
                                  "Hello World", ".in")
    context.Result(ok)
    return ok

env = Environment(tools=[])
conf = Configure(env,
                 custom_tests={'CustomTest':CustomTest},
                 conf_dir="config.test",
                 log_file="config.log")
if not conf.CustomTest():
    Exit(1)
else:
    env = conf.Finish()
""")
# test that conf_dir isn't created and an error is raised
stderr = r"""
scons: \*\*\* Cannot create configure directory "config\.test" within a dry-run\.
File \S+, line \S+, in \S+
"""
test.run(arguments="-n", stderr=stderr, status=2,
         chdir=test.workpath("configure"))
test.fail_test(os.path.exists(test.workpath("configure", "config.test")))
test.fail_test(os.path.exists(test.workpath("configure", "config.log")))


# depending on which default hash function we're using, we'd expect one of the following filenames.
# The filenames are generated by the conftest changes in #3543 : https://github.com/SCons/scons/pull/3543/files
possible_filenames = {
    'md5': "conftest_b10a8db164e0754105b7a99be72e3fe5_0.in",
    'sha1': "conftest_0a4d55a8d778e5022fab701977c5d840bbc486d0_0.in",
    'sha256': "conftest_a591a6d40bf420404a011733cfb7b190d62c65bf0bcda32b57b277d9ad9f146e_0.in"
}
test_filename = possible_filenames[get_current_hash_algorithm_used()]

# test that targets are not built, if conf_dir exists.
# verify that .cache and config.log are not created.
# an error should be raised
stderr = r"""
scons: \*\*\* Cannot update configure test "%s" within a dry-run\.
File \S+, line \S+, in \S+
""" % re.escape(os.path.join("config.test", test_filename))
test.subdir(['configure', 'config.test'])
test.run(arguments="-n", stderr=stderr, status=2,
         chdir=test.workpath("configure"))
test.fail_test(os.path.exists(test.workpath("configure", "config.test",
                                            ".cache")))
test.fail_test(os.path.exists(test.workpath("configure", "config.test",
                                            "conftest_0")))
test.fail_test(os.path.exists(test.workpath("configure", "config.test",
                                            "conftest_0.in")))
test.fail_test(os.path.exists(test.workpath("configure", "config.log")))

# test that no error is raised, if all targets are up-to-date. In this
# case .cache and config.log shouldn't be created
stdout = test.wrap_stdout(build_str="scons: `.' is up to date.\n",
                          read_str=r"""Executing Custom Test ... \(cached\) yes
""")
test.run(status=0, chdir=test.workpath("configure"))
log1_mtime = os.path.getmtime(test.workpath("configure", "config.log"))
test.run(stdout=stdout, arguments="-n", status=0,
         chdir=test.workpath("configure"))
log2_mtime = os.path.getmtime(test.workpath("configure", "config.log"))
test.fail_test(log1_mtime != log2_mtime)

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/option/option-o.py

#!/usr/bin/env python
#
# __COPYRIGHT__
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#

__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"

import TestSCons

test = TestSCons.TestSCons()

test.write('SConstruct', "")

test.option_not_yet_implemented('-o', 'foo .')

test.option_not_yet_implemented('--old-file', '=foo .')

test.option_not_yet_implemented('--assume-old', '=foo .')

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/option/option-p.py

#!/usr/bin/env python
#
# __COPYRIGHT__
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#

__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"

import TestSCons

test = TestSCons.TestSCons()

test.write('SConstruct', "")

test.option_not_yet_implemented('-p', '.')

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/option/option-r.py

#!/usr/bin/env python
#
# __COPYRIGHT__
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#

__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"

import TestSCons

test = TestSCons.TestSCons()

test.write('SConstruct', "")

test.option_not_yet_implemented('-r', '.')

test.option_not_yet_implemented('--no-builtin-rules', '.')

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/option/option-s.py

#!/usr/bin/env python
#
# MIT License
#
# Copyright The SCons Foundation
#
# 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.

import os.path

import TestSCons

_python_ = TestSCons._python_

test = TestSCons.TestSCons()

test.write('build.py', r"""
import sys

with open(sys.argv[1], 'w') as file:
    file.write("build.py: %s\n" % sys.argv[1])
sys.exit(0)
""")

test.write('SConstruct', """
DefaultEnvironment(tools=[])
MyBuild = Builder(action=r'%(_python_)s build.py $TARGET')

silent = ARGUMENTS.get('QUIET', 0)
if silent:
    SetOption('silent', True)

env = Environment(BUILDERS={'MyBuild': MyBuild}, tools=[])
env.MyBuild(target='f1.out', source='f1.in')
env.MyBuild(target='f2.out', source='f2.in')
""" % locals())

test.write('f1.in', "f1.in\n")
test.write('f2.in', "f2.in\n")

test.run(arguments='-s f1.out f2.out', stdout="")
test.fail_test(not os.path.exists(test.workpath('f1.out')))
test.fail_test(not os.path.exists(test.workpath('f2.out')))

test.unlink('f1.out')
test.unlink('f2.out')

test.run(arguments='--silent f1.out f2.out', stdout="")
test.fail_test(not os.path.exists(test.workpath('f1.out')))
test.fail_test(not os.path.exists(test.workpath('f2.out')))

test.unlink('f1.out')
test.unlink('f2.out')

test.run(arguments='--quiet f1.out f2.out', stdout="")
test.fail_test(not os.path.exists(test.workpath('f1.out')))
test.fail_test(not os.path.exists(test.workpath('f2.out')))

# -C should also be quiet Issue#2796
test.subdir( 'sub' )
test.write(['sub','SConstruct'],"")
test.run(arguments='-s -C sub', stdout="" )

test.unlink('f1.out')
test.unlink('f2.out')

test.run(arguments='QUIET=1 f1.out f2.out',
         stdout="scons: Reading SConscript files ...\nscons: done reading SConscript files.\n")
test.fail_test(not os.path.exists(test.workpath('f1.out')))
test.fail_test(not os.path.exists(test.workpath('f2.out')))

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/option/option-t.py

#!/usr/bin/env python
#
# __COPYRIGHT__
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#

__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"

import TestSCons

test = TestSCons.TestSCons()

test.write('SConstruct', "")

test.run(arguments = '-t .',
         stderr = "Warning:  ignoring -t option\n")

test.run(arguments = '--touch .',
         stderr = "Warning:  ignoring --touch option\n")

test.pass_test()
 

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/option/option-unknown.py

#!/usr/bin/env python
#
# MIT License
#
# Copyright The SCons Foundation
#
# 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.

import TestSCons

test = TestSCons.TestSCons()

test.write('SConstruct', "")

test.run(arguments = '-Z',
         stderr = """usage: scons [OPTIONS] [VARIABLES] [TARGETS]

SCons Error: no such option: -Z
""",
         status = 2)

test.run(arguments = '--ZizzerZazzerZuzz',
         stderr = """usage: scons [OPTIONS] [VARIABLES] [TARGETS]

SCons Error: no such option: --ZizzerZazzerZuzz
""",
         status = 2)

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/option/option-v.py

#!/usr/bin/env python
#
# __COPYRIGHT__
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"

import TestCmd
import TestSCons

test = TestSCons.TestSCons(match = TestCmd.match_re)

test.write('SConstruct', "")

# Standard copyright marker is mangled so it doesn't get replaced
# by the packaging build.
copyright_line = """\
(_{2}COPYRIGHT__|Copyright \\(c\\) 2001[-\\d, ]+ The SCons Foundation)
"""


expect2 = r"""SCons by Steven Knight et al.:
\tSCons: v\S+, [^,]*,[^,]*, by \S+ on \S+
\tSCons path: \[.*\]
""" + copyright_line

test.run(arguments = '-v')
stdout = test.stdout()
if not test.match_re(stdout, expect2):
    print(stdout)
    test.fail_test()

test.run(arguments = '--version')
stdout = test.stdout()
if not test.match_re(stdout, expect2):
    print(stdout)
    test.fail_test()

test.pass_test()


# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/option/option_profile.py

#!/usr/bin/env python
#
# MIT License
#
# Copyright The SCons Foundation
#
# 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.

import contextlib
import sys
from io import StringIO

import TestSCons

test = TestSCons.TestSCons()

try:
    import pstats
except ImportError:
    test.skip_test('No pstats module, skipping test.\n')

test.write('SConstruct', """\
DefaultEnvironment(tools=[])
Command('file.out', 'file.in', Copy("$TARGET", "$SOURCE"))
""")

test.write('file.in', "file.in\n")

scons_prof = test.workpath('scons.prof')

test.run(arguments = "--profile=%s -h" % scons_prof)
test.must_contain_all_lines(test.stdout(), ['usage: scons [OPTIONS] [VARIABLES] [TARGETS]'])

try:
    save_stdout = sys.stdout
    with contextlib.closing(StringIO()) as sys.stdout:
        stats = pstats.Stats(scons_prof)
        stats.sort_stats('time')

        stats.strip_dirs().print_stats()

        s = sys.stdout.getvalue()
finally:
    sys.stdout = save_stdout

test.must_contain_all_lines(s, ['Main.py', '_main'])



scons_prof = test.workpath('scons2.prof')

test.run(arguments = "--profile %s" % scons_prof)

try:
    save_stdout = sys.stdout
    with contextlib.closing(StringIO()) as sys.stdout:
        stats = pstats.Stats(scons_prof)
        stats.sort_stats('time')

        stats.strip_dirs().print_stats()

        s = sys.stdout.getvalue()
finally:
    sys.stdout = save_stdout

test.must_contain_all_lines(s, ['Main.py', '_main', 'FS.py'])



scons_prof = test.workpath('scons3.prof')

test.run(arguments = "--profile %s --debug=memory -h" % scons_prof)
expect = [
    'usage: scons [OPTIONS] [VARIABLES] [TARGETS]',
    'Options:'
]
test.must_contain_all_lines(test.stdout(), expect)

expect = 'Memory before reading SConscript files'
lines = test.stdout().split('\n')
memory_lines = [l for l in lines if l.find(expect) != -1]

test.fail_test(len(memory_lines) != 1)



test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/option/print-directory.py

#!/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 -w and --print-directory options are ignored.
"""

import TestSCons

test = TestSCons.TestSCons()

test.write('SConstruct', "DefaultEnvironment(tools=[])\n")

test.run(arguments = '-w .',
         stderr = "Warning:  ignoring -w option\n")

test.run(arguments = '--print-directory .',
         stderr = "Warning:  ignoring --print-directory option\n")

test.pass_test()
 

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/option/repository.py

#!/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 --srcdir option works to fetch things from a repository.
"""

import TestSCons

test = TestSCons.TestSCons()

test.subdir('repository', 'work1')

repository = test.workpath('repository')

test.write(['repository', 'SConstruct'], """\
DefaultEnvironment(tools=[])
env = Environment(tools=[])
env.Command('file.out', 'file.in', Copy('$TARGET', '$SOURCE'))
""")

test.write(['repository', 'file.in'], "repository/file.in\n")

opts = '--repository ' + repository

# Make the entire repository non-writable, so we'll detect
# if we try to write into it accidentally.
test.writable('repository', 0)

test.run(chdir = 'work1', options = opts, arguments = '.')

test.must_match(['work1', 'file.out'], "repository/file.in\n")

test.up_to_date(chdir = 'work1', options = opts, arguments = '.')



#
test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/option/srcdir.py

#!/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 --srcdir option works to fetch things from a repository.
"""

import TestSCons

test = TestSCons.TestSCons()

test.subdir('repository', 'work1')

repository = test.workpath('repository')

test.write(['repository', 'SConstruct'], r"""
DefaultEnvironment(tools=[])
env = Environment(tools=[])
env.Command('file.out', 'file.in', Copy('$TARGET', '$SOURCE'))
""")

test.write(['repository', 'file.in'], "repository/file.in\n")

opts = '--srcdir ' + repository

# Make the entire repository non-writable, so we'll detect
# if we try to write into it accidentally.
test.writable('repository', 0)

test.run(chdir = 'work1', options = opts, arguments = '.')

test.must_match(['work1', 'file.out'], "repository/file.in\n")

test.up_to_date(chdir = 'work1', options = opts, arguments = '.')



#
test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/option/stack-size.py

#!/usr/bin/env python
#
# __COPYRIGHT__
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#

__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"

import TestSCons

_python_ = TestSCons._python_

test = TestSCons.TestSCons()

isStackSizeAvailable = False
try:
    import threading
    isStackSizeAvailable = hasattr(threading,'stack_size')
except ImportError:
    pass

test.subdir('work1', 'work2')

test.write('build.py', r"""
import sys
with open(sys.argv[1], 'wb') as f, open(sys.argv[2], 'rb') as infp:
    f.write(infp.read())
""")


test.write(['work1', 'SConstruct'], """
DefaultEnvironment(tools=[])
B = Builder(action = r'%(_python_)s ../build.py $TARGETS $SOURCES')
env = Environment(tools=[], BUILDERS = { 'B' : B })
f1 = env.B(target = 'f1.out', source = 'f1.in')
f2 = env.B(target = 'f2.out', source = 'f2.in')
Requires(f2, f1)
""" % locals())

test.write(['work1', 'f1.in'], "f1.in\n")
test.write(['work1', 'f2.in'], "f2.in\n")


test.write(['work2', 'SConstruct'], """
SetOption('stack_size', 128)
B = Builder(action = r'%(_python_)s ../build.py $TARGETS $SOURCES')
env = Environment(BUILDERS = { 'B' : B })
f1 = env.B(target = 'f1.out', source = 'f1.in')
f2 = env.B(target = 'f2.out', source = 'f2.in')
Requires(f2, f1)
""" % locals())

test.write(['work2', 'f1.in'], "f1.in\n")
test.write(['work2', 'f2.in'], "f2.in\n")



expected_stdout = test.wrap_stdout("""\
%(_python_)s ../build.py f1.out f1.in
%(_python_)s ../build.py f2.out f2.in
""" % locals())

re_expected_stdout = expected_stdout.replace('\\', '\\\\')

expect_unsupported = """
scons: warning: Setting stack size is unsupported by this version of Python:
    (('module' object|'threading' module) has no attribute 'stack_size'|stack_size)
File .*
"""


#
# Test without any options
#
test.run(chdir='work1', 
         arguments = '.',
         stdout=expected_stdout,
         stderr='')
test.must_exist(['work1', 'f1.out'])
test.must_exist(['work1', 'f2.out'])

test.run(chdir='work1', 
         arguments = '-c .')
test.must_not_exist(['work1', 'f1.out'])
test.must_not_exist(['work1', 'f2.out'])

#
# Test with -j2
#
test.run(chdir='work1', 
         arguments = '-j2 .',
         stdout=expected_stdout,
         stderr='')
test.must_exist(['work1', 'f1.out'])
test.must_exist(['work1', 'f2.out'])

test.run(chdir='work1', 
         arguments = '-j2 -c .')
test.must_not_exist(['work1', 'f1.out'])
test.must_not_exist(['work1', 'f2.out'])


#
# Test with --stack-size
#
test.run(chdir='work1', 
         arguments = '--stack-size=128 .',
         stdout=expected_stdout,
         stderr='')
test.must_exist(['work1', 'f1.out'])
test.must_exist(['work1', 'f2.out'])

test.run(chdir='work1', 
         arguments = '--stack-size=128 -c .')
test.must_not_exist(['work1', 'f1.out'])
test.must_not_exist(['work1', 'f2.out'])

#
# Test with SetOption('stack_size', 128)
#
test.run(chdir='work2', 
         arguments = '.',
         stdout=expected_stdout,
         stderr='')
test.must_exist(['work2', 'f1.out'])
test.must_exist(['work2', 'f2.out'])

test.run(chdir='work2', 
         arguments = '--stack-size=128 -c .')
test.must_not_exist(['work2', 'f1.out'])
test.must_not_exist(['work2', 'f2.out'])

if isStackSizeAvailable:
    #
    # Test with -j2 --stack-size=128
    #
    test.run(chdir='work1', 
             arguments = '-j2 --stack-size=128 .',
             stdout=expected_stdout,
             stderr='')
    test.must_exist(['work1', 'f1.out'])
    test.must_exist(['work1', 'f2.out'])

    test.run(chdir='work1', 
             arguments = '-j2 --stack-size=128 -c .')
    test.must_not_exist(['work1', 'f1.out'])
    test.must_not_exist(['work1', 'f2.out'])

    #
    # Test with -j2 --stack-size=16
    #
    test.run(chdir='work1', 
             arguments = '-j2 --stack-size=16 .',
             match=TestSCons.match_re,
             stdout=re_expected_stdout,
             stderr="""
scons: warning: Setting stack size failed:
    size not valid: 16384 bytes
File .*
""")
    test.must_exist(['work1', 'f1.out'])
    test.must_exist(['work1', 'f2.out'])

    test.run(chdir='work1', 
             arguments = '-j2 --stack-size=16 -c .',
             match=TestSCons.match_re,
             stderr="""
scons: warning: Setting stack size failed:
    size not valid: 16384 bytes
File .*
""")
    test.must_not_exist(['work1', 'f1.out'])
    test.must_not_exist(['work1', 'f2.out'])

    #
    # Test with -j2 SetOption('stack_size', 128)
    #
    test.run(chdir='work2', 
             arguments = '-j2 .',
             stdout=expected_stdout,
             stderr='')
    test.must_exist(['work2', 'f1.out'])
    test.must_exist(['work2', 'f2.out'])

    test.run(chdir='work2', 
             arguments = '-j2  -c .')
    test.must_not_exist(['work2', 'f1.out'])
    test.must_not_exist(['work2', 'f2.out'])

    #
    # Test with -j2 --stack-size=128 --warn=no-stack-size
    #
    test.run(chdir='work1', 
             arguments = '-j2 --stack-size=128 --warn=no-stack-size .',
             stdout=expected_stdout,
             stderr='')
    test.must_exist(['work1', 'f1.out'])
    test.must_exist(['work1', 'f2.out'])

    test.run(chdir='work1', 
             arguments = '-j2 --stack-size=128  --warn=no-stack-size -c .')
    test.must_not_exist(['work1', 'f1.out'])
    test.must_not_exist(['work1', 'f2.out'])

    #
    # Test with -j2 --stack-size=16 --warn=no-stack-size
    #
    test.run(chdir='work1', 
             arguments = '-j2 --stack-size=16 --warn=no-stack-size .',
             stdout=expected_stdout,
             stderr='')
    test.must_exist(['work1', 'f1.out'])
    test.must_exist(['work1', 'f2.out'])

    test.run(chdir='work1', 
             arguments = '-j2 --stack-size=16 --warn=no-stack-size -c .')
    test.must_not_exist(['work1', 'f1.out'])
    test.must_not_exist(['work1', 'f2.out'])

    #
    # Test with -j2  --warn=no-stack-size SetOption('stack_size', 128) 
    #
    test.run(chdir='work2', 
             arguments = '-j2  --warn=no-stack-size .',
             stdout=expected_stdout,
             stderr='')
    test.must_exist(['work2', 'f1.out'])
    test.must_exist(['work2', 'f2.out'])

    test.run(chdir='work2', 
             arguments = '-j2   --warn=no-stack-size -c .')
    test.must_not_exist(['work2', 'f1.out'])
    test.must_not_exist(['work2', 'f2.out'])

else:

    #
    # Test with -j2 --stack-size=128
    #
    test.run(chdir='work1', 
             arguments = '-j2 --stack-size=128 .',
             match=TestSCons.match_re,
             stdout=re_expected_stdout,
             stderr=expect_unsupported)
    test.must_exist(['work1', 'f1.out'])
    test.must_exist(['work1', 'f2.out'])

    test.run(chdir='work1', 
             arguments = '-j2 --stack-size=128 -c .',
             match=TestSCons.match_re,
             stderr=expect_unsupported)
    test.must_not_exist(['work1', 'f1.out'])
    test.must_not_exist(['work1', 'f2.out'])

    #
    # Test with -j2 --stack-size=16
    #
    test.run(chdir='work1', 
             arguments = '-j2 --stack-size=16 .',
             match=TestSCons.match_re,
             stdout=re_expected_stdout,
             stderr=expect_unsupported)
    test.must_exist(['work1', 'f1.out'])
    test.must_exist(['work1', 'f2.out'])

    test.run(chdir='work1', 
             arguments = '-j2 --stack-size=16 -c .',
             match=TestSCons.match_re,
             stderr=expect_unsupported)
    test.must_not_exist(['work1', 'f1.out'])
    test.must_not_exist(['work1', 'f2.out'])

    #
    # Test with -j2 SetOption('stack_size', 128)
    #
    test.run(chdir='work2', 
             arguments = '-j2 .',
             match=TestSCons.match_re,
             stdout=re_expected_stdout,
             stderr=expect_unsupported)
    test.must_exist(['work2', 'f1.out'])
    test.must_exist(['work2', 'f2.out'])

    test.run(chdir='work2', 
             arguments = '-j2  -c .',
             match=TestSCons.match_re,
             stderr=expect_unsupported)
    test.must_not_exist(['work2', 'f1.out'])
    test.must_not_exist(['work2', 'f2.out'])

    #
    # Test with -j2 --stack-size=128 --warn=no-stack-size
    #
    test.run(chdir='work1', 
             arguments = '-j2 --stack-size=128 --warn=no-stack-size .',
             stdout=expected_stdout,
             stderr='')
    test.must_exist(['work1', 'f1.out'])
    test.must_exist(['work1', 'f2.out'])

    test.run(chdir='work1', 
             arguments = '-j2 --stack-size=128  --warn=no-stack-size -c .')
    test.must_not_exist(['work1', 'f1.out'])
    test.must_not_exist(['work1', 'f2.out'])

    #
    # Test with -j2 --stack-size=16 --warn=no-stack-size
    #
    test.run(chdir='work1', 
             arguments = '-j2 --stack-size=16 --warn=no-stack-size .',
             stdout=expected_stdout,
             stderr='')
    test.must_exist(['work1', 'f1.out'])
    test.must_exist(['work1', 'f2.out'])

    test.run(chdir='work1', 
             arguments = '-j2 --stack-size=16 --warn=no-stack-size -c .')
    test.must_not_exist(['work1', 'f1.out'])
    test.must_not_exist(['work1', 'f2.out'])

    #
    # Test with -j2  --warn=no-stack-size SetOption('stack_size', 128) 
    #
    test.run(chdir='work2', 
             arguments = '-j2  --warn=no-stack-size .',
             stdout=expected_stdout,
             stderr='')
    test.must_exist(['work2', 'f1.out'])
    test.must_exist(['work2', 'f2.out'])

    test.run(chdir='work2', 
             arguments = '-j2   --warn=no-stack-size -c .')
    test.must_not_exist(['work2', 'f1.out'])
    test.must_not_exist(['work2', 'f2.out'])

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/option/taskmastertrace.py

#!/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__"

"""
Simple tests of the --taskmastertrace= option.
"""

import TestSCons

test = TestSCons.TestSCons()

test.write('SConstruct', """
DefaultEnvironment(tools=[])
env = Environment(tools=[])

# We name the files 'Tfile' so that they will sort after the SConstruct
# file regardless of whether the test is being run on a case-sensitive
# or case-insensitive system.

env.Command('Tfile.out', 'Tfile.mid', Copy('$TARGET', '$SOURCE'))
env.Command('Tfile.mid', 'Tfile.in', Copy('$TARGET', '$SOURCE'))
""")

test.write('Tfile.in', "Tfile.in\n")

expect_stdout = test.wrap_stdout("""\

Taskmaster: Looking for a node to evaluate
Taskmaster:     Considering node <no_state   0   '.'> and its children:
Taskmaster:        <no_state   0   'SConstruct'>
Taskmaster:        <no_state   0   'Tfile.in'>
Taskmaster:        <no_state   0   'Tfile.mid'>
Taskmaster:        <no_state   0   'Tfile.out'>
Taskmaster:      adjusted ref count: <pending    1   '.'>, child 'SConstruct'
Taskmaster:      adjusted ref count: <pending    2   '.'>, child 'Tfile.in'
Taskmaster:      adjusted ref count: <pending    3   '.'>, child 'Tfile.mid'
Taskmaster:      adjusted ref count: <pending    4   '.'>, child 'Tfile.out'
Taskmaster:     Considering node <no_state   0   'SConstruct'> and its children:
Taskmaster: Evaluating <pending    0   'SConstruct'>

Task.make_ready_current(): node <pending    0   'SConstruct'>
Task.prepare():      node <up_to_date 0   'SConstruct'>
Task.executed_with_callbacks(): node <up_to_date 0   'SConstruct'>
Task.postprocess():  node <up_to_date 0   'SConstruct'>
Task.postprocess():  removing <up_to_date 0   'SConstruct'>
Task.postprocess():  adjusted parent ref count <pending    3   '.'>

Taskmaster: Looking for a node to evaluate
Taskmaster:     Considering node <no_state   0   'Tfile.in'> and its children:
Taskmaster: Evaluating <pending    0   'Tfile.in'>

Task.make_ready_current(): node <pending    0   'Tfile.in'>
Task.prepare():      node <up_to_date 0   'Tfile.in'>
Task.executed_with_callbacks(): node <up_to_date 0   'Tfile.in'>
Task.postprocess():  node <up_to_date 0   'Tfile.in'>
Task.postprocess():  removing <up_to_date 0   'Tfile.in'>
Task.postprocess():  adjusted parent ref count <pending    2   '.'>

Taskmaster: Looking for a node to evaluate
Taskmaster:     Considering node <no_state   0   'Tfile.mid'> and its children:
Taskmaster:        <up_to_date 0   'Tfile.in'>
Taskmaster: Evaluating <pending    0   'Tfile.mid'>

Task.make_ready_current(): node <pending    0   'Tfile.mid'>
Task.prepare():      node <executing  0   'Tfile.mid'>
Task.execute():      node <executing  0   'Tfile.mid'>
Copy("Tfile.mid", "Tfile.in")
Task.executed_with_callbacks(): node <executing  0   'Tfile.mid'>
Task.postprocess():  node <executed   0   'Tfile.mid'>
Task.postprocess():  removing <executed   0   'Tfile.mid'>
Task.postprocess():  adjusted parent ref count <pending    1   '.'>

Taskmaster: Looking for a node to evaluate
Taskmaster:     Considering node <no_state   0   'Tfile.out'> and its children:
Taskmaster:        <executed   0   'Tfile.mid'>
Taskmaster: Evaluating <pending    0   'Tfile.out'>

Task.make_ready_current(): node <pending    0   'Tfile.out'>
Task.prepare():      node <executing  0   'Tfile.out'>
Task.execute():      node <executing  0   'Tfile.out'>
Copy("Tfile.out", "Tfile.mid")
Task.executed_with_callbacks(): node <executing  0   'Tfile.out'>
Task.postprocess():  node <executed   0   'Tfile.out'>
Task.postprocess():  removing <executed   0   'Tfile.out'>
Task.postprocess():  adjusted parent ref count <pending    0   '.'>

Taskmaster: Looking for a node to evaluate
Taskmaster:     Considering node <pending    0   '.'> and its children:
Taskmaster:        <up_to_date 0   'SConstruct'>
Taskmaster:        <up_to_date 0   'Tfile.in'>
Taskmaster:        <executed   0   'Tfile.mid'>
Taskmaster:        <executed   0   'Tfile.out'>
Taskmaster: Evaluating <pending    0   '.'>

Task.make_ready_current(): node <pending    0   '.'>
Task.prepare():      node <executing  0   '.'>
Task.execute():      node <executing  0   '.'>
Task.executed_with_callbacks(): node <executing  0   '.'>
Task.postprocess():  node <executed   0   '.'>

Taskmaster: Looking for a node to evaluate
Taskmaster: No candidate anymore.

""")

test.run(arguments='--taskmastertrace=- .', stdout=expect_stdout)

test.run(arguments='-c .')

expect_stdout = test.wrap_stdout("""\
Copy("Tfile.mid", "Tfile.in")
Copy("Tfile.out", "Tfile.mid")
""")

test.run(arguments='--taskmastertrace=trace.out .', stdout=expect_stdout)

expect_trace = """\

Taskmaster: Looking for a node to evaluate
Taskmaster:     Considering node <no_state   0   '.'> and its children:
Taskmaster:        <no_state   0   'SConstruct'>
Taskmaster:        <no_state   0   'Tfile.in'>
Taskmaster:        <no_state   0   'Tfile.mid'>
Taskmaster:        <no_state   0   'Tfile.out'>
Taskmaster:      adjusted ref count: <pending    1   '.'>, child 'SConstruct'
Taskmaster:      adjusted ref count: <pending    2   '.'>, child 'Tfile.in'
Taskmaster:      adjusted ref count: <pending    3   '.'>, child 'Tfile.mid'
Taskmaster:      adjusted ref count: <pending    4   '.'>, child 'Tfile.out'
Taskmaster:     Considering node <no_state   0   'SConstruct'> and its children:
Taskmaster: Evaluating <pending    0   'SConstruct'>

Task.make_ready_current(): node <pending    0   'SConstruct'>
Task.prepare():      node <up_to_date 0   'SConstruct'>
Task.executed_with_callbacks(): node <up_to_date 0   'SConstruct'>
Task.postprocess():  node <up_to_date 0   'SConstruct'>
Task.postprocess():  removing <up_to_date 0   'SConstruct'>
Task.postprocess():  adjusted parent ref count <pending    3   '.'>

Taskmaster: Looking for a node to evaluate
Taskmaster:     Considering node <no_state   0   'Tfile.in'> and its children:
Taskmaster: Evaluating <pending    0   'Tfile.in'>

Task.make_ready_current(): node <pending    0   'Tfile.in'>
Task.prepare():      node <up_to_date 0   'Tfile.in'>
Task.executed_with_callbacks(): node <up_to_date 0   'Tfile.in'>
Task.postprocess():  node <up_to_date 0   'Tfile.in'>
Task.postprocess():  removing <up_to_date 0   'Tfile.in'>
Task.postprocess():  adjusted parent ref count <pending    2   '.'>

Taskmaster: Looking for a node to evaluate
Taskmaster:     Considering node <no_state   0   'Tfile.mid'> and its children:
Taskmaster:        <up_to_date 0   'Tfile.in'>
Taskmaster: Evaluating <pending    0   'Tfile.mid'>

Task.make_ready_current(): node <pending    0   'Tfile.mid'>
Task.prepare():      node <executing  0   'Tfile.mid'>
Task.execute():      node <executing  0   'Tfile.mid'>
Task.executed_with_callbacks(): node <executing  0   'Tfile.mid'>
Task.postprocess():  node <executed   0   'Tfile.mid'>
Task.postprocess():  removing <executed   0   'Tfile.mid'>
Task.postprocess():  adjusted parent ref count <pending    1   '.'>

Taskmaster: Looking for a node to evaluate
Taskmaster:     Considering node <no_state   0   'Tfile.out'> and its children:
Taskmaster:        <executed   0   'Tfile.mid'>
Taskmaster: Evaluating <pending    0   'Tfile.out'>

Task.make_ready_current(): node <pending    0   'Tfile.out'>
Task.prepare():      node <executing  0   'Tfile.out'>
Task.execute():      node <executing  0   'Tfile.out'>
Task.executed_with_callbacks(): node <executing  0   'Tfile.out'>
Task.postprocess():  node <executed   0   'Tfile.out'>
Task.postprocess():  removing <executed   0   'Tfile.out'>
Task.postprocess():  adjusted parent ref count <pending    0   '.'>

Taskmaster: Looking for a node to evaluate
Taskmaster:     Considering node <pending    0   '.'> and its children:
Taskmaster:        <up_to_date 0   'SConstruct'>
Taskmaster:        <up_to_date 0   'Tfile.in'>
Taskmaster:        <executed   0   'Tfile.mid'>
Taskmaster:        <executed   0   'Tfile.out'>
Taskmaster: Evaluating <pending    0   '.'>

Task.make_ready_current(): node <pending    0   '.'>
Task.prepare():      node <executing  0   '.'>
Task.execute():      node <executing  0   '.'>
Task.executed_with_callbacks(): node <executing  0   '.'>
Task.postprocess():  node <executed   0   '.'>

Taskmaster: Looking for a node to evaluate
Taskmaster: No candidate anymore.

"""

test.must_match('trace.out', expect_trace, mode='r')

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/option/tree-all.py

#!/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 the --tree=all option prints a tree representation of the
complete dependencies of a target.
"""

import TestSCons
import sys

test = TestSCons.TestSCons()

CC = test.detect('CC')
LINK = test.detect('LINK')
if LINK is None: LINK = CC

test.write('SConstruct', """
DefaultEnvironment(tools=[])
env = Environment(OBJSUFFIX = '.ooo', PROGSUFFIX = '.xxx')
env.Program('Foo', Split('Foo.c Bar.c'))
""")

# N.B.:  We use upper-case file names (Foo* and Bar*) so that the sorting
# order with our upper-case SConstruct file is the same on case-sensitive
# (UNIX/Linux) and case-insensitive (Windows) systems.

test.write('Foo.c', r"""
#include <stdio.h>
#include <stdlib.h>
#include "Foo.h"
int main(int argc, char *argv[])
{
        argv[argc++] = "--";
        printf("f1.c\n");
        exit (0);
}
""")

test.write('Bar.c', """
#include "Bar.h"
int local = 1;
""")

test.write('Foo.h', """
#ifndef FOO_H
#define FOO_H
#include "Bar.h"
#endif
""")

test.write('Bar.h', """
#ifndef BAR_H
#define BAR_H
#include "Foo.h"
#endif
""")

tree1 = """
+-Foo.xxx
  +-Foo.ooo
  | +-Foo.c
  | +-Foo.h
  | +-Bar.h
  | +-%(CC)s
  +-Bar.ooo
  | +-Bar.c
  | +-Bar.h
  | +-Foo.h
  | +-%(CC)s
  +-%(LINK)s
""" % locals()

test.run(arguments = "--tree=all Foo.xxx")
if test.stdout().count(tree1) != 1:
    sys.stdout.write('Did not find expected tree (or found duplicate) in the following output:\n')
    sys.stdout.write(test.stdout())
    test.fail_test()

tree2 = """
+-.
  +-Bar.c
  +-Bar.h
  +-Bar.ooo
  | +-Bar.c
  | +-Bar.h
  | +-Foo.h
  | +-%(CC)s
  +-Foo.c
  +-Foo.h
  +-Foo.ooo
  | +-Foo.c
  | +-Foo.h
  | +-Bar.h
  | +-%(CC)s
  +-Foo.xxx
  | +-Foo.ooo
  | | +-Foo.c
  | | +-Foo.h
  | | +-Bar.h
  | | +-%(CC)s
  | +-Bar.ooo
  | | +-Bar.c
  | | +-Bar.h
  | | +-Foo.h
  | | +-%(CC)s
  | +-%(LINK)s
  +-SConstruct
""" % locals()

test.run(arguments = "--tree=all .")
test.must_contain_all_lines(test.stdout(), [tree2])

tree3 = """
+-.
  +-Bar.c
  +-Bar.h
  +-Bar.ooo
  | +-Bar.c
  | +-Bar.h
  | +-Foo.h
  | +-%(CC)s
  +-Foo.c
  +-Foo.h
  +-Foo.ooo
  | +-Foo.c
  | +-Foo.h
  | +-Bar.h
  | +-%(CC)s
  +-Foo.xxx
  | +-[Foo.ooo]
  | +-[Bar.ooo]
  | +-%(LINK)s
  +-SConstruct
""" % locals()

test.run(arguments = "--tree=all,prune .")
if test.stdout().count(tree3) != 1:
    sys.stdout.write('Did not find expected tree (or found duplicate) in the following output:\n')
    sys.stdout.write(test.stdout())
    test.fail_test()

test.run(arguments = "--tree=prune .")
if test.stdout().count(tree3) != 1:
    sys.stdout.write('Did not find expected tree (or found duplicate) in the following output:\n')
    sys.stdout.write(test.stdout())
    test.fail_test()

tree4 = """
 E         = exists
  R        = exists in repository only
   b       = implicit builder
   B       = explicit builder
    S      = side effect
     P     = precious
      A    = always build
       C   = current
        N  = no clean
         H = no cache

[  B      ]+-Foo.xxx
[  B      ]  +-Foo.ooo
[E     C  ]  | +-Foo.c
[E     C  ]  | +-Foo.h
[E     C  ]  | +-Bar.h
[E     C  ]  | +-%(CC)s
[  B      ]  +-Bar.ooo
[E     C  ]  | +-Bar.c
[E     C  ]  | +-Bar.h
[E     C  ]  | +-Foo.h
[E     C  ]  | +-%(CC)s
[E     C  ]  +-%(LINK)s
""" % locals()

test.run(arguments = '-c Foo.xxx')

test.run(arguments = "--no-exec --tree=all,status Foo.xxx")
if test.stdout().count(tree4) != 1:
    sys.stdout.write('Did not find expected tree (or found duplicate) in the following output:\n')
    sys.stdout.write(test.stdout())
    test.fail_test()

test.run(arguments = "--no-exec --tree=status Foo.xxx")
if test.stdout().count(tree4) != 1:
    sys.stdout.write('Did not find expected tree (or found duplicate) in the following output:\n')
    sys.stdout.write(test.stdout())
    test.fail_test()

# Make sure we print the debug stuff even if there's a build failure.
test.write('Bar.h', """
#ifndef BAR_H
#define BAR_H
#include "Foo.h"
#endif
THIS SHOULD CAUSE A BUILD FAILURE
""")

test.run(arguments = "--tree=all Foo.xxx",
         status = 2,
         stderr = None)
if test.stdout().count(tree1) != 1:
    sys.stdout.write('Did not find expected tree (or found duplicate) in the following output:\n')
    sys.stdout.write(test.stdout())
    test.fail_test()

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/option/tree-derived.py

#!/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 the --debug=dtree option correctly prints just the explicit
dependencies (sources or Depends()) of a target.
"""

import TestSCons

test = TestSCons.TestSCons()

test.write('SConstruct', """
DefaultEnvironment(tools=[])
env = Environment(OBJSUFFIX = '.ooo', PROGSUFFIX = '.xxx')
env.Program('foo', Split('foo.c bar.c'))
""")

test.write('foo.c', r"""
#include <stdio.h>
#include <stdlib.h>
#include "foo.h"
int main(int argc, char *argv[])
{
        argv[argc++] = "--";
        printf("f1.c\n");
        exit (0);
}
""")

test.write('bar.c', """
#include "bar.h"
int local = 1;
""")

test.write('foo.h', """
#ifndef FOO_H
#define FOO_H
#include "bar.h"
#endif
""")

test.write('bar.h', """
#ifndef BAR_H
#define BAR_H
#include "foo.h"
#endif
""")

dtree1 = """
+-foo.xxx
  +-foo.ooo
  +-bar.ooo
"""

test.run(arguments = "--tree=derived foo.xxx")
test.must_contain_all_lines(test.stdout(), [dtree1])

dtree2 = """
+-.
  +-bar.ooo
  +-foo.ooo
  +-foo.xxx
    +-foo.ooo
    +-bar.ooo
"""

test.run(arguments = "--tree=derived .")
test.must_contain_all_lines(test.stdout(), [dtree2])

dtree3 = """
+-.
  +-bar.ooo
  +-foo.ooo
  +-foo.xxx
    +-foo.ooo
    +-bar.ooo
"""

test.run(arguments = "--tree=derived,prune .")
test.must_contain_all_lines(test.stdout(), [dtree3])

dtree4 = """
 E         = exists
  R        = exists in repository only
   b       = implicit builder
   B       = explicit builder
    S      = side effect
     P     = precious
      A    = always build
       C   = current
        N  = no clean
         H = no cache

[  B      ]+-foo.xxx
[  B      ]  +-foo.ooo
[  B      ]  +-bar.ooo
"""

test.run(arguments = '-c foo.xxx')

test.run(arguments = "--no-exec --tree=derived,status foo.xxx")
test.must_contain_all_lines(test.stdout(), [dtree4])

# Make sure we print the debug stuff even if there's a build failure.
test.write('bar.h', """
#ifndef BAR_H
#define BAR_H
#include "foo.h"
#endif
THIS SHOULD CAUSE A BUILD FAILURE
""")

test.run(arguments = "--tree=derived foo.xxx",
         status = 2,
         stderr = None)
test.must_contain_all_lines(test.stdout(), [dtree1])

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/option/tree-lib.py

#!/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__"

"""
Make sure that --tree=derived output with a library dependency shows
the dependency on the library.  (On earlier versions of the Microsoft
toolchain this wouldn't show up unless the library already existed
on disk.)

Issue 1363: https://github.com/SCons/scons/issues/1363
"""

import TestSCons

test = TestSCons.TestSCons()

test.write('SConstruct', """
DefaultEnvironment(tools=[])
env = Environment(LIBPREFIX='',
                  LIBSUFFIX='.lib',
                  OBJSUFFIX='.obj',
                  EXESUFFIX='.exe')
env.AppendENVPath('PATH', '.')
l = env.Library( 'util.lib', 'util.c' )
p = env.Program( 'test_tree_lib.exe', 'main.c', LIBS=l )
env.Command( 'foo.h', p, '$SOURCE > $TARGET')
""")

test.write('main.c', """\
#include <stdlib.h>
#include <stdio.h>
int
main(int argc, char **argv)
{
    printf("#define	FOO_H	\\"foo.h\\"\\n");
    return (0);
}
""")

test.write('util.c', """\
void
util(void)
{
    ;
}
""")

expect = """
  +-test_tree_lib.exe
    +-main.obj
    +-util.lib
      +-util.obj
"""

test.run(arguments = '--tree=derived foo.h')
test.must_contain_all_lines(test.stdout(), [expect])

test.up_to_date(arguments = 'foo.h')

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/option/warn-dependency.py

#!/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 use of the --warn=dependency option.
"""

import TestSCons

test = TestSCons.TestSCons(match = TestSCons.match_re_dotall)


test.write("SConstruct", """\
DefaultEnvironment(tools=[])
import SCons.Defaults

def build(target, source, env):
    pass

env=Environment(tools=[])
env['BUILDERS']['test'] = Builder(action=build,
                                  source_scanner=SCons.Defaults.ObjSourceScan)
env.test(target='foo', source='foo.c')
env.Pseudo('foo')
""")

test.write("foo.c","""
#include "not_there.h"
""")


expect = r"""
scons: warning: No dependency generated for file: not_there\.h \(included from: foo\.c\) \-\- file not found
""" + TestSCons.file_expr

test.run(arguments='--warn=dependency .',
         stderr=expect)

test.run(arguments='--warn=dependency .',
         stderr=expect)

test.run(arguments='--warn=all --warn=no-dependency .',
         stderr=TestSCons.deprecated_python_expr)

test.run(arguments='--warn=no-dependency --warn=all .',
         stderr=TestSCons.deprecated_python_expr + expect)


test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/option/warn-duplicate-environment.py

#!/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 use of the --warn=duplicate-environment option.
"""

import TestSCons

test = TestSCons.TestSCons(match = TestSCons.match_re_dotall)


test.write('SConstruct', """
DefaultEnvironment(tools=[])
def build(env, target, source):
    with open(str(target[0]), 'wb') as f:
        for s in source:
            with open(str(s), 'rb') as infp:
                f.write(infp.read())

WARN = ARGUMENTS.get('WARN')
if WARN:
    SetOption('warn', WARN)

B = Builder(action=build, multi=1)
env = Environment(tools=[], BUILDERS = { 'B' : B })
env2 = env.Clone(DIFFERENT_VARIABLE = 'true')
env.B(target = 'file1.out', source = 'file1a.in')
env2.B(target = 'file1.out', source = 'file1b.in')
""")

test.write('file1a.in', 'file1a.in\n')
test.write('file1b.in', 'file1b.in\n')

expect = r"""
scons: warning: Two different environments were specified for target file1.out,
\tbut they appear to have the same action: build\(target, source, env\)
""" + TestSCons.file_expr

test.run(arguments='file1.out', stderr=expect)

test.must_match('file1.out', "file1a.in\nfile1b.in\n")

test.run(arguments='--warn=duplicate-environment file1.out', stderr=expect)

test.run(arguments='--warn=no-duplicate-environment file1.out')

test.run(arguments='WARN=duplicate-environment file1.out', stderr=expect)

test.run(arguments='WARN=no-duplicate-environment file1.out')


test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/option/warn-misleading-keywords.py

#!/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 use of the --warn=misleading-keywords option.
"""

import TestSCons

test = TestSCons.TestSCons(match = TestSCons.match_re_dotall)


test.write('SConstruct', """
DefaultEnvironment(tools=[])
def build(env, target, source):
    with open(str(target[0]), 'wb') as f:
        for s in source:
            with open(str(s), 'rb') as infp:
                f.write(infp.read())

WARN = ARGUMENTS.get('WARN')
if WARN:
    SetOption('warn', WARN)

B = Builder(action=build, multi=1)
env = Environment(tools=[], BUILDERS = { 'B' : B })
env.B(targets = 'file3a.out', source = 'file3a.in')
env.B(target = 'file3b.out', sources = 'file3b.in')
""")

test.write('file3a.in', 'file3a.in\n')
test.write('file3b.out', 'file3b.out\n')

expect = r"""
scons: warning: Did you mean to use `(target|source)' instead of `(targets|sources)'\?
""" + TestSCons.file_expr

test.run(arguments='.', 
         stderr=expect + expect)

test.must_match(['file3a'], 'file3a.in\n')
test.must_match(['file3b'], 'file3b.out\n')

test.run(arguments='--warn=misleading-keywords .', stderr=expect + expect)

test.run(arguments='--warn=no-misleading-keywords .')

test.run(arguments='WARN=misleading-keywords .', stderr=expect + expect)

test.run(arguments='WARN=no-misleading-keywords .')


test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/option/warn-missing-sconscript.py

#!/usr/bin/env python
#
# MIT License
#
# Copyright The SCons Foundation
#
# 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 use of the --warn=missing-sconscript option.
"""

import TestSCons

test = TestSCons.TestSCons(match = TestSCons.match_re_dotall)


test.write("SConstruct", """\
DefaultEnvironment(tools=[])
def build(target, source, env):
    pass

env=Environment(tools=[])
env['BUILDERS']['test'] = Builder(action=build)
env.test(target='foo', source='foo.c')
WARN = ARGUMENTS.get('WARN')
if WARN:
    SetOption('warn', WARN)
SConscript('no_such_file')
""")

test.write("foo.c","""
#include "not_there.h"
""")

expect = r"""
scons: warning: Calling missing SConscript without error is deprecated.
Transition by adding must_exist=False to SConscript calls.
Missing SConscript 'no_such_file'
""" + TestSCons.file_expr

# this is the old message:
#expect = r"""
#scons: warning: Ignoring missing SConscript 'no_such_file'
"" + TestSCons.file_expr

test.run(arguments = '--warn=missing-sconscript .', stderr = expect)

test.run(arguments = '--warn=no-missing-sconscript .', stderr = "")

test.run(arguments = 'WARN=missing-sconscript .', stderr = expect)

test.run(arguments = 'WARN=no-missing-sconscript .', stderr = "")


test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/packaging/guess-package-name.py

#!/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__"

"""
This tests the feature of guessing the package name from the given metadata
projectname and version.

Also overriding this default package name is tested

Furthermore that targz is the default packager is tested.
"""

import sys

import TestSCons

python = TestSCons.python
test = TestSCons.TestSCons()
tar = test.detect('TAR', 'tar')

if not tar:
    test.skip_test('tar not found; skipping test\n')

#
# TEST: default package name creation.
#
test.subdir('src')

test.write( [ 'src', 'main.c' ], r"""
int main( int argc, char* argv[] )
{
  return 0;
}
""")

test.write('SConstruct', """
env=Environment(tools=['default', 'packaging'])
env.Program( 'src/main.c' )
env.Package( NAME        = 'libfoo',
             VERSION     = '1.2.3',
             PACKAGETYPE = 'zip',
             source      = [ 'src/main.c', 'SConstruct' ] )
""")

test.run(options="--debug=stacktrace", stderr = None)

test.must_exist( 'libfoo-1.2.3.zip' )

#
# TEST: overriding default package name.
#

test.write('SConstruct', """
env=Environment(tools=['default', 'packaging'])
env.Program( 'src/main.c' )
env.Package( NAME        = 'libfoo',
             VERSION     = '1.2.3',
             PACKAGETYPE = 'src_targz',
             target      = 'src.tar.gz',
             source      = [ 'src/main.c', 'SConstruct' ] )
""")

test.run(stderr=None)

test.must_exist('src.tar.gz')

#
# TEST: default package name creation with overridden packager.
#
# Windows 10 since at least 1803 supplies bsdtar, so tool
# detection will find it - but doesn't supply bzip2, so a
# test using it will fail. As a hack, just skip.

if sys.platform != 'win32':
    test.write('SConstruct', """
env=Environment(tools=['default', 'packaging'])
env.Program( 'src/main.c' )
env.Package( NAME        = 'libfoo',
             VERSION     = '1.2.3',
             PACKAGETYPE = 'src_tarbz2',
             source      = [ 'src/main.c', 'SConstruct' ] )
""")

    test.run(stderr=None)

    test.must_exist('libfoo-1.2.3.tar.bz2')

#
# TEST: default package name creation with another packager.
#
# Windows 10 since at least 1803 supplies bsdtar, so tool
# detection will find it - but it doesn't support xz
# compression so test using it will fail. As a hack, just skip.

if sys.platform != 'win32':
    test.write('SConstruct', """
env=Environment(tools=['default', 'packaging'])
env.Program( 'src/main.c' )
env.Package( NAME        = 'libfoo',
             VERSION     = '1.2.3',
             PACKAGETYPE = 'src_tarxz',
             source      = [ 'src/main.c', 'SConstruct' ] )
""")

    test.run(stderr=None)

    test.must_exist('libfoo-1.2.3.tar.xz')

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/packaging/ipkg.py

#!/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 the ability to call the ipkg tool trough SCons.

TODO: make a test to assert that the clean action removes ALL intermediate files
"""

import os
import TestSCons

python = TestSCons.python
test = TestSCons.TestSCons()
ipkg = test.Environment().WhereIs('ipkg-build')

if not ipkg:
  test.skip_test("ipkg-build not found, skipping test\n")

test.write( 'main.c', r"""
int main(int argc, char *argv[])
{
    return 0;
}
""")

test.write( 'foo.conf', '' )

test.write( 'SConstruct', r"""
env=Environment(tools=['default', 'packaging'])
prog = env.Install( 'bin/', Program( 'main.c') )
conf = env.Install( 'etc/', File( 'foo.conf' ) )
env.Tag( conf, 'CONF', 'MEHR', 'UND MEHR' )
env.Package( PACKAGETYPE = 'ipk',
             source      = env.FindInstalledFiles(),
             NAME        = 'foo',
             VERSION     = '0.0',
             SUMMARY     = 'foo is the ever-present example program -- it does everything',
             DESCRIPTION = '''foo is not a real package. This is simply an example that you
may modify if you wish.
.
When you modify this example, be sure to change the Package, Version,
Maintainer, Depends, and Description fields.''',

             SOURCE_URL       = 'http://gnu.org/foo-0.0.tar.gz',
             X_IPK_SECTION    = 'extras',
             X_IPK_PRIORITY   = 'optional',
             ARCHITECTURE     = 'arm',
             X_IPK_MAINTAINER = 'Familiar User <user@somehost.net>',
             X_IPK_DEPENDS    = 'libc6, grep', )
""")

with os.popen('id -un') as p:
    IPKGUSER = p.read().strip()
with os.popen('id -gn') as p:
    IPKGGROUP = p.read().strip()

expected="""scons: Reading SConscript files ...
scons: done reading SConscript files.
scons: Building targets ...
gcc -o main.o -c main.c
gcc -o main main.o
Copy file(s): "main" to "foo-0.0/bin/main"
Copy file(s): "foo.conf" to "foo-0.0/etc/foo.conf"
build_specfiles(["foo-0.0/CONTROL/control", "foo-0.0/CONTROL/conffiles", "foo-0.0/CONTROL/postrm", "foo-0.0/CONTROL/prerm", "foo-0.0/CONTROL/postinst", "foo-0.0/CONTROL/preinst"], ["foo-0.0/bin/main", "foo-0.0/etc/foo.conf"])
ipkg-build -o %s -g %s foo-0.0
Packaged contents of foo-0.0 into %s/foo_0.0_arm.ipk
scons: done building targets.
"""%(IPKGUSER, IPKGGROUP, test.workpath())

test.run(arguments="--debug=stacktrace foo_0.0_arm.ipk", stdout=expected)
test.must_exist( 'foo-0.0/CONTROL/control' )
test.must_exist( 'foo_0.0_arm.ipk' )

test.subdir( 'foo-0.0' )
test.subdir( [ 'foo-0.0', 'CONTROL' ] )

test.write( [ 'foo-0.0', 'CONTROL', 'control' ], r"""
Package: foo
Priority: optional
Section: extras
Source: http://gnu.org/foo-0.0.tar.gz
Version: 0.0
Architecture: arm
Maintainer: Familiar User <user@somehost.net>
Depends: libc6, grep
Description: foo is the ever-present example program -- it does everything
 foo is not a real package. This is simply an example that you
 may modify if you wish.
 .
 When you modify this example, be sure to change the Package, Version,
 Maintainer, Depends, and Description fields.
""")

test.write( 'main.c', r"""
int main(int argc, char *argv[])
{
    return 0;
}
""")

test.write('SConstruct', """
env = Environment( tools = [ 'default', 'ipkg' ] )
prog = env.Install( 'foo-0.0/bin/' , env.Program( 'main.c')  )
env.Ipkg( [ env.Dir( 'foo-0.0' ), prog ] )
""")

test.run(arguments='', stderr = None)
test.must_exist( 'foo_0.0_arm.ipk' )

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/packaging/multiple-packages-at-once.py

#!/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__"

"""
See if the packaging tool is able to build multiple packages at once.

TODO: test if the packages are clean versions (i.e. do not contain files
      added by different packager runs)
"""

import TestSCons

python = TestSCons.python

test = TestSCons.TestSCons()

zip = test.detect('ZIP', 'zip')
tar = test.detect('TAR', 'tar')

if not zip:
    test.skip_test('zip not found, skipping test\n')

if not tar:
    test.skip_test('tar not found, skipping test\n')

test.subdir('src')

test.write( [ 'src', 'main.c' ], r"""
int main( int argc, char* argv[] )
{
  return 0;
}
""")

test.write('SConstruct', """
Program( 'src/main.c' )
env=Environment(tools=['default', 'packaging'])
env.Package( PACKAGETYPE  = ['src_zip', 'src_targz'],
             target       = ['src.zip', 'src.tar.gz'],
             PACKAGEROOT  = 'test',
             source       = [ 'src/main.c', 'SConstruct' ] )
""")

test.run(arguments='', stderr = None)

test.must_exist( 'src.zip' )
test.must_exist( 'src.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' ] )
""")

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()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/packaging/multiple-subdirs.py

#!/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 build packages in different subdirectories.

Test case courtesy Andrew Smith.
"""

import TestSCons

test = TestSCons.TestSCons()

tar = test.detect('TAR', 'tar')

if not tar:
    test.skip_test('No TAR executable found; skipping test\n')

test.subdir('one', 'two', 'three')

test.write('SConstruct', """\
env = Environment(tools=['packaging', 'filesystem', 'tar'])
Export('env')
SConscript(dirs = ['one', 'two', 'three'])
""")

SConscript_template = """\
Import('*')

files = env.Install('/usr/bin', '%s.sh')

pkg = env.Package(NAME          = '%s',
                  VERSION       = '1.0.0',
                  PACKAGETYPE   = 'targz',
                  source        = [files]
                  )
"""

test.write(['one',   'SConscript'], SConscript_template % ('one', 'one'))
test.write(['two',   'SConscript'], SConscript_template % ('two', 'two'))
test.write(['three', 'SConscript'], SConscript_template % ('three', 'three'))

test.write(['one',   'one.sh'],     "one/one.sh\n")
test.write(['two',   'two.sh'],     "two/two.sh\n")
test.write(['three', 'three.sh'],   "three/three.sh\n")

test.run(arguments = '.')

test.must_match(['one', 'one-1.0.0', 'usr', 'bin', 'one.sh'], "one/one.sh\n")
test.must_match(['two', 'two-1.0.0', 'usr', 'bin', 'two.sh'], "two/two.sh\n")
test.must_match(['three', 'three-1.0.0', 'usr', 'bin', 'three.sh'], "three/three.sh\n")

test.must_exist(['one', 'one-1.0.0.tar.gz'])
test.must_exist(['two', 'two-1.0.0.tar.gz'])
test.must_exist(['three', 'three-1.0.0.tar.gz'])

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/packaging/option--package-type.py

#!/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 the --package-type option.

Side effect: also tests that we can produce a noarch package
by supplying the ARCHITECTURE tag.
"""

import TestSCons
import SCons.Tool.rpmutils

_python_ = TestSCons._python_

test = TestSCons.TestSCons()

rpm_build_root = test.workpath('rpm_build_root')

scons = test.program

rpm = test.Environment().WhereIs('rpm')

if not rpm:
    test.skip_test('rpm not found, skipping test\n')

test.subdir('src')

test.write( 'main', '' )

test.write('SConstruct', """
# -*- coding: iso-8859-15 -*-
env=Environment(tools=['packaging', 'filesystem', 'tar', 'rpm'])
env.Prepend(RPM = 'TAR_OPTIONS=--wildcards ')
env.Append(RPMFLAGS = r' --buildroot %(rpm_build_root)s')
prog=env.Install( '/bin', 'main' )
env.Package( NAME           = 'foo',
             VERSION        = '1.2.3',
             LICENSE        = 'gpl',
             SUMMARY        = 'hello',
             PACKAGEVERSION = 0,
             X_RPM_GROUP    = 'Application/office',
             X_RPM_INSTALL  = r'%(_python_)s %(scons)s --install-sandbox="$RPM_BUILD_ROOT" "$RPM_BUILD_ROOT"',
             DESCRIPTION    = 'this should be really long',
             source         = [ prog ],
             SOURCE_URL     = 'http://foo.org/foo-1.2.3.tar.gz',
             ARCHITECTURE   = 'noarch'
            )
""" % locals())

src_rpm = 'foo-1.2.3-0.src.rpm'
machine_rpm = 'foo-1.2.3-0.noarch.rpm'

test.run(arguments='package PACKAGETYPE=rpm', stderr = None)

test.must_exist( src_rpm )
test.must_exist( machine_rpm )
test.must_not_exist( 'bin/main.c' )
test.must_not_exist( '/bin/main.c' )

test.run(arguments='-c package PACKAGETYPE=rpm', stderr = None)

test.run(arguments='package --package-type=rpm', stderr = None)
test.must_exist( src_rpm )
test.must_exist( machine_rpm )
test.must_not_exist( 'bin/main.c' )
test.must_not_exist( '/bin/main.c' )

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/packaging/place-files-in-subdirectory.py

#!/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 the requirement to place files in a given subdirectory before archiving.
"""

import subprocess

import TestSCons

python = TestSCons.python

test = TestSCons.TestSCons()

tar = test.detect('TAR', 'tar')

if not tar:
    test.skip_test('tar not found, skipping test\n')

#
# TEST: subdir creation and file copying
#
test.subdir('src')
test.write('src/main.c', '')

test.write('SConstruct', """\
env = Environment(tools=['packaging', 'filesystem', 'zip'])
env.Package(
    NAME='libfoo',
    PACKAGEROOT='libfoo',
    PACKAGETYPE='src_zip',
    VERSION='1.2.3',
    source=['src/main.c', 'SConstruct'],
)
""")

test.run(arguments='libfoo-1.2.3.zip', stderr=None)

test.must_exist('libfoo')
test.must_exist('libfoo/SConstruct')
test.must_exist('libfoo/src/main.c')

#
# TEST: subdir guessing and file copying.
#
#test.subdir('src')  # already created above
test.write('src/main.c', '')

test.write('SConstruct', """\
env = Environment(tools=['packaging', 'filesystem', 'zip'])
env.Package(
    NAME='libfoo',
    VERSION='1.2.3',
    PACKAGETYPE='src_zip',
    TARGET='src.zip',
    source=['src/main.c', 'SConstruct'],
)
""")

test.run(stderr=None)

test.must_exist('libfoo-1.2.3')
test.must_exist('libfoo-1.2.3/SConstruct')
test.must_exist('libfoo-1.2.3/src/main.c')

#
# TEST: unpacking without the buildir.
#
#test.subdir('src')  # already created above
test.subdir('temp')
test.write('src/main.c', '')

test.write('SConstruct', """\
env = Environment(tools=['packaging', 'filesystem', 'tar'])
env.Package(
    NAME='libfoo',
    VERSION='1.2.3',
    PACKAGETYPE='src_targz',
    source=['src/main.c', 'SConstruct'],
)
""")

test.run(stderr=None)

cp = subprocess.run(
    [tar, '-tzf', test.workpath('libfoo-1.2.3.tar.gz')],
    stdout=subprocess.PIPE,
    universal_newlines=True,
)
test.fail_test(cp.stdout != "libfoo-1.2.3/src/main.c\nlibfoo-1.2.3/SConstruct\n")
test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/packaging/strip-install-dir.py

#!/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 stripping the InstallBuilder of the Package source file.
"""
import os

import TestSCons

python = TestSCons.python

test = TestSCons.TestSCons()

tar = test.detect('TAR', 'tar')

if not tar:
    test.skip_test('tar not found, skipping test\n')

test.write( 'main.c', '' )
test.write('SConstruct', """
prog = Install( '/bin', 'main.c' )
env=Environment(tools=['packaging', 'filesystem', 'tar'])
env.Package( NAME    = 'foo',
             VERSION = '1.2.3',
             source  = [ prog ],
            )
""")

expected = """scons: Reading SConscript files ...
scons: done reading SConscript files.
scons: Building targets ...
Copy file(s): "main.c" to "foo-1.2.3{os_sep}bin{os_sep}main.c"
tar -zc -f foo-1.2.3.tar.gz foo-1.2.3{os_sep}bin{os_sep}main.c
scons: done building targets.
""".format(os_sep=os.sep)

test.run(arguments='', stderr = None, stdout=expected)

test.must_not_exist( 'bin/main.c' )
test.must_not_exist( '/bin/main.c' )

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/packaging/use-builddir.py

#!/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 the ability to use the archiver in combination with builddir.
"""

import subprocess

import TestSCons

python = TestSCons.python

test = TestSCons.TestSCons()
tar = test.detect("TAR", "tar")

if not tar:
    test.skip_test("tar not found, skipping test\n")

#
# TEST: builddir usage.
#
test.subdir("src")
test.subdir("build")

test.write("src/main.c", "")

test.write("SConstruct", """\
VariantDir('build', 'src')
DefaultEnvironment(tools=[])
env = Environment(tools=['packaging', 'filesystem', 'zip'])
env.Package(
    NAME='libfoo',
    PACKAGEROOT='build/libfoo',
    VERSION='1.2.3',
    PACKAGETYPE='src_zip',
    target='build/libfoo-1.2.3.zip',
    source=['src/main.c', 'SConstruct'],
)
""")

test.run(stderr=None)

test.must_exist("build/libfoo-1.2.3.zip")

# TEST: builddir not placed in archive
# XXX: VariantDir should be stripped.
#
#test.subdir("src")  # already created above
#test.subdir("build")  # already created above
test.subdir("temp")

test.write("src/main.c", "")

test.write("SConstruct", """\
DefaultEnvironment(tools=[])
VariantDir('build', 'src')
env = Environment(tools=['packaging', 'filesystem', 'tar'])
env.Package(
    NAME='libfoo',
    VERSION='1.2.3',
    PAKCAGETYPE='src_targz',
    source=['src/main.c', 'SConstruct'],
)
""")

test.run(stderr=None)

test.must_exist("libfoo-1.2.3.tar.gz")

testdir = test.workpath('libfoo-1.2.3.tar.gz')
subprocess.run('%s -C temp -xzf %s' % (tar, testdir), shell=True)

test.must_exist("temp/libfoo-1.2.3/src/main.c")
test.must_exist("temp/libfoo-1.2.3/SConstruct")

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/packaging/zip.py

#!/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__"

"""
This tests the SRC zip packager, which does the following:
 - create a zip package from the specified files
"""

import TestSCons

python = TestSCons.python

test = TestSCons.TestSCons()

zip = test.detect('ZIP', 'zip')

if not zip:
    test.skip_test('zip not found, skipping test\n')

test.subdir('src')

test.write( [ 'src', 'main.c' ], r"""
int main( int argc, char* argv[] )
{
  return 0;
}
""")

test.write('SConstruct', """
Program( 'src/main.c' )
env=Environment(tools=['packaging', 'filesystem', 'zip'])
env.Package( PACKAGETYPE  = 'src_zip',
             target       = 'src.zip',
             PACKAGEROOT  = 'test',
             source       = [ 'src/main.c', 'SConstruct' ] )
""")

test.run(arguments='', stderr = None)

test.must_exist( 'src.zip' )

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/question/Configure.py

#!/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 operation of the -q (--question) option in conjunction
with Configure tests.

(This was originally mostly copied and pasted from test/option-n.py.)
"""

import os.path
import re

import TestCmd
import TestSCons
from SCons.Util import get_current_hash_algorithm_used

test = TestSCons.TestSCons(match = TestCmd.match_re_dotall)

test.write('aaa.in', 'Hello world\n')

test.write('SConstruct', """\
def userAction(target,source,env):
    import shutil
    shutil.copyfile( str(source[0]), str(target[0]))

def strAction(target,source,env):
    return "cp " + str(source[0]) + " " + str(target[0])

def CustomTest(context):
    context.Message("Executing Custom Test ... " )
    (ok, msg) = context.TryAction(Action(userAction,strAction),
                                  "Hello World", ".in")
    context.Result(ok)
    return ok

env = Environment(BUILDERS={'B' : Builder(action=Action(userAction,strAction))})

conf = Configure( env,
                  custom_tests={'CustomTest':CustomTest},
                  conf_dir="config.test",
                  log_file="config.log")
if not conf.CustomTest():
    Exit(1)
else:
    env = conf.Finish()

env.B(target='aaa.out', source='aaa.in')
""")

# test that conf_dir isn't created and an error is raised
stderr=r"""
scons: \*\*\* Cannot create configure directory "config\.test" within a dry-run\.
File \S+, line \S+, in \S+
"""
test.run(arguments="-q aaa.out",stderr=stderr,status=2)

test.must_not_exist(test.workpath("config.test"))
test.must_not_exist(test.workpath("config.log"))

# depending on which default hash function we're using, we'd expect one of the following filenames.
# The filenames are generated by the conftest changes in #3543 : https://github.com/SCons/scons/pull/3543/files
possible_filenames = {
    'md5': "conftest_b10a8db164e0754105b7a99be72e3fe5_0.in",
    'sha1': "conftest_0a4d55a8d778e5022fab701977c5d840bbc486d0_0.in",
    'sha256': "conftest_a591a6d40bf420404a011733cfb7b190d62c65bf0bcda32b57b277d9ad9f146e_0.in"
}
test_filename = possible_filenames[get_current_hash_algorithm_used()]

# test that targets are not built, if conf_dir exists.
# verify that .cache and config.log are not created.
# an error should be raised
stderr=r"""
scons: \*\*\* Cannot update configure test "%s" within a dry-run\.
File \S+, line \S+, in \S+
""" % re.escape(os.path.join("config.test", test_filename))

test.subdir('config.test')

test.run(arguments="-q aaa.out",stderr=stderr,status=2)

test.must_not_exist(test.workpath("config.test", ".cache"))
test.must_not_exist(test.workpath("config.test", "conftest_0"))
test.must_not_exist(test.workpath("config.test", test_filename))
test.must_not_exist(test.workpath("config.log"))

# test that no error is raised, if all targets are up-to-date. In this
# case .cache and config.log shouldn't be created
stdout=test.wrap_stdout(build_str='cp aaa.in aaa.out\n',
                        read_str="""Executing Custom Test ... yes
""")

test.run(stdout=stdout,arguments="aaa.out",status=0)

log1_mtime = os.path.getmtime(test.workpath("config.log"))

test.run(arguments="-q aaa.out",status=0)
log2_mtime = os.path.getmtime(test.workpath("config.log"))
test.fail_test( log1_mtime != log2_mtime )

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/question/basic.py

#!/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 -q (--question) option.
"""

import TestSCons

test = TestSCons.TestSCons()

_python_ = TestSCons._python_

test.write('build.py', r"""
import sys
with open(sys.argv[1], 'wb') as f, open(sys.argv[2], 'rb') as ifp:
    f.write(ifp.read())
""")

test.write('SConstruct', """
B = Builder(action=r'%(_python_)s build.py $TARGET $SOURCES')
env = Environment(BUILDERS = { 'B' : B })
env.B(target = 'aaa.out', source = 'aaa.in')
env.B(target = 'bbb.out', source = 'bbb.in')
""" % locals())

test.write('aaa.in', "aaa.in\n")
test.write('bbb.in', "bbb.in\n")

test.run(arguments = '-q aaa.out', status = 1)

test.must_not_exist(test.workpath('aaa.out'))

test.run(arguments = 'aaa.out')

test.must_match('aaa.out', "aaa.in\n")

test.run(arguments = '-q aaa.out', status = 0)

test.run(arguments = '--question bbb.out', status = 1)

test.must_not_exist(test.workpath('bbb.out'))

test.run(arguments = 'bbb.out')

test.must_match('bbb.out', "bbb.in\n")

test.run(arguments = '--question bbb.out', status = 0)

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/question/no-builder.py

#!/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 operation of the -q (--question) option when a specified
target has no builder.
"""

import TestSCons

test = TestSCons.TestSCons()

_python_ = TestSCons._python_

test.write('SConstruct', """
""")

test.run(arguments = '-q no_such_target', status = 1)

test.run(arguments = '--question no_such_target', status = 1)

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/runtest/SCons.py

#!/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 find tests under the SCons/ tree only if they end
with *Tests.py.
"""

import os

import TestRuntest

test = TestRuntest.TestRuntest()
test.subdir(['SCons'], ['SCons', 'suite'])

pythonstring = TestRuntest.pythonstring
pythonflags = TestRuntest.pythonflags
src_passTests_py = os.path.join('SCons', 'passTests.py')
src_suite_passTests_py = os.path.join('SCons', 'suite', 'passTests.py')

test.write_passing_test(['SCons', 'pass.py'])
test.write_passing_test(['SCons', 'passTests.py'])
test.write_passing_test(['SCons', 'suite', 'pass.py'])
test.write_passing_test(['SCons', 'suite', 'passTests.py'])

expect_stdout = """\
%(pythonstring)s%(pythonflags)s %(src_passTests_py)s
PASSING TEST STDOUT
%(pythonstring)s%(pythonflags)s %(src_suite_passTests_py)s
PASSING TEST STDOUT
""" % locals()

expect_stderr = """\
PASSING TEST STDERR
PASSING TEST STDERR
""" % locals()

test.run(arguments='-k SCons', stdout=expect_stdout, stderr=expect_stderr)

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/runtest/faillog.py

#!/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 a list of tests in failed_tests.log to run with the --retry option
"""

import os.path

import TestRuntest

pythonstring = TestRuntest.pythonstring
pythonflags = TestRuntest.pythonflags
test_fail_py = os.path.join('test', 'fail.py')
test_pass_py = os.path.join('test', 'pass.py')

test = TestRuntest.TestRuntest()
test.subdir('test')
test.write_failing_test(test_fail_py)
test.write_passing_test(test_pass_py)

expect_stdout = """\
%(pythonstring)s%(pythonflags)s %(test_fail_py)s
FAILING TEST STDOUT
%(pythonstring)s%(pythonflags)s %(test_pass_py)s
PASSING TEST STDOUT

Failed the following test:
\t%(test_fail_py)s
""" % locals()

expect_stderr = """\
FAILING TEST STDERR
PASSING TEST STDERR
"""

testlist = [
    test_fail_py,
    test_pass_py,
]

test.run(
    arguments='-k --faillog=fail.log %s' % ' '.join(testlist),
    status=1,
    stdout=expect_stdout,
    stderr=expect_stderr,
)
test.must_exist('fail.log')
test.must_contain('fail.log', test_fail_py)
test.must_not_exist('failed_tests.log')

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/runtest/no_faillog.py

#!/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 a list of tests in failed_tests.log to run with the --retry option
"""

import os.path

import TestRuntest

pythonstring = TestRuntest.pythonstring
pythonflags = TestRuntest.pythonflags
test_fail_py = os.path.join('test', 'fail.py')
test_pass_py = os.path.join('test', 'pass.py')

test = TestRuntest.TestRuntest()
test.subdir('test')
test.write_failing_test(test_fail_py)
test.write_passing_test(test_pass_py)

test.write('failed_tests.log', """\
%(test_fail_py)s
""" % locals())

expect_stdout = """\
%(pythonstring)s%(pythonflags)s %(test_fail_py)s
FAILING TEST STDOUT
%(pythonstring)s%(pythonflags)s %(test_pass_py)s
PASSING TEST STDOUT

Failed the following test:
\t%(test_fail_py)s
""" % locals()

expect_stderr = """\
FAILING TEST STDERR
PASSING TEST STDERR
"""

testlist = [
    test_fail_py,
    test_pass_py,
]

test.run(
    arguments='-k --no-faillog %s' % ' '.join(testlist),
    status=1,
    stdout=expect_stdout,
    stderr=expect_stderr,
)
test.must_not_exist('failing_tests.log')

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/runtest/print_time.py

#!/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 a combination of a passing test, failing test, and no-result
test with no argument on the command line.
"""

import os
import re

import TestCmd
import TestRuntest

pythonstring = re.escape(TestRuntest.pythonstring)
pythonflags = TestRuntest.pythonflags
test_fail_py = re.escape(os.path.join('test', 'fail.py'))
test_no_result_py = re.escape(os.path.join('test', 'no_result.py'))
test_pass_py = re.escape(os.path.join('test', 'pass.py'))

test = TestRuntest.TestRuntest(match = TestCmd.match_re)
test.subdir('test')
test.write_failing_test(['test', 'fail.py'])
test.write_no_result_test(['test', 'no_result.py'])
test.write_passing_test(['test', 'pass.py'])

expect_stdout = """\
%(pythonstring)s%(pythonflags)s %(test_fail_py)s
FAILING TEST STDOUT
Test execution time: \\d+.\\d seconds
%(pythonstring)s%(pythonflags)s %(test_no_result_py)s
NO RESULT TEST STDOUT
Test execution time: \\d+.\\d seconds
%(pythonstring)s%(pythonflags)s %(test_pass_py)s
PASSING TEST STDOUT
Test execution time: \\d+.\\d seconds
Total execution time for all tests: \\d+.\\d seconds

Failed the following test:
\t%(test_fail_py)s

NO RESULT from the following test:
\t%(test_no_result_py)s
""" % locals()

expect_stderr = """\
FAILING TEST STDERR
NO RESULT TEST STDERR
PASSING TEST STDERR
"""

test.run(arguments='-k -t test',
         status=1,
         stdout=expect_stdout,
         stderr=expect_stderr)

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/runtest/python.py

#!/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 the -P option lets us specify a Python version to use.
"""

import os
import re

if not hasattr(os.path, 'pardir'):
    os.path.pardir = '..'

import TestRuntest

test = TestRuntest.TestRuntest()
test_pass_py = os.path.join('test', 'pass.py')
head, python = os.path.split(TestRuntest.python)
head, dir = os.path.split(head)

# deciding whether or not to use -tt flag here is dicey.
# we'll go ahead and use TestRuntest.pythonflags, but it uses the
# python version then in use, which could be different
pythonflags = TestRuntest.pythonflags

# We have to normalize the python path here, because some installations don't like
# getting called with "/bin/../bin/python" as first argument, e.g. Fedora 17 Desktop.
mypython = os.path.normpath(os.path.join(head, dir, os.path.pardir, dir, python))

def escape(s):
    return s.replace('\\', '\\\\')

if re.search(r'\s', mypython):
    mypythonstring = '"%s"' % escape(mypython)
else:
    mypythonstring = escape(mypython)

test.subdir('test')

test.write_passing_test(['test', 'pass.py'])

expect_stdout = """\
%(mypythonstring)s%(pythonflags)s %(test_pass_py)s
PASSING TEST STDOUT
""" % locals()

expect_stderr = """\
PASSING TEST STDERR
"""

test.run(arguments=['-k','-P', mypython, 'test'],
         stdout=expect_stdout,
         stderr=expect_stderr)

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/runtest/retry.py

#!/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 a list of tests in failed_tests.log to run with the --retry option
"""

import os.path

import TestRuntest

pythonstring = TestRuntest.pythonstring
pythonflags = TestRuntest.pythonflags
test_fail_py = os.path.join('test', 'fail.py')
test_no_result_py = os.path.join('test', 'no_result.py')
test_pass_py = os.path.join('test', 'pass.py')

test = TestRuntest.TestRuntest()

test.subdir('test')
test.write_failing_test(['test', 'fail.py'])
test.write_no_result_test(['test', 'no_result.py'])
test.write_passing_test(['test', 'pass.py'])

test.write('failed_tests.log', """\
%(test_fail_py)s
""" % locals())

expect_stdout = """\
%(pythonstring)s%(pythonflags)s %(test_fail_py)s
FAILING TEST STDOUT
""" % locals()

expect_stderr = """\
FAILING TEST STDERR
"""

test.run(arguments='-k --retry', status=1, stdout=expect_stdout, stderr=expect_stderr)

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/runtest/testargv.py

#!/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 subdir args for runtest.py, for example:

    python runtest.py test/subdir

"""

import os

import TestRuntest

test = TestRuntest.TestRuntest()
test.subdir('test', ['test', 'subdir'])

files = {}
files['pythonstring'] = TestRuntest.pythonstring
files['pythonflags'] = TestRuntest.pythonflags

files['one'] = os.path.join('test/subdir', 'test_one.py')
files['two'] = os.path.join('test/subdir', 'two.py')
files['three'] = os.path.join('test', 'test_three.py')

test.write_passing_test(files['one'])
test.write_passing_test(files['two'])
test.write_passing_test(files['three'])

expect_stdout = """\
%(pythonstring)s%(pythonflags)s %(one)s
PASSING TEST STDOUT
%(pythonstring)s%(pythonflags)s %(two)s
PASSING TEST STDOUT
""" % files

expect_stderr = """\
PASSING TEST STDERR
PASSING TEST STDERR
"""

test.run(arguments = '--no-progress test/subdir',
         status = 0,
         stdout = expect_stdout,
         stderr = expect_stderr)

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/runtest/testlistfile.py

#!/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 a list of tests to run in a file specified with the -f option.
The commented-out test should not run.
"""

import os.path

import TestRuntest

pythonstring = TestRuntest.pythonstring
pythonflags = TestRuntest.pythonflags
test_fail_py = os.path.join('test', 'fail.py')
test_no_result_py = os.path.join('test', 'no_result.py')
test_pass_py = os.path.join('test', 'pass.py')

test = TestRuntest.TestRuntest()

test.subdir('test')
test.write_failing_test(['test', 'fail.py'])
test.write_no_result_test(['test', 'no_result.py'])
test.write_passing_test(['test', 'pass.py'])

test.write('t.txt', """\
#%(test_fail_py)s
%(test_pass_py)s
""" % locals())

expect_stdout = """\
%(pythonstring)s%(pythonflags)s %(test_pass_py)s
PASSING TEST STDOUT
""" % locals()

expect_stderr = """\
PASSING TEST STDERR
"""

test.run(arguments='-k -f t.txt', stdout=expect_stdout, stderr=expect_stderr)

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/scons-time/no-args.py

#!/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 invoking scons-test with no arguments prints the
fall-back message and exits non-zero.
"""

import TestSCons_time

test = TestSCons_time.TestSCons_time()

expect = """\
Type "scons-time help" for usage.
"""

test.run(arguments = '', status=1, stderr=expect)

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/scons-time/unknown.py

#!/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 invoking scons-test with an unknown argument generates
the appropriate error message and exits non-zero.
"""


import TestSCons_time

test = TestSCons_time.TestSCons_time()

expect = """\
scons-time: Unknown subcommand "unknown".
Type "scons-time help" for usage.
"""

test.run(arguments = 'unknown', status=1, stderr=expect)

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/sconsign/corrupt.py

#!/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 we get proper warnings when .sconsign* files are corrupt.
"""

import TestSCons
import TestCmd
import re

test = TestSCons.TestSCons(match = TestCmd.match_re)

test.subdir('work1', ['work1', 'sub'],
            'work2', ['work2', 'sub'])

database_name = test.get_sconsignname()
database_filename = database_name + ".dblite"

# for test1 we're using the default database filename
work1__sconsign_dblite = test.workpath('work1', database_filename)
# for test 2 we have an explicit hardcode to .sconsign
work2_sub__sconsign = test.workpath('work2', 'sub', database_name)

SConstruct_contents = """\
def build1(target, source, env):
    with open(str(target[0]), 'wb') as ofp, open(str(source[0]), 'rb') as ifp:
        ofp.write(ifp.read())
    return None

B1 = Builder(action = build1)
env = Environment(BUILDERS = { 'B1' : B1})
env.B1(target = 'sub/foo.out', source = 'foo.in')
"""



test.write(['work1', 'SConstruct'], SConstruct_contents)

test.write(['work1', 'foo.in'], "work1/foo.in\n")

stderr = r'''
scons: warning: Ignoring corrupt .sconsign file: {}
.*
'''.format(re.escape(database_filename))

stdout = test.wrap_stdout(r'build1\(\["sub.foo\.out"\], \["foo\.in"\]\)' + '\n')

test.write(work1__sconsign_dblite, 'not:a:sconsign:file')
test.run(chdir='work1', arguments='.', stderr=stderr, stdout=stdout)

test.write(work1__sconsign_dblite, '\0\0\0\0\0\0\0\0\0\0\0\0\0\0')
test.run(chdir='work1', arguments='.', stderr=stderr, stdout=stdout)



# Test explicitly using a .sconsign file in each directory.

SConstruct_contents = """\
SConsignFile(None)
""" + SConstruct_contents

test.write(['work2', 'SConstruct'], SConstruct_contents)

test.write(['work2', 'foo.in'], "work2/foo.in\n")

stderr = r'''
scons: warning: Ignoring corrupt .sconsign file: sub.{}
.*
'''.format(database_name)

stdout = test.wrap_stdout(r'build1\(\["sub.foo\.out"\], \["foo\.in"\]\)' + '\n')

test.write(work2_sub__sconsign, 'not:a:sconsign:file')
test.run(chdir='work2', arguments='.', stderr=stderr, stdout=stdout)

test.write(work2_sub__sconsign, '\0\0\0\0\0\0\0\0\0\0\0\0\0\0')
test.run(chdir='work2', arguments='.', stderr=stderr, stdout=stdout)



test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/sconsign/ghost-entries.py

#!/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):
    with open(str(target[0]), 'wb') as fp:
        for s in source:
            with open(str(s), 'rb') as infp:
                fp.write(infp.read())
env=Environment()
Export('env')
env['BUILDERS']['Cat']=Builder(action=cat, multi=1)
SConscript('src/SConscript',variant_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 'pass' in ARGUMENTS 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()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/sconsign/nonwritable.py

#!/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 things still work when a .sconsign* file is not writable.
"""

import os
import TestSCons
import TestCmd
import pickle

test = TestSCons.TestSCons(match = TestCmd.match_re)

test.subdir('work1',
            ['work1', 'sub1'],
            ['work1', 'sub2'],
            ['work1', 'sub3'],
            'work2',
            ['work2', 'sub1'],
            ['work2', 'sub2'],
            ['work2', 'sub3'])

database_name = test.get_sconsignname()
work1__sconsign_dblite = test.workpath('work1', database_name + '.dblite')
work2_sub1__sconsign = test.workpath('work2', 'sub1', database_name)
work2_sub2__sconsign = test.workpath('work2', 'sub2', database_name)
work2_sub3__sconsign = test.workpath('work2', 'sub3', database_name)

SConstruct_contents = """\
def build1(target, source, env):
    with open(str(target[0]), 'wb') as fo, open(str(source[0]), 'rb') as fi:
        fo.write(fi.read())
    return None

def build2(target, source, env):
    import os
    import os.path
    with open(str(target[0]), 'wb') as fo, open(str(source[0]), 'rb') as fi:
        fo.write(fi.read())
    dir, file = os.path.split(str(target[0]))
    os.chmod(dir, 0o555)
    return None

B1 = Builder(action = build1)
B2 = Builder(action = build2)
env = Environment(BUILDERS = { 'B1' : B1, 'B2' : B2 })
env.B1(target = 'sub1/foo.out', source = 'foo.in')
env.B2(target = 'sub2/foo.out', source = 'foo.in')
env.B2(target = 'sub3/foo.out', source = 'foo.in')
"""



test.write(['work1', 'SConstruct'], SConstruct_contents)

test.write(['work1', 'foo.in'], "work1/foo.in\n")

test.write(work1__sconsign_dblite, "")

os.chmod(work1__sconsign_dblite, 0o444)

test.run(chdir='work1', arguments='.')



SConstruct_contents = """\
SConsignFile(None)
""" + SConstruct_contents

test.write(['work2', 'SConstruct'], SConstruct_contents)

test.write(['work2', 'foo.in'], "work2/foo.in\n")

with open(work2_sub1__sconsign, 'wb') as p:
    pickle.dump({}, p, 1)
with open(work2_sub2__sconsign, 'wb') as p:
    pickle.dump({}, p, 1)

os.chmod(work2_sub1__sconsign, 0o444)

test.run(chdir='work2', arguments='.')



test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/site_scons/basic.py

#!/usr/bin/env python
#
# MIT License
#
# Copyright The SCons Foundation
#
# 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.

import TestSCons

"""
Verify basic functionality of the site_scons dir and
site_scons/site_init.py file:
Make sure the site_scons/site_init.py file gets loaded,
and make sure a tool can be loaded from the site_scons/site_tools subdir,
even when executing out of a subdirectory.
"""

test = TestSCons.TestSCons()

test.subdir('site_scons', ['site_scons', 'site_tools'])

test.write(['site_scons', 'site_init.py'], """
from SCons.Script import *
print("Hi there, I am in site_scons/site_init.py!")
""")

test.write(['site_scons', 'site_tools', 'mytool.py'], """
import SCons.Tool
def generate(env):
    env['MYTOOL']='mytool'
def exists(env):
    return 1
""")


test.write('SConstruct', """
e=Environment(tools=['default', 'mytool'])
print(e.subst('My site tool is $MYTOOL'))
""")

test.run(arguments = '-Q .',
         stdout = """Hi there, I am in site_scons/site_init.py!
My site tool is mytool
scons: `.' is up to date.\n""")



test.pass_test()

# end of file

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/site_scons/no-site-dir.py

#!/usr/bin/env python
#
# MIT License
#
# Copyright The SCons Foundation
#
# 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 use of the --no-site-dir option:
the site_scons/site_init.py script should NOT be loaded.
"""

import TestSCons

test = TestSCons.TestSCons()

test.subdir('site_scons', ['site_scons', 'site_tools'])

test.write(['site_scons', 'site_init.py'], """
from SCons.Script import *
print("Hi there, I am in site_scons/site_init.py!")
""")

test.write(['site_scons', 'site_tools', 'mytool.py'], """
import SCons.Tool
def generate(env):
    env['MYTOOL']='mytool'
def exists(env):
    return 1
""")

test.write(['site_scons', 'site_tools', 'm4.py'], """
import SCons.Tool
def generate(env):
    env['M4']='my_m4'
    env['M4_MINE']=1
def exists(env):
    return 1
""")

test.write('SConstruct', """
e=Environment()
""")

test.run(arguments = '-Q --no-site-dir .',
         stdout = "scons: `.' is up to date.\n")

# With --no-site-dir, shouldn't override default m4 tool

test.write('SConstruct', """
e=Environment()
print(e.subst('no site: M4 is $M4, M4_MINE is $M4_MINE'))
""")

test.run(arguments = '-Q --no-site-dir .')

not_expected = """Hi there, I am in site_scons/site_init.py!
no site: M4 is my_m4, M4_MINE is 1
scons: `.' is up to date.
"""

test.fail_test(test.stdout() == not_expected)



test.pass_test()

# end of file

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/site_scons/nonexistent.py

#!/usr/bin/env python
#
# MIT License
#
# Copyright The SCons Foundation
#
# 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 specifying --site-dir= with a nonexistent directory
gives an error and nonzero status.
"""

import TestSCons

test = TestSCons.TestSCons()

test.write('SConstruct', "\n")

test.run(arguments = '-Q --site-dir=whatever .',
         stderr = r".*site dir .*whatever not found.*",
         status = 2, 
         match = TestSCons.match_re_dotall)



test.pass_test()

# end of file

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/site_scons/override.py

#!/usr/bin/env python
#
# MIT License
#
# Copyright The SCons Foundation
#
# 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 that a tool module in site_tools overrides base tool.

Use 'm4' as test tool since it's likely to be found,
and not commonly overridden by platform-specific stuff the way cc is.
"""

import TestSCons

test = TestSCons.TestSCons()

test.subdir('site_scons', ['site_scons', 'site_tools'])

test.write(['site_scons', 'site_tools', 'm4.py'], """
import SCons.Tool
def generate(env):
    env['M4']='my_m4'
    env['M4_MINE']=1
def exists(env):
    return 1
""")

test.write('SConstruct', """
e=Environment(tools=['m4'])
print(e.subst('M4 is $M4, M4_MINE is $M4_MINE'))
""")
test.run(arguments = '-Q .',
         stdout = """M4 is my_m4, M4_MINE is 1
scons: `.' is up to date.\n""")



test.pass_test()

# end of file

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/site_scons/site-dir.py

#!/usr/bin/env python
#
# MIT License
#
# Copyright The SCons Foundation
#
# 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 --site-dir=otherdir loads the site_init.py script from otherdir;
the usual site_scons/site_init.py should NOT be loaded.
Check that a later --no-site-dir turns off site-dir processing
even if a --site-dir option was seen earlier.
"""

import os

import TestSCons

test = TestSCons.TestSCons()

test.subdir('site_scons', ['site_scons', 'site_tools'])

test.write(
    ['site_scons', 'site_init.py'],
    """
from SCons.Script import *
print("Hi there, I am in site_scons/site_init.py!")
""",
)

test.write(
    ['site_scons', 'site_tools', 'mytool.py'],
    """
import SCons.Tool
def generate(env):
    env['MYTOOL']='mytool'
def exists(env):
    return 1
""",
)

test.subdir('alt_site', ['alt_site', 'site_tools'])

test.write(
    ['alt_site', 'site_init.py'],
    """
from SCons.Script import *
print("Hi there, I am in alt_site/site_init.py!")
""",
)

test.write(
    'SConstruct',
    """
e=Environment()
""",
)

test.run(
    arguments='-Q --site-dir=alt_site .',
    stdout="""Hi there, I am in alt_site/site_init.py!
scons: `.' is up to date.\n""",
)


# --site-dir followed by --no-site-dir turns processing off:
test.run(
    arguments="-Q --site-dir=alt_site --no-site-dir .",
    stdout="""scons: `.' is up to date.\n""",
)


# same test, but using SCONSFLAGS
os.environ["SCONSFLAGS"] = "-Q --site-dir=alt_site"
test.run(
    arguments="--no-site-dir .",
    stdout="""scons: `.' is up to date.\n""",
)


test.pass_test()

# end of file

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/site_scons/site_init.py

#!/usr/bin/env python
#
# MIT License
#
# Copyright The SCons Foundation
#
# 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 various aspects of the handling of site_init.py.

And more ..
"""

import TestSCons
import sys
import os.path

test = TestSCons.TestSCons()

test.subdir('site_scons')


def _test_metadata():
    """Test site_init's module metadata.

    The following special variables should be predefined: __doc__,
    __file__ and __name__. No special variables should be transferred from
    SCons.Script.
    """
    test.write(['site_scons', 'site_init.py'], """\
import os.path
import re

special = []
for x in list(globals().keys()):
    if re.match("__[^_]+__", x):
        if x in ("__builtins__", "__package__",):
            # Ignore certain keywords, as they are known to be added by Python
            continue
        special.append(x)

print(sorted(special))
print(__doc__)
print(os.path.realpath(__file__))
print(__name__)
""")

    test.write('SConstruct', "\n")
    test.run(arguments = '-Q .',
             stdout = """\
['__doc__', '__file__', '__name__']
None
%s
site_init
scons: `.' is up to date.
""" % (os.path.realpath(os.path.join('site_scons', 'site_init.py')),))

_test_metadata()


"""
Verify site_scons/site_init.py file can define a tool, and it shows up
automatically in the SCons.Script namespace.
"""

if sys.platform == 'win32':
    cat_cmd='type'
else:
    cat_cmd='cat'

test.write(['site_scons', 'site_init.py'], """
def TOOL_FOO(env):
      env['FOO'] = '%s'
      bld = Builder(action = '$FOO ${SOURCE} > ${TARGET}',
				      suffix = '.tgt')
      env.Append(BUILDERS = {'Foo' : bld})

"""%cat_cmd)

test.write('SConstruct', """
e=Environment(tools=['default', TOOL_FOO])
e.Foo(target='foo.out', source='SConstruct')
""")

test.run(arguments = '-Q .',
         stdout = """%s SConstruct > foo.out\n"""%cat_cmd)


"""
Test errors in site_scons/site_init.py.
"""

test = TestSCons.TestSCons()

test.subdir('site_scons')

test.write(['site_scons', 'site_init.py'], """
raise Exception("Huh?")
""")

test.write('SConstruct', """
e=Environment(tools=['default', TOOL_FOO])
e.Foo(target='foo.out', source='SConstruct')
""")

test.run(arguments = '-Q .',
         stdout = "",
         stderr = r".*Error loading site_init file.*Huh\?.*",
         status=2,
         match=TestSCons.match_re_dotall)



test.pass_test()

# end of file

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/site_scons/sys-path.py

#!/usr/bin/env python
#
# MIT License
#
# Copyright The SCons Foundation
#
# 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 site_scons dir is added to sys.path as an
absolute path, so it will work from a subdir.
"""

import TestSCons

test = TestSCons.TestSCons()

test.subdir('site_scons')
test.subdir('sub1')

test.write(['site_scons', 'testmod1.py'], """
print("Imported site_scons/testmod1.py.")
""")
test.write(['site_scons', 'testmod2.py'], """
print("Imported site_scons/testmod2.py.")
""")

test.write(['sub1', 'SConscript'], """
import testmod2 # This call did not work before the fix

""")

test.write('SConstruct', """
import testmod1 # this always worked
SConscript('sub1/SConscript')
""")

test.run(arguments = '-Q .',
         stdout = """Imported site_scons/testmod1.py.
Imported site_scons/testmod2.py.
scons: `.' is up to date.\n""")

test.pass_test()

# end of file

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/site_scons/sysdirs.py

#!/usr/bin/env python
#
# MIT License
#
# Copyright The SCons Foundation
#
# 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 site_scons system dirs are getting loaded.
Uses an internal test fixture to get at the site_scons dirs.

TODO: it would be great to test if it can actually load site_scons
files from the system dirs, but the test harness can't put files in
those dirs (which may not even exist on a build system).
"""

__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"

import TestSCons

test = TestSCons.TestSCons()

test.write('SConstruct', """
import SCons.Script
SCons.Script.Main.test_load_all_site_scons_dirs(Dir('.').get_internal_path())
""")

test.run(arguments = '-Q .')

import SCons.Platform
platform = SCons.Platform.platform_default()
if platform in ('win32', 'cygwin'):
    dir_to_check_for='Application Data'
elif platform in 'darwin':
    dir_to_check_for='Library'
else:
    dir_to_check_for='.scons'

if 'Loading site dir' not in test.stdout():
    print(test.stdout())
    test.fail_test()
if dir_to_check_for not in test.stdout():
    print(test.stdout())
    test.fail_test()

test.pass_test()

# end of file

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/symlink/VariantDir.py

#!/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__"

"""
XXX Put a description of the test here.
"""

import os

import TestSCons

test = TestSCons.TestSCons()

if not test.platform_has_symlink():
    test.skip_test('No os.symlink() method, no symlinks to test.\n')

test.subdir('obj',
            ['obj', 'subdir'],
            'src',
            'srcdir')

test.write('SConstruct', """
env = Environment()
VariantDir('obj/subdir', 'src')
Program('hello', ['obj/subdir/main.c'])
""")

test.write(['srcdir', 'main.c'], r"""
#include <stdio.h>
#include <stdlib.h>

int
main(int ac, char *argv[])
{
    printf("srcdir/main.c\n");
    exit(0);
}
""")

os.symlink('../srcdir/main.c', 'src/main.c')

test.run(arguments = '.')

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/symlink/dangling-include.py

#!/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 how we handle #includes of dangling symlinks.
"""


import TestSCons

test = TestSCons.TestSCons()

if not test.platform_has_symlink():
    test.skip_test('No os.symlink() method, no symlinks to test.\n')

foo_obj = 'foo' + TestSCons._obj

test.write('SConstruct', """
Program('foo.c')
""")

test.write('foo.c', """\
#include "foo.h"
""")

test.symlink('nonexistent', 'foo.h')

expect = """\
scons: \\*\\*\\* \\[foo.o(bj)?\\] Implicit dependency `foo.h' not found, needed by target `%s'.(  Stop.)?
"""% foo_obj

test.run(arguments = '.', status = 2, stderr = expect, 
         match=TestSCons.match_re_dotall)

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/symlink/dangling-source.py

#!/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 how we handle dangling symlinks as source files.
"""


import TestSCons

test = TestSCons.TestSCons()

if not test.platform_has_symlink():
    test.skip_test('No os.symlink() method, no symlinks to test.\n')

test.write('SConstruct', """
Command('file.out', 'file.in', Copy('$TARGET', '$SOURCE'))
""")

test.symlink('nonexistent', 'file.in')

expect = """\
scons: *** [file.out] Source `file.in' not found, needed by target `file.out'.
"""

test.run(arguments = '.', status = 2, stderr = expect)

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/textfile/issue-3540.py

#!/usr/bin/env python
#
# MIT License
#
# Copyright The SCons Foundation
#
# 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.

"""
Test for GH Issue 3540

textfile()'s action is not sensitive to changes in TEXTFILEPREFIX (rather was sensitive to SUBSTFILEPREFIX)

"""

import TestSCons

test = TestSCons.TestSCons()

test.file_fixture('fixture/substfile.in', 'substfile.in')
test.file_fixture('fixture/SConstruct.issue-3540', 'SConstruct')

test.run()
test.must_exist('substfile')

test.up_to_date(options='text_file_suffix=BLAH')


test.pass_test()


# test/textfile/issue-3550.py

#!/usr/bin/env python
#
# MIT License
#
# Copyright The SCons Foundation
#
# 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.

"""
Test for GH Issue 3550

You can't pass a Windows path in a value to be interpolated, 
because SCons will try to pass it through re.sub which rejects
certain character sequences.
"""

import TestSCons

test = TestSCons.TestSCons()

match_mode = 'r'

test.file_fixture('fixture/SConstruct.issue-3550', 'SConstruct')
test.file_fixture('fixture/substfile.in', 'substfile.in')

test.run(arguments='.')

test.must_match('substfile',
                r'''foo_path: Z:\mongo\build\install\bin
''', mode=match_mode)

test.pass_test()


# test/textfile/issue-4037.py

#!/usr/bin/env python
#
# MIT License
#
# Copyright The SCons Foundation
#
# 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.

"""
Test for GH Issue 4037

The fix for #4031 created a code path where the subst function
used by textfile was called with SUBST_RAW, which, if the items to
subst was a callable, caused it to be called with for_signature=True.
This did not happen previously as the test was "!= SUBST_CMD",
and the mode coming in was indeed SUBST_CMD.
"""

import TestSCons

test = TestSCons.TestSCons()

match_mode = 'r'

test.file_fixture('fixture/SConstruct.issue-4037', 'SConstruct')

test.run(arguments='.')

test.must_match(
    'target.txt',
    "val",
    mode=match_mode,
)

test.pass_test()


# test/textfile/textfile.py

#!/usr/bin/env python
#
# MIT License
#
# Copyright The SCons Foundation
#
# 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.

import TestSCons

import os

test = TestSCons.TestSCons()

# foo1 = test.workpath('foo1.txt')
# foo2  = test.workpath('foo2.txt')
# foo1a = test.workpath('foo1a.txt')
# foo2a = test.workpath('foo2a.txt')

match_mode = 'r'

test.file_fixture('fixture/SConstruct', 'SConstruct')

test.run(arguments='.')

linesep = '\n'

textparts = ['lalala', '42',
             'Goethe', 'Schiller',
             'tanteratei']
foo1Text = linesep.join(textparts)
foo2Text = '|*'.join(textparts)
foo1aText = foo1Text + linesep
foo2aText = foo2Text + '|*'

issue_4021_text = r'<HintPath>..\..\..\NETCore\bin\$(Platform)\$(Configuration)\Datalogics.PDFL.dll</HintPath>'

test.up_to_date(arguments='.')

files = list(map(test.workpath, (
    'foo1.txt', 'foo2.txt', 'foo1a.txt', 'foo2a.txt',
    'bar1', 'bar2', 'bar1a.txt', 'bar2a.txt',
)))


def check_times():
    """
    make sure the files didn't get rewritten, because nothing changed:
    """
    before = list(map(os.path.getmtime, files))
    # introduce a small delay, to make the test valid
    test.sleep()
    # should still be up-to-date
    test.up_to_date(arguments='.')
    after = list(map(os.path.getmtime, files))
    test.fail_test(before != after)


# make sure that the file content is as expected
test.must_match('foo1.txt', foo1Text, mode=match_mode)
test.must_match('bar1', foo1Text, mode=match_mode)
test.must_match('foo2.txt', foo2Text, mode=match_mode)
test.must_match('bar2', foo2Text, mode=match_mode)
test.must_match('foo1a.txt', foo1aText, mode=match_mode)
test.must_match('bar1a.txt', foo1aText, mode=match_mode)
test.must_match('foo2a.txt', foo2aText, mode=match_mode)
test.must_match('bar2a.txt', foo2aText, mode=match_mode)
test.must_match('issue-4021.txt', issue_4021_text, mode=match_mode)
check_times()

# write the contents and make sure the files
# didn't get rewritten, because nothing changed:
test.write('foo1.txt', foo1Text)
test.write('bar1', foo1Text)
test.write('foo2.txt', foo2Text)
test.write('bar2', foo2Text)
test.write('foo1a.txt', foo1aText)
test.write('bar1a.txt', foo1aText)
test.write('foo2a.txt', foo2aText)
test.write('bar2a.txt', foo2aText)
check_times()

# now that textfile is part of default tool list, run one testcase
# without adding it explicitly as a tool to make sure.
test.file_fixture('fixture/SConstruct.2', 'SConstruct.2')

test.run(options='-f SConstruct.2', arguments='.')

line1 = 'This line has no substitutions'
line2a = 'This line has @subst@ substitutions'
line2b = 'This line has most substitutions'
line3a = 'This line has %subst% substitutions'
line3b = 'This line has many substitutions'


def matchem(match_file, lines):
    """
    Join all the lines with correct line separator,
    then compare
    """
    lines = linesep.join(lines)
    test.must_match(match_file, lines, mode=match_mode, message="Expected:\n%s\n" % lines)


matchem('text.txt', [line1, line2a, line3a])
matchem('sub1', [line1, line2a, line3a])
matchem('sub2', [line1, line2b, line3a])
matchem('sub3', [line1, line2b, line3b])
matchem('sub4', [line1, line2a, line3b])
matchem('sub5', [line1, line2b, line3b])
matchem('sub6', [line1, line2b, line3b])

test.up_to_date(options='-f SConstruct.2', arguments='.')

test.pass_test()


# test/toolpath/VariantDir.py

#!/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 toolpath works with VariantDir() for an SConscript.
"""

import TestSCons

test = TestSCons.TestSCons()

test.subdir('subdir', ['subdir', 'src'], ['subdir', 'src', 'tools'])

test.write('SConstruct', """\
VariantDir('build', 'subdir', duplicate=0)
SConscript('build/SConscript')
""")

test.write(['subdir', 'SConscript'], """\
env = Environment(tools = ['MyBuilder'], toolpath = ['src/tools'])
env.MyCopy('src/file.out', 'src/file.in')
""")

test.write(['subdir', 'src', 'file.in'], "subdir/src/file.in\n")

test.write(['subdir', 'src', 'tools', 'MyBuilder.py'], """\
from SCons.Script import Builder
def generate(env):
    def my_copy(target, source, env):
        with open(str(target[0]), 'wb') as f, open(str(source[0]), 'rb') as ifp:
            f.write(ifp.read())
    env['BUILDERS']['MyCopy'] = Builder(action = my_copy)

def exists(env):
    return 1
""")

test.run()

test.must_match(['build', 'src', 'file.out'], "subdir/src/file.in\n")

# We should look for the underlying tool in both the build/src/tools
# (which doesn't exist) and subdir/src/tools (which still does).  If we
# don't, the following would fail because the execution directory is
# now relative to the created VariantDir.
test.run()

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/toolpath/basic.py

#!/usr/bin/env python
#
# __COPYRIGHT__
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#

__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"


import TestSCons

test = TestSCons.TestSCons()

test.write('SConstruct', """
def foo(env):
    env['TOOL_FOO'] = 1

env1 = Environment(tools=[foo, 'bar'], toolpath=['tools'])
print("env1['TOOL_FOO'] = %s"%env1.get('TOOL_FOO'))
print("env1['TOOL_BAR'] = %s"%env1.get('TOOL_BAR'))

# pick a built-in tool with pretty simple behavior
env2 = Environment(tools=['zip'])
print("env2['ZIP'] = %s"%env2.get('ZIP'))
print("env2['TOOL_zip1'] = %s"%env2.get('TOOL_zip1'))
print("env2['TOOLDIR_zip'] = %s"%env2.get('TOOLDIR_zip'))

# Only find tools in current dir, or Scons.Tool.TOOLNAME
env3 = Environment(tools=['zip'], toolpath=['.'])
print("env3['ZIP'] = %s"%env3.get('ZIP'))
print("env3['TOOL_zip1'] = %s"%env3.get('TOOL_zip1'))
print("env3['TOOLDIR_zip'] = %s"%env3.get('TOOLDIR_zip'))

env4 = Environment(tools=['zip'], toolpath=['tools'])
print("env4['ZIP'] = %s"%env4.get('ZIP'))
print("env4['TOOL_zip1'] = %s"%env4.get('TOOL_zip1'))
print("env4['TOOLDIR_zip'] = %s"%env4.get('TOOLDIR_zip'))

# Should pick up from tools dir, and then current dir
env5 = Environment(tools=['zip'], toolpath=['tools', '.'])
print("env5['ZIP'] = %s"%env5.get('ZIP'))
print("env5['TOOL_zip1'] = %s"%env5.get('TOOL_zip1'))
print("env5['TOOLDIR_zip'] = %s"%env5.get('TOOLDIR_zip'))


# Should pick up from current dir, and then tools dir
env6 = Environment(tools=['zip'], toolpath=['.', 'tools'])
print("env6['ZIP'] = %s"%env6.get('ZIP'))
print("env6['TOOL_zip1'] = %s"%env6.get('TOOL_zip1'))
print("env6['TOOLDIR_zip'] = %s"%env6.get('TOOLDIR_zip'))

env7 = Environment(TOOLPATH="tools", tools=['zip'], toolpath=['$TOOLPATH'])
print("env7['ZIP'] = %s"%env7.get('ZIP'))
print("env7['TOOL_zip1'] = %s"%env7.get('TOOL_zip1'))
print("env7['TOOLDIR_zip'] = %s"%env7.get('TOOLDIR_zip'))

env8 = Environment(tools=[])
env8.Tool('zip', toolpath=['tools'])
print("env8['ZIP'] = %s"%env8.get('ZIP'))
print("env8['TOOL_zip1'] = %s"%env8.get('TOOL_zip1'))
print("env8['TOOLDIR_zip'] = %s"%env8.get('TOOLDIR_zip'))

env9 = Environment(tools=[])
Tool('zip', toolpath=['tools'])(env9)
print("env9['ZIP'] = %s"%env9.get('ZIP'))
print("env9['TOOL_zip1'] = %s"%env9.get('TOOL_zip1'))
print("env9['TOOLDIR_zip'] = %s"%env9.get('TOOLDIR_zip'))

env0 = Environment(TOOLPATH='tools', tools=[])
env0.Tool('zip', toolpath=['$TOOLPATH'])
print("env0['ZIP'] = %s"%env0.get('ZIP'))
print("env0['TOOL_zip1'] = %s"%env0.get('TOOL_zip1'))
print("env0['TOOLDIR_zip'] = %s"%env0.get('TOOLDIR_zip'))

base = Environment(tools=[], toolpath=['tools'])
derived = base.Clone(tools=['bar'])
print("derived['TOOL_BAR'] = %s"%derived.get('TOOL_BAR'))
""")

test.write('zip.py', r"""
def generate(env):
    env['TOOL_zip1'] = 1
def exists(env):
    return 1
""",mode='w')

test.subdir('tools')

test.write(['tools', 'Common.py'], r"""\
One = 1
""")

test.write(['tools', 'zip.py'], r"""\
import Common
def generate(env):
    env['TOOLDIR_zip'] = Common.One
def exists(env):
    return Common.One
""")

test.write(['tools', 'bar.py'], r"""\
def generate(env):
    env['TOOL_BAR'] = 1
def exists(env):
    return 1
""")

test.run(arguments = '.', stdout = """\
scons: Reading SConscript files ...
env1['TOOL_FOO'] = 1
env1['TOOL_BAR'] = 1
env2['ZIP'] = zip
env2['TOOL_zip1'] = None
env2['TOOLDIR_zip'] = None
env3['ZIP'] = None
env3['TOOL_zip1'] = 1
env3['TOOLDIR_zip'] = None
env4['ZIP'] = None
env4['TOOL_zip1'] = None
env4['TOOLDIR_zip'] = 1
env5['ZIP'] = None
env5['TOOL_zip1'] = None
env5['TOOLDIR_zip'] = 1
env6['ZIP'] = None
env6['TOOL_zip1'] = 1
env6['TOOLDIR_zip'] = None
env7['ZIP'] = None
env7['TOOL_zip1'] = None
env7['TOOLDIR_zip'] = 1
env8['ZIP'] = None
env8['TOOL_zip1'] = None
env8['TOOLDIR_zip'] = 1
env9['ZIP'] = None
env9['TOOL_zip1'] = None
env9['TOOLDIR_zip'] = 1
env0['ZIP'] = None
env0['TOOL_zip1'] = None
env0['TOOLDIR_zip'] = 1
derived['TOOL_BAR'] = 1
scons: done reading SConscript files.
scons: Building targets ...
scons: `.' is up to date.
scons: done building targets.
""")

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/update-release-info/update-release-info.py

#!/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.
"""
Test bin/update-release-info.py.  Also verify that the original files
have the appropriate triggers to cause the modifications.
"""

__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"

import os
import time

import TestRuntest

# Needed to ensure we're using the correct year
this_year = time.localtime()[0]

TestSCons = 'testing/framework/TestSCons.py'.split('/')
README = 'README.rst'.split('/')
README_SF = 'README-SF.rst'.split('/')

ReleaseConfig = 'ReleaseConfig'.split('/')
CHANGES = 'CHANGES.txt'.split('/')
RELEASE = 'RELEASE.txt'.split('/')
Main = 'SCons/Script/Main.py'.split('/')
main_in = 'doc/user/main.in'.split('/')
main_xml = 'doc/user/main.xml'.split('/')

test = TestRuntest.TestRuntest(
    program=os.path.join('bin', 'update-release-info.py'),
    things_to_copy=['bin', 'template']
)
if not os.path.exists(test.program):
    test.skip_test("update-release-info.py is not distributed in this package\n")

expected_stderr = """usage: update-release-info.py [-h] [--verbose] [--timestamp TIMESTAMP]
                              [{develop,release,post}]
update-release-info.py: error: argument mode: invalid choice: 'bad' (choose from 'develop', 'release', 'post')
"""
test.run(arguments='bad', stderr=expected_stderr, status=2)

# Strings to go in ReleaseConfig
combo_strings = [
    # Index 0: version tuple with bad release level
    """version_tuple = (2, 0, 0, 'bad', 0)\n""",
    # Index 1: Python version tuple
    """unsupported_python_version = (2, 6)\n""",
    # Index 2: Python version tuple
    """deprecated_python_version  = (2, 7)\n""",
    # Index 3: alpha version tuple
    """version_tuple = (2, 0, 0, 'a', 0)\n""",
    # Index 4: final version tuple
    """version_tuple = (2, 0, 0, 'final', 0)\n""",
    # Index 5: bad release date
    """release_date = (%d, 12)\n""" % this_year,
    # Index 6: release date (hhhh, mm, dd)
    """release_date = (%d, 12, 21)\n""" % this_year,
    # Index 7: release date (hhhh, mm, dd, hh, mm, ss)
    """release_date = (%d, 12, 21, 12, 21, 12)\n""" % this_year,
]

combo_error = \
    """ERROR: Config file must contain at least version_tuple,
\tunsupported_python_version, and deprecated_python_version.\n"""


def combo_fail(*args, **kw):
    kw.setdefault('status', 1)
    combo_run(*args, **kw)


def combo_run(*args, **kw):
    t = '\n'
    for a in args:
        t += combo_strings[a]

    test.write(ReleaseConfig, t)

    kw.setdefault('stdout', combo_error)
    test.run(**kw)


combo_fail()
combo_fail(0)
combo_fail(1)
combo_fail(2)
combo_fail(0, 1)
combo_fail(0, 2)
combo_fail(1, 2)
combo_fail(0, 1, 2, stdout=
"""ERROR: `bad' is not a valid release type in version tuple;
\tit must be one of a, b, rc, or final\n""")

# We won't need this entry again, so put in a default
combo_strings[0] = combo_strings[1] + combo_strings[2] + combo_strings[3]

combo_fail(0, 5, stdout=
"""ERROR: Invalid release date (%d, 12)
""" % this_year)


def pave(path):
    path = path[:-1]
    if not path or os.path.isdir(os.path.join(*path)):
        return
    pave(path)
    test.subdir(path)


def pave_write(file, contents):
    pave(file)
    test.write(file, contents)


pave_write(CHANGES, """
RELEASE  It doesn't matter what goes here...
""")

pave_write(RELEASE, """
This file has a 3.2.1.beta.20121221 version string in it
""")


pave_write(README, """
These files are a part of 33.22.11:
        scons-33.22.11.tar.gz
        scons-33.22.11.zip

        scons-33.22.11.b.20012122112.suffix
""")

pave_write(README_SF, """
These files are a part of 33.22.11:
        scons-33.22.11.tar.gz
        scons-33.22.11.zip

        scons-33.22.11.b.20012122112.suffix
""")

pave_write(TestSCons, """
copyright_years = Some junk to be overwritten
default_version = More junk
python_version_unsupported = Yep, more junk
python_version_deprecated = And still more
""")

pave_write(Main, """
unsupported_python_version = Not done with junk
deprecated_python_version = It goes on forever
""")

pave_write(main_in, """
TODO
""")

pave_write(main_xml, """
TODO
""")


def updating_run(*args):
    stdout = ''
    for file in args:
        stdout += 'Updating %s...\n' % os.path.join(*file)
    combo_run(0, 7, stdout=stdout, arguments=['--timestamp=yyyymmdd'])


updating_run(ReleaseConfig, CHANGES, RELEASE, README, README_SF,  TestSCons, Main)

test.must_match(CHANGES, """
RELEASE  VERSION/DATE TO BE FILLED IN LATER

      From John Doe:

        - Whatever John Doe did.


RELEASE  It doesn't matter what goes here...
""", mode='r')

test.must_exist(RELEASE)
# TODO Fix checking contents
# test.must_match(RELEASE, """
# This file has a 2.0.0.devyyyymmdd version string in it
# """, mode='r')


years = '2001 - %d' % (this_year + 1)

test.must_match(README, """
These files are a part of 33.22.11:
        scons-2.1.0ayyyymmdd.tar.gz
        scons-2.1.0ayyyymmdd.zip

        scons-2.1.0ayyyymmdd.suffix
""", mode='r')

test.must_match(README_SF, """
These files are a part of 33.22.11:
        scons-2.1.0ayyyymmdd.tar.gz
        scons-2.1.0ayyyymmdd.zip

        scons-2.1.0ayyyymmdd.suffix
""", mode='r')

# should get Python floors from TestSCons module.
test.must_match(TestSCons, """
copyright_years = '%s'
default_version = '2.1.0ayyyymmdd'
python_version_unsupported = (2, 6)
python_version_deprecated = (2, 7)
""" % years, mode='r')

# should get Python floors from TestSCons module.
test.must_match(Main, """
unsupported_python_version = (2, 6)
deprecated_python_version = (2, 7)
""", mode='r')

# TODO: Release option
# TODO: ==============
# TODO:
# TODO: Dates in beta/candidate flow
# TODO:
# TODO: Dates in final flow
# TODO:
# TODO: Post option
# TODO: ===========
# TODO:
# TODO: Dates in post flow
# TODO:
# TODO: Update minor or micro version
# TODO:
# TODO: ReleaseConfig - new version tuple
# TODO:
# TODO: CHANGES - new section
# TODO:
# TODO: RELEASE - new template
# TODO:

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# bootstrap.py

#!/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.

"""bootstrap.py

Execute SCons from this source tree. It copies Python scripts and modules
from src/ subdirectory into a subdirectory named "bootstrap/" (by default),
and executes SCons from there with the supplied command-line arguments.

This is a minimal build of SCons to bootstrap the full build of all the
packages, as specified in our local SConstruct file.

Some options are specific to this bootstrap.py script and are *not* passed
on to the SCons script. All of these begin with the string "bootstrap_":

    --bootstrap_dir=DIR

        Sets the name of the directory into which the SCons files will
        be copied.  The default is "bootstrap" in the local subdirectory.

    --bootstrap_force

        Forces a copy of all necessary files.  By default, the
        bootstrap.py script only updates the bootstrap copy if the
        content of the source copy is different.

    --bootstrap_src=DIR

        Searches for the SCons files relative to the specified DIR,
        then relative to the directory in which this bootstrap.py
        script is found.

    --bootstrap_update

        Only updates the bootstrap subdirectory, and then exits.

In addition to the above, the bootstrap.py script understands
the following SCons options:

    -C, --directory

        Changes to the specified directory before invoking SCons.
        Because we change directory right away to the specified directory,
        the SCons script itself doesn't need to, so this option gets
        "eaten" by the bootstrap.py script.
"""

import os
import os.path
import sys
import glob
import subprocess
import filecmp
import shutil

def parseManifestLines(basedir, manifest):
    """
    Scans a MANIFEST file, and returns the list of source files.

    Has basic support for recursive globs '**',
    filename wildcards of the form '*.xml' and
    comment lines, starting with a '#'.

    :param basedir: base path to find files in. Note this does not
                    run in an SCons context so path must not need
                    further processing (e.g. no '#' signs)
    :param manifest: path to manifest file
    :returns: list of files
    """
    sources = []
    basewd = os.path.abspath(basedir)
    with open(manifest) as m:
        lines = m.readlines()
    for l in lines:
        if l.startswith('#'):
            # Skip comments
            continue
        l = l.rstrip('\n')
        if l.endswith('**'):
            # Glob all files recursively
            globwd = os.path.dirname(os.path.join(basewd, l))
            for path, dirs, files in os.walk(globwd):
                for f in files:
                    fpath = os.path.join(globwd, path, f)
                    sources.append(os.path.relpath(fpath, basewd))
        elif '*' in l:
            # Glob file pattern
            files = glob.glob(os.path.join(basewd, l))
            for f in files:
                sources.append(os.path.relpath(f, basewd))
        else:
            sources.append(l)

    return sources

def main():
    script_dir = os.path.abspath(os.path.dirname(__file__))

    bootstrap_dir = os.path.join(script_dir, 'bootstrap')

    pass_through_args = []
    update_only = None

    requires_an_argument = 'bootstrap.py:  %s requires an argument\n'

    search = [script_dir]

    def find(filename, search=search):
        for dir_name in search:
            filepath = os.path.join(dir_name, filename)
            if os.path.exists(filepath):
                return os.path.normpath(filepath)
        sys.stderr.write("could not find `%s' in search path:\n" % filename)
        sys.stderr.write("\t" + "\n\t".join(search) + "\n")
        sys.exit(2)

    def must_copy(dst, src):
        if not os.path.exists(dst):
            return 1
        return not filecmp.cmp(dst,src)

    # Note:  We don't use the getopt module to process the command-line
    # arguments because we'd have to teach it about all of the SCons options.

    command_line_args = sys.argv[1:]

    while command_line_args:
        arg = command_line_args.pop(0)

        if arg == '--bootstrap_dir':
            try:
                bootstrap_dir = command_line_args.pop(0)
            except IndexError:
                sys.stderr.write(requires_an_argument % arg)
                sys.exit(1)
        elif arg[:16] == '--bootstrap_dir=':
            bootstrap_dir = arg[16:]
        elif arg == '--bootstrap_force':
            def must_copy(dst, src):
                return 1
        elif arg == '--bootstrap_src':
            try:
                search.insert(0, command_line_args.pop(0))
            except IndexError:
                sys.stderr.write(requires_an_argument % arg)
                sys.exit(1)
        elif arg[:16] == '--bootstrap_src=':
            search.insert(0, arg[16:])
        elif arg == '--bootstrap_update':
            update_only = 1
        elif arg in ('-C', '--directory'):
            try:
                dir = command_line_args.pop(0)
            except IndexError:
                sys.stderr.write(requires_an_argument % arg)
                sys.exit(1)
            else:
                os.chdir(dir)
        elif arg[:2] == '-C':
            os.chdir(arg[2:])
        elif arg[:12] == '--directory=':
            os.chdir(arg[12:])
        else:
            pass_through_args.append(arg)

    scons_py = os.path.join('scripts', 'scons.py')
    src_engine = os.path.join('src', 'engine')
    MANIFEST_in = find(os.path.join(src_engine, 'MANIFEST.in'))
    manifest_files = [os.path.join(src_engine, x)
                      for x in parseManifestLines(os.path.join(script_dir, src_engine),
                                                  MANIFEST_in)]

    files = [scons_py] + manifest_files

    for filename in files:
        src = find(filename)
        dst = os.path.join(bootstrap_dir, filename)
        if must_copy(dst, src):
            dir = os.path.split(dst)[0]
            if not os.path.isdir(dir):
                os.makedirs(dir)
            try:
                os.unlink(dst)
            except Exception as e:
                pass

            shutil.copyfile(src, dst)

    if update_only:
        sys.exit(0)

    args = [sys.executable, os.path.join(bootstrap_dir, scons_py)] + pass_through_args

    sys.stdout.write(" ".join(args) + '\n')
    sys.stdout.flush()

    os.environ['SCONS_LIB_DIR'] = os.path.join(bootstrap_dir, src_engine)

    sys.exit(subprocess.Popen(args, env=os.environ).wait())


if __name__ == "__main__":
    print("Please use")
    print("python scripts/scons.py")
    print("Instead of python bootstrap.py. Bootstrap.py is obsolete")
    sys.exit(-1)
    main()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# runtest.py

#!/usr/bin/env python
#
# Copyright The SCons Foundation
#
"""runtest - wrapper script for running SCons tests

The SCons test suite consists of:

 * unit tests        - *Tests.py files from the SCons/ dir
 * end-to-end tests  - *.py files in the test/ directory that
                       require the custom SCons framework from testing/

This script adds SCons/ and testing/ directories to PYTHONPATH,
performs test discovery and processes tests according to options.
"""

# TODO: normalize requested and testlist/exclude paths for easier comparison.
# e.g.: "runtest foo/bar" on windows will produce paths like foo/bar\test.py
# this is hard to match with excludelists, and makes those both os.sep-specific
# and command-line-typing specific.

import argparse
import glob
import os
import re
import stat
import subprocess
import sys
import tempfile
import threading
import time
from abc import ABC, abstractmethod
from pathlib import Path
from queue import Queue

cwd = os.getcwd()

debug = None
scons = None
catch_output = False
suppress_output = False

script = os.path.basename(sys.argv[0])
usagestr = """\
%(script)s [OPTIONS] [TEST ...]
""" % locals()

epilogstr = """\
Environment Variables:
  PRESERVE, PRESERVE_{PASS,FAIL,NO_RESULT}: preserve test subdirs
  TESTCMD_VERBOSE: turn on verbosity in TestCommand\
"""

parser = argparse.ArgumentParser(
    usage=usagestr, epilog=epilogstr, allow_abbrev=False,
    formatter_class=argparse.RawDescriptionHelpFormatter
)

# test selection options:
testsel = parser.add_argument_group(description='Test selection options:')
testsel.add_argument(metavar='TEST', nargs='*', dest='testlist',
                     help="Select TEST(s) (tests and/or directories) to run")
testlisting = testsel.add_mutually_exclusive_group()
testlisting.add_argument('-f', '--file', metavar='FILE', dest='testlistfile',
                     help="Select only tests in FILE")
testlisting.add_argument('-a', '--all', action='store_true',
                     help="Select all tests")
testlisting.add_argument('--retry', action='store_true',
                     help="Rerun the last failed tests in 'failed_tests.log'")
testsel.add_argument('--exclude-list', metavar="FILE", dest='excludelistfile',
                     help="""Exclude tests in FILE from current selection""")
testtype = testsel.add_mutually_exclusive_group()
testtype.add_argument('--e2e-only', action='store_true',
                      help="Exclude unit tests from selection")
testtype.add_argument('--unit-only', action='store_true',
                      help="Exclude end-to-end tests from selection")

# miscellaneous options
parser.add_argument('-b', '--baseline', metavar='BASE',
                    help="Run test scripts against baseline BASE.")
parser.add_argument('-d', '--debug', action='store_true',
                    help="Run test scripts under the Python debugger.")
parser.add_argument('-D', '--devmode', action='store_true',
                    help="Run tests in Python's development mode (Py3.7+ only).")
parser.add_argument('-e', '--external', action='store_true',
                    help="Run the script in external mode (for external Tools)")
parser.add_argument('-j', '--jobs', metavar='JOBS', default=1, type=int,
                    help="Run tests in JOBS parallel jobs (0 for cpu_count).")
parser.add_argument('-l', '--list', action='store_true', dest='list_only',
                    help="List available tests and exit.")
parser.add_argument('-n', '--no-exec', action='store_false',
                    dest='execute_tests',
                    help="No execute, just print command lines.")
parser.add_argument('--nopipefiles', action='store_false',
                    dest='allow_pipe_files',
                    help="""Do not use the "file pipe" workaround for subprocess
                           for starting tests. See source code for warnings.""")
parser.add_argument('-P', '--python', metavar='PYTHON',
                    help="Use the specified Python interpreter.")
parser.add_argument('--quit-on-failure', action='store_true',
                    help="Quit on any test failure.")
parser.add_argument('--runner', metavar='CLASS',
                    help="Test runner class for unit tests.")
parser.add_argument('-X', dest='scons_exec', action='store_true',
                    help="Test script is executable, don't feed to Python.")
parser.add_argument('-x', '--exec', metavar="SCRIPT",
                    help="Test using SCRIPT as path to SCons.")
parser.add_argument('--faillog', dest='error_log', metavar="FILE",
                    default='failed_tests.log',
                    help="Log failed tests to FILE (enabled by default, "
                         "default file 'failed_tests.log')")
parser.add_argument('--no-faillog', dest='error_log',
                    action='store_const', const=None,
                    default='failed_tests.log',
                    help="Do not log failed tests to a file")

parser.add_argument('--no-ignore-skips', dest='dont_ignore_skips',
                    action='store_true',
                    default=False,
                    help="If any tests are skipped, exit status 2")

outctl = parser.add_argument_group(description='Output control options:')
outctl.add_argument('-k', '--no-progress', action='store_false',
                    dest='print_progress',
                    help="Suppress count and progress percentage messages.")
outctl.add_argument('--passed', action='store_true',
                    dest='print_passed_summary',
                    help="Summarize which tests passed.")
outctl.add_argument('-q', '--quiet', action='store_false',
                    dest='printcommand',
                    help="Don't print the test being executed.")
outctl.add_argument('-s', '--short-progress', action='store_true',
                    help="""Short progress, prints only the command line
                             and a progress percentage.""")
outctl.add_argument('-t', '--time', action='store_true', dest='print_times',
                    help="Print test execution time.")
outctl.add_argument('--verbose', metavar='LEVEL', type=int, choices=range(1, 4),
                    help="""Set verbose level
                             (1=print executed commands,
                             2=print commands and non-zero output,
                             3=print commands and all output).""")
# maybe add?
# outctl.add_argument('--version', action='version', version='%s 1.0' % script)

logctl = parser.add_argument_group(description='Log control options:')
logctl.add_argument('-o', '--output', metavar='LOG', help="Save console output to LOG.")
logctl.add_argument('--xml', metavar='XML', help="Save results to XML in SCons XML format.")

# process args and handle a few specific cases:
args = parser.parse_args()

# we can't do this check with an argparse exclusive group, since those
# only work with optional args, and the cmdline tests (args.testlist)
# are not optional args,
if args.testlist and (args.testlistfile or args.all or args.retry):
    sys.stderr.write(
        parser.format_usage()
        + "error: command line tests cannot be combined with -f/--file, -a/--all or --retry\n"
    )
    sys.exit(1)

if args.retry:
    args.testlistfile = 'failed_tests.log'

if args.testlistfile:
    # args.testlistfile changes from a string to a pathlib Path object
    try:
        p = Path(args.testlistfile)
        # TODO simplify when Py3.5 dropped
        if sys.version_info.major == 3 and sys.version_info.minor < 6:
            args.testlistfile = p.resolve()
        else:
            args.testlistfile = p.resolve(strict=True)
    except FileNotFoundError:
        sys.stderr.write(
            parser.format_usage()
            + 'error: -f/--file testlist file "%s" not found\n' % p
        )
        sys.exit(1)

if args.excludelistfile:
    # args.excludelistfile changes from a string to a pathlib Path object
    try:
        p = Path(args.excludelistfile)
        # TODO simplify when Py3.5 dropped
        if sys.version_info.major == 3 and sys.version_info.minor < 6:
            args.excludelistfile = p.resolve()
        else:
            args.excludelistfile = p.resolve(strict=True)
    except FileNotFoundError:
        sys.stderr.write(
            parser.format_usage()
            + 'error: --exclude-list file "%s" not found\n' % p
        )
        sys.exit(1)

if args.jobs == 0:
    try:
        # on Linux, check available rather then physical CPUs
        args.jobs = len(os.sched_getaffinity(0))
    except AttributeError:
        # Windows
        args.jobs = os.cpu_count()

# sanity check
if args.jobs == 0:
    sys.stderr.write(
        parser.format_usage()
        + "Unable to detect CPU count, give -j a non-zero value\n"
    )
    sys.exit(1)

if args.jobs > 1 or args.output:
    # 1. don't let tests write stdout/stderr directly if multi-job,
    # else outputs will interleave and be hard to read.
    # 2. If we're going to write a logfile, we also need to catch the output.
    catch_output = True

if not args.printcommand:
    suppress_output = catch_output = True

if args.verbose:
    os.environ['TESTCMD_VERBOSE'] = str(args.verbose)

if args.short_progress:
    args.print_progress = True
    suppress_output = catch_output = True

if args.debug:
    # TODO: add a way to pass a specific debugger
    debug = "pdb"

if args.exec:
    scons = args.exec

# --- setup stdout/stderr ---
class Unbuffered:
    def __init__(self, file):
        self.file = file

    def write(self, arg):
        self.file.write(arg)
        self.file.flush()

    def __getattr__(self, attr):
        return getattr(self.file, attr)

sys.stdout = Unbuffered(sys.stdout)
sys.stderr = Unbuffered(sys.stderr)

# possible alternative: switch to using print, and:
# print = functools.partial(print, flush)

if args.output:
    class Tee:
        def __init__(self, openfile, stream):
            self.file = openfile
            self.stream = stream

        def write(self, data):
            self.file.write(data)
            self.stream.write(data)

        def flush(self, data):
            self.file.flush(data)
            self.stream.flush(data)

    logfile = open(args.output, 'w')
    # this is not ideal: we monkeypatch stdout/stderr a second time
    # (already did for Unbuffered), so here we can't easily detect what
    # state we're in on closedown. Just hope it's okay...
    sys.stdout = Tee(logfile, sys.stdout)
    sys.stderr = Tee(logfile, sys.stderr)

# --- define helpers ----
if sys.platform == 'win32':
    # thanks to Eryk Sun for this recipe
    import ctypes

    shlwapi = ctypes.OleDLL('shlwapi')
    shlwapi.AssocQueryStringW.argtypes = (
        ctypes.c_ulong,  # flags
        ctypes.c_ulong,  # str
        ctypes.c_wchar_p,  # pszAssoc
        ctypes.c_wchar_p,  # pszExtra
        ctypes.c_wchar_p,  # pszOut
        ctypes.POINTER(ctypes.c_ulong),  # pcchOut
    )

    ASSOCF_NOTRUNCATE = 0x00000020
    ASSOCF_INIT_IGNOREUNKNOWN = 0x00000400
    ASSOCSTR_COMMAND = 1
    ASSOCSTR_EXECUTABLE = 2
    E_POINTER = ctypes.c_long(0x80004003).value

    def get_template_command(filetype, verb=None):
        flags = ASSOCF_INIT_IGNOREUNKNOWN | ASSOCF_NOTRUNCATE
        assoc_str = ASSOCSTR_COMMAND
        cch = ctypes.c_ulong(260)
        while True:
            buf = (ctypes.c_wchar * cch.value)()
            try:
                shlwapi.AssocQueryStringW(
                    flags, assoc_str, filetype, verb, buf, ctypes.byref(cch)
                )
            except OSError as e:
                if e.winerror != E_POINTER:
                    raise
                continue
            break
        return buf.value


_ws = re.compile(r'\s')

def escape(s):
    if _ws.search(s):
        s = '"' + s + '"'
    s = s.replace('\\', '\\\\')
    return s


if not catch_output:
    # Without any output suppressed, we let the subprocess
    # write its stuff freely to stdout/stderr.

    def spawn_it(command_args, env):
        cp = subprocess.run(command_args, shell=False, env=env)
        return cp.stdout, cp.stderr, cp.returncode

else:
    # Else, we catch the output of both pipes...
    if args.allow_pipe_files:
        # The subprocess.Popen() suffers from a well-known
        # problem. Data for stdout/stderr is read into a
        # memory buffer of fixed size, 65K which is not very much.
        # When it fills up, it simply stops letting the child process
        # write to it. The child will then sit and patiently wait to
        # be able to write the rest of its output. Hang!
        # In order to work around this, we follow a suggestion
        # by Anders Pearson in
        #   https://thraxil.org/users/anders/posts/2008/03/13/Subprocess-Hanging-PIPE-is-your-enemy/
        # and pass temp file objects to Popen() instead of the ubiquitous
        # subprocess.PIPE.

        def spawn_it(command_args, env):
            # Create temporary files
            tmp_stdout = tempfile.TemporaryFile(mode='w+t')
            tmp_stderr = tempfile.TemporaryFile(mode='w+t')
            # Start subprocess...
            cp = subprocess.run(
                command_args,
                stdout=tmp_stdout,
                stderr=tmp_stderr,
                shell=False,
                env=env,
            )

            try:
                # Rewind to start of files
                tmp_stdout.seek(0)
                tmp_stderr.seek(0)
                # Read output
                spawned_stdout = tmp_stdout.read()
                spawned_stderr = tmp_stderr.read()
            finally:
                # Remove temp files by closing them
                tmp_stdout.close()
                tmp_stderr.close()

            # Return values
            return spawned_stderr, spawned_stdout, cp.returncode

    else:
        # We get here only if the user gave the '--nopipefiles'
        # option, meaning the "temp file" approach for
        # subprocess.communicate() above shouldn't be used.
        # He hopefully knows what he's doing, but again we have a
        # potential deadlock situation in the following code:
        #   If the subprocess writes a lot of data to its stderr,
        #   the pipe will fill up (nobody's reading it yet) and the
        #   subprocess will wait for someone to read it.
        #   But the parent process is trying to read from stdin
        #   (but the subprocess isn't writing anything there).
        #   Hence a deadlock.
        # Be dragons here! Better don't use this!

        def spawn_it(command_args, env):
            cp = subprocess.run(
                command_args,
                stdout=subprocess.PIPE,
                stderr=subprocess.PIPE,
                shell=False,
                env=env,
            )
            return cp.stdout, cp.stderr, cp.returncode


class RuntestBase(ABC):
    """ Base class for tests """
    def __init__(self, path, num, spe=None):
        self.path = path
        self.num = num
        self.stdout = self.stderr = self.status = None
        self.abspath = os.path.abspath(path)
        self.command_args = []
        self.command_str = ""
        self.test_time = self.total_time = 0
        if spe:
            for d in spe:
                f = os.path.join(d, path)
                if os.path.isfile(f):
                    self.abspath = f
                    break

    @abstractmethod
    def execute(self):
        pass


class SystemExecutor(RuntestBase):
    """ Test class for tests executed with spawn_it() """
    def execute(self, env):
        self.stderr, self.stdout, s = spawn_it(self.command_args, env)
        self.status = s
        if s < 0 or s > 2:
            sys.stdout.write("Unexpected exit status %d\n" % s)


class PopenExecutor(RuntestBase):
    """ Test class for tests executed with Popen

    A bit of a misnomer as the Popen call is now wrapped
    by calling subprocess.run (behind the covers uses Popen.
    Very similar to SystemExecutor, but uses command_str
    instead of command_args, and doesn't allow for not catching
    the output).
    """
    # For an explanation of the following 'if ... else'
    # and the 'allow_pipe_files' option, please check out the
    # definition of spawn_it() above.
    if args.allow_pipe_files:

        def execute(self, env):
            # Create temporary files
            tmp_stdout = tempfile.TemporaryFile(mode='w+t')
            tmp_stderr = tempfile.TemporaryFile(mode='w+t')
            # Start subprocess...
            cp = subprocess.run(
                self.command_str.split(),
                stdout=tmp_stdout,
                stderr=tmp_stderr,
                shell=False,
                env=env,
            )
            self.status = cp.returncode

            try:
                # Rewind to start of files
                tmp_stdout.seek(0)
                tmp_stderr.seek(0)
                # Read output
                self.stdout = tmp_stdout.read()
                self.stderr = tmp_stderr.read()
            finally:
                # Remove temp files by closing them
                tmp_stdout.close()
                tmp_stderr.close()
    else:

        def execute(self, env):
            cp = subprocess.run(
                self.command_str.split(),
                stdout=subprocess.PIPE,
                stderr=subprocess.PIPE,
                shell=False,
                env=env,
            )
            self.status, self.stdout, self.stderr = cp.returncode, cp.stdout, cp.stderr

class XML(PopenExecutor):
    """ Test class for tests that will output in scons xml """
    @staticmethod
    def header(f):
        f.write('  <results>\n')

    def write(self, f):
        f.write('    <test>\n')
        f.write('      <file_name>%s</file_name>\n' % self.path)
        f.write('      <command_line>%s</command_line>\n' % self.command_str)
        f.write('      <exit_status>%s</exit_status>\n' % self.status)
        f.write('      <stdout>%s</stdout>\n' % self.stdout)
        f.write('      <stderr>%s</stderr>\n' % self.stderr)
        f.write('      <time>%.1f</time>\n' % self.test_time)
        f.write('    </test>\n')

    def footer(self, f):
        f.write('  <time>%.1f</time>\n' % self.total_time)
        f.write('  </results>\n')

if args.xml:
    Test = XML
else:
    Test = SystemExecutor

# --- start processing ---

if not args.baseline or args.baseline == '.':
    baseline = cwd
elif args.baseline == '-':
    print("This logic used to checkout from svn. It's been removed. If you used this, please let us know on devel mailing list, IRC, or discord server")
    sys.exit(-1)
else:
    baseline = args.baseline
scons_runtest_dir = baseline

if not args.external:
    scons_script_dir = os.path.join(baseline, 'scripts')
    scons_tools_dir = os.path.join(baseline, 'bin')
    scons_lib_dir = baseline
else:
    scons_script_dir = ''
    scons_tools_dir = ''
    scons_lib_dir = ''

testenv = {
    'SCONS_RUNTEST_DIR': scons_runtest_dir,
    'SCONS_TOOLS_DIR': scons_tools_dir,
    'SCONS_SCRIPT_DIR': scons_script_dir,
    'SCONS_CWD': cwd,
}

if scons:
    # Let the version of SCons that the -x option pointed to find
    # its own modules.
    testenv['SCONS'] = scons
elif scons_lib_dir:
    # Because SCons is really aggressive about finding its modules,
    # it sometimes finds SCons modules elsewhere on the system.
    # This forces SCons to use the modules that are being tested.
    testenv['SCONS_LIB_DIR'] = scons_lib_dir

if args.scons_exec:
    testenv['SCONS_EXEC'] = '1'

if args.external:
    testenv['SCONS_EXTERNAL_TEST'] = '1'

# Insert scons path and path for testing framework to PYTHONPATH
scriptpath = os.path.dirname(os.path.realpath(__file__))
frameworkpath = os.path.join(scriptpath, 'testing', 'framework')
testenv['PYTHONPATH'] = os.pathsep.join((scons_lib_dir, frameworkpath))
pythonpath = os.environ.get('PYTHONPATH')
if pythonpath:
    testenv['PYTHONPATH'] = testenv['PYTHONPATH'] + os.pathsep + pythonpath

if sys.platform == 'win32':
    # Windows doesn't support "shebang" lines directly (the Python launcher
    # and Windows Store version do, but you have to get them launched first)
    # so to directly launch a script we depend on an assoc for .py to work.
    # Some systems may have none, and in some cases IDE programs take over 
    # the assoc.  Detect this so the small number of tests affected can skip.
    try:
        python_assoc = get_template_command('.py')
    except OSError:
        python_assoc = None
    if not python_assoc or "py" not in python_assoc:
        testenv['SCONS_NO_DIRECT_SCRIPT'] = '1'

os.environ.update(testenv)

# Clear _JAVA_OPTIONS which java tools output to stderr when run breaking tests
if '_JAVA_OPTIONS' in os.environ:
    del os.environ['_JAVA_OPTIONS']


# ---[ test discovery ]------------------------------------
# This section figures which tests to run.
#
# The initial testlist is made by reading from the testlistfile,
# if supplied, or by looking at the test arguments, if supplied,
# or by looking for all test files if the "all" argument is supplied.
# One of the three is required.
#
# Each test path, whichever of the three sources it comes from,
# specifies either a test file or a directory to search for
# SCons tests. SCons code layout assumes that any file under the 'SCons'
# subdirectory that ends with 'Tests.py' is a unit test, and any Python
# script (*.py) under the 'test' subdirectory is an end-to-end test.
# We need to track these because they are invoked differently.
# find_unit_tests and find_e2e_tests are used for this searching.
#
# Note that there are some tests under 'SCons' that *begin* with
# 'test_', but they're packaging and installation tests, not
# functional tests, so we don't execute them by default.  (They can
# still be executed by hand, though).
#
# Test exclusions, if specified, are then applied.


def scanlist(testlist):
    """ Process a testlist file """
    tests = [t.strip() for t in testlist if not t.startswith('#')]
    return [t for t in tests if t]


def find_unit_tests(directory):
    """ Look for unit tests """
    result = []
    for dirpath, dirnames, filenames in os.walk(directory):
        # Skip folders containing a sconstest.skip file
        if 'sconstest.skip' in filenames:
            continue
        for fname in filenames:
            if fname.endswith("Tests.py"):
                result.append(os.path.join(dirpath, fname))
    return sorted(result)


def find_e2e_tests(directory):
    """ Look for end-to-end tests """
    result = []
    for dirpath, dirnames, filenames in os.walk(directory):
        # Skip folders containing a sconstest.skip file
        if 'sconstest.skip' in filenames:
            continue

        # Slurp in any tests in exclude lists
        excludes = []
        if ".exclude_tests" in filenames:
            p = Path(dirpath).joinpath(".exclude_tests")
            # TODO simplify when Py3.5 dropped
            if sys.version_info.major == 3 and sys.version_info.minor < 6:
                excludefile = p.resolve()
            else:
                excludefile = p.resolve(strict=True)
            with excludefile.open() as f:
                excludes = scanlist(f)

        for fname in filenames:
            if fname.endswith(".py") and fname not in excludes:
                result.append(os.path.join(dirpath, fname))

    return sorted(result)


# initial selection:
unittests = []
endtests = []
if args.testlistfile:
    with args.testlistfile.open() as f:
        tests = scanlist(f)
else:
    testpaths = []
    if args.all:
        testpaths = ['SCons', 'test']
    elif args.testlist:
        testpaths = args.testlist

    for tp in testpaths:
        # Clean up path so it can match startswith's below
        # remove leading ./ or .\
        if tp.startswith('.') and tp[1] in (os.sep, os.altsep):
            tp = tp[2:]

        for path in glob.glob(tp):
            if os.path.isdir(path):
                if path.startswith(('SCons', 'testing')):
                    unittests.extend(find_unit_tests(path))
                elif path.startswith('test'):
                    endtests.extend(find_e2e_tests(path))
            else:
                if path.endswith("Tests.py"):
                    unittests.append(path)
                elif path.endswith(".py"):
                    endtests.append(path)
    tests = sorted(unittests + endtests)


# Remove exclusions:
if args.e2e_only:
    tests = [t for t in tests if not t.endswith("Tests.py")]
if args.unit_only:
    tests = [t for t in tests if t.endswith("Tests.py")]
if args.excludelistfile:
    with args.excludelistfile.open() as f:
        excludetests = scanlist(f)
    tests = [t for t in tests if t not in excludetests]

if not tests:
    sys.stderr.write(parser.format_usage() + """
error: no tests were found.
       Tests can be specified on the command line, read from a file with
       the -f/--file option, or discovered with -a/--all to run all tests.
""")
    sys.exit(1)

# ---[ test processing ]-----------------------------------
tests = [Test(t, n + 1) for n, t in enumerate(tests)]

if args.list_only:
    for t in tests:
        sys.stdout.write(t.path + "\n")
    sys.exit(0)

if not args.python:
    if os.name == 'java':
        args.python = os.path.join(sys.prefix, 'jython')
    else:
        args.python = sys.executable
os.environ["python_executable"] = args.python

if args.print_times:

    def print_time(fmt, tm):
        sys.stdout.write(fmt % tm)

else:

    def print_time(fmt, tm):
        pass

time_func = time.perf_counter
total_start_time = time_func()
total_num_tests = len(tests)


def log_result(t, io_lock=None):
    """ log the result of a test.

    "log" in this case means writing to stdout. Since we might be
    called from from any of several different threads (multi-job run),
    we need to lock access to the log to avoid interleaving. The same
    would apply if output was a file.

    Args:
        t (Test): (completed) testcase instance
        io_lock (threading.lock): (optional) lock to use
    """

    # there is no lock in single-job run, which includes
    # running test/runtest tests from multi-job run, so check.
    if io_lock:
        io_lock.acquire()
    try:
        if suppress_output or catch_output:
            sys.stdout.write(t.headline)
        if not suppress_output:
            if t.stdout:
                print(t.stdout)
            if t.stderr:
                print(t.stderr)
        print_time("Test execution time: %.1f seconds\n", t.test_time)
    finally:
        if io_lock:
            io_lock.release()

    if args.quit_on_failure and t.status == 1:
        print("Exiting due to error")
        print(t.status)
        sys.exit(1)


def run_test(t, io_lock=None, run_async=True):
    """ Run a testcase.

    Builds the command line to give to execute().
    Also the best place to record some information that will be
    used in output, which in some conditions is printed here.

    Args:
        t (Test): testcase instance
        io_lock (threading.Lock): (optional) lock to use
        run_async (bool): whether to run asynchronously
    """

    t.headline = ""
    command_args = []
    if debug:
        command_args.extend(['-m', debug])
    if args.devmode and sys.version_info >= (3, 7, 0):
        command_args.append('-X dev')
    command_args.append(t.path)
    if args.runner and t.path in unittests:
        # For example --runner TestUnit.TAPTestRunner
        command_args.append('--runner ' + args.runner)
    t.command_args = [escape(args.python)] + command_args
    t.command_str = " ".join(t.command_args)
    if args.printcommand:
        if args.print_progress:
            t.headline += "%d/%d (%.2f%s) %s\n" % (
                t.num, total_num_tests,
                float(t.num) * 100.0 / float(total_num_tests),
                "%",
                t.command_str,
            )
        else:
            t.headline += t.command_str + "\n"
    if not suppress_output and not catch_output:
        # defer printing the headline until test is done
        sys.stdout.write(t.headline)
    head, _ = os.path.split(t.abspath)
    fixture_dirs = []
    if head:
        fixture_dirs.append(head)
    fixture_dirs.append(os.path.join(scriptpath, 'test', 'fixture'))

    # Set the list of fixture dirs directly in the environment. Just putting
    # it in os.environ and spawning the process is racy. Make it reliable by
    # overriding the environment passed to execute().
    env = dict(os.environ)
    env['FIXTURE_DIRS'] = os.pathsep.join(fixture_dirs)

    test_start_time = time_func()
    if args.execute_tests:
        t.execute(env)

    t.test_time = time_func() - test_start_time
    log_result(t, io_lock=io_lock)


class RunTest(threading.Thread):
    """ Test Runner class.

    One instance will be created for each job thread in multi-job mode
    """
    def __init__(self, queue=None, io_lock=None, group=None, target=None, name=None):
        super().__init__(group=group, target=target, name=name)
        self.queue = queue
        self.io_lock = io_lock

    def run(self):
        for t in iter(self.queue.get, None):
            run_test(t, io_lock=self.io_lock, run_async=True)
            self.queue.task_done()

if args.jobs > 1:
    print("Running tests using %d jobs" % args.jobs)
    testq = Queue()
    for t in tests:
        testq.put(t)
    testlock = threading.Lock()
    # Start worker threads to consume the queue
    threads = [RunTest(queue=testq, io_lock=testlock) for _ in range(args.jobs)]
    for t in threads:
        t.daemon = True
        t.start()
    # wait on the queue rather than the individual threads
    testq.join()
else:
    for t in tests:
        run_test(t, io_lock=None, run_async=False)

# --- all tests are complete by the time we get here ---
if tests:
    tests[0].total_time = time_func() - total_start_time
    print_time("Total execution time for all tests: %.1f seconds\n", tests[0].total_time)

passed = [t for t in tests if t.status == 0]
fail = [t for t in tests if t.status == 1]
no_result = [t for t in tests if t.status == 2]

# print summaries, but only if multiple tests were run
if len(tests) != 1 and args.execute_tests:
    if passed and args.print_passed_summary:
        if len(passed) == 1:
            sys.stdout.write("\nPassed the following test:\n")
        else:
            sys.stdout.write("\nPassed the following %d tests:\n" % len(passed))
        paths = [x.path for x in passed]
        sys.stdout.write("\t" + "\n\t".join(paths) + "\n")
    if fail:
        if len(fail) == 1:
            sys.stdout.write("\nFailed the following test:\n")
        else:
            sys.stdout.write("\nFailed the following %d tests:\n" % len(fail))
        paths = [x.path for x in fail]
        sys.stdout.write("\t" + "\n\t".join(paths) + "\n")
    if no_result:
        if len(no_result) == 1:
            sys.stdout.write("\nNO RESULT from the following test:\n")
        else:
            sys.stdout.write("\nNO RESULT from the following %d tests:\n" % len(no_result))
        paths = [x.path for x in no_result]
        sys.stdout.write("\t" + "\n\t".join(paths) + "\n")

# save the fails to a file
if args.error_log:
    with open(args.error_log, "w") as f:
        if fail:
            paths = [x.path for x in fail]
            for test in paths:
                print(test, file=f)
        # if there are no fails, file will be cleared

if args.xml:
    if args.output == '-':
        f = sys.stdout
    else:
        f = open(args.xml, 'w')
    tests[0].header(f)
    #f.write("test_result = [\n")
    for t in tests:
        t.write(f)
    tests[0].footer(f)
    #f.write("];\n")
    if args.output != '-':
        f.close()

if args.output:
    if isinstance(sys.stdout, Tee):
        sys.stdout.file.close()
    if isinstance(sys.stderr, Tee):
        sys.stderr.file.close()

if fail:
    sys.exit(1)
elif no_result and args.dont_ignore_skips:
    # if no fails, but skips were found
    sys.exit(2)
else:
    sys.exit(0)

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# setup.py

#!python3

import fnmatch
from setuptools import setup
from setuptools.command.build_py import build_py as build_py_orig

import codecs
import os.path


def read(rel_path):
    here = os.path.abspath(os.path.dirname(__file__))
    with codecs.open(os.path.join(here, rel_path), 'r') as fp:
        return fp.read()


def get_version(rel_path):
    for line in read(rel_path).splitlines():
        if line.startswith('__version__'):
            delim = '"' if '"' in line else "'"
            return line.split(delim)[1]
    else:
        raise RuntimeError("Unable to find version string.")


exclude = ['*Tests']


class build_py(build_py_orig):

    def find_package_modules(self, package, package_dir):
        """
        Custom module to find package modules.
        It will strip out any modules which match the glob patters in exclude above
        """
        modules = super().find_package_modules(package, package_dir)
        return [(pkg, mod, file, ) for (pkg, mod, file, ) in modules
                if not any(fnmatch.fnmatchcase(mod, pat=pattern)
                for pattern in exclude)]

setup(
    cmdclass={
        'build_py': build_py,
    },
    version=get_version('SCons/__init__.py'),
)

# test/MSVC/pch_gen/pch_gen.py

#!/usr/bin/env python
#
# MIT License
#
# Copyright The SCons Foundation
#
# 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.

"""
Template for end-to-end test file.
Replace this with a description of the test.
"""

import TestSCons

test = TestSCons.TestSCons()

test.skip_if_not_msvc()

# include all of msvc_fixture's files
test.dir_fixture('../msvc_fixture','src')

# Then we'll replace the SConstruct with one specific to this test.
test.file_fixture('fixture/SConstruct',
                  'SConstruct')

test.run(arguments='.')

test.must_exist(test.workpath('output1/test.exe'))
test.must_exist(test.workpath('output1/test.res'))
test.must_exist(test.workpath('output1/test.pdb'))
test.must_exist(test.workpath('output1/StdAfx-1.pch'))
test.must_exist(test.workpath('output1/StdAfx-1.obj'))

test.run(arguments="-c .")
test.run(arguments="DISABLE_PCH=1 .")

test.must_exist(test.workpath('output1/test.exe'))
test.must_exist(test.workpath('output1/test.res'))
test.must_exist(test.workpath('output1/test.pdb'))
test.fail_test(condition = ('/Yuoutput1/StdAfx.h' in test.stdout()), message="Shouldn't have output1/YuStdAfx.h in compile line when PCH is disabled")

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/ARGLIST.py

#!/usr/bin/env python
#
# __COPYRIGHT__
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#

__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"

import TestSCons

test = TestSCons.TestSCons()

test.write('SConstruct', """
i = 0
for key, value in ARGLIST:
    print("%d:  %s = %s" % (i, key, value))
    i = i + 1
""")

expect = test.wrap_stdout(read_str="""\
0:  a = 1
1:  bz = 3
2:  xx = sd
3:  zzz = foo=bar
""",
                           build_str="scons: `.' is up to date.\n")

test.run(arguments='a=1 bz=3 xx=sd zzz=foo=bar .', stdout = expect)

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/ARGUMENTS.py

#!/usr/bin/env python
#
# __COPYRIGHT__
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#

__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"

import TestSCons

test = TestSCons.TestSCons()

test.write('SConstruct', """
foo = open('foo.out', 'wb')
for k in sorted(ARGUMENTS.keys()):
    foo.write((k + " = " + ARGUMENTS[k] + "\\n").encode())
foo.close()
""")

test.run(arguments='a=1 bz=3 xx=sd zzz=foo=bar .')

test.must_match('foo.out', """a = 1
bz = 3
xx = sd
zzz = foo=bar
""")

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/AddMethod.py

#!/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 use of the AddMethod() global function (specifically, to add
an unbound method to the Environment class) and its counterpart
construction environment method.
"""

import TestSCons

test = TestSCons.TestSCons()

test.write('SConstruct', """
def foo(self):
    return 'foo-' + self['FOO']

AddMethod(Environment, foo)
env = Environment(FOO = '111')
print(env.foo())

env = Environment(FOO = '222')
print(env.foo())

env.AddMethod(foo, 'bar')
env['FOO'] = '333'

e = env.Clone()
e['FOO'] = '444'

print(env.bar())
print(e.bar())
""")

expect = """\
foo-111
foo-222
foo-333
foo-444
"""

test.run(arguments = '-Q -q', stdout = expect)

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/AlwaysBuild.py

#!/usr/bin/env python
#
# __COPYRIGHT__
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#


__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"

import os

import TestSCons

test = TestSCons.TestSCons()

test.subdir('sub')

sub_f3_out = os.path.join('sub', 'f3.out')
_SUBDIR_f3_out = os.path.join('$SUBDIR', 'f3.out')

test.write('SConstruct', """\
def bfunc(target, source, env):
    import shutil
    shutil.copyfile('f2.in', str(target[0]))

B = Builder(action=bfunc)
env = Environment(BUILDERS = { 'B' : B }, SUBDIR='sub')
env.B('f1.out', source='f1.in')
AlwaysBuild('f1.out')

env.B(r'%(sub_f3_out)s', source='f3.in')
env.AlwaysBuild(r'%(_SUBDIR_f3_out)s')

env.Alias('clean1', [], Delete('clean1-target'))
env.AlwaysBuild('clean1')
c2 = env.Alias('clean2', [], [Delete('clean2-t1'), Delete('clean2-t2')])
env.AlwaysBuild(c2)

def dir_build(target, source, env):
    with open('dir_build.txt', 'ab') as f:
        f.write(b'dir_build()\\n')
env.Command(Dir('dir'), None, dir_build)
env.AlwaysBuild('dir')
""" % locals())

test.write('f1.in', "f1.in\n")
test.write('f2.in', "1")
test.write('f3.in', "f3.in\n")

test.subdir('dir')

test.run(arguments = ".")
test.must_match('f1.out', '1')
test.must_match(['sub', 'f3.out'], '1')
test.must_match('dir_build.txt', "dir_build()\n")

test.write('f2.in', "2")

test.run(arguments = ".")
test.must_match('f1.out', '2')
test.must_match(['sub', 'f3.out'], '2')
test.must_match('dir_build.txt', "dir_build()\ndir_build()\n")

test.run(arguments = 'clean1', stdout=test.wrap_stdout("""\
Delete("clean1-target")
"""))

test.run(arguments = 'clean2', stdout=test.wrap_stdout("""\
Delete("clean2-t1")
Delete("clean2-t2")
"""))

test.not_up_to_date(arguments = 'dir')

test.must_match('dir_build.txt', "dir_build()\ndir_build()\ndir_build()\n")

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/Builder-factories.py

#!/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 the ability to specify the target_factory and source_factory
of a Builder.
"""

import os.path

import TestSCons

test = TestSCons.TestSCons()

test.subdir('src')

test.write('SConstruct', """
import os
import os.path
def mkdir(env, source, target):
    t = str(target[0])
    os.makedirs(t)
    with open(os.path.join(t, 'marker'), 'wb') as f:
        f.write(b"MakeDirectory\\n")
MakeDirectory = Builder(action=mkdir, target_factory=Dir)
def collect(env, source, target):
    with open(str(target[0]), 'wb') as out:
        dir = str(source[0])
        for f in sorted(os.listdir(dir)):
            f = os.path.join(dir, f)
            with open(f, 'rb') as infp:
                out.write(infp.read())
Collect = Builder(action=collect, source_factory=Dir)
env = Environment(BUILDERS = {'MakeDirectory':MakeDirectory,
                              'Collect':Collect})
env.MakeDirectory('foo', [])
env.Collect('output', 'src')
""")

test.write(['src', 'file1'], "src/file1\n")
test.write(['src', 'file2'], "src/file2\n")
test.write(['src', 'file3'], "src/file3\n")

test.run(arguments = '.')

test.fail_test(not os.path.isdir(test.workpath('foo')))
test.must_match(["foo", "marker"], "MakeDirectory\n")
test.must_match("output", "src/file1\nsrc/file2\nsrc/file3\n")

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/CFILESUFFIX.py

#!/usr/bin/env python
#
# MIT License
#
# Copyright The SCons Foundation
#
# 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 we can set CFILESUFFIX to arbitrary values.
"""


import TestSCons

_python_ = TestSCons._python_

test = TestSCons.TestSCons()

test.file_fixture('mylex.py')

test.write('SConstruct', """
env = Environment(LEX=r'%(_python_)s mylex.py', tools=['lex'])
env.CFile(target='foo', source='foo.l')
env.Clone(CFILESUFFIX='.xyz').CFile(target='bar', source='bar.l')

# Make sure that calling a Tool on a construction environment *after*
# we've set CFILESUFFIX doesn't overwrite the value.
env2 = Environment(tools=[], CFILESUFFIX='.env2')
env2.Tool('lex')
env2['LEX'] = r'%(_python_)s mylex.py'
env2.CFile(target='f3', source='f3.l')
""" % locals())

input = r"""
int
main(int argc, char *argv[])
{
        argv[argc++] = "--";
        printf("LEX\n");
        printf("%s\n");
        exit (0);
}
"""

test.write('foo.l', input % 'foo.l')

test.write('bar.l', input % 'bar.l')

test.write('f3.l', input % 'f3.l')

test.run(arguments = '.')

test.must_exist(test.workpath('foo.c'))

test.must_exist(test.workpath('bar.xyz'))

test.must_exist(test.workpath('f3.env2'))

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/CPPFLAGS.py

#!/usr/bin/env python
#
# MIT License
#
# Copyright The SCons Foundation
#
# 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.

import sys

import TestSCons

_python_ = TestSCons._python_

test = TestSCons.TestSCons()

# Writing this to accommodate both our in-line tool chain and the
# MSVC command lines is too hard, and will be completely unnecessary
# some day when we separate our tests.  Punt for now.
if sys.platform == 'win32':
    test.skip_test('Skipping on win32.\n')

test.file_fixture('mylink.py')
test.file_fixture('mygcc.py')

test.write('SConstruct', """
env = Environment(
    CPPFLAGS='-x',
    LINK=r'%(_python_)s mylink.py',
    LINKFLAGS=[],
    CC=r'%(_python_)s mygcc.py cc',
    CXX=r'%(_python_)s mygcc.py c++',
    CXXFLAGS=[],
    FORTRAN=r'%(_python_)s mygcc.py g77',
    OBJSUFFIX='.obj',
    PROGSUFFIX='.exe',
)
env.Program(target='foo', source=Split('test1.c test2.cpp test3.F'))
""" % locals())

test.write('test1.c', r"""test1.c
#cc
#link
""")

test.write('test2.cpp', r"""test2.cpp
#c++
#link
""")

test.write('test3.F', r"""test3.F
#g77
#link
""")

test.run(arguments = '.', stderr=None)

test.must_match('test1.obj', "test1.c\n#link\n")
test.must_match('test2.obj', "test2.cpp\n#link\n")
test.must_match('test3.obj', "test3.F\n#link\n")
test.must_match('foo.exe',   "test1.c\ntest2.cpp\ntest3.F\n")
if TestSCons.case_sensitive_suffixes('.F', '.f'):
    test.must_match('mygcc.out', "cc\nc++\ng77\n")
else:
    test.must_match('mygcc.out', "cc\nc++\n")   

test.write('SConstruct', """
env = Environment(
    CPPFLAGS='-x',
    SHLINK=r'%(_python_)s mylink.py',
    SHLINKFLAGS=[],
    CC=r'%(_python_)s mygcc.py cc',
    CXX=r'%(_python_)s mygcc.py c++',
    CXXFLAGS=[],
    FORTRAN=r'%(_python_)s mygcc.py g77',
    OBJSUFFIX='.obj',
    SHOBJPREFIX='',
    SHOBJSUFFIX='.shobj',
    PROGSUFFIX='.exe',
)
env.SharedLibrary(target=File('foo.bar'), source=Split('test1.c test2.cpp test3.F'))
""" % locals())

test.write('test1.c', r"""test1.c
#cc
#link
""")

test.write('test2.cpp', r"""test2.cpp
#c++
#link
""")

test.write('test3.F', r"""test3.F
#g77
#link
""")

test.unlink('mygcc.out')
test.unlink('test1.obj')
test.unlink('test2.obj')
test.unlink('test3.obj')

test.run(arguments = '.', stderr = None)

test.must_match('test1.shobj', "test1.c\n#link\n")
test.must_match('test2.shobj', "test2.cpp\n#link\n")
test.must_match('test3.shobj', "test3.F\n#link\n")
test.must_match('foo.bar',        "test1.c\ntest2.cpp\ntest3.F\n")
if TestSCons.case_sensitive_suffixes('.F', '.f'):
    test.must_match('mygcc.out', "cc\nc++\ng77\n")
else:
    test.must_match('mygcc.out', "cc\nc++\n")   

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/CPPSUFFIXES.py

#!/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 the ability to scan additional filesuffixes added to $CPPSUFFIXES.
"""

import TestSCons

_python_ = TestSCons._python_

test = TestSCons.TestSCons()

test.write('mycc.py', r"""
import sys
def do_file(outf, inf):
    with open(inf, 'r') as ifp:
        for line in ifp.readlines():
            if line[:10] == '#include <':
                do_file(outf, line[10:-2])
            else:
                outf.write(line)
with open(sys.argv[1], 'w') as outf:
    for f in sys.argv[2:]:
        do_file(outf, f)
sys.exit(0)
""")

test.write('SConstruct', """
DefaultEnvironment(tools=[])
env = Environment(CPPPATH = ['.'],
                  CC = r'%(_python_)s mycc.py',
                  CCFLAGS = [],
                  CCCOM = '$CC $TARGET $SOURCES',
                  OBJSUFFIX = '.o')
env.Append(CPPSUFFIXES = ['.x'])
env.Object(target = 'test1', source = 'test1.c')
env.InstallAs('test1_c', 'test1.c')
env.InstallAs('test1_h', 'test1.h')
env.InstallAs('test1_x', 'test1.x')
""" % locals())

test.write('test1.c', """\
test1.c 1
#include <test1.h>
#include <test1.x>
""")

test.write('test1.h', """\
test1.h 1
#include <foo.h>
""")

test.write('test1.x', """\
test1.x 1
#include <foo.h>
""")

test.write('foo.h', "foo.h 1\n")

expect = test.wrap_stdout("""\
%(_python_)s mycc.py test1.o test1.c
Install file: "test1.c" as "test1_c"
Install file: "test1.h" as "test1_h"
Install file: "test1.x" as "test1_x"
""" % locals())

test.run(arguments='.', stdout=expect)

test.must_match('test1.o', """\
test1.c 1
test1.h 1
foo.h 1
test1.x 1
foo.h 1
""", mode='r')

test.up_to_date(arguments='.')

test.write('foo.h', "foo.h 2\n")

expect = test.wrap_stdout("""\
%(_python_)s mycc.py test1.o test1.c
""" % locals())

test.run(arguments='.', stdout=expect)

test.must_match('test1.o', """\
test1.c 1
test1.h 1
foo.h 2
test1.x 1
foo.h 2
""", mode='r')

test.up_to_date(arguments='.')

test.write('test1.x', """\
test1.x 2
#include <foo.h>
""")

expect = test.wrap_stdout("""\
%(_python_)s mycc.py test1.o test1.c
Install file: "test1.x" as "test1_x"
""" % locals())

test.run(arguments='.', stdout=expect)

test.must_match('test1.o', """\
test1.c 1
test1.h 1
foo.h 2
test1.x 2
foo.h 2
""", mode='r')

test.up_to_date(arguments='.')

test.write('test1.h', """\
test1.h 2
#include <foo.h>
""")

expect = test.wrap_stdout("""\
%(_python_)s mycc.py test1.o test1.c
Install file: "test1.h" as "test1_h"
""" % locals())

test.run(arguments='.', stdout=expect)

test.must_match('test1.o', """\
test1.c 1
test1.h 2
foo.h 2
test1.x 2
foo.h 2
""", mode='r')

test.up_to_date(arguments='.')

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/Case.py

#!/usr/bin/env python
#
# __COPYRIGHT__
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#

__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"

import sys
import TestSCons

_exe = TestSCons._exe

test = TestSCons.TestSCons()

test.write('SConstruct', """\
Program('main', [
    'main.c',
    Object('foo.o', 'foo.c'),
    Object('FOO.o', 'bar.c')])
""")

test.write('main.c', """\
#include <stdlib.h>

void foo();
void bar();
int main(void) {
    foo();
    bar();
    exit (0);
}
""")

test.write('foo.c', """\
#include <stdio.h>
void foo() {
    puts("foo");
}
""")

test.write('bar.c', """\
#include <stdio.h>
void bar() {
    puts("bar");
}
""")

if sys.platform[:6] == 'darwin':
    test.skip_test("Skipping test on Darwin/OSX; it has partial case sensitivity.\n")

if sys.platform in ['cygwin', 'win32']:
    sys.stdout.write("Using case-insensitive filesystem, testing for failure\n")
    sys.stdout.flush()

    test.run(stderr = None, status = None)
    test.fail_test(test.stderr().split('\n')[0] ==
                   "scons: *** Multiple ways to build the same target were specified for: foo.o")

else:
    sys.stdout.write("Not using case-insensitive filesystem, testing for success\n")
    sys.stdout.flush()

    test.run()
    test.run(program = test.workpath('main' + _exe), stdout = "foo\nbar\n")

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/Chmod.py

#!/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 Chmod() Action works.
"""

import os
import stat

import TestSCons

test = TestSCons.TestSCons()

# Note:  Windows basically has two modes that it can os.chmod() files to
# 0o444 and 0o666, and directories to 0o555 and 0o777, so we can only really
# oscillate between those values.
test.write('SConstruct', """
Execute(Chmod('f1', 0o666))
Execute(Chmod(('f1-File'), 0o666))
Execute(Chmod('d2', 0o777))
Execute(Chmod(Dir('d2-Dir'), 0o777))
def cat(env, source, target):
    target = str(target[0])
    with open(target, "wb") as f:
        for src in source:
            with open(str(src), "rb") as infp:
                f.write(infp.read())
Cat = Action(cat)
env = Environment()
env.Command('bar.out', 'bar.in', [Cat,
                                  Chmod("f3", 0o666),
                                  Chmod("d4", 0o777)])
env = Environment(FILE = 'f5')
env.Command('f6.out', 'f6.in', [Chmod('$FILE', 0o666), Cat])
env.Command('f7.out', 'f7.in', [Cat,
                                Chmod('Chmod-$SOURCE', 0o666),
                                Chmod('${TARGET}-Chmod', 0o666)])

# Make sure Chmod works with a list of arguments
env = Environment(FILE = 'f9')
env.Command('f8.out', 'f8.in', [Chmod(['$FILE', File('f10')], 0o666), Cat])
Execute(Chmod(['d11', Dir('d12')], 0o777))
Execute(Chmod('f13', "a=r"))
Execute(Chmod('f14', "ogu+w"))
Execute(Chmod('f15', "ug=rw, go+ rw"))
Execute(Chmod('d16', "0777"))
Execute(Chmod(['d17', 'd18'], "ogu = rwx"))
""")

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')
test.write(['d4', 'file'], "d4/file\n")
test.write('f5', "f5\n")
test.write('f6.in', "f6.in\n")
test.write('f7.in', "f7.in\n")
test.write('Chmod-f7.in', "Chmod-f7.in\n")
test.write('f7.out-Chmod', "f7.out-Chmod\n")
test.write('f8.in', "f8.in\n")
test.write('f9', "f9\n")
test.write('f10', "f10\n")
test.subdir('d11')
test.subdir('d12')
test.write('f13', "f13\n")
test.write('f14', "f14\n")
test.write('f15', "f15\n")
test.subdir('d16')
test.subdir('d17')
test.subdir('d18')

os.chmod(test.workpath('f1'), 0o444)
os.chmod(test.workpath('f1-File'), 0o444)
os.chmod(test.workpath('d2'), 0o555)
os.chmod(test.workpath('d2-Dir'), 0o555)
os.chmod(test.workpath('f3'), 0o444)
os.chmod(test.workpath('d4'), 0o555)
os.chmod(test.workpath('f5'), 0o444)
os.chmod(test.workpath('Chmod-f7.in'), 0o444)
os.chmod(test.workpath('f7.out-Chmod'), 0o444)
os.chmod(test.workpath('f9'), 0o444)
os.chmod(test.workpath('f10'), 0o444)
os.chmod(test.workpath('d11'), 0o555)
os.chmod(test.workpath('d12'), 0o555)
os.chmod(test.workpath('f13'), 0o444)
os.chmod(test.workpath('f14'), 0o444)
os.chmod(test.workpath('f15'), 0o444)
os.chmod(test.workpath('d16'), 0o555)
os.chmod(test.workpath('d17'), 0o555)
os.chmod(test.workpath('d18'), 0o555)
expect = test.wrap_stdout(read_str = """\
Chmod("f1", 0666)
Chmod("f1-File", 0666)
Chmod("d2", 0777)
Chmod("d2-Dir", 0777)
Chmod(["d11", "d12"], 0777)
Chmod("f13", "a=r")
Chmod("f14", "ogu+w")
Chmod("f15", "ug=rw, go+ rw")
Chmod("d16", "0777")
Chmod(["d17", "d18"], "ogu = rwx")
""",
                          build_str = """\
cat(["bar.out"], ["bar.in"])
Chmod("f3", 0666)
Chmod("d4", 0777)
Chmod("f5", 0666)
cat(["f6.out"], ["f6.in"])
cat(["f7.out"], ["f7.in"])
Chmod("Chmod-f7.in", 0666)
Chmod("f7.out-Chmod", 0666)
Chmod(["f9", "f10"], 0666)
cat(["f8.out"], ["f8.in"])
""")
test.run(options = '-n', arguments = '.', stdout = expect)

s = stat.S_IMODE(os.stat(test.workpath('f1'))[stat.ST_MODE])
test.fail_test(s != 0o444)
s = stat.S_IMODE(os.stat(test.workpath('f1-File'))[stat.ST_MODE])
test.fail_test(s != 0o444)
s = stat.S_IMODE(os.stat(test.workpath('d2'))[stat.ST_MODE])
test.fail_test(s != 0o555)
s = stat.S_IMODE(os.stat(test.workpath('d2-Dir'))[stat.ST_MODE])
test.fail_test(s != 0o555)
test.must_not_exist('bar.out')
s = stat.S_IMODE(os.stat(test.workpath('f3'))[stat.ST_MODE])
test.fail_test(s != 0o444)
s = stat.S_IMODE(os.stat(test.workpath('d4'))[stat.ST_MODE])
test.fail_test(s != 0o555)
s = stat.S_IMODE(os.stat(test.workpath('f5'))[stat.ST_MODE])
test.fail_test(s != 0o444)
test.must_not_exist('f6.out')
test.must_not_exist('f7.out')
s = stat.S_IMODE(os.stat(test.workpath('Chmod-f7.in'))[stat.ST_MODE])
test.fail_test(s != 0o444)
s = stat.S_IMODE(os.stat(test.workpath('f7.out-Chmod'))[stat.ST_MODE])
test.fail_test(s != 0o444)
test.must_not_exist('f8.out')
s = stat.S_IMODE(os.stat(test.workpath('f9'))[stat.ST_MODE])
test.fail_test(s != 0o444)
s = stat.S_IMODE(os.stat(test.workpath('f10'))[stat.ST_MODE])
test.fail_test(s != 0o444)
s = stat.S_IMODE(os.stat(test.workpath('d11'))[stat.ST_MODE])
test.fail_test(s != 0o555)
s = stat.S_IMODE(os.stat(test.workpath('d12'))[stat.ST_MODE])
test.fail_test(s != 0o555)
s = stat.S_IMODE(os.stat(test.workpath('f13'))[stat.ST_MODE])
test.fail_test(s != 0o444)
s = stat.S_IMODE(os.stat(test.workpath('f14'))[stat.ST_MODE])
test.fail_test(s != 0o444)
s = stat.S_IMODE(os.stat(test.workpath('f15'))[stat.ST_MODE])
test.fail_test(s != 0o444)
s = stat.S_IMODE(os.stat(test.workpath('d16'))[stat.ST_MODE])
test.fail_test(s != 0o555)
s = stat.S_IMODE(os.stat(test.workpath('d17'))[stat.ST_MODE])
test.fail_test(s != 0o555)
s = stat.S_IMODE(os.stat(test.workpath('d18'))[stat.ST_MODE])
test.fail_test(s != 0o555)

test.run()

s = stat.S_IMODE(os.stat(test.workpath('f1'))[stat.ST_MODE])
test.fail_test(s != 0o666)
s = stat.S_IMODE(os.stat(test.workpath('f1-File'))[stat.ST_MODE])
test.fail_test(s != 0o666)
s = stat.S_IMODE(os.stat(test.workpath('d2'))[stat.ST_MODE])
test.fail_test(s != 0o777)
s = stat.S_IMODE(os.stat(test.workpath('d2-Dir'))[stat.ST_MODE])
test.fail_test(s != 0o777)
test.must_match('bar.out', "bar.in\n")
s = stat.S_IMODE(os.stat(test.workpath('f3'))[stat.ST_MODE])
test.fail_test(s != 0o666)
s = stat.S_IMODE(os.stat(test.workpath('d4'))[stat.ST_MODE])
test.fail_test(s != 0o777)
s = stat.S_IMODE(os.stat(test.workpath('f5'))[stat.ST_MODE])
test.fail_test(s != 0o666)
test.must_match('f6.out', "f6.in\n")
test.must_match('f7.out', "f7.in\n")
s = stat.S_IMODE(os.stat(test.workpath('Chmod-f7.in'))[stat.ST_MODE])
test.fail_test(s != 0o666)
s = stat.S_IMODE(os.stat(test.workpath('f7.out-Chmod'))[stat.ST_MODE])
test.fail_test(s != 0o666)
test.must_match('f8.out', "f8.in\n")
s = stat.S_IMODE(os.stat(test.workpath('f9'))[stat.ST_MODE])
test.fail_test(s != 0o666)
s = stat.S_IMODE(os.stat(test.workpath('f10'))[stat.ST_MODE])
test.fail_test(s != 0o666)
s = stat.S_IMODE(os.stat(test.workpath('d11'))[stat.ST_MODE])
test.fail_test(s != 0o777)
s = stat.S_IMODE(os.stat(test.workpath('d12'))[stat.ST_MODE])
test.fail_test(s != 0o777)
s = stat.S_IMODE(os.stat(test.workpath('f13'))[stat.ST_MODE])
test.fail_test(s != 0o444)
s = stat.S_IMODE(os.stat(test.workpath('f14'))[stat.ST_MODE])
test.fail_test(s != 0o666)
s = stat.S_IMODE(os.stat(test.workpath('f15'))[stat.ST_MODE])
test.fail_test(s != 0o666)
s = stat.S_IMODE(os.stat(test.workpath('d16'))[stat.ST_MODE])
test.fail_test(s != 0o777)
s = stat.S_IMODE(os.stat(test.workpath('d17'))[stat.ST_MODE])
test.fail_test(s != 0o777)
s = stat.S_IMODE(os.stat(test.workpath('d18'))[stat.ST_MODE])
test.fail_test(s != 0o777)

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/Clone-compatibility.py

#!/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 a specific snippet of backwards-compatibility code works.

"""

import TestSCons

test = TestSCons.TestSCons()

test.write('SConstruct', """

# When the 0.96.93 release introduced the env.Clone() we advertised this
# code as the correct pattern for maintaining the backwards compatibility
# of SConstruct files to earlier release of SCons.  Going forward, make
# sure it still works (or at least doesn't blow up).
# Copy was removed for 3.1.2 but Clone will certainly be there -
# this test probably isn't needed any longer.
import SCons.Environment
try:
    SCons.Environment.Environment.Clone
except AttributeError:
    SCons.Environment.Environment.Clone = SCons.Environment.Environment.Copy

env1 = Environment(X = 1)
env2 = env1.Clone(X = 2)

print(env1['X'])
print(env2['X'])
""")

test.run(arguments = '-q -Q', stdout = "1\n2\n")

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/Command.py

#!/usr/bin/env python
#
# __COPYRIGHT__
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"

import TestSCons

python = TestSCons.python
_python_ = TestSCons._python_

test = TestSCons.TestSCons()

test.subdir('expand_chdir_sub')
test.subdir('sub')

build_py = r"""
import sys
with open(sys.argv[1], 'w') as f, open(sys.argv[2], 'r') as infp:
    f.write(infp.read())
"""
test.write('build.py', build_py)
test.write(['expand_chdir_sub', 'subbuild.py'], build_py)

test.write('SConstruct', """
import os
import sys

def buildIt(env, target, source):
    with open(str(target[0]), 'w') as f, open(str(source[0]), 'r') as infp:
        xyzzy = env.get('XYZZY', '')
        if xyzzy:
            f.write(xyzzy + '\\n')
        f.write(infp.read())
    return 0

def sub(env, target, source):
    target = str(target[0])
    source = str(source[0])
    with open(target, 'w') as t:
        for f in sorted(os.listdir(source)):
            with open(os.path.join(source, f), 'r') as s:
                t.write(s.read())
    return 0

def source_scanner(node, env, path, builder):
    print("Source scanner node=", node, "builder =", builder,file=sys.stderr)
    return []

def target_scanner(node, env, path, builder):
    print("Target scanner node=", node, "builder =", builder,file=sys.stderr)
    return []

def factory(node,*lst,**kw):
    print("factory called on:",node,file=sys.stderr)
    return env.File(node)

env = Environment(COPY_THROUGH_TEMP = r'%(_python_)s build.py .tmp $SOURCE' + '\\n' + r'%(_python_)s build.py $TARGET .tmp',
                  EXPAND = '$COPY_THROUGH_TEMP')
env.Command(target = 'f1.out', source = 'f1.in',
            action = buildIt)
env.Command(target = 'f2.out', source = 'f2.in',
            action = r'%(_python_)s build.py temp2 $SOURCES' + '\\n' + r'%(_python_)s build.py $TARGET temp2')
env.Command(target = 'f3.out', source = 'f3.in',
            action = [ [ r'%(_python_)s', 'build.py', 'temp3', '$SOURCES' ],
                       [ r'%(_python_)s', 'build.py', '$TARGET', 'temp3'] ])
Command(target = 'f4.out', source = 'sub', action = sub)
env.Command(target = 'f5.out', source = 'f5.in', action = buildIt,
            XYZZY='XYZZY is set')
env.Command(target = 'f5.out', source = 'f5.in', action = buildIt,
            XYZZY='XYZZY is set')
Command(target = 'f6.out', source = 'f6.in',
        action = r'%(_python_)s build.py f6.out f6.in')
env.Command(target = 'f7.out', source = 'f7.in',
            action = r'%(_python_)s build.py $TARGET $SOURCE')
Command(target = 'f8.out', source = 'f8.in',
        action = r'%(_python_)s build.py $TARGET $SOURCE')
env.Command(target = 'f7s.out', source = 'f7.in',
            action = r'%(_python_)s build.py $TARGET $SOURCE',
            target_scanner=Scanner(lambda node, env, path: target_scanner(node, env, path, "w-env")),
            source_scanner=Scanner(lambda node, env, path: source_scanner(node, env, path, "w-env")))
Command(target = 'f8s.out', source = 'f8.in',
        action = r'%(_python_)s build.py $TARGET $SOURCE',
        target_scanner=Scanner(lambda node, env, path: target_scanner(node, env, path, "wo-env")),
        source_scanner=Scanner(lambda node, env, path: source_scanner(node, env, path, "wo-env")))
Command(target = 'f8f.out', source = 'f8.in',
        action = r'%(_python_)s build.py $TARGET $SOURCE',
        target_factory=factory,
        source_factory=factory
        )
env.Command(target = 'f9.out', source = 'f9.in',
            action = r'$EXPAND')
env.Command(target = '${F10}.out', source = '${F10}.in',
            action = r'%(_python_)s build.py $TARGET $SOURCE',
            F10 = 'f10')
env['SUB'] = 'expand_chdir_sub'
env.Command(target = '$SUB/${F11}.out', source = '$SUB/${F11}.in',
            action = r'%(_python_)s subbuild.py ${F11}.out ${F11}.in',
            chdir = '$SUB',
            F11 = 'f11')
""" % locals())

test.write('f1.in', "f1.in\n")
test.write('f2.in', "f2.in\n")
test.write('f3.in', "f3.in\n")
test.write(['sub', 'f4a'], "sub/f4a\n")
test.write(['sub', 'f4b'], "sub/f4b\n")
test.write(['sub', 'f4c'], "sub/f4c\n")
test.write('f5.in', "f5.in\n")
test.write('f6.in', "f6.in\n")
test.write('f7.in', "f7.in\n")
test.write('f8.in', "f8.in\n")
test.write('f9.in', "f9.in\n")
test.write('f10.in', "f10.in\n")
test.write(['expand_chdir_sub', 'f11.in'], "expand_chdir_sub/f11.in\n")

test_str = r'''factory called on: f8.in
factory called on: f8f.out
Source scanner node= f7.in builder = w-env
Target scanner node= f7s.out builder = w-env
Source scanner node= f8.in builder = wo-env
Target scanner node= f8s.out builder = wo-env
'''

out = test.run(arguments='.',
               stderr=test_str,
               match=TestSCons.match_re_dotall)


test.must_match('f1.out', "f1.in\n", mode='r')
test.must_match('f2.out', "f2.in\n", mode='r')
test.must_match('f3.out', "f3.in\n", mode='r')
test.must_match('f4.out', "sub/f4a\nsub/f4b\nsub/f4c\n", mode='r')
test.must_match('f5.out', "XYZZY is set\nf5.in\n", mode='r')
test.must_match('f6.out', "f6.in\n", mode='r')
test.must_match('f7.out', "f7.in\n", mode='r')
test.must_match('f8.out', "f8.in\n", mode='r')
test.must_match('f7s.out', "f7.in\n", mode='r')
test.must_match('f8s.out', "f8.in\n", mode='r')
test.must_match('f9.out', "f9.in\n", mode='r')
test.must_match('f10.out', "f10.in\n", mode='r')
test.must_match(['expand_chdir_sub', 'f11.out'],
                "expand_chdir_sub/f11.in\n", mode='r')

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/CommandGenerator.py

#!/usr/bin/env python
#
# __COPYRIGHT__
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#

__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"


import TestSCons

python = TestSCons.python

test = TestSCons.TestSCons()

test.write('build.py', r"""
import sys
with open(sys.argv[1], 'w') as f, open(sys.argv[2], 'r') as ifp:
    f.write(ifp.read())
sys.exit(0)
""")

test.write('SConstruct', """
def g(source, target, for_signature, env):
    import sys
    python = r'%(python)s'
    return [[python, "build.py", "$TEMPFILE"] + source,
            [python, "build.py"] + target + ["$TEMPFILE"]]

b = Builder(generator=g)
env = Environment(BUILDERS = { 'b' : b },
                  TEMPFILE=".temp")
env.b(target = 'foo1.out', source = 'foo1.in')
env.b(target = 'foo2.out', source = 'foo2.in')
env.b(target = 'foo3.out', source = 'foo3.in')
""" % locals())

test.write('foo1.in', "foo1.in\n")

test.write('foo2.in', "foo2.in\n")

test.write('foo3.in', "foo3.in\n")

test.run(arguments = 'foo1.out foo2.out foo3.out')

test.must_match('foo1.out','foo1.in\n', mode='r')
test.must_match('foo2.out','foo2.in\n', mode='r')
test.must_match('foo3.out','foo3.in\n', mode='r')

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/ConstructionEnvironment.py

#!/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 setting values in SCons.Defaults.ConstructionEnvironment
will, in fact, affect the DefaultEnvironment() that's created.
"""

import TestSCons

test = TestSCons.TestSCons()

test.write('SConstruct', """
import SCons.Defaults
SCons.Defaults.ConstructionEnvironment.update({
        'XXX'   : 777,
})
print(DefaultEnvironment()['XXX'])
""")

expect = test.wrap_stdout(read_str = "777\n",
                          build_str = "scons: `.' is up to date.\n")

test.run(arguments = '.', stdout = expect)

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/Copy-Action.py

#!/usr/bin/env python
#
# MIT License
#
# Copyright The SCons Foundation
#
# 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 Copy() Action works, and preserves file modification
times and modes.
"""

import os
import stat
import sys

import TestSCons

test = TestSCons.TestSCons()

test.write('SConstruct', """\
Execute(Copy('f1.out', 'f1.in'))
Execute(Copy(File('d2.out'), 'd2.in'))
Execute(Copy('d3.out', File('f3.in')))

def cat(env, source, target):
    target = str(target[0])
    with open(target, "w") as f:
        for src in source:
            with open(str(src), "r") as ifp:
                f.write(ifp.read())

Cat = Action(cat)
env = Environment()
env.Command(
    'bar.out',
    'bar.in',
    [Cat, Copy("f4.out", "f4.in"), Copy("d5.out", "d5.in"), Copy("d6.out", "f6.in")],
)
env = Environment(OUTPUT='f7.out', INPUT='f7.in')
env.Command('f8.out', 'f8.in', [Copy('$OUTPUT', '$INPUT'), Cat])
env.Command('f9.out', 'f9.in', [Cat, Copy('${TARGET}-Copy', '$SOURCE')])

env.CopyTo('d4', 'f10.in')
env.CopyAs('d4/f11.out', 'f11.in')
env.CopyAs('d4/f12.out', 'd5/f12.in')

env.Command('f   13.out', 'f   13.in', Copy('$TARGET', '$SOURCE'))
""")

test.write('f1.in', "f1.in\n")
test.subdir('d2.in')
test.write(['d2.in', 'file'], "d2.in/file\n")
test.write('f3.in', "f3.in\n")
test.subdir('d3.out')
test.write('bar.in', "bar.in\n")
test.write('f4.in', "f4.in\n")
test.subdir('d5.in')
test.write(['d5.in', 'file'], "d5.in/file\n")
test.write('f6.in', "f6.in\n")
test.subdir('d6.out')
test.write('f7.in', "f7.in\n")
test.write('f8.in', "f8.in\n")
test.write('f9.in', "f9.in\n")
test.write('f10.in', "f10.in\n")
test.write('f11.in', "f11.in\n")
test.subdir('d5')
test.write(['d5', 'f12.in'], "f12.in\n")
test.write('f   13.in', "f   13.in\n")

os.chmod('f1.in', 0o646)
os.chmod('f4.in', 0o644)

test.sleep()  # delay for timestamps

d4_f10_in   = os.path.join('d4', 'f10.in')
d4_f11_out  = os.path.join('d4', 'f11.out')
d4_f12_out  = os.path.join('d4', 'f12.out')
d5_f12_in   = os.path.join('d5', 'f12.in')

expect = test.wrap_stdout(
    read_str="""\
Copy("f1.out", "f1.in")
Copy("d2.out", "d2.in")
Copy("d3.out", "f3.in")
""",
    build_str="""\
cat(["bar.out"], ["bar.in"])
Copy("f4.out", "f4.in")
Copy("d5.out", "d5.in")
Copy("d6.out", "f6.in")
Copy file(s): "f10.in" to "%(d4_f10_in)s"
Copy file(s): "f11.in" to "%(d4_f11_out)s"
Copy file(s): "%(d5_f12_in)s" to "%(d4_f12_out)s"
Copy("f   13.out", "f   13.in")
Copy("f7.out", "f7.in")
cat(["f8.out"], ["f8.in"])
cat(["f9.out"], ["f9.in"])
Copy("f9.out-Copy", "f9.in")
""" % locals(),
)

test.run(options='-n', arguments='.', stdout=expect)

test.must_not_exist('f1.out')
test.must_not_exist('d2.out')
test.must_not_exist(os.path.join('d3.out', 'f3.in'))
test.must_not_exist('f4.out')
test.must_not_exist('d5.out')
test.must_not_exist(os.path.join('d6.out', 'f6.in'))
test.must_not_exist('f7.out')
test.must_not_exist('f8.out')
test.must_not_exist('f9.out')
test.must_not_exist('f9.out-Copy')
test.must_not_exist('d4/f10.in')
test.must_not_exist('d4/f11.out')
test.must_not_exist('d4/f12.out')
test.must_not_exist('f 13.out')
test.must_not_exist('f    13.out')

test.run()

test.must_match('f1.out', "f1.in\n", mode='r')
test.must_match(['d2.out', 'file'], "d2.in/file\n", mode='r')
test.must_match(['d3.out', 'f3.in'], "f3.in\n", mode='r')
test.must_match('f4.out', "f4.in\n", mode='r')
test.must_match(['d5.out', 'file'], "d5.in/file\n", mode='r')
test.must_match(['d6.out', 'f6.in'], "f6.in\n", mode='r')
test.must_match('f7.out', "f7.in\n", mode='r')
test.must_match('f8.out', "f8.in\n", mode='r')
test.must_match('f9.out', "f9.in\n", mode='r')
test.must_match('f9.out-Copy', "f9.in\n", mode='r')
test.must_match('d4/f10.in', 'f10.in\n', mode='r')
test.must_match('d4/f11.out', 'f11.in\n', mode='r')
test.must_match('d4/f12.out', 'f12.in\n', mode='r')
test.must_match('f   13.out', 'f   13.in\n', mode='r')

errors = 0

def must_be_same(f1, f2):
    global errors
    if isinstance(f1, list):
        f1 = os.path.join(*f1)
    if isinstance(f2, list):
        f2 = os.path.join(*f2)
    s1 = os.stat(f1)
    s2 = os.stat(f2)
    for value in ['ST_MODE', 'ST_MTIME']:
        v = getattr(stat, value)
        if s1[v] != s2[v]:
            msg = f"{f1!r}[{value}] {s1[v]} != {f2!r}[{value}] {s2[v]}\n"
            sys.stderr.write(msg)
            errors += 1

must_be_same('f1.out', 'f1.in')
must_be_same(['d2.out', 'file'], ['d2.in', 'file'])
must_be_same(['d3.out', 'f3.in'], 'f3.in')
must_be_same('f4.out', 'f4.in')
must_be_same(['d5.out', 'file'], ['d5.in', 'file'])
must_be_same(['d6.out', 'f6.in'], 'f6.in')
must_be_same('f7.out', 'f7.in')
must_be_same(['d4', 'f10.in'], 'f10.in')
must_be_same(['d4', 'f11.out'], 'f11.in')
must_be_same(['d4', 'f12.out'], ['d5', 'f12.in'])
must_be_same('f   13.out', 'f   13.in')

if errors:
    test.fail_test()

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/Copy-Option.py

#!/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 setting Variables in an Environment doesn't prevent the
Environment from being copied.
"""

import TestSCons

test = TestSCons.TestSCons()

test.write('SConstruct', """
gpib_options = ['NI_GPIB', 'NI_ENET']
gpib_include = '/'

#0.96 broke copying  ListVariables ???
opts = Variables('config.py', ARGUMENTS)
opts.AddVariables(
    BoolVariable('gpib', 'enable gpib support', 1),
    ListVariable('gpib_options',
        'whether and what kind of gpib support shall be enabled',
        'all',
        gpib_options),
    )
env = Environment(options = opts, CPPPATH = ['#/'])
new_env=env.Clone()
""")

test.run(arguments = '.')

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/Copy-Symlinks.py

#!/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 Copy() Action symlink soft-copy support works.
"""

import os
import TestSCons

import SCons.Defaults
SCons.Defaults.DefaultEnvironment( tools = [] )

test = TestSCons.TestSCons()

if not test.platform_has_symlink():
    test.skip_test('No os.symlink() method, no symlinks to test.\n')

filelinkToCopy = 'filelinkToCopy'
fileToLink = 'file.in'
fileContents = 'stuff n things\n'
dirToLink = 'dir'
dirlinkToCopy = 'dirlinkToCopy'
treeToLink = 'tree'
treelinkToCopy = 'treelinkToCopy'
badToLink = 'None' # do not write this item
badlinkToCopy = 'badlinkToCopy'
relToLink = os.path.join( treeToLink, fileToLink )
rellinkToCopy = 'relLinkToCopy'

test.symlink( fileToLink, filelinkToCopy )
test.symlink( dirToLink, dirlinkToCopy )
test.symlink( treeToLink, treelinkToCopy )
test.symlink( badToLink, badlinkToCopy )
test.symlink( relToLink, rellinkToCopy )

test.write( fileToLink, fileContents )
test.subdir( dirToLink )
test.subdir( treeToLink )
test.write( relToLink, fileContents )

sconstructPath = 'SConstruct'
sconscriptPath = os.path.join( treeToLink, 'SConscript' )

test.write( sconstructPath,
"""\
import SCons.Defaults
SCons.Defaults.DefaultEnvironment( tools = [] )

Execute( Copy( 'F1', '%(filelinkToCopy)s', False ) )
Execute( Copy( 'L1', '%(filelinkToCopy)s' ) )
Execute( Copy( 'L2', '%(filelinkToCopy)s', True ) )

Execute( Copy( 'D1', '%(dirlinkToCopy)s', False ) )
Execute( Copy( 'L3', '%(dirlinkToCopy)s' ) )
Execute( Copy( 'L4', '%(dirlinkToCopy)s', True ) )

Execute( Copy( 'T1', '%(treelinkToCopy)s', False ) )
Execute( Copy( 'L5', '%(treelinkToCopy)s' ) )
Execute( Copy( 'L6', '%(treelinkToCopy)s', True ) )

Execute( Copy( 'Fails', '%(badlinkToCopy)s', False ) )
Execute( Copy( 'L7', '%(badlinkToCopy)s' ) )
Execute( Copy( 'L8', '%(badlinkToCopy)s', True ) )

SConscript( '%(sconscriptPath)s' )
"""
% locals()
)

relLinkCopyPath = os.path.join( '..', rellinkToCopy )

test.write( sconscriptPath,
"""\
Execute( Copy( 'F2', '%(relLinkCopyPath)s', False ) )
Execute( Copy( 'L9', '%(relLinkCopyPath)s' ) )
Execute( Copy( 'L10', '%(relLinkCopyPath)s', True ) )
"""
% locals()
)

test.must_exist( sconstructPath )
test.must_exist( sconscriptPath )
test.must_exist( fileToLink )
test.must_exist( filelinkToCopy )
test.must_exist( dirlinkToCopy )
test.must_exist( treelinkToCopy )
test.must_not_exist( badToLink )
test.must_exist( badlinkToCopy )
test.must_exist( rellinkToCopy )

expectStdout = test.wrap_stdout(
read_str =
'''\
Copy("F1", "%(filelinkToCopy)s")
Copy("L1", "%(filelinkToCopy)s")
Copy("L2", "%(filelinkToCopy)s")
Copy("D1", "%(dirlinkToCopy)s")
Copy("L3", "%(dirlinkToCopy)s")
Copy("L4", "%(dirlinkToCopy)s")
Copy("T1", "%(treelinkToCopy)s")
Copy("L5", "%(treelinkToCopy)s")
Copy("L6", "%(treelinkToCopy)s")
Copy("Fails", "%(badlinkToCopy)s")
Copy("L7", "%(badlinkToCopy)s")
Copy("L8", "%(badlinkToCopy)s")
Copy("F2", "%(relLinkCopyPath)s")
Copy("L9", "%(relLinkCopyPath)s")
Copy("L10", "%(relLinkCopyPath)s")
''' % locals(),
build_str =
'''\
scons: `.' is up to date.
'''
)

expectStderr = \
'''\
scons: *** %s: No such file or directory
''' % os.path.join( os.getcwd(), badToLink )

test.run( stdout = expectStdout, stderr = expectStderr, status = None )

F2 = os.path.join( treeToLink, 'F2' )
L9 = os.path.join( treeToLink, 'L9' )
L10 = os.path.join( treeToLink, 'L10' )

test.must_exist('D1')
test.must_exist('F1')
test.must_exist( F2 )
test.must_exist('L2')
test.must_exist('L3')
test.must_exist('L4')
test.must_exist('L5')
test.must_exist('L6')
test.must_exist('L7')
test.must_exist('L8')
test.must_exist( L9 )
test.must_exist( L10 )
test.must_exist('T1')
test.must_not_exist( 'Fails' )

test.must_match( fileToLink, fileContents )
test.must_match( 'F1', fileContents )
test.must_match(  F2 , fileContents )
test.must_match( 'L1', fileContents )
test.must_match( 'L2', fileContents )
test.must_match( os.path.join( treeToLink, fileToLink ), fileContents )

test.fail_test( condition=os.path.islink('D1') )
test.fail_test( condition=os.path.islink('F1') )
test.fail_test( condition=os.path.islink( F2 ) )
test.fail_test( condition=os.path.islink('T1') )
test.fail_test( condition=(not os.path.isdir('D1')) )
test.fail_test( condition=(not os.path.isfile('F1')) )
test.fail_test( condition=(not os.path.isdir('T1')) )
test.fail_test( condition=(not os.path.islink('L1')) )
test.fail_test( condition=(not os.path.islink('L2')) )
test.fail_test( condition=(not os.path.islink('L3')) )
test.fail_test( condition=(not os.path.islink('L4')) )
test.fail_test( condition=(not os.path.islink('L5')) )
test.fail_test( condition=(not os.path.islink('L6')) )
test.fail_test( condition=(not os.path.islink('L7')) )
test.fail_test( condition=(not os.path.islink('L8')) )
test.fail_test( condition=(not os.path.islink( L9 )) )
test.fail_test( condition=(not os.path.islink( L10 )) )
test.fail_test( condition=(os.path.exists('L7')) )
test.fail_test( condition=(os.path.exists('L8')) )
test.fail_test( condition=(os.path.exists( L9 )) )
test.fail_test( condition=(os.path.exists( L10 )) )
test.fail_test( condition=(os.readlink(filelinkToCopy) != os.readlink('L1')) )
test.fail_test( condition=(os.readlink(filelinkToCopy) != os.readlink('L2')) )
test.fail_test( condition=(os.readlink(dirlinkToCopy) != os.readlink('L3')) )
test.fail_test( condition=(os.readlink(dirlinkToCopy) != os.readlink('L4')) )
test.fail_test( condition=(os.readlink(treelinkToCopy) != os.readlink('L5')) )
test.fail_test( condition=(os.readlink(treelinkToCopy) != os.readlink('L6')) )
test.fail_test( condition=(os.readlink(badlinkToCopy) != os.readlink('L7')) )
test.fail_test( condition=(os.readlink(badlinkToCopy) != os.readlink('L8')) )
test.fail_test( condition=(os.readlink(rellinkToCopy) != os.readlink( L9 )) )
test.fail_test( condition=(os.readlink(rellinkToCopy) != os.readlink( L10 )) )

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/DSUFFIXES.py

#!/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 the ability to scan additional filesuffixes added to $DSUFFIXES.
"""

import TestSCons

_python_ = TestSCons._python_

test = TestSCons.TestSCons()

test.write('mydc.py', r"""
import sys
def do_file(outf, inf):
    with open(inf, 'rb') as ifp:
        for line in ifp.readlines():
            if line[:7] == b'import ':
                do_file(outf, line[7:-2] + b'.d')
            else:
                outf.write(line)
with open(sys.argv[1], 'wb') as outf:
    for f in sys.argv[2:]:
        do_file(outf, f)
sys.exit(0)
""")

test.write('SConstruct', """
# Force the 'dmd' tool to get added to the Environment, even if it's not
# installed, so we get its definition of variables to deal with turning
# '.d' suffix files into objects.
env = Environment()
Tool('dmd')(env)
# Now replace those suffixes with our fake-D things.
env.Replace(DPATH = ['.'],
            DC = r'%(_python_)s mydc.py',
            DFLAGS = [],
            DCOM = '$DC $TARGET $SOURCES',
            OBJSUFFIX = '.o')
env.Append(CPPSUFFIXES = ['.x'])
env.Object(target = 'test1', source = 'test1.d')
env.InstallAs('test1_d', 'test1.d')
env.InstallAs('test2_d', 'test2.d')
env.InstallAs('test3_d', 'test3.d')
""" % locals())

test.write('test1.d', """\
test1.d 1
import test2;
import test3;
""")

test.write('test2.d', """\
test2.d 1
import foo;
""")

test.write('test3.d', """\
test3.d 1
import foo;
""")

test.write('foo.d', "foo.d 1\n")

expect = test.wrap_stdout("""\
%(_python_)s mydc.py test1.o test1.d
Install file: "test1.d" as "test1_d"
Install file: "test2.d" as "test2_d"
Install file: "test3.d" as "test3_d"
""" % locals())

test.run(arguments='.', stdout=expect)

test.must_match('test1.o', """\
test1.d 1
test2.d 1
foo.d 1
test3.d 1
foo.d 1
""")

test.up_to_date(arguments='.')

test.write('foo.d', "foo.d 2\n")

expect = test.wrap_stdout("""\
%(_python_)s mydc.py test1.o test1.d
""" % locals())

test.run(arguments='.', stdout=expect)

test.must_match('test1.o', """\
test1.d 1
test2.d 1
foo.d 2
test3.d 1
foo.d 2
""")

test.up_to_date(arguments='.')

test.write('test3.d', """\
test3.d 2
import foo;
""")

expect = test.wrap_stdout("""\
%(_python_)s mydc.py test1.o test1.d
Install file: "test3.d" as "test3_d"
""" % locals())

test.run(arguments='.', stdout=expect)

test.must_match('test1.o', """\
test1.d 1
test2.d 1
foo.d 2
test3.d 2
foo.d 2
""")

test.up_to_date(arguments='.')

test.write('test2.d', """\
test2.d 2
import foo;
""")

expect = test.wrap_stdout("""\
%(_python_)s mydc.py test1.o test1.d
Install file: "test2.d" as "test2_d"
""" % locals())

test.run(arguments='.', stdout=expect)

test.must_match('test1.o', """\
test1.d 1
test2.d 2
foo.d 2
test3.d 2
foo.d 2
""")

test.up_to_date(arguments='.')

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/Default.py

#!/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 various combinations of arguments to Default() work properly.
"""

import os

import TestSCons

_python_ = TestSCons._python_

test = TestSCons.TestSCons()

for dirname in ['one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight']:
    test.subdir(dirname)
    test.write(os.path.join(dirname, 'foo.in'), dirname + "/foo.in\n")
    test.write(os.path.join(dirname, 'bar.in'), dirname + "/bar.in\n")

test.write('build.py', r"""
import sys
with open(sys.argv[1], 'w') as f, open(sys.argv[2], 'r') as ifp:
    f.write(ifp.read())
""")

#
test.write(['one', 'SConstruct'], """
B = Builder(action = r'%(_python_)s ../build.py $TARGET $SOURCES')
env = Environment(BUILDERS = { 'B' : B })
env.B(target = 'foo.out', source = 'foo.in')
env.B(target = 'bar.out', source = 'bar.in')
Default('foo.out')
""" % locals())

test.write(['two', 'SConstruct'], """
B = Builder(action = r'%(_python_)s ../build.py $TARGET $SOURCES')
env = Environment(BUILDERS = { 'B' : B })
env.B(target = 'foo.out', source = 'foo.in')
env.B(target = 'bar.out', source = 'bar.in')
Default('foo.out', 'bar.out')
""" % locals())

test.write(['three', 'SConstruct'], """
B = Builder(action = r'%(_python_)s ../build.py $TARGET $SOURCES')
env = Environment(BUILDERS = { 'B' : B })
env.B(target = 'foo.out', source = 'foo.in')
env.B(target = 'bar.out', source = 'bar.in')
Default(Split('foo.out bar.out'))
""" % locals())

test.write(['four', 'SConstruct'], """
B = Builder(action = r'%(_python_)s ../build.py $TARGET $SOURCES')
env = Environment(BUILDERS = { 'B' : B })
env.B(target = ['foo bar'], source = 'foo.in')
env.B(target = 'foo', source = 'foo.in')
env.B(target = 'bar', source = 'bar.in')
Default(['foo bar'])
""" % locals())

test.write(['five', 'SConstruct'], """
B = Builder(action = r'%(_python_)s ../build.py $TARGET $SOURCES')
env = Environment(BUILDERS = { 'B' : B })
Default(env.B(target = 'foo.out', source = 'foo.in'))
Default(env.B(target = 'bar.out', source = 'bar.in'))
""" % locals())


for dirname in ['one', 'two', 'three', 'four', 'five']:
    test.run(chdir=dirname)       # no arguments, use the Default

test.must_match(test.workpath('one', 'foo.out'), "one/foo.in\n", mode='r')
test.fail_test(os.path.exists(test.workpath('one', 'bar')))

test.must_match(test.workpath('two', 'foo.out'), "two/foo.in\n", mode='r')
test.must_match(test.workpath('two', 'bar.out'), "two/bar.in\n", mode='r')

test.must_match(test.workpath('three', 'foo.out'), "three/foo.in\n", mode='r')
test.must_match(test.workpath('three', 'bar.out'), "three/bar.in\n", mode='r')

test.fail_test(os.path.exists(test.workpath('four', 'foo')))
test.fail_test(os.path.exists(test.workpath('four', 'bar')))
test.must_match(test.workpath('four', 'foo bar'), "four/foo.in\n", mode='r')

test.must_match(test.workpath('five', 'foo.out'), "five/foo.in\n", mode='r')
test.must_match(test.workpath('five', 'bar.out'), "five/bar.in\n", mode='r')


# Test how a None Default() argument works to disable/reset default targets.
test.write(['six', 'SConstruct'], """\
B = Builder(action = r'%(_python_)s ../build.py $TARGET $SOURCES')
env = Environment(BUILDERS = { 'B' : B })
foo = env.B(target = 'foo.out', source = 'foo.in')
bar = env.B(target = 'bar.out', source = 'bar.in')
Default(None)
""" % locals())

test.run(chdir='six', status=2,
         stderr="scons: *** No targets specified and no Default() targets found.  Stop.\n")

test.write(['seven', 'SConstruct'], """\
B = Builder(action = r'%(_python_)s ../build.py $TARGET $SOURCES')
env = Environment(BUILDERS = { 'B' : B })
foo = env.B(target = 'foo.out', source = 'foo.in')
bar = env.B(target = 'bar.out', source = 'bar.in')
Default(foo, bar, None)
""" % locals())

test.run(chdir='seven', status=2,
         stderr="scons: *** No targets specified and no Default() targets found.  Stop.\n")

test.write(['eight', 'SConstruct'], """\
B = Builder(action = r'%(_python_)s ../build.py $TARGET $SOURCES')
env = Environment(BUILDERS = { 'B' : B })
foo = env.B(target = 'foo.out', source = 'foo.in')
bar = env.B(target = 'bar.out', source = 'bar.in')
Default(foo, None, bar)
""" % locals())

test.run(chdir='eight')       # no arguments, use the Default

test.fail_test(os.path.exists(test.workpath('eight', 'foo.out')))
test.must_match(test.workpath('eight', 'bar.out'), "eight/bar.in\n", mode='r')


test.subdir('nine', ['nine', 'sub1'])

test.write(['nine', 'SConstruct'], """\
B = Builder(action = r'%(_python_)s build.py $TARGET $SOURCES')
env = Environment(BUILDERS = { 'B' : B })
env.B(target = 'xxx.out', source = 'xxx.in')
SConscript('sub1/SConscript')
""" % locals())

test.write(['nine', 'xxx.in'], "xxx.in\n")

test.write(['nine', 'sub1', 'SConscript'], """
B = Builder(action = r'%(_python_)s ../build.py $TARGET $SOURCES')
env = Environment(BUILDERS = { 'B' : B })
env.B(target = 'xxx.out', source = 'xxx.in')
Default('xxx.out')
""" % locals())

test.write(['nine', 'sub1', 'xxx.in'], "sub1/xxx.in\n")

test.run(chdir='nine')        # no arguments, use the Default

test.fail_test(os.path.exists(test.workpath('nine', 'xxx.out')))
test.must_match(test.workpath('nine', 'sub1', 'xxx.out'), "sub1/xxx.in\n", mode='r')


test.subdir('ten', ['ten', 'sub2'])

test.write(['ten', 'SConstruct'], """\
Default('sub2')
B = Builder(action = r'%(_python_)s ../build.py $TARGET $SOURCES')
env = Environment(BUILDERS = { 'B' : B })
env.B(target = 'xxx.out', source = 'xxx.in')
SConscript('sub2/SConscript')
""" % locals())

test.write(['ten', 'xxx.in'], "xxx.in\n")

test.write(['ten', 'sub2', 'SConscript'], """
B = Builder(action = r'%(_python_)s ../build.py $TARGET $SOURCES')
env = Environment(BUILDERS = { 'B' : B })
env.B(target = 'xxx.out', source = 'xxx.in')
""" % locals())

test.write(['ten', 'sub2', 'xxx.in'], "sub2/xxx.in\n")

test.run(chdir='ten')  # no arguments, use the Default

test.fail_test(os.path.exists(test.workpath('ten', 'xxx.out')))
test.must_match(test.workpath('ten', 'sub2', 'xxx.out'), "sub2/xxx.in\n", mode='r')


test.subdir('eleven')

test.write(['eleven', 'SConstruct'], """
B = Builder(action = r'%(_python_)s ../build.py $TARGET $SOURCES')
env = Environment(BUILDERS = { 'B' : B }, XXX = 'foo.out')
env.B(target = 'foo.out', source = 'foo.in')
env.B(target = 'bar.out', source = 'bar.in')
env.Default('$XXX')
""" % locals())

test.write(os.path.join('eleven', 'foo.in'), "eleven/foo.in\n")

test.write(os.path.join('eleven', 'bar.in'), "eleven/bar.in\n")

test.run(chdir='eleven')      # no arguments, use the Default

test.must_match(test.workpath('eleven', 'foo.out'), "eleven/foo.in\n", mode='r')
test.fail_test(os.path.exists(test.workpath('eleven', 'bar')))


test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/Delete.py

#!/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 Delete() Action works.
"""

import sys
import os.path

import TestSCons

test = TestSCons.TestSCons()

test.write('SConstruct', """
Execute(Delete('f1'))
Execute(Delete('d2'))
Execute(Delete('symlinks/filelink'))
Execute(Delete('symlinks/brokenlink'))
Execute(Delete('symlinks/dirlink'))

def cat(env, source, target):
    target = str(target[0])
    with open(target, "wb") as ofp:
        for src in source:
            with open(str(src), "rb") as ifp:
                ofp.write(ifp.read())
Cat = Action(cat)
env = Environment()
env.Command('f3.out', 'f3.in', [Cat, Delete("f4"), Delete("d5")])
env = Environment(FILE='f6', DIR='d7')
env.Command('f8.out', 'f8.in', [Delete("$FILE"), Delete("$DIR"), Cat])
env.Command('f9.out', 'f9.in', [Cat,
                                Delete("Delete-$SOURCE"),
                                Delete("$TARGET-Delete")])

env.Command('f10-nonexistent.out', 'f10.in',
            [Delete("$TARGET"), Cat])

env.Command(Dir('d11-nonexistent.out'), 'd11.in',
            [Delete("$TARGET"), Mkdir("$TARGET")])

env.Command('f12-nonexistent.out', 'f12.in',
            [Delete("$TARGET", must_exist=0), Cat])

env.Command(Dir('d13-nonexistent.out'), 'd13.in',
            [Delete("$TARGET", must_exist=0), Mkdir("$TARGET")])

# Make sure Delete works with a list of arguments
env = Environment(FILE='f14', DIR='d15')
env.Command('f16.out', 'f16.in', [Delete(["$FILE", "$DIR"]), Cat])
""")

test.write('f1', "f1\n")
test.subdir('d2')
test.write(['d2', 'file'], "d2/file\n")
test.write('f3.in', "f3.in\n")
test.write('f4', "f4\n")
test.subdir('d5')
test.write(['d5', 'file'], "d5/file\n")
test.write('f6', "f6\n")
test.subdir('d7')
test.write(['d7', 'file'], "d7/file\n")
test.write('f8.in', "f8.in\n")
test.write('f9.in', "f9.in\n")
test.write('Delete-f9.in', "Delete-f9.in\n")
test.write('f9.out-Delete', "f9.out-Delete\n")
test.write('f10.in', "f10.in\n")
test.subdir('d11.in')
test.write('f12.in', "f12.in\n")
test.subdir('d13.in')
test.write('f14', "f14\n")
test.subdir('d15')
test.write('f16.in', "f16.in\n")
test.subdir('symlinks')
test.subdir('symlinks/dirtarget')
test.write('symlinks/dirtarget/dircontent', 'dircontent content\n')
test.write('symlinks/filetarget', 'filetarget content\n')
test.symlink('filetarget', 'symlinks/filelink')
test.symlink('dirtarget', 'symlinks/dirlink')
test.symlink('brokentarget', 'symlinks/brokenlink')

expect = test.wrap_stdout(read_str = """\
Delete("f1")
Delete("d2")
Delete("symlinks/filelink")
Delete("symlinks/brokenlink")
Delete("symlinks/dirlink")
""",
                          build_str = """\
Delete("d11-nonexistent.out")
Mkdir("d11-nonexistent.out")
Delete("d13-nonexistent.out")
Mkdir("d13-nonexistent.out")
Delete("f10-nonexistent.out")
cat(["f10-nonexistent.out"], ["f10.in"])
Delete("f12-nonexistent.out")
cat(["f12-nonexistent.out"], ["f12.in"])
Delete(["f14", "d15"])
cat(["f16.out"], ["f16.in"])
cat(["f3.out"], ["f3.in"])
Delete("f4")
Delete("d5")
Delete("f6")
Delete("d7")
cat(["f8.out"], ["f8.in"])
cat(["f9.out"], ["f9.in"])
Delete("Delete-f9.in")
Delete("f9.out-Delete")
""")
test.run(options = '-n', arguments = '.', stdout = expect)

test.must_exist('f1')
test.must_exist('d2')
test.must_exist(os.path.join('d2', 'file'))
test.must_not_exist('f3.out')
test.must_exist('f4')
test.must_exist('d5')
test.must_exist(os.path.join('d5', 'file'))
test.must_exist('f6')
test.must_exist('d7')
test.must_exist(os.path.join('d7', 'file'))
test.must_not_exist('f8.out')
test.must_not_exist('f9.out')
test.must_exist('Delete-f9.in')
test.must_exist('f9.out-Delete')
test.must_exist('f14')
test.must_exist('d15')
test.must_not_exist('f16.out')
if sys.platform != 'win32':
    test.must_exist('symlinks')
    test.must_exist('symlinks/dirtarget')
    test.must_exist('symlinks/dirtarget/dircontent')
    test.must_exist('symlinks/filetarget')
    test.must_exist('symlinks/filelink')
    test.must_exist('symlinks/brokenlink')
    test.must_exist('symlinks/dirlink')

test.run()

test.must_not_exist('f1')
test.must_not_exist('d2')
test.must_not_exist(os.path.join('d2', 'file'))
test.must_match('f3.out', "f3.in\n")
test.must_not_exist('f4')
test.must_not_exist('d5')
test.must_not_exist(os.path.join('d5', 'file'))
test.must_not_exist('f6')
test.must_not_exist('d7')
test.must_not_exist(os.path.join('d7', 'file'))
test.must_match('f8.out', "f8.in\n")
test.must_match('f9.out', "f9.in\n")
test.must_not_exist('Delete-f9.in')
test.must_not_exist('f9.out-Delete')
test.must_exist('f10-nonexistent.out')
test.must_exist('d11-nonexistent.out')
test.must_exist('f12-nonexistent.out')
test.must_exist('d13-nonexistent.out')
test.must_not_exist('f14')
test.must_not_exist('d15')
test.must_match('f16.out', "f16.in\n")
if sys.platform != 'win32':
    test.must_exist('symlinks')
    test.must_exist('symlinks/dirtarget')
    test.must_exist('symlinks/dirtarget/dircontent')
    test.must_exist('symlinks/filetarget')
    test.must_not_exist('symlinks/filelink')
    test.must_not_exist('symlinks/brokenlink')
    test.must_not_exist('symlinks/dirlink')

test.write("SConstruct", """\
def cat(env, source, target):
    target = str(target[0])
    with open(target, "wb") as ifp:
        for src in source:
            with open(str(src), "rb") as ofp:
                ofp.write(ifp.read())
Cat = Action(cat)
env = Environment()
env.Command('f14-nonexistent.out', 'f14.in', [Delete("$TARGET", must_exist=1),
                                              Cat])
""")

test.write('f14.in', "f14.in\n")

test.run(status=2, stderr=None)

fail_strings = [
    "No such file or directory",
    "The system cannot find the file specified",
    "The system cannot find the path specified",
    "Das System kann die angegebene Datei nicht finden",
]

test.must_contain_any_line(test.stderr(), fail_strings)

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/ENV.py

#!/usr/bin/env python
#
# __COPYRIGHT__
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"

import os
import TestSCons

_python_ = TestSCons._python_

test = TestSCons.TestSCons()

bin1_build_py = test.workpath('bin1', 'build.py')
bin2_build_py = test.workpath('bin2', 'build.py')

test.write('SConstruct', """
import os
Bld = Builder(action = r'%(_python_)s build.py $TARGET $SOURCES')
env1 = Environment(BUILDERS = { 'Bld' : Bld })
env2 = Environment(BUILDERS = { 'Bld' : Bld })
env1['ENV']['X'] = 'env1'
env2['ENV']['X'] = 'env2'
env1.Bld(target = 'env1.out', source = 'input')
env2.Bld(target = 'env2.out', source = 'input')
""" % locals())

test.write('build.py',
r"""\
import os
import sys
with open(sys.argv[2], 'r') as f:
    contents = f.read()
with open(sys.argv[1], 'w') as f:
    f.write("build.py %s\n%s" % (os.environ['X'], contents))
""")

test.write('input', "input file\n")

test.run(arguments = '.')

test.must_match('env1.out', "build.py env1\ninput file\n", mode='r')
test.must_match('env2.out', "build.py env2\ninput file\n", mode='r')


test.write('SConstruct', """
env = Environment()
foo = env.Command('foo', [], r'%(_python_)s build.py $TARGET')
env['ENV']['LIST'] = [foo, 'bar']
env['ENV']['FOO'] = foo
""" % locals())

test.write('build.py', r"""
import os
print('LIST:', os.environ['LIST'])
print('FOO:', os.environ['FOO'])
""")

test.run()

expect = [
    "LIST: foo%sbar" % os.pathsep,
    "FOO: foo",
]

test.must_contain_all_lines(test.stdout(), expect)

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/ESCAPE.py

#!/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 the ESCAPE construction variable.
"""

import TestSCons

_python_ = TestSCons._python_

test = TestSCons.TestSCons()

test.write('cat.py', """\
import sys
with open(sys.argv[1], 'wb') as ofp:
    for s in sys.argv[2:]:
        with open(s, 'rb') as ifp:
            ofp.write(ifp.read())
""")

test.write('SConstruct', """\
# We still need to run this through the original ESCAPE function,
# because that's set up to work in tandem with the existing SHELL,
# which we're not replacing.
orig_escape = Environment()['ESCAPE']
def my_escape(s):
    s = s.replace('file.in', 'file.xxx')
    return orig_escape(s)
env = Environment(ESCAPE = my_escape)
env.Command('file.out', 'file.in', r'%(_python_)s cat.py $TARGET $SOURCES')
""" % locals())

test.write('file.in', "file.in\n")
test.write('file.xxx', "file.xxx\n")

test.run()

test.must_match('file.out', "file.xxx\n")

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/EnsurePythonVersion.py

#!/usr/bin/env python
#
# __COPYRIGHT__
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#

__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"

import TestSCons

test = TestSCons.TestSCons()


test.write('SConstruct', """\
EnsurePythonVersion(0,0)
Exit(0)
""")

test.run()

test.write('SConstruct', """\
EnsurePythonVersion(2000,0)
Exit(0)
""")

test.run(status=2)



test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/EnsureSConsVersion.py

#!/usr/bin/env python
#
# __COPYRIGHT__
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#

__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"

import TestSCons

test = TestSCons.TestSCons()

import SCons

if SCons.__version__ != "__VERSION__":

    test.write('SConstruct', """\
env = Environment()
env.EnsureSConsVersion(0,0)
Exit(0)
""")

    test.run()

    test.write('SConstruct', """\
env = Environment()
env.EnsureSConsVersion(1,0)
Exit(0)
""")

    test.run()

    test.write('SConstruct', """\
env = Environment()
env.EnsureSConsVersion(5,0)
Exit(0)
""")

    test.run(status=2)

    test.write('SConstruct', """\
EnsureSConsVersion(2000,0)
Exit(0)
""")

    test.run(status=2)



test.write('SConstruct', """\
import SCons
SCons.__version__ = '0.33.2'
EnsureSConsVersion(0,33)
""")

test.run()

test.write('SConstruct', """\
import SCons
SCons.__version__ = '0.33.2'
EnsureSConsVersion(0,33,0)
""")

test.run()

test.write('SConstruct', """\
import SCons
SCons.__version__ = '0.33.2'
EnsureSConsVersion(0,33,1)
""")

test.run()

test.write('SConstruct', """\
import SCons
SCons.__version__ = '0.33.2'
EnsureSConsVersion(0,33,2)
""")

test.run()

test.write('SConstruct', """\
import SCons
SCons.__version__ = '0.33.2'
EnsureSConsVersion(0,33,3)
""")

test.run(status=2)

test.write('SConstruct', """\
import SCons
SCons.__version__ = '0.33.2'
EnsureSConsVersion(0,34)
""")

test.run(status=2)

test.write('SConstruct', """\
import SCons
SCons.__version__ = '0.33.2'
EnsureSConsVersion(1,0)
""")

test.run(status=2)



test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/Entry.py

#!/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 Entry() global function and environment method work
correctly, and that the former does not try to expand construction
variables.
"""

import TestSCons

test = TestSCons.TestSCons()

test.write('SConstruct', """
env = Environment(FOO = 'fff', BAR = 'bbb')
print(Entry('ddd'))
print(Entry('$FOO'))
print(Entry('${BAR}_$BAR'))
print(env.Entry('eee'))
print(env.Entry('$FOO'))
print(env.Entry('${BAR}_$BAR'))
""")

test.run(stdout = test.wrap_stdout(read_str = """\
ddd
$FOO
${BAR}_$BAR
eee
fff
bbb_bbb
""", build_str = """\
scons: `.' is up to date.
"""))

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/Environment.py

#!/usr/bin/env python
#
# __COPYRIGHT__
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#

__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"

import TestSCons

_python_ = TestSCons._python_

test = TestSCons.TestSCons()

test.write('SConstruct', """
env=Environment(BAR='#bar.in', BLAT='subdir/../blat blat')
target = env.Command('foo.out',
                     'foo.in',
                     r'%(_python_)s build.py $SOURCE $TARGET ${File(BAR)} ${Dir(BLAT)}')

target = target[0]
assert target == Dir('.').File('foo.out')
assert Dir('.') == Dir('.').Dir('.')
assert target == target.File('foo.out')

e2 = env.Environment(XXX='$BAR', YYY='$BLAT')
print(e2['XXX'])
print(e2['YYY'])
""" % locals())

test.write('build.py', """
import sys
assert sys.argv[1] == 'foo.in', sys.argv[1]
assert sys.argv[2] == 'foo.out', sys.argv[2]
assert sys.argv[3] == 'bar.in', sys.argv[3]
assert sys.argv[4] == 'blat blat', sys.argv[4]
""")

test.write('foo.in', "foo.in\n")

test.run(arguments='foo.out')

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/Execute.py

#!/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 the Execute() function for executing actions directly.
"""
import sys
import TestSCons

_python_ = TestSCons._python_

test = TestSCons.TestSCons()

test.write('my_copy.py', """\
import sys
with open(sys.argv[2], 'wb') as ofp, open(sys.argv[1], 'rb') as ifp:
    ofp.write(ifp.read())
try:
    exitval = int(sys.argv[3])
except IndexError:
    exitval = 0
sys.exit(exitval)
""")

test.write('SConstruct', """\
Execute(r'%(_python_)s my_copy.py a.in a.out')
Execute(Action(r'%(_python_)s my_copy.py b.in b.out'))
env = Environment(COPY = 'my_copy.py')
env.Execute(r'%(_python_)s my_copy.py c.in c.out')
env.Execute(Action(r'%(_python_)s my_copy.py d.in d.out'))
v = env.Execute(r'%(_python_)s $COPY e.in e.out')
assert v == 0, v
v = env.Execute(Action(r'%(_python_)s $COPY f.in f.out'))
assert v == 0, v
v = env.Execute(r'%(_python_)s $COPY g.in g.out 1')
assert v == 1, v
v = env.Execute(Action(r'%(_python_)s $COPY h.in h.out 2'))
assert v == 2, v
import shutil
Execute(lambda target, source, env: shutil.copy('i.in', 'i.out'))
Execute(Action(lambda target, source, env: shutil.copy('j.in', 'j.out')))
env.Execute(lambda target, source, env: shutil.copy('k.in', 'k.out'))
env.Execute(Action(lambda target, source, env: shutil.copy('l.in', 'l.out')))

Execute(Copy('m.out', 'm.in'))
Execute(Copy('nonexistent.out', 'nonexistent.in'))
""" % locals())

test.write('a.in', "a.in\n")
test.write('b.in', "b.in\n")
test.write('c.in', "c.in\n")
test.write('d.in', "d.in\n")
test.write('e.in', "e.in\n")
test.write('f.in', "f.in\n")
test.write('g.in', "g.in\n")
test.write('h.in', "h.in\n")
test.write('i.in', "i.in\n")
test.write('j.in', "j.in\n")
test.write('k.in', "k.in\n")
test.write('l.in', "l.in\n")
test.write('m.in', "m.in\n")

if sys.platform == 'win32' and sys.version_info[0] == 3:
    expect = r"""scons: \*\*\* Error 1
scons: \*\*\* Error 2
scons: \*\*\* nonexistent.in: (The system cannot find the path specified|Das System kann den angegebenen Pfad nicht finden)"""

else:
    expect = r"""scons: \*\*\* Error 1
scons: \*\*\* Error 2
scons: \*\*\* nonexistent\.in: No such file or directory"""

test.run(arguments = '.', stdout = None, stderr = None)

test.must_contain_all_lines(test.stderr(), expect.splitlines(), find=TestSCons.search_re)

test.must_match('a.out', "a.in\n")
test.must_match('b.out', "b.in\n")
test.must_match('c.out', "c.in\n")
test.must_match('d.out', "d.in\n")
test.must_match('e.out', "e.in\n")
test.must_match('f.out', "f.in\n")
test.must_match('g.out', "g.in\n")
test.must_match('h.out', "h.in\n")
test.must_match('i.out', "i.in\n")
test.must_match('j.out', "j.in\n")
test.must_match('k.out', "k.in\n")
test.must_match('l.out', "l.in\n")
test.must_match('m.out', "m.in\n")

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/ExecuteInvalidateCache.py

#!/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 the Execute() functions clears the memoized values of affected target Nodes
when used with Delete(). Derived from
https://github.com/SCons/scons/issues/1307
"""

import TestSCons
import os.path

test = TestSCons.TestSCons()

subfn = os.path.join('sub', 'foo')

test.write('SConstruct', """\
def exists(node):
    if node.exists():
        print(str(node)+" exists")
    else:
        print(str(node)+" does not exist")

Execute(Delete('abc'))
n1 = File('abc')
exists( n1 )
Execute(Touch('abc'))
exists( n1 )
Execute(Delete('abc'))
exists( n1 )

env = Environment()
env.Execute(Delete('def'))
n2 = env.File('def')
exists( n2 )
env.Execute(Touch('def'))
exists( n2 )
env.Execute(Delete(n2))
exists( n2 )

Execute(Touch('abc'))
exists( n1 )
Execute(Move('def', 'abc'))
exists( n1 )
exists( n2 )

Execute(Copy('abc', 'def'))
exists( n1 )

n3 = File(r"%(subfn)s")
exists( n3 )
Execute(Mkdir('sub'))
Execute(Touch(r"%(subfn)s"))
exists( n3 )
""" % locals())


expect = test.wrap_stdout(read_str="""\
Delete("abc")
abc does not exist
Touch("abc")
abc exists
Delete("abc")
abc does not exist
Delete("def")
def does not exist
Touch("def")
def exists
Delete("def")
def does not exist
Touch("abc")
abc exists
Move("def", "abc")
abc does not exist
def exists
Copy("abc", "def")
abc exists
%(subfn)s does not exist
Mkdir("sub")
Touch("%(subfn)s")
%(subfn)s exists
""" % locals(), build_str = "scons: `.' is up to date.\n")

test.run(arguments = '.', stdout = expect)

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/Exit.py

#!/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 the explicit Exit() function.
"""

import os.path

import TestSCons

test = TestSCons.TestSCons()

test.subdir('subdir')

subdir_foo_in = os.path.join('subdir', 'foo.in')
subdir_foo_out = os.path.join('subdir', 'foo.out')

test.write('SConstruct', """\
print("SConstruct, Exit()")
Exit()
""")

test.run(stdout = """\
scons: Reading SConscript files ...
SConstruct, Exit()
""")

test.write('SConstruct', """\
env = Environment()
print("SConstruct, env.Exit()")
env.Exit()
""")

test.run(stdout = """\
scons: Reading SConscript files ...
SConstruct, env.Exit()
""")

test.write('SConstruct', """\
print("SConstruct")
Exit(7)
""")

test.run(status = 7, stdout = """\
scons: Reading SConscript files ...
SConstruct
""")

test.write('SConstruct', """\
print("SConstruct")
SConscript('subdir/SConscript')
""")

test.write(['subdir', 'SConscript'], """\
print("subdir/SConscript")
Exit()
""")

test.run(stdout = """\
scons: Reading SConscript files ...
SConstruct
subdir/SConscript
""")

test.write(['subdir', 'SConscript'], """\
print("subdir/SConscript")
Exit(17)
""")

test.run(status = 17, stdout = """\
scons: Reading SConscript files ...
SConstruct
subdir/SConscript
""")

test.write('SConstruct', """\
SConscript('subdir/SConscript')
""")

test.write(['subdir', 'SConscript'], """\
def exit_builder(env, source, target):
    target = str(target[0])
    with open(target, "wb") as f:
        for src in source:
            with open(str(src), "rb") as ifp:
                f.write(ifp.read())
    Exit(27)
env = Environment(BUILDERS = {'my_exit' : Builder(action=exit_builder)})
env.my_exit('foo.out', 'foo.in')
""")

test.write(['subdir', 'foo.in'], "subdir/foo.in\n")

test.run(status = 27,
         stdout = test.wrap_stdout("""\
exit_builder(["%s"], ["%s"])
""" % (subdir_foo_out, subdir_foo_in), error=1),
         stderr = """\
scons: *** [%s] Explicit exit, status 27
""" % subdir_foo_out)

test.must_match(['subdir', 'foo.out'], "subdir/foo.in\n")

test.write('SConstruct', """\
def exit_scanner(node, env, target):
    Exit(37)

exitscan = Scanner(function = exit_scanner, skeys = ['.k'])

def cat(env, source, target):
    target = str(target[0])
    with open(target, 'wb') as ofp:
        for src in source:
            with open(str(src), "rb") as ifp:
                outf.write(ifp.read())

env = Environment(BUILDERS={'Cat':Builder(action=cat)})
env.Append(SCANNERS = [exitscan])

env.Cat('foo', 'foo.k')
""")

test.write('foo.k', "foo.k\n")

test.run(status = 37,
         stdout = test.wrap_stdout("", error=1),
         stderr = "scons: *** [foo] Explicit exit, status 37\n")

#
test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/FindFile.py

#!/usr/bin/env python
#
# __COPYRIGHT__
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#

__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"

import TestSCons

test = TestSCons.TestSCons()

test.subdir('foo')
test.subdir('bar')
test.subdir(['bar', 'baz'])

test.write('testfile1', 'test 1\n')
test.write(['foo', 'testfile2'], 'test 2\n')
test.write(['bar', 'testfile1'], 'test 3\n')
test.write(['bar', 'baz', 'testfile2'], 'test 4\n')

test.write('SConstruct', """
env = Environment(FILE = 'file', BAR = 'bar')
file1 = FindFile('testfile1', [ 'foo', '.', 'bar', 'bar/baz' ])
with open(str(file1), 'r') as f:
    print(f.read())
file2 = env.FindFile('test${FILE}1', [ 'bar', 'foo', '.', 'bar/baz' ])
with open(str(file2), 'r') as f:
    print(f.read())
file3 = FindFile('testfile2', [ 'foo', '.', 'bar', 'bar/baz' ])
with open(str(file3), 'r') as f:
    print(f.read())
file4 = env.FindFile('testfile2', [ '$BAR/baz', 'foo', '.', 'bar' ])
with open(str(file4), 'r') as f:
    print(f.read())
""")

expect = test.wrap_stdout(read_str = """test 1

test 3

test 2

test 4

""", build_str = "scons: `.' is up to date.\n")

test.run(arguments = ".", stdout = expect)

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/FindSourceFiles.py

#!/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 Environment's FindSourceFiles method.
"""

import sys
import TestSCons

test = TestSCons.TestSCons()

package_format = "src_tarbz2"
if not test.where_is('tar') or sys.platform == 'win32':
    if not test.where_is('zip'):
        test.skip_test("neither 'tar' nor 'zip' found; skipping test\n")
    package_format = "src_zip"

# Quite complex, but real-life test.
# 0. Setup VariantDir, "var", without duplication. The "src" is source dir.
# 1. Generate souce file var/foo.c from src/foo.c.in. Define program foo.
# 2. Gather all sources necessary to create '.' node and create source
#    tarball. We expect 'src/foo.c.in' file within tarball, and no content
#    under 'var' directory.
test.subdir('src')

test.write('SConstruct', """
VariantDir(src_dir = 'src', variant_dir = 'var', duplicate = 0)
env = Environment(tools = ['default','textfile','packaging'])
SConscript(['var/SConscript'], exports = 'env')
sources = env.FindSourceFiles('.')
pkg = env.Package( NAME = 'foo', VERSION = '1.0', PACKAGETYPE = '%s',
                   source = sources )
Ignore( '.', pkg )
""" % package_format)

test.write('src/SConscript', """
Import('env')
foo_c = env.Substfile('foo.c.in', SUBST_DICT = {'__A__' : '0' })
foo = env.Program(foo_c)
""")

test.write('src/foo.c.in', """ int main(void) { return __A__;}
""")

test.run(arguments = 'package')

test.must_exist('foo-1.0/src/SConscript')
test.must_exist('foo-1.0/src/foo.c.in')
test.must_not_exist('foo-1.0/var/SConscript')
test.must_not_exist('foo-1.0/var/foo.c.in')

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/Flatten.py

#!/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 the Flatten() function is available and works.
"""

import TestSCons

test = TestSCons.TestSCons()

test.subdir('work')

test.write(['work', 'SConstruct'], """
def cat(env, source, target):
    target = str(target[0])
    with open(target, "wb") as ofp:
        for src in source:
            with open(str(src), "rb") as ifp:
                ofp.write(ifp.read())
env = Environment(BUILDERS={'Cat':Builder(action=cat)})
f1 = env.Cat('../file1.out', 'file1.in')
f2 = env.Cat('../file2.out', ['file2a.in', 'file2b.in'])
print(list(map(str, Flatten(['begin', f1, 'middle', f2, 'end']))))
print(list(map(str, env.Flatten([f1, [['a', 'b'], 'c'], f2]))))
SConscript('SConscript', "env")
""")

test.write(['work', 'SConscript'], """
Import("env")
print(Flatten([1, [2, 3], 4]))
print(env.Flatten([[[[1], 2], 3], 4]))
""")

test.write('file1.in', "file1.in\n")
test.write('file2a.in', "file2a.in\n")
test.write('file2b.in', "file2b.in\n")

def double_backslash(f):
    p = test.workpath(f)
    return p.replace('\\', '\\\\')

expect = """\
['begin', '%s', 'middle', '%s', 'end']
['%s', 'a', 'b', 'c', '%s']
[1, 2, 3, 4]
[1, 2, 3, 4]
""" % (double_backslash('file1.out'), double_backslash('file2.out'),
       double_backslash('file1.out'), double_backslash('file2.out'))

test.run(chdir = "work",
         arguments = ".",
         stdout = test.wrap_stdout(read_str = expect,
                                   build_str = "scons: `.' is up to date.\n"))

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/HeaderGen.py

#!/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 dependencies in generated header files get re-scanned correctly
and that generated header files don't cause circular dependencies.
"""

import TestSCons

test = TestSCons.TestSCons()

test.write('SConstruct', """\
def writeFile(target, contents):
    with open(str(target[0]), 'w') as f:
        f.write(contents)
    return 0

env = Environment()
libgen = env.StaticLibrary('gen', 'gen.cpp')
Default(libgen)
env.Command('gen2.h', [],
            lambda env,target,source: writeFile(target, 'int foo = 3;\\n'))
env.Command('gen.h', [],
            lambda env,target,source: writeFile(target, '#include "gen2.h"\\n'))
env.Command('gen.cpp', [],
            lambda env,target,source: writeFile(target, '#include "gen.h"\\n'))
""")

test.run(stderr=TestSCons.noisy_ar,
         match=TestSCons.match_re_dotall)

test.up_to_date(arguments = '.')

test.write('SConstruct', """\
env = Environment()

def gen_a_h(target, source, env):
    with open(str(target[0]), 'w') as t, open(str(source[0]), 'r') as s:
        s.readline()
        t.write(s.readline()[:-1] + ';\\n')

MakeHeader = Builder(action = gen_a_h)
env_no_scan = env.Clone(SCANNERS=[], BUILDERS={'MakeHeader' : MakeHeader})
env_no_scan.MakeHeader('a.h', 'a.c')

env.StaticObject('a.c')
""")

test.write('a.c', """\
#include "a.h"
void a(void)
{
        ;
}
""")

test.run()

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/HeaderInstall.py

#!/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 dependencies in installed header files get re-scanned correctly.
"""

import os.path

import TestSCons

test = TestSCons.TestSCons()

test.subdir('work1', ['work1', 'dist'])

test.write(['work1', 'SConstruct'], """
env = Environment(CPPPATH=['#include'])
Export('env')
SConscript('dist/SConscript')
libfoo = env.StaticLibrary('foo', ['foo.c'])
Default(libfoo)
""")

test.write(['work1', 'foo.c'], """
#include <h1.h>
""")

test.write(['work1', 'dist', 'SConscript'], """\
Import('env')
env.Install('#include', ['h1.h', 'h2.h', 'h3.h'])
""")

test.write(['work1', 'dist', 'h1.h'], """\
#include "h2.h"
""")

test.write(['work1', 'dist', 'h2.h'], """\
#include "h3.h"
""")

test.write(['work1', 'dist', 'h3.h'], """\
int foo = 3;
""")

test.run(chdir='work1', arguments=".",
         stderr=TestSCons.noisy_ar,
         match=TestSCons.match_re_dotall)

test.up_to_date(chdir = 'work1', arguments = ".")

#
test.subdir('ref', 'work2', ['work2', 'src'])

test.write(['work2', 'SConstruct'], """
env = Environment(CPPPATH=['build', r'%s'])
env.Install('build', 'src/in1.h')
env.Install('build', 'src/in2.h')
env.Install('build', 'src/in3.h')
""" % test.workpath('ref'))

test.write(['ref', 'in1.h'], '#define FILE "ref/in1.h"\n#include <in2.h>\n')
test.write(['ref', 'in2.h'], '#define FILE "ref/in2.h"\n#include <in3.h>\n')
test.write(['ref', 'in3.h'], '#define FILE "ref/in3.h"\n#define FOO 0\n')

src_in1_h = '#define FILE "src/in1.h"\n#include <in2.h>\n'
src_in2_h = '#define FILE "src/in2.h"\n#include <in3.h>\n'
src_in3_h = '#define FILE "src/in3.h"\n#define FOO 0\n'
test.write(['work2', 'src', 'in1.h'], src_in1_h)
test.write(['work2', 'src', 'in2.h'], src_in2_h)
test.write(['work2', 'src', 'in3.h'], src_in3_h)

test.run(chdir = 'work2', arguments = 'build')

test.must_match(['work2', 'build', 'in1.h'], src_in1_h)
test.must_match(['work2', 'build', 'in2.h'], src_in2_h)
test.must_match(['work2', 'build', 'in3.h'], src_in3_h)

test.up_to_date(chdir = 'work2', arguments = 'build')

src_in3_h = '#define FILE "src/in3.h"\n#define FOO 1\n'
test.write(['work2', 'src', 'in3.h'], src_in3_h)

test.run(chdir = 'work2', arguments = 'build', stdout=test.wrap_stdout("""\
Install file: "%s" as "%s"
""" % (os.path.join('src', 'in3.h'),
       os.path.join('build', 'in3.h'))))

test.must_match(['work2', 'build', 'in1.h'], src_in1_h)
test.must_match(['work2', 'build', 'in2.h'], src_in2_h)
test.must_match(['work2', 'build', 'in3.h'], src_in3_h)

test.up_to_date(chdir = 'work2', arguments = 'build')

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/Help.py

#!/usr/bin/env python
#
# __COPYRIGHT__
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#

__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"

import TestSCons

test = TestSCons.TestSCons()

wpath = test.workpath()

test.write('SConstruct', r"""
Help("Help text\ngoes here.\n")
""")

expect = """scons: Reading SConscript files ...
scons: done reading SConscript files.
Help text
goes here.

Use scons -H for help about command-line options.
"""

test.run(arguments = '-h', stdout = expect)

test.write('SConstruct', r"""
env = Environment(MORE='more', HELP='help')
env.Help("\nEven $MORE\n$HELP text!\n")
""")

expect = """scons: Reading SConscript files ...
scons: done reading SConscript files.

Even more
help text!

Use scons -H for help about command-line options.
"""

test.run(arguments = '-h', stdout = expect)

test.write('SConstruct', r"""
Help('\nMulti')
Help('line\n')
Help('''\
help
text!
''')
""")

expect = """\
scons: Reading SConscript files ...
scons: done reading SConscript files.

Multiline
help
text!

Use scons -H for help about command-line options.
"""

test.run(arguments = '-h', stdout = expect)

# Bug #2831 - append flag to Help doesn't wipe out addoptions and variables used together
test.write('SConstruct', r"""

AddOption('--debugging',
	dest='debugging',
	action='store_true',
	default=False,
	metavar='BDEBUGGING',
	help='Compile with debugging symbols')

vars = Variables()
vars.Add(ListVariable('buildmod', 'List of modules to build', 'none',
                    ['python']))

env = Environment()

Help(vars.GenerateHelpText(env),append=True)
""")

expect = ".*--debugging.*Compile with debugging symbols.*buildmod: List of modules to build.*"

test.run(arguments = '-h', stdout = expect, match=TestSCons.match_re_dotall)


# Bug 2831
# This test checks to verify that append=False doesn't include anything
# but the expected help for the specified Variable()

test.write('SConstruct', r"""

AddOption('--debugging',
	dest='debugging',
	action='store_true',
	default=False,
	metavar='BDEBUGGING',
	help='Compile with debugging symbols')

vars = Variables()
vars.Add(ListVariable('buildmod', 'List of modules to build', 'none',
                    ['python']))

env = Environment()

Help(vars.GenerateHelpText(env),append=False)
""")

expect = """\
scons: Reading SConscript files ...
scons: done reading SConscript files.

buildmod: List of modules to build
    (all|none|comma-separated list of names)
    allowed names: python
    default: none
    actual: None

Use scons -H for help about command-line options.
"""

test.run(arguments = '-h', stdout = expect)



test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/Ignore.py

#!/usr/bin/env python
#
# __COPYRIGHT__
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#

__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"

import os.path

import TestSCons

_python_ = TestSCons._python_

test = TestSCons.TestSCons()

test.subdir('subdir')

test.write('build.py', r"""
import sys
with open(sys.argv[2], 'rb') as afp2, open(sys.argv[3], 'rb') as afp3:
    contents = afp2.read() + afp3.read()
with open(sys.argv[1], 'wb') as f:
    for arg in sys.argv[2:]:
        with open(arg, 'rb') as ifp:
            f.write(ifp.read())
""")

SUBDIR_f3_out = os.path.join('$SUBDIR', 'f3.out')
SUBDIR_f3b_in = os.path.join('$SUBDIR', 'f3b.in')

test.write('SConstruct', """\
Foo = Builder(action = r'%(_python_)s build.py $TARGET $SOURCES')
Bar = Builder(action = r'%(_python_)s build.py $TARGET $SOURCES')
env = Environment(BUILDERS = { 'Foo' : Foo, 'Bar' : Bar }, SUBDIR='subdir')
env.Foo(target = 'f1.out', source = ['f1a.in', 'f1b.in'])
Ignore(target = 'f1.out', dependency = 'f1b.in')
SConscript('subdir/SConscript', "env")
env.Foo(target = 'subdir/f3.out', source = ['subdir/f3a.in', 'subdir/f3b.in'])
env.Ignore(target = r'%(SUBDIR_f3_out)s', dependency = r'%(SUBDIR_f3b_in)s')
""" % locals())

test.write(['subdir', 'SConscript'], """
Import("env")
env.Bar(target = 'f2.out', source = ['f2a.in', 'f2b.in'])
env.Ignore('f2.out', 'f2a.in')
""")

test.write('f1a.in', "f1a.in\n")
test.write('f1b.in', "f1b.in\n")

test.write(['subdir', 'f2a.in'], "subdir/f2a.in\n")
test.write(['subdir', 'f2b.in'], "subdir/f2b.in\n")

test.write(['subdir', 'f3a.in'], "subdir/f3a.in\n")
test.write(['subdir', 'f3b.in'], "subdir/f3b.in\n")

test.run(arguments = '.')

test.must_match('f1.out', "f1a.in\nf1b.in\n")
test.must_match(['subdir', 'f2.out'], "subdir/f2a.in\nsubdir/f2b.in\n")
test.must_match(['subdir', 'f3.out'], "subdir/f3a.in\nsubdir/f3b.in\n")

test.up_to_date(arguments = '.')

test.write('f1b.in', "f1b.in 2\n")
test.write(['subdir', 'f2a.in'], "subdir/f2a.in 2\n")
test.write(['subdir', 'f3b.in'], "subdir/f3b.in 2\n")

test.up_to_date(arguments = '.')

test.must_match('f1.out', "f1a.in\nf1b.in\n")
test.must_match(['subdir', 'f2.out'], "subdir/f2a.in\nsubdir/f2b.in\n")
test.must_match(['subdir', 'f3.out'], "subdir/f3a.in\nsubdir/f3b.in\n")

test.write('f1a.in', "f1a.in 2\n")
test.write(['subdir', 'f2b.in'], "subdir/f2b.in 2\n")
test.write(['subdir', 'f3a.in'], "subdir/f3a.in 2\n")

test.run(arguments = '.')

test.must_match('f1.out', "f1a.in 2\nf1b.in 2\n")
test.must_match(['subdir', 'f2.out'], "subdir/f2a.in 2\nsubdir/f2b.in 2\n")
test.must_match(['subdir', 'f3.out'], "subdir/f3a.in 2\nsubdir/f3b.in 2\n")

test.up_to_date(arguments = '.')

#
test.write('SConstruct', """\
env = Environment()
file1 = File('file1')
file2 = File('file2')
env.Ignore(file1, [[file2, 'file3']])
""")

test.up_to_date(arguments = '.')

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/KeyboardInterrupt.py

#!/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 handle keyboard interrupts (CTRL-C) correctly.
"""

import TestSCons

test = TestSCons.TestSCons()

test.write('toto.c', r"""
void foo()
{}
""")

test.write('SConstruct', r"""
import os
import sys
import signal

if 'killpg' not in dir(os) or 'setpgrp' not in dir(os) or sys.platform == 'cygwin':
    # The platform does not support process group. Therefore, we
    # directly invoked the SIGINT handler to simulate a
    # KeyboardInterrupt. This hack is necessary because there is no
    # easy way to get access to the current Job/Taskmaster object.
    #
    # Note that this way of performing the test is not as good as
    # using killpg because the Taskmaster is stopped synchronously. In
    # addition, the SCons subprocesses (or forked children before the
    # exec() of the subprocess) are never killed. This therefore
    # exercise less SCons functionality.
    #
    # FIXME: There seems to be a bug on Cygwin where the compiler
    # process hangs after sending the SIGINT signal to the process
    # group. It is probably a bug in cygwin1.dll, or maybe in the
    # Python 'C' code or the Python subprocess module. We therefore do
    # not use 'killpg' on Cygwin.
    def explode(env, target, source):
        handler = signal.getsignal(signal.SIGINT)
        handler(signal.SIGINT, None)
        return 0        
else:
    # The platform does support process group so we use killpg to send
    # a SIGINT to everyone.

    # Make sure that SCons is a process group leader.
    os.setpgrp()

    def explode(env, target, source):
        os.killpg(0, signal.SIGINT)


all = []

for i in range(40):
    all.extend(Object('toto%5d' % i, 'toto.c'))

all.extend(Command( 'broken', 'toto.c', explode))

Default( Alias('all', all))
"""
)

interruptedStr = """\
.*\
scons: building terminated because of errors\\.
.*\
scons: writing .sconsign file\\.
.*\
"""

def runtest(arguments):
    test.run(arguments='-c')
    test.run(arguments=arguments, status=2,
             stdout=interruptedStr,
             stderr='.*scons: Build interrupted\\.',
             match=TestSCons.match_re_dotall)

for i in range(2):
    runtest('-j1')
    runtest('-j4')
    runtest('-j8')
    runtest('-j16')
    runtest('-j32')
    runtest('-j64')

    runtest('-j1 --random')
    runtest('-j4 --random')
    runtest('-j8 --random')
    runtest('-j16 --random')
    runtest('-j32 --random')
    runtest('-j64 --random')

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/LoadableModule.py

#!/usr/bin/env python
#
# __COPYRIGHT__
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#

__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"

import os
import sys

import TestCmd
import TestSCons

dll_ = TestSCons.dll_
_dll = TestSCons._dll

test = TestSCons.TestSCons()

# Some systems apparently need -ldl on the link line, others don't.
no_dl_lib = "env.Program(target = 'dlopenprog', source = 'dlopenprog.c')"
use_dl_lib = "env.Program(target = 'dlopenprog', source = 'dlopenprog.c', LIBS=['dl'])"

dlopen_line = {
    'darwin' : no_dl_lib,
    'freebsd4' : no_dl_lib,
    'linux2' : use_dl_lib,
    'linux3' : use_dl_lib,
}
platforms_with_dlopen = list(dlopen_line.keys())

test.write('SConstruct', """
env = Environment()
# dlopenprog tries to dynamically load foo1 at runtime using dlopen().
env.LoadableModule(target = 'foo1', source = 'f1.c')
""" + dlopen_line.get(sys.platform, ''))


test.write('f1.c', r"""
#include <stdio.h>

void
f1(void)
{
        printf("f1.c\n");
        fflush(stdout);
}
""")

dlopenprog = r"""
#include <errno.h>
#include <stdio.h>
#include <dlfcn.h>

extern int errno;

int
main(int argc, char *argv[])
{
        argv[argc++] = "--";
        void *foo1_shobj = dlopen("__foo1_name__", RTLD_NOW);
        if(!foo1_shobj){
          printf("Error loading foo1 '__foo1_name__' library at runtime, exiting.\n");
          printf("%d\n", errno);
          perror("");
          return -1;
        }
        void (*f1)() = dlsym(foo1_shobj, "f1\0");
        (*f1)();
        printf("dlopenprog.c\n");
        dlclose(foo1_shobj);
        return 0;
}
"""

# Darwin dlopen()s a bundle named "foo1",
# other systems dlopen() a traditional libfoo1.so file.
foo1_name = {'darwin' : 'foo1'}.get(sys.platform[:6], dll_+'foo1'+_dll)

test.write('dlopenprog.c',
           dlopenprog.replace('__foo1_name__', foo1_name))

test.run(arguments = '.',
         stderr=TestSCons.noisy_ar,
         match=TestSCons.match_re_dotall)

# TODO: Add new Intel-based Macs?  Why are we only picking on Macs?
#if sys.platform.find('darwin') != -1:
#    test.run(program='/usr/bin/file',
#             arguments = "foo1",
#             match = TestCmd.match_re,
#             stdout="foo1: Mach-O bundle (ppc|i386)\n")
# My laptop prints "foo1: Mach-O 64-bit bundle x86_64"

if sys.platform in platforms_with_dlopen:
    os.environ['LD_LIBRARY_PATH'] = test.workpath()
    test.run(program = test.workpath('dlopenprog'),
             stdout = "f1.c\ndlopenprog.c\n")
                 


test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/Mkdir.py

#!/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 Mkdir() Action works.
"""

import os.path

import TestSCons

test = TestSCons.TestSCons()

test.subdir('work1', 'work2', 'work3')

test.write(['work1', 'SConstruct'], """
Execute(Mkdir('d1'))
Execute(Mkdir(Dir('#d1-Dir')))
def cat(env, source, target):
    target = str(target[0])
    with open(target, "wb") as f:
        for src in source:
            with open(str(src), "rb") as ifp:
                f.write(ifp.read())
Cat = Action(cat)
env = Environment()
env.Command('f2.out', 'f2.in', [Cat, Mkdir("d3")])
env = Environment(DIR = 'd4')
env.Command('f5.out', 'f5.in', [Mkdir("$DIR"), Cat])
env.Command('f6.out', 'f6.in', [Cat,
                                Mkdir("Mkdir-$SOURCE"),
                                Mkdir("$TARGET-Mkdir")])
# Make sure that a user-defined Mkdir builder on a directory
# doesn't get executed twice if it has to get called to create
# directory for another target.
env.Command(Dir('hello'), None, [Mkdir('$TARGET')])
env.Command('hello/world', None, [Touch('$TARGET')])

# Make sure Mkdir works with a list of arguments
Execute(Mkdir(['d7', Dir('d8')]))
""")

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")
Mkdir("d1-Dir")
Mkdir(["d7", "d8"])
""",
                          build_str = """\
cat(["f2.out"], ["f2.in"])
Mkdir("d3")
Mkdir("d4")
cat(["f5.out"], ["f5.in"])
cat(["f6.out"], ["f6.in"])
Mkdir("Mkdir-f6.in")
Mkdir("f6.out-Mkdir")
Mkdir("hello")
Touch("%s")
""" % (os.path.join('hello', 'world')))
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'])
test.must_not_exist(['work1', 'f5.out'])
test.must_not_exist(['work1', 'f6.out'])
test.must_not_exist(['work1', 'Mkdir-f6.in'])
test.must_not_exist(['work1', 'f6.out-Mkdir'])
test.must_not_exist(['work1', 'd7'])
test.must_not_exist(['work1', 'd8'])

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'])
test.must_match(['work1', 'f5.out'], "f5.in\n")
test.must_exist(['work1', 'f6.out'])
test.must_exist(['work1', 'Mkdir-f6.in'])
test.must_exist(['work1', 'f6.out-Mkdir'])
test.must_exist(['work1', 'hello'])
test.must_exist(['work1', 'hello/world'])
test.must_exist(['work1', 'd7'])
test.must_exist(['work1', 'd8'])

test.write(['work1', 'd1', 'file'], "d1/file\n")
test.write(['work1', 'd3', 'file'], "d3/file\n")
test.write(['work1', 'Mkdir-f6.in', 'file'], "Mkdir-f6.in/file\n")
test.write(['work1', 'f6.out-Mkdir', 'file'], "f6.out-Mkdir/file\n")
test.write(['work1', 'hello', 'file'], "hello/file\n")




test.write(['work2', 'SConstruct'], """\
import os
def catdir(env, source, target):
    target = str(target[0])
    with open(target, "wb") as outfp:
        for src in source:
            s = str(src)
            for f in sorted(os.listdir(s)):
                f = os.path.join(s, f)
                if os.path.isfile(f):
                    with open(f, "rb") as infp:
                        outfp.write(infp.read())
CatDir = Builder(action = catdir)
env = Environment(BUILDERS = {'CatDir' : CatDir})
env.Command(Dir('hello'), None, [Mkdir('$TARGET')])
env.Command('hello/file1.out', 'file1.in', [Copy('$TARGET', '$SOURCE')])
env.Command('hello/file2.out', 'file2.in', [Copy('$TARGET', '$SOURCE')])
env.CatDir('output', Dir('hello'))
""")

test.write(['work2', 'file1.in'], "work2/file1.in\n")
test.write(['work2', 'file2.in'], "work2/file2.in\n")

test.run(chdir = 'work2', arguments = 'hello/file2.out output')

test.must_match(['work2', 'output'], "work2/file1.in\nwork2/file2.in\n")


#----------------------------------------
# Regression test for bug #1249

test.subdir(['work3', 'sub1'], ['work3', 'sub1', 'sub11'])

test.write(['work3', 'SConstruct'], """\
#/SConstruct ------------------------------------------
import os
env = Environment(ENV = os.environ)
VariantDir('build', 'sub1', duplicate=0)
base = '#build/sub1'
Export('env base')
SConscript('sub1/SConscript', exports='env')
""")

test.write(['work3', 'sub1', 'SConscript'], """\
#/sub1/SConscript ----------------------------------
Import ('env base')
test1 = base + '/test1'
Export ('env test1')
env.Command(Dir(test1), '', Mkdir('$TARGET'))
SConscript('sub11/SConscript')
""")

test.write(['work3', 'sub1', 'sub11', 'SConscript'], """\
#/sub1/sub11/SConscript-------------------------
Import('env test1')
test11 = test1 + '/test11'
print('test11 = ' + test11)
env.Command(Dir(test11), '', Mkdir('$TARGET'))
""")

test.run(chdir = 'work3', arguments = '')

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/Move.py

#!/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 Move() Action works.
"""

import TestSCons

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])
    with open(target, "wb") as f:
        for src in source:
            with open(str(src), "rb") as ifp:
                f.write(ifp.read())
Cat = Action(cat)
env = Environment()
env.Command('f2.out', 'f2.in', [Cat, Move("f3.out", "f3.in")])
env = Environment(OUT = 'f4.out', IN = 'f4.in')
env.Command('f5.out', 'f5.in', [Move("$OUT", "$IN"), Cat])
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")
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")
Move("File-f1.out", "f1.in-File")
""",
                          build_str = """\
cat(["f2.out"], ["f2.in"])
Move("f3.out", "f3.in")
Move("f4.out", "f4.in")
cat(["f5.out"], ["f5.in"])
cat(["f6.out"], ["f6.in"])
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')
test.must_not_exist('f5.out')
test.must_not_exist('f6.out')
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")
test.must_match('f4.out', "f4.in\n")
test.must_match('f5.out', "f5.in\n")
test.must_match('f6.out', "f6.in\n")
test.must_match('Move-f6.out', "f6.in-Move\n")

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/NoClean.py

#!/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__"

#
# This test ensures that NoClean works correctly, even when it's applied to
# a single target in the return list of an multi-target Builder.
#
import TestSCons

test = TestSCons.TestSCons()

test.write('SConstruct', """
def action(target, source, env):
    for t in target:
        with open(t.get_internal_path(), 'w'):
            pass
Command('1.out', 'SConstruct', action)
NoClean('1.out')
""")

test.write('SConstruct.force', """
def action(target, source, env):
    for t in target:
        with open(t.get_internal_path(), 'w'):
            pass
    with open('4.out', 'w'):
        pass
res = Command('3.out', 'SConstruct.force', action)
Clean('4.out', res)
NoClean('4.out')
""")

test.write('SConstruct.multi', """
def action(target, source, env):
    for t in target:
        with open(t.get_internal_path(), 'w'):
            pass
Command(['5.out', '6.out'], 'SConstruct.multi', action)
NoClean('6.out')
""")

#
# Basic check: NoClean keeps files
#
test.run()
test.run(arguments='-c')

test.must_exist('1.out')

#
# Check: NoClean overrides Clean
#
test.run(arguments=['-f', 'SConstruct.force'])
test.run(arguments=['-f', 'SConstruct.force', '-c'])

test.must_not_exist('3.out')
test.must_exist('4.out')

#
# Check: NoClean works for multi-target Builders
#
test.run(arguments=['-f', 'SConstruct.multi'])
test.run(arguments=['-f', 'SConstruct.multi', '-c'])

test.must_not_exist('5.out')
test.must_exist('6.out')

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/NodeOps.py

#!/usr/bin/env python
#
# MIT License
#
# Copyright The SCons Foundation
#
# 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.

"""
This test is used to verify that the Buildability of a set of nodes
is unaffected by various querying operations on those nodes:

1) Calling exists() on a Node (e.g. from find_file) in a VariantDir
   will cause that node to be duplicated into the builddir.
   However, this should *not* occur during a dryrun (-n).  When not
   performed during a dryrun, this should not affect buildability.
2) Calling is_derived() should not affect buildability.
"""

import sys
import os

import TestSCons
from TestSCons import _exe, lib_, _lib, _obj, dll_, _dll

if os.name == 'posix':
    os.environ['LD_LIBRARY_PATH'] = '.'
if sys.platform.find('irix') > -1:
    os.environ['LD_LIBRARYN32_PATH'] = '.'

test = TestSCons.TestSCons()

test.subdir('bld', 'src', ['src', 'subsrcdir'])

sconstruct = r"""
foo = Environment(SHOBJPREFIX='', WINDOWS_INSERT_DEF=1)
foo.Append(SHCXXFLAGS = '-DFOO')
bar = Environment(SHOBJPREFIX='', WINDOWS_INSERT_DEF=1)
bar.Append(SHCXXFLAGS = '-DBAR')
src = Dir('src')
VariantDir('bld', src, duplicate=1)
Nodes=[]
Nodes.extend(foo.SharedObject(target = 'foo%(_obj)s', source = 'prog.cpp'))
Nodes.extend(bar.SharedObject(target = 'bar%(_obj)s', source = 'prog.cpp'))
SConscript('bld/SConscript', ['Nodes'])
if %(_E)s:
  import os
  derived = [N.is_derived() for N in Nodes]
  real1 = [os.path.exists(str(N)) for N in Nodes]
  exists = [N.exists() for N in Nodes]
  real2 = [os.path.exists(str(N)) for N in Nodes]
  for N,D,R,E,F in zip(Nodes, derived, real1, exists, real2):
    print('%%s: %%s %%s %%s %%s'%%(N,D,R,E,F))
foo.SharedLibrary(target = 'foo', source = 'foo%(_obj)s')
bar.SharedLibrary(target = 'bar', source = 'bar%(_obj)s')

fooMain = foo.Clone(LIBS='foo', LIBPATH='.')
foo_obj = fooMain.Object(target='foomain', source='main.c')
fooMain.Program(target='fooprog', source=foo_obj)

barMain = bar.Clone(LIBS='bar', LIBPATH='.')
bar_obj = barMain.Object(target='barmain', source='main.c')
barMain.Program(target='barprog', source=bar_obj)

gooMain = foo.Clone(LIBS='goo', LIBPATH='bld')
goo_obj = gooMain.Object(target='goomain', source='main.c')
gooMain.Program(target='gooprog', source=goo_obj)
"""

test.write('foo.def', r"""
LIBRARY        "foo"

EXPORTS
   doIt
""")

test.write('bar.def', r"""
LIBRARY        "bar"

EXPORTS
   doIt
""")

test.write('prog.cpp', r"""
#include <stdio.h>

extern "C" void
doIt()
{
#ifdef FOO
        printf("prog.cpp:  FOO\n");
#endif
#ifdef BAR
        printf("prog.cpp:  BAR\n");
#endif
}
""")

sconscript = r"""
import os
Import('*')

def mycopy(env, source, target):
    with open(str(target[0]), 'wt') as fo, open(str(source[0]), 'rt') as fi:
        fo.write(fi.read())

def exists_test(node):
    before = os.path.exists(str(node))  # doesn't exist yet in VariantDir
    via_node = node.exists()            # side effect causes copy from src
    after = os.path.exists(str(node))
    node.is_derived()
    import SCons.Script
    if GetOption('no_exec'):
        if (before,via_node,after) != (False,False,False):
            import sys
            sys.stderr.write('VariantDir exists() populated during dryrun!\n')
            sys.exit(-2)
    else:
        if (before,via_node,after) != (False,True,True):
            import sys
            sys.stderr.write('VariantDir exists() population did not occur! (%%s:%%s,%%s,%%s)\n'%%(str(node),before,via_node,after))
            sys.exit(-2)

goo = Environment()
goo.Append(CFLAGS = '-DFOO')
goof_in = File('goof.in')
if %(_E)s:
    exists_test(goof_in)
Nodes.append(goof_in)
Nodes.extend(goo.Command(target='goof.c', source='goof.in', action=mycopy))
boo_src = File('subsrcdir/boo.c')
if %(_E)s:
    exists_test(boo_src)
boo_objs = goo.Object(target='subsrcdir/boo%(_obj)s', source = boo_src)
Nodes.extend(boo_objs)
Nodes.extend(goo.Object(target='goo%(_obj)s',source='goof.c'))
goo.Library(target = 'goo', source = ['goo%(_obj)s'] + boo_objs)
"""

test.write(['src', 'goof.in'], r"""
#include <stdio.h>

extern char *boo_sub();

void
doIt()
{
#ifdef FOO
        printf("prog.cpp:  %s\n", boo_sub());
#endif
}
""")

test.write(['src', 'subsrcdir', 'boo.c'], r"""
char *
boo_sub()
{
    return "GOO";
}
""")

test.write('main.c', r"""
void doIt();

int
main(int argc, char* argv[])
{
    doIt();
    return 0;
}
""")

builddir_srcnodes = [ os.path.join('bld', 'goof.in'),
                      os.path.join('bld', 'subsrcdir', 'boo.c'),
                    ]

sub_build_nodes = [ os.path.join('bld', 'subsrcdir','boo' + _obj),
                    os.path.join('bld', 'goo' + _obj),
                    os.path.join('bld', 'goof.c'),
                    os.path.join('bld', lib_ + 'goo' + _lib),
]

build_nodes = ['fooprog' + _exe,
               dll_ + 'foo' + _dll,
               'foo' + _obj,
               'barprog' + _exe,
               dll_ + 'bar' + _dll,
               'bar' + _obj,

               'gooprog' + _exe,

               ] + builddir_srcnodes + sub_build_nodes

def cleanup_test():
    """cleanup after running a test"""
    for F in builddir_srcnodes:
        test.unlink(F)  # will be repopulated during clean operation
    test.run(arguments = '-c')
    for F in builddir_srcnodes:
        test.unlink(F)
    for name in build_nodes:
        test.must_not_exist(test.workpath(name))


### First pass, make sure everything goes quietly

for name in build_nodes:
    test.must_not_exist(test.workpath(name))

_E=0
test.write('SConstruct', sconstruct % locals() )
test.write(['src', 'SConscript'], sconscript % locals() )

test.run(arguments = '.',
         stderr=TestSCons.noisy_ar,
         match=TestSCons.match_re_dotall)

test.run(program = test.workpath('fooprog'), stdout = "prog.cpp:  FOO\n")
test.run(program = test.workpath('barprog'), stdout = "prog.cpp:  BAR\n")
test.run(program = test.workpath('gooprog'), stdout = "prog.cpp:  GOO\n")

for name in build_nodes:
    test.must_exist(test.workpath(name))

cleanup_test()

### Next pass: add internal Node ops that may have side effects to
### ensure that those side-effects don't interfere with building

for name in build_nodes:
    test.must_not_exist(test.workpath(name))

_E=1
test.write('SConstruct', sconstruct % locals() )
test.write(['src', 'SConscript'], sconscript % locals() )

test.run(arguments = '.',
         stderr=TestSCons.noisy_ar,
         match=TestSCons.match_re_dotall)

test.run(program = test.workpath('fooprog'), stdout = "prog.cpp:  FOO\n")
test.run(program = test.workpath('barprog'), stdout = "prog.cpp:  BAR\n")
test.run(program = test.workpath('gooprog'), stdout = "prog.cpp:  GOO\n")

for name in build_nodes:
    test.must_exist(test.workpath(name))

cleanup_test()

### Next pass: try a dry-run first and verify that it doesn't change
### the buildability.

for name in build_nodes:
    test.must_not_exist(test.workpath(name))

_E=1
test.write('SConstruct', sconstruct % locals() )
test.write(['src', 'SConscript'], sconscript % locals() )

test.run(arguments = '-n .',
         stderr=TestSCons.noisy_ar,
         match=TestSCons.match_re_dotall)

for name in build_nodes:
    test.must_not_exist(test.workpath(name))

test.run(arguments = '.',
         stderr=TestSCons.noisy_ar,
         match=TestSCons.match_re_dotall)

test.run(program = test.workpath('fooprog'), stdout = "prog.cpp:  FOO\n")
test.run(program = test.workpath('barprog'), stdout = "prog.cpp:  BAR\n")
test.run(program = test.workpath('gooprog'), stdout = "prog.cpp:  GOO\n")

for name in build_nodes:
    test.must_exist(test.workpath(name))

cleanup_test()

### Next pass: do an up-build from a VariantDir src


for name in build_nodes:
    test.must_not_exist(test.workpath(name))

_E=0
test.write('SConstruct', sconstruct % locals() )
test.write(['src', 'SConscript'], sconscript % locals() )

test.run(chdir='src', arguments = '-u',
         stderr=TestSCons.noisy_ar,
         match=TestSCons.match_re_dotall)

for name in build_nodes:
    if name in sub_build_nodes or name in builddir_srcnodes:
        test.must_exist(test.workpath(name))
    else:
        test.must_not_exist(test.workpath(name))

cleanup_test()

### Next pass: do an up-build from a VariantDir src with Node Ops
### side-effects

for name in build_nodes:
    test.must_not_exist(test.workpath(name))

_E=1
test.write('SConstruct', sconstruct % locals() )
test.write(['src', 'SConscript'], sconscript % locals() )

test.run(chdir='src', arguments = '-u',
         stderr=TestSCons.noisy_ar,
         match=TestSCons.match_re_dotall)

for name in build_nodes:
    if name in sub_build_nodes or name in builddir_srcnodes:
        test.must_exist(test.workpath(name))
    else:
        test.must_not_exist(test.workpath(name))

cleanup_test()

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/Object.py

#!/usr/bin/env python
#
# __COPYRIGHT__
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#

__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"

import TestSCons

_obj = TestSCons._obj

test = TestSCons.TestSCons()

test.write('SConstruct', """
env = Environment()
f1 = env.Object(target = 'f1', source = 'f1.c')
f2 = Object(target = 'f2', source = 'f2.cpp')
f3 = env.Object(target = 'f3', source = 'f3.c')
mult_o = env.Object(['f4.c', 'f5.c'])
env.Program(target = 'prog1', source = Split('f1%s f2%s f3%s f4%s prog.cpp'))
env.Program(target = 'prog2', source = mult_o + [f1, f2, f3, 'prog.cpp'])
env.Program(target = 'prog3', source = ['f1%s', f2, 'f3%s', 'prog.cpp'])
""" % (_obj, _obj, _obj, _obj, _obj, _obj))

test.write('f1.c', r"""
#include <stdio.h>
void
f1(void)
{
        printf("f1.c\n");
}
""")

test.write('f2.cpp', r"""
#include <stdio.h>

void
f2(void)
{
        printf("f2.c\n");
}
""")

test.write('f3.c', r"""
#include <stdio.h>
void
f3(void)
{
        printf("f3.c\n");
}
""")

test.write('f4.c', r"""
#include <stdio.h>
void
f4(void)
{
        printf("f4.c\n");
}
""")

test.write('f5.c', r"""
#include <stdio.h>
void
f5(void)
{
        printf("f5.c\n");
}
""")

test.write('prog.cpp', r"""
#include <stdio.h>

extern "C" void f1(void);
extern void f2(void);
extern "C" void f3(void);
int
main(int argc, char *argv[])
{
        argv[argc++] = (char *)"--";
        f1();
        f2();
        f3();
        printf("prog.c\n");
        return 0;
}
""")

stdout = "f1.c\nf2.c\nf3.c\nprog.c\n"

test.run(arguments = '.')

test.run(program = test.workpath('prog1'), stdout = stdout)

test.run(program = test.workpath('prog2'), stdout = stdout)

test.run(program = test.workpath('prog3'), stdout = stdout)

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/PRINT_CMD_LINE_FUNC.py

#!/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 the PRINT_CMD_LINE_FUNC construction variable.
"""

import TestSCons

_exe = TestSCons._exe
_obj = TestSCons._obj

test = TestSCons.TestSCons(match = TestSCons.match_re)


test.write('SConstruct', r"""
import sys
def print_cmd_line(s, target, source, env):
    sys.stdout.write("BUILDING %s from %s with %s\n"%
                     (str(target[0]), str(source[0]), s))

e = Environment(PRINT_CMD_LINE_FUNC=print_cmd_line)
e.Program(target = 'prog', source = 'prog.c')
""")

test.write('prog.c', r"""
int main(int argc, char *argv[]) { return 0; }
""")

test.run(arguments = '-Q .')

expected_lines = [
    "BUILDING prog%s from prog.c with" % (_obj,),
    "BUILDING prog%s from prog%s with" % (_exe, _obj),
]

test.must_contain_all_lines(test.stdout(), expected_lines)

test.run(arguments = '-c .')

# Just make sure it doesn't blow up when PRINT_CMD_LINE_FUNC
# is explicity initialized to None.
test.write('SConstruct', r"""
e = Environment(PRINT_CMD_LINE_FUNC=None)
e.Program(target = 'prog', source = 'prog.c')
""")

test.run(arguments = '-Q .')

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/ParseConfig.py

#!/usr/bin/env python
#
# __COPYRIGHT__
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#

__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"

import TestSCons

_python_ = TestSCons._python_

test = TestSCons.TestSCons()

test_config1 = test.workpath('test-config1')
test_config2 = test.workpath('test-config2')
test_config3 = test.workpath('test-config3')

# 'abc' is supposed to be a static lib; it is included in LIBS as a
# File node.
# It used to be returned as the 'static_libs' output of ParseConfig.
test.write(test_config1, """\
print("-I/usr/include/fum -Ibar -X -arch i386")
print("-L/usr/fax -Lfoo -lxxx abc")
""")

test.write(test_config2, """\
print("-L foo -L lib_dir")
""")

# This is like what wxWidgets does on OSX w/ Universal Binaries
test.write(test_config3, """\
print("-L foo -L lib_dir -isysroot /tmp -arch ppc -arch i386")
""")

test.write('SConstruct1', """
env = Environment(CPPPATH = [], LIBPATH = [], LIBS = [],
                  CCFLAGS = '-pipe -Wall')
env.ParseConfig([r'%(_python_)s', r"%(test_config1)s", "--libs --cflags"])
env.ParseConfig([r'%(_python_)s', r"%(test_config2)s", "--libs --cflags"])
print(env['CPPPATH'])
print(env['LIBPATH'])
print([str(x) for x in env['LIBS']])
print(env['CCFLAGS'])
""" % locals())

test.write('SConstruct2', """
env = Environment(CPPPATH = [], LIBPATH = [], LIBS = [],
                  CCFLAGS = '-pipe -Wall',
                  PYTHON = r'%(_python_)s')
env.ParseConfig(r"$PYTHON %(test_config1)s --libs --cflags")
env.ParseConfig(r"$PYTHON %(test_config2)s --libs --cflags")
print(env['CPPPATH'])
print(env['LIBPATH'])
print([str(x) for x in env['LIBS']])
print(env['CCFLAGS'])
""" % locals())

test.write('SConstruct3', """
env = Environment(CPPPATH = [], LIBPATH = [], LIBS = [],
                  CCFLAGS = '-pipe -Wall',
                  PYTHON = r'%(_python_)s')
env.ParseConfig(r"$PYTHON %(test_config3)s --libs --cflags")
print(env['CPPPATH'])
print(env['LIBPATH'])
print([str(x) for x in env['LIBS']])
print(env['CCFLAGS'])
""" % locals())

good_stdout = """\
['/usr/include/fum', 'bar']
['/usr/fax', 'foo', 'lib_dir']
['xxx', 'abc']
['-pipe', '-Wall', '-X', ('-arch', 'i386')]
"""

stdout3 = """\
[]
['foo', 'lib_dir']
[]
['-pipe', '-Wall', ('-isysroot', '/tmp'), ('-arch', 'ppc'), ('-arch', 'i386')]
"""

test.run(arguments = "-q -Q -f SConstruct1 .", stdout = good_stdout)

test.run(arguments = "-q -Q -f SConstruct2 .", stdout = good_stdout)

test.run(arguments = "-q -Q -f SConstruct3 .", stdout = stdout3)

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/ParseDepends.py

#!/usr/bin/env python
#
# __COPYRIGHT__
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#

__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"

import os.path

import TestSCons

_python_ = TestSCons._python_

test = TestSCons.TestSCons()

test.subdir('subdir', 'sub2')

test.write('build.py', r"""
import sys
with open(sys.argv[1], 'wb') as f, open(sys.argv[2], 'rb') as afp2, open(sys.argv[3], 'rb') as afp3:
    f.write(afp2.read() + afp3.read())
""")

test.write('SConstruct', """
Foo = Builder(action = r'%(_python_)s build.py $TARGET $SOURCES subdir/foo.dep')
Bar = Builder(action = r'%(_python_)s build.py $TARGET $SOURCES subdir/bar.dep')
env = Environment(BUILDERS = { 'Foo' : Foo, 'Bar' : Bar }, SUBDIR='subdir')
env.ParseDepends('foo.d')
env.ParseDepends('bar.d')
env.Foo(target = 'f1.out', source = 'f1.in')
env.Foo(target = 'f2.out', source = 'f2.in')
env.Bar(target = 'subdir/f3.out', source = 'f3.in')
SConscript('subdir/SConscript', "env")
env.Foo(target = 'f5.out', source = 'f5.in')
env.Bar(target = 'sub2/f6.out', source = 'f6.in')
""" % locals())

test.write('foo.d', "f1.out f2.out: %s\n" % os.path.join('subdir', 'foo.dep'))
test.write('bar.d', "%s: %s\nf5.out: sub2" % (os.path.join('subdir', 'f3.out'),
                                  os.path.join('subdir', 'bar.dep')))

test.write(['subdir', 'SConscript'], """
Import("env")
ParseDepends('bar.d')
env.Bar(target = 'f4.out', source = 'f4.in')
""")

test.write(['subdir', 'bar.d'], "f4.out: bar.dep\n")

test.write('f1.in', "f1.in\n")
test.write('f2.in', "f2.in\n")
test.write('f3.in', "f3.in\n")
test.write(['subdir', 'f4.in'], "subdir/f4.in\n")
test.write('f5.in', "f5.in\n")
test.write('f6.in', "f6.in\n")

test.write(['subdir', 'foo.dep'], "subdir/foo.dep 1\n")
test.write(['subdir', 'bar.dep'], "subdir/bar.dep 1\n")

test.run(arguments = '.')

test.must_match('f1.out', "f1.in\nsubdir/foo.dep 1\n")
test.must_match('f2.out', "f2.in\nsubdir/foo.dep 1\n")
test.must_match(['subdir', 'f3.out'], "f3.in\nsubdir/bar.dep 1\n")
test.must_match(['subdir', 'f4.out'], "subdir/f4.in\nsubdir/bar.dep 1\n")
test.must_match('f5.out', "f5.in\nsubdir/foo.dep 1\n")
test.must_match(['sub2', 'f6.out'], "f6.in\nsubdir/bar.dep 1\n")

#
test.write(['subdir', 'foo.dep'], "subdir/foo.dep 2\n")
test.write(['subdir', 'bar.dep'], "subdir/bar.dep 2\n")
test.write('f6.in', "f6.in 2\n")

test.run(arguments = '.')

test.must_match('f1.out', "f1.in\nsubdir/foo.dep 2\n")
test.must_match('f2.out', "f2.in\nsubdir/foo.dep 2\n")
test.must_match(['subdir', 'f3.out'], "f3.in\nsubdir/bar.dep 2\n")
test.must_match(['subdir', 'f4.out'], "subdir/f4.in\nsubdir/bar.dep 2\n")
test.must_match('f5.out', "f5.in\nsubdir/foo.dep 2\n")
test.must_match(['sub2', 'f6.out'], "f6.in 2\nsubdir/bar.dep 2\n")

#
test.write(['subdir', 'foo.dep'], "subdir/foo.dep 3\n")

test.run(arguments = '.')

test.must_match('f1.out', "f1.in\nsubdir/foo.dep 3\n")
test.must_match('f2.out', "f2.in\nsubdir/foo.dep 3\n")
test.must_match(['subdir', 'f3.out'], "f3.in\nsubdir/bar.dep 2\n")
test.must_match(['subdir', 'f4.out'], "subdir/f4.in\nsubdir/bar.dep 2\n")
test.must_match('f5.out', "f5.in\nsubdir/foo.dep 2\n")
test.must_match(['sub2', 'f6.out'], "f6.in 2\nsubdir/bar.dep 2\n")

#
test.write(['subdir', 'bar.dep'], "subdir/bar.dep 3\n")

test.run(arguments = '.')

test.must_match('f1.out', "f1.in\nsubdir/foo.dep 3\n")
test.must_match('f2.out', "f2.in\nsubdir/foo.dep 3\n")
test.must_match(['subdir', 'f3.out'], "f3.in\nsubdir/bar.dep 3\n")
test.must_match(['subdir', 'f4.out'], "subdir/f4.in\nsubdir/bar.dep 3\n")
test.must_match('f5.out', "f5.in\nsubdir/foo.dep 2\n")
test.must_match(['sub2', 'f6.out'], "f6.in 2\nsubdir/bar.dep 2\n")

#
test.write('f6.in', "f6.in 3\n")

test.run(arguments = '.')

test.must_match('f1.out', "f1.in\nsubdir/foo.dep 3\n")
test.must_match('f2.out', "f2.in\nsubdir/foo.dep 3\n")
test.must_match(['subdir', 'f3.out'], "f3.in\nsubdir/bar.dep 3\n")
test.must_match(['subdir', 'f4.out'], "subdir/f4.in\nsubdir/bar.dep 3\n")
test.must_match('f5.out', "f5.in\nsubdir/foo.dep 3\n")
test.must_match(['sub2', 'f6.out'], "f6.in 3\nsubdir/bar.dep 3\n")



test.write('SConstruct', """
ParseDepends('nonexistent_file')
""")

test.run()

test.write('SConstruct', """
ParseDepends('nonexistent_file', must_exist=1)
""")

test.run(status=2, stderr=None)

test.must_contain_all_lines(test.stderr(), ["No such file or directory"])

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/PharLap.py

#!/usr/bin/env python
#
# MIT License
#
# Copyright The SCons Foundation
#
# 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.

import os
import sys
import time

import TestSCons

test = TestSCons.TestSCons()

if sys.platform != 'win32':
    test.skip_test('PharLap is only available on Windows; skipping test.\n')

if not test.detect_tool('linkloc'):
    test.skip_test("Could not find 'linkloc', skipping test.\n")

if not test.detect_tool('386asm'):
    test.skip_test("Could not find '386asm', skipping test.\n")

# From the Phar Lap minasm example program...
test.write("minasm.asm", r"""
; 
; MINASM.ASM - A minimal assembly language program which runs
;       under ToolSuite.  You can use this program as a framework
;       for large assembly language programs.
;
.386

;
; Segmentation and segment ordering.
;
; First comes the code segment.
;
_TEXT	segment use32 byte public 'CODE'
_TEXT	ends

;
; The data segment contains initialized RAM based data.  It will automatically
; be placed in the ROM at link time and unpacked into RAM at run-time
; by the __pl_unpackrom function.
;
; If you do not need any initialized data in your assembly language program,
; you can leave this segment empty and remove the call to __pl_unpackrom.
;
;
_DATA	segment use32 dword public 'DATA'

loopcount	dd 10d
rammessage	db 'This message is in RAM memory',0dh,0ah,0

_DATA	ends

;
; The BSS segment contains RAM based variables which
; are initialized to zero at run-time.  Putting unitialized
; variables which should start at zero here saves space in
; the ROM.
;
; If you do not need any zero-initialized data in your assembly language
; program, you can leave this segment empty (and optionally remove the
; instructions below which initialize it).
;
; The segment name must be lower case for compatibility with the linker
;
_bss	segment use32 dword public 'BSS'
dummy_bss db 32 dup(?)	; Use a little bit of BSS just to test it
_bss	ends

;
; The const segment contains constants which will never
; change.  It is put in the ROM and never copied to RAM.
;
; If you do not need any ROM based constants in your assembly language
; program, you can leave this segment empty.
;
_CONST	segment use32 dword public 'CONST'
rommessage	db 'This message is in ROM memory',0dh,0ah,0
_CONST	ends

;
; We're in flat model, so we'll put all the read-only segments we know about
; in a code group, and the writeable segments in a data group, so that
; we can use assume to easily get addressability to the segments.
;
CGROUP group _TEXT, _CONST
DGROUP group _DATA, _bss

        assume cs:CGROUP,ds:DGROUP
_TEXT	segment

;
; _main - the main routine of this program.
;
; We will display the RAM and ROM messages the number of times
; specified in the loopcount variable.  This proves that we can
; initialize RAM data out of ROM and the fact that we can
; modify the loop count in memory verifies that it actually ends
; up in RAM.
;
        public _main
_main proc near

        mov	cl,0ah			; Skip a line before we start
        call	PutCharTarget		;
main_loop:
        cmp	loopcount,0		; Are we at the end of our loop?
        je	short done_main		;  yes.
        lea	edx,rommessage		; EDX -> ROM message
        call	WriteStringTarget	; Display it
        lea	edx,rammessage		; EDX -> RAM message
        call	WriteStringTarget	; Display it
        dec	loopcount		;
        jmp	main_loop		; Branch back for next loop iteration
done_main:
        ret				; That's it!

_main endp

;
; WriteStringTarget - Display a string on the target console
;
; Inputs:
;       EDX -> Null terminated ASCII string to display
;
; Outputs:
;       All registers preserved
;
WriteStringTarget proc near

        push	ecx			; Save registers
        push	edx			;

write_loop:
        movzx	ecx,byte ptr [edx]	; Get a character
        jecxz	done_str		; Branch if end of string
        call	PutCharTarget		; Display this character
        inc	edx			; Bump scan pointer
        jmp	write_loop		; And loop back for next character

done_str:
        pop	edx			; Restore registers
        pop	ecx			;
        ret				;  and return

WriteStringTarget endp

;
; PutCharTarget - Write a character on the target console
;
; This routine displays a character on the target console by using
; the PutChar kernel service available through int 254.
;
; Inputs:
;       CL = character to display
;
; Outputs:
;       All registers preserved
;
PutCharTarget proc near

        push	eax		; Save registers
        push	ebx		;
        push	edx		;

        mov     ax,254Ah	; Request Kernel Service
        mov     bx,1		; service code 1 = PutChar
        movzx   edx,cl		; EDX = character to display
        int     0FEh		; Int 254 is for kernel services

        pop	edx		; Restore registers
        pop	ebx		;
        pop	eax		;
        ret			;  and return

PutCharTarget endp

;
; The __pl_unpackrom unpacks initialized RAM based data variables
; out of the ROMINIT segment into their RAM area.  They are put
; in the ROMINIT segment with the -ROMINIT switch in the link file.
;
extrn __pl_unpackrom:near

;
; The _EtsExitProcess function is used to terminate our program
;
extrn _EtsExitProcess:near

;
; The linker will define symbols for the beginning and end of the
; BSS segment.
;
extrn   __p_SEG__bss_BEGIN:dword
extrn   __p_SEG__bss_END:dword

;
; __p_start -- The entry point for our assembly language program.
; We unpack the RAM based variables out of the ROM and clear the
; BSS to zero, then call _main where the real work happens.  When
; _main returns, we call EtsExitProcess(0) to terminate.
;
public __p_start
__p_start proc near
        pushad				; save initial regs
        push	es				;
        call	__pl_unpackrom		; Call the unpacker 
        cld				; Clear direction flag

        lea 	eax,__p_SEG__bss_END	; load end address and 
        lea	ebx,__p_SEG__bss_BEGIN	; subtract start to get size
        sub 	eax,ebx
        mov 	ecx,eax			; This is size
        inc	ecx
        lea	edi,__p_SEG__bss_BEGIN	; Zero from start address
        mov 	al,0			;Zero out BSS and C_COMMON	
        rep     stosb

        pop	es			; restore initial regs
        popad
        call	_main			; go do some work
stopme:
 	xor	eax,eax			; Call _EtsExitProcess(0)
        push	eax			;
        call	_EtsExitProcess		;
        pop	eax			;
        jmp	stopme			;  .. in a loop just in case it ever
        				;  comes back

__p_start endp

TD_hack:
        mov	eax, __p_tdhack		; force reference to TD-hack symbol

_TEXT	ends

;
;       Hack for Turbo Debugger/TDEMB - TD will fault if the .exe being
;       debugged doesn't have an import table.  (TD looks for the address of
;       the table, then dereferences that address wihtout checking for NULL).
;
;       This symbol, __p_tdhack, must be declared as an import in all the
;       .emb files shipped.  IE:
;
;               -implib embkern.lib
;               -import __p_tdhack
;
;       This forces the creation of an import table within the .EXE.
_DATA	segment
extrn	__p_tdhack:dword
_DATA	ends
        end	__p_start
""")

test.write("foo.lnk","""
@baz\\bar.lnk
""")

test.subdir("baz")
test.write([ "baz", "bar.lnk"],"""
@asm.emb
""")

test.write("SConstruct", """\
env = Environment(
    tools=['linkloc', '386asm'], ASFLAGS='-twocase -cvsym', LINKFLAGS='@foo.lnk'
)
env.Program(target='minasm', source='minasm.asm')
""")

test.run(arguments='.')

# Assume .exe extension...this test is for Windows only.
test.fail_test(not os.path.exists('minasm.exe'))
test.up_to_date(arguments='.')

# Updating a linker command file should cause a rebuild!
test.write([ "baz", "bar.lnk"],"""
-cvsym
@asm.emb
""")

oldtime = os.path.getmtime(test.workpath('minasm.exe'))
test.sleep()  # delay for timestamps
test.run(arguments='.')
test.fail_test(oldtime == os.path.getmtime(test.workpath('minasm.exe')))

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/Platform.py

#!/usr/bin/env python
#
# __COPYRIGHT__
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#

__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"

import TestSCons

test = TestSCons.TestSCons()

test.write('SConstruct', """
env = Environment()
Platform('cygwin')(env)
print("'%s'" % env['PROGSUFFIX'])
assert env['SHELL'] == 'sh'
Platform('os2')(env)
print("'%s'" % env['PROGSUFFIX'])
env.Platform('posix')
print("'%s'" % env['PROGSUFFIX'])
Platform('win32')(env)
print("'%s'" % env['PROGSUFFIX'])
SConscript('SConscript')
""")

test.write('SConscript', """
env = Environment()
Platform('cygwin')(env)
print("'%s'" % env['LIBSUFFIX'])
Platform('os2')(env)
print("'%s'" % env['LIBSUFFIX'])
env.Platform('posix')
print("'%s'" % env['LIBSUFFIX'])
Platform('win32')(env)
print("'%s'" % env['LIBSUFFIX'])
""")

expect = test.wrap_stdout(read_str = """'.exe'
'.exe'
''
'.exe'
'.a'
'.lib'
'.a'
'.lib'
""", build_str = "scons: `.' is up to date.\n")

test.run(arguments = ".", stdout = expect)

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/Precious.py

#!/usr/bin/env python
#
# __COPYRIGHT__
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#

__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"

import os.path

import TestSCons

_python_ = TestSCons._python_

test = TestSCons.TestSCons()

test.subdir('subdir')

test.write('build.py', r"""
import sys
sys.exit(0)
""")

SUBDIR_f4_out = os.path.join('$SUBDIR', 'f4.out')

test.write('SConstruct', """\
B = Builder(action = r'%(_python_)s build.py $TARGET $SOURCES')
env = Environment(BUILDERS = { 'B' : B }, SUBDIR = 'subdir')
f1 = env.B(target = 'f1.out', source = 'f1.in')
env.B(target = 'f2.out', source = 'f2.in')
env.B(target = 'f3.out', source = 'f3.in')
env.B(target = 'subdir/f4.out', source = 'f4.in')
env.Precious(f1, 'f2.out', r'%(SUBDIR_f4_out)s')
SConscript('subdir/SConscript', "env")
""" % locals())

test.write(['subdir', 'SConscript'], """
Import("env")
env.B(target = 'f5.out', source = 'f5.in')
f6 = env.B(target = 'f6.out', source = 'f6.in')
env.B(target = 'f7.out', source = 'f7.in')
Precious(['f5.out', f6])
""")

test.write('f1.in', "f1.in\n")
test.write('f2.in', "f2.in\n")
test.write('f3.in', "f3.in\n")
test.write('f4.in', "f4.in\n")

test.write(['subdir', 'f5.in'], "subdir/f5.in\n")
test.write(['subdir', 'f6.in'], "subdir/f6.in\n")
test.write(['subdir', 'f7.in'], "subdir/f7.in\n")

test.write('f1.out', "SHOULD NOT BE REMOVED\n")
test.write('f2.out', "SHOULD NOT BE REMOVED\n")
test.write('f3.out', "SHOULD BE REMOVED\n")
test.write(['subdir', 'f4.out'], "SHOULD NOT BE REMOVED\n")

test.write(['subdir', 'f5.out'], "SHOULD NOT BE REMOVED\n")
test.write(['subdir', 'f6.out'], "SHOULD NOT BE REMOVED\n")
test.write(['subdir', 'f7.out'], "SHOULD BE REMOVED\n")

test.run(arguments = '.')

test.fail_test(not os.path.exists(test.workpath('f1.out')))
test.fail_test(not os.path.exists(test.workpath('f2.out')))
test.fail_test(os.path.exists(test.workpath('f3.out')))
test.fail_test(not os.path.exists(test.workpath('subdir', 'f4.out')))

test.fail_test(not os.path.exists(test.workpath('subdir', 'f5.out')))
test.fail_test(not os.path.exists(test.workpath('subdir', 'f6.out')))
test.fail_test(os.path.exists(test.workpath('subdir', 'f7.out')))

test.write('f3.out', "SHOULD BE REMOVED\n")
test.write(['subdir', 'f7.out'], "SHOULD BE REMOVED\n")

test.run(arguments = '.')

test.fail_test(not os.path.exists(test.workpath('f1.out')))
test.fail_test(not os.path.exists(test.workpath('f2.out')))
test.fail_test(not os.path.exists(test.workpath('f3.out')))
test.fail_test(not os.path.exists(test.workpath('subdir', 'f4.out')))

test.fail_test(not os.path.exists(test.workpath('subdir', 'f5.out')))
test.fail_test(not os.path.exists(test.workpath('subdir', 'f6.out')))
test.fail_test(not os.path.exists(test.workpath('subdir', 'f7.out')))

test.write('f3.in', "f3.in 2\n")
test.write(['subdir', 'f7.in'], "subdir/f7.in 2\n")

test.run(arguments = '.')

test.fail_test(not os.path.exists(test.workpath('f1.out')))
test.fail_test(not os.path.exists(test.workpath('f2.out')))
test.fail_test(os.path.exists(test.workpath('f3.out')))
test.fail_test(not os.path.exists(test.workpath('subdir', 'f4.out')))

test.fail_test(not os.path.exists(test.workpath('subdir', 'f5.out')))
test.fail_test(not os.path.exists(test.workpath('subdir', 'f6.out')))
test.fail_test(os.path.exists(test.workpath('subdir', 'f7.out')))

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/Program-j.py

#!/usr/bin/env python
#
# __COPYRIGHT__
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#

__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"

import TestSCons

_exe = TestSCons._exe

f1 = 'f1' + _exe
f2 = 'f2' + _exe
f3 = 'f3' + _exe
f4 = 'f4' + _exe

test = TestSCons.TestSCons()

test.write('SConstruct', """
env = Environment()
env.Program(target = 'f1', source = 'f1.c')
env.Program(target = 'f2', source = 'f2.c')
env.Program(target = 'f3', source = 'f3.c')
env.Program(target = 'f4', source = 'f4.c')
""")

test.write('f1.c', r"""
#include <stdio.h>
#include <stdlib.h>
int
main(int argc, char *argv[])
{
    argv[argc++] = "--";
    printf("f1.c\n");
    exit (0);
}
""")

test.write('f2.c', r"""
#include <stdio.h>
#include <stdlib.h>

int
main(int argc, char *argv[])
{
    argv[argc++] = "--";
    printf("f2.c\n");
    exit (0);
}
""")


test.write('f3.c', r"""
#include <stdio.h>
#include <stdlib.h>
int
main(int argc, char *argv[])
{
    argv[argc++] = "--";
    printf("f3.c\n");
    exit (0);
}
""")

test.write('f4.c', r"""
#include <stdio.h>
#include <stdlib.h>
int
main(int argc, char *argv[])
{
    argv[argc++] = "--";
    printf("f4.c\n");
    exit (0);
}
""")


test.run(arguments = '-j 3 %s %s %s %s' % (f1, f2, f3, f4))

test.run(program = test.workpath('f1'), stdout = "f1.c\n")

test.run(program = test.workpath('f2'), stdout = "f2.c\n")

test.run(program = test.workpath('f3'), stdout = "f3.c\n")

test.run(program = test.workpath('f4'), stdout = "f4.c\n")

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/Program.py

#!/usr/bin/env python
#
# MIT License
#
# Copyright The SCons Foundation
#
# 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.

import os.path
import time

import TestSCons

_exe = TestSCons._exe

test = TestSCons.TestSCons()

foo1 = test.workpath('foo1' + _exe)
foo2 = test.workpath('foo2' + _exe)
foo3 = test.workpath('foo3' + _exe)
foo4 = test.workpath('foo4' + _exe)
foo5 = test.workpath('foo5' + _exe)
foo_args = 'foo1%s foo2%s foo3%s foo4%s foo5%s' % (_exe, _exe, _exe, _exe, _exe)

test.write('SConstruct', """\
env = Environment()
env.Program(target='foo1', source='f1.c')
env.Program(target='foo2', source=Split('f2a.c f2b.c f2c.c'))
f3a = File('f3a.c')
f3b = File('f3b.c')
Program(target='foo3', source=[f3a, [f3b, 'f3c.c']])
env.Program('foo4', 'f4.c')
env.Program('foo5.c')
""")

test.write('f1.c', r"""
#include <stdio.h>
#include <stdlib.h>
int
main(int argc, char *argv[])
{
        argv[argc++] = "--";
        printf("f1.c\n");
        exit (0);
}
""")

test.write('f2a.c', r"""
#include <stdio.h>
#include <stdlib.h>
void
f2a(void)
{
        printf("f2a.c\n");
}
""")

test.write('f2b.c', r"""
#include <stdio.h>
void
f2b(void)
{
        printf("f2b.c\n");
}
""")

test.write('f2c.c', r"""
#include <stdio.h>
#include <stdlib.h>
extern void f2a(void);
extern void f2b(void);
int
main(int argc, char *argv[])
{
        argv[argc++] = "--";
        f2a();
        f2b();
        printf("f2c.c\n");
        exit (0);
}
""")

test.write('f3a.c', r"""
#include <stdio.h>
void
f3a(void)
{
        printf("f3a.c\n");
}
""")

test.write('f3b.c', r"""
#include <stdio.h>
void
f3b(void)
{
        printf("f3b.c\n");
}
""")

test.write('f3c.c', r"""
#include <stdio.h>
#include <stdlib.h>
extern void f3a(void);
extern void f3b(void);
int
main(int argc, char *argv[])
{
        argv[argc++] = "--";
        f3a();
        f3b();
        printf("f3c.c\n");
        exit (0);
}
""")

test.write('f4.c', r"""
#include <stdio.h>
#include <stdlib.h>
int
main(int argc, char *argv[])
{
        argv[argc++] = "--";
        printf("f4.c\n");
        exit (0);
}
""")

test.write('foo5.c', r"""
#include <stdio.h>
#include <stdlib.h>
int
main(int argc, char *argv[])
{
        argv[argc++] = "--";
        printf("foo5.c\n");
        exit (0);
}
""")

test.run(arguments='.')

test.run(program=foo1, stdout="f1.c\n")
test.run(program=foo2, stdout="f2a.c\nf2b.c\nf2c.c\n")
test.run(program=foo3, stdout="f3a.c\nf3b.c\nf3c.c\n")
test.run(program=foo4, stdout="f4.c\n")
test.run(program=foo5, stdout="foo5.c\n")
test.up_to_date(arguments='.')

test.write('f1.c', r"""
#include <stdio.h>
#include <stdlib.h>
int
main(int argc, char *argv[])
{
        argv[argc++] = "--";
        printf("f1.c X\n");
        exit (0);
}
""")

test.write('f3b.c', r"""
#include <stdio.h>
void
f3b(void)
{
        printf("f3b.c X\n");
}
""")

test.write('f4.c', r"""
#include <stdio.h>
#include <stdlib.h>
int
main(int argc, char *argv[])
{
        argv[argc++] = "--";
        printf("f4.c X\n");
        exit (0);
}
""")

test.write('foo5.c', r"""
#include <stdio.h>
#include <stdlib.h>
int
main(int argc, char *argv[])
{
        argv[argc++] = "--";
        printf("foo5.c X\n");
        exit (0);
}
""")

test.run(arguments='.')

test.run(program=foo1, stdout="f1.c X\n")
test.run(program=foo2, stdout="f2a.c\nf2b.c\nf2c.c\n")
test.run(program=foo3, stdout="f3a.c\nf3b.c X\nf3c.c\n")
test.run(program=foo4, stdout="f4.c X\n")
test.run(program=foo5, stdout="foo5.c X\n")
test.up_to_date(arguments='.')

# make sure the programs didn't get rebuilt, because nothing changed:
oldtime1 = os.path.getmtime(foo1)
oldtime2 = os.path.getmtime(foo2)
oldtime3 = os.path.getmtime(foo3)
oldtime4 = os.path.getmtime(foo4)
oldtime5 = os.path.getmtime(foo5)

test.sleep()  # delay for timestamps
test.run(arguments=foo_args)
test.fail_test(oldtime1 != os.path.getmtime(foo1))
test.fail_test(oldtime2 != os.path.getmtime(foo2))
test.fail_test(oldtime3 != os.path.getmtime(foo3))
test.fail_test(oldtime4 != os.path.getmtime(foo4))
test.fail_test(oldtime5 != os.path.getmtime(foo5))

test.write('f1.c', r"""
#include <stdio.h>
#include <stdlib.h>
int
main(int argc, char *argv[])
{
        argv[argc++] = "--";
        printf("f1.c Y\n");
        exit (0);
}
""")

test.write('f3b.c', r"""
#include <stdio.h>
#include <stdlib.h>
void
f3b(void)
{
        printf("f3b.c Y\n");
}
""")

test.write('f4.c', r"""
#include <stdio.h>
#include <stdlib.h>
int
main(int argc, char *argv[])
{
        argv[argc++] = "--";
        printf("f4.c Y\n");
        exit (0);
}
""")

test.write('foo5.c', r"""
#include <stdio.h>
#include <stdlib.h>
int
main(int argc, char *argv[])
{
        argv[argc++] = "--";
        printf("foo5.c Y\n");
        exit (0);
}
""")

test.run(arguments=foo_args)

test.run(program=foo1, stdout="f1.c Y\n")
test.run(program=foo2, stdout="f2a.c\nf2b.c\nf2c.c\n")
test.run(program=foo3, stdout="f3a.c\nf3b.c Y\nf3c.c\n")
test.run(program=foo4, stdout="f4.c Y\n")
test.run(program=foo5, stdout="foo5.c Y\n")
test.up_to_date(arguments=foo_args)

test.write('f1.c', r"""
#include <stdio.h>
#include <stdlib.h>
int
main(int argc, char *argv[])
{
        argv[argc++] = "--";
        printf("f1.c Z\n");
        exit (0);
}
""")

test.write('f3b.c', r"""
#include <stdio.h>
#include <stdlib.h>
void
f3b(void)
{
        printf("f3b.c Z\n");
}
""")

test.write('f4.c', r"""
#include <stdio.h>
#include <stdlib.h>
int
main(int argc, char *argv[])
{
        argv[argc++] = "--";
        printf("f4.c Z\n");
        exit (0);
}
""")

test.write('foo5.c', r"""
#include <stdio.h>
#include <stdlib.h>
int
main(int argc, char *argv[])
{
        argv[argc++] = "--";
        printf("foo5.c Z\n");
        exit (0);
}
""")

test.run(arguments=foo_args)

test.run(program=foo1, stdout="f1.c Z\n")
test.run(program=foo2, stdout="f2a.c\nf2b.c\nf2c.c\n")
test.run(program=foo3, stdout="f3a.c\nf3b.c Z\nf3c.c\n")
test.run(program=foo4, stdout="f4.c Z\n")
test.run(program=foo5, stdout="foo5.c Z\n")
test.up_to_date(arguments=foo_args)

# make sure the programs didn't get rebuilt, because nothing changed:
oldtime1 = os.path.getmtime(foo1)
oldtime2 = os.path.getmtime(foo2)
oldtime3 = os.path.getmtime(foo3)
oldtime4 = os.path.getmtime(foo4)
oldtime5 = os.path.getmtime(foo5)

test.sleep()  # delay for timestamps
test.run(arguments=foo_args)
test.fail_test(not (oldtime1 == os.path.getmtime(foo1)))
test.fail_test(not (oldtime2 == os.path.getmtime(foo2)))
test.fail_test(not (oldtime3 == os.path.getmtime(foo3)))
test.fail_test(not (oldtime4 == os.path.getmtime(foo4)))
test.fail_test(not (oldtime5 == os.path.getmtime(foo5)))

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/Pseudo.py

#!/usr/bin/env python
#
# __COPYRIGHT__
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#

__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"

import TestSCons

test = TestSCons.TestSCons()

# Firstly, build a pseudo target and make sure we get no warnings it
# doesn't exist under any circumstances
test.write('SConstruct', """
env = Environment()
env.Pseudo(env.Command('foo.out', [], '@echo boo'))
""")

test.run(arguments='-Q', stdout = 'boo\n')

test.run(arguments='-Q --warning=target-not-built', stdout = "boo\n")

# Now do the same thing again but create the target and check we get an
# error if it exists after the build
test.write('SConstruct', """
env = Environment()
env.Pseudo(env.Command('foo.out', [], Touch('$TARGET')))
""")

test.run(arguments='-Q', stdout = 'Touch("foo.out")\n', stderr = None,
         status = 2)
test.must_contain_all_lines(test.stderr(),
                            'scons:  *** Pseudo target foo.out must not exist')
test.run(arguments='-Q --warning=target-not-built',
         stdout = 'Touch("foo.out")\n',
         stderr = None, status = 2)
test.must_contain_all_lines(test.stderr(),
                            'scons:  *** Pseudo target foo.out must not exist')

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/RPATH.py

#!/usr/bin/env python
#
# __COPYRIGHT__
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#

__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"

import sys
import TestSCons

_exe = TestSCons._exe

test = TestSCons.TestSCons()

if sys.platform in ['cygwin', 'win32']:
    msg = "Can not test RPATH on '%s', skipping test.\n" % sys.platform
    test.skip_test(msg)

foo = test.workpath('foo' + _exe)

test.subdir('bar')

test.write('SConstruct', """\
SConscript('bar/SConscript')
Program('foo', 'foo.c', LIBS='bar', LIBPATH='bar', RPATH='bar')
""")

test.write('foo.c', """\
#include <stdlib.h>
int main(void) {
    void bar();
    bar();
    exit (0);
}
""")

test.write(['bar', 'SConscript'], """\
SharedLibrary('bar', 'bar.c')
""")

test.write(['bar', 'bar.c'], """\
#include <stdio.h>
void bar() {
    puts("bar");
}
""")

test.run(arguments='.')

test.run(program=foo, chdir=test.workpath('.'), stdout='bar\n')

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/SCONSFLAGS.py

#!/usr/bin/env python
#
# MIT License
#
# Copyright The SCons Foundation
#
# 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.

import os

import TestCmd
import TestSCons

test = TestSCons.TestSCons(match = TestCmd.match_re_dotall,ignore_python_version=0)

wpath = test.workpath()

test.write('SConstruct', r"""
Help("Help text.\n")
""")

expect = """scons: Reading SConscript files ...
scons: done reading SConscript files.
Help text.

Use scons -H for help about command-line options.
"""

os.environ['SCONSFLAGS'] = ''

test.run(arguments = '-h',
         stdout = expect,
         stderr = TestSCons.deprecated_python_expr)

os.environ['SCONSFLAGS'] = '-h'

test.run(stdout = expect,
         stderr = TestSCons.deprecated_python_expr)

# No TestSCons.deprecated_python_expr because the -H option gets
# processed before the SConscript files and therefore before we check
# for the deprecation warning.
test.run(arguments = "-H")

test.must_not_contain_any_line(test.stdout(), ['Help text.'])
test.must_contain_all_lines(test.stdout(), ['-H, --help-options'])

os.environ['SCONSFLAGS'] = '-Z'

expect = r"""usage: scons [OPTIONS] [VARIABLES] [TARGETS]

SCons Error: no such option: -Z
"""

test.run(arguments = "-H", status = 2,
         stderr = expect, match=TestSCons.match_exact)

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/SCONS_LIB_DIR.py

#!/usr/bin/env python
#
# __COPYRIGHT__
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"

import TestSCons
import os

test = TestSCons.TestSCons()

test.subdir('SCons')
test.write(['SCons','Script.py'], """
def main ():
    print("SCons.Script")
""")

test.write(['SCons','__init__.py'], """
""")


expect = "SCons.Script\n"

os.environ['SCONS_LIB_DIR'] = test.workpath()

test.run(stdout = expect)

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/SConstruct.py

#!/usr/bin/env python
#
# __COPYRIGHT__
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#

__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"

import TestCmd
import TestSCons

test = TestSCons.TestSCons()

test.run(arguments = ".",
         status = 2,
         stdout = "",
         stderr = r"""
scons: \*\*\* No SConstruct file found.
""" + TestSCons.file_expr,
         match = TestCmd.match_re)

wpath = test.workpath()

test.write('sconstruct.py', """
import os
print("sconstruct.py "+os.getcwd())
""")

test.run(arguments = ".",
         stdout = test.wrap_stdout(read_str = 'sconstruct.py %s\n' % wpath,
                                   build_str = "scons: `.' is up to date.\n"))

test.write('Sconstruct.py', """
import os
print("sconstruct.py "+os.getcwd())
""")

test.run(arguments = ".",
         stdout = test.wrap_stdout(read_str = 'sconstruct.py %s\n' % wpath,
                                   build_str = "scons: `.' is up to date.\n"))

test.write('SConstruct.py', """
import os
print("SConstruct.py "+os.getcwd())
""")

test.run(arguments = ".",
         stdout = test.wrap_stdout(read_str = 'SConstruct.py %s\n' % wpath,
                                   build_str = "scons: `.' is up to date.\n"))

test.write('sconstruct', """
import os
print("sconstruct "+os.getcwd())
""")

test.run(arguments = ".",
         stdout = test.wrap_stdout(read_str = 'sconstruct %s\n' % wpath,
                                   build_str = "scons: `.' is up to date.\n"))


test.write('Sconstruct', """
import os
print("Sconstruct "+os.getcwd())
""")

test.run(arguments = ".",
         stdout = test.wrap_stdout(read_str = 'Sconstruct %s\n' % wpath,
                                   build_str = "scons: `.' is up to date.\n"))

test.write('SConstruct', """
import os
print("SConstruct "+os.getcwd())
""")

test.run(arguments = ".",
         stdout = test.wrap_stdout(read_str = 'SConstruct %s\n' % wpath,
                                   build_str = "scons: `.' is up to date.\n"))

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/SHELL.py

#!/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 the SHELL construction variable.
"""

import os
import sys


import TestSCons

python = TestSCons.python
_python_ = TestSCons._python_

test = TestSCons.TestSCons()

if sys.platform == 'win32':
    msg = 'Cannot set SHELL separately from other variables on Windows.\n'
    test.skip_test(msg)

my_shell = test.workpath('my_shell.py')

test.write(my_shell, """\
#!%(python)s
import os
import sys
cmd = sys.argv[2]
def stripquote(s):
    if s[0] == '"' and s[-1] == '"' or \
       s[0] == "'" and s[-1] == "'":
        s = s[1:-1]
    return s
args = stripquote(sys.argv[2]).split()
args = list(map(stripquote, args))
with open(args[2], 'wb') as ofp:
    for f in args[3:] + ['extra.txt']:
        with open(f, 'rb') as ifp:
            ofp.write(ifp.read())
sys.exit(0)
""" % locals())

os.chmod(my_shell, 0o755)

test.write('SConstruct', """\
env = Environment(SHELL = r'%(my_shell)s')
env.Command('file.out', 'file.in',
            'r%(_python_)s fake_cat_program $TARGET $SOURCES')
""" % locals())

test.write('file.in', "file.in\n")
test.write('extra.txt', "extra.txt\n")

test.run()

test.must_match('file.out', "file.in\nextra.txt\n")

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/SPAWN.py

#!/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 the SPAWN construction variable.
"""

import TestSCons

_python_ = TestSCons._python_

test = TestSCons.TestSCons()

test.write('cat.py', """\
import sys
with open(sys.argv[1], 'wb') as ofp:
    for s in sys.argv[2:]:
        with open(s, 'rb') as ifp:
            ofp.write(ifp.read())
""")

test.write('SConstruct', """
import subprocess
import sys

def my_spawn1(sh, escape, cmd, args, env):
    s = " ".join(args + ['extra1.txt'])
    cp = subprocess.run(s, shell=True)
    return cp.returncode

def my_spawn2(sh, escape, cmd, args, env):
    s = " ".join(args + ['extra2.txt'])
    cp = subprocess.run(s, shell=True)
    return cp.returncode

env = Environment(MY_SPAWN1 = my_spawn1,
                  MY_SPAWN2 = my_spawn2,
                  COMMAND = r'%(_python_)s cat.py $TARGET $SOURCES')
env1 = env.Clone(SPAWN = my_spawn1)
env1.Command('file1.out', 'file1.in', '$COMMAND')

env2 = env.Clone(SPAWN = '$MY_SPAWN2')
env2.Command('file2.out', 'file2.in', '$COMMAND')

env3 = env.Clone(SPAWN = '${USE_TWO and MY_SPAWN2 or MY_SPAWN1}')
env3.Command('file3.out', 'file3.in', '$COMMAND', USE_TWO=0)
env3.Command('file4.out', 'file4.in', '$COMMAND', USE_TWO=1)
""" % locals())

test.write('file1.in', "file1.in\n")
test.write('file2.in', "file2.in\n")
test.write('file3.in', "file3.in\n")
test.write('file4.in', "file4.in\n")
test.write('extra1.txt', "extra1.txt\n")
test.write('extra2.txt', "extra2.txt\n")

test.run(arguments = '.')

test.must_match('file1.out', "file1.in\nextra1.txt\n")
test.must_match('file2.out', "file2.in\nextra2.txt\n")
test.must_match('file3.out', "file3.in\nextra1.txt\n")
test.must_match('file4.out', "file4.in\nextra2.txt\n")

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/Script-import.py

#!/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 a module that we import into an SConscript file can itself
easily import the global SCons variables, and a handful of other variables
directly from SCons.Script modules.
"""

import TestSCons

test = TestSCons.TestSCons()

test.write('SConstruct', """\
import m1
""")

test.write("m1.py", """\
from SCons.Script import *
SConscript('SConscript')
""")

test.write('SConscript', """\
import m2
import m3
import m4
""")

test.write("m2.py", """\
from SCons.Script import *
Command("file.out", "file.in", Copy("$TARGET", "$SOURCE"))
""")

test.write("m3.py", """\
import SCons.Script

SCons.Script.BuildTask
SCons.Script.CleanTask
SCons.Script.QuestionTask

old_SCons_Script_variables = [
    'OptParser',
    'keep_going_on_error',
    'print_explanations',
    'print_includes',
    'print_objects',
    'print_time',
    'memory_stats',
    'ignore_errors',
    'repositories',
    'print_dtree',
    'print_tree',
    'sconscript_time',
    'command_time',
    'exit_status',
    'profiling',
]

for var in old_SCons_Script_variables:
    try:
        getattr(SCons.Script, var)
    except AttributeError:
        pass
    else:
        raise Exception("unexpected variable SCons.Script.%s" % var)
""")

test.write("m4.py", """\
import SCons.Script.SConscript
SCons.Script.SConscript.Arguments
SCons.Script.SConscript.ArgList
SCons.Script.SConscript.BuildTargets
SCons.Script.SConscript.CommandLineTargets
SCons.Script.SConscript.DefaultTargets
""")

test.write("file.in", "file.in\n")

test.run(arguments = '.')

test.must_match("file.out", "file.in\n")

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/Split.py

#!/usr/bin/env python
#
# __COPYRIGHT__
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#

__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"

import TestSCons

test = TestSCons.TestSCons()

test.write('SConstruct', """
env = Environment(BBB = 'bbb', CCC = 'ccc')
print(Split('aaa'))
print(Split('aaa $BBB'))
print(env.Split('bbb $CCC'))
print(env.Split('$BBB ccc'))
print(Split(['ddd', 'eee']))
SConscript('SConscript')
""")

test.write('SConscript', """
env = Environment(FFF='fff', JJJ='jjj')
print(env.Split('${FFF}.f'))
print(Split('ggg hhh'))
print(env.Split(['iii', '$JJJ']))
""")

expect = """\
['aaa']
['aaa', '$BBB']
['bbb', 'ccc']
['bbb', 'ccc']
['ddd', 'eee']
['fff.f']
['ggg', 'hhh']
['iii', 'jjj']
"""

test.run(arguments = ".",
         stdout = test.wrap_stdout(read_str = expect,
                                   build_str = "scons: `.' is up to date.\n"))

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/TARGET-dir.py

#!/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 use of ${TARGET.dir} to specify a CPPPATH directory in
combination VariantDirs and a generated .h file.
"""

import TestSCons

_exe = TestSCons._exe

test = TestSCons.TestSCons()

build1_foo = test.workpath('build1', 'foo' + _exe)
build2_foo = test.workpath('build2', 'foo' + _exe)

test.subdir('src', 'build1', 'build2')

test.write('SConstruct', """
def cat(env, source, target):
    target = str(target[0])
    with open(target, "wb") as f:
        for src in source:
            with open(str(src), "rb") as ifp:
                f.write(ifp.read())
    f.close()
env = Environment(CPPPATH='${TARGET.dir}')
env.Append(BUILDERS = {'Cat' : Builder(action=cat)})
Export('env')
VariantDir('build1', 'src')
SConscript('build1/SConscript')
VariantDir('build2', 'src')
SConscript('build2/SConscript', duplicate=0)
""")

test.write(['src', 'SConscript'], """
Import('env')
env.Cat('foo.h', 'foo.h.in')
env.Program('foo', ['foo.c'])
""")

test.write(['src', 'foo.h.in'], """\
#define STRING  "foo.h.in\\n"
""")

test.write(['src', 'foo.c'], """\
#include <stdio.h>
#include <stdlib.h>

#include <foo.h>

int
main(int argc, char *argv[])
{
    printf(STRING);
    printf("foo.c\\n");
    exit (0);
}
""")

test.run(arguments = '.')

test.run(program = build1_foo, stdout = "foo.h.in\nfoo.c\n")
test.run(program = build2_foo, stdout = "foo.h.in\nfoo.c\n")

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/TARGETS.py

#!/usr/bin/env python
#
# MIT License
#
# Copyright The SCons Foundation
#
# 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.

"""
Test use of the COMMAND_LINE_TARGETS and DEFAULT_TARGETS variables.
"""

import TestSCons

test = TestSCons.TestSCons()



test.write('SConstruct', """
print(COMMAND_LINE_TARGETS)
print(list(map(str, BUILD_TARGETS)))
Default('.')
print(COMMAND_LINE_TARGETS)
print(list(map(str, BUILD_TARGETS)))
""")

test.write('aaa', 'aaa\n')
test.write('bbb', 'bbb\n')

expect = test.wrap_stdout(read_str = "[]\n[]\n[]\n['.']\n",
                          build_str = "scons: `.' is up to date.\n")
test.run(stdout = expect)

expect = test.wrap_stdout(read_str = "['.']\n['.']\n['.']\n['.']\n",
                          build_str = "scons: `.' is up to date.\n")
test.run(arguments = '.', stdout = expect)

expect = test.wrap_stdout(read_str = "['aaa']\n['aaa']\n['aaa']\n['aaa']\n",
                          build_str = "scons: Nothing to be done for `aaa'.\n")
test.run(arguments = 'aaa', stdout = expect)

expect = test.wrap_stdout(read_str = "['bbb', 'aaa']\n['bbb', 'aaa']\n['bbb', 'aaa']\n['bbb', 'aaa']\n",
                          build_str = """\
scons: Nothing to be done for `bbb'.
scons: Nothing to be done for `aaa'.
""")
test.run(arguments = 'bbb ccc=xyz -n aaa', stdout = expect)



test.write('SConstruct', """
env = Environment()
print(list(map(str, DEFAULT_TARGETS)))
print(list(map(str, BUILD_TARGETS)))
Default('aaa')
print(list(map(str, DEFAULT_TARGETS)))
print(list(map(str, BUILD_TARGETS)))
env.Default('bbb')
print(list(map(str, DEFAULT_TARGETS)))
print(list(map(str, BUILD_TARGETS)))
env.Default(None)
print(list(map(str, DEFAULT_TARGETS)))
print(list(map(str, BUILD_TARGETS)))
env.Default('ccc')
""")

test.write('ccc', "ccc\n")

expect = test.wrap_stdout(build_str = "scons: Nothing to be done for `ccc'.\n",
                          read_str = """\
[]
[]
['aaa']
['aaa']
['aaa', 'bbb']
['aaa', 'bbb']
[]
[]
""")
test.run(stdout = expect)

expect = test.wrap_stdout(build_str = "scons: `.' is up to date.\n",
                          read_str = """\
[]
['.']
['aaa']
['.']
['aaa', 'bbb']
['.']
[]
['.']
""")
test.run(arguments = '.', stdout = expect)



test.write('SConstruct', """\
print(list(map(str, BUILD_TARGETS)))
SConscript('SConscript')
print(list(map(str, BUILD_TARGETS)))
""")

test.write('SConscript', """\
BUILD_TARGETS.append('sconscript_target')
""")

test.write('command_line_target', "command_line_target\n")
test.write('sconscript_target', "sconscript_target\n")

expect = test.wrap_stdout(read_str = """\
['command_line_target']
['command_line_target', 'sconscript_target']
""",
                          build_str = """\
scons: Nothing to be done for `command_line_target'.
scons: Nothing to be done for `sconscript_target'.
""")
test.run(arguments = 'command_line_target', stdout = expect)



# blanks in cmdline should not be treated as targets (issue 2986)
test.write(
    file='SConstruct',
    content="""\
tgt_foo = Textfile(target="foo", source="foostuff")
tgt_bar = Textfile(target="bar", source="bartuff")
Default(tgt_foo)
""",
)
test.run(arguments=["-Q", "-n", "''"], stdout="Creating 'foo.txt'\n")
test.run(arguments=["-Q", "-n", ""], stdout="Creating 'foo.txt'\n")
test.run(arguments=["-Q", "-n", '""'], stdout="Creating 'foo.txt'\n")



test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/ToolSurrogate.py

#!/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 SCons supports use of a home-brew ToolSurrogate class
like we use in our bin/sconsexamples.py script.
"""

import TestSCons

test = TestSCons.TestSCons()

test.write('SConstruct', """\
class Curry:
    def __init__(self, fun, *args, **kwargs):
        self.fun = fun
        self.pending = args[:]
        self.kwargs = kwargs.copy()

    def __call__(self, *args, **kwargs):
        if kwargs and self.kwargs:
            kw = self.kwargs.copy()
            kw.update(kwargs)
        else:
            kw = kwargs or self.kwargs

        return self.fun(*self.pending + args, **kw)

def Str(target, source, env, cmd=""):
    result = []
    for cmd in env.subst_list(cmd, target=target, source=source):
        result.append(" ".join(map(str, cmd)))
    return '\\n'.join(result)

class ToolSurrogate:
    def __init__(self, tool, variable, func):
        self.tool = tool
        self.variable = variable
        self.func = func
    def __call__(self, env):
        t = Tool(self.tool)
        t.generate(env)
        orig = env[self.variable]
        env[self.variable] = Action(self.func, strfunction=Curry(Str, cmd=orig))

def Cat(target, source, env):
    target = str(target[0])
    with open(target, "wb") as ofp:
        for src in map(str, source):
            with open(src, "rb") as ifp:
                ofp.write(ifp.read())

ToolList = {
    'posix' :   [('cc', 'CCCOM', Cat),
                 ('link', 'LINKCOM', Cat)],
    'win32' :   [('msvc', 'CCCOM', Cat),
                 ('mslink', 'LINKCOM', Cat)]
}

platform = ARGUMENTS['platform']
tools = [ToolSurrogate(*t) for t in ToolList[platform]]

env = Environment(tools=tools, PROGSUFFIX='.exe', OBJSUFFIX='.obj')
env.Program('foo.c')
""")

test.write('foo.c', "foo.c posix\n")

test.run(arguments = '. platform=posix', stdout = test.wrap_stdout("""\
cc -o foo.obj -c foo.c
cc -o foo.exe foo.obj
"""))

test.write('foo.c', "foo.c win32\n")

test.run(arguments = '. platform=win32', stdout = test.wrap_stdout("""\
cl /Fofoo.obj /c foo.c /nologo
link /nologo /OUT:foo.exe foo.obj
embedManifestExeCheck(target, source, env)
"""))

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/Touch.py

#!/usr/bin/env python
#
# MIT License
#
# Copyright The SCons Foundation
#
# 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 Touch() Action works.
"""

import os.path

import TestSCons

test = TestSCons.TestSCons()

test.write('SConstruct', """\
Execute(Touch('f1'))
Execute(Touch(File('f1-File')))

def cat(env, source, target):
    target = str(target[0])
    with open(target, "wb") as f:
        for src in source:
            with open(str(src), "rb") as ifp:
                f.write(ifp.read())

Cat = Action(cat)
env = Environment()
env.Command('f2.out', 'f2.in', [Cat, Touch("f3")])
env = Environment(FILE='f4')
env.Command('f5.out', 'f5.in', [Touch("$FILE"), Cat])
env.Command('f6.out', 'f6.in', [Cat, Touch("Touch-$SOURCE"), Touch("$TARGET-Touch")])

# Make sure Touch works with a list of arguments
env = Environment()
env.Command(
    'f7.out', 'f7.in', [Cat, Touch(["Touch-$SOURCE", "$TARGET-Touch", File("f8")])]
)
""")

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")
test.write('f7.in', "f7.in\n")

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")
Touch("f1-File")
""",
    build_str="""\
cat(["f2.out"], ["f2.in"])
Touch("f3")
Touch("f4")
cat(["f5.out"], ["f5.in"])
cat(["f6.out"], ["f6.in"])
Touch("Touch-f6.in")
Touch("f6.out-Touch")
cat(["f7.out"], ["f7.in"])
Touch(["Touch-f7.in", "f7.out-Touch", "f8"])
""",
)
test.run(options='-n', arguments='.', stdout=expect)

test.sleep()  # delay for timestamps
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'))
test.must_not_exist(test.workpath('f4'))
test.must_not_exist(test.workpath('f5.out'))
test.must_not_exist(test.workpath('f6.out'))
test.must_not_exist(test.workpath('Touch-f6.in'))
test.must_not_exist(test.workpath('f6.out-Touch'))
test.must_not_exist(test.workpath('f7.out'))
test.must_not_exist(test.workpath('Touch-f7.in'))
test.must_not_exist(test.workpath('f7.out-Touch'))
test.must_not_exist(test.workpath('f8'))

test.run()

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'))
test.must_exist(test.workpath('f4'))
test.must_match('f5.out', "f5.in\n")
test.must_match('f6.out', "f6.in\n")
test.must_exist(test.workpath('Touch-f6.in'))
test.must_exist(test.workpath('f6.out-Touch'))
test.must_match('f7.out', "f7.in\n")
test.must_exist(test.workpath('Touch-f7.in'))
test.must_exist(test.workpath('f7.out-Touch'))
test.must_exist(test.workpath('f8'))

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/Value.py

#!/usr/bin/env python
#
# __COPYRIGHT__
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"

import re

import TestSCons
import TestCmd

_python_ = TestSCons._python_

test = TestSCons.TestSCons(match=TestCmd.match_re)

python = TestSCons.python

SConstruct_content = """
Decider(r'%(source_signature)s')

class Custom:
    def __init__(self, value):  self.value = value
    def __str__(self):          return "C=" + str(self.value)

P = ARGUMENTS.get('prefix', '/usr/local')
L = len(P)
C = Custom(P)

def create(target, source, env):
    with open(str(target[0]), 'wb') as f:
        f.write(source[0].get_contents())

env = Environment()
env['BUILDERS']['B'] = Builder(action = create)
env['BUILDERS']['S'] = Builder(action = r'%(_python_)s put.py $SOURCES into $TARGET')
env.B('f1.out', Value(P))
env.B('f2.out', env.Value(L))
env.B('f3.out', Value(C))
env.S('f4.out', Value(L))

def create_value (target, source, env):
    target[0].write(source[0].get_contents())

def create_value_file (target, source, env):
    with open(str(target[0]), 'wb') as f:
        f.write(source[0].read())

env['BUILDERS']['B2'] = Builder(action = create_value)
env['BUILDERS']['B3'] = Builder(action = create_value_file)

V = Value('my value')
env.B2(V, 'f3.out')
env.B3('f5.out', V)
"""

test.write('put.py', """\
import os
import sys
with open(sys.argv[-1],'w') as f:
    f.write(" ".join(sys.argv[1:-2]))
""")

# Run all of the tests with both types of source signature
# to make sure there's no difference in behavior.
for source_signature in ['MD5', 'timestamp-newer']:

    print("Testing Value node with source signatures:", source_signature)

    test.write('SConstruct', SConstruct_content % locals())

    test.run(arguments='-c')
    test.run()

    out7 = """create_value(['my value'], ["f3.out"])"""
    out8 = """create_value_file(["f5.out"], ['my value'])"""

    out1 = """create(["f1.out"], ['/usr/local'])"""
    out2 = """create(["f2.out"], [10])"""
    out3 = """create\\(\\["f3.out"\\], \\[<.*.Custom (instance|object) at """
    #" <- unconfuses emacs syntax highlighting

    test.must_contain_all_lines(test.stdout(), [out1, out2, out7, out8])
    #print test.stdout()
    test.fail_test(re.search(out3, test.stdout()) is None)

    test.must_match('f1.out', "/usr/local")
    test.must_match('f2.out', "10")
    test.must_match('f3.out', "C=/usr/local")
    test.must_match('f4.out', '10')
    test.must_match('f5.out', "C=/usr/local")

    test.up_to_date(arguments='.')

    test.run(options='prefix=/usr')
    out4 = """create(["f1.out"], ['/usr'])"""
    out5 = """create(["f2.out"], [4])"""
    out6 = """create\\(\\["f3.out"\\], \\[<.*.Custom (instance|object) at """
    #" <- unconfuses emacs syntax highlighting
    test.must_contain_all_lines(test.stdout(), [out4, out5])
    test.fail_test(re.search(out6, test.stdout()) is None)

    test.must_match('f1.out', "/usr")
    test.must_match('f2.out', "4")
    test.must_match('f3.out', "C=/usr")
    test.must_match('f4.out', '4')

    test.up_to_date(options='prefix=/usr', arguments='.')

    test.unlink('f3.out')

    test.run(options='prefix=/var')
    out4 = """create(["f1.out"], ['/var'])"""

    test.must_contain_all_lines(test.stdout(), [out4, out7, out8])
    test.must_not_contain_any_line(test.stdout(), [out5])
    test.fail_test(re.search(out6, test.stdout()) is None)

    test.up_to_date(options='prefix=/var', arguments='.')

    test.must_match('f1.out', "/var")
    test.must_match('f2.out', "4")
    test.must_match('f3.out', "C=/var")
    test.must_match('f4.out', "4")
    test.must_match('f5.out', "C=/var")

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/WhereIs.py

#!/usr/bin/env python
#
# __COPYRIGHT__
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#

__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"

import os
import sys

import TestSCons

test = TestSCons.TestSCons()

subdir_SConscript = os.path.join('subdir/SConscript')
sub1_xxx_exe = test.workpath('sub1', 'xxx.exe')
sub2_xxx_exe = test.workpath('sub2', 'xxx.exe')
sub3_xxx_exe = test.workpath('sub3', 'xxx.exe')
sub4_xxx_exe = test.workpath('sub4', 'xxx.exe')

test.subdir('subdir', 'sub1', 'sub2', 'sub3', 'sub4')

if sys.platform != 'win32':
    test.write(sub1_xxx_exe, "\n")

os.mkdir(sub2_xxx_exe)

test.write(sub3_xxx_exe, "\n")
os.chmod(sub3_xxx_exe, 0o777)

test.write(sub4_xxx_exe, "\n")
os.chmod(sub4_xxx_exe, 0o777)

env_path = os.environ['PATH']

pathdirs_1234 = [ test.workpath('sub1'),
                  test.workpath('sub2'),
                  test.workpath('sub3'),
                  test.workpath('sub4'),
                ] + env_path.split(os.pathsep)

pathdirs_1243 = [ test.workpath('sub1'),
                  test.workpath('sub2'),
                  test.workpath('sub4'),
                  test.workpath('sub3'),
                ] + env_path.split(os.pathsep)

test.write('SConstruct', """
SConscript('%s')
env = Environment()
print(WhereIs('xxx.exe'))
print(WhereIs('xxx.exe', %s))
print(env.WhereIs('xxx.exe', %s))
print(WhereIs('xxx.exe', %s))
print(WhereIs('xxx.exe', %s))
print(WhereIs('xxx.exe', %s, reject=%s))
env.Replace( XXXNAME='xxx.exe' )
print(env.WhereIs( '$XXXNAME', %s ))
""" % (subdir_SConscript,
       repr(os.pathsep.join(pathdirs_1234)),
       repr(os.pathsep.join(pathdirs_1243)),
       repr(pathdirs_1234),
       repr(pathdirs_1243),
       repr(pathdirs_1243),
       repr(sub4_xxx_exe),
       repr(os.pathsep.join(pathdirs_1243)),
      ))

test.write(subdir_SConscript, """
env = Environment()
print(WhereIs('xxx.exe'))
print(WhereIs('xxx.exe', %s))
print(env.WhereIs('xxx.exe', %s))
print(WhereIs('xxx.exe', %s))
print(WhereIs('xxx.exe', %s))
""" % (repr(os.pathsep.join(pathdirs_1234)),
       repr(os.pathsep.join(pathdirs_1243)),
       repr(pathdirs_1234),
       repr(pathdirs_1243),
      ))

os.environ['PATH'] = os.pathsep.join(pathdirs_1234)

expect = [ test.workpath(sub3_xxx_exe),
           test.workpath(sub3_xxx_exe),
           test.workpath(sub4_xxx_exe),
           test.workpath(sub3_xxx_exe),
           test.workpath(sub4_xxx_exe),
           test.workpath(sub3_xxx_exe),
           test.workpath(sub3_xxx_exe),
           test.workpath(sub4_xxx_exe),
           test.workpath(sub3_xxx_exe),
           test.workpath(sub4_xxx_exe),
           test.workpath(sub3_xxx_exe),
           test.workpath(sub4_xxx_exe)
         ]

test.run(arguments = ".",
         stdout = test.wrap_stdout(read_str = "\n".join(expect) + "\n",
                                   build_str = "scons: `.' is up to date.\n"))

os.environ['PATH'] = os.pathsep.join(pathdirs_1243)

expect = [ test.workpath(sub4_xxx_exe),
           test.workpath(sub3_xxx_exe),
           test.workpath(sub4_xxx_exe),
           test.workpath(sub3_xxx_exe),
           test.workpath(sub4_xxx_exe),
           test.workpath(sub4_xxx_exe),
           test.workpath(sub3_xxx_exe),
           test.workpath(sub4_xxx_exe),
           test.workpath(sub3_xxx_exe),
           test.workpath(sub4_xxx_exe),
           test.workpath(sub3_xxx_exe),
           test.workpath(sub4_xxx_exe)
         ]

test.run(arguments = ".",
         stdout = test.wrap_stdout(read_str = "\n".join(expect) + "\n",
                                   build_str = "scons: `.' is up to date.\n"))


test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/_CPPINCFLAGS.py

#!/usr/bin/env python
# MIT License
#
# Copyright The SCons Foundation
#
# 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.

"""
Test that we can expand $_CPPINCFLAGS correctly regardless of whether
the target is an entry, a directory, or a file.  (Internally, this tests
that RDirs() is available to be called for each Node.FS type.)
"""

import TestSCons

test = TestSCons.TestSCons()

test.write('SConstruct', """\
env=Environment(CPPPATH=['tmp'], INCPREFIX='-I')
d=Entry('foo.d')
e=Entry('foo.e')
f=File('foo.f')
print(env.subst('$_CPPINCFLAGS', target=e, source=f))
print(env.subst('$_CPPINCFLAGS', target=d, source=f))
print(env.subst('$_CPPINCFLAGS', target=f, source=d))
""")

expect = """\
-Itmp
-Itmp
-Itmp
"""

test.run(arguments = '-Q -q', stdout = expect)

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/bad-variables.py

#!/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 setting illegal construction variables fails in ways that are
useful to the user.
"""

import TestSCons

test = TestSCons.TestSCons()

SConstruct_path = test.workpath('SConstruct')
SConscript_path = test.workpath('SConscript')

test.write(SConstruct_path, """\
env = Environment()
env['foo-bar'] = 1
""")

expect_stderr = """
scons: *** Illegal construction variable `foo-bar'
""" + test.python_file_line(SConstruct_path, 2)

test.run(arguments='.', status=2, stderr=expect_stderr)



test.write(SConstruct_path, """\
SConscript('SConscript')
""")

test.write('SConscript', """\
env = Environment()
env['foo(bar)'] = 1
""")


expect_stderr = """
scons: *** Illegal construction variable `foo(bar)'
""" + test.python_file_line(SConscript_path, 2)

test.run(arguments='.', status=2, stderr=expect_stderr)

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/builderrors.py

#!/usr/bin/env python
#
# __COPYRIGHT__
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"

import os

import TestSCons

_python_ = TestSCons._python_

test = TestSCons.TestSCons()

test.subdir('one', 'two', 'three')

test.write('build.py', r"""
import sys
exitval = int(sys.argv[1])
if exitval == 0:
    with open(sys.argv[2], 'w') as f, open(sys.argv[3], 'r') as infp:
        f.write(infp.read())
sys.exit(exitval)
""")

test.write(['one', 'SConstruct'], """
B0 = Builder(action = r'%(_python_)s ../build.py 0 $TARGET $SOURCES')
B1 = Builder(action = r'%(_python_)s ../build.py 1 $TARGET $SOURCES')
env = Environment(BUILDERS = { 'B0' : B0, 'B1' : B1 })
env.B1(target = 'f1.out', source = 'f1.in')
env.B0(target = 'f2.out', source = 'f2.in')
env.B0(target = 'f3.out', source = 'f3.in')
""" % locals())

test.write(['one', 'f1.in'], "one/f1.in\n")
test.write(['one', 'f2.in'], "one/f2.in\n")
test.write(['one', 'f3.in'], "one/f3.in\n")

test.run(chdir = 'one', arguments = "f1.out f2.out f3.out",
         stderr = "scons: *** [f1.out] Error 1\n", status = 2)

test.fail_test(os.path.exists(test.workpath('f1.out')))
test.fail_test(os.path.exists(test.workpath('f2.out')))
test.fail_test(os.path.exists(test.workpath('f3.out')))

test.write(['two', 'SConstruct'], """
B0 = Builder(action = r'%(_python_)s ../build.py 0 $TARGET $SOURCES')
B1 = Builder(action = r'%(_python_)s ../build.py 1 $TARGET $SOURCES')
env = Environment(BUILDERS = { 'B0': B0, 'B1' : B1 })
env.B0(target = 'f1.out', source = 'f1.in')
env.B1(target = 'f2.out', source = 'f2.in')
env.B0(target = 'f3.out', source = 'f3.in')
""" % locals())

test.write(['two', 'f1.in'], "two/f1.in\n")
test.write(['two', 'f2.in'], "two/f2.in\n")
test.write(['two', 'f3.in'], "two/f3.in\n")

test.run(chdir = 'two', arguments = "f1.out f2.out f3.out",
         stderr = "scons: *** [f2.out] Error 1\n", status = 2)

test.must_match(['two', 'f1.out'], "two/f1.in\n", mode='r')
test.fail_test(os.path.exists(test.workpath('f2.out')))
test.fail_test(os.path.exists(test.workpath('f3.out')))

test.write(['three', 'SConstruct'], """
B0 = Builder(action = r'%(_python_)s ../build.py 0 $TARGET $SOURCES')
B1 = Builder(action = r'%(_python_)s ../build.py 1 $TARGET $SOURCES')
env = Environment(BUILDERS = { 'B0' : B0, 'B1': B1 })
env.B0(target = 'f1.out', source = 'f1.in')
env.B0(target = 'f2.out', source = 'f2.in')
env.B1(target = 'f3.out', source = 'f3.in')
""" % locals())

test.write(['three', 'f1.in'], "three/f1.in\n")
test.write(['three', 'f2.in'], "three/f2.in\n")
test.write(['three', 'f3.in'], "three/f3.in\n")

test.run(chdir = 'three', arguments = "f1.out f2.out f3.out",
         stderr = "scons: *** [f3.out] Error 1\n", status = 2)

test.must_match(['three', 'f1.out'], "three/f1.in\n", mode='r')
test.must_match(['three', 'f2.out'], "three/f2.in\n", mode='r')
test.fail_test(os.path.exists(test.workpath('f3.out')))

test.write('SConstruct', """
env=Environment()
env['ENV']['PATH'] = ''
env.Command(target='foo.out', source=[], action='not_a_program')
""")

test.run(status=2, stderr=None)
test.must_not_contain_any_line(test.stderr(), ['Exception', 'Traceback'])


# Test ETOOLONG (arg list too long).  This is not in exitvalmap,
# but that shouldn't cause a scons traceback.
long_cmd = 'xyz ' + "foobarxyz" * 100000
test.write('SConstruct', """
env=Environment()
env.Command(target='longcmd.out', source=[], action='echo %s')
"""%long_cmd)

test.run(status=2, stderr=None)

test.must_not_contain_any_line(test.stderr(), ['Exception', 'Traceback'])

#TODO: This was originally commented out because of a problem with 1.5.2,
# but it doesn't work on later Pythons, either.
#expected = [
#    "too long", # posix
#    "nvalid argument", # win32
#]
#test.must_contain_any_line(test.stderr(), expected)


# Test bad shell ('./one' is a dir, so it can't be used as a shell).
# This will also give an exit status not in exitvalmap,
# with error "Permission denied" or "No such file or directory".
test.write('SConstruct', """
env=Environment()
env['SHELL'] = 'one'
env.Command(target='badshell.out', source=[], action='foo')
""")

test.run(status=2, stderr=None)
test.must_not_contain_any_line(test.stderr(), ['Exception', 'Traceback'])
expect = [
    'No such file',
    'Permission denied',
    'permission denied',
]
test.must_contain_any_line(test.stderr(), expect)


# Test command with exit status -1.
# Should not give traceback.
test.write('SConstruct', """
import os
env = Environment(ENV = os.environ)
env.Command('dummy.txt', None, ['python -c "import sys; sys.exit(-1)"'])
""")

test.run(status=2, stderr=None)
test.must_not_contain_any_line(test.stderr(), ['Exception', 'Traceback'])


# Test SConscript with errors and an atexit function.
# Should not give traceback; the task error should get converted
# to a BuildError.
test.write('SConstruct', """
import atexit

env = Environment()
env2 = env.Clone()

env.Install("target", "dir1/myFile")
env2.Install("target", "dir2/myFile")

def print_build_failures():
    from SCons.Script import GetBuildFailures
    for bf in GetBuildFailures():
    print(bf.action)

atexit.register(print_build_failures)
""")

test.run(status=2, stderr=None)
test.must_not_contain_any_line(test.stderr(), ['Exception', 'Traceback'])


# Bug #1053: Alias is called "all", but default is the File "all"
test.write('SConstruct', """
env = Environment()
env.Default("all")
env.Alias("all", env.Install("dir", "file.txt"))
""")
test.run(status=2, match=TestSCons.match_re, stderr=\
r"""scons: \*\*\* Do not know how to make File target `all' \(.*all\).  Stop.
""")

# No tests failed; OK.
test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/chained-build.py

#!/usr/bin/env python
#
# MIT License
#
# Copyright The SCons Foundation
#
# 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.

import TestSCons

test = TestSCons.TestSCons()

# During the development of 0.96, there was a --save-explain-info
# option for a brief moment that would surpress storing extra
# info in the .sconsign file(s).  At that time, this test used two
# working subdirectories to test both with and without the saved info.
# We eliminated the --save-explain-info option and the second working
# subdirectory here, but didn't go back and change all the filenames.
test.subdir('w1')

SConstruct1_contents = """\
def build(env, target, source):
    with open(str(target[0]), 'wt') as fo, open(str(source[0]), 'rt') as fi:
        fo.write(fi.read())

env=Environment(BUILDERS={'B' : Builder(action=build)})
env.B('foo.mid', 'foo.in')
"""

SConstruct2_contents = """\
def build(env, target, source):
    with open(str(target[0]), 'wt') as fo, open(str(source[0]), 'rt') as fi:
        fo.write(fi.read())

env=Environment(BUILDERS={'B' : Builder(action=build)})
env.B('foo.out', 'foo.mid')
"""

test.write(['w1', 'SConstruct1'], SConstruct1_contents)
test.write(['w1', 'SConstruct2'], SConstruct2_contents)
test.write(['w1', 'foo.in'], "foo.in 1")

test.run(
    chdir='w1',
    arguments="--max-drift=0 -f SConstruct1 foo.mid",
    stdout=test.wrap_stdout('build(["foo.mid"], ["foo.in"])\n'),
)
test.run(
    chdir='w1',
    arguments="--max-drift=0 -f SConstruct2 foo.out",
    stdout=test.wrap_stdout('build(["foo.out"], ["foo.mid"])\n'),
)
test.up_to_date(chdir='w1', options="--max-drift=0 -f SConstruct1", arguments="foo.mid")
test.up_to_date(chdir='w1', options="--max-drift=0 -f SConstruct2", arguments="foo.out")

test.sleep()  # delay for timestamps
test.write(['w1', 'foo.in'], "foo.in 2")

# Because we're using --max-drift=0, we use the cached csig value
# and think that foo.in hasn't changed even though it has on disk.
test.up_to_date(chdir='w1',
         options="--max-drift=0 -f SConstruct1",
         arguments="foo.mid")

# Now try with --max-drift disabled.  The build of foo.out should still
# be considered up-to-date, but the build of foo.mid now detects the
# change and rebuilds, too, which then causes a rebuild of foo.out.
test.up_to_date(
    chdir='w1', options="--max-drift=-1 -f SConstruct2", arguments="foo.out"
)
test.run(
    chdir='w1',
    arguments="--max-drift=-1 -f SConstruct1 foo.mid",
    stdout=test.wrap_stdout('build(["foo.mid"], ["foo.in"])\n'),
)
test.run(
    chdir='w1',
    arguments="--max-drift=-1 -f SConstruct2 foo.out",
    stdout=test.wrap_stdout('build(["foo.out"], ["foo.mid"])\n'),
)

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/chdir.py

#!/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 the chdir argument to Builder creation, Action creation,
Command() calls and execution work1s correctly.
"""

import TestSCons

_python_ = TestSCons._python_

test = TestSCons.TestSCons()

test.subdir('other1',
            'other2',
            'other3',
            'other4',
            'other5',
            'other6',
            'other7',
            'other8',
            'other9',
            'work1',
            ['work1', 'sub1'],
            ['work1', 'sub2'],
            ['work1', 'sub3'],
            ['work1', 'sub4'],
            ['work1', 'sub5'],
            ['work1', 'sub6'],
            ['work1', 'sub7'],
            ['work1', 'sub8'],
            ['work1', 'sub9'],
            ['work1', 'sub20'],
            ['work1', 'sub21'],
            ['work1', 'sub22'],
            ['work1', 'sub23'])

cat_py = test.workpath('cat.py')

other1 = test.workpath('other1')
other1_f11_out = test.workpath('other1', 'f11.out')
other1_f11_in = test.workpath('other1', 'f11.in')
other2 = test.workpath('other2')
other2_f12_out = test.workpath('other2', 'f12.out')
other2_f12_in = test.workpath('other2', 'f12.in')
other3 = test.workpath('other3')
other3_f13_out = test.workpath('other3', 'f13.out')
other3_f13_in = test.workpath('other3', 'f13.in')
other4 = test.workpath('other4')
other4_f14_out = test.workpath('other4', 'f14.out')
other4_f14_in = test.workpath('other4', 'f14.in')
other5 = test.workpath('other5')
other5_f15_out = test.workpath('other5', 'f15.out')
other5_f15_in = test.workpath('other5', 'f15.in')
other6 = test.workpath('other6')
other6_f16_out = test.workpath('other6', 'f16.out')
other6_f16_in = test.workpath('other6', 'f16.in')
other7 = test.workpath('other7')
other7_f17_out = test.workpath('other7', 'f17.out')
other7_f17_in = test.workpath('other7', 'f17.in')
other8 = test.workpath('other8')
other8_f18_out = test.workpath('other8', 'f18.out')
other8_f18_in = test.workpath('other8', 'f18.in')
other9 = test.workpath('other9')
other9_f19_out = test.workpath('other9', 'f19.out')
other9_f19_in = test.workpath('other9', 'f19.in')

test.write(cat_py, """\
import sys
with open(sys.argv[1], 'wb') as ofp:
    for f in sys.argv[2:]:
        with open(f, 'rb') as ifp:
            ofp.write(ifp.read())
""")

test.write(['work1', 'SConstruct'], """
cat_command = r'%(_python_)s %(cat_py)s ${TARGET.file} ${SOURCE.file}'

no_chdir_act = Action(cat_command)
chdir_sub4_act = Action(cat_command, chdir=1)
chdir_sub5_act = Action(cat_command, chdir='sub5')
chdir_sub6_act = Action(cat_command, chdir=Dir('sub6'))

env = Environment(BUILDERS = {
    'Chdir4' : Builder(action = chdir_sub4_act),
    'Chdir5' : Builder(action = chdir_sub5_act),
    'Chdir6' : Builder(action = chdir_sub6_act),
    'Chdir7' : Builder(action = no_chdir_act, chdir=1),
    'Chdir8' : Builder(action = no_chdir_act, chdir='sub8'),
    'Chdir9' : Builder(action = no_chdir_act, chdir=Dir('sub9')),
})

env.Command('f0.out', 'f0.in', cat_command)

env.Command('sub1/f1.out', 'sub1/f1.in', cat_command,
            chdir=1)
env.Command('sub2/f2.out', 'sub2/f2.in', cat_command,
            chdir='sub2')
env.Command('sub3/f3.out', 'sub3/f3.in', cat_command,
            chdir=Dir('sub3'))

env.Chdir4('sub4/f4.out', 'sub4/f4.in')
env.Chdir5('sub5/f5.out', 'sub5/f5.in')
env.Chdir6('sub6/f6.out', 'sub6/f6.in')

env.Chdir7('sub7/f7.out', 'sub7/f7.in')
env.Chdir8('sub8/f8.out', 'sub8/f8.in')
env.Chdir9('sub9/f9.out', 'sub9/f9.in')

env.Command(r'%(other1_f11_out)s', r'%(other1_f11_in)s', cat_command,
            chdir=1)
env.Command(r'%(other2_f12_out)s', r'%(other2_f12_in)s', cat_command,
            chdir=r'%(other2)s')
env.Command(r'%(other3_f13_out)s', r'%(other3_f13_in)s', cat_command,
            chdir=Dir(r'%(other3)s'))

env.Chdir4(r'%(other4_f14_out)s', r'%(other4_f14_in)s')
env.Chdir5(r'%(other5_f15_out)s', r'%(other5_f15_in)s',
           chdir=r'%(other5)s')
env.Chdir6(r'%(other6_f16_out)s', r'%(other6_f16_in)s',
           chdir=Dir(r'%(other6)s'))

env.Chdir7(r'%(other7_f17_out)s', r'%(other7_f17_in)s')
env.Chdir8(r'%(other8_f18_out)s', r'%(other8_f18_in)s',
           chdir=r'%(other8)s')
env.Chdir9(r'%(other9_f19_out)s', r'%(other9_f19_in)s',
           chdir=Dir(r'%(other9)s'))

Command('f20.out', 'f20.in', cat_command)

Command('sub21/f21.out', 'sub21/f21.in', cat_command,
        chdir=1)
Command('sub22/f22.out', 'sub22/f22.in', cat_command,
        chdir='sub22')
Command('sub23/f23.out', 'sub23/f23.in', cat_command,
        chdir=Dir('sub23'))
""" % locals())

test.write(['work1', 'f0.in'], "work1/f0.in\n")

test.write(['work1', 'sub1', 'f1.in'], "work1/sub1/f1.in\n")
test.write(['work1', 'sub2', 'f2.in'], "work1/sub2/f2.in\n")
test.write(['work1', 'sub3', 'f3.in'], "work1/sub3/f3.in\n")
test.write(['work1', 'sub4', 'f4.in'], "work1/sub4/f4.in\n")
test.write(['work1', 'sub5', 'f5.in'], "work1/sub5/f5.in\n")
test.write(['work1', 'sub6', 'f6.in'], "work1/sub6/f6.in\n")
test.write(['work1', 'sub7', 'f7.in'], "work1/sub7/f7.in\n")
test.write(['work1', 'sub8', 'f8.in'], "work1/sub8/f8.in\n")
test.write(['work1', 'sub9', 'f9.in'], "work1/sub9/f9.in\n")

test.write(['other1', 'f11.in'], "other1/f11.in\n")
test.write(['other2', 'f12.in'], "other2/f12.in\n")
test.write(['other3', 'f13.in'], "other3/f13.in\n")
test.write(['other4', 'f14.in'], "other4/f14.in\n")
test.write(['other5', 'f15.in'], "other5/f15.in\n")
test.write(['other6', 'f16.in'], "other6/f16.in\n")
test.write(['other7', 'f17.in'], "other7/f17.in\n")
test.write(['other8', 'f18.in'], "other8/f18.in\n")
test.write(['other9', 'f19.in'], "other9/f19.in\n")

test.write(['work1', 'f20.in'], "work1/f20.in\n")

test.write(['work1', 'sub21', 'f21.in'], "work1/sub21/f21.in\n")
test.write(['work1', 'sub22', 'f22.in'], "work1/sub22/f22.in\n")
test.write(['work1', 'sub23', 'f23.in'], "work1/sub23/f23.in\n")

test.run(chdir='work1', arguments='..')

test.must_match(['work1', 'f0.out'], "work1/f0.in\n")

test.must_match(['work1', 'sub1', 'f1.out'], "work1/sub1/f1.in\n")
test.must_match(['work1', 'sub2', 'f2.out'], "work1/sub2/f2.in\n")
test.must_match(['work1', 'sub3', 'f3.out'], "work1/sub3/f3.in\n")
test.must_match(['work1', 'sub4', 'f4.out'], "work1/sub4/f4.in\n")
test.must_match(['work1', 'sub5', 'f5.out'], "work1/sub5/f5.in\n")
test.must_match(['work1', 'sub6', 'f6.out'], "work1/sub6/f6.in\n")
test.must_match(['work1', 'sub7', 'f7.out'], "work1/sub7/f7.in\n")
test.must_match(['work1', 'sub8', 'f8.out'], "work1/sub8/f8.in\n")
test.must_match(['work1', 'sub9', 'f9.out'], "work1/sub9/f9.in\n")

test.must_match(['other1', 'f11.out'], "other1/f11.in\n")
test.must_match(['other2', 'f12.out'], "other2/f12.in\n")
test.must_match(['other3', 'f13.out'], "other3/f13.in\n")
test.must_match(['other4', 'f14.out'], "other4/f14.in\n")
test.must_match(['other5', 'f15.out'], "other5/f15.in\n")
test.must_match(['other6', 'f16.out'], "other6/f16.in\n")
test.must_match(['other7', 'f17.out'], "other7/f17.in\n")
test.must_match(['other8', 'f18.out'], "other8/f18.in\n")
test.must_match(['other9', 'f19.out'], "other9/f19.in\n")

test.must_match(['work1', 'f20.out'], "work1/f20.in\n")

test.must_match(['work1', 'sub21', 'f21.out'], "work1/sub21/f21.in\n")
test.must_match(['work1', 'sub22', 'f22.out'], "work1/sub22/f22.in\n")
test.must_match(['work1', 'sub23', 'f23.out'], "work1/sub23/f23.in\n")



test.subdir('work2',
            ['work2', 'sub'])

work2 = repr(test.workpath('work2'))
work2_sub_f1_out = test.workpath('work2', 'sub', 'f1.out')
work2_sub_f2_out = test.workpath('work2', 'sub', 'f2.out')

test.write(['work2', 'SConstruct'], """\
cat_command = r'%(_python_)s %(cat_py)s ${TARGET.file} ${SOURCE.file}'
env = Environment()
env.Command('sub/f1.out', 'sub/f1.in', cat_command,
            chdir=1)
env.Command('sub/f2.out', 'sub/f2.in',
            [
              r'%(_python_)s %(cat_py)s .temp ${SOURCE.file}',
              r'%(_python_)s %(cat_py)s ${TARGET.file} .temp',
            ],
            chdir=1)
""" % locals())

test.write(['work2', 'sub', 'f1.in'], "work2/sub/f1.in")
test.write(['work2', 'sub', 'f2.in'], "work2/sub/f2.in")

expect = test.wrap_stdout("""\
os.chdir('sub')
%(_python_)s %(cat_py)s f1.out f1.in
os.chdir(%(work2)s)
os.chdir('sub')
%(_python_)s %(cat_py)s .temp f2.in
os.chdir(%(work2)s)
os.chdir('sub')
%(_python_)s %(cat_py)s f2.out .temp
os.chdir(%(work2)s)
""" % locals())

test.run(chdir='work2', arguments='-n .', stdout=expect)

test.must_not_exist(work2_sub_f1_out)
test.must_not_exist(work2_sub_f2_out)

test.run(chdir='work2', arguments='.', stdout=expect)

test.must_match(work2_sub_f1_out, "work2/sub/f1.in")
test.must_match(work2_sub_f2_out, "work2/sub/f2.in")

test.run(chdir='work2', arguments='-c .')

test.must_not_exist(work2_sub_f1_out)
test.must_not_exist(work2_sub_f2_out)

test.run(chdir='work2', arguments='-s .', stdout="")

test.must_match(work2_sub_f1_out, "work2/sub/f1.in")
test.must_match(work2_sub_f2_out, "work2/sub/f2.in")

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/custom-concat.py

#!/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 _stripixes() can use a custom _concat() function through
the construction environment.
"""

import TestSCons

test = TestSCons.TestSCons()

test.write('SConstruct', """
def my_concat1(pref, list, suff, env, f=None):
    if f:
        list = f(list)
    list = ['my'+pref+x+suff+'1' for x in list]
    return list
myflags = '${_stripixes(MYPREFIX, LIST, MYSUFFIX, STRIPPREFIX, STRIPSUFFIX, __env__)}'
env1 = Environment(MYFLAGS=myflags, _concat = my_concat1,
                   MYPREFIX='p', MYSUFFIX='s',
                   STRIPPREFIX='xxx', STRIPSUFFIX='yyy',
                   LIST=['a', 'xxxb', 'cyyy', 'd'])
print(env1.subst('$MYFLAGS'))
""")

expect = test.wrap_stdout(read_str = "mypas1 mypbs1 mypcs1 mypds1\n",
                          build_str = "scons: `.' is up to date.\n")
test.run(arguments = '.', stdout = expect)

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/dependency-cycle.py

#!/usr/bin/env python
#
# __COPYRIGHT__
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#

__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"

import TestSCons
import TestCmd

test = TestSCons.TestSCons(match = TestCmd.match_re)

test.write('SConstruct', """
env = Environment()
foo1 = env.Library(target = 'foo1', source = 'f1.c')
foo2 = env.Library(target = 'foo2', source = 'f1.c')
foo3 = env.Library(target = 'foo3', source = 'f1.c')
env.Depends(foo1, foo2)
env.Depends(foo2, foo3)
env.Depends(foo3, foo1)
""")

test.write('f1.c', r"""
#include <stdio.h>
void
f1(void)
{
        printf("f1.c\n");
} 
""")

test.run(arguments = ".", stderr=r"""
scons: \*\*\* Found dependency cycle\(s\):
  .*foo(1|3|2).* -> .*foo(3|2|1).* -> .*foo(2|1|3).* -> .*foo(1|3|2).*
  .*foo(3|1|2).* -> .*foo(2|3|1).* -> .*foo(1|2|3).* -> .*foo(3|1|2).*

.*
""", status=2)

test.fail_test(test.stdout() == "")


test.pass_test()


# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/diskcheck.py

#!/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 the --diskcheck option and SetOption('diskcheck') correctly
control where or not we look for on-disk matches files and directories
that we look up.
"""

import TestSCons

test = TestSCons.TestSCons()

test.subdir('subdir')

test.write('file', "file\n")



test.write('SConstruct', """
SetOption('diskcheck', 'none')
File('subdir')
""")

test.run()

test.run(arguments='--diskcheck=match', status=2, stderr=None)
test.must_contain_all_lines(test.stderr(), ["found where file expected"])



test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/duplicate-sources.py

#!/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 specifying a source file more than once works correctly
and dos not cause a rebuild.
"""

import TestSCons

test = TestSCons.TestSCons()

test.write('SConstruct', """\
def cat(target, source, env):
    with open(str(target[0]), 'wb') as t:
        for s in source:
            with open(str(s), 'rb') as s:
                t.write(s.read())
env = Environment(BUILDERS = {'Cat' : Builder(action = cat)})
env.Cat('out.txt', ['f1.in', 'f2.in', 'f1.in'])
""")

test.write('f1.in', "f1.in\n")
test.write('f2.in', "f2.in\n")

test.run(arguments='--debug=explain .')

test.must_match('out.txt', "f1.in\nf2.in\nf1.in\n")

test.up_to_date(options='--debug=explain', arguments='.')

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/emitter.py

#!/usr/bin/env python
#
# __COPYRIGHT__
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#

__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"

import TestSCons

test = TestSCons.TestSCons()

test.subdir('src')

test.write('SConstruct',"""
VariantDir('var1', 'src', duplicate=0)
VariantDir('var2', 'src', duplicate=1)
SConscript('src/SConscript')
SConscript('var1/SConscript')
SConscript('var2/SConscript')
""")

test.write('src/SConscript',"""
def build(target, source, env):
    for t in target:
        with open(str(t), "wt") as f:
            f.write(str(t))

def emitter(target, source, env):
    target.append(str(target[0])+".foo")
    return target,source

def emit1(t, s, e): return (t + ['emit.1'], s)
def emit2(t, s, e): return (t + ['emit.2'], s)

foo = Builder(action=build, emitter=emitter)
bar = Builder(action=build, emitter='$EMITTERS')

env=Environment(BUILDERS={ 'foo': foo, 'bar': bar },
                EMITTERS=[emit1, emit2])
env.foo('f.out', 'f.in')
env.foo(File('g.out'), 'g.in')
env.bar('h.out', 'h.in')
""")

test.write(['src', 'f.in'], 'f.in')
test.write(['src', 'g.in'], 'g.in')
test.write(['src', 'h.in'], 'h.in')

# Do 'src' last so that creation of the emitter files in there doesn't
# interfere with searching for them in the VariantDirs.

test.run(arguments='var2')

test.must_exist(test.workpath('var2', 'f.out'))
test.must_exist(test.workpath('var2', 'f.out.foo'))
test.must_exist(test.workpath('var2', 'g.out'))
test.must_exist(test.workpath('var2', 'g.out.foo'))
test.must_exist(test.workpath('var2', 'h.out'))
test.must_exist(test.workpath('var2', 'emit.1'))
test.must_exist(test.workpath('var2', 'emit.2'))

test.run(arguments = 'var1')

test.must_exist(test.workpath('var1', 'f.out'))
test.must_exist(test.workpath('var1', 'f.out.foo'))
test.must_exist(test.workpath('var1', 'g.out'))
test.must_exist(test.workpath('var1', 'g.out.foo'))
test.must_exist(test.workpath('var1', 'h.out'))
test.must_exist(test.workpath('var1', 'emit.1'))
test.must_exist(test.workpath('var1', 'emit.2'))

test.run(arguments = 'src')

test.must_exist(test.workpath('src', 'f.out'))
test.must_exist(test.workpath('src', 'f.out.foo'))
test.must_exist(test.workpath('src', 'g.out'))
test.must_exist(test.workpath('src', 'g.out.foo'))
test.must_exist(test.workpath('src', 'h.out'))
test.must_exist(test.workpath('src', 'emit.1'))
test.must_exist(test.workpath('src', 'emit.2'))

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/exceptions.py

#!/usr/bin/env python
#
# __COPYRIGHT__
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#

__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"

import re

import TestSCons

_python_ = TestSCons._python_

test = TestSCons.TestSCons(match = TestSCons.match_re_dotall)

SConstruct_path = test.workpath('SConstruct')

test.write(SConstruct_path, """\
def func(source = None, target = None, env = None):
    raise Exception("func exception")
B = Builder(action = func)
env = Environment(BUILDERS = { 'B' : B })
env.B(target = 'foo.out', source = 'foo.in')
""")

test.write('foo.in', "foo.in\n")

expected_stderr = r"""scons: \*\*\* \[foo.out\] Exception : func exception
Traceback \((most recent call|innermost) last\):
(  File ".+", line \d+, in \S+
    [^\n]+
)*(  File ".+", line \d+, in \S+
)*(  File ".+", line \d+, in \S+
    [^\n]+
)*  File "%s", line 2, in func
    raise Exception\("func exception"\)
Exception: func exception
""" % re.escape(SConstruct_path)

test.run(arguments = "foo.out", stderr = expected_stderr, status = 2)

test.run(arguments = "-j2 foo.out", stderr = expected_stderr, status = 2)


# Verify that exceptions caused by exit values of builder actions are
# correctly signalled, for both Serial and Parallel jobs.

test.write('myfail.py', r"""\
import sys
sys.exit(1)
""")

test.write(SConstruct_path, """
Fail = Builder(action = r'%(_python_)s myfail.py $TARGETS $SOURCE')
env = Environment(BUILDERS = { 'Fail' : Fail })
env.Fail(target = 'out.f1', source = 'in.f1')
""" % locals())

test.write('in.f1', "in.f1\n")

expected_stderr = "scons: \\*\\*\\* \\[out.f1\\] Error 1\n"

test.run(arguments = '.', status = 2, stderr = expected_stderr)
test.run(arguments = '-j2 .', status = 2, stderr = expected_stderr)


# Verify that all exceptions from simultaneous tasks are reported,
# even if the exception is raised during the Task.prepare()
# [Node.prepare()]

test.write(SConstruct_path, """
Fail = Builder(action = r'%(_python_)s myfail.py $TARGETS $SOURCE')
env = Environment(BUILDERS = { 'Fail' : Fail })
env.Fail(target = 'out.f1', source = 'in.f1')
env.Fail(target = 'out.f2', source = 'in.f2')
env.Fail(target = 'out.f3', source = 'in.f3')
""" % locals())

# in.f2 is not created to cause a Task.prepare exception
test.write('in.f1', 'in.f1\n')
test.write('in.f3', 'in.f3\n')

# In Serial task mode, get the first exception and stop
test.run(arguments = '.', status = 2, stderr = expected_stderr)

# In Parallel task mode, we will get all three exceptions.

expected_stderr_list = [
    "scons: *** [out.f1] Error 1\n",
    "scons: *** [out.f2] Source `in.f2' not found, needed by target `out.f2'.\n",
    "scons: *** [out.f3] Error 1\n",
]

# To get all three exceptions simultaneously, we execute -j7 to create
# one thread each for the SConstruct file and {in,out}.f[123].  Note that
# it's important that the input (source) files sort earlier alphabetically
# than the output files, so they're visited first in the dependency graph
# walk of '.' and are already considered up-to-date when we kick off the
# "simultaneous" builds of the output (target) files.

test.run(arguments = '-j7 -k .', status = 2, stderr = None)

test.must_contain_all_lines(test.stderr(), expected_stderr_list)


test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/exitfns.py

#!/usr/bin/env python
#
# __COPYRIGHT__
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#

__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"

import TestSCons
test = TestSCons.TestSCons()

# also exclude these tests since it overides the exit function which doesnt work with coverage 
# # more info here: https://coverage.readthedocs.io/en/coverage-4.4.2/subprocess.html#
# TODO: figure out how to cover tests which use exit functions
if test.coverage_run():
    test.skip_test("This test replaces the exit function which is needed by coverage to write test data; skipping test.")

sconstruct = """
from SCons.exitfuncs import register

def x1():
    print("running x1")
def x2(n):
    print("running x2(%s)" % repr(n))
def x3(n, kwd=None):
    print("running x3(%s, kwd=%s)" % (repr(n), repr(kwd)))

register(x3, "no kwd args")
register(x1)
register(x2, 12)
register(x3, 5, kwd="bar")
register(x3, "no kwd args")

"""

expected_output = test.wrap_stdout("scons: `.' is up to date.\n") + \
"""running x3('no kwd args', kwd=None)
running x3(5, kwd='bar')
running x2(12)
running x1
running x3('no kwd args', kwd=None)
"""

test.write('SConstruct', sconstruct)

test.run(arguments='-f SConstruct .', stdout = expected_output)

test.write('SConstruct', """import sys
def f():
    pass

sys.exitfunc = f
""" + sconstruct)

test.run(arguments='-f SConstruct .', stdout = expected_output)

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/expansion.py

#!/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 construction variable expansion in Builder paths.
"""

import os.path

import TestSCons

_exe = TestSCons._exe
_obj = TestSCons._obj

test = TestSCons.TestSCons()

test.subdir('sub')

test.write('SConstruct', """\
env = Environment(SUBDIR = 'sub')
env.Program(target = 'foo1', source = env.Object(source = r'%s'))
env.Program(source = env.Object(target = r'%s', source = 'f2.c'))
env.Program('foo3', r'%s')
env.Program(r'%s')
""" % (os.path.join('$SUBDIR', 'f1.c'),
       os.path.join('$SUBDIR', 'foo2'),
       os.path.join('$SUBDIR', 'f3.c'),
       os.path.join('$SUBDIR', 'foo4.c')))

test.write(['sub', 'f1.c'], r"""
#include <stdio.h>
#include <stdlib.h>
int
main(int argc, char *argv[])
{
        argv[argc++] = "--";
        printf("sub/f1.c\n");
        exit (0);
}
""")

test.write('f2.c', r"""
#include <stdio.h>
#include <stdlib.h>
int
main(int argc, char *argv[])
{
        argv[argc++] = "--";
        printf("f2.c\n");
        exit (0);
}
""")

test.write(['sub', 'f3.c'], r"""
#include <stdio.h>
#include <stdlib.h>
int
main(int argc, char *argv[])
{
        argv[argc++] = "--";
        printf("sub/f3.c\n");
        exit (0);
}
""")

test.write(['sub', 'foo4.c'], r"""
#include <stdio.h>
#include <stdlib.h>
int
main(int argc, char *argv[])
{
        argv[argc++] = "--";
        printf("sub/foo4.c\n");
        exit (0);
}
""")

test.run(arguments = '.')

test.run(program = test.workpath('foo1' + _exe), stdout = "sub/f1.c\n")
test.run(program = test.workpath('sub', 'foo2' + _exe), stdout = "f2.c\n")
test.run(program = test.workpath('foo3' + _exe), stdout = "sub/f3.c\n")
test.run(program = test.workpath('sub','foo4' + _exe), stdout = "sub/foo4.c\n")

test.fail_test(not os.path.exists(test.workpath('sub', 'f1' + _obj)))
test.fail_test(not os.path.exists(test.workpath('sub', 'foo2' + _obj)))
test.fail_test(not os.path.exists(test.workpath('sub', 'f3' + _obj)))
test.fail_test(not os.path.exists(test.workpath('sub', 'foo4' + _obj)))

test.up_to_date(arguments = '.')

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/file-names.py

#!/usr/bin/env python
#
# __COPYRIGHT__
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#

__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"

import sys
import TestSCons

test = TestSCons.TestSCons()

# Right now, due to interaction with external quoting conventions,
# we do NOT actually support arbitrary characters in file names.
# (For example, double-quotes in a file name on POSIX break due
# to interaction with the "sh -c" quoting conventions.)
#
# This is a tough nut to crack, though.  Right now, we use the
# external command interpreters so we don't have to roll our own
# parsing and interpretation of redirection and piping.  But that
# means we have to find ways to work with *all* of their quoting
# conventions.

def contents(c):
    return "|" + c + "|\n"

invalid_chars = '/\0'

if sys.platform == 'win32':
    invalid_chars = set(invalid_chars)

    # See the 'naming conventions' section of
    # https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx
    invalid_chars.update([ chr(c) for c in range(32) ])
    invalid_chars.update(r'\/:*?"<>|')
    invalid_chars.update(chr(127))

    # Win32 filesystems are case insensitive so don't do half the alphabet.
    import string
    invalid_chars.update(string.ascii_lowercase)

    # See the 'naming conventions' section of
    # https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx
    def bad_char(c):
        return c in invalid_chars
    def invalid_leading_char(c):
        # the hash character as a leading character is interpreted to mean the project root
        return c in ' #'
    def invalid_trailing_char(c):
        return c in ' .'
    commandString = "copy $SOURCE $TARGET"
else:
    invalid_chars = set(invalid_chars)
    invalid_chars.add(chr(10))
    invalid_chars.add(chr(13))
    invalid_chars.add(chr(92)) # forward slash (dirsep)
    invalid_chars.add(chr(96)) # backtick

    
    def bad_char(c):
        return c in invalid_chars
    def invalid_leading_char(c):
        # the hash character as a leading character is interpreted to mean the project root
        return c in '#'
    def invalid_trailing_char(c):
        return False
    commandString = "cp $SOURCE $TARGET"

goodChars = [ chr(c) for c in range(1, 128) if not bad_char(chr(c)) ]

def get_filename(ftype,c):
    return ftype+"%d"%ord(c[-1])+c+ftype

for c in goodChars:
    test.write(get_filename("in",c), contents(c))

def create_command(a, b, c):
    a = ('', 'out')[a]
    b = ('', 'out')[b]
    return 'env.Command("' + a + get_filename('',c) + b + '", "'+get_filename("in",c)+ '","' + commandString + '")'

sconstruct = [ 'import sys', 'env = Environment(tools=[])' ]
for c in goodChars:
    if c == '$':
        c = '$$'
    if c == '"':
        c = r'\"'
    infile = get_filename("in",c)
    if not invalid_leading_char(c):
        sconstruct.append(create_command(False, True, c))
    sconstruct.append(create_command(True, True, c))
    if not invalid_trailing_char(c):
        sconstruct.append(create_command(True, False, c))
test.write('SConstruct', '\n'.join(sconstruct))

test.run(arguments = '.')

for c in goodChars:
#    print "Checking %d "%ord(c)

    c_str = ("%d"%ord(c[-1]))+c
    if not invalid_leading_char(c):
        test.must_match(c_str + "out", contents(c))
    test.must_match("out" + c_str + "out", contents(c))
    if not invalid_trailing_char(c):
        test.must_match("out" + c_str, contents(c))

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/gnutools.py

#!/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.

"""
Testing the gnu tool chain, i.e. the tools 'gcc', 'g++' and 'gnulink'.
"""

__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"

import TestSCons
import sys

_python_ = TestSCons._python_
_exe = TestSCons._exe

def dll(s):
    return TestSCons.dll_ + s + TestSCons._dll

test = TestSCons.TestSCons()

test.subdir('gnutools')

test.write(['gnutools','mygcc.py'], """
import getopt
import sys
try:
    cmd_opts, args = getopt.getopt(sys.argv[1:], 'f:s:co:', [])
except getopt.GetoptError:
    # we may be called with --version, just quit if so
    sys.exit(0)
out = None
opt_string = ''
for opt, arg in cmd_opts:
    if opt == '-o': out = arg
    else: opt_string = opt_string + ' ' + opt + arg
with open(out, 'w') as ofp:
    ofp.write('gcc ' + opt_string + '\\n')
    for a in args:
        with open(a, 'r') as ifp:
            ofp.write(ifp.read())
sys.exit(0)
""")

test.write(['gnutools','myg++.py'], """
import getopt
import sys
try:
    cmd_opts, args = getopt.getopt(sys.argv[1:], 'f:s:co:', [])
except getopt.GetoptError:
    # we may be called with --version, just quit if so
    sys.exit(0)
out = None
opt_string = ''
for opt, arg in cmd_opts:
    if opt == '-o': out = arg
    else: opt_string = opt_string + ' ' + opt + arg
with open(out, 'w') as ofp:
    ofp.write('g++ ' + opt_string + '\\n')
    for a in args:
        with open(a, 'r') as ifp:
            ofp.write(ifp.read())
sys.exit(0)
""")

test.subdir('work1')

test.write(['work1', 'cfile1.c'],"""
/* c file 1 */
""")

test.write(['work1', 'cfile2.c'],"""
/* c file 2 */
""")

test.write(['work1', 'cppfile1.cpp'],"""
/* cpp file 1 */
""")

test.write(['work1', 'cppfile2.cpp'],"""
/* cpp file 2 */
""")

mygcc_py = test.workpath('gnutools','mygcc.py')
mygxx_py = test.workpath('gnutools','myg++.py')

test.write(['work1', 'SConstruct'],"""
env = Environment(tools=['gcc','g++','gnulink'],
                  CC=r'%(_python_)s %(mygcc_py)s',
                  CXX=r'%(_python_)s %(mygxx_py)s',
                  OBJSUFFIX='.o',
                  SHOBJSUFFIX='.os')
env.Program('c-only', Split('cfile1.c cfile2.c'))
env.Program('cpp-only', Split('cppfile1.cpp cppfile2.cpp'))
env.Program('c-and-cpp', Split('cfile1.c cppfile1.cpp'))

env.SharedLibrary('c-only', Split('cfile1.c cfile2.c'))
env.SharedLibrary('cpp-only', Split('cppfile1.cpp cppfile2.cpp'))
env.SharedLibrary('c-and-cpp', Split('cfile1.c cppfile1.cpp'))
""" % locals())

test.run(chdir='work1')

def testObject(test, obj, expect):
    contents = test.read(test.workpath('work1', obj))
    line1 = contents.split(b'\n')[0]
    actual = b' '.join(line1.split())
    if not expect == actual:
        print("%s:  %s != %s\n" % (obj, repr(expect), repr(actual)))
        test.fail_test()

if sys.platform in ('win32', 'cygwin'):
    c_fpic = b''
else:
    c_fpic = b' -fPIC'

testObject(test, 'cfile1.o',            b'gcc -c')
testObject(test, 'cfile2.o',            b'gcc -c')
testObject(test, 'cppfile1.o',          b'g++ -c')
testObject(test, 'cppfile2.o',          b'g++ -c')
testObject(test, 'cfile1.os',           b'gcc -c' + c_fpic)
testObject(test, 'cfile2.os',           b'gcc -c' + c_fpic)
testObject(test, 'cppfile1.os',         b'g++ -c' + c_fpic)
testObject(test, 'cppfile2.os',         b'g++ -c' + c_fpic)
testObject(test, 'c-only' + _exe,       b'gcc')
testObject(test, 'cpp-only' + _exe,     b'g++')
testObject(test, 'c-and-cpp' + _exe,    b'g++')
testObject(test, dll('c-only'),         b'gcc -shared')
testObject(test, dll('cpp-only'),       b'g++ -shared')
testObject(test, dll('c-and-cpp'),      b'g++ -shared')

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/ignore-command.py

#!/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.
#

"""
Test use of a preceding - to ignore the return value from a command.
"""

__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"


import TestSCons

_python_ = TestSCons._python_

test = TestSCons.TestSCons()

test.subdir('build', 'src')

test.write('build.py', r"""
import sys
with open(sys.argv[1], 'wb') as fp:
    for f in sys.argv[2:]:
        with open(f, 'rb') as ifp:
            fp.write(ifp.read())
sys.exit(1)
""")

test.write('SConstruct', """\
env = Environment()
f1 = env.Command('f1.out', 'f1.in', r'%(_python_)s build.py $TARGET $SOURCE')
f2 = env.Command('f2.out', 'f2.in', r'-%(_python_)s build.py $TARGET $SOURCE')
f3 = env.Command('f3.out', 'f3.in', r'- %(_python_)s build.py $TARGET $SOURCE')
f4 = env.Command('f4.out', 'f4.in', r'@-%(_python_)s build.py $TARGET $SOURCE')
f5 = env.Command('f5.out', 'f5.in', r'@- %(_python_)s build.py $TARGET $SOURCE')
f6 = env.Command('f6.out', 'f6.in', r'-@%(_python_)s build.py $TARGET $SOURCE')
f7 = env.Command('f7.out', 'f7.in', r'-@ %(_python_)s build.py $TARGET $SOURCE')
Default(f2, f3, f4, f5, f6, f7)
""" % locals())

test.write('f1.in', "f1.in\n")
test.write('f2.in', "f2.in\n")
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.write('f7.in', "f7.in\n")

test.run()

test.must_match('f2.out', "f2.in\n")
test.must_match('f3.out', "f3.in\n")
test.must_match('f4.out', "f4.in\n")
test.must_match('f5.out', "f5.in\n")
test.must_match('f6.out', "f6.in\n")
test.must_match('f7.out', "f7.in\n")

test.run(arguments='.', status=2, stderr=None)

test.must_match('f1.out', "f1.in\n")

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/import.py

#!/usr/bin/env python
#
# 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 we can import and use the contents of Platform and Tool
modules directly.
"""

import os
import re

# must do this here, since TestSCons will chdir
tooldir = os.path.join(os.getcwd(), 'SCons', 'Tool')

import TestSCons
test = TestSCons.TestSCons()

# Before executing any of the platform or tool modules, add some
# null entries to the environment $PATH variable to make sure there's
# no code that tries to index elements from the list before making sure
# they're non-null.
# (This was a problem in checkpoint release 0.97.d020070809.)
os.environ['PATH'] = os.pathsep + os.environ['PATH'] + \
                     os.pathsep + os.pathsep + '/no/such/dir' + os.pathsep

SConstruct_path = test.workpath('SConstruct')

platforms = [
    'aix',
    'cygwin',
    'darwin',
    'hpux',
    'irix',
    'os2',
    'posix',
    'sunos',
    'win32'
]

for platform in platforms:
    test.write('SConstruct', """
DefaultEnvironment(tools=[])
print("Platform %(platform)s")
env = Environment(platform = '%(platform)s', tools=[])
import SCons.Platform.%(platform)s
x = SCons.Platform.%(platform)s.generate
""" % locals())
    test.run()

ignore = ('__init__.py',
        # Can't import these everywhere due to Windows registry dependency.
        '386asm.py', 'linkloc.py',
        # Directory of common stuff for MSVC and MSVS
        'MSCommon',
        # clang common
        "clangCommon",
        # link common logic
        "linkCommon",
        # Sun pkgchk and pkginfo common stuff
        'sun_pkg.py',
        # RPM utilities
        'rpmutils.py',
        )
tools = []
for name in os.listdir(tooldir):
    if name in ignore: continue
    if name[0] == '#': continue
    if name[0:1] == '.': continue
    if name[-1]  == '~' : continue
    if name[-3:] == '.py':
        if name[-8:] not in ('Tests.py', 'ommon.py'):
            tools.append(name[:-3])
    elif os.path.exists(os.path.join(tooldir,name,'__init__.py')):
        tools.append(name)
tools.sort()    # why not?

#if sys.platform == 'win32':
# Just comment out (for now?) due to registry dependency.
#    tools.extend([
#        '386asm',
#        'linkloc',
#    ])

# Intel no compiler warning..
intel_no_compiler_warning = """
scons: warning: Failed to find Intel compiler for version='None', abi='[^']*'
""" + TestSCons.file_expr

# Intel no top dir warning.
intel_no_top_dir_warning = """
scons: warning: Can't find Intel compiler top dir for version='None', abi='[^']*'
""" + TestSCons.file_expr

# Intel no license directory warning
intel_license_warning = re.escape(
r"""scons: warning: Intel license dir was not found.  Tried using the INTEL_LICENSE_FILE environment variable (), the registry () and the default path (C:\Program Files\Common Files\Intel\Licenses).  Using the default path as a last resort.
""") + TestSCons.file_expr

intel_warnings = [
    re.compile(intel_license_warning),
    re.compile(intel_no_compiler_warning),
    re.compile(intel_no_compiler_warning + intel_license_warning),
    re.compile(intel_no_top_dir_warning),
    re.compile(intel_no_top_dir_warning + intel_license_warning),
]

moc = test.where_is('moc')
if moc:
    import os.path

    qtdir = os.path.dirname(os.path.dirname(moc))

    qt_err = r"""
scons: warning: Could not detect qt, using moc executable as a hint \(QTDIR=%(qtdir)s\)
""" % locals()

else:

    qt_err = """
scons: warning: Could not detect qt, using empty QTDIR
"""

qt_warnings = [ re.compile(qt_err + TestSCons.file_expr) ]

error_output = {
    'icl' : intel_warnings,
    'intelc' : intel_warnings,
    'qt' : qt_warnings,
}

# An SConstruct for importing Tool names that have illegal characters
# for Python variable names.
indirect_import = """\
DefaultEnvironment(tools=[])
print("Tool %(tool)s (indirect)")
env = Environment(tools = ['%(tool)s'])

SCons = __import__('SCons.Tool.%(tool)s', globals(), locals(), [])
m = getattr(SCons.Tool, '%(tool)s')
env = Environment(tools=[])
m.generate(env)
"""

# An SConstruct for importing Tool names "normally."
direct_import = """\
DefaultEnvironment(tools=[])
print("Tool %(tool)s (direct)")
env = Environment(tools = ['%(tool)s'])

import SCons.Tool.%(tool)s
env = Environment(tools=[])
SCons.Tool.%(tool)s.exists(env)
SCons.Tool.%(tool)s.generate(env)
"""

failures = []
for tool in tools:
    if tool[0] in '0123456789' or '+' in tool or tool in ('as',):
        test.write('SConstruct', indirect_import % locals())
    else:
        test.write('SConstruct', direct_import % locals())
    test.run(stderr=None)
    stderr = test.stderr()
    if stderr:
        matched = None
        for expression in error_output.get(tool, []):
            if expression.match(stderr):
                matched = 1
                break
        if not matched:
            print("Failed importing '%s', stderr:" % tool)
            print(stderr)
            failures.append(tool)

test.fail_test(len(failures))

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/issue2821.py

#!/usr/bin/env python
#
# __COPYRIGHT__
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#

__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"

import TestSCons

test = TestSCons.TestSCons()

test.write('SConstruct', """
test = Environment()
def blub():
    pass

test.Library.__call__ = blub
test.Clone()
assert test.Library.__call__ == blub
""")

test.run()

test.pass_test()
 

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/leaky-handles.py

#!/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 file handles aren't leaked to child processes
"""

import sys

import TestSCons

test = TestSCons.TestSCons()

if sys.platform != 'linux':
    msg = "Skipping fork leak test on non-linux platforms\n"
    test.skip_test(msg)

test.write('SConstruct', """

# Leave a file handle open when invoking a command
with open('/dev/null'):
    # Check it gets closed when an external command is forked off:
    test2 = Command('test2', [], '@ls /proc/$$$$/fd|wc -l')
""")

# In theory that should have 3 lines (handles 0/1/2). This is v. unix specific

test.run(arguments = '-Q', stdout='3\n')

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/multiline.py

#!/usr/bin/env python
#
# __COPYRIGHT__
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#

__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"


import TestSCons

python = TestSCons.python
_python_ = TestSCons._python_

test = TestSCons.TestSCons()

test.write('build.py', r"""
import sys
with open(sys.argv[1], 'wb') as f, open(sys.argv[2], 'rb') as ifp:
    f.write(ifp.read())
sys.exit(0)
""")

test.write('SConstruct', """
B1 = Builder(action = [ [ r'%(python)s', 'build.py', '.temp', '$SOURCES' ],
                        [ r'%(python)s', 'build.py', '$TARGETS', '.temp'] ])
B2 = Builder(action = r'%(_python_)s' + ' build.py .temp $SOURCES\\n' + r'%(_python_)s' + " build.py $TARGETS .temp")
env = Environment(BUILDERS = { 'B1' : B1, 'B2' : B2 })
env.B1(target = 'foo1.out', source = 'foo1.in')
env.B2(target = 'foo2.out', source = 'foo2.in')
env.B1(target = 'foo3.out', source = 'foo3.in')
""" % locals())

test.write('foo1.in', "foo1.in\n")

test.write('foo2.in', "foo2.in\n")

test.write('foo3.in', "foo3.in\n")

test.run(arguments = 'foo1.out foo2.out foo3.out')

test.fail_test(test.read(test.workpath('foo1.out')) != b"foo1.in\n")
test.fail_test(test.read(test.workpath('foo2.out')) != b"foo2.in\n")
test.fail_test(test.read(test.workpath('foo3.out')) != b"foo3.in\n")

test.pass_test()
 

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/no-arguments.py

#!/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 use a default target of the current directory when there
is no Default() in the SConstruct file and there are no command-line
arguments, or a null command-line argument.
"""


import TestSCons

test = TestSCons.TestSCons()

test.write('SConstruct', r"""
def cat(env, source, target):
    target = str(target[0])
    source = list(map(str, source))
    print('cat(%s) > %s' % (source, target))
    with open(target, "wb") as f:
        for src in source:
            with open(src, "rb") as ifp:
                f.write(ifp.read())

env = Environment(BUILDERS={'Build':Builder(action=cat)})
env.Build('aaa.out', 'aaa.in')
""")

test.write('aaa.in', "aaa.in\n")

up_to_date = test.wrap_stdout("scons: `.' is up to date.\n")

#
test.run()
test.must_match('aaa.out', "aaa.in\n")
test.run(stdout=up_to_date)

#
test.unlink('aaa.out')
test.must_not_exist('aaa.out')

#
test.run([''])
test.must_match('aaa.out', "aaa.in\n")
test.run([''], stdout=up_to_date)

#
test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/no-global-dependencies.py

#!/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 variant 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 TestSCons

test = TestSCons.TestSCons()

test.subdir('dir1')
test.subdir('dir2')

test.write('SConstruct', """\
opts = Variables()
opts.AddVariables(
    BoolVariable('view_all_dependencies', 'View all dependencies', True),
    BoolVariable('duplicate', 'Duplicate sources to variant dir', True)
)

env = Environment(options=opts)
Export('env')

SConscript(dirs='.', variant_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.must_not_contain_any_line(test.stdout(), ["`.' is up to date."])

# Double check that targets are not rebuilt.
test.run(arguments = 'duplicate=False view_all_dependencies=True .')
test.must_exist('build/dir1/x.cpp')
test.must_contain_all_lines(test.stdout(), ["`.' is up to date."])

# 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.must_not_contain_any_line(test.stdout(), ["`.' is up to date."])

# 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.must_contain_all_lines(test.stdout(), ["`.' is up to date."])

test.run(arguments = 'duplicate=False view_all_dependencies=True .')
test.must_exist('build/dir1/x.cpp')
test.must_contain_all_lines(test.stdout(), ["`.' is up to date."])

# 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.must_not_contain_any_line(test.stdout(), ["`.' is up to date."])

# # Double check that targets are not rebuilt.
# test.run(arguments = 'duplicate=True view_all_dependencies=True .')
# test.must_exist('build/dir1/x.cpp')
# test.must_contain_all_lines(test.stdout(), ["`.' is up to date."])

# # 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.must_not_contain_any_line(test.stdout(), ["`.' is up to date."])

# # 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.must_contain_all_lines(test.stdout(), ["`.' is up to date."])

# test.run(arguments = 'duplicate=True view_all_dependencies=True .')
# test.must_exist('build/dir1/x.cpp')
# test.must_contain_all_lines(test.stdout(), ["`.' is up to date."])

# # Clean-up everything.
# test.run(arguments = 'duplicate=True view_all_dependencies=True -c .')
# test.must_not_exist('build/dir1/x.cpp')


test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/no-target.py

#!/usr/bin/env python
#
# __COPYRIGHT__
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#

__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"

import os.path

import TestSCons

test = TestSCons.TestSCons()

test.subdir('subdir', ['subdir', 'ccc'])

ccc_ccc_in = os.path.join('ccc', 'ccc.in')
subdir_SConscript = os.path.join('subdir', 'SConscript')

test.write('SConstruct', r"""
SConscript(r'%s')
""" % subdir_SConscript)

test.write(subdir_SConscript, r"""
def cat(env, source, target):
    target = str(target[0])
    with open(target, "wb") as f:
        for src in source:
            with open(str(src), "rb") as ifp:
                f.write(ifp.read())

b = Builder(action=cat, suffix='.out', src_suffix='.in')
env = Environment(BUILDERS={'Build':b})
env.Build('aaa.in')
n = env.Build('bbb.in', 'bbb.input')
env.Build(n)
env.Build(source = r'%s')
""" % ccc_ccc_in)

test.write(['subdir', 'aaa.in'], "subdir/aaa.in\n")
test.write(['subdir', 'bbb.input'], "subdir/bbb.input\n")
test.write(['subdir', 'ccc', 'ccc.in'], "subdir/ccc/ccc.in\n")

#
test.run(arguments = '.')

test.fail_test(test.read(['subdir', 'aaa.out']) != b"subdir/aaa.in\n")
test.fail_test(test.read(['subdir', 'bbb.out']) != b"subdir/bbb.input\n")
test.fail_test(test.read(['subdir', 'ccc', 'ccc.out']) != b"subdir/ccc/ccc.in\n")

#
test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/nonexistent.py

#!/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.
#

"""
This test verifies that we fail gracefully and provide informative
messages if someone tries to build a target that hasn't been defined
or uses a nonexistent source file.
"""

__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"

import os.path
import re

import TestSCons

test = TestSCons.TestSCons()

foo_bar = os.path.join('foo', 'bar')

test.write('SConstruct', """
env = Environment()
env.Command("aaa.out", "aaa.in", "should never get executed")
env.Command("bbb.out", "bbb.in", "should never get executed")
File('xxx')
Dir('ddd')
""")

test.run(arguments = 'foo',
         stderr = "scons: \\*\\*\\* Do not know how to make File target `foo' \\(.*foo\\).( *Stop.)?\n",
         status = 2,
         match=TestSCons.match_re_dotall)

test.run(arguments = '-k foo/bar foo',
         stderr = "scons: \\*\\*\\* Do not know how to make File target `%s' \\(.*foo.bar\\).\n" % re.escape(foo_bar),
         status = 2,
         match=TestSCons.match_re_dotall)

test.run(arguments = "aaa.out",
         stderr = "scons: *** [aaa.out] Source `aaa.in' not found, needed by target `aaa.out'.\n",
         status = 2)

test.run(arguments = "-k bbb.out aaa.out",
         stderr = """scons: *** [bbb.out] Source `bbb.in' not found, needed by target `bbb.out'.
scons: *** [aaa.out] Source `aaa.in' not found, needed by target `aaa.out'.
""",
         status = 2)

test.run(arguments = '-k aaa.in bbb.in',
         stderr = """scons: \\*\\*\\* Do not know how to make File target `aaa.in' \\(.*aaa.in\\).
scons: \\*\\*\\* Do not know how to make File target `bbb.in' \\(.*bbb.in\\).
""",
         status = 2,
         match=TestSCons.match_re_dotall)


test.run(arguments = 'xxx',
         stderr = "scons: \\*\\*\\* Do not know how to make File target `xxx' \\(.*xxx\\).( *Stop.)?\n",
         status = 2,
         match=TestSCons.match_re_dotall)

test.run(arguments = 'ddd')


# Make sure that SCons doesn't print up-to-date messages for non-derived files that exist:
test.write('SConstruct', """
File('xxx')
""")

test.write('xxx', "xxx")

test.run(arguments='xxx', stdout=test.wrap_stdout("""\
scons: Nothing to be done for `xxx'.
"""))
         
test.run(arguments='xxx', stdout=test.wrap_stdout("""\
scons: Nothing to be done for `xxx'.
"""))

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/overrides.py

#!/usr/bin/env python
#
# __COPYRIGHT__
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#

__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"

import TestSCons


test = TestSCons.TestSCons()


_python_ = TestSCons._python_

test.write('SConstruct', """
env = Environment(CCFLAGS='-DFOO', LIBS=['a'])
def build(target, source, env):
    print("env['CC'] = "+env['CC'])
    print("env['CCFLAGS'] = "+env['CCFLAGS'])
    print("env['LIBS'] = "+str(env['LIBS']))
builder = Builder(action=build, CC='buildcc', LIBS='buildlibs')
env['BUILDERS']['Build'] = builder

foo = env.Build('foo.out', 'foo.in',
                CC='mycc',
                CCFLAGS='$CCFLAGS -DBAR',
                LIBS = env['LIBS']+['b'])
bar = env.Build('bar.out', 'bar.in')
Default([foo, bar])
""")

test.write('foo.in', "foo.in\n")
test.write('bar.in', "bar.in\n")

test.run(arguments = "-Q", stdout = """\
build(["foo.out"], ["foo.in"])
env['CC'] = mycc
env['CCFLAGS'] = -DFOO -DBAR
env['LIBS'] = ['a', 'b']
build(["bar.out"], ["bar.in"])
env['CC'] = buildcc
env['CCFLAGS'] = -DFOO
env['LIBS'] = buildlibs
""")



test.write('SConstruct', """
env = Environment()
env.Program('hello', 'hello.c',
            CC=r'%(_python_)s mycc.py',
            LINK=r'%(_python_)s mylink.py',
            OBJSUFFIX='.not_obj',
            PROGSUFFIX='.not_exe')
""" % locals())

test.write('hello.c',"this ain't no c file!\n")

test.write('mycc.py',"""
with open('hello.not_obj', 'w') as f:
    f.write('this is no object file!')
""")

test.write('mylink.py',"""
with open('hello.not_exe', 'w') as f:
    f.write('this is not a program!')
""")

test.run(arguments='hello.not_exe')

assert test.read('hello.not_obj', mode='r') == 'this is no object file!'
assert test.read('hello.not_exe', mode='r') == 'this is not a program!'

test.up_to_date(arguments='hello.not_exe')



test.write('SConstruct', """\
env = Environment()
env.Program('goodbye', 'goodbye.c',
            CC=r'%(_python_)s mycc.py',
            LINK=r'%(_python_)s mylink.py',
            OBJSUFFIX='.not_obj',
            PROGSUFFIX='.not_exe',
            targets='ttt',
            sources='sss')
""" % locals())

test.write('goodbye.c',"this ain't no c file!\n")

test.write('mycc.py',"""
with open('goodbye.not_obj', 'wt') as f:
    f.write('this is no object file!')
""")

test.write('mylink.py',"""
with open('goodbye.not_exe', 'wt') as f:
    f.write('this is not a program!')
""")

test.run(arguments='goodbye.not_exe', stderr=None)
test.fail_test(not test.match_re(test.stderr(), r"""
scons: warning: Did you mean to use `(target|source)' instead of `(targets|sources)'\?
""" + TestSCons.file_expr + r"""
scons: warning: Did you mean to use `(target|source)' instead of `(targets|sources)'\?
""" + TestSCons.file_expr))

assert test.read('goodbye.not_obj', mode='r') == 'this is no object file!'
assert test.read('goodbye.not_exe', mode='r') == 'this is not a program!'



test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/path-change.py

#!/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__"

"""
Make sure that changing the location - but not the name - of a
source file triggers a rebuild (issue #2311).
"""

import TestSCons

test = TestSCons.TestSCons()

test.subdir('src1')
test.subdir('src2')

test.write('SConstruct', """

vars = Variables()
vars.AddVariables(
      PathVariable('SRCDIR', 'name the subdir to take the sources from', 'src1'))
env = Environment(variables = vars)
Export('env')

env.Object(target='hello.o', source=['$SRCDIR/hello.c'])
env.Program(target = 'hello', source = ['hello.o'])
""")

hello_text=r"""

#include <stdio.h>
#include <stdlib.h>
int
main()
{
        printf("%s\n");
        exit (0);
}

"""

test.write('src1/hello.c', hello_text % 'src1/hello')
test.write('src2/hello.c', hello_text % 'src2/hello')

test.not_up_to_date(options='SRCDIR=src1')
test.up_to_date(options='SRCDIR=src1')
test.not_up_to_date(options='SRCDIR=src2')

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/preserve-source.py

#!/usr/bin/env python
#
# __COPYRIGHT__
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#

__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"

import os.path

import TestSCons

test = TestSCons.TestSCons()

#
test.write('SConstruct', r"""
def cat(env, source, target):
    target = str(target[0])
    source = list(map(str, source))
    print('cat(%s) > %s' % (source, target))
    with open(target, "wb") as f:
        for src in source:
            with open(src, "rb") as ifp:
                f.write(ifp.read())

env = Environment(BUILDERS={'Build':Builder(action=cat)})
env.Build('aaa.out', 'aaa.in')
""")

test.write('aaa.in', "aaa.in\n")

#
test.run(arguments = '.')

test.fail_test(test.read('aaa.out') != b"aaa.in\n")

#
test.run(arguments = "aaa.in",
         stdout = test.wrap_stdout("scons: Nothing to be done for `aaa.in'.\n"))

test.fail_test(not os.path.exists('aaa.in'))

#
test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/print_statement.py

#!/usr/bin/env python
#
# __COPYRIGHT__
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#

__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"

import sys
import TestSCons

test = TestSCons.TestSCons()


test.write('SConstruct', """\
print('python 3 style statement')
Exit(0)
""")

test.run()

test.write('SConstruct', """\
print 'python 2 style statement'
Exit(0)
""")

if sys.version_info >= (3,0):
    test.skip_test('Python 2 print statement test, skipping on Python 3.\n')
else:
    test.run()

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/python-version.py

#!/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 behavior of our check for unsupported or deprecated versions
of Python.
"""

import re

import TestCmd
import TestSCons

test = TestSCons.TestSCons(match = TestCmd.match_re_dotall,ignore_python_version=0)

test.write('SConstruct', "\n")

test.write('SetOption-deprecated', "SetOption('warn', 'no-deprecated')\n")

test.write('SetOption-python', "SetOption('warn', ['no-python-version'])\n")

if TestSCons.unsupported_python_version():

    error = r"scons: \*\*\* SCons version \S+ does not run under Python version %s."
    error = error % re.escape(TestSCons.python_version_string()) + "\n"
    test.run(arguments = '-Q', status = 1, stderr = error)

else:

    if TestSCons.deprecated_python_version():

        test.run(arguments = '-Q', stderr = TestSCons.deprecated_python_expr)

    else:

        test.run(arguments = '-Q')

    test.run(arguments = '-Q --warn=no-deprecated')

    test.run(arguments = '-f SetOption-deprecated -Q')

    test.run(arguments = '-f SetOption-python -Q')

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/rebuild-generated.py

#!/usr/bin/env python
#
# MIT License
#
# Copyright The SCons Foundation
#
# 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.

"""
Test case for the bug report:
"[ 1088979 ] Unnecessary rebuild with generated header file"
(<http://sourceforge.net/tracker/index.php?func=detail&aid=1088979&group_id=30337&atid=398971>).

Unnecessary rebuild with generated header file
Scons rebuilds some nodes when invoked twice. The
trigger seems to be a generated C++ source file that
includes a header file that also is generated.

A tarball with a minimal test case is attached.
Transcript for reproducing:

cd /tmp
tar xzf scons_rebuild_debug.tar.gz
cd scons_rebuild_debug
scons target.o
scons target.o


Note that the bug is not triggered when scons is run
without arguments.

This may be a duplicate to bug 1019683.
"""

import os
import sys
import sysconfig

import TestSCons

test = TestSCons.TestSCons()

_obj = TestSCons._obj

if sys.platform == 'win32' and not sysconfig.get_platform() in ("mingw",):

    generator_name = 'generator.bat'
    test.write(generator_name, '@echo #include "header.hh"')
    kernel_action = "$SOURCES  > $TARGET"
else:
    generator_name = 'generator.sh'
    test.write(generator_name, 'echo \'#include "header.hh"\'')
    kernel_action = "sh $SOURCES  > $TARGET"

if sysconfig.get_platform() in ("mingw",):
    # mingw Python uses a sep of '/', when Command fires, that will not work.
    # use its altsep instead, that is the standard Windows separator.
    sep = os.altsep
else:
    sep = os.sep


test.write('SConstruct', """\
env = Environment()

kernelDefines = env.Command("header.hh", "header.hh.in", Copy('$TARGET', '$SOURCE'))
kernelImporterSource = env.Command("generated.cc", ["%s"], "%s")
kernelImporter = env.Program(kernelImporterSource + ["main.cc"])
kernelImports = env.Command("KernelImport.hh", kernelImporter, ".%s$SOURCE > $TARGET")
osLinuxModule = env.StaticObject(["target.cc"])
""" % (generator_name, kernel_action, sep))

test.write('main.cc', """\
int
main(int, char *[])
{
    return (0);
}
""")

test.write('target.cc', """\
#if 0

#include "KernelImport.hh"

#endif
""")

test.write("header.hh.in", "#define HEADER_HH 1\n")

test.run(arguments = 'target' + _obj)

expected_stdout = """\
scons: Reading SConscript files ...
scons: done reading SConscript files.
scons: Building targets ...
scons: `target%(_obj)s' is up to date.
scons: done building targets.
""" % locals()

test.run(arguments = 'target' + _obj, stdout=expected_stdout)

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/redirection.py

#!/usr/bin/env python
#
# __COPYRIGHT__
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#

__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"

import TestSCons

_python_ = TestSCons._python_

test = TestSCons.TestSCons()

test.write('cat.py', r"""
import sys

# write binary to stdout
if sys.platform == "win32":
    import os, msvcrt
    msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY)
    msvcrt.setmode(sys.stdin.fileno(), os.O_BINARY)

try:
    with open(sys.argv[1], 'rb') as f:
        indata = f.read()
except IndexError:
    indata = sys.stdin.buffer.read()
    
sys.stdout.buffer.write(indata)
sys.exit(0)
""")

test.write('SConstruct', r"""
env = Environment()
env.Command(target='foo1', source='bar1',
            action= r'%(_python_)s cat.py $SOURCES > $TARGET')
env.Command(target='foo2', source='bar2',
            action= r'%(_python_)s cat.py < $SOURCES > $TARGET')
env.Command(target='foo3', source='bar3',
            action=r'%(_python_)s cat.py $SOURCES | %(_python_)s cat.py > $TARGET')
env.Command(target='foo4', source='bar4',
            action=r'%(_python_)s cat.py <$SOURCES |%(_python_)s cat.py >$TARGET')
""" % locals())

test.write('bar1', 'bar1\r\n')
test.write('bar2', 'bar2\r\n')
test.write('bar3', 'bar3\r\n')
test.write('bar4', 'bar4\r\n')

test.run(arguments='.')

test.must_match('foo1', 'bar1\r\n')
test.must_match('foo2', 'bar2\r\n')
test.must_match('foo3', 'bar3\r\n')
test.must_match('foo4', 'bar4\r\n')

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/same-name.py

#!/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__"

"""
Make sure that we can build from a source file with the same basename as
the subdirectory in which it lives.
"""

import TestSCons

test = TestSCons.TestSCons()

test.subdir('bu')

test.write('SConstruct', """
env = Environment(CPPPATH = ['.'])
env.Program(source = ['foo.c', 'bu/bu.c'])
""")

test.write('foo.c', r"""
#include <stdio.h>
#include <stdlib.h>
#include <bu/bu.h>
int
main(int argc, char *argv[])
{
        argv[argc++] = "--";
        bu();
        printf("foo.c\n");
        exit (0);
}
""")

test.write(['bu', 'bu.h'], r"""
void bu(void);
""")

test.write(['bu', 'bu.c'], r"""
#include <stdio.h>
void
bu(void)
{
        printf("bu/bu.c\n");
}
""")

test.run(arguments = '.')

test.run(program = test.workpath("foo"), stdout ="""\
bu/bu.c
foo.c
""")

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/signature-order.py

#!/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 do rebuild things when the contents of
two .h files are swapped, changing the order in which
dependency signatures show up in the calculated list,
but 

"""

import TestSCons

_exe = TestSCons._exe

test = TestSCons.TestSCons()

test.subdir('work1', 'work2')

work1_foo = test.workpath('work1', 'foo' + _exe)
work2_foo = test.workpath('work2', 'foo' + _exe)

content1 = """\
#ifndef STRING
#define STRING  "content1"
#endif
"""

content2 = """\
#ifndef STRING
#define STRING  "content2"
#endif
"""



test.write(['work1', 'SConstruct'], """\
env = Environment(CPPPATH = ['.'])
env.Program(target = 'foo', source = 'foo.c')
""")

test.write(['work1', 'foo.c'], r"""
#include <stdio.h>
#include <stdlib.h>
#include <aaa.h>
#include <bbb.h>
int
main(int argc, char *argv[])
{
        argv[argc++] = "--";
        printf("%s\n", STRING);
        exit (0);
}
""")

test.write(['work1', 'aaa.h'], content1)
test.write(['work1', 'bbb.h'], content2)

test.run(chdir = 'work1')

test.run(program = work1_foo, stdout = "content1\n")

test.write(['work1', 'aaa.h'], content2)
test.write(['work1', 'bbb.h'], content1)

test.run(chdir = 'work1')

test.run(program = work1_foo, stdout = "content2\n")



test.write(['work2', 'SConstruct'], """\
env = Environment(CPPPATH = ['.'])
env.Program(target = 'foo', source = 'foo.c')
""")

test.write(['work2', 'foo.c'], r"""
#include <stdio.h>
#include <stdlib.h>
#include "aaa.h"
#include "bbb.h"
int
main(int argc, char *argv[])
{
        argv[argc++] = "--";
        printf("%s\n", STRING);
        exit (0);
}
""")

test.write(['work2', 'aaa.h'], content1)
test.write(['work2', 'bbb.h'], content2)

test.run(chdir = 'work2')

test.run(program = work2_foo, stdout = "content1\n")

test.write(['work2', 'aaa.h'], content2)
test.write(['work2', 'bbb.h'], content1)

test.run(chdir = 'work2')

test.run(program = work2_foo, stdout = "content2\n")



test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/silent-command.py

#!/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.
#

"""
Test the use of a preceding @ to suppress printing a command.
"""

__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"


import TestSCons

_python_ = TestSCons._python_

test = TestSCons.TestSCons()

test.subdir('build', 'src')

test.write('build.py', r"""
import sys
with open(sys.argv[1], 'wb') as fp:
    for f in sys.argv[2:]:
        with open(f, 'rb') as ifp:
            fp.write(ifp.read())
""")

test.write('SConstruct', """\
env = Environment()
env.Command('f1.out', 'f1.in', r'%(_python_)s build.py $TARGET $SOURCE')
env.Command('f2.out', 'f2.in', r'@%(_python_)s build.py $TARGET $SOURCE')
env.Command('f3.out', 'f3.in', r'@ %(_python_)s build.py $TARGET $SOURCE')
env.Command('f4.out', 'f4.in', r'@-%(_python_)s build.py $TARGET $SOURCE')
env.Command('f5.out', 'f5.in', r'@- %(_python_)s build.py $TARGET $SOURCE')
env.Command('f6.out', 'f6.in', r'-@%(_python_)s build.py $TARGET $SOURCE')
env.Command('f7.out', 'f7.in', r'-@ %(_python_)s build.py $TARGET $SOURCE')
""" % locals())

test.write('f1.in', "f1.in\n")
test.write('f2.in', "f2.in\n")
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.write('f7.in', "f7.in\n")

expect = test.wrap_stdout("""\
%(_python_)s build.py f1.out f1.in
""" % locals())

test.run(arguments = '.', stdout = expect)

test.must_match('f1.out', "f1.in\n")
test.must_match('f2.out', "f2.in\n")
test.must_match('f3.out', "f3.in\n")
test.must_match('f4.out', "f4.in\n")
test.must_match('f5.out', "f5.in\n")
test.must_match('f6.out', "f6.in\n")
test.must_match('f7.out', "f7.in\n")

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/skip-execution.py

#!/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 a command that builds multiple targets doesn't get
skipped if the first target is up-to-date but the rest aren't.
Test (and fix for the bug) courtesy Patrick Mezard.
"""

import TestSCons

test = TestSCons.TestSCons()


test.write('SConstruct', """
env = Environment()
env.Command(['a', 'b', 'c'], ['source'], [Touch('a'),Touch('b'),Touch('c')])
""")

test.write('source', '')

test.run(arguments = '.')
test.must_exist('a')
test.must_exist('b')
test.must_exist('c')

test.unlink('c')
test.run(arguments = '.')
test.must_exist('c')

test.unlink('b')
test.run(arguments = '.')
test.must_exist('b')

test.unlink('a')
test.run(arguments = '.')
test.must_exist('a')

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/spaces.py

#!/usr/bin/env python
#
# __COPYRIGHT__
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#

__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"

import TestSCons
import sys
import os

test = TestSCons.TestSCons()

if sys.platform == 'win32':
    test.write('duplicate a file.bat', 'copy foo.in foo.out\n')
    copy = test.workpath('duplicate a file.bat')
else:
    test.write('duplicate a file.sh', 'cp foo.in foo.out\n')
    copy = test.workpath('duplicate a file.sh')
    os.chmod(test.workpath('duplicate a file.sh'), 0o777)
    

test.write('SConstruct', r'''
env=Environment()
env.Command("foo.out", "foo.in", [[r"%s", "$SOURCE", "$TARGET"]])
'''%copy)

test.write('foo.in', 'foo.in 1 \n')

test.run(arguments='foo.out')

test.write('SConstruct', r'''
env=Environment()
env["COPY"] = File(r"%s")
env["ENV"]
env.Command("foo.out", "foo.in", [["./$COPY", "$SOURCE", "$TARGET"]])
'''%copy)

test.write('foo.in', 'foo.in 2 \n')

test.run(arguments='foo.out')

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/special-filenames.py

#!/usr/bin/env python
#
# __COPYRIGHT__
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#

__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"

import TestSCons

_python_ = TestSCons._python_

test = TestSCons.TestSCons()

attempt_file_names = [ 
    'File with spaces',
    'File"with"double"quotes',
    "File'with'single'quotes",
    "File\nwith\nnewlines",
    "File\\with\\backslashes",
    "File;with;semicolons",
    "File<with>redirect",
    "File|with|pipe",
    "File*with*asterisk",
    "File&with&ampersand",
    "File?with?question",
    "File\twith\ttab",
    "File$$with$$dollar",
    "Combination '\"\n\\;<>?|*\t&"
    ]

test.write("cat.py", """\
import sys
with open(sys.argv[1], 'wb') as f, open(sys.argv[2], 'rb') as ifp:
    f.write(ifp.read())
""")

file_names = []
for fn in attempt_file_names:
    try:
        in_name = fn.replace('$$', '$') + '.in'
        test.write(in_name, fn + '\n')
        file_names.append(fn)
    except IOError:
        # if the Python interpreter can't handle it, don't bother
        # testing to see if SCons can
        pass

def buildFileStr(fn):
    return "env.Build(source=r\"\"\"%s.in\"\"\", target=r\"\"\"%s.out\"\"\")" % ( fn, fn )

xxx = '\n'.join(map(buildFileStr, file_names))

test.write("SConstruct", """
env=Environment(BUILDERS = {'Build' : Builder(action = r'%(_python_)s cat.py $TARGET $SOURCE')})

%(xxx)s
""" % locals())

test.run(arguments='.')

for fn in file_names:
    out_name = fn.replace('$$', '$') + '.out'
    test.fail_test(test.read(out_name, mode='r') != fn + '\n')

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/srcchange.py

#!/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.

"""
Test changing the C source files based on an always-executed revision
extraction and substitution.

This makes sure we evaluate the content of intermediate files as
expected.  This relies on the default behavior being the equivalent
of Decider('content').
"""

__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"


import TestSCons

_python_ = TestSCons._python_

test = TestSCons.TestSCons()

test.write('getrevision', r"""
with open('revnum.in', 'r') as f:
    print(f.read().strip(), end='')
""")

test.write('SConstruct', r"""
import re

def subrevision(target, source ,env):
    orig = target[0].get_text_contents()
    new = re.sub(r'\$REV.*?\$',
                 '$REV: %%s$'%%source[0].get_text_contents().strip(),
                 target[0].get_text_contents())
    with open(str(target[0]),'w') as outf:
        outf.write(new)

SubRevision = Action(subrevision)

env=Environment()
content_env=env.Clone()
content_env.Command('revision.in', [], r'%(_python_)s getrevision > $TARGET')
content_env.AlwaysBuild('revision.in')
env.Precious('main.c')
env.Command('main.c', 'revision.in', SubRevision)
exe = env.Program('main.c')
env.Default(exe)
""" % locals())

test.write('main.c', r"""
#include <stdio.h>
#include <stdlib.h>
#include <stdio.h>
int
main(int argc, char *argv[])
{
    printf("Revision $REV$\n");
    exit (0);
}

""", mode='w')

test.write('revnum.in', '3.2\n')

program_name = 'main' + TestSCons._exe

light_build = test.wrap_stdout("""\
%(_python_)s getrevision > revision.in
""" % locals())

test.run(arguments='.')
test.must_exist(program_name)
test.run(program=test.workpath(program_name), stdout='Revision $REV: 3.2$\n')

test.run(arguments='.', stdout=light_build)
test.must_exist(program_name)

test.run(arguments='.', stdout=light_build)
test.must_exist(program_name)

test.write('revnum.in', '3.3\n', mode='w')

test.run(arguments='.')
test.must_exist(program_name)
test.run(program=test.workpath(program_name), stdout='Revision $REV: 3.3$\n')

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/strfunction.py

#!/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 how using strfunction() to report different types of
"""

import TestSCons

_python_ = TestSCons._python_

test = TestSCons.TestSCons()

test.write('cat.py', """\
import sys
with open(sys.argv[2], "wb") as f, open(sys.argv[1], "rb") as ifp:
    f.write(ifp.read())
sys.exit(0)
""")

test.write('SConstruct', """\
def strfunction(target, source, env):
    t = str(target[0])
    s = str(source[0])
    return "Building %%s from %%s" %% (t, s)

def func(target, source, env):
    t = str(target[0])
    s = str(source[0])
    with open(t, 'w') as f, open(s, 'r') as ifp:
        f.write(ifp.read())
func1action = Action(func, strfunction)
func2action = Action(func, strfunction=strfunction)

cmd = r'%(_python_)s cat.py $SOURCE $TARGET'
cmd1action = Action(cmd, strfunction)
cmd2action = Action(cmd, strfunction=strfunction)

list = [ r'%(_python_)s cat.py $SOURCE .temp',
         r'%(_python_)s cat.py .temp $TARGET' ]
listaction = Action(list, strfunction=strfunction)

lazy = '$LAZY'
lazy1action = Action(lazy, strfunction)
lazy2action = Action(lazy, strfunction=strfunction)

targetaction = Action(func, '$TARGET')

dict = {
    '.cmd'      : cmd,
    '.cmdstr'   : cmd2action,
    '.func'     : func,
    '.funcstr'  : func2action,
    '.list'     : list,
    '.liststr'  : listaction,
    '.lazy'     : lazy,
    '.lazystr'  : lazy2action,
}

env = Environment(BUILDERS = {
                        'Cmd'           : Builder(action=cmd),
                        'Cmd1Str'       : Builder(action=cmd1action),
                        'Cmd2Str'       : Builder(action=cmd2action),
                        'Func'          : Builder(action=func),
                        'Func1Str'      : Builder(action=func1action),
                        'Func2Str'      : Builder(action=func2action),
                        'Lazy'          : Builder(action=lazy),
                        'Lazy1Str'      : Builder(action=lazy1action),
                        'Lazy2Str'      : Builder(action=lazy2action),
                        'List'          : Builder(action=list),
                        'ListStr'       : Builder(action=listaction),
                        'Target'        : Builder(action=targetaction),

                        'Dict'          : Builder(action=dict),
                  },
                  LAZY = r'%(_python_)s cat.py $SOURCE $TARGET')

env.Cmd('cmd.out', 'cmd.in')
env.Cmd1Str('cmd1str.out', 'cmdstr.in')
env.Cmd2Str('cmd2str.out', 'cmdstr.in')
env.Func('func.out', 'func.in')
env.Func1Str('func1str.out', 'funcstr.in')
env.Func2Str('func2str.out', 'funcstr.in')
env.Lazy('lazy.out', 'lazy.in')
env.Lazy1Str('lazy1str.out', 'lazystr.in')
env.Lazy2Str('lazy2str.out', 'lazystr.in')
env.List('list.out', 'list.in')
env.ListStr('liststr.out', 'liststr.in')
env.Target('target.out', 'target.in')

env.Dict('dict1.out', 'dict1.cmd')
env.Dict('dict2.out', 'dict2.cmdstr')
env.Dict('dict3.out', 'dict3.func')
env.Dict('dict4.out', 'dict4.funcstr')
env.Dict('dict5.out', 'dict5.lazy')
env.Dict('dict6.out', 'dict6.lazystr')
env.Dict('dict7.out', 'dict7.list')
env.Dict('dict8.out', 'dict8.liststr')
""" % locals())

test.write('func.in',           "func.in\n")
test.write('funcstr.in',        "funcstr.in\n")
test.write('cmd.in',            "cmd.in\n")
test.write('cmdstr.in',         "cmdstr.in\n")
test.write('lazy.in',           "lazy.in\n")
test.write('lazystr.in',        "lazystr.in\n")
test.write('list.in',           "list.in\n")
test.write('liststr.in',        "liststr.in\n")
test.write('target.in',         "target.in\n")

test.write('dict1.cmd',         "dict1.cmd\n")
test.write('dict2.cmdstr',      "dict2.cmdstr\n")
test.write('dict3.func',        "dict3.func\n")
test.write('dict4.funcstr',     "dict4.funcstr\n")
test.write('dict5.lazy',        "dict4.lazy\n")
test.write('dict6.lazystr',     "dict6.lazystr\n")
test.write('dict7.list',        "dict7.list\n")
test.write('dict8.liststr',     "dict8.liststr\n")

expect = test.wrap_stdout("""\
%(_python_)s cat.py cmd.in cmd.out
Building cmd1str.out from cmdstr.in
Building cmd2str.out from cmdstr.in
%(_python_)s cat.py dict1.cmd dict1.out
Building dict2.out from dict2.cmdstr
func(["dict3.out"], ["dict3.func"])
Building dict4.out from dict4.funcstr
%(_python_)s cat.py dict5.lazy dict5.out
Building dict6.out from dict6.lazystr
%(_python_)s cat.py dict7.list .temp
%(_python_)s cat.py .temp dict7.out
Building dict8.out from dict8.liststr
Building dict8.out from dict8.liststr
func(["func.out"], ["func.in"])
Building func1str.out from funcstr.in
Building func2str.out from funcstr.in
%(_python_)s cat.py lazy.in lazy.out
Building lazy1str.out from lazystr.in
Building lazy2str.out from lazystr.in
%(_python_)s cat.py list.in .temp
%(_python_)s cat.py .temp list.out
Building liststr.out from liststr.in
Building liststr.out from liststr.in
target.out
""" % locals())

test.run(arguments = '.', stdout=expect)

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/subclassing.py

#!/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 trivially subclass our "public" classes.  Also
verify that we can use a trivial subclass of new-style str classes
as well as UserString as Builder input.
"""

import TestSCons

test = TestSCons.TestSCons()

test.write('SConstruct', """
copy_action = Copy('$TARGET', '$SOURCE')

# Some day, we'd probably like people to be able to subclass Action and
# Builder, but that's going to take some serious class-hackery to turn
# our factory function into the class itself.
#class my_Action(Action):
#    pass
#class my_Builder(Builder):
#    pass
class my_Scanner(Scanner):
    pass
class my_Environment(Environment):
    pass
env = my_Environment()
env.Command('f0.out', 'f0.in', copy_action)

try:
    from collections import UserString
except ImportError:
    from UserString import UserString
try:
    class mystr(str):
        pass
except TypeError:
    class mystr(UserString):
        pass

Command(mystr('f1.out'),        mystr('f1.in'), copy_action)
Command(UserString('f2.out'),   UserString('f2.in'),    copy_action)

Install(mystr('install'),       mystr('f1.out'))
Install(mystr('install'),       UserString('f2.out'))
""")

test.write('f0.in', "f0.in\n")
test.write('f1.in', "f1.in\n")
test.write('f2.in', "f2.in\n")

test.run(arguments = '.')

test.must_match('f0.out',              "f0.in\n")
test.must_match(['install', 'f1.out'], "f1.in\n")
test.must_match(['install', 'f2.out'], "f2.in\n")

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/subdir.py

#!/usr/bin/env python
#
# __COPYRIGHT__
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#

__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"

import TestSCons

_python_ = TestSCons._python_

test = TestSCons.TestSCons()

test.subdir('subdir')

test.write('build.py', r"""
import sys
with open(sys.argv[1], 'w') as f, open(sys.argv[2], 'r') as ifp:
    f.write(ifp.read())
""")

test.write('SConstruct', """
B = Builder(action = r'%(_python_)s build.py $TARGETS $SOURCES')
env = Environment(BUILDERS = { 'B' : B })
env.B(target = 'subdir/f1.out', source = 'subdir/f1.in')
env.B(target = 'subdir/f2.out', source = 'subdir/f2.in')
env.B(target = 'subdir/f3.out', source = 'subdir/f3.in')
env.B(target = 'subdir/f4.out', source = 'subdir/f4.in')
""" % locals())

test.write(['subdir', 'f1.in'], "f1.in\n")
test.write(['subdir', 'f2.in'], "f2.in\n")
test.write(['subdir', 'f3.in'], "f3.in\n")
test.write(['subdir', 'f4.in'], "f4.in\n")

test.run(arguments = 'subdir')

test.must_match(['subdir', 'f1.out'], "f1.in\n", mode='r')
test.must_match(['subdir', 'f2.out'], "f2.in\n", mode='r')
test.must_match(['subdir', 'f3.out'], "f3.in\n", mode='r')
test.must_match(['subdir', 'f4.out'], "f4.in\n", mode='r')

test.up_to_date(arguments = 'subdir')

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/subdivide.py

#!/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 rebuilds do not occur when SConsignFile(None) is used to
put a .sconsign file in each directory and we subdvide the dependency
tree with subsidiary *SConstruct* files in various subdirectories.

This depends on using content signatures for evaluation of
intermediate Nodes. This relies on the default behavior
being the equivalent of Decider('content').
"""

import os
import TestSCons

test = TestSCons.TestSCons()

test.subdir('src', ['src', 'sub'])

_python_ = TestSCons._python_

# Because this test sets SConsignFile(None), we execute our fake
# scripts directly, not by feeding them to the Python executable.
# That is, we chmod 0o755 and use a "#!/usr/bin/env python" first
# line for POSIX systems, and add .PY to the %PATHEXT% variable on
# Windows.  If we didn't do this, then running this script with
# suitable prileveges would create a .sconsign file in the directory
# where the Python executable lives.  This can happen out of the
# box on Mac OS X, with the result that the .sconsign statefulness
# can mess up other tests.

fake_cc_py = test.workpath('fake_cc.py')
fake_link_py = test.workpath('fake_link.py')

test.write(fake_cc_py, """\
import sys
with open(sys.argv[1], 'w') as ofp:
    ofp.write('fake_cc.py:  %s\\n' % sys.argv)
    for s in sys.argv[2:]:
        with open(s, 'r') as ifp:
            ofp.write(ifp.read())
""")

test.write(fake_link_py, """\
import sys
with open(sys.argv[1], 'w') as ofp:
    ofp.write('fake_link.py:  %s\\n' % sys.argv)
    for s in sys.argv[2:]:
        with open(s, 'r') as ifp:
            ofp.write(ifp.read())
""")

test.chmod(fake_cc_py, 0o755)
test.chmod(fake_link_py, 0o755)

test.write('SConstruct', """\
DefaultEnvironment(tools=[])
SConsignFile(None)
env = Environment(PROGSUFFIX = '.exe',
                  OBJSUFFIX = '.obj',
                  CCCOM = r'%(_python_)s %(fake_cc_py)s $TARGET $SOURCES',
                  LINKCOM = r'%(_python_)s %(fake_link_py)s $TARGET $SOURCES')
env.PrependENVPath('PATHEXT', '.PY')
env.SConscript('src/SConstruct', exports=['env'])
env.Object('foo.c')
""" % locals())

test.write(['src', 'SConstruct'], """\
DefaultEnvironment(tools=[])
SConsignFile(None)
env = Environment(PROGSUFFIX = '.exe',
                  OBJSUFFIX = '.obj',
                  CCCOM = r'%(_python_)s %(fake_cc_py)s $TARGET $SOURCES',
                  LINKCOM = r'%(_python_)s %(fake_link_py)s $TARGET $SOURCES')
env.PrependENVPath('PATHEXT', '.PY')
p = env.Program('prog', ['main.c', '../foo$OBJSUFFIX', 'sub/bar.c'])
env.Default(p)
""" % locals())

test.write('foo.c', """\
foo.c
""")

test.write(['src', 'main.c'], """\
src/main.c
""")

test.write(['src', 'sub', 'bar.c'], """\
src/sub/bar.c
""")

test.run()

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)s', '%(src_prog_exe)s', '%(src_main_obj)s', 'foo.obj', '%(src_sub_bar_obj)s']
fake_cc.py:  ['%(fake_cc_py)s', '%(src_main_obj)s', '%(src_main_c)s']
src/main.c
fake_cc.py:  ['%(fake_cc_py)s', 'foo.obj', 'foo.c']
foo.c
fake_cc.py:  ['%(fake_cc_py)s', '%(src_sub_bar_obj)s', '%(src_sub_bar_c)s']
src/sub/bar.c
""" % locals()

if os.sep == '\\':
    expect = expect.replace('\\', '\\\\')

test.must_match(['src', 'prog.exe'], expect, mode='r')

test.up_to_date(chdir='src', arguments = test.workpath())

test.up_to_date(arguments = '.')

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/suffixes.py

#!/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 handling of file suffixes.
"""

import TestSCons

test = TestSCons.TestSCons()

test.write('SConstruct', """
def cat(env, source, target):
    target = str(target[0])
    with open(target, "wb") as f:
        for src in source:
            with open(str(src), "rb") as ifp:
                f.write(ifp.read())
Cat = Builder(action=cat, suffix='.out')
env = Environment(BUILDERS = {'Cat':Cat})
env.Cat('file1', 'file1.in')
env.Cat('file2.out', 'file2.in')
env.Cat('file3.xyz', 'file3.in')
env.Cat('file4.123', 'file4.in')
""")

test.write('file1.in', "file1.in\n")
test.write('file2.in', "file2.in\n")
test.write('file3.in', "file3.in\n")
test.write('file4.in', "file4.in\n")

test.run(arguments = '.')

test.must_match('file1.out', "file1.in\n")
test.must_match('file2.out', "file2.in\n")
test.must_match('file3.xyz', "file3.in\n")
test.must_match('file4.123.out', "file4.in\n")

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/timestamp-fallback.py

#!/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 falling back to 'timestamp' behavior if there is no md5
module. Formerly checked for hashlib first, but that has been
standard library since 2.5; test is kept in case one of those
rare no-md5 Pythons comes into play (some entities ban the use
of md5 as unsafe, although SCons does not use it in a security context.
"""

import os

import TestSCons

test = TestSCons.TestSCons()

try:
    from hashlib import md5
except ImportError:
    pass
else:
    msg = "The 'md5' algorithm is built in to hashlib in this version of Python.\n" + \
          "Cannot test falling back to timestamps.\n"
    test.skip_test(msg)

test.write('md5.py', r"""
raise ImportError
""")

os.environ['PYTHONPATH'] = test.workpath('.')

test.write('SConstruct', """
DefaultEnvironment(tools=[])

def build(env, target, source):
    with open(str(target[0]), 'wt') as ofp, open(str(source[0]), 'rt') as ifp:
        ofp.write(ifp.read())

B = Builder(action = build)
env = Environment(tools = [], BUILDERS = { 'B' : B })
env.B(target = 'f1.out', source = 'f1.in')
env.B(target = 'f2.out', source = 'f2.in')
env.B(target = 'f3.out', source = 'f3.in')
env.B(target = 'f4.out', source = 'f4.in')
""")

test.write('f1.in', "f1.in\n")
test.write('f2.in', "f2.in\n")
test.write('f3.in', "f3.in\n")
test.write('f4.in', "f4.in\n")

test.run(arguments = 'f1.out f3.out',
         stderr = None)

test.run(arguments = 'f1.out f2.out f3.out f4.out',
         stdout = test.wrap_stdout("""\
scons: `f1.out' is up to date.
build(["f2.out"], ["f2.in"])
scons: `f3.out' is up to date.
build(["f4.out"], ["f4.in"])
"""),
         stderr = None)

os.utime(test.workpath('f1.in'),
         (os.path.getatime(test.workpath('f1.in')),
          os.path.getmtime(test.workpath('f1.in'))+10))
os.utime(test.workpath('f3.in'),
         (os.path.getatime(test.workpath('f3.in')),
          os.path.getmtime(test.workpath('f3.in'))+10))

test.run(arguments = 'f1.out f2.out f3.out f4.out',
         stdout = test.wrap_stdout("""\
build(["f1.out"], ["f1.in"])
scons: `f2.out' is up to date.
build(["f3.out"], ["f3.in"])
scons: `f4.out' is up to date.
"""),
         stderr = None)


test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/tool_args.py

#!/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 the ability to pass a dictionary of keyword arguments to
a Tool specification's generate() method.
"""


import TestSCons

test = TestSCons.TestSCons()

test.write('SConstruct', """
# Test passing kw args to Tool constructor
env1 = Environment(tools=[Tool('FooTool', toolpath=['.'], kw1='kw1val')])
print("env1['TOOL_FOO'] = "+str(env1.get('TOOL_FOO')))
print("env1['kw1'] = "+env1.get('kw1'))

# Test apply_tools taking a list of (name, kwargs_dict)
env2 = Environment(tools=[('FooTool', {'kw2':'kw2val'})], toolpath=['.'])
print("env2['TOOL_FOO'] = "+str(env2.get('TOOL_FOO')))
print("env2['kw2'] = "+env2.get('kw2'))

""")

test.write('FooTool.py', r"""\
def generate(env, **kw):
    for k in kw.keys():
        env[k] = kw[k]
    env['TOOL_FOO'] = 1
def exists(env):
    return 1
""")

test.run(arguments = '.', stdout = """\
scons: Reading SConscript files ...
env1['TOOL_FOO'] = 1
env1['kw1'] = kw1val
env2['TOOL_FOO'] = 1
env2['kw2'] = kw2val
scons: done reading SConscript files.
scons: Building targets ...
scons: `.' is up to date.
scons: done building targets.
""")

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/up-to-date.py

#!/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 appropriate printing of "is up to date" messages.
"""

import TestSCons

_python_ = TestSCons._python_

test = TestSCons.TestSCons()

test.write('build.py', r"""
import sys
with open(sys.argv[1], 'wb') as f, open(sys.argv[2], 'rb') as ifp:
    f.write(ifp.read())
""")

test.write('SConstruct', """
B = Builder(action = r'%(_python_)s build.py $TARGETS $SOURCES')
env = Environment(BUILDERS =  { 'B' : B })
env.B(target = 'f1.out', source = 'f1.in')
env.B(target = 'f2.out', source = 'f2.in')
env.B(target = 'f3.out', source = 'f3.in')
env.B(target = 'f4.out', source = 'f4.in')
""" % locals())

test.write('f1.in', "f1.in\n")
test.write('f2.in', "f2.in\n")
test.write('f3.in', "f3.in\n")
test.write('f4.in', "f4.in\n")

test.run(arguments = 'f1.out f3.out')

expect = test.wrap_stdout("""\
scons: `f1.out' is up to date.
%(_python_)s build.py f2.out f2.in
scons: `f3.out' is up to date.
%(_python_)s build.py f4.out f4.in
""" % locals())

test.run(arguments = 'f1.out f2.out f3.out f4.out', stdout = expect)

# Make sure all of the "up to date" messages get printed even when -j
# is used.  This broke during signature refactoring development.
expected_lines = [
    "scons: `f1.out' is up to date.",
    "scons: `f2.out' is up to date.",
    "scons: `f3.out' is up to date.",
    "scons: `f4.out' is up to date.",
]

test.run(options = '-j4 f1.out f2.out f3.out f4.out')

test.must_contain_all_lines(test.stdout(), expected_lines)

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/warning-TargetNotBuiltWarning.py

#!/usr/bin/env python
#
# __COPYRIGHT__
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#

__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"

import TestSCons

test = TestSCons.TestSCons()

test.write('SConstruct', """
foo = Command('foo.out', [], '@echo boo')
bill = Command('bill.out', [], Touch('$TARGET'))
Depends(bill, foo)
Alias('jim', bill)
""")

test.run(arguments='-Q jim', stdout = 'boo\nTouch("bill.out")\n')

test.run(arguments='-Q jim --warning=target-not-built',
         stdout = "boo\nscons: `jim' is up to date.\n",
         stderr = None)
test.must_contain_all_lines(test.stderr(),
                            'scons: warning: Cannot find target foo.out after building')

test.run(arguments='-Q jim --warning=target-not-built -n',
         stdout = "scons: `jim' is up to date.\n")

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/MSVC/MSVC_BATCH-spaces-targetdir.py

import TestSCons



test = TestSCons.TestSCons()

test.skip_if_not_msvc()


test.dir_fixture('MSVC_BATCH-spaces-targetdir')
test.run()

# test/MSVC/MSVC_NOTFOUND_POLICY.py

# MIT License
#
# Copyright The SCons Foundation
#
# 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.

"""
Test the msvc not found policy construction variable and functions.
"""

import TestSCons

test = TestSCons.TestSCons()

test.skip_if_not_msvc()

import textwrap

# Test global functions with valid symbols
test.write('SConstruct', textwrap.dedent(
    """
    from SCons.Tool.MSCommon import msvc_set_notfound_policy
    from SCons.Tool.MSCommon import msvc_get_notfound_policy
    DefaultEnvironment(tools=[])
    for symbol in ['Error', 'Exception', 'Warn', 'Warning', 'Ignore', 'Suppress']:
        for policy in [symbol, symbol.upper(), symbol.lower()]:
            old_policy = msvc_set_notfound_policy(policy)
            cur_policy = msvc_get_notfound_policy()
    if msvc_set_notfound_policy(None) != msvc_get_notfound_policy():
        raise RuntimeError()
    """
))
test.run(arguments='-Q -s', stdout='')

# Test global function with invalid symbol
test.write('SConstruct', textwrap.dedent(
    """
    from SCons.Tool.MSCommon import msvc_set_notfound_policy
    DefaultEnvironment(tools=[])
    msvc_set_notfound_policy('Undefined')
    """
))
test.run(arguments='-Q -s', status=2, stderr=None)
expect = "MSVCArgumentError: Value specified for MSVC_NOTFOUND_POLICY is not supported: 'Undefined'."
test.must_contain_all(test.stderr(), expect)

# Test construction variable with valid symbols
test.write('SConstruct', textwrap.dedent(
    """
    env_list = []
    DefaultEnvironment(tools=[])
    for symbol in ['Error', 'Exception', 'Warn', 'Warning', 'Ignore', 'Suppress']:
        for policy in [symbol, symbol.upper(), symbol.lower()]:
            env = Environment(MSVC_NOTFOUND_POLICY=policy, tools=['msvc'])
            env_list.append(env)
    """
))
test.run(arguments='-Q -s', stdout='')

# Test construction variable with invalid symbol
test.write('SConstruct', textwrap.dedent(
    """
    env = Environment(MSVC_VERSION='12.9', MSVC_NOTFOUND_POLICY='Undefined', tools=['msvc'])
    """
))
test.run(arguments='-Q -s', status=2, stderr=None)
expect = "MSVCArgumentError: Value specified for MSVC_NOTFOUND_POLICY is not supported: 'Undefined'."
test.must_contain_all(test.stderr(), expect)

# Test environment construction with global policy
test.write('SConstruct', textwrap.dedent(
    """
    from SCons.Tool.MSCommon import msvc_set_notfound_policy
    msvc_set_notfound_policy('Exception')
    env = Environment(MSVC_VERSION='12.9', tools=['msvc'])
    """
))
test.run(arguments='-Q -s', status=2, stderr=None)
expect = "MSVCVersionNotFound: MSVC version '12.9' was not found."
test.must_contain_all(test.stderr(), expect)

# Test environment construction with global policy and construction variable ignored
test.write('SConstruct', textwrap.dedent(
    """
    from SCons.Tool.MSCommon import msvc_set_notfound_policy
    msvc_set_notfound_policy('Exception')
    env = Environment(MSVC_VERSION='12.9', MSVC_NOTFOUND_POLICY=None, tools=['msvc'])
    """
))
test.run(arguments='-Q -s', status=2, stderr=None)
expect = "MSVCVersionNotFound: MSVC version '12.9' was not found."
test.must_contain_all(test.stderr(), expect)

# Test environment construction with construction variable
test.write('SConstruct', textwrap.dedent(
    """
    env = Environment(MSVC_VERSION='12.9', MSVC_NOTFOUND_POLICY='Error', tools=['msvc'])
    """
))
test.run(arguments='-Q -s', status=2, stderr=None)
expect = "MSVCVersionNotFound: MSVC version '12.9' was not found."
test.must_contain_all(test.stderr(), expect)

# Test environment construction with global policy
test.write('SConstruct', textwrap.dedent(
    """
    from SCons.Tool.MSCommon import msvc_set_notfound_policy
    msvc_set_notfound_policy('Warning')
    env = Environment(MSVC_VERSION='12.9', tools=['msvc'])
    """
))
test.run(arguments="-Q -s --warn=visual-c-missing .", status=0, stderr=None)
expect = "scons: warning: MSVC version '12.9' was not found."
test.must_contain_all(test.stderr(), expect)

# Test environment construction with construction variable
test.write('SConstruct', textwrap.dedent(
    """
    env = Environment(MSVC_VERSION='12.9', MSVC_NOTFOUND_POLICY='Warning', tools=['msvc'])
    """
))
test.run(arguments="-Q -s --warn=visual-c-missing .", status=0, stderr=None)
expect = "scons: warning: MSVC version '12.9' was not found."
test.must_contain_all(test.stderr(), expect)

# Test environment construction with construction variable (override global)
test.write('SConstruct', textwrap.dedent(
    """
    from SCons.Tool.MSCommon import msvc_set_notfound_policy
    msvc_set_notfound_policy('Exception')
    env = Environment(MSVC_VERSION='12.9', MSVC_NOTFOUND_POLICY='Ignore', tools=['msvc'])
    """
))
test.run(arguments='-Q -s', stdout='')

test.pass_test()



# test/MSVC/MSVC_SCRIPTERROR_POLICY.py

# MIT License
#
# Copyright The SCons Foundation
#
# 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.

"""
Test the msvc script error policy construction variable and functions.
"""

import TestSCons

test = TestSCons.TestSCons()

test.skip_if_not_msvc()

import textwrap

from SCons.Tool.MSCommon.vc import get_installed_vcs_components

installed_versions = get_installed_vcs_components()

default_version = installed_versions[0]

# Test global functions with valid symbols
test.write('SConstruct', textwrap.dedent(
    """
    from SCons.Tool.MSCommon import msvc_set_scripterror_policy
    from SCons.Tool.MSCommon import msvc_get_scripterror_policy
    DefaultEnvironment(tools=[])
    for symbol in ['Error', 'Exception', 'Warn', 'Warning', 'Ignore', 'Suppress']:
        for policy in [symbol, symbol.upper(), symbol.lower()]:
            old_policy = msvc_set_scripterror_policy(policy)
            cur_policy = msvc_get_scripterror_policy()
    if msvc_set_scripterror_policy(None) != msvc_get_scripterror_policy():
        raise RuntimeError()
    """
))
test.run(arguments='-Q -s', stdout='')

# Test global function with invalid symbol
test.write('SConstruct', textwrap.dedent(
    """
    from SCons.Tool.MSCommon import msvc_set_scripterror_policy
    DefaultEnvironment(tools=[])
    msvc_set_scripterror_policy('Undefined')
    """
))
test.run(arguments='-Q -s', status=2, stderr=None)
expect = "MSVCArgumentError: Value specified for MSVC_SCRIPTERROR_POLICY is not supported: 'Undefined'."
test.must_contain_all(test.stderr(), expect)

# Test construction variable with valid symbols
test.write('SConstruct', textwrap.dedent(
    """
    env_list = []
    DefaultEnvironment(tools=[])
    for symbol in ['Error', 'Exception', 'Warn', 'Warning', 'Ignore', 'Suppress']:
        for policy in [symbol, symbol.upper(), symbol.lower()]:
            env = Environment(MSVC_SCRIPTERROR_POLICY=policy, tools=['msvc'])
            env_list.append(env)
    """
))
test.run(arguments='-Q -s', stdout='')

if default_version.msvc_vernum >= 14.1:
    # Need VS2017 or later for MSVC_SCRIPT_ARGS

    # Test environment construction with construction variable (invalid)
    test.write('SConstruct', textwrap.dedent(
        """
        DefaultEnvironment(tools=[])
        env = Environment(MSVC_SCRIPT_ARGS=['-thisdoesnotexist=somevalue'], MSVC_SCRIPTERROR_POLICY='Undefined', tools=['msvc'])
        """
    ))
    test.run(arguments='-Q -s', status=2, stderr=None)
    expect = "MSVCArgumentError: Value specified for MSVC_SCRIPTERROR_POLICY is not supported: 'Undefined'."
    test.must_contain_all(test.stderr(), expect)

    # Test environment construction with construction variable (override global)
    test.write('SConstruct', textwrap.dedent(
        """
        from SCons.Tool.MSCommon import msvc_set_scripterror_policy
        DefaultEnvironment(tools=[])
        msvc_set_scripterror_policy('Exception')
        env = Environment(MSVC_SCRIPT_ARGS=['-thisdoesnotexist=somevalue'], MSVC_SCRIPTERROR_POLICY='Ignore', tools=['msvc'])
        """
    ))
    test.run(arguments='-Q -s', stdout='')

    # Test environment construction with global policy
    test.write('SConstruct', textwrap.dedent(
        """
        from SCons.Tool.MSCommon import msvc_set_scripterror_policy
        DefaultEnvironment(tools=[])
        msvc_set_scripterror_policy('Exception')
        env = Environment(MSVC_SCRIPT_ARGS=['-thisdoesnotexist=somevalue'], tools=['msvc'])
        """
    ))
    test.run(arguments='-Q -s', status=2, stderr=None)
    expect = "MSVCScriptExecutionError: vc script errors detected:"
    test.must_contain_all(test.stderr(), expect)

    # Test environment construction with global policy and construction variable ignored
    test.write('SConstruct', textwrap.dedent(
        """
        from SCons.Tool.MSCommon import msvc_set_scripterror_policy
        DefaultEnvironment(tools=[])
        msvc_set_scripterror_policy('Exception')
        env = Environment(MSVC_SCRIPT_ARGS=['-thisdoesnotexist=somevalue'], MSVC_SCRIPTERROR_POLICY=None, tools=['msvc'])
        """
    ))
    test.run(arguments='-Q -s', status=2, stderr=None)
    expect = "MSVCScriptExecutionError: vc script errors detected:"
    test.must_contain_all(test.stderr(), expect)

    # Test environment construction with construction variable
    test.write('SConstruct', textwrap.dedent(
        """
        DefaultEnvironment(tools=[])
        env = Environment(MSVC_SCRIPT_ARGS=['-thisdoesnotexist=somevalue'], MSVC_SCRIPTERROR_POLICY='Error', tools=['msvc'])
        """
    ))
    test.run(arguments='-Q -s', status=2, stderr=None)
    expect = "MSVCScriptExecutionError: vc script errors detected:"
    test.must_contain_all(test.stderr(), expect)

    # Test environment construction with global policy
    test.write('SConstruct', textwrap.dedent(
        """
        from SCons.Tool.MSCommon import msvc_set_scripterror_policy
        DefaultEnvironment(tools=[])
        msvc_set_scripterror_policy('Warning')
        env = Environment(MSVC_SCRIPT_ARGS=['-thisdoesnotexist=somevalue'], tools=['msvc'])
        """
    ))
    test.run(arguments='-Q -s', status=0, stderr=None)
    expect = "scons: warning: vc script errors detected:"
    test.must_contain_all(test.stderr(), expect)

    # Test environment construction with construction variable
    test.write('SConstruct', textwrap.dedent(
        """
        DefaultEnvironment(tools=[])
        env = Environment(MSVC_SCRIPT_ARGS=['-thisdoesnotexist=somevalue'], MSVC_SCRIPTERROR_POLICY='Warning', tools=['msvc'])
        """
    ))
    test.run(arguments='-Q -s', status=0, stderr=None)
    expect = "scons: warning: vc script errors detected:"
    test.must_contain_all(test.stderr(), expect)

test.pass_test()



# test/MSVC/MSVC_TOOLSET_VERSION.py

# MIT License
#
# Copyright The SCons Foundation
#
# 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.

"""
Test the MSVC_TOOLSET_VERSION construction variable.
"""

import TestSCons

test = TestSCons.TestSCons()

test.skip_if_not_msvc()

import textwrap

from SCons.Tool.MSCommon.vc import get_installed_vcs_components

installed_versions = get_installed_vcs_components()

default_version = installed_versions[0]

GE_VS2017_versions = [v for v in installed_versions if v.msvc_vernum >= 14.1]
LT_VS2017_versions = [v for v in installed_versions if v.msvc_vernum < 14.1]
LT_VS2015_versions = [v for v in LT_VS2017_versions if v.msvc_vernum < 14.0]

if GE_VS2017_versions:
    # VS2017 and later for toolset argument

    for supported in GE_VS2017_versions:

        # msvc_version as toolset version
        test.write('SConstruct', textwrap.dedent(
            """
            DefaultEnvironment(tools=[])
            env = Environment(MSVC_VERSION={}, MSVC_TOOLSET_VERSION={}, tools=['msvc'])
            """.format(repr(supported.msvc_version), repr(supported.msvc_verstr))
        ))
        test.run(arguments='-Q -s', stdout='')

        # msvc_version as toolset version using script argument
        test.write('SConstruct', textwrap.dedent(
            """
            DefaultEnvironment(tools=[])
            env = Environment(MSVC_VERSION={}, MSVC_SCRIPT_ARGS='-vcvars_ver={}', tools=['msvc'])
            """.format(repr(supported.msvc_version), supported.msvc_verstr)
        ))
        test.run(arguments='-Q -s', stdout='')

        # error toolset version and script argument
        test.write('SConstruct', textwrap.dedent(
            """
            DefaultEnvironment(tools=[])
            env = Environment(MSVC_VERSION={}, MSVC_TOOLSET_VERSION={}, MSVC_SCRIPT_ARGS='-vcvars_ver={}', tools=['msvc'])
            """.format(repr(supported.msvc_version), repr(supported.msvc_verstr), supported.msvc_verstr)
        ))
        test.run(arguments='-Q -s', status=2, stderr=None)
        expect = "MSVCArgumentError: multiple toolset version declarations: MSVC_TOOLSET_VERSION={} and MSVC_SCRIPT_ARGS='-vcvars_ver={}':".format(
            repr(supported.msvc_verstr), supported.msvc_verstr
        )
        test.must_contain_all(test.stderr(), expect)

        # msvc_toolset_version does not exist (hopefully)
        missing_toolset_version = supported.msvc_verstr + '9.99999'
        test.write('SConstruct', textwrap.dedent(
            """
            DefaultEnvironment(tools=[])
            env = Environment(MSVC_VERSION={}, MSVC_TOOLSET_VERSION={}, tools=['msvc'])
            """.format(repr(supported.msvc_version), repr(missing_toolset_version))
        ))
        test.run(arguments='-Q -s', status=2, stderr=None)
        expect = "MSVCToolsetVersionNotFound: MSVC_TOOLSET_VERSION {} not found for MSVC_VERSION {}:".format(
            repr(missing_toolset_version), repr(supported.msvc_version)
        )
        test.must_contain_all(test.stderr(), expect)

        # msvc_toolset_version is invalid (format)
        invalid_toolset_version = supported.msvc_verstr + '9.99999.99999'
        test.write('SConstruct', textwrap.dedent(
            """
            DefaultEnvironment(tools=[])
            env = Environment(MSVC_VERSION={}, MSVC_TOOLSET_VERSION={}, tools=['msvc'])
            """.format(repr(supported.msvc_version), repr(invalid_toolset_version))
        ))
        test.run(arguments='-Q -s', status=2, stderr=None)
        expect = "MSVCArgumentError: MSVC_TOOLSET_VERSION ({}) format is not supported:".format(
            repr(invalid_toolset_version)
        )
        test.must_contain_all(test.stderr(), expect)

        # msvc_toolset_version is invalid (version greater than msvc version)
        invalid_toolset_vernum = round(supported.msvc_vernum + 0.1, 1)
        invalid_toolset_version = str(invalid_toolset_vernum)
        test.write('SConstruct', textwrap.dedent(
            """
            DefaultEnvironment(tools=[])
            env = Environment(MSVC_VERSION={}, MSVC_TOOLSET_VERSION={}, tools=['msvc'])
            """.format(repr(supported.msvc_version), repr(invalid_toolset_version))
        ))
        test.run(arguments='-Q -s', status=2, stderr=None)
        expect = "MSVCArgumentError: MSVC_TOOLSET_VERSION ({}) constraint violation: toolset version {} > {} MSVC_VERSION:".format(
            repr(invalid_toolset_version), repr(invalid_toolset_version), repr(supported.msvc_version)
        )
        test.must_contain_all(test.stderr(), expect)

        # msvc_toolset_version is invalid (version less than 14.0)
        invalid_toolset_version = '12.0'
        test.write('SConstruct', textwrap.dedent(
            """
            DefaultEnvironment(tools=[])
            env = Environment(MSVC_VERSION={}, MSVC_TOOLSET_VERSION={}, tools=['msvc'])
            """.format(repr(supported.msvc_version), repr(invalid_toolset_version))
        ))
        test.run(arguments='-Q -s', status=2, stderr=None)
        expect = "MSVCArgumentError: MSVC_TOOLSET_VERSION ({}) constraint violation: toolset version {} < '14.0' VS2015:".format(
            repr(invalid_toolset_version), repr(invalid_toolset_version)
        )
        test.must_contain_all(test.stderr(), expect)

        # 14.0 toolset is invalid (toolset version != 14.0)
        invalid_toolset_version = '14.00.00001'
        test.write('SConstruct', textwrap.dedent(
            """
            DefaultEnvironment(tools=[])
            env = Environment(MSVC_VERSION={}, MSVC_TOOLSET_VERSION={}, tools=['msvc'])
            """.format(repr(supported.msvc_version), repr(invalid_toolset_version))
        ))
        test.run(arguments='-Q -s', status=2, stderr=None)
        expect = "MSVCArgumentError: MSVC_TOOLSET_VERSION ({}) constraint violation: toolset version {} != '14.0':".format(
            repr(invalid_toolset_version), repr(invalid_toolset_version)
        )
        test.must_contain_all(test.stderr(), expect)

        if supported == default_version:
            msvc_version_list = ['None', repr(supported.msvc_version)]
        else:
            msvc_version_list = [repr(supported.msvc_version)]

        for test_version in msvc_version_list:

            # msvc toolsets detected
            test.write('SConstruct', textwrap.dedent(
                """
                from SCons.Tool.MSCommon import msvc_toolset_versions
                DefaultEnvironment(tools=[])
                for full in (True, False):
                    for sxs in (True, False):
                        toolsets = msvc_toolset_versions(msvc_version={}, full=full, sxs=sxs)
                """.format(test_version)
            ))
            test.run(arguments='-Q -s', stdout='')

            # msvc query version toolset
            test.write('SConstruct', textwrap.dedent(
                """
                from SCons.Tool.MSCommon import msvc_query_version_toolset
                DefaultEnvironment(tools=[])
                for prefer_newest in (True, False):
                    msvc_version, msvc_toolset_version = msvc_query_version_toolset(version={}, prefer_newest=prefer_newest)
                """.format(test_version)
            ))
            test.run(arguments='-Q -s', stdout='')

    # msvc_version is invalid
    invalid_msvc_version = '12.9'
    test.write('SConstruct', textwrap.dedent(
        """
        from SCons.Tool.MSCommon import msvc_toolset_versions
        DefaultEnvironment(tools=[])
        toolsets = msvc_toolset_versions(msvc_version={}, full=True, sxs=True)
        """.format(repr(invalid_msvc_version))
    ))
    test.run(arguments='-Q -s', status=2, stderr=None)
    expect = "MSVCArgumentError: Unsupported msvc version {}:".format(
        repr(invalid_msvc_version)
    )
    test.must_contain_all(test.stderr(), expect)

if LT_VS2017_versions:
    # VS2015 and earlier for toolset argument error

    for unsupported in LT_VS2017_versions:

        # must be VS2017 or later
        test.write('SConstruct', textwrap.dedent(
            """
            DefaultEnvironment(tools=[])
            env = Environment(MSVC_VERSION={}, MSVC_TOOLSET_VERSION={}, tools=['msvc'])
            """.format(repr(unsupported.msvc_version), repr(unsupported.msvc_verstr))
        ))
        test.run(arguments='-Q -s', status=2, stderr=None)
        expect = "MSVCArgumentError: MSVC_TOOLSET_VERSION ({}) constraint violation: MSVC_VERSION {} < '14.1' VS2017:".format(
            repr(unsupported.msvc_verstr), repr(unsupported.msvc_version)
        )
        test.must_contain_all(test.stderr(), expect)

        # msvc_toolset_versions returns None for versions that don't support toolsets
        test.write('SConstruct', textwrap.dedent(
            """
            from SCons.Tool.MSCommon import msvc_toolset_versions
            DefaultEnvironment(tools=[])
            toolsets = msvc_toolset_versions(msvc_version={}, full=True, sxs=True)
            if toolsets is not None:
                raise RuntimeError("Expected toolsets==None")
            """.format(repr(unsupported.msvc_version))
        ))
        test.run(arguments='-Q -s', stdout='')

if LT_VS2015_versions:
    # VS2013 and earlier for script argument error

    for unsupported in LT_VS2015_versions:

        # must be VS2015 or later for MSVC_SCRIPT_ARGS
        test.write('SConstruct', textwrap.dedent(
            """
            DefaultEnvironment(tools=[])
            env = Environment(MSVC_VERSION={}, MSVC_SCRIPT_ARGS='-vcvars_ver={}', tools=['msvc'])
            """.format(repr(unsupported.msvc_version), unsupported.msvc_verstr)
        ))
        test.run(arguments='-Q -s', status=2, stderr=None)
        expect = "MSVCArgumentError: MSVC_SCRIPT_ARGS ('-vcvars_ver={}') constraint violation: MSVC_VERSION {} < '14.0' VS2015:".format(
            unsupported.msvc_verstr, repr(unsupported.msvc_version)
        )
        test.must_contain_all(test.stderr(), expect)

test.pass_test()



# test/MSVC/MSVC_USE_SCRIPT.py

# MIT License
#
# Copyright The SCons Foundation
#
# 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.

"""
Test the $MSVC_USE_SCRIPT construction variable.
"""

import TestSCons

_python_ = TestSCons._python_

test = TestSCons.TestSCons()

test.skip_if_not_msvc()

test.write('SConstruct', """
env = Environment(tools=['msvc'], MSVC_USE_SCRIPT='nosuchscriptexists')
""" % locals())

test.run(arguments = ".", status=2, stderr=None)

test.must_contain_all(test.stderr(), "Script specified by MSVC_USE_SCRIPT not found")

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/MSVC/MSVC_USE_SCRIPT_ARGS.py

# MIT License
#
# Copyright The SCons Foundation
#
# 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.

"""
Test the $MSVC_USE_SCRIPT construction variable.
"""

import TestSCons

_python_ = TestSCons._python_

test = TestSCons.TestSCons()

test.skip_if_not_msvc()
test.dir_fixture('MSVC_USE_SCRIPT_ARGS-fixture')

test.run(arguments = ".", status=0, stderr=None)

test.must_contain('MSDEBUG_OUTPUT.log', "Calling 'fake_script.bat one two'")

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/MSVC/MSVC_USE_SETTINGS.py

# MIT License
#
# Copyright The SCons Foundation
#
# 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.

"""
Test the $MSVC_USE_SETTINGS construction variable.
"""

import TestSCons

_python_ = TestSCons._python_

test = TestSCons.TestSCons()

test.skip_if_not_msvc()

test.write('SConstruct', """
e1 = Environment()
cl1 = e1.WhereIs('cl.exe')

e2 = Environment(tools=[])

d = {key: e1['ENV'][key] for key in e1['ENV'].keys() if key not in e2['ENV'] or e1['ENV'][key] != e2['ENV'][key]}
e3 = Environment(MSVC_USE_SETTINGS=d)
cl3 = e3.WhereIs('cl.exe')

if cl1 == cl3:
    print("CL.EXE PATHS MATCH")
""" % locals())

test.run(arguments = ".", status=0, stderr=None)

test.must_contain_all(test.stdout(), "CL.EXE PATHS MATCH")

test.write('SConstruct', """
env = Environment(MSVC_USE_SETTINGS={})
""" % locals())

test.run(arguments = "--warn=visual-c-missing .", status=0, stderr=None)

test.must_contain_all(test.stderr(), "Could not find MSVC compiler 'cl'")

test.write('SConstruct', """
env = Environment(MSVC_USE_SETTINGS='dict or None')
""" % locals())
  
test.run(arguments = ".", status=2, stderr=None)
  
test.must_contain_all(test.stderr(), "MSVCUseSettingsError: MSVC_USE_SETTINGS type error")
  
test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/MSVC/MSVC_UWP_APP.py

#!/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 the ability to configure the $MSVC_UWP_APP construction variable with
the desired effect.
"""

import TestSCons
import SCons.Tool.MSCommon.vc as msvc
from SCons.Tool.MSCommon.vc import get_msvc_version_numeric

def AreVCStoreLibPathsInLIBPATH(output):
    libpath = None
    msvc_version = None
    UWP_APP = None
    lines = output.splitlines()
    for line in lines:
        if 'env[ENV][LIBPATH]=' in line:
            libpath = line.split('=')[1]
        elif 'env[MSVC_VERSION]=' in line:
            msvc_version = line.split('=')[1]
        elif 'env[ENV][VSCMD_ARG_app_plat]=' in line:
            UWP_APP = line.split('=')[1]

    if not libpath or not msvc_version:
        # Couldn't find the libpath or msvc version in the output
        return (False, False, None)

    libpaths = libpath.lower().split(';')
    msvc_num = float(get_msvc_version_numeric(msvc_version))
    
    (vclibstore_path_present, vclibstorerefs_path_present) = (False, False)
    for path in libpaths:
        # Look for the Store VC Lib paths in the LIBPATH:
        # [VS install path]\VC\LIB\store[\arch] and 
        # [VS install path]\VC\LIB\store\references
        # For example,
        # C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\LIB\store\amd64
        # C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\LIB\store\references
        
        if msvc_num <= 14:
            if r'vc\lib\store\references' in path:
                vclibstorerefs_path_present = True
            elif r'vc\lib\store' in path:
                vclibstore_path_present = True
        elif msvc_num > 14:
            if UWP_APP == "UWP":
                if(r'\lib\x86\store\references' in path
                or r'\lib\x64\store' in path):
                    vclibstorerefs_path_present = True
                    vclibstore_path_present = True

    return (vclibstore_path_present, vclibstorerefs_path_present, msvc_version)

_python_ = TestSCons._python_

test = TestSCons.TestSCons()

test.skip_if_not_msvc()

installed_msvc_versions = msvc.get_installed_vcs()
# MSVC guaranteed to be at least one version on the system or else
# skip_if_not_msvc() function would have skipped the test

msvc_140 = '14.0' in installed_msvc_versions
msvc_141 = '14.1' in installed_msvc_versions
msvc_142 = '14.2' in installed_msvc_versions
msvc_143 = '14.3' in installed_msvc_versions

if not any((msvc_140, msvc_141, msvc_142, msvc_143)):
    test.skip_test("Available MSVC doesn't support App store\n")

if msvc_140:
    test.write('SConstruct', """\
if ARGUMENTS.get('MSVC_UWP_APP'):
    help_vars = Variables()
    help_vars.Add(EnumVariable(
                'MSVC_UWP_APP',
                'Build a Universal Windows Platform (UWP) Application',
                '0',
                allowed_values=('0', '1')))
else:
    help_vars = None
env = Environment(tools=['default', 'msvc'], variables=help_vars, MSVC_VERSION='14.0')
# Print the ENV LIBPATH to stdout
print('env[ENV][LIBPATH]=%s' % env.get('ENV').get('LIBPATH'))
print('env[MSVC_VERSION]=%s' % env.get('MSVC_VERSION'))
""")

    # Test setting MSVC_UWP_APP is '1' (True)
    test.run(arguments = "MSVC_UWP_APP=1")
    (vclibstore_path_present, vclibstorerefs_path_present, msvc_version) = AreVCStoreLibPathsInLIBPATH(test.stdout())
    test.fail_test((vclibstore_path_present is False) or (vclibstorerefs_path_present is False),
                message='VC Store LIBPATHs NOT present when MSVC_UWP_APP=1 (msvc_version=%s)' % msvc_version)

    # Test setting MSVC_UWP_APP is '0' (False)
    test.run(arguments = "MSVC_UWP_APP=0")
    (vclibstore_path_present, vclibstorerefs_path_present, msvc_version) = AreVCStoreLibPathsInLIBPATH(test.stdout())
    test.fail_test((vclibstore_path_present is True) or (vclibstorerefs_path_present is True),
                message='VC Store LIBPATHs present when MSVC_UWP_APP=0 (msvc_version=%s)' % msvc_version)

    # Test not setting MSVC_UWP_APP
    test.run(arguments = "")
    (vclibstore_path_present, vclibstorerefs_path_present, msvc_version) = AreVCStoreLibPathsInLIBPATH(test.stdout())
    test.fail_test((vclibstore_path_present is True) or (vclibstorerefs_path_present is True),
                message='VC Store LIBPATHs present when MSVC_UWP_APP not set (msvc_version=%s)' % msvc_version)

if msvc_141 or msvc_142 or msvc_143:
    if msvc_143:
        test.write('SConstruct', """\
if ARGUMENTS.get('MSVC_UWP_APP'):
    help_vars = Variables()
    help_vars.Add(EnumVariable(
                'MSVC_UWP_APP',
                'Build a Universal Windows Platform (UWP) Application',
                '0',
                allowed_values=('0', '1')))
else:
    help_vars = None
env = Environment(tools=['default', 'msvc'], variables=help_vars, MSVC_VERSION='14.3')
# Print the ENV LIBPATH to stdout
print('env[ENV][LIBPATH]=%s' % env.get('ENV').get('LIBPATH'))
print('env[MSVC_VERSION]=%s' % env.get('MSVC_VERSION'))
print('env[ENV][VSCMD_ARG_app_plat]=%s' % env.get('ENV').get('VSCMD_ARG_app_plat'))
""")
    elif msvc_142:
        test.write('SConstruct', """\
if ARGUMENTS.get('MSVC_UWP_APP'):
    help_vars = Variables()
    help_vars.Add(EnumVariable(
                'MSVC_UWP_APP',
                'Build a Universal Windows Platform (UWP) Application',
                '0',
                allowed_values=('0', '1')))
else:
    help_vars = None
env = Environment(tools=['default', 'msvc'], variables=help_vars, MSVC_VERSION='14.2')
# Print the ENV LIBPATH to stdout
print('env[ENV][LIBPATH]=%s' % env.get('ENV').get('LIBPATH'))
print('env[MSVC_VERSION]=%s' % env.get('MSVC_VERSION'))
print('env[ENV][VSCMD_ARG_app_plat]=%s' % env.get('ENV').get('VSCMD_ARG_app_plat'))
""")
    elif msvc_141:
        test.write('SConstruct', """\
if ARGUMENTS.get('MSVC_UWP_APP'):
    help_vars = Variables()
    help_vars.Add(EnumVariable(
                'MSVC_UWP_APP',
                'Build a Universal Windows Platform (UWP) Application',
                '0',
                allowed_values=('0', '1')))
else:
    help_vars = None
env = Environment(tools=['default', 'msvc'], variables=help_vars, MSVC_VERSION='14.1')
# Print the ENV LIBPATH to stdout
print('env[ENV][LIBPATH]=%s' % env.get('ENV').get('LIBPATH'))
print('env[MSVC_VERSION]=%s' % env.get('MSVC_VERSION'))
print('env[ENV][VSCMD_ARG_app_plat]=%s' % env.get('ENV').get('VSCMD_ARG_app_plat'))
""")

    # Test setting MSVC_UWP_APP is '1' (True)
    test.run(arguments = "MSVC_UWP_APP=1")
    (vclibstore_path_present, vclibstorerefs_path_present, msvc_version) = AreVCStoreLibPathsInLIBPATH(test.stdout())
    test.fail_test((vclibstore_path_present is False) or (vclibstorerefs_path_present is False),
                message='VC Store LIBPATHs NOT present when MSVC_UWP_APP=1 (msvc_version=%s)' % msvc_version)

    # Test setting MSVC_UWP_APP is '0' (False)
    test.run(arguments = "MSVC_UWP_APP=0")
    (vclibstore_path_present, vclibstorerefs_path_present, msvc_version) = AreVCStoreLibPathsInLIBPATH(test.stdout())
    test.fail_test((vclibstore_path_present is True) or (vclibstorerefs_path_present is True),
                    message='VC Store LIBPATHs NOT present when MSVC_UWP_APP=1 (msvc_version=%s)' % msvc_version)

    # Test not setting MSVC_UWP_APP
    test.run(arguments = "")
    (vclibstore_path_present, vclibstorerefs_path_present, msvc_version) = AreVCStoreLibPathsInLIBPATH(test.stdout())
    test.fail_test((vclibstore_path_present is True) or (vclibstorerefs_path_present is True),
                    message='VC Store LIBPATHs NOT present when MSVC_UWP_APP=1 (msvc_version=%s)' % msvc_version)

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/MSVC/PCH-source.py

#!/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 use of pre-compiled headers when the source .cpp file shows
up in both the env.PCH() and the env.Program() source list.

Issue 2505:  http://github.com/SCons/scons/issues/2505
"""

import TestSCons

test = TestSCons.TestSCons()

test.skip_if_not_msvc()

test.write('SConstruct', """\
env = Environment(tools=['msvc', 'mslink'])
env['PCH'] = env.PCH('Source1.cpp')[0]
env['PCHSTOP'] = 'Header1.hpp'
env.Program('foo', ['foo.cpp', 'Source2.cpp', 'Source1.cpp'])
""" % locals())

test.write('Header1.hpp', r"""
""")

test.write('Source1.cpp', r"""
#include <stdio.h>

#include "Header1.hpp"

void
Source1(void) {
    printf("Source1.cpp\n");
}
""")

test.write('Source2.cpp', r"""
#include <stdio.h>

#include "Header1.hpp"

void
Source2(void) {
    printf("Source2.cpp\n");
}
""")

test.write('foo.cpp', r"""
#include <stdio.h>

#include "Header1.hpp"

void Source1(void);
void Source2(void);

int
main(int argc, char *argv[])
{
    Source1();
    Source2();
    printf("foo.cpp\n");
}
""")

test.run(arguments = ".")

test.run(program=test.workpath('foo'+TestSCons._exe),
         stdout="Source1.cpp\nSource2.cpp\nfoo.cpp\n")



test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/MSVC/PCHCOM.py

#!/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 the ability to configure the $PCHCOM construction variable.
"""

import TestSCons

_python_ = TestSCons._python_

test = TestSCons.TestSCons()

test.file_fixture('mycompile.py')

test.write('SConstruct', """
env = Environment(tools=['default', 'msvc'],
                  PCHCOM = r'%(_python_)s mycompile.py pch $TARGET $SOURCES')
env.PCH(target = 'aaa', source = 'aaa.h')
""" % locals())

test.write('aaa.h', "aaa.h\n/*pch*/\n")

test.run(arguments = ".")

test.must_match('aaa.pch', "aaa.h\n")

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/MSVC/PCHCOMSTR.py

#!/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 the $PCHCOMSTR construction variable allows you to customize
the displayed string when pch is called.
"""

import TestSCons

_python_ = TestSCons._python_

test = TestSCons.TestSCons()

test.file_fixture('mycompile.py')

test.write('SConstruct', """
env = Environment(tools=['default', 'msvc'],
                  PCHCOM = r'%(_python_)s mycompile.py pch $TARGET $SOURCES',
                  PCHCOMSTR = 'PCHing $TARGET from $SOURCE')
env.PCH(target = 'aaa', source = 'aaa.h')
""" % locals())

test.write('aaa.h', "aaa.h\n/*pch*/\n")

test.run(stdout = test.wrap_stdout("""\
PCHing aaa.pch from aaa.h
"""))

test.must_match('aaa.pch', "aaa.h\n")

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/MSVC/PCHSTOP-errors.py

#!/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 error reporting
"""


import TestSCons

test = TestSCons.TestSCons(match = TestSCons.match_re)

test.skip_if_not_msvc()

SConstruct_path = test.workpath('SConstruct')

test.write(SConstruct_path, """\
env = Environment()
env['PDB'] = File('test.pdb')
env['PCH'] = env.PCH('StdAfx.cpp')[0]
if int(ARGUMENTS.get('SET_PCHSTOP')):
    env['PCHSTOP'] = File('StdAfx.h')
env.Program('test', 'test.cpp')
""")



expect_stderr = r'''
scons: \*\*\* The PCHSTOP construction must be defined if PCH is defined.
''' + TestSCons.file_expr

test.run(arguments='SET_PCHSTOP=0', status=2, stderr=expect_stderr)



expect_stderr = r'''
scons: \*\*\* The PCHSTOP construction variable must be a string: .+
''' + TestSCons.file_expr

test.run(arguments='SET_PCHSTOP=1', status=2, stderr=expect_stderr)



test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/MSVC/RCCOM.py

#!/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 the ability to configure the $RCCOM construction variable
when using MSVC.
"""

import TestSCons

_python_ = TestSCons._python_

test = TestSCons.TestSCons()

test.file_fixture('mycompile.py')

test.write('SConstruct', """
env = Environment(tools=['default', 'msvc'],
                  RCCOM = r'%(_python_)s mycompile.py rc $TARGET $SOURCES')
env.RES(target = 'aaa', source = 'aaa.rc')
""" % locals())

test.write('aaa.rc', "aaa.rc\n/*rc*/\n")

test.run(arguments = ".")

test.must_match('aaa.res', "aaa.rc\n")

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/MSVC/RCCOMSTR.py

#!/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 the $RCCOMSTR construction variable allows you to customize
the displayed string when rc is called.
"""

import TestSCons

_python_ = TestSCons._python_

test = TestSCons.TestSCons()

test.file_fixture('mycompile.py')

test.write('SConstruct', """
env = Environment(tools=['default', 'msvc'],
                  RCCOM = r'%(_python_)s mycompile.py rc $TARGET $SOURCES',
                  RCCOMSTR = 'RCing $TARGET from $SOURCE')
env.RES(target = 'aaa', source = 'aaa.rc')
""" % locals())

test.write('aaa.rc', "aaa.rc\n/*rc*/\n")

test.run(stdout = test.wrap_stdout("""\
RCing aaa.res from aaa.rc
"""))

test.must_match('aaa.res', "aaa.rc\n")

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/MSVC/TARGET_ARCH.py

#!/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 the ability to configure the $TARGET_ARCH construction variable.
"""

import TestSCons

_python_ = TestSCons._python_

test = TestSCons.TestSCons()

test.skip_if_not_msvc()

test.write('SConstruct', """
env_64 = Environment(tools=['default', 'msvc'],
                  TARGET_ARCH = 'amd64')
env_32 = Environment(tools=['default', 'msvc'],
                  TARGET_ARCH = 'x86')
""" % locals())

test.run(arguments = ".")

# test.pass_test()

test.write('SConstruct', """
env_xx = Environment(tools=['default', 'msvc'],
                  TARGET_ARCH = 'nosucharch')
""" % locals())

test.run(arguments = ".", status=2, stderr=None)
test.must_contain_any_line(test.stderr(), "Unrecognized target architecture")
test.must_contain_any_line(test.stderr(), "Valid architectures")

test.write('SConstruct', """
env = Environment(tools=['default', 'msvc'],
                  TARGET_ARCH = 'arm', MSVC_VERSION='11.0')
if env.Detect('cl'):
    env.Command('checkarm', [], 'cl')
""" % locals())
test.run(arguments = ".", stderr = None)
if test.stderr().strip() != "" and "ARM" not in test.stderr():
    test.fail_test()

test.write('SConstruct', """
env = Environment(tools=['default', 'msvc'],
                  TARGET_ARCH = 'arm64', MSVC_VERSION='11.0')
if env.Detect('cl'):
    env.Command('checkarm64', [], 'cl')
""" % locals())
test.run(arguments = ".", stderr = None)
if test.stderr().strip() != "" and "ARM64" not in test.stderr():
    test.fail_test()

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/MSVC/VSWHERE.py

#!/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 the ability to configure the $VSWHERE construction variable.
Also test that vswhere.exe is found and sets VSWHERE to the correct values
"""
import os.path
import TestSCons

_python_ = TestSCons._python_

test = TestSCons.TestSCons()
test.verbose_set(1)

test.skip_if_not_msvc()
test.dir_fixture('VSWHERE-fixture')

test.run(arguments=".")

# Now grab info out of stdout
lines = test.stdout().splitlines()

# Debug code
# print("LINES:\n%s" % lines)

default_locations = []
detected_path = None
env_path = None
for l in lines:
    if 'VSWHERE_PATH' in l:
        path = l.strip().split('=')[-1]
        default_locations.append(path)
    elif 'VSWHERE-detect' in l:
        detected_path = l.strip().split('=')[-1]
    elif 'VSWHERE-env' in l:
        env_path = l.strip().split('=')[-1]

# Debug code
# print("VPP:%s" % default_locations)
# print("V-D:%s" % detected_path)
# print("V-E:%s" % env_path)


test.fail_test(len(default_locations) == 0,
               message='No default vswhere.exe locations found')
test.fail_test(
    detected_path is None, message='No vswhere.exe detected in default paths :%s' % default_locations)
test.fail_test(detected_path not in default_locations,
               message='detected path [%s] not in default locations[%s]' % (detected_path, default_locations))

expected_env_path = os.path.join(test.workdir, 'vswhere.exe')
test.fail_test(env_path != expected_env_path,
               message='VSWHERE not\n\t%s\n\t but\n\t%s' % (expected_env_path, env_path))


test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:

expected = r"""
PS C:\Users\Bill\AppData\Local\Temp\testcmd.11256.1ae1_as5> py -3.8 C:\Users\Bill\devel\scons\git\scons-2\scripts\scons.py
scons: Reading SConscript files ...
VSWHERE_PATH=C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe
VSWHERE_PATH=C:\Program Files\Microsoft Visual Studio\Installer\vswhere.exe
VSWHERE_PATH=C:\ProgramData\chocolatey\bin\vswhere.exe
VSWHERE-detect=C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe
Copy("C:\Users\Bill\AppData\Local\Temp\testcmd.11256.1ae1_as5\vswhere.exe", "C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe")
VSWHERE-env=C:\Users\Bill\AppData\Local\Temp\testcmd.11256.1ae1_as5\vswhere.exe
scons: done reading SConscript files.
scons: Building targets ...
scons: `.' is up to date.
scons: done building targets.
"""


# test/MSVC/batch-longlines.py

#!/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 operation of Visual C/C++ batch builds with long lines.

Only runs on Windows.
"""

import TestSCons

test = TestSCons.TestSCons()

test.skip_if_not_msvc()

_python_ = TestSCons._python_

for i in range(1,200):
    test.write('source-file-with-quite-a-long-name-maybe-unrealistic-but-who-cares-%05d.cxx'%i,
               '/* source file %d */\nint var%d;\n'%(i,i))

test.write('SConstruct', """
env = Environment(tools=['msvc', 'mslink'],
                  MSVC_BATCH=ARGUMENTS.get('MSVC_BATCH'))
env.SharedLibrary('mylib', Glob('source*.cxx'))
""" % locals())

test.run(arguments = 'MSVC_BATCH=1 .')

test.must_exist('mylib.dll')

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/MSVC/batch.py

#!/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 operation of Visual C/C++ batch builds.

This uses a fake compiler and linker script, fake command lines, and
explicit suffix settings so that the test should work when run on any
platform.
"""

import os
import TestSCons

test = TestSCons.TestSCons()

_python_ = TestSCons._python_

test.write('fake_cl.py', """\
import os
import sys
input_files = sys.argv[2:]
if sys.argv[1][-1] in (os.sep, '\\\\'):
    # The output (/Fo) argument ends with a backslash, indicating an
    # output directory.  We accept ending with a slash as well so this
    # test runs on non-Windows systems.  Strip either character and
    # record the directory name.
    sys.argv[1] = sys.argv[1][:-1]
    dir = sys.argv[1][3:]
else:
    dir = None
    output = sys.argv[1][3:]
# Delay writing the .log output until here so any trailing slash or
# backslash has been stripped, and the output comparisons later in this
# script don't have to account for the difference.
with open('fake_cl.log', 'a') as ofp:
    ofp.write(" ".join(sys.argv[1:]) + '\\n')
for infile in input_files:
    if dir:
        outfile = os.path.join(dir, infile.replace('.c', '.obj'))
    else:
        outfile = output
    with open(outfile, 'w') as ofp:
        with open(infile, 'r') as ifp:
            ofp.write(ifp.read())
""")

test.write('fake_link.py', """\
import sys
with open(sys.argv[1], 'w') as ofp:
    for infile in sys.argv[2:]:
        with open(infile, 'r') as ifp:
            ofp.write(ifp.read())
""")

test.write('SConstruct', """
DefaultEnvironment(tools=[])
cccom = r'%(_python_)s fake_cl.py $_MSVC_OUTPUT_FLAG $CHANGED_SOURCES'
linkcom = r'%(_python_)s fake_link.py ${TARGET.windows} $SOURCES'
env = Environment(tools=['msvc', 'mslink'],
                  CCCOM=cccom, 
                  LINKCOM=linkcom,
                  PROGSUFFIX='.exe',
                  OBJSUFFIX='.obj',
                  MSVC_BATCH=ARGUMENTS.get('MSVC_BATCH'))
p = env.Object('prog.c')
f1 = env.Object('f1.c')
f2 = env.Object('f2.c')
env.Program(p + f1 + f2)
""" % locals())

test.write('prog.c', "prog.c\n")
test.write('f1.c', "f1.c\n")
test.write('f2.c', "f2.c\n")



test.run(arguments = 'MSVC_BATCH=1 .')

test.must_match('prog.exe', "prog.c\nf1.c\nf2.c\n", mode='r')
test.must_match('fake_cl.log', """\
/Fo.%s prog.c f1.c f2.c
"""%os.sep, mode='r')

test.up_to_date(options = 'MSVC_BATCH=1', arguments = '.')



test.write('f1.c', "f1.c 2\n")

test.run(arguments = 'MSVC_BATCH=1 .')

test.must_match('prog.exe', "prog.c\nf1.c 2\nf2.c\n", mode='r')
test.must_match('fake_cl.log', """\
/Fo.%s prog.c f1.c f2.c
/Fo.%s f1.c
"""%(os.sep, os.sep), mode='r')

test.up_to_date(options = 'MSVC_BATCH=1', arguments = '.')



test.run(arguments = '-c .')

test.unlink('fake_cl.log')



test.run(arguments = '. MSVC_BATCH=0')

test.must_match('prog.exe', "prog.c\nf1.c 2\nf2.c\n", mode='r')
test.must_match('fake_cl.log', """\
/Fof1.obj f1.c
/Fof2.obj f2.c
/Foprog.obj prog.c
""", mode='r')

test.run(arguments = '-c .')
test.unlink('fake_cl.log')


test.run(arguments = '. MSVC_BATCH=False')

test.must_match('prog.exe', "prog.c\nf1.c 2\nf2.c\n", mode='r')
test.must_match('fake_cl.log', """\
/Fof1.obj f1.c
/Fof2.obj f2.c
/Foprog.obj prog.c
""", mode='r')



test.write('f1.c', "f1.c 3\n")

test.run(arguments = '. MSVC_BATCH=0')

test.must_match('prog.exe', "prog.c\nf1.c 3\nf2.c\n", mode='r')
test.must_match('fake_cl.log', """\
/Fof1.obj f1.c
/Fof2.obj f2.c
/Foprog.obj prog.c
/Fof1.obj f1.c
""", mode='r')



test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/MSVC/embed-manifest.py

#!/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 manifest files get embedded correctly in EXEs and DLLs
"""

import TestSCons

_exe = TestSCons._exe
_dll = TestSCons._dll
_lib = TestSCons._lib

test = TestSCons.TestSCons()

test.skip_if_not_msvc()

test.write('SConstruct', """\
env=Environment(WINDOWS_EMBED_MANIFEST=True)
env.Append(CCFLAGS = '/MD')
env.Append(LINKFLAGS = '/MANIFEST')
env.Append(SHLINKFLAGS = '/MANIFEST')
exe=env.Program('test.cpp')
dll=env.SharedLibrary('testdll.cpp')
env.Command('exe-extracted.manifest', exe,
  '$MT /nologo -inputresource:${SOURCE};1 -out:${TARGET}')
env.Command('dll-extracted.manifest', dll,
  '$MT /nologo -inputresource:${SOURCE};2 -out:${TARGET}')
env2=Environment(WINDOWS_EMBED_MANIFEST=True) # no /MD here
env2.Program('test-nomanifest', env2.Object('test-nomanifest', 'test.cpp'))
""")

test.write('test.cpp', """\
#include <stdio.h>
#include <stdlib.h>
int
main(int argc, char *argv)
{
    printf("test.cpp\\n");
    exit (0);
}
""")

test.write('testdll.cpp', """\
#include <stdio.h>
#include <stdlib.h>

__declspec(dllexport) int
testdll(int argc, char *argv)
{
    printf("testdll.cpp\\n");
    return 0;
}
""")

test.run(arguments='.')

test.must_exist('test%s' % _exe)
test.must_exist('test%s.manifest' % _exe)
test.must_contain('exe-extracted.manifest', '</assembly>', mode='r')
test.must_exist('testdll%s' % _dll)
test.must_exist('testdll%s.manifest' % _dll)
test.must_contain('dll-extracted.manifest', '</assembly>', mode='r')

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/MSVC/generate-rc.py

#!/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 adding a src_builder to the RES builder so that RC files can
be generated.
"""

import TestSCons

_python_ = TestSCons._python_

test = TestSCons.TestSCons()

fake_rc = test.workpath('fake_rc.py')

test.write(fake_rc, """\
import sys
with open(sys.argv[1], 'w') as fo, open(sys.argv[2], 'r') as fi:
    fo.write("fake_rc.py\\n" + fi.read())
""")

test.write('SConstruct', """
def generate_rc(target, source, env):
    t = str(target[0])
    s = str(source[0])
    with open(t, 'w') as fo, open(s, 'r') as fi:
        fo.write('generate_rc\\n' + fi.read())

env = Environment(tools=['msvc'],
                  RCCOM=r'%(_python_)s %(fake_rc)s $TARGET $SOURCE')
env['BUILDERS']['GenerateRC'] = Builder(action=generate_rc,
                                        suffix='.rc',
                                        src_suffix='.in')
env['BUILDERS']['RES'].src_builder.append('GenerateRC')

env.RES('my.in')
""" % locals())

test.write('my.in', "my.in\n")

test.run(arguments = '.')

test.must_match('my.rc', "generate_rc\nmy.in\n", mode='r')
test.must_match('my.res', "fake_rc.py\ngenerate_rc\nmy.in\n", mode='r')

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/MSVC/hierarchical.py

#!/usr/bin/env python
#
# MIT License
#
# Copyright The SCons Foundation
#
# 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 use of Visual Studio with a hierarchical build.
"""

import TestSCons

test = TestSCons.TestSCons(match = TestSCons.match_re)

test.skip_if_not_msvc()

test.subdir('src', 'build', 'out')

test.write('SConstruct', """
DefaultEnvironment(tools=[])
VariantDir('build', 'src', duplicate=0)
SConscript('build/SConscript')
""")

test.write('src/SConscript',"""
# TODO:  this is order-dependent (putting 'mssdk' second or third breaks),
# and ideally we shouldn't need to specify the tools= list anyway.
env = Environment(tools=['mssdk', 'msvc', 'mslink'])
env['PCH'] = File('StdAfx.pch')
env['PDB'] = '#out/test.pdb'
env['PCHSTOP'] = 'StdAfx.h'
env.PCH('StdAfx.cpp')
env.Program('#out/test.exe', 'test.cpp')
""")

test.write('src/test.cpp', '''
#include "StdAfx.h"

int main(void) 
{ 
    return 1;
}
''')

test.write('src/StdAfx.h', '''
#include <windows.h>
''')

test.write('src/StdAfx.cpp', '''
#include "StdAfx.h"
''')

test.run(arguments='out', stderr=None)

test.must_exist(test.workpath('out/test.pdb'))
test.must_exist(test.workpath('build/StdAfx.pch'))
test.must_exist(test.workpath('build/StdAfx.obj'))

test.run(arguments='-c out')

test.must_not_exist(test.workpath('out/test.pdb'))
test.must_not_exist(test.workpath('build/StdAfx.pch'))
test.must_not_exist(test.workpath('build/StdAfx.obj'))



test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/MSVC/mssdk.py

#!/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.

"""
Simple test to make sure mssdk works.
"""

__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"


import TestSCons

test = TestSCons.TestSCons()

test.skip_if_not_msvc()

#####
# Test the basics

test.write('SConstruct',"""
import os
DefaultEnvironment(tools=[])
# TODO:  this is order-dependent (putting 'mssdk' second or third breaks),
# and ideally we shouldn't need to specify the tools= list anyway.
env = Environment(tools=['mssdk', 'msvc', 'mslink'])
env.Tool('mssdk')

""")


#  Visual Studio 8 has deprecated the /Yd option and prints warnings
#  about it, so ignore stderr when running SCons.
test.run(stderr=None, stdout=None)


test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/MSVC/msvc.py

#!/usr/bin/env python
#
# MIT License
#
# Copyright The SCons Foundation
#
# 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 basic invocation of Microsoft Visual C/C++, including use
of a precompiled header with the $CCFLAGS variable.
"""


import time

import TestSCons

test = TestSCons.TestSCons(match = TestSCons.match_re)

test.skip_if_not_msvc()

test.dir_fixture('msvc_fixture')

#####
# Test the basics

#  Visual Studio 8 has deprecated the /Yd option and prints warnings
#  about it, so ignore stderr when running SCons.

test.run(arguments='test.exe', stderr=None)

test.must_exist(test.workpath('test.exe'))
test.must_exist(test.workpath('test.res'))
test.must_exist(test.workpath('test.pdb'))
test.must_exist(test.workpath('StdAfx.pch'))
test.must_exist(test.workpath('StdAfx.obj'))

test.run(program=test.workpath('test.exe'), stdout='2001 test 1\n')

test.write('resource.h', '''
#define IDS_TEST 2002
''')
test.run(arguments='test.exe', stderr=None)
test.run(program=test.workpath('test.exe'), stdout='2002 test 1\n')

test.write('test.rc', '''
#include "resource.h"

STRINGTABLE DISCARDABLE 
BEGIN
    IDS_TEST "test 2"
END
''')
test.run(arguments='test.exe', stderr=None)
test.run(program=test.workpath('test.exe'), stdout='2002 test 2\n')

test.run(arguments='-c .')

test.must_not_exist(test.workpath('test.exe'))
test.must_not_exist(test.workpath('test.pdb'))
test.must_not_exist(test.workpath('test.res'))
test.must_not_exist(test.workpath('StdAfx.pch'))
test.must_not_exist(test.workpath('StdAfx.obj'))

test.run(arguments='test.exe', stderr=None)

test.must_exist(test.workpath('test.pdb'))
test.must_exist(test.workpath('StdAfx.pch'))
test.must_exist(test.workpath('StdAfx.obj'))

test.run(arguments='-c test.pdb')
test.must_not_exist(test.workpath('test.exe'))
test.must_not_exist(test.workpath('test.obj'))
test.must_not_exist(test.workpath('test.pdb'))
test.must_not_exist(test.workpath('StdAfx.pch'))
test.must_not_exist(test.workpath('StdAfx.obj'))

test.run(arguments='StdAfx.pch', stderr=None)

test.must_not_exist(test.workpath('test.pdb'))
test.must_exist(test.workpath('StdAfx.pch'))
test.must_exist(test.workpath('StdAfx.obj'))

test.run(arguments='-c test.exe')
test.must_not_exist(test.workpath('test.exe'))
test.must_not_exist(test.workpath('test.obj'))
test.must_not_exist(test.workpath('test.pdb'))
test.must_not_exist(test.workpath('StdAfx.pch'))
test.must_not_exist(test.workpath('StdAfx.obj'))

test.run(arguments='test.obj', stderr=None)
test.must_not_exist(test.workpath('test.pdb'))
test.must_exist(test.workpath('test.obj'))


start = time.perf_counter()
test.run(arguments='fast.obj', stderr=None)
fast = time.perf_counter() - start

start = time.perf_counter()
test.run(arguments='slow.obj', stderr=None)
slow = time.perf_counter() - start


# TODO: Reevaluate if having this part of the test makes sense any longer
# using precompiled headers should be faster
limit = slow*0.90
if fast >= limit:
    print("Using precompiled headers was not fast enough:")
    print("slow.obj:  %.3fs" % slow)
    print("fast.obj:  %.3fs (expected less than %.3fs)" % (fast, limit))
    test.fail_test()

# Modifying resource.h should cause both the resource and precompiled header to be rebuilt:
test.write('resource.h', '''
#define IDS_TEST 2003
''')

test.not_up_to_date(arguments='test.res', stderr=None)
test.not_up_to_date(arguments='StdAfx.pch', stderr=None)
test.not_up_to_date(arguments='test.exe', stderr=None)
test.run(program=test.workpath('test.exe'), stdout='2003 test 2\n')



test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/MSVC/msvc_badversion.py

#!/usr/bin/env python
#
# MIT License
#
# Copyright The SCons Foundation
#
# 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.

"""
Test scons with an invalid MSVC version when at least one MSVC is present.
"""

import sys

import TestSCons
import SCons.Tool.MSCommon.vc as msvc

test = TestSCons.TestSCons()

if sys.platform != 'win32':
    test.skip_test("Not win32 platform. Skipping test\n")

test.skip_if_not_msvc()

installed_msvc_versions = msvc.get_installed_vcs()
# MSVC guaranteed to be at least one version on the system or else
# skip_if_not_msvc() function would have skipped the test

test.write('SConstruct', """\
DefaultEnvironment(tools=[])
env = Environment(MSVC_VERSION='12.9')
""")
test.run(arguments='-Q -s', stdout='')

test.write('SConstruct', """\
DefaultEnvironment(tools=[])
env = Environment(MSVC_VERSION='12.9', MSVC_NOTFOUND_POLICY='ignore')
""")
test.run(arguments='-Q -s', stdout='')

test.write('SConstruct', """\
DefaultEnvironment(tools=[])
env = Environment(MSVC_VERSION='12.9', MSVC_NOTFOUND_POLICY='warning')
""")
test.run(arguments='-Q -s', stdout='')

test.write('SConstruct', """\
DefaultEnvironment(tools=[])
env = Environment(MSVC_VERSION='12.9', MSVC_NOTFOUND_POLICY='error')
""")
test.run(arguments='-Q -s', status=2, stderr=r"^.*MSVCVersionNotFound.+", match=TestSCons.match_re_dotall)

test.write('SConstruct', """\
env = Environment(MSVC_VERSION='12.9', MSVC_NOTFOUND_POLICY='bad_value')
""")
test.run(arguments='-Q -s', status=2, stderr=r"^.* Value specified for MSVC_NOTFOUND_POLICY.+", match=TestSCons.match_re_dotall)


test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/MSVC/multiple-pdb.py

#!/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 setting $PDB to '${TARGET}.pdb allows us to build multiple
programs with separate .pdb files from the same environment.

Under the covers, this verifies that emitters support expansion of the
$TARGET variable (and implicitly $SOURCE), using the original specified
list(s).
"""

import TestSCons

_exe = TestSCons._exe

test = TestSCons.TestSCons()

test.skip_if_not_msvc()

test.write('SConstruct', """\
env = Environment(PDB = '${TARGET.base}.pdb')
env.Program('test1.cpp')
env.Program('test2.cpp')
""")

test.write('test1.cpp', """\
#include <stdio.h>
#include <stdlib.h>
int
main(int argc, char *argv)
{
    printf("test1.cpp\\n");
    exit (0);
}
""")

test.write('test2.cpp', """\
#include <stdio.h>
#include <stdlib.h>
int
main(int argc, char *argv)
{
    printf("test2.cpp\\n");
    exit (0);
}
""")

test.run(arguments = '.')

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()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/MSVC/no_msvc.py

#!/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 scons when no MSVCs are present.
"""

import sys

import TestSCons

test = TestSCons.TestSCons()

if sys.platform != 'win32':
    test.skip_test("Not win32 platform. Skipping test\n")

# test find_vc_pdir_vswhere by removing all other VS's reg keys
test.file_fixture('no_msvc/no_regs_sconstruct.py', 'SConstruct')
test.run(arguments='-Q -s', stdout='')

# test no msvc's
test.file_fixture('no_msvc/no_msvcs_sconstruct.py', 'SConstruct')
test.run(arguments='-Q -s')

if 'MSVC_VERSION=None' not in test.stdout():
    test.fail_test()

# test msvc version number request with no msvc's
test.file_fixture('no_msvc/no_msvcs_sconstruct_version.py', 'SConstruct')
test.run(arguments='-Q -s', status=2, stderr=r"^.*MSVCVersionNotFound.+", match=TestSCons.match_re_dotall)

# test that MSVCVersionNotFound is not raised for default msvc tools
# when a non-msvc tool list is used
test.subdir('site_scons', ['site_scons', 'site_tools'])

test.write(['site_scons', 'site_tools', 'myignoredefaultmsvctool.py'], """
import SCons.Tool
def generate(env):
    env['MYIGNOREDEFAULTMSVCTOOL']='myignoredefaultmsvctool'
def exists(env):
    return 1
""")

test.file_fixture('no_msvc/no_msvcs_sconstruct_tools.py', 'SConstruct')
test.run(arguments='-Q -s')

test.pass_test()



# test/MSVC/pch-basics.py

#!/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 PCH works to build a simple exe and a simple dll.
"""
 
 
import TestSCons
 
test = TestSCons.TestSCons(match = TestSCons.match_re)
 
test.skip_if_not_msvc()
 
test.write('Main.cpp', """\
#include "Precompiled.h"
 
int main(void)
{
    return testf();
}
""")
 
test.write('Precompiled.cpp', """\
#include "Precompiled.h"
""")
 
test.write('Precompiled.h', """\
#pragma once
 
static int testf()
{
    return 0;
}
""")
 
test.write('SConstruct', """\
env = Environment()
 
env['PCHSTOP'] = 'Precompiled.h'
env['PCH'] = env.PCH('Precompiled.cpp')[0]
 
env.SharedLibrary('pch_dll', 'Main.cpp')
env.Program('pch_exe', 'Main.cpp')
""")
 
test.run(arguments='.', stderr=None)
 
test.pass_test()
 
# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/MSVC/pch-spaces-subdir.py

#!/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 PCH works if variant dir has spaces in its name
"""


import TestSCons

test = TestSCons.TestSCons(match = TestSCons.match_re)

test.skip_if_not_msvc()

test.write('Main.cpp', """\
#include "Precompiled.h"

int main(void)
{
    return testf();
}
""")

test.write('Precompiled.cpp', """\
#include "Precompiled.h"
""")

test.write('Precompiled.h', """\
#pragma once

static int testf()
{
    return 0;
}
""")

test.write('SConstruct', """\
SConscript('SConscript', variant_dir='Release Output', duplicate=0)
""")

test.write('SConscript', """\
DefaultEnvironment(tools=[])
env = Environment()

env['PCHSTOP'] = 'Precompiled.h'
env['PCH'] = env.PCH('Precompiled.cpp')[0]

env.Program('Main.cpp')
""")

test.run(arguments='.', stderr=None)

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/MSVC/pdb-VariantDir-path.py

#!/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 .pdb files get put in a variant_dir correctly.
"""

import TestSCons

_exe = TestSCons._exe

test = TestSCons.TestSCons()

test.skip_if_not_msvc()

test.subdir('src')

test.write('SConstruct', """\
env = Environment()
env.Append(BINDIR = '#bin')

Export('env')
SConscript('#src/SConscript', duplicate = 0, variant_dir = '#.build')
""")

test.write(['src', 'SConscript'], """\
Import('env')
env['PDB'] = '${TARGET}.pdb'
p = env.Program('test.exe', 'test.cpp')
env.Install(env['BINDIR'], p)
""")

test.write(['src', 'test.cpp'], """\
#include <stdio.h>
#include <stdlib.h>
int
main(int argc, char *argv)
{
    printf("test.cpp\\n");
    exit (0);
}
""")

test.run(arguments = '.')

test.must_exist(['.build', 'test%s'     % _exe])
test.must_exist(['.build', 'test%s.pdb' % _exe])

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/MSVC/pdb-manifest.py

#!/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 .pdb files work correctly in conjunction with manifest files.
"""

import TestSCons

_exe = TestSCons._exe
_dll = TestSCons._dll
_lib = TestSCons._lib

test = TestSCons.TestSCons()

test.skip_if_not_msvc()

test.write('SConstruct', """\
env = Environment()

env['WINDOWS_INSERT_DEF'] = True
env['WINDOWS_INSERT_MANIFEST'] = True
env['PDB'] = '${TARGET.base}.pdb'
env.Program('test', 'test.cpp')
env.SharedLibrary('sharedlib', 'test.cpp')
env.StaticLibrary('staticlib', 'test.cpp')
""")

test.write('test.cpp', """\
#include <stdio.h>
#include <stdlib.h>
int
main(int argc, char *argv)
{
    printf("test.cpp\\n");
    exit (0);
}
""")

test.write('sharedlib.def', """\
""")

test.run(arguments = '.')

test.must_exist('test%s' % _exe)
test.must_exist('test.pdb')

test.must_exist('sharedlib%s' % _dll)
test.must_exist('sharedlib.pdb')

test.must_exist('staticlib%s' % _lib)
test.must_not_exist('staticlib.pdb')

test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/MSVC/query_vcbat.py

#
# __COPYRIGHT__
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#

__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"

import TestSCons

test = TestSCons.TestSCons(match = TestSCons.match_re)

test.skip_if_not_msvc()

#####
# Test the basics

test.write('SConstruct', """
#from SCons.Tool.MSCommon.misc import FindMSVSBatFile, \\
#                                       ParseBatFile, \\
#                                       MergeMSVSBatFile
from SCons.Tool.MSCommon import query_versions
#env = Environment(tools = ['mingw'])
DefaultEnvironment(tools = [])
#for v in [9, 8, 7.1, 7]:
#    print " ==== Testing for version %s ==== " % str(v)
#    bat = FindMSVSBatFile(v)
#    print bat
#    if bat:
#        d = ParseBatFile(bat)
#        for k, v in d.items():
#            print k, v
#MergeMSVSBatFile(env, 9.0)
#print(env['ENV']['PATH'])
print(query_versions())
""")

test.run(stderr = None)
test.pass_test()

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:


# test/MSVC/MSVC_SDK_VERSION.py
# MIT License
#
# Copyright The SCons Foundation
#
# 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.

"""
Test the MSVC_SDK_VERSION construction variable.
"""

import TestSCons

test = TestSCons.TestSCons()

test.skip_if_not_msvc()

import textwrap

from SCons.Tool.MSCommon.vc import get_installed_vcs_components
from SCons.Tool.MSCommon import msvc_sdk_versions
from SCons.Tool.MSCommon import msvc_toolset_versions

installed_versions = get_installed_vcs_components()

default_version = installed_versions[0]

GE_VS2015_versions = [v for v in installed_versions if v.msvc_vernum >= 14.0]
LT_VS2015_versions = [v for v in installed_versions if v.msvc_vernum < 14.0]

default_sdk_versions_uwp = msvc_sdk_versions(msvc_version=None, msvc_uwp_app=True)
default_sdk_versions_def = msvc_sdk_versions(msvc_version=None, msvc_uwp_app=False)

have_140 = any([v.msvc_verstr == '14.0' for v in GE_VS2015_versions])

def version_major(version):
    components = version.split('.')
    if len(components) >= 2:
        return components[0] + '.' + components[1][0]
    if len(components) == 1:
        return components[0] + '.0'
    return version

def version_major_list(version_list):
    versions = []
    seen_major = set()
    for version in version_list:
        major = version_major(version)
        if major in seen_major:
            continue
        versions.append(version)
        seen_major.add(major)
    return versions

if GE_VS2015_versions:

    for supported in GE_VS2015_versions:

        sdk_versions_uwp = msvc_sdk_versions(msvc_version=supported.msvc_version, msvc_uwp_app=True)
        sdk_versions_def = msvc_sdk_versions(msvc_version=supported.msvc_version, msvc_uwp_app=False)

        # find sdk version for each major SDK
        sdk_versions = version_major_list(sdk_versions_def)

        for sdk_version in sdk_versions:

            # sdk version construction variable
            test.write('SConstruct', textwrap.dedent(
                """
                DefaultEnvironment(tools=[])
                env = Environment(MSVC_VERSION={}, MSVC_SDK_VERSION={}, tools=['msvc'])
                """.format(repr(supported.msvc_version), repr(sdk_version))
            ))
            test.run(arguments='-Q -s', stdout='')

            # sdk version script argument
            test.write('SConstruct', textwrap.dedent(
                """
                DefaultEnvironment(tools=[])
                env = Environment(MSVC_VERSION={}, MSVC_SCRIPT_ARGS={}, tools=['msvc'])
                """.format(repr(supported.msvc_version), repr(sdk_version))
            ))
            test.run(arguments='-Q -s', stdout='')

            # sdk version construction variable and script argument
            test.write('SConstruct', textwrap.dedent(
                """
                DefaultEnvironment(tools=[])
                env = Environment(MSVC_VERSION={}, MSVC_SDK_VERSION={}, MSVC_SCRIPT_ARGS={}, tools=['msvc'])
                """.format(repr(supported.msvc_version), repr(sdk_version), repr(sdk_version))
            ))
            test.run(arguments='-Q -s', status=2, stderr=None)
            expect = "MSVCArgumentError: multiple sdk version declarations: MSVC_SDK_VERSION={} and MSVC_SCRIPT_ARGS={}:".format(
                repr(sdk_version), repr(sdk_version)
            )
            test.must_contain_all(test.stderr(), expect)

        # TODO: non-existent sdk version

        # sdk version is not supported
        invalid_sdk_version = '9.1'
        test.write('SConstruct', textwrap.dedent(
            """
            DefaultEnvironment(tools=[])
            env = Environment(MSVC_VERSION={}, MSVC_SDK_VERSION={}, tools=['msvc'])
            """.format(repr(supported.msvc_version), repr(invalid_sdk_version))
        ))
        test.run(arguments='-Q -s', status=2, stderr=None)
        expect = "MSVCArgumentError: MSVC_SDK_VERSION ({}) is not supported:".format(
            repr(invalid_sdk_version)
        )
        test.must_contain_all(test.stderr(), expect)

        # sdk version not found
        missing_sdk_version = '10.0.12345.6'
        test.write('SConstruct', textwrap.dedent(
            """
            DefaultEnvironment(tools=[])
            env = Environment(MSVC_VERSION={}, MSVC_SDK_VERSION={}, tools=['msvc'])
            """.format(repr(supported.msvc_version), repr(missing_sdk_version))
        ))
        test.run(arguments='-Q -s', status=2, stderr=None)
        expect = "MSVCSDKVersionNotFound: MSVC_SDK_VERSION {} not found for platform type 'Desktop':".format(
            repr(missing_sdk_version)
        )
        test.must_contain_all(test.stderr(), expect)

        # platform contraints: 8.1 and UWP
        if '8.1' in sdk_versions:

            if supported.msvc_vernum > 14.0:

                toolset_full_versions = msvc_toolset_versions(supported.msvc_version, full=True, sxs=False)
                toolset_versions = version_major_list(toolset_full_versions)

                # toolset msvc_version != current msvc_version and toolset msvc_version != 14.0
                toolset_candidates = [v for v in toolset_versions if version_major(v) not in (supported.msvc_verstr, '14.0')]
                toolset_version = toolset_candidates[0] if toolset_candidates else None

                # sdk version 8.1, UWP, and msvc_verson > VS2015
                test.write('SConstruct', textwrap.dedent(
                    """
                    DefaultEnvironment(tools=[])
                    env = Environment(MSVC_VERSION={}, MSVC_SDK_VERSION='8.1', MSVC_UWP_APP=True, tools=['msvc'])
                    """.format(repr(supported.msvc_version), repr(sdk_version))
                ))
                test.run(arguments='-Q -s', status=2, stderr=None)
                expect = "MSVCArgumentError: MSVC_SDK_VERSION ('8.1') and platform type ('UWP') constraint violation: MSVC_VERSION {} > '14.0' VS2015:".format(
                    repr(supported.msvc_version)
                )
                test.must_contain_all(test.stderr(), expect)

                if toolset_version:

                    # sdk version 8.1, UWP, and msvc_toolset_verson > VS2015
                    test.write('SConstruct', textwrap.dedent(
                        """
                        DefaultEnvironment(tools=[])
                        env = Environment(MSVC_VERSION={}, MSVC_TOOLSET_VERSION={}, MSVC_SDK_VERSION='8.1', MSVC_UWP_APP=True, tools=['msvc'])
                        """.format(repr(supported.msvc_version), repr(toolset_version), repr(sdk_version))
                        ))
                    test.run(arguments='-Q -s', status=2, stderr=None)
                    expect = "MSVCArgumentError: MSVC_SDK_VERSION ('8.1') and platform type ('UWP') constraint violation: toolset version {} > '14.0' VS2015:".format(
                        repr(toolset_version)
                    )
                    test.must_contain_all(test.stderr(), expect)

                if have_140:

                    # sdk version 8.1, UWP, and msvc_toolset_version > VS2015
                    test.write('SConstruct', textwrap.dedent(
                        """
                        DefaultEnvironment(tools=[])
                        env = Environment(MSVC_VERSION={}, MSVC_SDK_VERSION='8.1', MSVC_TOOLSET_VERSION='14.0', MSVC_UWP_APP=True, tools=['msvc'])
                        """.format(repr(supported.msvc_version), repr(sdk_version))
                    ))
                    test.run(arguments='-Q -s', stdout='')

            elif supported.msvc_vernum == 14.0:

                # sdk version 8.1, UWP, and msvc_verson == VS2015
                test.write('SConstruct', textwrap.dedent(
                    """
                    DefaultEnvironment(tools=[])
                    env = Environment(MSVC_VERSION={}, MSVC_SDK_VERSION='8.1', MSVC_UWP_APP=True, tools=['msvc'])
                    """.format(repr(supported.msvc_version), repr(sdk_version))
                ))
                test.run(arguments='-Q -s', stdout='')

if LT_VS2015_versions:

    for unsupported in LT_VS2015_versions:
        # must be VS2015 or later

        sdk_version = default_sdk_versions_def[0] if default_sdk_versions_def else '8.1'

        test.write('SConstruct', textwrap.dedent(
            """
            DefaultEnvironment(tools=[])
            env = Environment(MSVC_VERSION={}, MSVC_SDK_VERSION={}, tools=['msvc'])
            """.format(repr(unsupported.msvc_version), repr(sdk_version))
        ))
        test.run(arguments='-Q -s', status=2, stderr=None)
        expect = "MSVCArgumentError: MSVC_SDK_VERSION ({}) constraint violation: MSVC_VERSION {} < '14.0' VS2015:".format(
            repr(sdk_version), repr(unsupported.msvc_version)
        )
        test.must_contain_all(test.stderr(), expect)

        test.write('SConstruct', textwrap.dedent(
            """
            DefaultEnvironment(tools=[])
            env = Environment(MSVC_VERSION={}, MSVC_SCRIPT_ARGS={}, tools=['msvc'])
            """.format(repr(unsupported.msvc_version), repr(sdk_version))
        ))
        test.run(arguments='-Q -s', status=2, stderr=None)
        expect = "MSVCArgumentError: MSVC_SCRIPT_ARGS ({}) constraint violation: MSVC_VERSION {} < '14.0' VS2015:".format(
            repr(sdk_version), repr(unsupported.msvc_version)
        )
        test.must_contain_all(test.stderr(), expect)

test.pass_test()

