Home | History | Annotate | Download | only in tests
      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