Home | History | Annotate | Download | only in tests
      1 #!/usr/bin/env python3
      2 
      3 from __future__ import print_function
      4 
      5 import os
      6 import re
      7 import subprocess
      8 import sys
      9 import unittest
     10 
     11 from .compat import TemporaryDirectory, makedirs
     12 from .ndk_toolchain import create_targets
     13 
     14 
     15 SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
     16 VNDK_DEF_TOOL = os.path.join(SCRIPT_DIR, '..', 'vndk_definition_tool.py')
     17 
     18 INPUT_DIR = os.path.join(SCRIPT_DIR, 'testdata', 'test_elfdump', 'input')
     19 EXPECTED_DIR = os.path.join(SCRIPT_DIR, 'testdata', 'test_elfdump', 'expected')
     20 test_dir_base = None
     21 
     22 
     23 def run_elf_dump(path):
     24     cmd = [sys.executable, VNDK_DEF_TOOL, 'elfdump', path]
     25     return subprocess.check_output(cmd, universal_newlines=True)
     26 
     27 
     28 class ELFDumpTest(unittest.TestCase):
     29     @classmethod
     30     def setUpClass(cls):
     31         cls.targets = create_targets()
     32 
     33         if test_dir_base:
     34             cls.test_dir_base = test_dir_base
     35         else:
     36             cls.tmp_dir = TemporaryDirectory()
     37             cls.test_dir_base = cls.tmp_dir.name
     38 
     39         cls._build_fixtures(cls.target_name)
     40 
     41 
     42     @classmethod
     43     def tearDownClass(cls):
     44         if not test_dir_base:
     45             cls.tmp_dir.cleanup()
     46 
     47 
     48     @classmethod
     49     def _build_fixtures(cls, target_name):
     50         target = cls.targets[target_name]
     51 
     52         cls.expected_dir = os.path.join(EXPECTED_DIR, target_name)
     53         cls.test_dir = os.path.join(cls.test_dir_base, target_name)
     54 
     55         makedirs(cls.test_dir, exist_ok=True)
     56 
     57         # Compile main.o.
     58         src_file = os.path.join(INPUT_DIR, 'main.c')
     59         obj_file = os.path.join(cls.test_dir, 'main.o')
     60         target.compile(obj_file, src_file, [])
     61 
     62         # Link main.out.
     63         out_file = os.path.join(cls.test_dir, 'main.out')
     64         target.link(out_file, [obj_file], ['-ldl', '-lc', '-lstdc++'])
     65 
     66         # Compile test.o.
     67         src_file = os.path.join(INPUT_DIR, 'test.c')
     68         obj_file = os.path.join(cls.test_dir, 'test.o')
     69         target.compile(obj_file, src_file, [])
     70 
     71         # Link libtest.so.
     72         out_file = os.path.join(cls.test_dir, 'libtest.so')
     73         target.link(out_file, [obj_file], ['-shared', '-lc'])
     74 
     75         # Link libtest-rpath.so.
     76         out_file = os.path.join(cls.test_dir, 'libtest-rpath.so')
     77         target.link(out_file, [obj_file],
     78                     ['-shared', '-lc', '-Wl,-rpath,$ORIGIN/../lib',
     79                      '-Wl,--disable-new-dtags'])
     80 
     81         # Link libtest-rpath-multi.so.
     82         out_file = os.path.join(cls.test_dir, 'libtest-rpath-multi.so')
     83         target.link(out_file, [obj_file],
     84                     ['-shared', '-lc', '-Wl,-rpath,/system/lib:/vendor/lib',
     85                      '-Wl,--disable-new-dtags'])
     86 
     87         # Link libtest-runpath.so.
     88         out_file = os.path.join(cls.test_dir, 'libtest-runpath.so')
     89         target.link(out_file, [obj_file],
     90                     ['-shared', '-lc', '-Wl,-rpath,$ORIGIN/../lib',
     91                      '-Wl,--enable-new-dtags'])
     92 
     93         # Link libtest-runpath-multi.so.
     94         out_file = os.path.join(cls.test_dir, 'libtest-runpath-multi.so')
     95         target.link(out_file, [obj_file],
     96                     ['-shared', '-lc', '-Wl,-rpath,/system/lib:/vendor/lib',
     97                      '-Wl,--enable-new-dtags'])
     98 
     99 
    100     def _remove_size_lines(self, lines):
    101         """Remove file size information because they may vary."""
    102         prefixes = (
    103             'FILE_SIZE\t',
    104             'RO_SEG_FILE_SIZE\t',
    105             'RO_SEG_MEM_SIZE\t',
    106             'RW_SEG_FILE_SIZE\t',
    107             'RW_SEG_MEM_SIZE\t',
    108         )
    109         patt = re.compile('|'.join('(?:' + re.escape(x) +')' for x in prefixes))
    110         return [line for line in lines if not patt.match(line)]
    111 
    112 
    113     def _assert_equal_to_file(self, expected_file_name, actual):
    114         actual = actual.splitlines(True)
    115         expected_file_path = os.path.join(self.expected_dir, expected_file_name)
    116         with open(expected_file_path, 'r') as f:
    117             expected = f.readlines()
    118         self.assertEqual(self._remove_size_lines(expected),
    119                          self._remove_size_lines(actual))
    120 
    121 
    122     def _test_main_out(self):
    123         out_file = os.path.join(self.test_dir, 'main.out')
    124         self._assert_equal_to_file('main.out.txt', run_elf_dump(out_file))
    125 
    126 
    127     def _test_libtest(self, expected_file_name, lib_name):
    128         lib_file = os.path.join(self.test_dir, lib_name)
    129         self._assert_equal_to_file(expected_file_name, run_elf_dump(lib_file))
    130 
    131 
    132 def create_target_test(target_name):
    133     def test_main(self):
    134         self._test_main_out()
    135 
    136     def test_libtest(self):
    137         self._test_libtest('libtest.so.txt', 'libtest.so')
    138 
    139     def test_libtest_rpath(self):
    140         self._test_libtest('libtest-rpath.so.txt', 'libtest-rpath.so')
    141 
    142     def test_libtest_rpath_multi(self):
    143         self._test_libtest('libtest-rpath-multi.so.txt',
    144                            'libtest-rpath-multi.so')
    145 
    146     def test_libtest_runpath(self):
    147         self._test_libtest('libtest-runpath.so.txt', 'libtest-runpath.so')
    148 
    149     def test_libtest_runpath_multi(self):
    150         self._test_libtest('libtest-runpath-multi.so.txt',
    151                            'libtest-runpath-multi.so')
    152 
    153     class_name = 'ELFDumpTest_' + target_name
    154     globals()[class_name] = type(
    155         class_name, (ELFDumpTest,),
    156         dict(test_main=test_main,
    157              test_libtest=test_libtest,
    158              test_libtest_rpath=test_libtest_rpath,
    159              test_libtest_rpath_multi=test_libtest_rpath_multi,
    160              test_libtest_runpath=test_libtest_runpath,
    161              test_libtest_runpath_multi=test_libtest_runpath_multi,
    162              target_name=target_name))
    163 
    164 
    165 for target in ('arm', 'arm64', 'mips', 'mips64', 'x86', 'x86_64'):
    166     create_target_test(target)
    167