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 20 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(__file__).parent.parent.resolve() 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 33 def test_build_id_correctness(self): 34 """Tests to ensure GNU build IDs are read/written correctly.""" 35 with tempfile.TemporaryDirectory() as exe_dir: 36 exe_file = Path(exe_dir) / 'print_build_id.elf' 37 38 # Compiles a binary that prints the embedded GNU build id. 39 cmd = [ 40 'clang++', 41 'build_id.cc', 42 _MODULE_PY_DIR / 'print_build_id.cc', 43 '-Ipublic', 44 '-I../pw_polyfill/public', 45 '-I../pw_preprocessor/public', 46 '-I../pw_span/public', 47 '-std=c++17', 48 '-fuse-ld=lld', 49 '-Wl,-Tadd_build_id_to_default_linker_script.ld', 50 '-Wl,--build-id=sha1', 51 '-o', 52 exe_file, 53 ] 54 55 process = subprocess.run( 56 cmd, 57 stdout=subprocess.PIPE, 58 stderr=subprocess.STDOUT, 59 cwd=_MODULE_DIR, 60 ) 61 self.assertEqual( 62 process.returncode, 0, process.stdout.decode(errors='replace') 63 ) 64 65 # Run the compiled binary so the printed build ID can be read. 66 process = subprocess.run( 67 [exe_file], 68 stdout=subprocess.PIPE, 69 stderr=subprocess.STDOUT, 70 cwd=_MODULE_DIR, 71 ) 72 self.assertEqual(process.returncode, 0) 73 74 with open(exe_file, 'rb') as elf: 75 expected = build_id.read_build_id_from_section(elf) 76 self.assertEqual(len(expected), _SHA1_BUILD_ID_LENGTH) 77 self.assertEqual( 78 process.stdout.decode().rstrip(), expected.hex() 79 ) 80 81 # Test method that parses using symbol information. 82 expected = build_id.read_build_id_from_symbol(elf) 83 self.assertEqual(len(expected), _SHA1_BUILD_ID_LENGTH) 84 self.assertEqual( 85 process.stdout.decode().rstrip(), expected.hex() 86 ) 87 88 # Test the user-facing method. 89 expected = build_id.read_build_id(elf) 90 self.assertEqual(len(expected), _SHA1_BUILD_ID_LENGTH) 91 self.assertEqual( 92 process.stdout.decode().rstrip(), expected.hex() 93 ) 94 95 96if __name__ == '__main__': 97 unittest.main() 98