"""Unit tests for reviewbot.tools.clang."""

from __future__ import unicode_literals

import os

try:
    # Python 3.x
    from plistlib import writePlist as dump_plist
except ImportError:
    # Python 2.7
    from plistlib import dump as dump_plist

import six

from reviewbot.tools.clang import ClangTool
from reviewbot.tools.testing import (BaseToolTestCase,
                                     ToolTestCaseMetaclass,
                                     integration_test,
                                     simulation_test)
from reviewbot.utils.filesystem import tmpfiles
from reviewbot.utils.process import execute


@six.add_metaclass(ToolTestCaseMetaclass)
class ClangToolTests(BaseToolTestCase):
    """Unit tests for reviewbot.tools.clang.ClangTool."""

    tool_class = ClangTool
    tool_exe_config_key = 'clang'
    tool_exe_path = '/path/to/clang'

    @integration_test()
    @simulation_test(plist_data={
        'files': ['test.c'],
        'diagnostics': [
            {
                'description': (
                    'Called function pointer is null (null '
                    'dereference)'
                ),
                'location': {
                    'col': 5,
                    'file': 0,
                    'line': 5,
                },
            },
            {
                'description': (
                    "Value stored to 'i' during its "
                    "initialization is never read"
                ),
                'location': {
                    'col': 9,
                    'file': 0,
                    'line': 7,
                },
                'path': [
                    {
                        'kind': 'event',
                        'ranges': [[
                            {
                                'col': 9,
                                'file': 0,
                                'line': 7,
                            },
                            {
                                'col': 9,
                                'file': 0,
                                'line': 8,
                            },
                        ]],
                    },
                ],
            },
        ],
    })
    def test_execute_with_c(self):
        """Testing ClangTool.execute with C file"""
        review, review_file = self.run_tool_execute(
            filename='test.c',
            file_contents=(
                b'int main()\n'
                b'{\n'
                b'    void (*foo)(void);\n'
                b'    foo = 0;\n'
                b'    foo();\n'
                b'\n'
                b'    int i = (1 /\n'
                b'             0);\n'
                b'}\n'
            ))

        self.assertEqual(review.comments, [
            {
                'filediff_id': review_file.id,
                'first_line': 5,
                'num_lines': 1,
                'text': (
                    'Called function pointer is null (null dereference)\n'
                    '\n'
                    'Column: 5'
                ),
                'issue_opened': True,
                'rich_text': False,
            },
            {
                'filediff_id': review_file.id,
                'first_line': 7,
                'num_lines': 2,
                'text': (
                    "Value stored to 'i' during its initialization is "
                    "never read\n"
                    "\n"
                    "Column: 9"
                ),
                'issue_opened': True,
                'rich_text': False,
            },
        ])

        self.assertSpyCalledWith(
            execute,
            [
                self.tool_exe_path,
                '-S',
                '--analyze',
                '-Xanalyzer',
                '-analyzer-output=plist',
                'test.c',
                '-o',
                tmpfiles[-1],
            ],
            ignore_errors=True)

    @integration_test()
    @simulation_test(plist_data={
        'files': ['test.m'],
        'diagnostics': [
            {
                'description': (
                    "Value stored to 'i' during its initialization "
                    "is never read"
                ),
                'location': {
                    'col': 13,
                    'file': 0,
                    'line': 4,
                },
            },
            {
                'description': 'Division by zero',
                'location': {
                    'col': 19,
                    'file': 0,
                    'line': 4,
                },
                'path': [
                    {
                        'kind': 'event',
                        'ranges': [[
                            {
                                'col': 17,
                                'file': 0,
                                'line': 4,
                            },
                            {
                                'col': 21,
                                'file': 0,
                                'line': 4,
                            },
                        ]],
                    },