blob: edc98cd3ae02e417ec72964b72c99d47ade97e5e [file] [log] [blame]
Colin Cross8bb10e82018-06-07 16:46:02 -07001#!/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_test.py."""
18
19import StringIO
20import sys
21import unittest
22from xml.dom import minidom
23
24import manifest_fixer
25
26sys.dont_write_bytecode = True
27
28
29class CompareVersionGtTest(unittest.TestCase):
30 """Unit tests for compare_version_gt function."""
31
32 def test_sdk(self):
33 """Test comparing sdk versions."""
34 self.assertTrue(manifest_fixer.compare_version_gt('28', '27'))
35 self.assertFalse(manifest_fixer.compare_version_gt('27', '28'))
36 self.assertFalse(manifest_fixer.compare_version_gt('28', '28'))
37
38 def test_codename(self):
39 """Test comparing codenames."""
40 self.assertTrue(manifest_fixer.compare_version_gt('Q', 'P'))
41 self.assertFalse(manifest_fixer.compare_version_gt('P', 'Q'))
42 self.assertFalse(manifest_fixer.compare_version_gt('Q', 'Q'))
43
44 def test_sdk_codename(self):
45 """Test comparing sdk versions with codenames."""
46 self.assertTrue(manifest_fixer.compare_version_gt('Q', '28'))
47 self.assertFalse(manifest_fixer.compare_version_gt('28', 'Q'))
48
49 def test_compare_numeric(self):
50 """Test that numbers are compared in numeric and not lexicographic order."""
51 self.assertTrue(manifest_fixer.compare_version_gt('18', '8'))
52
53
54class RaiseMinSdkVersionTest(unittest.TestCase):
55 """Unit tests for raise_min_sdk_version function."""
56
Colin Cross496d66d2018-09-10 14:02:18 -070057 def raise_min_sdk_version_test(self, input_manifest, min_sdk_version,
Colin Cross7b59e7b2018-09-10 13:35:13 -070058 target_sdk_version, library):
Colin Cross8bb10e82018-06-07 16:46:02 -070059 doc = minidom.parseString(input_manifest)
Colin Cross7b59e7b2018-09-10 13:35:13 -070060 manifest_fixer.raise_min_sdk_version(doc, min_sdk_version,
61 target_sdk_version, library)
Colin Cross8bb10e82018-06-07 16:46:02 -070062 output = StringIO.StringIO()
63 manifest_fixer.write_xml(output, doc)
64 return output.getvalue()
65
66 manifest_tmpl = (
67 '<?xml version="1.0" encoding="utf-8"?>\n'
68 '<manifest xmlns:android="http://schemas.android.com/apk/res/android">\n'
69 '%s'
70 '</manifest>\n')
71
Colin Cross1b6a3cf2018-07-24 14:51:30 -070072 # pylint: disable=redefined-builtin
73 def uses_sdk(self, min=None, target=None, extra=''):
Colin Cross496d66d2018-09-10 14:02:18 -070074 attrs = ''
Colin Cross1b6a3cf2018-07-24 14:51:30 -070075 if min:
76 attrs += ' android:minSdkVersion="%s"' % (min)
77 if target:
78 attrs += ' android:targetSdkVersion="%s"' % (target)
Colin Cross8bb10e82018-06-07 16:46:02 -070079 if extra:
Colin Cross496d66d2018-09-10 14:02:18 -070080 attrs += ' ' + extra
Colin Cross1b6a3cf2018-07-24 14:51:30 -070081 return ' <uses-sdk%s/>\n' % (attrs)
Colin Cross8bb10e82018-06-07 16:46:02 -070082
83 def test_no_uses_sdk(self):
84 """Tests inserting a uses-sdk element into a manifest."""
85
86 manifest_input = self.manifest_tmpl % ''
Colin Cross1b6a3cf2018-07-24 14:51:30 -070087 expected = self.manifest_tmpl % self.uses_sdk(min='28', target='28')
Colin Cross7b59e7b2018-09-10 13:35:13 -070088 output = self.raise_min_sdk_version_test(manifest_input, '28', '28', False)
Colin Cross8bb10e82018-06-07 16:46:02 -070089 self.assertEqual(output, expected)
90
91 def test_no_min(self):
92 """Tests inserting a minSdkVersion attribute into a uses-sdk element."""
93
94 manifest_input = self.manifest_tmpl % ' <uses-sdk extra="foo"/>\n'
Colin Cross1b6a3cf2018-07-24 14:51:30 -070095 expected = self.manifest_tmpl % self.uses_sdk(min='28', target='28',
96 extra='extra="foo"')
Colin Cross7b59e7b2018-09-10 13:35:13 -070097 output = self.raise_min_sdk_version_test(manifest_input, '28', '28', False)
Colin Cross8bb10e82018-06-07 16:46:02 -070098 self.assertEqual(output, expected)
99
100 def test_raise_min(self):
101 """Tests inserting a minSdkVersion attribute into a uses-sdk element."""
102
Colin Cross1b6a3cf2018-07-24 14:51:30 -0700103 manifest_input = self.manifest_tmpl % self.uses_sdk(min='27')
Colin Cross496d66d2018-09-10 14:02:18 -0700104 expected = self.manifest_tmpl % self.uses_sdk(min='28', target='28')
Colin Cross7b59e7b2018-09-10 13:35:13 -0700105 output = self.raise_min_sdk_version_test(manifest_input, '28', '28', False)
Colin Cross8bb10e82018-06-07 16:46:02 -0700106 self.assertEqual(output, expected)
107
108 def test_raise(self):
109 """Tests raising a minSdkVersion attribute."""
110
Colin Cross1b6a3cf2018-07-24 14:51:30 -0700111 manifest_input = self.manifest_tmpl % self.uses_sdk(min='27')
Colin Cross496d66d2018-09-10 14:02:18 -0700112 expected = self.manifest_tmpl % self.uses_sdk(min='28', target='28')
Colin Cross7b59e7b2018-09-10 13:35:13 -0700113 output = self.raise_min_sdk_version_test(manifest_input, '28', '28', False)
Colin Cross8bb10e82018-06-07 16:46:02 -0700114 self.assertEqual(output, expected)
115
116 def test_no_raise_min(self):
117 """Tests a minSdkVersion that doesn't need raising."""
118
Colin Cross1b6a3cf2018-07-24 14:51:30 -0700119 manifest_input = self.manifest_tmpl % self.uses_sdk(min='28')
Colin Cross496d66d2018-09-10 14:02:18 -0700120 expected = self.manifest_tmpl % self.uses_sdk(min='28', target='27')
Colin Cross7b59e7b2018-09-10 13:35:13 -0700121 output = self.raise_min_sdk_version_test(manifest_input, '27', '27', False)
Colin Cross8bb10e82018-06-07 16:46:02 -0700122 self.assertEqual(output, expected)
123
124 def test_raise_codename(self):
125 """Tests raising a minSdkVersion attribute to a codename."""
126
Colin Cross1b6a3cf2018-07-24 14:51:30 -0700127 manifest_input = self.manifest_tmpl % self.uses_sdk(min='28')
Colin Cross496d66d2018-09-10 14:02:18 -0700128 expected = self.manifest_tmpl % self.uses_sdk(min='P', target='P')
Colin Cross7b59e7b2018-09-10 13:35:13 -0700129 output = self.raise_min_sdk_version_test(manifest_input, 'P', 'P', False)
Colin Cross8bb10e82018-06-07 16:46:02 -0700130 self.assertEqual(output, expected)
131
132 def test_no_raise_codename(self):
133 """Tests a minSdkVersion codename that doesn't need raising."""
134
Colin Cross1b6a3cf2018-07-24 14:51:30 -0700135 manifest_input = self.manifest_tmpl % self.uses_sdk(min='P')
Colin Cross496d66d2018-09-10 14:02:18 -0700136 expected = self.manifest_tmpl % self.uses_sdk(min='P', target='28')
Colin Cross7b59e7b2018-09-10 13:35:13 -0700137 output = self.raise_min_sdk_version_test(manifest_input, '28', '28', False)
Colin Cross8bb10e82018-06-07 16:46:02 -0700138 self.assertEqual(output, expected)
139
Colin Cross1b6a3cf2018-07-24 14:51:30 -0700140 def test_target(self):
141 """Tests an existing targetSdkVersion is preserved."""
142
143 manifest_input = self.manifest_tmpl % self.uses_sdk(min='26', target='27')
144 expected = self.manifest_tmpl % self.uses_sdk(min='28', target='27')
Colin Cross7b59e7b2018-09-10 13:35:13 -0700145 output = self.raise_min_sdk_version_test(manifest_input, '28', '29', False)
Colin Cross1b6a3cf2018-07-24 14:51:30 -0700146 self.assertEqual(output, expected)
147
148 def test_no_target(self):
149 """Tests inserting targetSdkVersion when minSdkVersion exists."""
150
151 manifest_input = self.manifest_tmpl % self.uses_sdk(min='27')
Colin Cross7b59e7b2018-09-10 13:35:13 -0700152 expected = self.manifest_tmpl % self.uses_sdk(min='28', target='29')
153 output = self.raise_min_sdk_version_test(manifest_input, '28', '29', False)
Colin Cross1b6a3cf2018-07-24 14:51:30 -0700154 self.assertEqual(output, expected)
155
156 def test_target_no_min(self):
Colin Cross7b59e7b2018-09-10 13:35:13 -0700157 """"Tests inserting targetSdkVersion when minSdkVersion exists."""
Colin Cross1b6a3cf2018-07-24 14:51:30 -0700158
Colin Cross496d66d2018-09-10 14:02:18 -0700159 manifest_input = self.manifest_tmpl % self.uses_sdk(target='27')
160 expected = self.manifest_tmpl % self.uses_sdk(min='28', target='27')
Colin Cross7b59e7b2018-09-10 13:35:13 -0700161 output = self.raise_min_sdk_version_test(manifest_input, '28', '29', False)
Colin Cross496d66d2018-09-10 14:02:18 -0700162 self.assertEqual(output, expected)
Colin Cross1b6a3cf2018-07-24 14:51:30 -0700163
164 def test_no_target_no_min(self):
165 """Tests inserting targetSdkVersion when minSdkVersion does not exist."""
166
167 manifest_input = self.manifest_tmpl % ''
Colin Cross7b59e7b2018-09-10 13:35:13 -0700168 expected = self.manifest_tmpl % self.uses_sdk(min='28', target='29')
169 output = self.raise_min_sdk_version_test(manifest_input, '28', '29', False)
Colin Cross1b6a3cf2018-07-24 14:51:30 -0700170 self.assertEqual(output, expected)
171
172 def test_library_no_target(self):
Colin Cross496d66d2018-09-10 14:02:18 -0700173 """Tests inserting targetSdkVersion when minSdkVersion exists."""
Colin Cross1b6a3cf2018-07-24 14:51:30 -0700174
Colin Cross496d66d2018-09-10 14:02:18 -0700175 manifest_input = self.manifest_tmpl % self.uses_sdk(min='27')
Colin Cross4b176062018-10-01 15:15:51 -0700176 expected = self.manifest_tmpl % self.uses_sdk(min='28', target='15')
Colin Cross7b59e7b2018-09-10 13:35:13 -0700177 output = self.raise_min_sdk_version_test(manifest_input, '28', '29', True)
Colin Cross496d66d2018-09-10 14:02:18 -0700178 self.assertEqual(output, expected)
Colin Cross1b6a3cf2018-07-24 14:51:30 -0700179
180 def test_library_target_no_min(self):
Colin Cross496d66d2018-09-10 14:02:18 -0700181 """Tests inserting targetSdkVersion when minSdkVersion exists."""
Colin Cross1b6a3cf2018-07-24 14:51:30 -0700182
Colin Cross496d66d2018-09-10 14:02:18 -0700183 manifest_input = self.manifest_tmpl % self.uses_sdk(target='27')
184 expected = self.manifest_tmpl % self.uses_sdk(min='28', target='27')
Colin Cross7b59e7b2018-09-10 13:35:13 -0700185 output = self.raise_min_sdk_version_test(manifest_input, '28', '29', True)
Colin Cross496d66d2018-09-10 14:02:18 -0700186 self.assertEqual(output, expected)
Colin Cross1b6a3cf2018-07-24 14:51:30 -0700187
188 def test_library_no_target_no_min(self):
Colin Cross496d66d2018-09-10 14:02:18 -0700189 """Tests inserting targetSdkVersion when minSdkVersion does not exist."""
Colin Cross1b6a3cf2018-07-24 14:51:30 -0700190
Colin Cross496d66d2018-09-10 14:02:18 -0700191 manifest_input = self.manifest_tmpl % ''
Colin Cross4b176062018-10-01 15:15:51 -0700192 expected = self.manifest_tmpl % self.uses_sdk(min='28', target='15')
Colin Cross7b59e7b2018-09-10 13:35:13 -0700193 output = self.raise_min_sdk_version_test(manifest_input, '28', '29', True)
Colin Cross496d66d2018-09-10 14:02:18 -0700194 self.assertEqual(output, expected)
Colin Cross1b6a3cf2018-07-24 14:51:30 -0700195
Colin Cross8bb10e82018-06-07 16:46:02 -0700196 def test_extra(self):
197 """Tests that extra attributes and elements are maintained."""
198
199 manifest_input = self.manifest_tmpl % (
200 ' <!-- comment -->\n'
201 ' <uses-sdk android:minSdkVersion="27" extra="foo"/>\n'
202 ' <application/>\n')
203
Colin Cross1b6a3cf2018-07-24 14:51:30 -0700204 # pylint: disable=line-too-long
Colin Cross8bb10e82018-06-07 16:46:02 -0700205 expected = self.manifest_tmpl % (
206 ' <!-- comment -->\n'
Colin Cross7b59e7b2018-09-10 13:35:13 -0700207 ' <uses-sdk android:minSdkVersion="28" android:targetSdkVersion="29" extra="foo"/>\n'
Colin Cross8bb10e82018-06-07 16:46:02 -0700208 ' <application/>\n')
209
Colin Cross7b59e7b2018-09-10 13:35:13 -0700210 output = self.raise_min_sdk_version_test(manifest_input, '28', '29', False)
Colin Cross8bb10e82018-06-07 16:46:02 -0700211
212 self.assertEqual(output, expected)
213
214 def test_indent(self):
215 """Tests that an inserted element copies the existing indentation."""
216
217 manifest_input = self.manifest_tmpl % ' <!-- comment -->\n'
218
Colin Cross1b6a3cf2018-07-24 14:51:30 -0700219 # pylint: disable=line-too-long
Colin Cross8bb10e82018-06-07 16:46:02 -0700220 expected = self.manifest_tmpl % (
Colin Cross7b59e7b2018-09-10 13:35:13 -0700221 ' <uses-sdk android:minSdkVersion="28" android:targetSdkVersion="29"/>\n'
Colin Cross8bb10e82018-06-07 16:46:02 -0700222 ' <!-- comment -->\n')
223
Colin Cross7b59e7b2018-09-10 13:35:13 -0700224 output = self.raise_min_sdk_version_test(manifest_input, '28', '29', False)
Colin Cross8bb10e82018-06-07 16:46:02 -0700225
226 self.assertEqual(output, expected)
227
Jiyong Parkc08f46f2018-06-18 11:01:00 +0900228
229class AddUsesLibrariesTest(unittest.TestCase):
230 """Unit tests for add_uses_libraries function."""
231
232 def run_test(self, input_manifest, new_uses_libraries):
233 doc = minidom.parseString(input_manifest)
234 manifest_fixer.add_uses_libraries(doc, new_uses_libraries)
235 output = StringIO.StringIO()
236 manifest_fixer.write_xml(output, doc)
237 return output.getvalue()
238
239 manifest_tmpl = (
240 '<?xml version="1.0" encoding="utf-8"?>\n'
241 '<manifest xmlns:android="http://schemas.android.com/apk/res/android">\n'
242 ' <application>\n'
243 '%s'
244 ' </application>\n'
245 '</manifest>\n')
246
247 def uses_libraries(self, name_required_pairs):
248 ret = ''
249 for name, required in name_required_pairs:
250 ret += (
251 ' <uses-library android:name="%s" android:required="%s"/>\n'
252 ) % (name, required)
253
254 return ret
255
256 def test_empty(self):
257 """Empty new_uses_libraries must not touch the manifest."""
258 manifest_input = self.manifest_tmpl % self.uses_libraries([
259 ('foo', 'true'),
260 ('bar', 'false')])
261 expected = manifest_input
262 output = self.run_test(manifest_input, [])
263 self.assertEqual(output, expected)
264
265 def test_not_overwrite(self):
266 """new_uses_libraries must not overwrite existing tags."""
267 manifest_input = self.manifest_tmpl % self.uses_libraries([
268 ('foo', 'true'),
269 ('bar', 'false')])
270 expected = manifest_input
271 output = self.run_test(manifest_input, ['foo', 'bar'])
272 self.assertEqual(output, expected)
273
274 def test_add(self):
275 """New names are added with 'required:true'."""
276 manifest_input = self.manifest_tmpl % self.uses_libraries([
277 ('foo', 'true'),
278 ('bar', 'false')])
279 expected = self.manifest_tmpl % self.uses_libraries([
280 ('foo', 'true'),
281 ('bar', 'false'),
282 ('baz', 'true'),
283 ('qux', 'true')])
284 output = self.run_test(manifest_input, ['bar', 'baz', 'qux'])
285 self.assertEqual(output, expected)
286
287 def test_no_application(self):
288 """When there is no <application> tag, the tag is added."""
289 manifest_input = (
290 '<?xml version="1.0" encoding="utf-8"?>\n'
291 '<manifest xmlns:android='
292 '"http://schemas.android.com/apk/res/android">\n'
293 '</manifest>\n')
294 expected = self.manifest_tmpl % self.uses_libraries([
295 ('foo', 'true'),
296 ('bar', 'true')])
297 output = self.run_test(manifest_input, ['foo', 'bar'])
298 self.assertEqual(output, expected)
299
300 def test_empty_application(self):
301 """Even when here is an empty <application/> tag, the libs are added."""
302 manifest_input = (
303 '<?xml version="1.0" encoding="utf-8"?>\n'
304 '<manifest xmlns:android='
305 '"http://schemas.android.com/apk/res/android">\n'
306 ' <application/>\n'
307 '</manifest>\n')
308 expected = self.manifest_tmpl % self.uses_libraries([
309 ('foo', 'true'),
310 ('bar', 'true')])
311 output = self.run_test(manifest_input, ['foo', 'bar'])
312 self.assertEqual(output, expected)
313
314
David Brazdild5b74992018-08-28 12:41:01 +0100315class AddUsesNonSdkApiTest(unittest.TestCase):
316 """Unit tests for add_uses_libraries function."""
317
318 def run_test(self, input_manifest):
319 doc = minidom.parseString(input_manifest)
320 manifest_fixer.add_uses_non_sdk_api(doc)
321 output = StringIO.StringIO()
322 manifest_fixer.write_xml(output, doc)
323 return output.getvalue()
324
325 manifest_tmpl = (
326 '<?xml version="1.0" encoding="utf-8"?>\n'
327 '<manifest xmlns:android="http://schemas.android.com/apk/res/android">\n'
328 ' <application%s/>\n'
329 '</manifest>\n')
330
331 def uses_non_sdk_api(self, value):
332 return ' android:usesNonSdkApi="true"' if value else ''
333
334 def test_set_true(self):
335 """Empty new_uses_libraries must not touch the manifest."""
336 manifest_input = self.manifest_tmpl % self.uses_non_sdk_api(False)
337 expected = self.manifest_tmpl % self.uses_non_sdk_api(True)
338 output = self.run_test(manifest_input)
339 self.assertEqual(output, expected)
340
341 def test_already_set(self):
342 """new_uses_libraries must not overwrite existing tags."""
343 manifest_input = self.manifest_tmpl % self.uses_non_sdk_api(True)
344 expected = manifest_input
345 output = self.run_test(manifest_input)
346 self.assertEqual(output, expected)
347
348
Victor Hsieha2c16c12019-01-02 14:50:56 -0800349class PreferCodeIntegrityTest(unittest.TestCase):
350 """Unit tests for add_prefer_code_integrity function."""
Victor Hsiehce7818e2018-10-22 11:16:25 -0700351
352 def run_test(self, input_manifest):
353 doc = minidom.parseString(input_manifest)
Victor Hsieha2c16c12019-01-02 14:50:56 -0800354 manifest_fixer.add_prefer_code_integrity(doc)
Victor Hsiehce7818e2018-10-22 11:16:25 -0700355 output = StringIO.StringIO()
356 manifest_fixer.write_xml(output, doc)
357 return output.getvalue()
358
359 manifest_tmpl = (
360 '<?xml version="1.0" encoding="utf-8"?>\n'
361 '<manifest xmlns:android="http://schemas.android.com/apk/res/android">\n'
362 ' <application%s/>\n'
363 '</manifest>\n')
364
Victor Hsieha2c16c12019-01-02 14:50:56 -0800365 def prefer_code_integrity(self, value):
366 return ' android:preferCodeIntegrity="%s"' % value
Victor Hsiehce7818e2018-10-22 11:16:25 -0700367
368 def test_manifest_with_undeclared_preference(self):
369 manifest_input = self.manifest_tmpl % ''
Victor Hsieha2c16c12019-01-02 14:50:56 -0800370 expected = self.manifest_tmpl % self.prefer_code_integrity('true')
Victor Hsiehce7818e2018-10-22 11:16:25 -0700371 output = self.run_test(manifest_input)
372 self.assertEqual(output, expected)
373
Victor Hsieha2c16c12019-01-02 14:50:56 -0800374 def test_manifest_with_prefer_code_integrity(self):
375 manifest_input = self.manifest_tmpl % self.prefer_code_integrity('true')
Victor Hsiehce7818e2018-10-22 11:16:25 -0700376 expected = manifest_input
377 output = self.run_test(manifest_input)
378 self.assertEqual(output, expected)
379
Victor Hsieha2c16c12019-01-02 14:50:56 -0800380 def test_manifest_with_not_prefer_code_integrity(self):
381 manifest_input = self.manifest_tmpl % self.prefer_code_integrity('false')
Victor Hsiehce7818e2018-10-22 11:16:25 -0700382 self.assertRaises(RuntimeError, self.run_test, manifest_input)
383
Colin Cross8bb10e82018-06-07 16:46:02 -0700384if __name__ == '__main__':
385 unittest.main()