1#!/usr/bin/env python3 2# Copyright 2023 The ChromiumOS Authors 3# Use of this source code is governed by a BSD-style license that can be 4# found in the LICENSE file. 5 6"""Tests for generate_pgo_profile.""" 7 8from pathlib import Path 9import shutil 10import tempfile 11import unittest 12from unittest import mock 13 14import generate_pgo_profile 15import pgo_tools 16 17 18class Test(unittest.TestCase): 19 """Tests for generate_pgo_profile.""" 20 21 @mock.patch.object(pgo_tools, "run") 22 def test_find_missing_cross_libs_works_for_empty_results(self, mock_run): 23 mock_run.return_value.returncode = 3 24 mock_run.return_value.stdout = "" 25 self.assertEqual( 26 generate_pgo_profile.find_missing_cross_libs(), 27 generate_pgo_profile.ALL_NEEDED_CROSS_LIBS, 28 ) 29 30 mock_run.return_value.returncode = 0 31 self.assertEqual( 32 generate_pgo_profile.find_missing_cross_libs(), 33 generate_pgo_profile.ALL_NEEDED_CROSS_LIBS, 34 ) 35 36 @mock.patch.object(pgo_tools, "run") 37 def test_find_missing_cross_libs_filters_results_properly(self, mock_run): 38 mock_run.return_value.returncode = 0 39 mock_run.return_value.stdout = "\n".join( 40 generate_pgo_profile.ALL_NEEDED_CROSS_LIBS 41 ) 42 self.assertEqual(generate_pgo_profile.find_missing_cross_libs(), set()) 43 44 some_cross_libs = sorted(generate_pgo_profile.ALL_NEEDED_CROSS_LIBS) 45 del some_cross_libs[len(some_cross_libs) // 3 :] 46 mock_run.return_value.stdout = "\n".join( 47 some_cross_libs + ["cross-foo/bar"] 48 ) 49 50 expected_result = generate_pgo_profile.ALL_NEEDED_CROSS_LIBS - set( 51 some_cross_libs 52 ) 53 self.assertEqual( 54 generate_pgo_profile.find_missing_cross_libs(), expected_result 55 ) 56 57 def make_tempdir(self) -> Path: 58 tempdir = Path(tempfile.mkdtemp(prefix="generate_pgo_profile_test_")) 59 self.addCleanup(lambda: shutil.rmtree(tempdir)) 60 return tempdir 61 62 def test_read_exactly_one_dirent_works(self): 63 tempdir = self.make_tempdir() 64 ent = tempdir / "one-ent" 65 ent.touch() 66 67 self.assertEqual( 68 generate_pgo_profile.read_exactly_one_dirent(tempdir), ent 69 ) 70 71 def test_read_exactly_one_dirent_fails_when_no_ents(self): 72 tempdir = self.make_tempdir() 73 with self.assertRaisesRegex(ValueError, "^Expected exactly one"): 74 generate_pgo_profile.read_exactly_one_dirent(tempdir) 75 76 def test_read_exactly_one_dirent_fails_when_multiple_ents(self): 77 tempdir = self.make_tempdir() 78 (tempdir / "a").touch() 79 (tempdir / "b").touch() 80 with self.assertRaisesRegex(ValueError, "^Expected exactly one"): 81 generate_pgo_profile.read_exactly_one_dirent(tempdir) 82 83 @mock.patch.object(pgo_tools, "run") 84 def test_profraw_conversion_works(self, mock_run): 85 tempdir = self.make_tempdir() 86 profiles = [ 87 tempdir / "profile-foo.profraw", 88 tempdir / "profile-bar.profraw", 89 ] 90 not_a_profile = tempdir / "not-a-profile.profraw" 91 for f in profiles + [not_a_profile]: 92 f.touch() 93 94 result = generate_pgo_profile.convert_profraw_to_pgo_profile(tempdir) 95 self.assertNotEqual(result.stem, ".profraw") 96 try: 97 # is_relative_to was added in Py3.9; until the chroot has that, 98 # this code needs to use `relative_to` & check for exceptions. 99 result.relative_to(tempdir) 100 except ValueError: 101 self.fail(f"{result} should be relative to {tempdir}") 102 103 mock_run.assert_called_once() 104 run_cmd = mock_run.call_args[0][0] 105 for p in profiles: 106 self.assertIn(p, run_cmd) 107 self.assertNotIn(not_a_profile, run_cmd) 108 self.assertIn(f"--output={result}", run_cmd) 109 110 111if __name__ == "__main__": 112 unittest.main() 113