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