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

"""
Testing the 'qt' tool, i.e. support for .ui files and automatic
generation of qt's moc files.
"""

import os.path
import re
import string

import TestSCons

python = TestSCons.python
_exe = TestSCons._exe
lib_ = TestSCons.lib_
_lib = TestSCons._lib
dll_ = TestSCons.dll_
_dll = TestSCons._dll
_shobj = TestSCons._shobj

test = TestSCons.TestSCons()

test.subdir( 'qt', ['qt', 'bin'], ['qt', 'include'], ['qt', 'lib'] )

# create a dummy qt installation

test.write(['qt', 'bin', 'mymoc.py'], """
import getopt
import sys
import string
import re
cmd_opts, args = getopt.getopt(sys.argv[1:], 'io:', [])
output = None
impl = 0
opt_string = ''
for opt, arg in cmd_opts:
    if opt == '-o': output = open(arg, 'wb')
    elif opt == '-i': impl = 1
    else: opt_string = opt_string + ' ' + opt
for a in args:
    contents = open(a, 'rb').read()
    subst = r'{ my_qt_symbol( "' + a + '\\\\n" ); }'
    if impl:
        contents = re.sub( r'#include.*', '', contents )
    output.write(string.replace(contents, 'Q_OBJECT', subst))
output.close()
sys.exit(0)
""" )

test.write(['qt', 'bin', 'myuic.py'], """
import os.path
import re
import sys
import string
output_arg = 0
impl_arg = 0
impl = None
source = None
for arg in sys.argv[1:]:
    if output_arg:
        output = open(arg, 'wb')
        output_arg = 0
    elif impl_arg:
        impl = arg
        impl_arg = 0
    elif arg == "-o":
        output_arg = 1
    elif arg == "-impl":
        impl_arg = 1
    else:
        if source:
            sys.exit(1)
        source = open(arg, 'rb')
        sourceFile = arg
if impl:
    output.write( '#include "' + impl + '"\\n' )
    includes = re.findall('<include.*?>(.*?)</include>', source.read())
    for incFile in includes:
        # this is valid for ui.h files, at least
        if os.path.exists(incFile):
            output.write('#include "' + incFile + '"\\n')
else:
    output.write( '#include "my_qobject.h"\\n' + source.read() + " Q_OBJECT \\n" )
output.close()
sys.exit(0)
""" )

test.write(['qt', 'include', 'my_qobject.h'], r"""
#define Q_OBJECT ;
void my_qt_symbol(const char *arg);
""")

test.write(['qt', 'lib', 'my_qobject.cpp'], r"""
#include "../include/my_qobject.h"
#include <stdio.h>
void my_qt_symbol(const char *arg) {
  printf( arg );
}
""")

test.write(['qt', 'lib', 'SConstruct'], r"""
env = Environment()
env.StaticLibrary( 'myqt', 'my_qobject.cpp' )
""")

test.run(chdir=test.workpath('qt','lib'), arguments = '.',
         stderr=TestSCons.noisy_ar,
         match=TestSCons.match_re_dotall)

QT = test.workpath('qt')
QT_LIB = 'myqt'
QT_MOC = '%s %s' % (python, test.workpath('qt','bin','mymoc.py'))
QT_UIC = '%s %s' % (python, test.workpath('qt','bin','myuic.py'))

##############################################################################
# Test cases with different operation modes

def createSConstruct(test,place):
    test.write(place, """
if ARGUMENTS.get('noqtdir', 0): QTDIR=None
else: QTDIR=r'%s'
env = Environment(QTDIR = QTDIR,
                  QT_LIB = r'%s',
                  QT_MOC = r'%s',
                  QT_UIC = r'%s',
                  tools=['default','qt'])
dup = 1
if ARGUMENTS.get('build_dir', 0):
    if ARGUMENTS.get('chdir', 0):
        SConscriptChdir(1)
    else:
        SConscriptChdir(0)
    dup=int(ARGUMENTS.get('dup', 1))
    if dup == 0:
        builddir = 'build_dup0'
        env['QT_DEBUG'] = 1
    else:
        builddir = 'build'
    BuildDir(builddir, '.', duplicate=dup)
    print builddir, dup
    sconscript = Dir(builddir).File('SConscript')
else:
    sconscript = File('SConscript')
Export("env dup")
SConscript( sconscript )
""" % (QT, QT_LIB, QT_MOC, QT_UIC))

test.subdir( 'work1', 'work2', 'work3', 'work4',
             'work5', 'work6', 'work7', 'work8',
             'work9', ['work9', 'local_include'],
             'work10', ['work10', 'sub'], ['work10', 'sub', 'local_include'],
             'work11', ['work11', 'include'], ['work11', 'ui'],
             'work12')

##############################################################################
# 1. create a moc file from a header file.

aaa_exe = 'aaa' + _exe
moc = 'moc_aaa.cc'

createSConstruct(test, ['work1', 'SConstruct'])
test.write( ['work1', 'SConscript'], """
Import("env")
env.Program(target = 'aaa', source = 'aaa.cpp')
""")

test.write(['work1', 'aaa.cpp'], r"""
#include "aaa.h"
int main() { aaa(); return 0; }
""")

test.write(['work1', 'aaa.h'], r"""
#include "my_qobject.h"
void aaa(void) Q_OBJECT;
""")

test.run(chdir='work1', arguments = aaa_exe)
test.up_to_date(chdir='work1', options = '-n', arguments=aaa_exe)

test.up_to_date(chdir='work1', options = '-n', arguments = aaa_exe)
test.write(['work1', 'aaa.h'], r"""
/* a change */
#include "my_qobject.h"
void aaa(void) Q_OBJECT;
""")
test.not_up_to_date(chdir='work1', options='-n', arguments = moc)
test.run(program = test.workpath('work1', aaa_exe), stdout = 'aaa.h\n')

test.run(chdir='work1',
         arguments = "build_dir=1 " +
                     test.workpath('work1', 'build', aaa_exe) )
test.run(chdir='work1',
         arguments = "build_dir=1 chdir=1 " +
                     test.workpath('work1', 'build', aaa_exe) )

test.fail_test( not os.path.exists(test.workpath('work1', 'build', moc)) )

test.run(chdir='work1',
         arguments = "build_dir=1 chdir=1 dup=0 " +
                     test.workpath('work1', 'build_dup0', aaa_exe) )
test.must_exist(['work1', 'build_dup0', moc],
                ['work1', 'build_dup0', aaa_exe])

##############################################################################
# 2. create .cpp, .h, moc_....cpp from .ui file

aaa_dll = dll_ + 'aaa' + _dll
moc = 'moc_aaa.cc'
cpp = 'uic_aaa.cc'
obj = os.path.splitext(cpp)[0] + _shobj
h = 'aaa.h'

createSConstruct(test, ['work2', 'SConstruct'])
test.write(['work2', 'SConscript'], """
Import("env dup")
if dup == 0: env.Append(CPPPATH=['#', '.'])
env.SharedLibrary(target = 'aaa', source = ['aaa.ui', 'useit.cpp'])
""")

test.write(['work2', 'aaa.ui'], r"""
#if defined (_WIN32) || defined(__CYGWIN__)
#define DLLEXPORT __declspec(dllexport)
#else
#define DLLEXPORT
#endif
DLLEXPORT void aaa(void)
""")

test.write(['work2', 'useit.cpp'], r"""
#include "aaa.h"
void useit() {
  aaa();
}
""")

test.run(chdir='work2', arguments = aaa_dll)
test.up_to_date(chdir='work2', options='-n',arguments = aaa_dll)
test.write(['work2', 'aaa.ui'], r"""
/* a change */
#if defined (_WIN32) || defined(__CYGWIN__)
#define DLLEXPORT __declspec(dllexport)
#else
#define DLLEXPORT
#endif
DLLEXPORT void aaa(void)
""")
test.not_up_to_date(chdir='work2', options = '-n', arguments = moc)
test.not_up_to_date(chdir='work2', options = '-n', arguments = cpp)
test.not_up_to_date(chdir='work2', options = '-n', arguments = h)
test.run(chdir='work2', arguments = aaa_dll)
test.write(['work2', 'aaa.ui'], r"""
void aaa(void)
//<include>aaa.ui.h</include>
""")
test.run(chdir='work2', arguments = aaa_dll) # test that non-existant ui.h files are ignored (as uic does)
test.write(['work2', 'aaa.ui.h'], r"""
/* test dependency to .ui.h */
""")
test.run(chdir='work2', arguments = aaa_dll)
test.write(['work2', 'aaa.ui.h'], r"""
/* changed */
""")
test.not_up_to_date(chdir='work2', options = '-n', arguments = obj)
test.not_up_to_date(chdir='work2', options = '-n', arguments = cpp)
test.not_up_to_date(chdir='work2', options = '-n', arguments = h)
test.not_up_to_date(chdir='work2', options = '-n', arguments = moc)
# clean up
test.run(chdir='work2', arguments = '-c ' + aaa_dll)

test.run(chdir='work2',
         arguments = "build_dir=1 " +
                     test.workpath('work2', 'build', aaa_dll) )
test.fail_test(not os.path.exists(test.workpath('work2','build',moc)) or
               not os.path.exists(test.workpath('work2','build',cpp)) or
               not os.path.exists(test.workpath('work2','build',h)) or
               os.path.exists(test.workpath('work2', moc)) or
               os.path.exists(test.workpath('work2', cpp)) or
               os.path.exists(test.workpath('work2', h)))
cppContents = test.read(test.workpath('work2', 'build', cpp))
test.fail_test(string.find(cppContents, '#include "aaa.ui.h"') == -1)

test.run(chdir='work2',
         arguments = "build_dir=1 chdir=1 " +
                     test.workpath('work2', 'build', aaa_dll) )
test.fail_test(not os.path.exists(test.workpath('work2','build',moc)) or
               not os.path.exists(test.workpath('work2','build',cpp)) or
               not os.path.exists(test.workpath('work2','build',h)) or
               os.path.exists(test.workpath('work2', moc)) or
               os.path.exists(test.workpath('work2', cpp)) or
               os.path.exists(test.workpath('work2', h)))

test.run(chdir='work2',
         arguments = "build_dir=1 chdir=1 dup=0 " +
                     test.workpath('work2', 'build_dup0', aaa_dll) )

test.must_exist(['work2','build_dup0',moc], 
                ['work2','build_dup0',cpp],
                ['work2','build_dup0',h])
test.must_not_exist(['work2', moc],
                    ['work2', cpp],
                    ['work2', h])

##############################################################################
# 3. create a moc file from a cpp file

lib_aaa = lib_ + 'aaa' + _lib
moc = 'aaa.moc'

createSConstruct(test, ['work3', 'SConstruct'])
test.write(['work3', 'SConscript'], """
Import("env dup")
if dup == 0: env.Append(CPPPATH=['.'])
env.StaticLibrary(target = '%s', source = ['aaa.cpp','useit.cpp'])
""" % lib_aaa)

test.write(['work3', 'aaa.h'], r"""
void aaa(void);
""")

test.write(['work3', 'aaa.cpp'], r"""
#include "my_qobject.h"
void aaa(void) Q_OBJECT
#include "%s"
""" % moc)

test.write(['work3', 'useit.cpp'], r"""
#include "aaa.h"
void useit() {
  aaa();
}
""")

test.run(chdir='work3', arguments = lib_aaa,
         stderr=TestSCons.noisy_ar,
         match=TestSCons.match_re_dotall)
test.up_to_date(chdir='work3', options = '-n', arguments = lib_aaa)
test.write(['work3', 'aaa.cpp'], r"""
#include "my_qobject.h"
/* a change */
void aaa(void) Q_OBJECT
#include "%s"
""" % moc)
test.not_up_to_date(chdir='work3', options = '-n', arguments = moc)
test.run(chdir='work3', options = '-c', arguments = lib_aaa)

test.run(chdir='work3',
         arguments = "build_dir=1 " +
                     test.workpath('work3', 'build', lib_aaa),
         stderr=TestSCons.noisy_ar,
         match=TestSCons.match_re_dotall)
test.run(chdir='work3',
         arguments = "build_dir=1 chdir=1 " +
                     test.workpath('work3', 'build', lib_aaa) )

test.fail_test(not os.path.exists(test.workpath('work3', 'build', moc)))

test.run(chdir='work3',
         arguments = "build_dir=1 dup=0 " +
                     test.workpath('work3', 'build_dup0', lib_aaa),
         stderr=TestSCons.noisy_ar,
         match=TestSCons.match_re_dotall)
test.must_exist(['work3', 'build_dup0', moc])

##############################################################################
# 4. Test with a copied environment.

createSConstruct(test, ['work4', 'SConstruct'])
test.write(['work4', 'SConscript'], """\
Import("env")
env.Append(CPPDEFINES = ['FOOBAZ'])
                                                                                
copy = env.Copy()
copy.Append(CPPDEFINES = ['MYLIB_IMPL'])
                                                                                
copy.SharedLibrary(
   target = 'MyLib',
   source = ['MyFile.cpp','MyForm.ui']
)
""")

test.write(['work4', 'MyFile.h'], r"""
void aaa(void);
""")

test.write(['work4', 'MyFile.cpp'], r"""
#include "MyFile.h"
void useit() {
  aaa();
}
""")

test.write(['work4', 'MyForm.ui'], r"""
void aaa(void)
""")

test.run(chdir='work4')
moc_MyForm = filter(lambda x: string.find(x, 'moc_MyForm') != -1,
                    string.split(test.stdout(), '\n'))
MYLIB_IMPL = filter(lambda x: string.find(x, 'MYLIB_IMPL') != -1, moc_MyForm)
if not MYLIB_IMPL:
    print "Did not find MYLIB_IMPL on moc_MyForm compilation line:"
    print test.stdout()
    test.fail_test()

##############################################################################
# 5. Test creation from a copied environment that already has QT variables.
#    This makes sure the tool initialization is re-entrant.

createSConstruct(test, ['work5', 'SConstruct'])
test.write( ['work5', 'SConscript'], """
Import("env")
env = env.Copy(tools=['qt'])
env.Program('main', 'main.cpp', CPPDEFINES=['FOO'], LIBS=[])
""")

test.write(['work5', 'main.cpp'], r"""
#include "foo5.h"
int main() { foo5(); return 0; }
""")

test.write(['qt', 'include', 'foo5.h'], """\
#include <stdio.h>
void
foo5(void)
{
#ifdef  FOO
    printf("qt/include/foo5.h\\n");
#endif
}
""")

test.run(chdir='work5')

main_exe = 'main' + _exe
test.run(program = test.workpath('work5', main_exe),
         stdout = 'qt/include/foo5.h\n')

##############################################################################
# 6. Test creation from a copied empty environment.

test.write(['work6', 'SConstruct'], """\
orig = Environment()
env = orig.Copy(QTDIR = r'%s',
                QT_LIB = r'%s',
                QT_MOC = r'%s',
                QT_UIC = r'%s',
                tools=['qt'])
env.Program('main', 'main.cpp', CPPDEFINES=['FOO'], LIBS=[])
""" % (QT, QT_LIB, QT_MOC, QT_UIC))

test.write(['work6', 'main.cpp'], r"""
#include "foo6.h"
int main() { foo6(); return 0; }
""")

test.write(['qt', 'include', 'foo6.h'], """\
#include <stdio.h>
void
foo6(void)
{
#ifdef  FOO
    printf("qt/include/foo6.h\\n");
#endif
}
""")

# we can receive warnings about a non detected qt (empty QTDIR)
# these are not critical, but maybe annoying
test.run(chdir='work6', stderr=None)

main_exe = 'main' + _exe
test.run(program = test.workpath('work6', main_exe),
         stderr = None,
         stdout = 'qt/include/foo6.h\n')

##############################################################################
# 7. look if qt is installed, and try out all builders

if os.environ.get('QTDIR', None):

    QTDIR=os.environ['QTDIR']
    

    test.write( ['work7', 'SConstruct'],"""
import os
dummy_env = Environment()
ENV = dummy_env['ENV']
try:
    PATH=ARGUMENTS['PATH']
    if ENV.has_key('PATH'):
        ENV_PATH = PATH + os.pathsep + ENV['PATH']
    else:
        Exit(0) # this is certainly a weird system :-)
except KeyError:
    ENV_PATH=ENV.get('PATH', '')

env = Environment(tools=['default','qt'],
                  ENV={'PATH':ENV_PATH,
                       'PATHEXT':os.environ.get('PATHEXT'),
                       'HOME':os.getcwd()},
                       # moc / uic want to write stuff in ~/.qt
                  CXXFILESUFFIX=".cpp")

conf = env.Configure()
if not conf.CheckLib(env.subst("$QT_LIB"), autoadd=0):
    conf.env['QT_LIB'] = 'qt-mt'
    if not conf.CheckLib(env.subst("$QT_LIB"), autoadd=0):
         Exit(0)
env = conf.Finish()
BuildDir('bld', '.')
env.Program('bld/test_realqt', ['bld/mocFromCpp.cpp',
                                'bld/mocFromH.cpp',
                                'bld/anUiFile.ui',
                                'bld/main.cpp'])
""")

    test.write( ['work7', 'mocFromCpp.h'],"""
void mocFromCpp();
""")

    test.write( ['work7', 'mocFromCpp.cpp'],"""
#include <qobject.h>
#include "mocFromCpp.h"
class MyClass1 : public QObject {
  Q_OBJECT
  public:
  MyClass1() : QObject() {};
  public slots:
  void myslot() {};
};
void mocFromCpp() {
  MyClass1 myclass;
}
#include "mocFromCpp.moc"
""")

    test.write( ['work7', 'mocFromH.h'],"""
#include <qobject.h>
class MyClass2 : public QObject {
  Q_OBJECT;
  public:
  MyClass2();
  public slots:
  void myslot();
};
void mocFromH();
""")
    
    test.write( ['work7', 'mocFromH.cpp'],"""
#include "mocFromH.h"
    
MyClass2::MyClass2() : QObject() {}
void MyClass2::myslot() {}
void mocFromH() {
  MyClass2 myclass;
}
""")
    
    test.write( ['work7', 'anUiFile.ui'],"""
<!DOCTYPE UI><UI>
<class>MyWidget</class>
<widget>
    <class>QWidget</class>
    <property name="name">
        <cstring>MyWidget</cstring>
    </property>
    <property name="caption">
        <string>MyWidget</string>
    </property>
</widget>
<includes>
    <include location="local" impldecl="in implementation">anUiFile.ui.h</include>
</includes>
<slots>
    <slot>testSlot()</slot>
</slots>
<layoutdefaults spacing="6" margin="11"/>
</UI>
""")
    test.write( ['work7', 'anUiFile.ui.h'], r"""
#include <stdio.h>
#if QT_VERSION >= 0x030100
void MyWidget::testSlot()
{
    printf("Hello World\n");
}
#endif
""")

    test.write( ['work7', 'main.cpp'], r"""
#include <qapp.h>
#include "mocFromCpp.h"
#include "mocFromH.h"
#include "anUiFile.h"
#include <stdio.h>
    
int main(int argc, char **argv) {
  QApplication app(argc, argv);
  mocFromCpp();
  mocFromH();
  MyWidget mywidget;
#if QT_VERSION >= 0x030100
  mywidget.testSlot();
#else
  printf("Hello World\n");
#endif
  return 0;
}
""")

    test.run(chdir='work7', arguments="bld/test_realqt" + _exe)
    test.run(program=test.workpath("work7", "bld", "test_realqt"),
             stdout="Hello World\n")

    QTDIR=os.environ['QTDIR']
    del os.environ['QTDIR']
    PATH=os.environ['PATH']
    os.environ['PATH']='.'

    test.run(chdir='work7', stderr=None, arguments="-c bld/test_realqt" + _exe)
    test.fail_test(not test.match_re_dotall(test.stderr(), r""".*
scons: warning: Could not detect qt, using empty QTDIR
""" + TestSCons.file_expr))

    os.environ['PATH'] = PATH

    test.run(chdir='work7', stderr=None,
             arguments="PATH=%s%sbin bld%stest_realqt%s"%(QTDIR,os.sep,os.sep,_exe))
    test.fail_test(not test.match_re(test.stderr(), (r"""
scons: warning: Could not detect qt, using moc executable as a hint \(QTDIR=%s\)
""" + TestSCons.file_expr) % re.escape(QTDIR)))

    
else:
    print "Could not find QT, skipping test(s)."

##############################################################################
# 8. test the $QT_AUTOBUILD_MOC_SOURCES variable
#
# This has been removed, but I'm leaving the test here, commented out,
# in case we ever resurrect this functionality again in the future.
#
#aaa_dll = dll_ + 'aaa' + _dll
#moc = 'moc_aaa.cc'
#
#createSConstruct(test, ['work8', 'SConstruct'])
#
#test.write(['work8', 'SConscript'], """
#Import("env")
#env = env.Copy(QT_AUTOBUILD_MOC_SOURCES = 0)
#env.SharedLibrary(target = 'aaa', source = ['aaa.ui', 'useit.cpp', 'aaa_function.cpp'])
#""")
#
#test.write(['work8', 'aaa.ui'], r"""
##if defined (_WIN32) || defined(__CYGWIN__)
##define DLLEXPORT __declspec(dllexport)
##else
##define DLLEXPORT
##endif
#DLLEXPORT void aaa(void)
#""")
#
#test.write(['work8', 'useit.cpp'], r"""
##include "aaa.h"
#void useit() {
#  aaa();
#}
#""")
#
#test.write(['work8', 'aaa_function.cpp'], r"""
##include "my_qobject.h"
##if defined (_WIN32) || defined(__CYGWIN__)
##define DLLEXPORT __declspec(dllexport)
##else
##define DLLEXPORT
##endif
#DLLEXPORT void aaa(void)
# { my_qt_symbol( "aaa_function.cpp\n" ); }
#""")
#
#test.run(chdir='work8', arguments = aaa_dll)
#
#test.must_not_exist(test.workpath('work8', moc))
#
#test.write(['work8', 'SConscript'], """
#Import("env")
#env = env.Copy(QT_AUTOBUILD_MOC_SOURCES = 1)
#env.SharedLibrary(target = 'aaa', source = ['aaa.ui', 'useit.cpp'])
#""")
#
#test.run(chdir='work8', arguments = aaa_dll)
#
#test.must_exist(test.workpath('work8', moc))

##############################################################################
# 9. test that an overwritten CPPPATH is working with generated files

# this is basically test 1, but with an additional include
aaa_exe = 'aaa' + _exe

createSConstruct(test, ['work9', 'SConstruct'])
test.write( ['work9', 'SConscript'], """
Import("env")
env.Program(target = 'aaa', source = 'aaa.cpp', CPPPATH=['$CPPPATH', './local_include'])
""")

test.write(['work9', 'aaa.cpp'], r"""
#include "aaa.h"
int main() { aaa(); return 0; }
""")

test.write(['work9', 'aaa.h'], r"""
#include "my_qobject.h"
#include "local_include.h"
void aaa(void) Q_OBJECT;
""")

test.write(['work9', 'local_include', 'local_include.h'], r"""
/* empty; just needs to be found */
""")

test.run(chdir='work9', arguments = aaa_exe)

##############################################################################
# 10. test that an appended relative CPPPATH is working with generated files

# this is basically test 9, but the include path is env.Append-ed and
# everything goes into sub directory "sub"
aaa_exe = os.path.join('sub', 'aaa' + _exe)

createSConstruct(test, ['work10', 'SConstruct'])
test.write( ['work10', 'SConscript'], r"""
SConscript('sub/SConscript')
""")

test.write( ['work10', 'sub', 'SConscript'], r"""
Import("env")
env.Append(CPPPATH=['./local_include'])
env.Program(target = 'aaa', source = 'aaa.cpp')
""")

test.write(['work10', 'sub', 'aaa.cpp'], r"""
#include "aaa.h"
int main() { aaa(); return 0; }
""")

test.write(['work10', 'sub', 'aaa.h'], r"""
#include "my_qobject.h"
#include "local_include.h"
void aaa(void) Q_OBJECT;
""")

test.write(['work10', 'sub', 'local_include', 'local_include.h'], r"""
/* empty; just needs to be found */
""")

test.run(chdir='work10', arguments = aaa_exe)

###############################################################################
# 11. test the manual QT builder calls

aaa_exe = 'aaa' + _exe

createSConstruct(test, ['work11', 'SConstruct'])
test.write( ['work11', 'SConscript'], r"""
Import("env")
sources = ['aaa.cpp', 'bbb.cpp', 'ddd.cpp', 'eee.cpp', 'main.cpp']

# normal invocation
sources.append(env.Moc('include/aaa.h'))
env.Moc('bbb.cpp')
sources.extend(env.Uic('ui/ccc.ui')[1:])

# manual target specification
sources.append(env.Moc('moc-ddd.cpp', 'include/ddd.h',
               QT_MOCHPREFIX='')) # Watch out !
env.Moc('moc_eee.cpp', 'eee.cpp')
sources.extend(env.Uic(['include/uic_fff.hpp', 'fff.cpp', 'fff.moc.cpp'],
                       'ui/fff.ui')[1:])

print map(str,sources)
env.Program(target='aaa',
            source=sources,
            CPPPATH=['$CPPPATH', './include'],
            QT_AUTOSCAN=0)
""")

test.write(['work11', 'aaa.cpp'], r"""
#include "aaa.h"
""")
                     
test.write(['work11', 'include', 'aaa.h'], r"""
#include "my_qobject.h"
void aaa(void) Q_OBJECT;
""")

test.write(['work11', 'bbb.h'], r"""
void bbb(void);
""")

test.write(['work11', 'bbb.cpp'], r"""
#include "my_qobject.h"
void bbb(void) Q_OBJECT
#include "bbb.moc"
""")

test.write(['work11', 'ui', 'ccc.ui'], r"""
void ccc(void)
""")

test.write(['work11', 'ddd.cpp'], r"""
#include "ddd.h"
""")
                     
test.write(['work11', 'include', 'ddd.h'], r"""
#include "my_qobject.h"
void ddd(void) Q_OBJECT;
""")

test.write(['work11', 'eee.h'], r"""
void eee(void);
""")

test.write(['work11', 'eee.cpp'], r"""
#include "my_qobject.h"
void eee(void) Q_OBJECT
#include "moc_eee.cpp"
""")

test.write(['work11', 'ui', 'fff.ui'], r"""
void fff(void)
""")

test.write(['work11', 'main.cpp'], r"""
#include "aaa.h"
#include "bbb.h"
#include "ui/ccc.h"
#include "ddd.h"
#include "eee.h"
#include "uic_fff.hpp"

int main() {
  aaa(); bbb(); ccc(); ddd(); eee(); fff(); return 0;
}
""")

test.run(chdir='work11', arguments = aaa_exe)

# normal invocation
test.must_exist(test.workpath('work11', 'include', 'moc_aaa.cc'))
test.must_exist(test.workpath('work11', 'bbb.moc'))
test.must_exist(test.workpath('work11', 'ui', 'ccc.h'))
test.must_exist(test.workpath('work11', 'ui', 'uic_ccc.cc'))
test.must_exist(test.workpath('work11', 'ui', 'moc_ccc.cc'))

# manual target spec.
test.must_exist(test.workpath('work11', 'moc-ddd.cpp'))
test.must_exist(test.workpath('work11', 'moc_eee.cpp'))
test.must_exist(test.workpath('work11', 'include', 'uic_fff.hpp'))
test.must_exist(test.workpath('work11', 'fff.cpp'))
test.must_exist(test.workpath('work11', 'fff.moc.cpp'))


##############################################################################
# 12. test the tool warings
createSConstruct(test, ['work12', 'SConstruct'])

test.write(['work12', 'aaa.cpp'], r"""
#include "my_qobject.h"
void aaa(void) Q_OBJECT
""")

test.write(['work12', 'SConscript'], r"""
Import("env")
import os
env.StaticLibrary('aaa.cpp')
""")

test.run(chdir='work12', stderr=None)

match12 = r"""
scons: warning: Generated moc file 'aaa.moc' is not included by 'aaa.cpp'
""" + TestSCons.file_expr

# In case 'ar' gives a warning about creating a library.
test.fail_test(not test.match_re(test.stderr(), match12) and \
               not test.match_re(test.stderr(), match12 + ".+\n"))

os.environ['QTDIR'] = QT
test.run(chdir='work12', arguments='-n noqtdir=1')

# We'd like to eliminate $QTDIR from the environment as follows:
#       del os.environ['QTDIR']
# But unfortunately, in at least some versions of Python, the Environment
# class doesn't implement a __delitem__() method to make the library
# call to actually remove the deleted variable from the *external*
# environment, so it only gets removed from the Python dictionary.
# Consequently, we need to just wipe out its value as follows>
os.environ['QTDIR'] = ''
test.run(chdir='work12', stderr=None, arguments='-n noqtdir=1')
test.fail_test(not test.match_re(test.stderr(), r"""
scons: warning: Could not detect qt, using empty QTDIR
""" + TestSCons.file_expr))

test.pass_test()