1 #!/usr/bin/env python3 2 3 import os 4 import unittest 5 import sys 6 import tempfile 7 8 import_path = os.path.abspath(os.path.join(os.path.dirname(__file__), '..')) 9 import_path = os.path.abspath(os.path.join(import_path, 'utils')) 10 sys.path.insert(1, import_path) 11 12 from utils import (AOSP_DIR, read_output_content, run_abi_diff, 13 run_header_abi_dumper) 14 from module import Module 15 16 17 SCRIPT_DIR = os.path.abspath(os.path.dirname(__file__)) 18 INPUT_DIR = os.path.join(SCRIPT_DIR, 'input') 19 EXPECTED_DIR = os.path.join(SCRIPT_DIR, 'expected') 20 REF_DUMP_DIR = os.path.join(SCRIPT_DIR, 'reference_dumps') 21 22 23 def make_and_copy_reference_dumps(module, reference_dump_dir=REF_DUMP_DIR): 24 output_content = module.make_dump() 25 26 dump_dir = os.path.join(reference_dump_dir, module.arch) 27 os.makedirs(dump_dir, exist_ok=True) 28 29 dump_path = os.path.join(dump_dir, module.get_dump_name()) 30 with open(dump_path, 'w') as f: 31 f.write(output_content) 32 33 return dump_path 34 35 36 class HeaderCheckerTest(unittest.TestCase): 37 @classmethod 38 def setUpClass(cls): 39 cls.maxDiff = None 40 41 def setUp(self): 42 self.tmp_dir = None 43 44 def tearDown(self): 45 if self.tmp_dir: 46 self.tmp_dir.cleanup() 47 self.tmp_dir = None 48 49 def get_tmp_dir(self): 50 if not self.tmp_dir: 51 self.tmp_dir = tempfile.TemporaryDirectory() 52 return self.tmp_dir.name 53 54 def run_and_compare(self, input_path, expected_path, cflags=[]): 55 with open(expected_path, 'r') as f: 56 expected_output = f.read() 57 actual_output = run_header_abi_dumper(input_path, cflags) 58 self.assertEqual(actual_output, expected_output) 59 60 def run_and_compare_name(self, name, cflags=[]): 61 input_path = os.path.join(INPUT_DIR, name) 62 expected_path = os.path.join(EXPECTED_DIR, name) 63 self.run_and_compare(input_path, expected_path, cflags) 64 65 def run_and_compare_name_cpp(self, name, cflags=[]): 66 self.run_and_compare_name(name, cflags + ['-x', 'c++', '-std=c++11']) 67 68 def run_and_compare_name_c_cpp(self, name, cflags=[]): 69 self.run_and_compare_name(name, cflags) 70 self.run_and_compare_name_cpp(name, cflags) 71 72 def run_and_compare_abi_diff(self, old_dump, new_dump, lib, arch, 73 expected_return_code, flags=[]): 74 actual_output = run_abi_diff(old_dump, new_dump, arch, lib, flags) 75 self.assertEqual(actual_output, expected_return_code) 76 77 def prepare_and_run_abi_diff(self, old_ref_dump_path, new_ref_dump_path, 78 target_arch, expected_return_code, flags=[]): 79 self.run_and_compare_abi_diff(old_ref_dump_path, new_ref_dump_path, 80 'test', target_arch, 81 expected_return_code, flags) 82 83 def get_or_create_ref_dump(self, module, create): 84 if create: 85 return make_and_copy_reference_dumps(module, self.get_tmp_dir()) 86 return os.path.join(REF_DUMP_DIR, module.arch, module.get_dump_name()) 87 88 def prepare_and_run_abi_diff_all_archs(self, old_lib, new_lib, 89 expected_return_code, flags=[], 90 create_old=False, create_new=True): 91 old_modules = Module.get_test_modules_by_name(old_lib) 92 new_modules = Module.get_test_modules_by_name(new_lib) 93 self.assertEqual(len(old_modules), len(new_modules)) 94 95 for old_module, new_module in zip(old_modules, new_modules): 96 self.assertEqual(old_module.arch, new_module.arch) 97 old_ref_dump_path = self.get_or_create_ref_dump(old_module, 98 create_old) 99 new_ref_dump_path = self.get_or_create_ref_dump(new_module, 100 create_new) 101 self.prepare_and_run_abi_diff( 102 old_ref_dump_path, new_ref_dump_path, new_module.arch, 103 expected_return_code, flags) 104 105 def prepare_and_absolute_diff_all_archs(self, old_lib, new_lib): 106 old_modules = Module.get_test_modules_by_name(old_lib) 107 new_modules = Module.get_test_modules_by_name(new_lib) 108 self.assertEqual(len(old_modules), len(new_modules)) 109 110 for old_module, new_module in zip(old_modules, new_modules): 111 self.assertEqual(old_module.arch, new_module.arch) 112 old_ref_dump_path = self.get_or_create_ref_dump(old_module, False) 113 new_ref_dump_path = self.get_or_create_ref_dump(new_module, True) 114 self.assertEqual( 115 read_output_content(old_ref_dump_path, AOSP_DIR), 116 read_output_content(new_ref_dump_path, AOSP_DIR)) 117 118 def test_example1_cpp(self): 119 self.run_and_compare_name_cpp('example1.cpp') 120 121 def test_example1_h(self): 122 self.run_and_compare_name_cpp('example1.h') 123 124 def test_example2_h(self): 125 self.run_and_compare_name_cpp('example2.h') 126 127 def test_example3_h(self): 128 self.run_and_compare_name_cpp('example3.h') 129 130 def test_undeclared_types_h(self): 131 self.prepare_and_absolute_diff_all_archs( 132 'undeclared_types.h', 'undeclared_types.h') 133 134 def test_known_issues_h(self): 135 self.prepare_and_absolute_diff_all_archs( 136 'known_issues.h', 'known_issues.h') 137 138 def test_libc_and_cpp(self): 139 self.prepare_and_run_abi_diff_all_archs( 140 "libc_and_cpp", "libc_and_cpp", 0) 141 142 def test_libc_and_cpp_and_libc_and_cpp_with_unused_struct(self): 143 self.prepare_and_run_abi_diff_all_archs( 144 "libc_and_cpp", "libc_and_cpp_with_unused_struct", 0) 145 146 def test_libc_and_cpp_and_libc_and_cpp_with_unused_struct_allow(self): 147 self.prepare_and_run_abi_diff_all_archs( 148 "libc_and_cpp", "libc_and_cpp_with_unused_struct", 0, 149 ["-allow-unreferenced-changes"]) 150 151 def test_libc_and_cpp_and_libc_and_cpp_with_unused_struct_check_all(self): 152 self.prepare_and_run_abi_diff_all_archs( 153 "libc_and_cpp", "libc_and_cpp_with_unused_struct", 1, 154 ['-check-all-apis']) 155 156 def test_libc_and_cpp_with_unused_struct_and_libc_and_cpp_with_unused_cstruct( 157 self): 158 self.prepare_and_run_abi_diff_all_archs( 159 "libc_and_cpp_with_unused_struct", 160 "libc_and_cpp_with_unused_cstruct", 0, 161 ['-check-all-apis', '-allow-unreferenced-changes']) 162 163 def test_libc_and_cpp_and_libc_and_cpp_with_unused_struct_check_all_advice( 164 self): 165 self.prepare_and_run_abi_diff_all_archs( 166 "libc_and_cpp", "libc_and_cpp_with_unused_struct", 0, 167 ['-check-all-apis', '-advice-only']) 168 169 def test_libc_and_cpp_opaque_pointer_diff(self): 170 self.prepare_and_run_abi_diff_all_archs( 171 "libc_and_cpp_with_opaque_ptr_a", 172 "libc_and_cpp_with_opaque_ptr_b", 8, 173 ['-consider-opaque-types-different'], True, True) 174 175 def test_libgolden_cpp_return_type_diff(self): 176 self.prepare_and_run_abi_diff_all_archs( 177 "libgolden_cpp", "libgolden_cpp_return_type_diff", 8) 178 179 def test_libgolden_cpp_add_odr(self): 180 self.prepare_and_run_abi_diff_all_archs( 181 "libgolden_cpp", "libgolden_cpp_odr", 0, 182 ['-check-all-apis', '-allow-unreferenced-changes']) 183 184 def test_libgolden_cpp_add_function(self): 185 self.prepare_and_run_abi_diff_all_archs( 186 "libgolden_cpp", "libgolden_cpp_add_function", 4) 187 188 def test_libgolden_cpp_add_function_allow_extension(self): 189 self.prepare_and_run_abi_diff_all_archs( 190 "libgolden_cpp", "libgolden_cpp_add_function", 0, 191 ['-allow-extensions']) 192 193 def test_libgolden_cpp_add_function_and_elf_symbol(self): 194 self.prepare_and_run_abi_diff_all_archs( 195 "libgolden_cpp", "libgolden_cpp_add_function_and_unexported_elf", 196 4) 197 198 def test_libgolden_cpp_fabricated_function_ast_removed_diff(self): 199 self.prepare_and_run_abi_diff_all_archs( 200 "libgolden_cpp_add_function_sybmol_only", 201 "libgolden_cpp_add_function", 0, [], False, False) 202 203 def test_libgolden_cpp_change_function_access(self): 204 self.prepare_and_run_abi_diff_all_archs( 205 "libgolden_cpp", "libgolden_cpp_change_function_access", 8) 206 207 def test_libgolden_cpp_add_global_variable(self): 208 self.prepare_and_run_abi_diff_all_archs( 209 "libgolden_cpp", "libgolden_cpp_add_global_variable", 4) 210 211 def test_libgolden_cpp_change_global_var_access(self): 212 self.prepare_and_run_abi_diff_all_archs( 213 "libgolden_cpp_add_global_variable", 214 "libgolden_cpp_add_global_variable_private", 8) 215 216 def test_libgolden_cpp_parameter_type_diff(self): 217 self.prepare_and_run_abi_diff_all_archs( 218 "libgolden_cpp", "libgolden_cpp_parameter_type_diff", 8) 219 220 def test_libgolden_cpp_with_vtable_diff(self): 221 self.prepare_and_run_abi_diff_all_archs( 222 "libgolden_cpp", "libgolden_cpp_vtable_diff", 8) 223 224 def test_libgolden_cpp_member_diff_advice_only(self): 225 self.prepare_and_run_abi_diff_all_archs( 226 "libgolden_cpp", "libgolden_cpp_member_diff", 0, ['-advice-only']) 227 228 def test_libgolden_cpp_member_diff(self): 229 self.prepare_and_run_abi_diff_all_archs( 230 "libgolden_cpp", "libgolden_cpp_member_diff", 8) 231 232 def test_libgolden_cpp_change_member_access(self): 233 self.prepare_and_run_abi_diff_all_archs( 234 "libgolden_cpp", "libgolden_cpp_change_member_access", 8) 235 236 def test_libgolden_cpp_enum_extended(self): 237 self.prepare_and_run_abi_diff_all_archs( 238 "libgolden_cpp", "libgolden_cpp_enum_extended", 4) 239 240 def test_libgolden_cpp_enum_diff(self): 241 self.prepare_and_run_abi_diff_all_archs( 242 "libgolden_cpp", "libgolden_cpp_enum_diff", 8) 243 244 def test_libgolden_cpp_member_fake_diff(self): 245 self.prepare_and_run_abi_diff_all_archs( 246 "libgolden_cpp", "libgolden_cpp_member_fake_diff", 0) 247 248 def test_libgolden_cpp_member_integral_type_diff(self): 249 self.prepare_and_run_abi_diff_all_archs( 250 "libgolden_cpp", "libgolden_cpp_member_integral_type_diff", 8) 251 252 def test_libgolden_cpp_member_cv_diff(self): 253 self.prepare_and_run_abi_diff_all_archs( 254 "libgolden_cpp", "libgolden_cpp_member_cv_diff", 8) 255 256 def test_libgolden_cpp_unreferenced_elf_symbol_removed(self): 257 self.prepare_and_run_abi_diff_all_archs( 258 "libgolden_cpp", "libgolden_cpp_unreferenced_elf_symbol_removed", 259 16) 260 261 def test_libreproducability(self): 262 self.prepare_and_absolute_diff_all_archs( 263 "libreproducability", "libreproducability") 264 265 def test_libgolden_cpp_member_name_changed(self): 266 self.prepare_and_run_abi_diff_all_archs( 267 "libgolden_cpp", "libgolden_cpp_member_name_changed", 0) 268 269 def test_libgolden_cpp_member_function_pointer_changed(self): 270 self.prepare_and_run_abi_diff_all_archs( 271 "libgolden_cpp_function_pointer", 272 "libgolden_cpp_function_pointer_parameter_added", 8, [], 273 True, True) 274 275 def test_libgolden_cpp_internal_struct_access_upgraded(self): 276 self.prepare_and_run_abi_diff_all_archs( 277 "libgolden_cpp_internal_private_struct", 278 "libgolden_cpp_internal_public_struct", 0, [], True, True) 279 280 def test_libgolden_cpp_internal_struct_access_downgraded(self): 281 self.prepare_and_run_abi_diff_all_archs( 282 "libgolden_cpp_internal_public_struct", 283 "libgolden_cpp_internal_private_struct", 8, [], True, True) 284 285 def test_libgolden_cpp_inheritance_type_changed(self): 286 self.prepare_and_run_abi_diff_all_archs( 287 "libgolden_cpp", "libgolden_cpp_inheritance_type_changed", 8, [], 288 True, True) 289 290 def test_libpure_virtual_function(self): 291 self.prepare_and_absolute_diff_all_archs( 292 "libpure_virtual_function", "libpure_virtual_function") 293 294 def test_libc_and_cpp_in_json(self): 295 self.prepare_and_absolute_diff_all_archs( 296 "libgolden_cpp_json", "libgolden_cpp_json") 297 298 def test_libc_and_cpp_in_protobuf_and_json(self): 299 self.prepare_and_run_abi_diff_all_archs( 300 "libgolden_cpp", "libgolden_cpp_json", 0, 301 ["-input-format-old", "ProtobufTextFormat", 302 "-input-format-new", "Json"]) 303 304 def test_opaque_type_self_diff(self): 305 lsdump = os.path.join( 306 SCRIPT_DIR, "abi_dumps", "opaque_ptr_types.lsdump") 307 self.run_and_compare_abi_diff( 308 lsdump, lsdump, "libexample", "arm64", 0, 309 ["-input-format-old", "Json", "-input-format-new", "Json", 310 "-consider-opaque-types-different"]) 311 312 def test_allow_adding_removing_weak_symbols(self): 313 module_old = Module.get_test_modules_by_name("libweak_symbols_old")[0] 314 module_new = Module.get_test_modules_by_name("libweak_symbols_new")[0] 315 lsdump_old = self.get_or_create_ref_dump(module_old, False) 316 lsdump_new = self.get_or_create_ref_dump(module_new, False) 317 318 options = ["-input-format-old", "Json", "-input-format-new", "Json"] 319 320 # If `-allow-adding-removing-weak-symbols` is not specified, removing a 321 # weak symbol must be treated as an incompatible change. 322 self.run_and_compare_abi_diff( 323 lsdump_old, lsdump_new, "libweak_symbols", "arm64", 8, options) 324 325 # If `-allow-adding-removing-weak-symbols` is specified, removing a 326 # weak symbol must be fine and mustn't be a fatal error. 327 self.run_and_compare_abi_diff( 328 lsdump_old, lsdump_new, "libweak_symbols", "arm64", 0, 329 options + ["-allow-adding-removing-weak-symbols"]) 330 331 def test_linker_shared_object_file_and_version_script(self): 332 base_dir = os.path.join( 333 SCRIPT_DIR, 'integration', 'version_script_example') 334 335 cases = [ 336 'libversion_script_example', 337 'libversion_script_example_no_mytag', 338 'libversion_script_example_no_private', 339 ] 340 341 for module_name in cases: 342 module = Module.get_test_modules_by_name(module_name)[0] 343 example_lsdump_old = self.get_or_create_ref_dump(module, False) 344 example_lsdump_new = self.get_or_create_ref_dump(module, True) 345 self.run_and_compare_abi_diff( 346 example_lsdump_old, example_lsdump_new, 347 module_name, "arm64", 0, 348 ["-input-format-old", "Json", "-input-format-new", "Json"]) 349 350 351 if __name__ == '__main__': 352 unittest.main() 353