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