# -*- coding: utf-8 -*-
#                     The LLVM Compiler Infrastructure
#
# This file is distributed under the University of Illinois Open Source
# License. See LICENSE.TXT for details.

import libear
from . import make_args, check_call_and_report, create_empty_file
import unittest

import os
import os.path
import glob


class OutputDirectoryTest(unittest.TestCase):

    @staticmethod
    def run_analyzer(outdir, args, cmd):
        return check_call_and_report(
            ['scan-build', '--intercept-first', '-o', outdir] + args,
            cmd)

    def test_regular_keeps_report_dir(self):
        with libear.TemporaryDirectory() as tmpdir:
            make = make_args(tmpdir) + ['build_regular']
            outdir = self.run_analyzer(tmpdir, [], make)
            self.assertTrue(os.path.isdir(outdir))

    def test_clear_deletes_report_dir(self):
        with libear.TemporaryDirectory() as tmpdir:
            make = make_args(tmpdir) + ['build_clean']
            outdir = self.run_analyzer(tmpdir, [], make)
            self.assertFalse(os.path.isdir(outdir))

    def test_clear_keeps_report_dir_when_asked(self):
        with libear.TemporaryDirectory() as tmpdir:
            make = make_args(tmpdir) + ['build_clean']
            outdir = self.run_analyzer(tmpdir, ['--keep-empty'], make)
            self.assertTrue(os.path.isdir(outdir))


class RunAnalyzerTest(unittest.TestCase):

    @staticmethod
    def get_plist_count(directory):
        return len(glob.glob(os.path.join(directory, 'report-*.plist')))

    def test_interposition_works(self):
        with libear.TemporaryDirectory() as tmpdir:
            make = make_args(tmpdir) + ['build_regular']
            outdir = check_call_and_report(
                ['scan-build', '--plist', '-o', tmpdir, '--override-compiler'],
                make)

            self.assertTrue(os.path.isdir(outdir))
            self.assertEqual(self.get_plist_count(outdir), 5)

    def test_intercept_wrapper_works(self):
        with libear.TemporaryDirectory() as tmpdir:
            make = make_args(tmpdir) + ['build_regular']
            outdir = check_call_and_report(
                ['scan-build', '--plist', '-o', tmpdir, '--intercept-first',
                 '--override-compiler'],
                make)

            self.assertTrue(os.path.isdir(outdir))
            self.assertEqual(self.get_plist_count(outdir), 5)

    def test_intercept_library_works(self):
        with libear.TemporaryDirectory() as tmpdir:
            make = make_args(tmpdir) + ['build_regular']
            outdir = check_call_and_report(
                ['scan-build', '--plist', '-o', tmpdir, '--intercept-first'],
                make)

            self.assertTrue(os.path.isdir(outdir))
            self.assertEqual(self.get_plist_count(outdir), 5)

    @staticmethod
    def compile_empty_source_file(target_dir, is_cxx):
        compiler = '$CXX' if is_cxx else '$CC'
        src_file_name = 'test.cxx' if is_cxx else 'test.c'
        src_file = os.path.join(target_dir, src_file_name)
        obj_file = os.path.join(target_dir, 'test.o')
        create_empty_file(src_file)
        command = ' '.join([compiler, '-c', src_file, '-o', obj_file])
        return ['sh', '-c', command]

    def test_interposition_cc_works(self):
        with libear.TemporaryDirectory() as tmpdir:
            outdir = check_call_and_report(
                ['scan-build', '--plist', '-o', tmpdir, '--override-compiler'],
                self.compile_empty_source_file(tmpdir, False))
            self.assertEqual(self.get_plist_count(outdir), 1)

    def test_interposition_cxx_works(self):
        with libear.TemporaryDirectory() as tmpdir:
            outdir = check_call_and_report(
                ['scan-build', '--plist', '-o', tmpdir, '--override-compiler'],
                self.compile_empty_source_file(tmpdir, True))
            self.assertEqual(self.get_plist_count(outdir), 1)

    def test_intercept_cc_works(self):
        with libear.TemporaryDirectory() as tmpdir:
            outdir = check_call_and_report(
                ['scan-build', '--plist', '-o', tmpdir, '--override-compiler',
                 '--intercept-first'],
                self.compile_empty_source_file(tmpdir, False))
            self.assertEqual(self.get_plist_count(outdir), 1)

    def test_intercept_cxx_works(self):
        with libear.TemporaryDirectory() as tmpdir:
            outdir = check_call_and_report(
                ['scan-build', '--plist', '-o', tmpdir, '--override-compiler',
                 '--intercept-first'],
                self.compile_empty_source_file(tmpdir, True))
            self.assertEqual(self.get_plist_count(outdir), 1)
