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