1#!/usr/bin/env python
2#
3# Copyright (C) 2018 The Android Open Source Project
4#
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9#      http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16#
17"""Unit tests for manifest_fixer.py."""
18
19import sys
20import unittest
21from xml.dom import minidom
22
23import manifest_check
24
25sys.dont_write_bytecode = True
26
27
28def uses_library_xml(name, attr=''):
29  return '<uses-library android:name="%s"%s />' % (name, attr)
30
31
32def required_xml(value):
33  return ' android:required="%s"' % ('true' if value else 'false')
34
35
36def uses_library_apk(name, sfx=''):
37  return "uses-library%s:'%s'" % (sfx, name)
38
39
40def required_apk(value):
41  return '' if value else '-not-required'
42
43
44class EnforceUsesLibrariesTest(unittest.TestCase):
45  """Unit tests for add_extract_native_libs function."""
46
47  def run_test(self, xml, apk, uses_libraries=[], optional_uses_libraries=[]):
48    doc = minidom.parseString(xml)
49    try:
50      relax = False
51      manifest_check.enforce_uses_libraries(doc, uses_libraries,
52        optional_uses_libraries, relax, False, 'path/to/X/AndroidManifest.xml')
53      manifest_check.enforce_uses_libraries(apk, uses_libraries,
54        optional_uses_libraries, relax, True, 'path/to/X/X.apk')
55      return True
56    except manifest_check.ManifestMismatchError:
57      return False
58
59  xml_tmpl = (
60      '<?xml version="1.0" encoding="utf-8"?>\n'
61      '<manifest xmlns:android="http://schemas.android.com/apk/res/android">\n'
62      '    <application>\n'
63      '    %s\n'
64      '    </application>\n'
65      '</manifest>\n')
66
67  apk_tmpl = (
68      "package: name='com.google.android.something' versionCode='100'\n"
69      "sdkVersion:'29'\n"
70      "targetSdkVersion:'29'\n"
71      "uses-permission: name='android.permission.ACCESS_NETWORK_STATE'\n"
72      "%s\n"
73      "densities: '160' '240' '320' '480' '640' '65534")
74
75  def test_uses_library(self):
76    xml = self.xml_tmpl % (uses_library_xml('foo'))
77    apk = self.apk_tmpl % (uses_library_apk('foo'))
78    matches = self.run_test(xml, apk, uses_libraries=['foo'])
79    self.assertTrue(matches)
80
81  def test_uses_library_required(self):
82    xml = self.xml_tmpl % (uses_library_xml('foo', required_xml(True)))
83    apk = self.apk_tmpl % (uses_library_apk('foo', required_apk(True)))
84    matches = self.run_test(xml, apk, uses_libraries=['foo'])
85    self.assertTrue(matches)
86
87  def test_optional_uses_library(self):
88    xml = self.xml_tmpl % (uses_library_xml('foo', required_xml(False)))
89    apk = self.apk_tmpl % (uses_library_apk('foo', required_apk(False)))
90    matches = self.run_test(xml, apk, optional_uses_libraries=['foo'])
91    self.assertTrue(matches)
92
93  def test_expected_uses_library(self):
94    xml = self.xml_tmpl % (uses_library_xml('foo', required_xml(False)))
95    apk = self.apk_tmpl % (uses_library_apk('foo', required_apk(False)))
96    matches = self.run_test(xml, apk, uses_libraries=['foo'])
97    self.assertFalse(matches)
98
99  def test_expected_optional_uses_library(self):
100    xml = self.xml_tmpl % (uses_library_xml('foo'))
101    apk = self.apk_tmpl % (uses_library_apk('foo'))
102    matches = self.run_test(xml, apk, optional_uses_libraries=['foo'])
103    self.assertFalse(matches)
104
105  def test_missing_uses_library(self):
106    xml = self.xml_tmpl % ('')
107    apk = self.apk_tmpl % ('')
108    matches = self.run_test(xml, apk, uses_libraries=['foo'])
109    self.assertFalse(matches)
110
111  def test_missing_optional_uses_library(self):
112    xml = self.xml_tmpl % ('')
113    apk = self.apk_tmpl % ('')
114    matches = self.run_test(xml, apk, optional_uses_libraries=['foo'])
115    self.assertFalse(matches)
116
117  def test_extra_uses_library(self):
118    xml = self.xml_tmpl % (uses_library_xml('foo'))
119    apk = self.apk_tmpl % (uses_library_xml('foo'))
120    matches = self.run_test(xml, apk)
121    self.assertFalse(matches)
122
123  def test_extra_optional_uses_library(self):
124    xml = self.xml_tmpl % (uses_library_xml('foo', required_xml(False)))
125    apk = self.apk_tmpl % (uses_library_apk('foo', required_apk(False)))
126    matches = self.run_test(xml, apk)
127    self.assertFalse(matches)
128
129  def test_multiple_uses_library(self):
130    xml = self.xml_tmpl % ('\n'.join([uses_library_xml('foo'),
131                                      uses_library_xml('bar')]))
132    apk = self.apk_tmpl % ('\n'.join([uses_library_apk('foo'),
133                                      uses_library_apk('bar')]))
134    matches = self.run_test(xml, apk, uses_libraries=['foo', 'bar'])
135    self.assertTrue(matches)
136
137  def test_multiple_optional_uses_library(self):
138    xml = self.xml_tmpl % ('\n'.join([uses_library_xml('foo', required_xml(False)),
139                                      uses_library_xml('bar', required_xml(False))]))
140    apk = self.apk_tmpl % ('\n'.join([uses_library_apk('foo', required_apk(False)),
141                                      uses_library_apk('bar', required_apk(False))]))
142    matches = self.run_test(xml, apk, optional_uses_libraries=['foo', 'bar'])
143    self.assertTrue(matches)
144
145  def test_order_uses_library(self):
146    xml = self.xml_tmpl % ('\n'.join([uses_library_xml('foo'),
147                                      uses_library_xml('bar')]))
148    apk = self.apk_tmpl % ('\n'.join([uses_library_apk('foo'),
149                                      uses_library_apk('bar')]))
150    matches = self.run_test(xml, apk, uses_libraries=['bar', 'foo'])
151    self.assertFalse(matches)
152
153  def test_order_optional_uses_library(self):
154    xml = self.xml_tmpl % ('\n'.join([uses_library_xml('foo', required_xml(False)),
155                                      uses_library_xml('bar', required_xml(False))]))
156    apk = self.apk_tmpl % ('\n'.join([uses_library_apk('foo', required_apk(False)),
157                                      uses_library_apk('bar', required_apk(False))]))
158    matches = self.run_test(xml, apk, optional_uses_libraries=['bar', 'foo'])
159    self.assertFalse(matches)
160
161  def test_duplicate_uses_library(self):
162    xml = self.xml_tmpl % ('\n'.join([uses_library_xml('foo'),
163                                      uses_library_xml('foo')]))
164    apk = self.apk_tmpl % ('\n'.join([uses_library_apk('foo'),
165                                      uses_library_apk('foo')]))
166    matches = self.run_test(xml, apk, uses_libraries=['foo'])
167    self.assertTrue(matches)
168
169  def test_duplicate_optional_uses_library(self):
170    xml = self.xml_tmpl % ('\n'.join([uses_library_xml('foo', required_xml(False)),
171                                      uses_library_xml('foo', required_xml(False))]))
172    apk = self.apk_tmpl % ('\n'.join([uses_library_apk('foo', required_apk(False)),
173                                      uses_library_apk('foo', required_apk(False))]))
174    matches = self.run_test(xml, apk, optional_uses_libraries=['foo'])
175    self.assertTrue(matches)
176
177  def test_mixed(self):
178    xml = self.xml_tmpl % ('\n'.join([uses_library_xml('foo'),
179                                      uses_library_xml('bar', required_xml(False))]))
180    apk = self.apk_tmpl % ('\n'.join([uses_library_apk('foo'),
181                                      uses_library_apk('bar', required_apk(False))]))
182    matches = self.run_test(xml, apk, uses_libraries=['foo'],
183                            optional_uses_libraries=['bar'])
184    self.assertTrue(matches)
185
186
187class ExtractTargetSdkVersionTest(unittest.TestCase):
188  def run_test(self, xml, apk, version):
189    doc = minidom.parseString(xml)
190    v = manifest_check.extract_target_sdk_version(doc, is_apk=False)
191    self.assertEqual(v, version)
192    v = manifest_check.extract_target_sdk_version(apk, is_apk=True)
193    self.assertEqual(v, version)
194
195  xml_tmpl = (
196      '<?xml version="1.0" encoding="utf-8"?>\n'
197      '<manifest xmlns:android="http://schemas.android.com/apk/res/android">\n'
198      '    <uses-sdk android:minSdkVersion="28" android:targetSdkVersion="%s" />\n'
199      '</manifest>\n')
200
201  apk_tmpl = (
202      "package: name='com.google.android.something' versionCode='100'\n"
203      "sdkVersion:'28'\n"
204      "targetSdkVersion:'%s'\n"
205      "uses-permission: name='android.permission.ACCESS_NETWORK_STATE'\n")
206
207  def test_targert_sdk_version_28(self):
208    xml = self.xml_tmpl % "28"
209    apk = self.apk_tmpl % "28"
210    self.run_test(xml, apk, "28")
211
212  def test_targert_sdk_version_29(self):
213    xml = self.xml_tmpl % "29"
214    apk = self.apk_tmpl % "29"
215    self.run_test(xml, apk, "29")
216
217if __name__ == '__main__':
218  unittest.main(verbosity=2)
219