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