• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_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
57  def raise_min_sdk_version_test(self, input_manifest, min_sdk_version,
58                                 target_sdk_version, library):
59    doc = minidom.parseString(input_manifest)
60    manifest_fixer.raise_min_sdk_version(doc, min_sdk_version,
61                                         target_sdk_version, library)
62    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
72  # pylint: disable=redefined-builtin
73  def uses_sdk(self, min=None, target=None, extra=''):
74    attrs = ''
75    if min:
76      attrs += ' android:minSdkVersion="%s"' % (min)
77    if target:
78      attrs += ' android:targetSdkVersion="%s"' % (target)
79    if extra:
80      attrs += ' ' + extra
81    return '    <uses-sdk%s/>\n' % (attrs)
82
83  def test_no_uses_sdk(self):
84    """Tests inserting a uses-sdk element into a manifest."""
85
86    manifest_input = self.manifest_tmpl % ''
87    expected = self.manifest_tmpl % self.uses_sdk(min='28', target='28')
88    output = self.raise_min_sdk_version_test(manifest_input, '28', '28', False)
89    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'
95    expected = self.manifest_tmpl % self.uses_sdk(min='28', target='28',
96                                                  extra='extra="foo"')
97    output = self.raise_min_sdk_version_test(manifest_input, '28', '28', False)
98    self.assertEqual(output, expected)
99
100  def test_raise_min(self):
101    """Tests inserting a minSdkVersion attribute into a uses-sdk element."""
102
103    manifest_input = self.manifest_tmpl % self.uses_sdk(min='27')
104    expected = self.manifest_tmpl % self.uses_sdk(min='28', target='28')
105    output = self.raise_min_sdk_version_test(manifest_input, '28', '28', False)
106    self.assertEqual(output, expected)
107
108  def test_raise(self):
109    """Tests raising a minSdkVersion attribute."""
110
111    manifest_input = self.manifest_tmpl % self.uses_sdk(min='27')
112    expected = self.manifest_tmpl % self.uses_sdk(min='28', target='28')
113    output = self.raise_min_sdk_version_test(manifest_input, '28', '28', False)
114    self.assertEqual(output, expected)
115
116  def test_no_raise_min(self):
117    """Tests a minSdkVersion that doesn't need raising."""
118
119    manifest_input = self.manifest_tmpl % self.uses_sdk(min='28')
120    expected = self.manifest_tmpl % self.uses_sdk(min='28', target='27')
121    output = self.raise_min_sdk_version_test(manifest_input, '27', '27', False)
122    self.assertEqual(output, expected)
123
124  def test_raise_codename(self):
125    """Tests raising a minSdkVersion attribute to a codename."""
126
127    manifest_input = self.manifest_tmpl % self.uses_sdk(min='28')
128    expected = self.manifest_tmpl % self.uses_sdk(min='P', target='P')
129    output = self.raise_min_sdk_version_test(manifest_input, 'P', 'P', False)
130    self.assertEqual(output, expected)
131
132  def test_no_raise_codename(self):
133    """Tests a minSdkVersion codename that doesn't need raising."""
134
135    manifest_input = self.manifest_tmpl % self.uses_sdk(min='P')
136    expected = self.manifest_tmpl % self.uses_sdk(min='P', target='28')
137    output = self.raise_min_sdk_version_test(manifest_input, '28', '28', False)
138    self.assertEqual(output, expected)
139
140  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')
145    output = self.raise_min_sdk_version_test(manifest_input, '28', '29', False)
146    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')
152    expected = self.manifest_tmpl % self.uses_sdk(min='28', target='29')
153    output = self.raise_min_sdk_version_test(manifest_input, '28', '29', False)
154    self.assertEqual(output, expected)
155
156  def test_target_no_min(self):
157    """"Tests inserting targetSdkVersion when minSdkVersion exists."""
158
159    manifest_input = self.manifest_tmpl % self.uses_sdk(target='27')
160    expected = self.manifest_tmpl % self.uses_sdk(min='28', target='27')
161    output = self.raise_min_sdk_version_test(manifest_input, '28', '29', False)
162    self.assertEqual(output, expected)
163
164  def test_no_target_no_min(self):
165    """Tests inserting targetSdkVersion when minSdkVersion does not exist."""
166
167    manifest_input = self.manifest_tmpl % ''
168    expected = self.manifest_tmpl % self.uses_sdk(min='28', target='29')
169    output = self.raise_min_sdk_version_test(manifest_input, '28', '29', False)
170    self.assertEqual(output, expected)
171
172  def test_library_no_target(self):
173    """Tests inserting targetSdkVersion when minSdkVersion exists."""
174
175    manifest_input = self.manifest_tmpl % self.uses_sdk(min='27')
176    expected = self.manifest_tmpl % self.uses_sdk(min='28', target='15')
177    output = self.raise_min_sdk_version_test(manifest_input, '28', '29', True)
178    self.assertEqual(output, expected)
179
180  def test_library_target_no_min(self):
181    """Tests inserting targetSdkVersion when minSdkVersion exists."""
182
183    manifest_input = self.manifest_tmpl % self.uses_sdk(target='27')
184    expected = self.manifest_tmpl % self.uses_sdk(min='28', target='27')
185    output = self.raise_min_sdk_version_test(manifest_input, '28', '29', True)
186    self.assertEqual(output, expected)
187
188  def test_library_no_target_no_min(self):
189    """Tests inserting targetSdkVersion when minSdkVersion does not exist."""
190
191    manifest_input = self.manifest_tmpl % ''
192    expected = self.manifest_tmpl % self.uses_sdk(min='28', target='15')
193    output = self.raise_min_sdk_version_test(manifest_input, '28', '29', True)
194    self.assertEqual(output, expected)
195
196  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
204    # pylint: disable=line-too-long
205    expected = self.manifest_tmpl % (
206        '    <!-- comment -->\n'
207        '    <uses-sdk android:minSdkVersion="28" android:targetSdkVersion="29" extra="foo"/>\n'
208        '    <application/>\n')
209
210    output = self.raise_min_sdk_version_test(manifest_input, '28', '29', False)
211
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
219    # pylint: disable=line-too-long
220    expected = self.manifest_tmpl % (
221        '  <uses-sdk android:minSdkVersion="28" android:targetSdkVersion="29"/>\n'
222        '  <!-- comment -->\n')
223
224    output = self.raise_min_sdk_version_test(manifest_input, '28', '29', False)
225
226    self.assertEqual(output, expected)
227
228
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
315class 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
349class UseEmbeddedDexTest(unittest.TestCase):
350  """Unit tests for add_use_embedded_dex function."""
351
352  def run_test(self, input_manifest):
353    doc = minidom.parseString(input_manifest)
354    manifest_fixer.add_use_embedded_dex(doc)
355    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
365  def use_embedded_dex(self, value):
366    return ' android:useEmbeddedDex="%s"' % value
367
368  def test_manifest_with_undeclared_preference(self):
369    manifest_input = self.manifest_tmpl % ''
370    expected = self.manifest_tmpl % self.use_embedded_dex('true')
371    output = self.run_test(manifest_input)
372    self.assertEqual(output, expected)
373
374  def test_manifest_with_use_embedded_dex(self):
375    manifest_input = self.manifest_tmpl % self.use_embedded_dex('true')
376    expected = manifest_input
377    output = self.run_test(manifest_input)
378    self.assertEqual(output, expected)
379
380  def test_manifest_with_not_use_embedded_dex(self):
381    manifest_input = self.manifest_tmpl % self.use_embedded_dex('false')
382    self.assertRaises(RuntimeError, self.run_test, manifest_input)
383
384
385class AddExtractNativeLibsTest(unittest.TestCase):
386  """Unit tests for add_extract_native_libs function."""
387
388  def run_test(self, input_manifest, value):
389    doc = minidom.parseString(input_manifest)
390    manifest_fixer.add_extract_native_libs(doc, value)
391    output = StringIO.StringIO()
392    manifest_fixer.write_xml(output, doc)
393    return output.getvalue()
394
395  manifest_tmpl = (
396    '<?xml version="1.0" encoding="utf-8"?>\n'
397    '<manifest xmlns:android="http://schemas.android.com/apk/res/android">\n'
398    '    <application%s/>\n'
399    '</manifest>\n')
400
401  def extract_native_libs(self, value):
402    return ' android:extractNativeLibs="%s"' % value
403
404  def test_set_true(self):
405    manifest_input = self.manifest_tmpl % ''
406    expected = self.manifest_tmpl % self.extract_native_libs('true')
407    output = self.run_test(manifest_input, True)
408    self.assertEqual(output, expected)
409
410  def test_set_false(self):
411    manifest_input = self.manifest_tmpl % ''
412    expected = self.manifest_tmpl % self.extract_native_libs('false')
413    output = self.run_test(manifest_input, False)
414    self.assertEqual(output, expected)
415
416  def test_match(self):
417    manifest_input = self.manifest_tmpl % self.extract_native_libs('true')
418    expected = manifest_input
419    output = self.run_test(manifest_input, True)
420    self.assertEqual(output, expected)
421
422  def test_conflict(self):
423    manifest_input = self.manifest_tmpl % self.extract_native_libs('true')
424    self.assertRaises(RuntimeError, self.run_test, manifest_input, False)
425
426
427if __name__ == '__main__':
428  unittest.main()
429