1from clang.cindex import CompilationDatabase
2from clang.cindex import CompilationDatabaseError
3from clang.cindex import CompileCommands
4from clang.cindex import CompileCommand
5import os
6import gc
7
8kInputsDir = os.path.join(os.path.dirname(__file__), 'INPUTS')
9
10def test_create_fail():
11    """Check we fail loading a database with an assertion"""
12    path = os.path.dirname(__file__)
13    try:
14      cdb = CompilationDatabase.fromDirectory(path)
15    except CompilationDatabaseError as e:
16      assert e.cdb_error == CompilationDatabaseError.ERROR_CANNOTLOADDATABASE
17    else:
18      assert False
19
20def test_create():
21    """Check we can load a compilation database"""
22    cdb = CompilationDatabase.fromDirectory(kInputsDir)
23
24def test_lookup_fail():
25    """Check file lookup failure"""
26    cdb = CompilationDatabase.fromDirectory(kInputsDir)
27    assert cdb.getCompileCommands('file_do_not_exist.cpp') == None
28
29def test_lookup_succeed():
30    """Check we get some results if the file exists in the db"""
31    cdb = CompilationDatabase.fromDirectory(kInputsDir)
32    cmds = cdb.getCompileCommands('/home/john.doe/MyProject/project.cpp')
33    assert len(cmds) != 0
34
35def test_all_compilecommand():
36    """Check we get all results from the db"""
37    cdb = CompilationDatabase.fromDirectory(kInputsDir)
38    cmds = cdb.getAllCompileCommands()
39    assert len(cmds) == 3
40    expected = [
41        { 'wd': '/home/john.doe/MyProject',
42          'file': '/home/john.doe/MyProject/project.cpp',
43          'line': ['clang++', '-o', 'project.o', '-c',
44                   '/home/john.doe/MyProject/project.cpp']},
45        { 'wd': '/home/john.doe/MyProjectA',
46          'file': '/home/john.doe/MyProject/project2.cpp',
47          'line': ['clang++', '-o', 'project2.o', '-c',
48                   '/home/john.doe/MyProject/project2.cpp']},
49        { 'wd': '/home/john.doe/MyProjectB',
50          'file': '/home/john.doe/MyProject/project2.cpp',
51          'line': ['clang++', '-DFEATURE=1', '-o', 'project2-feature.o', '-c',
52                   '/home/john.doe/MyProject/project2.cpp']},
53
54        ]
55    for i in range(len(cmds)):
56        assert cmds[i].directory == expected[i]['wd']
57        assert cmds[i].filename == expected[i]['file']
58        for arg, exp in zip(cmds[i].arguments, expected[i]['line']):
59            assert arg == exp
60
61def test_1_compilecommand():
62    """Check file with single compile command"""
63    cdb = CompilationDatabase.fromDirectory(kInputsDir)
64    file = '/home/john.doe/MyProject/project.cpp'
65    cmds = cdb.getCompileCommands(file)
66    assert len(cmds) == 1
67    assert cmds[0].directory == os.path.dirname(file)
68    assert cmds[0].filename == file
69    expected = [ 'clang++', '-o', 'project.o', '-c',
70                 '/home/john.doe/MyProject/project.cpp']
71    for arg, exp in zip(cmds[0].arguments, expected):
72        assert arg == exp
73
74def test_2_compilecommand():
75    """Check file with 2 compile commands"""
76    cdb = CompilationDatabase.fromDirectory(kInputsDir)
77    cmds = cdb.getCompileCommands('/home/john.doe/MyProject/project2.cpp')
78    assert len(cmds) == 2
79    expected = [
80        { 'wd': '/home/john.doe/MyProjectA',
81          'line': ['clang++', '-o', 'project2.o', '-c',
82                   '/home/john.doe/MyProject/project2.cpp']},
83        { 'wd': '/home/john.doe/MyProjectB',
84          'line': ['clang++', '-DFEATURE=1', '-o', 'project2-feature.o', '-c',
85                   '/home/john.doe/MyProject/project2.cpp']}
86        ]
87    for i in range(len(cmds)):
88        assert cmds[i].directory == expected[i]['wd']
89        for arg, exp in zip(cmds[i].arguments, expected[i]['line']):
90            assert arg == exp
91
92def test_compilecommand_iterator_stops():
93    """Check that iterator stops after the correct number of elements"""
94    cdb = CompilationDatabase.fromDirectory(kInputsDir)
95    count = 0
96    for cmd in cdb.getCompileCommands('/home/john.doe/MyProject/project2.cpp'):
97        count += 1
98        assert count <= 2
99
100def test_compilationDB_references():
101    """Ensure CompilationsCommands are independent of the database"""
102    cdb = CompilationDatabase.fromDirectory(kInputsDir)
103    cmds = cdb.getCompileCommands('/home/john.doe/MyProject/project.cpp')
104    del cdb
105    gc.collect()
106    workingdir = cmds[0].directory
107
108def test_compilationCommands_references():
109    """Ensure CompilationsCommand keeps a reference to CompilationCommands"""
110    cdb = CompilationDatabase.fromDirectory(kInputsDir)
111    cmds = cdb.getCompileCommands('/home/john.doe/MyProject/project.cpp')
112    del cdb
113    cmd0 = cmds[0]
114    del cmds
115    gc.collect()
116    workingdir = cmd0.directory
117
118