# Copyright AllSeen Alliance. All rights reserved.
#
#    Permission to use, copy, modify, and/or distribute this software for any
#    purpose with or without fee is hereby granted, provided that the above
#    copyright notice and this permission notice appear in all copies.
#
#    THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
#    WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
#    MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
#    ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
#    WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
#    ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
#    OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#
import os
from os.path import basename

Import('commonenv')
Import('libcommon')

if not commonenv.has_key('GTEST_DIR'):
    print('GTEST_DIR not specified skipping common unit test build')

elif commonenv['OS'] == 'darwin' and commonenv['CPU'] in ['arm', 'armv7', 'armv7s', 'arm64',]:
    # do not even try Google test if darwin and arm
    print 'GTEST_DIR ignored when building for OS=darwin CPU=arm, skipping common unit test build'

else:
    gtest_env = commonenv.Clone();
    gtest_dir = gtest_env['GTEST_DIR']
    vars = Variables();
    vars.AddVariables(('GTEST_HOME', '', gtest_dir))
    vars.Update(gtest_env)

    if gtest_env['CXX'].startswith('clang'):
        # Suppress a clang warning in google-test code.
        gtest_env.Append(CPPFLAGS = ['-Wno-unused-private-field'])

    if gtest_dir == '/usr':
        gtest_src_base = os.path.join(gtest_dir, 'src', 'gtest')
    else:
        gtest_src_base = gtest_dir

    if gtest_env['OS_GROUP'] == 'windows':
        # gTest does not require the same CPPDEFINES as AllJoyn core.
        gtest_env.Append(CPPDEFINES = ['WIN32', '_LIB'])
        # don't use the _DEBUG define unless the /MDd compiler flag is specified
        #gtest_env.Append(CPPDEFINES = ['WIN32', '_DEBUG', '_LIB'])
        gtest_env.Append(CXXFLAGS = ['/EHsc'])
    
    if gtest_env['OS_CONF'] == 'android':
        # used by gtest to prevent use of wcscasecmp and set GTEST_HAS_STD_WSTRING=0
        gtest_env.Append(CPPDEFINES = ['ANDROID'])

    # tr1::tuple is not avalible for android or darwin
    if gtest_env['OS_CONF'] == 'android' or gtest_env['OS_CONF'] == 'darwin':
        gtest_env.Append(CPPDEFINES = ['GTEST_HAS_TR1_TUPLE=0'])

    # clone() library function is NOT available on android-x86
    if gtest_env['OS_CONF'] == 'android' and gtest_env['CPU'] == 'x86':
        gtest_env.Append(CPPDEFINES = ['GTEST_HAS_CLONE=0'])

    # Microsoft Visual Studio 2012 has a different _VARIADIC_MAX default value.
    # See: http://blogs.msdn.com/b/vcblog/archive/2011/09/12/10209291.aspx
    if gtest_env['OS_CONF'] == 'windows' and (gtest_env['MSVC_VERSION'] == '11.0' or gtest_env['MSVC_VERSION'] == '11.0Exp'):
        gtest_env.Append(CPPDEFINES = ['_VARIADIC_MAX=10'])

    # we compile with no rtti and we are not using exceptions. 
    gtest_env.Append(CPPDEFINES = ['GTEST_HAS_RTTI=0'])
    gtest_env.Append(CPPPATH = [ gtest_src_base ])
    if gtest_dir != '/usr':
        gtest_env.Append(CPPPATH = [ gtest_env.Dir('$GTEST_DIR/include') ])

    gtest_obj = gtest_env.StaticObject(target = 'gtest-all', source = [ '%s/src/gtest-all.cc' % gtest_src_base ])
    gtest_env.StaticLibrary(target = 'gtest', source = gtest_obj)

    test_src = gtest_env.Glob('*.cc')
    if gtest_env['CRYPTO'] != 'builtin':
        # Some unit tests are only valid for builtin crypto
        test_src = [ f for f in test_src if basename(str(f)) != 'CryptoRand.cc' ]

    unittest_env = gtest_env.Clone()

    gtest_dir = unittest_env['GTEST_DIR']
    if gtest_dir != '/usr':
        unittest_env.Append(CPPPATH = [gtest_dir + '/include'])

    if unittest_env['OS_GROUP'] == 'windows':
        unittest_env.Append(CXXFLAGS = ['/EHsc'])

    # we compile with no rtti and we are not using exceptions.
    unittest_env.Append(CPPDEFINES = ['GTEST_HAS_RTTI=0'])

    if unittest_env['OS_CONF'] == 'android':
        # used by gtest to prevent use of wcscasecmp and set GTEST_HAS_STD_WSTRING=0
        unittest_env.Append(CPPDEFINES = ['ANDROID'])

    if unittest_env['OS_CONF'] == 'android' or unittest_env['OS_CONF'] == 'darwin':
        unittest_env.Append(CPPDEFINES = ['GTEST_HAS_TR1_TUPLE=0'])
    if unittest_env['OS_CONF'] == 'android' and unittest_env['CPU'] == 'x86':
        unittest_env.Append(CPPDEFINES = ['GTEST_HAS_CLONE=0'])
    if unittest_env['OS_CONF'] == 'windows' and unittest_env['MSVC_VERSION'] == '11.0':
        unittest_env.Append(CPPDEFINES = ['_VARIADIC_MAX=10'])
    # path for alljoyn library file
    unittest_env.Append(LIBPATH = ['$DISTDIR/cpp/lib'])
    # gtest library file is placed in same folder as the the object files.
    unittest_env.Append(LIBPATH = ['./'])

    # using the alljoyn library to test common since the status object file is not
    # compiled till alljoyn_core is compiled.
    unittest_env.Prepend(LIBS = ['gtest', libcommon])

    # If BUILD_COMMON_STATUS is already specified then the status library is built
    # and linked into libcommon no need to repeat this build build step. If
    # BUILD_COMMON_STATUS is not specified status will not be linked with libcommon
    # because it is not built as part of the common build step. And we must add
    # status to the objs and make sure the header file can be found.
    if not unittest_env.has_key('BUILD_COMMON_STATUS'):
        status_src, status_hdr = unittest_env.Status('../Status')
        unittest_env.Append(CPPPATH = [ os.path.dirname(str(status_hdr)) ])

        objs = [ unittest_env.Object(test_src),
                 unittest_env.Object(status_src) ]
    else:
        objs = [ unittest_env.Object(test_src) ]

    unittest_prog = unittest_env.Program('cmtest', objs)
    unittest_env.Install('$TESTDIR/cpp/bin', unittest_prog)
