# test_cmake.py - Unit tests for swift_build_support.cmake -*- python -*-
#
# This source file is part of the Swift.org open source project
#
# Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
# Licensed under Apache License v2.0 with Runtime Library Exception
#
# See https://swift.org/LICENSE.txt for license information
# See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors

import os
import unittest
from argparse import Namespace

from swift_build_support.arguments import CompilerVersion
from swift_build_support.cmake import CMake, CMakeOptions
from swift_build_support.toolchain import host_toolchain


class CMakeTestCase(unittest.TestCase):

    def mock_distcc_path(self):
        """Return a path string of mock distcc executable
        """
        return os.path.join(os.path.dirname(__file__),
                            'mock-distcc')

    def default_args(self):
        """Return new args object with default values
        """
        return Namespace(host_cc="/path/to/clang",
                         host_cxx="/path/to/clang++",
                         host_libtool="/path/to/libtool",
                         enable_asan=False,
                         enable_ubsan=False,
                         enable_tsan=False,
                         enable_lsan=False,
                         enable_sanitize_coverage=False,
                         export_compile_commands=False,
                         distcc=False,
                         cmake_generator="Ninja",
                         cmake_c_launcher=None,
                         cmake_cxx_launcher=None,
                         clang_compiler_version=None,
                         clang_user_visible_version=None,
                         build_jobs=8,
                         build_args=[],
                         verbose_build=False,
                         build_ninja=False)

    def which_ninja(self, args):
        toolchain = host_toolchain()
        if toolchain.ninja is not None:
            return '/path/to/installed/ninja'
        # Maybe we'll build a ninja, maybe we wont.
        # Fake it anyway for the tests.
        return '/path/to/built/ninja'

    def cmake(self, args):
        """Return new CMake object initialized with given args
        """
        toolchain = host_toolchain()
        toolchain.cc = args.host_cc
        toolchain.cxx = args.host_cxx
        toolchain.libtool = args.host_libtool
        if args.distcc:
            toolchain.distcc = self.mock_distcc_path()
        toolchain.ninja = self.which_ninja(args)
        return CMake(args=args, toolchain=toolchain)

    def test_common_options_defaults(self):
        args = self.default_args()
        cmake = self.cmake(args)
        self.assertEqual(
            list(cmake.common_options()),
            ["-G", "Ninja",
             "-DCMAKE_C_COMPILER:PATH=/path/to/clang",
             "-DCMAKE_CXX_COMPILER:PATH=/path/to/clang++",
             "-DCMAKE_LIBTOOL:PATH=/path/to/libtool",
             "-DCMAKE_MAKE_PROGRAM=" + self.which_ninja(args)])

    def test_common_options_asan(self):
        args = self.default_args()
        args.enable_asan = True
        cmake = self.cmake(args)
        self.assertEqual(
            list(cmake.common_options()),
            ["-G", "Ninja",
             "-DLLVM_USE_SANITIZER=Address",
             "-DCMAKE_C_COMPILER:PATH=/path/to/clang",
             "-DCMAKE_CXX_COMPILER:PATH=/path/to/clang++",
             "-DCMAKE_LIBTOOL:PATH=/path/to/libtool",
             "-DCMAKE_MAKE_PROGRAM=" + self.which_ninja(args)])

    def test_common_options_ubsan(self):
        args = self.default_args()
        args.enable_ubsan = True
        cmake = self.cmake(args)
        self.assertEqual(
            list(cmake.common_options()),
            ["-G", "Ninja",
             "-DLLVM_USE_SANITIZER=Undefined",
             "-DCMAKE_C_COMPILER:PATH=/path/to/clang",
             "-DCMAKE_CXX_COMPILER:PATH=/path/to/clang++",
             "-DCMAKE_LIBTOOL:PATH=/path/to/libtool",
             "-DCMAKE_MAKE_PROGRAM=" + self.which_ninja(args)])

    def test_common_options_tsan(self):
        args = self.default_args()
        args.enable_tsan = True
        cmake = self.cmake(args)
        self.assertEqual(
            list(cmake.common_options()),
            ["-G", "Ninja",
             "-DLLVM_USE_SANITIZER=Thread",
             "-DCMAKE_C_COMPILER:PATH=/path/to/clang",
             "-DCMAKE_CXX_COMPILER:PATH=/path/to/clang++",
             "-DCMAKE_LIBTOOL:PATH=/path/to/libtool",
             "-DCMAKE_MAKE_PROGRAM=" + self.which_ninja(args)])

    def test_common_options_asan_ubsan(self):
        args = self.default_args()
        args.enable_asan = True
        args.enable_ubsan = True
        cmake = self.cmake(args)
        self.assertEqual(
            list(cmake.common_options()),
            ["-G", "Ninja",
             "-DLLVM_USE_SANITIZER=Address;Undefined",
             "-DCMAKE_C_COMPILER:PATH=/path/to/clang",
             "-DCMAKE_CXX_COMPILER:PATH=/path/to/clang++",
             "-DCMAKE_LIBTOOL:PATH=/path/to/libtool",
             "-DCMAKE_MAKE_PROGRAM=" + self.which_ninja(args)])

    def test_common_options_ubsan_tsan(self):
        args = self.default_args()
        args.enable_ubsan = True
        args.enable_tsan = True
        cmake = self.cmake(args)
        self.assertEqual(
            list(cmake.common_options()),
            ["-G", "Ninja",
             "-DLLVM_USE_SANITIZER=Undefined;Thread",
             "-DCMAKE_C_COMPILER:PATH=/path/to/clang",
             "-DCMAKE_CXX_COMPILER:PATH=/path/to/clang++",
             "-DCMAKE_LIBTOOL:PATH=/path/to/libtool",
             "-DCMAKE_MAKE_PROGRAM=" + self.which_ninja(args)])

    def test_common_options_asan_ubsan_tsan(self):
        args = self.default_args()
        args.enable_asan = True
        args.enable_ubsan = True
        args.enable_tsan = True
        cmake = self.cmake(args)
        self.assertEqual(
            list(cmake.common_options()),
            ["-G", "Ninja",
             "-DLLVM_USE_SANITIZER=Address;Undefined;Thread",
             "-DCMAKE_C_COMPILER:PATH=/path/to/clang",
             "-DCMAKE_CXX_COMPILER:PATH=/path/to/clang++",
             "-DCMAKE_LIBTOOL:PATH=/path/to/libtool",
             "-DCMAKE_MAKE_PROGRAM=" + self.which_ninja(args)])

    def test_common_options_lsan(self):
        args = self.default_args()
        args.enable_lsan = True