reference, declarationdefinition
definition → references, declarations, derived classes, virtual overrides
reference to multiple definitions → definitions
unreferenced
    1
    2
    3
    4
    5
    6
    7
    8
    9
   10
   11
   12
   13
   14
   15
   16
   17
   18
   19
   20
   21
   22
   23
   24
   25
   26
   27
   28
   29
   30
   31
   32
   33
   34
   35
   36
   37
   38
   39
   40
   41
   42
   43
   44
   45
   46
   47
   48
   49
   50
   51
   52
   53
   54
   55
   56
   57
   58
   59
   60
   61
   62
   63
   64
   65
   66
   67
   68
   69
   70
   71
   72
   73
   74
   75
   76
   77
   78
   79
   80
   81
   82
   83
   84
   85
   86
   87
   88
   89
   90
   91
   92
   93
   94
   95
   96
   97
   98
   99
  100
  101
  102
  103
  104
  105
  106
  107
  108
  109
  110
  111
  112
  113
  114
  115
  116
  117
  118
  119
  120
  121
  122
  123
  124
  125
  126
  127
  128
  129
  130
  131
  132
  133
  134
  135
  136
  137
  138
  139
  140
  141
import os
from clang.cindex import Config
if 'CLANG_LIBRARY_PATH' in os.environ:
    Config.set_library_path(os.environ['CLANG_LIBRARY_PATH'])

from clang.cindex import CompilationDatabase
from clang.cindex import CompilationDatabaseError
from clang.cindex import CompileCommands
from clang.cindex import CompileCommand
import os
import gc
import unittest
import sys
from .util import skip_if_no_fspath
from .util import str_to_path


kInputsDir = os.path.join(os.path.dirname(__file__), 'INPUTS')


@unittest.skipIf(sys.platform == 'win32', "TODO: Fix these tests on Windows")
class TestCDB(unittest.TestCase):
    def test_create_fail(self):
        """Check we fail loading a database with an assertion"""
        path = os.path.dirname(__file__)

        # clang_CompilationDatabase_fromDirectory calls fprintf(stderr, ...)
        # Suppress its output.
        stderr = os.dup(2)
        with open(os.devnull, 'wb') as null:
            os.dup2(null.fileno(), 2)
        with self.assertRaises(CompilationDatabaseError) as cm:
            cdb = CompilationDatabase.fromDirectory(path)
        os.dup2(stderr, 2)
        os.close(stderr)

        e = cm.exception
        self.assertEqual(e.cdb_error,
            CompilationDatabaseError.ERROR_CANNOTLOADDATABASE)

    def test_create(self):
        """Check we can load a compilation database"""
        cdb = CompilationDatabase.fromDirectory(kInputsDir)

    def test_lookup_succeed(self):
        """Check we get some results if the file exists in the db"""
        cdb = CompilationDatabase.fromDirectory(kInputsDir)
        cmds = cdb.getCompileCommands('/home/john.doe/MyProject/project.cpp')
        self.assertNotEqual(len(cmds), 0)

    @skip_if_no_fspath
    def test_lookup_succeed_pathlike(self):
        """Same as test_lookup_succeed, but with PathLikes"""
        cdb = CompilationDatabase.fromDirectory(str_to_path(kInputsDir))
        cmds = cdb.getCompileCommands(str_to_path('/home/john.doe/MyProject/project.cpp'))
        self.assertNotEqual(len(cmds), 0)

    def test_all_compilecommand(self):
        """Check we get all results from the db"""
        cdb = CompilationDatabase.fromDirectory(kInputsDir)
        cmds = cdb.getAllCompileCommands()
        self.assertEqual(len(cmds), 3)
        expected = [
            { 'wd': '/home/john.doe/MyProject',
              'file': '/home/john.doe/MyProject/project.cpp',
              'line': ['clang++', '--driver-mode=g++', '-o', 'project.o', '-c',
                       '/home/john.doe/MyProject/project.cpp']},
            { 'wd': '/home/john.doe/MyProjectA',
              'file': '/home/john.doe/MyProject/project2.cpp',
              'line': ['clang++', '--driver-mode=g++', '-o', 'project2.o', '-c',
                       '/home/john.doe/MyProject/project2.cpp']},
            { 'wd': '/home/john.doe/MyProjectB',
              'file': '/home/john.doe/MyProject/project2.cpp',
              'line': ['clang++', '--driver-mode=g++', '-DFEATURE=1', '-o',
                       'project2-feature.o', '-c',
                       '/home/john.doe/MyProject/project2.cpp']},

            ]
        for i in range(len(cmds)):
            self.assertEqual(cmds[i].directory, expected[i]['wd'])
            self.assertEqual(cmds[i].filename, expected[i]['file'])
            for arg, exp in zip(cmds[i].arguments, expected[i]['line']):
                self.assertEqual(arg, exp)

    def test_1_compilecommand(self):
        """Check file with single compile command"""
        cdb = CompilationDatabase.fromDirectory(kInputsDir)
        file = '/home/john.doe/MyProject/project.cpp'
        cmds = cdb.getCompileCommands(file)
        self.assertEqual(len(cmds), 1)
        self.assertEqual(cmds[0].directory, os.path.dirname(file))
        self.assertEqual(cmds[0].filename, file)
        expected = [ 'clang++', '--driver-mode=g++', '-o', 'project.o', '-c',
                     '/home/john.doe/MyProject/project.cpp']
        for arg, exp in zip(cmds[0].arguments, expected):
            self.assertEqual(arg, exp)

    def test_2_compilecommand(self):
        """Check file with 2 compile commands"""
        cdb = CompilationDatabase.fromDirectory(kInputsDir)
        cmds = cdb.getCompileCommands('/home/john.doe/MyProject/project2.cpp')
        self.assertEqual(len(cmds), 2)
        expected = [
            { 'wd': '/home/john.doe/MyProjectA',
              'line': ['clang++', '--driver-mode=g++', '-o', 'project2.o', '-c',
                       '/home/john.doe/MyProject/project2.cpp']},
            { 'wd': '/home/john.doe/MyProjectB',
              'line': ['clang++', '--driver-mode=g++', '-DFEATURE=1', '-o',
                       'project2-feature.o', '-c',
                       '/home/john.doe/MyProject/project2.cpp']}
            ]
        for i in range(len(cmds)):
            self.assertEqual(cmds[i].directory, expected[i]['wd'])
            for arg, exp in zip(cmds[i].arguments, expected[i]['line']):
                self.assertEqual(arg, exp)

    def test_compilecommand_iterator_stops(self):
        """Check that iterator stops after the correct number of elements"""
        cdb = CompilationDatabase.fromDirectory(kInputsDir)
        count = 0
        for cmd in cdb.getCompileCommands('/home/john.doe/MyProject/project2.cpp'):
            count += 1
            self.assertLessEqual(count, 2)

    def test_compilationDB_references(self):
        """Ensure CompilationsCommands are independent of the database"""
        cdb = CompilationDatabase.fromDirectory(kInputsDir)
        cmds = cdb.getCompileCommands('/home/john.doe/MyProject/project.cpp')
        del cdb
        gc.collect()
        workingdir = cmds[0].directory

    def test_compilationCommands_references(self):
        """Ensure CompilationsCommand keeps a reference to CompilationCommands"""
        cdb = CompilationDatabase.fromDirectory(kInputsDir)
        cmds = cdb.getCompileCommands('/home/john.doe/MyProject/project.cpp')
        del cdb
        cmd0 = cmds[0]
        del cmds
        gc.collect()
        workingdir = cmd0.directory