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 missing_optional_uses_libraries=()): #pylint: disable=dangerous-default-value 49 doc = minidom.parseString(xml) 50 try: 51 relax = False 52 manifest_check.enforce_uses_libraries( 53 doc, uses_libraries, optional_uses_libraries, missing_optional_uses_libraries, 54 relax, False, 'path/to/X/AndroidManifest.xml') 55 manifest_check.enforce_uses_libraries(apk, uses_libraries, 56 optional_uses_libraries, 57 missing_optional_uses_libraries, 58 relax, True, 59 'path/to/X/X.apk') 60 return True 61 except manifest_check.ManifestMismatchError: 62 return False 63 64 xml_tmpl = ( 65 '<?xml version="1.0" encoding="utf-8"?>\n<manifest ' 66 'xmlns:android="http://schemas.android.com/apk/res/android">\n ' 67 '<application>\n %s\n </application>\n</manifest>\n') 68 69 apk_tmpl = ( 70 "package: name='com.google.android.something' versionCode='100'\n" 71 "sdkVersion:'29'\n" 72 "targetSdkVersion:'29'\n" 73 "uses-permission: name='android.permission.ACCESS_NETWORK_STATE'\n" 74 '%s\n' 75 "densities: '160' '240' '320' '480' '640' '65534") 76 77 def test_uses_library(self): 78 xml = self.xml_tmpl % (uses_library_xml('foo')) 79 apk = self.apk_tmpl % (uses_library_apk('foo')) 80 matches = self.run_test(xml, apk, uses_libraries=['foo']) 81 self.assertTrue(matches) 82 83 def test_uses_library_required(self): 84 xml = self.xml_tmpl % (uses_library_xml('foo', required_xml(True))) 85 apk = self.apk_tmpl % (uses_library_apk('foo', required_apk(True))) 86 matches = self.run_test(xml, apk, uses_libraries=['foo']) 87 self.assertTrue(matches) 88 89 def test_optional_uses_library(self): 90 xml = self.xml_tmpl % (uses_library_xml('foo', required_xml(False))) 91 apk = self.apk_tmpl % (uses_library_apk('foo', required_apk(False))) 92 matches = self.run_test(xml, apk, optional_uses_libraries=['foo']) 93 self.assertTrue(matches) 94 95 def test_expected_uses_library(self): 96 xml = self.xml_tmpl % (uses_library_xml('foo', required_xml(False))) 97 apk = self.apk_tmpl % (uses_library_apk('foo', required_apk(False))) 98 matches = self.run_test(xml, apk, uses_libraries=['foo']) 99 self.assertFalse(matches) 100 101 def test_expected_optional_uses_library(self): 102 xml = self.xml_tmpl % (uses_library_xml('foo')) 103 apk = self.apk_tmpl % (uses_library_apk('foo')) 104 matches = self.run_test(xml, apk, optional_uses_libraries=['foo']) 105 self.assertFalse(matches) 106 107 def test_expected_missing_optional_uses_library(self): 108 xml = self.xml_tmpl % ( 109 uses_library_xml('foo') + uses_library_xml('missing') + uses_library_xml('bar')) 110 apk = self.apk_tmpl % ( 111 uses_library_apk('foo') + uses_library_apk('missing') + uses_library_apk('bar')) 112 matches = self.run_test(xml, apk, optional_uses_libraries=['foo', 'bar'], 113 missing_optional_uses_libraries=['missing']) 114 self.assertFalse(matches) 115 116 def test_missing_uses_library(self): 117 xml = self.xml_tmpl % '' 118 apk = self.apk_tmpl % '' 119 matches = self.run_test(xml, apk, uses_libraries=['foo']) 120 self.assertFalse(matches) 121 122 def test_missing_optional_uses_library(self): 123 xml = self.xml_tmpl % '' 124 apk = self.apk_tmpl % '' 125 matches = self.run_test(xml, apk, optional_uses_libraries=['foo']) 126 self.assertFalse(matches) 127 128 def test_extra_uses_library(self): 129 xml = self.xml_tmpl % (uses_library_xml('foo')) 130 apk = self.apk_tmpl % (uses_library_xml('foo')) 131 matches = self.run_test(xml, apk) 132 self.assertFalse(matches) 133 134 def test_extra_optional_uses_library(self): 135 xml = self.xml_tmpl % (uses_library_xml('foo', required_xml(False))) 136 apk = self.apk_tmpl % (uses_library_apk('foo', required_apk(False))) 137 matches = self.run_test(xml, apk) 138 self.assertFalse(matches) 139 140 def test_multiple_uses_library(self): 141 xml = self.xml_tmpl % ('\n'.join( 142 [uses_library_xml('foo'), 143 uses_library_xml('bar')])) 144 apk = self.apk_tmpl % ('\n'.join( 145 [uses_library_apk('foo'), 146 uses_library_apk('bar')])) 147 matches = self.run_test(xml, apk, uses_libraries=['foo', 'bar']) 148 self.assertTrue(matches) 149 150 def test_multiple_optional_uses_library(self): 151 xml = self.xml_tmpl % ('\n'.join([ 152 uses_library_xml('foo', required_xml(False)), 153 uses_library_xml('bar', required_xml(False)) 154 ])) 155 apk = self.apk_tmpl % ('\n'.join([ 156 uses_library_apk('foo', required_apk(False)), 157 uses_library_apk('bar', required_apk(False)) 158 ])) 159 matches = self.run_test( 160 xml, apk, optional_uses_libraries=['foo', 'bar']) 161 self.assertTrue(matches) 162 163 def test_order_uses_library(self): 164 xml = self.xml_tmpl % ('\n'.join( 165 [uses_library_xml('foo'), 166 uses_library_xml('bar')])) 167 apk = self.apk_tmpl % ('\n'.join( 168 [uses_library_apk('foo'), 169 uses_library_apk('bar')])) 170 matches = self.run_test(xml, apk, uses_libraries=['bar', 'foo']) 171 self.assertFalse(matches) 172 173 def test_order_optional_uses_library(self): 174 xml = self.xml_tmpl % ('\n'.join([ 175 uses_library_xml('foo', required_xml(False)), 176 uses_library_xml('bar', required_xml(False)) 177 ])) 178 apk = self.apk_tmpl % ('\n'.join([ 179 uses_library_apk('foo', required_apk(False)), 180 uses_library_apk('bar', required_apk(False)) 181 ])) 182 matches = self.run_test( 183 xml, apk, optional_uses_libraries=['bar', 'foo']) 184 self.assertFalse(matches) 185 186 def test_duplicate_uses_library(self): 187 xml = self.xml_tmpl % ('\n'.join( 188 [uses_library_xml('foo'), 189 uses_library_xml('foo')])) 190 apk = self.apk_tmpl % ('\n'.join( 191 [uses_library_apk('foo'), 192 uses_library_apk('foo')])) 193 matches = self.run_test(xml, apk, uses_libraries=['foo']) 194 self.assertTrue(matches) 195 196 def test_duplicate_optional_uses_library(self): 197 xml = self.xml_tmpl % ('\n'.join([ 198 uses_library_xml('foo', required_xml(False)), 199 uses_library_xml('foo', required_xml(False)) 200 ])) 201 apk = self.apk_tmpl % ('\n'.join([ 202 uses_library_apk('foo', required_apk(False)), 203 uses_library_apk('foo', required_apk(False)) 204 ])) 205 matches = self.run_test(xml, apk, optional_uses_libraries=['foo']) 206 self.assertTrue(matches) 207 208 def test_mixed(self): 209 xml = self.xml_tmpl % ('\n'.join([ 210 uses_library_xml('foo'), 211 uses_library_xml('bar', required_xml(False)) 212 ])) 213 apk = self.apk_tmpl % ('\n'.join([ 214 uses_library_apk('foo'), 215 uses_library_apk('bar', required_apk(False)) 216 ])) 217 matches = self.run_test( 218 xml, apk, uses_libraries=['foo'], optional_uses_libraries=['bar']) 219 self.assertTrue(matches) 220 221 def test_mixed_with_namespace(self): 222 xml = self.xml_tmpl % ('\n'.join([ 223 uses_library_xml('foo'), 224 uses_library_xml('bar', required_xml(False)) 225 ])) 226 apk = self.apk_tmpl % ('\n'.join([ 227 uses_library_apk('foo'), 228 uses_library_apk('bar', required_apk(False)) 229 ])) 230 matches = self.run_test( 231 xml, 232 apk, 233 uses_libraries=['//x/y/z:foo'], 234 optional_uses_libraries=['//x/y/z:bar']) 235 self.assertTrue(matches) 236 237 def test_multiple_applications(self): 238 xml = """<?xml version="1.0" encoding="utf-8"?> 239 <manifest xmlns:android="http://schemas.android.com/apk/res/android"> 240 <application android:featureFlag="foo"> 241 <uses-library android:name="foo" /> 242 <uses-library android:name="bar" android:required="false" /> 243 </application> 244 <application android:featureFlag="!foo"> 245 <uses-library android:name="foo" /> 246 <uses-library android:name="qux" android:required="false" /> 247 </application> 248 </manifest> 249 """ 250 apk = self.apk_tmpl % ('\n'.join([ 251 uses_library_apk('foo'), 252 uses_library_apk('bar', required_apk(False)), 253 uses_library_apk('foo'), 254 uses_library_apk('qux', required_apk(False)) 255 ])) 256 matches = self.run_test( 257 xml, 258 apk, 259 uses_libraries=['//x/y/z:foo'], 260 optional_uses_libraries=['//x/y/z:bar', '//x/y/z:qux']) 261 self.assertTrue(matches) 262 263 264class ExtractTargetSdkVersionTest(unittest.TestCase): 265 266 def run_test(self, xml, apk, version): 267 doc = minidom.parseString(xml) 268 v = manifest_check.extract_target_sdk_version(doc, is_apk=False) 269 self.assertEqual(v, version) 270 v = manifest_check.extract_target_sdk_version(apk, is_apk=True) 271 self.assertEqual(v, version) 272 273 xml_tmpl = ( 274 '<?xml version="1.0" encoding="utf-8"?>\n<manifest ' 275 'xmlns:android="http://schemas.android.com/apk/res/android">\n ' 276 '<uses-sdk android:minSdkVersion="28" android:targetSdkVersion="%s" ' 277 '/>\n</manifest>\n') 278 279 apk_tmpl = ( 280 "package: name='com.google.android.something' versionCode='100'\n" 281 "sdkVersion:'28'\n" 282 "targetSdkVersion:'%s'\n" 283 "uses-permission: name='android.permission.ACCESS_NETWORK_STATE'\n") 284 285 def test_target_sdk_version_28(self): 286 xml = self.xml_tmpl % '28' 287 apk = self.apk_tmpl % '28' 288 self.run_test(xml, apk, '28') 289 290 def test_target_sdk_version_29(self): 291 xml = self.xml_tmpl % '29' 292 apk = self.apk_tmpl % '29' 293 self.run_test(xml, apk, '29') 294 295 296if __name__ == '__main__': 297 unittest.main(verbosity=2) 298