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