• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Copyright 2023 The Bazel Authors. All rights reserved.
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7#    http://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,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14
15import os
16import subprocess
17import unittest
18import zipfile
19
20
21class R8IntegrationTest(unittest.TestCase):
22  """Tests Bazel's R8 integration."""
23
24  def _r8_integration_check(
25      self, apk, expect_unused_activity_resource, expect_unused_activity_class
26  ):
27    tmp = os.environ["TEST_TMPDIR"]
28    apk_directory = (
29        "test/rules/android_binary_internal/r8_integration/java/com/basicapp"
30    )
31    apk_tmp = os.path.join(tmp, apk)
32    classes_dex = os.path.join(apk_tmp, "classes.dex")
33    with zipfile.ZipFile(os.path.join(apk_directory, apk)) as zf:
34      apk_files = zf.namelist()
35      zf.extract("classes.dex", apk_tmp)
36
37    self.assertEqual(
38        expect_unused_activity_resource,
39        "res/layout/unused_activity.xml" in apk_files,
40    )
41
42    build_tools_dir = "external/androidsdk-supplemental/build-tools"
43    build_tools_version = os.listdir(build_tools_dir)[0]
44    dexdump = os.path.join(build_tools_dir, build_tools_version, "dexdump")
45
46    dexdump_proc = subprocess.run(
47        [dexdump, classes_dex],
48        stdout=subprocess.PIPE,
49        stderr=subprocess.PIPE,
50        check=True,
51    )
52    dexdump_stdout = str(dexdump_proc.stdout)
53    self.assertEqual(
54        expect_unused_activity_class,
55        "Class descriptor  : 'Lcom/basicapp/UnusedActivity;'" in dexdump_stdout,
56    )
57
58    # In all cases, the Lib2WithSpecsActivity class should be in the app,
59    # since lib2_proguard.cfg (an indirect dependency) specifies to keep it.
60    self.assertIn(
61        "Class descriptor  : 'Lcom/basicapp/Lib2WithSpecsActivity;'",
62        dexdump_stdout,
63    )
64
65  def test_r8_integration(self):
66    # No R8, so unused resources and unused classes should be in the app
67    self._r8_integration_check(
68        "basic_app_no_R8.apk",
69        expect_unused_activity_resource=True,
70        expect_unused_activity_class=True,
71    )
72
73    # Run R8, don't shrink, so unused class should not be in the app but unused
74    # resource should remain.
75    self._r8_integration_check(
76        "basic_app_R8_no_shrink.apk",
77        expect_unused_activity_resource=True,
78        expect_unused_activity_class=False,
79    )
80
81    # Run R8 and shrinkings, so unused classes and resources should not be in
82    # the app.
83    self._r8_integration_check(
84        "basic_app_R8_shrink.apk",
85        expect_unused_activity_resource=False,
86        expect_unused_activity_class=False,
87    )
88
89
90if __name__ == "__main__":
91  unittest.main()
92