• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Copyright 2021 The Pigweed Authors
2#
3# Licensed under the Apache License, Version 2.0 (the "License"); you may not
4# use this file except in compliance with the License. You may obtain a copy of
5# the License at
6#
7#     https://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12# License for the specific language governing permissions and limitations under
13# the License.
14"""Tests for pw_build_info's GNU build ID support."""
15
16import subprocess
17import tempfile
18import unittest
19from pathlib import Path
20from pw_cli import env
21from pw_build_info import build_id
22
23# Since build_id.cc depends on pw_preprocessor, we have to use the in-tree path.
24_MODULE_DIR = Path(env.pigweed_environment().PW_ROOT) / 'pw_build_info'
25_MODULE_PY_DIR = Path(__file__).parent.resolve()
26
27_SHA1_BUILD_ID_LENGTH = 20
28
29
30class TestGnuBuildId(unittest.TestCase):
31    """Unit tests for GNU build ID parsing."""
32    def test_build_id_correctness(self):
33        """Tests to ensure GNU build IDs are read/written correctly."""
34        with tempfile.TemporaryDirectory() as exe_dir:
35            exe_file = Path(exe_dir) / 'print_build_id.elf'
36
37            # Compiles a binary that prints the embedded GNU build id.
38            cmd = [
39                'clang++',
40                'build_id.cc',
41                _MODULE_PY_DIR / 'print_build_id.cc',
42                '-Ipublic',
43                '-I../pw_preprocessor/public',
44                '-std=c++20',
45                '-fuse-ld=lld',
46                '-Wl,-Tadd_build_id_to_default_linker_script.ld',
47                '-Wl,--build-id=sha1',
48                '-o',
49                exe_file,
50            ]
51
52            process = subprocess.run(cmd,
53                                     stdout=subprocess.PIPE,
54                                     stderr=subprocess.STDOUT,
55                                     cwd=_MODULE_DIR)
56            self.assertEqual(process.returncode, 0)
57
58            # Run the compiled binary so the printed build ID can be read.
59            process = subprocess.run([exe_file],
60                                     stdout=subprocess.PIPE,
61                                     stderr=subprocess.STDOUT,
62                                     cwd=_MODULE_DIR)
63            self.assertEqual(process.returncode, 0)
64
65            with open(exe_file, 'rb') as elf:
66                expected = build_id.read_build_id_from_section(elf)
67                self.assertEqual(len(expected), _SHA1_BUILD_ID_LENGTH)
68                self.assertEqual(process.stdout.decode().rstrip(),
69                                 expected.hex())
70
71                # Test method that parses using symbol information.
72                expected = build_id.read_build_id_from_symbol(elf)
73                self.assertEqual(len(expected), _SHA1_BUILD_ID_LENGTH)
74                self.assertEqual(process.stdout.decode().rstrip(),
75                                 expected.hex())
76
77                # Test the user-facing method.
78                expected = build_id.read_build_id(elf)
79                self.assertEqual(len(expected), _SHA1_BUILD_ID_LENGTH)
80                self.assertEqual(process.stdout.decode().rstrip(),
81                                 expected.hex())
82
83
84if __name__ == '__main__':
85    unittest.main()
86