xref: /aosp_15_r20/build/soong/scripts/manifest_fixer_test.py (revision 333d2b3687b3a337dbcca9d65000bca186795e39)
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 io
20import sys
21import unittest
22from xml.dom import minidom
23import xml.etree.ElementTree as ElementTree
24
25import manifest_fixer
26
27sys.dont_write_bytecode = True
28
29
30class CompareVersionGtTest(unittest.TestCase):
31  """Unit tests for compare_version_gt function."""
32
33  def test_sdk(self):
34    """Test comparing sdk versions."""
35    self.assertTrue(manifest_fixer.compare_version_gt('28', '27'))
36    self.assertFalse(manifest_fixer.compare_version_gt('27', '28'))
37    self.assertFalse(manifest_fixer.compare_version_gt('28', '28'))
38
39  def test_codename(self):
40    """Test comparing codenames."""
41    self.assertTrue(manifest_fixer.compare_version_gt('Q', 'P'))
42    self.assertFalse(manifest_fixer.compare_version_gt('P', 'Q'))
43    self.assertFalse(manifest_fixer.compare_version_gt('Q', 'Q'))
44
45  def test_sdk_codename(self):
46    """Test comparing sdk versions with codenames."""
47    self.assertTrue(manifest_fixer.compare_version_gt('Q', '28'))
48    self.assertFalse(manifest_fixer.compare_version_gt('28', 'Q'))
49
50  def test_compare_numeric(self):
51    """Test that numbers are compared in numeric and not lexicographic order."""
52    self.assertTrue(manifest_fixer.compare_version_gt('18', '8'))
53
54
55class RaiseMinSdkVersionTest(unittest.TestCase):
56  """Unit tests for raise_min_sdk_version function."""
57
58  def raise_min_sdk_version_test(self, input_manifest, min_sdk_version,
59                                 target_sdk_version, library):
60    doc = minidom.parseString(input_manifest)
61    manifest_fixer.raise_min_sdk_version(doc, min_sdk_version,
62                                         target_sdk_version, library)
63    output = io.StringIO()
64    manifest_fixer.write_xml(output, doc)
65    return output.getvalue()
66
67  manifest_tmpl = (
68      '<?xml version="1.0" encoding="utf-8"?>\n'
69      '<manifest xmlns:android="http://schemas.android.com/apk/res/android">\n'
70      '%s'
71      '</manifest>\n')
72
73  def uses_sdk(self, min_sdk=None, target_sdk=None, extra=''):
74    attrs = ''
75    if min_sdk:
76      attrs += ' android:minSdkVersion="%s"' % min_sdk
77    if target_sdk:
78      attrs += ' android:targetSdkVersion="%s"' % target_sdk
79    if extra:
80      attrs += ' ' + extra
81    return '    <uses-sdk%s/>\n' % attrs
82
83  def assert_xml_equal(self, output, expected):
84    self.assertEqual(ElementTree.canonicalize(output), ElementTree.canonicalize(expected))
85
86  def test_no_uses_sdk(self):
87    """Tests inserting a uses-sdk element into a manifest."""
88
89    manifest_input = self.manifest_tmpl % ''
90    expected = self.manifest_tmpl % self.uses_sdk(min_sdk='28', target_sdk='28')
91    output = self.raise_min_sdk_version_test(manifest_input, '28', '28', False)
92    self.assert_xml_equal(output, expected)
93
94  def test_no_min(self):
95    """Tests inserting a minSdkVersion attribute into a uses-sdk element."""
96
97    manifest_input = self.manifest_tmpl % '    <uses-sdk extra="foo"/>\n'
98    expected = self.manifest_tmpl % self.uses_sdk(min_sdk='28', target_sdk='28',
99                                                  extra='extra="foo"')
100    output = self.raise_min_sdk_version_test(manifest_input, '28', '28', False)
101    self.assert_xml_equal(output, expected)
102
103  def test_raise_min(self):
104    """Tests inserting a minSdkVersion attribute into a uses-sdk element."""
105
106    manifest_input = self.manifest_tmpl % self.uses_sdk(min_sdk='27')
107    expected = self.manifest_tmpl % self.uses_sdk(min_sdk='28', target_sdk='28')
108    output = self.raise_min_sdk_version_test(manifest_input, '28', '28', False)
109    self.assert_xml_equal(output, expected)
110
111  def test_raise(self):
112    """Tests raising a minSdkVersion attribute."""
113
114    manifest_input = self.manifest_tmpl % self.uses_sdk(min_sdk='27')
115    expected = self.manifest_tmpl % self.uses_sdk(min_sdk='28', target_sdk='28')
116    output = self.raise_min_sdk_version_test(manifest_input, '28', '28', False)
117    self.assert_xml_equal(output, expected)
118
119  def test_no_raise_min(self):
120    """Tests a minSdkVersion that doesn't need raising."""
121
122    manifest_input = self.manifest_tmpl % self.uses_sdk(min_sdk='28')
123    expected = self.manifest_tmpl % self.uses_sdk(min_sdk='28', target_sdk='27')
124    output = self.raise_min_sdk_version_test(manifest_input, '27', '27', False)
125    self.assert_xml_equal(output, expected)
126
127  def test_raise_codename(self):
128    """Tests raising a minSdkVersion attribute to a codename."""
129
130    manifest_input = self.manifest_tmpl % self.uses_sdk(min_sdk='28')
131    expected = self.manifest_tmpl % self.uses_sdk(min_sdk='P', target_sdk='P')
132    output = self.raise_min_sdk_version_test(manifest_input, 'P', 'P', False)
133    self.assert_xml_equal(output, expected)
134
135  def test_no_raise_codename(self):
136    """Tests a minSdkVersion codename that doesn't need raising."""
137
138    manifest_input = self.manifest_tmpl % self.uses_sdk(min_sdk='P')
139    expected = self.manifest_tmpl % self.uses_sdk(min_sdk='P', target_sdk='28')
140    output = self.raise_min_sdk_version_test(manifest_input, '28', '28', False)
141    self.assert_xml_equal(output, expected)
142
143  def test_target(self):
144    """Tests an existing targetSdkVersion is preserved."""
145
146    manifest_input = self.manifest_tmpl % self.uses_sdk(min_sdk='26', target_sdk='27')
147    expected = self.manifest_tmpl % self.uses_sdk(min_sdk='28', target_sdk='27')
148    output = self.raise_min_sdk_version_test(manifest_input, '28', '29', False)
149    self.assert_xml_equal(output, expected)
150
151  def test_no_target(self):
152    """Tests inserting targetSdkVersion when minSdkVersion exists."""
153
154    manifest_input = self.manifest_tmpl % self.uses_sdk(min_sdk='27')
155    expected = self.manifest_tmpl % self.uses_sdk(min_sdk='28', target_sdk='29')
156    output = self.raise_min_sdk_version_test(manifest_input, '28', '29', False)
157    self.assert_xml_equal(output, expected)
158
159  def test_target_no_min(self):
160    """"Tests inserting targetSdkVersion when minSdkVersion exists."""
161
162    manifest_input = self.manifest_tmpl % self.uses_sdk(target_sdk='27')
163    expected = self.manifest_tmpl % self.uses_sdk(min_sdk='28', target_sdk='27')
164    output = self.raise_min_sdk_version_test(manifest_input, '28', '29', False)
165    self.assert_xml_equal(output, expected)
166
167  def test_no_target_no_min(self):
168    """Tests inserting targetSdkVersion when minSdkVersion does not exist."""
169
170    manifest_input = self.manifest_tmpl % ''
171    expected = self.manifest_tmpl % self.uses_sdk(min_sdk='28', target_sdk='29')
172    output = self.raise_min_sdk_version_test(manifest_input, '28', '29', False)
173    self.assert_xml_equal(output, expected)
174
175  def test_library_no_target(self):
176    """Tests inserting targetSdkVersion when minSdkVersion exists."""
177
178    manifest_input = self.manifest_tmpl % self.uses_sdk(min_sdk='27')
179    expected = self.manifest_tmpl % self.uses_sdk(min_sdk='28', target_sdk='16')
180    output = self.raise_min_sdk_version_test(manifest_input, '28', '29', True)
181    self.assert_xml_equal(output, expected)
182
183  def test_library_target_no_min(self):
184    """Tests inserting targetSdkVersion when minSdkVersion exists."""
185
186    manifest_input = self.manifest_tmpl % self.uses_sdk(target_sdk='27')
187    expected = self.manifest_tmpl % self.uses_sdk(min_sdk='28', target_sdk='27')
188    output = self.raise_min_sdk_version_test(manifest_input, '28', '29', True)
189    self.assert_xml_equal(output, expected)
190
191  def test_library_no_target_no_min(self):
192    """Tests inserting targetSdkVersion when minSdkVersion does not exist."""
193
194    manifest_input = self.manifest_tmpl % ''
195    expected = self.manifest_tmpl % self.uses_sdk(min_sdk='28', target_sdk='16')
196    output = self.raise_min_sdk_version_test(manifest_input, '28', '29', True)
197    self.assert_xml_equal(output, expected)
198
199  def test_extra(self):
200    """Tests that extra attributes and elements are maintained."""
201
202    manifest_input = self.manifest_tmpl % (
203        '    <!-- comment -->\n'
204        '    <uses-sdk android:minSdkVersion="27" extra="foo"/>\n'
205        '    <application/>\n')
206
207    # pylint: disable=line-too-long
208    expected = self.manifest_tmpl % (
209        '    <!-- comment -->\n'
210        '    <uses-sdk android:minSdkVersion="28" extra="foo" android:targetSdkVersion="29"/>\n'
211        '    <application/>\n')
212
213    output = self.raise_min_sdk_version_test(manifest_input, '28', '29', False)
214
215    self.assert_xml_equal(output, expected)
216
217  def test_indent(self):
218    """Tests that an inserted element copies the existing indentation."""
219
220    manifest_input = self.manifest_tmpl % '  <!-- comment -->\n'
221
222    # pylint: disable=line-too-long
223    expected = self.manifest_tmpl % (
224        '  <uses-sdk android:minSdkVersion="28" android:targetSdkVersion="29"/>\n'
225        '  <!-- comment -->\n')
226
227    output = self.raise_min_sdk_version_test(manifest_input, '28', '29', False)
228
229    self.assert_xml_equal(output, expected)
230
231  def test_multiple_uses_sdks(self):
232    """Tests a manifest that contains multiple uses_sdks elements."""
233
234    manifest_input = self.manifest_tmpl % (
235        '    <uses-sdk android:featureFlag="foo" android:minSdkVersion="21" />\n'
236        '    <uses-sdk android:featureFlag="!foo" android:minSdkVersion="22" />\n')
237    expected = self.manifest_tmpl % (
238      '    <uses-sdk android:featureFlag="foo" android:minSdkVersion="28" android:targetSdkVersion="28" />\n'
239      '    <uses-sdk android:featureFlag="!foo" android:minSdkVersion="28" android:targetSdkVersion="28" />\n')
240
241    output = self.raise_min_sdk_version_test(manifest_input, '28', '28', False)
242    self.assert_xml_equal(output, expected)
243
244class AddLoggingParentTest(unittest.TestCase):
245  """Unit tests for add_logging_parent function."""
246
247  def assert_xml_equal(self, output, expected):
248    self.assertEqual(ElementTree.canonicalize(output), ElementTree.canonicalize(expected))
249
250  def add_logging_parent_test(self, input_manifest, logging_parent=None):
251    doc = minidom.parseString(input_manifest)
252    if logging_parent:
253      manifest_fixer.add_logging_parent(doc, logging_parent)
254    output = io.StringIO()
255    manifest_fixer.write_xml(output, doc)
256    return output.getvalue()
257
258  manifest_tmpl = (
259      '<?xml version="1.0" encoding="utf-8"?>\n'
260      '<manifest xmlns:android="http://schemas.android.com/apk/res/android">\n'
261      '%s'
262      '</manifest>\n')
263
264  def uses_logging_parent(self, logging_parent=None):
265    attrs = ''
266    if logging_parent:
267      meta_text = ('<meta-data android:name="android.content.pm.LOGGING_PARENT" '
268                   'android:value="%s"/>\n') % logging_parent
269      attrs += '    <application>\n        %s    </application>\n' % meta_text
270
271    return attrs
272
273  def test_no_logging_parent(self):
274    """Tests manifest_fixer with no logging_parent."""
275    manifest_input = self.manifest_tmpl % ''
276    expected = self.manifest_tmpl % self.uses_logging_parent()
277    output = self.add_logging_parent_test(manifest_input)
278    self.assert_xml_equal(output, expected)
279
280  def test_logging_parent(self):
281    """Tests manifest_fixer with no logging_parent."""
282    manifest_input = self.manifest_tmpl % ''
283    expected = self.manifest_tmpl % self.uses_logging_parent('FOO')
284    output = self.add_logging_parent_test(manifest_input, 'FOO')
285    self.assert_xml_equal(output, expected)
286
287
288class AddUsesLibrariesTest(unittest.TestCase):
289  """Unit tests for add_uses_libraries function."""
290
291  def assert_xml_equal(self, output, expected):
292    self.assertEqual(ElementTree.canonicalize(output), ElementTree.canonicalize(expected))
293
294  def run_test(self, input_manifest, new_uses_libraries):
295    doc = minidom.parseString(input_manifest)
296    manifest_fixer.add_uses_libraries(doc, new_uses_libraries, True)
297    output = io.StringIO()
298    manifest_fixer.write_xml(output, doc)
299    return output.getvalue()
300
301  manifest_tmpl = (
302      '<?xml version="1.0" encoding="utf-8"?>\n'
303      '<manifest xmlns:android="http://schemas.android.com/apk/res/android">\n'
304      '%s'
305      '</manifest>\n')
306
307  def uses_libraries(self, name_required_pairs):
308    ret = '    <application>\n'
309    for name, required in name_required_pairs:
310      ret += (
311          '        <uses-library android:name="%s" android:required="%s"/>\n'
312      ) % (name, required)
313    ret += '    </application>\n'
314    return ret
315
316  def test_empty(self):
317    """Empty new_uses_libraries must not touch the manifest."""
318    manifest_input = self.manifest_tmpl % self.uses_libraries([
319        ('foo', 'true'),
320        ('bar', 'false')])
321    expected = manifest_input
322    output = self.run_test(manifest_input, [])
323    self.assert_xml_equal(output, expected)
324
325  def test_not_overwrite(self):
326    """new_uses_libraries must not overwrite existing tags."""
327    manifest_input = self.manifest_tmpl % self.uses_libraries([
328        ('foo', 'true'),
329        ('bar', 'false')])
330    expected = manifest_input
331    output = self.run_test(manifest_input, ['foo', 'bar'])
332    self.assert_xml_equal(output, expected)
333
334  def test_add(self):
335    """New names are added with 'required:true'."""
336    manifest_input = self.manifest_tmpl % self.uses_libraries([
337        ('foo', 'true'),
338        ('bar', 'false')])
339    expected = self.manifest_tmpl % self.uses_libraries([
340        ('foo', 'true'),
341        ('bar', 'false'),
342        ('baz', 'true'),
343        ('qux', 'true')])
344    output = self.run_test(manifest_input, ['bar', 'baz', 'qux'])
345    self.assert_xml_equal(output, expected)
346
347  def test_no_application(self):
348    """When there is no <application> tag, the tag is added."""
349    manifest_input = (
350        '<?xml version="1.0" encoding="utf-8"?>\n'
351        '<manifest xmlns:android='
352        '"http://schemas.android.com/apk/res/android">\n'
353        '</manifest>\n')
354    expected = self.manifest_tmpl % self.uses_libraries([
355        ('foo', 'true'),
356        ('bar', 'true')])
357    output = self.run_test(manifest_input, ['foo', 'bar'])
358    self.assert_xml_equal(output, expected)
359
360  def test_empty_application(self):
361    """Even when here is an empty <application/> tag, the libs are added."""
362    manifest_input = (
363        '<?xml version="1.0" encoding="utf-8"?>\n'
364        '<manifest xmlns:android='
365        '"http://schemas.android.com/apk/res/android">\n'
366        '    <application/>\n'
367        '</manifest>\n')
368    expected = self.manifest_tmpl % self.uses_libraries([
369        ('foo', 'true'),
370        ('bar', 'true')])
371    output = self.run_test(manifest_input, ['foo', 'bar'])
372    self.assert_xml_equal(output, expected)
373
374  def test_multiple_application(self):
375    """When there are multiple applications, the libs are added to each."""
376    manifest_input = self.manifest_tmpl % (
377            self.uses_libraries([('foo', 'false')]) +
378            self.uses_libraries([('bar', 'false')]))
379    expected = self.manifest_tmpl % (
380            self.uses_libraries([('foo', 'false'), ('bar', 'true')]) +
381            self.uses_libraries([('bar', 'false'), ('foo', 'true')]))
382    output = self.run_test(manifest_input, ['foo', 'bar'])
383    self.assert_xml_equal(output, expected)
384
385
386class AddUsesNonSdkApiTest(unittest.TestCase):
387  """Unit tests for add_uses_libraries function."""
388
389  def assert_xml_equal(self, output, expected):
390    self.assertEqual(ElementTree.canonicalize(output), ElementTree.canonicalize(expected))
391
392  def run_test(self, input_manifest):
393    doc = minidom.parseString(input_manifest)
394    manifest_fixer.add_uses_non_sdk_api(doc)
395    output = io.StringIO()
396    manifest_fixer.write_xml(output, doc)
397    return output.getvalue()
398
399  manifest_tmpl = (
400      '<?xml version="1.0" encoding="utf-8"?>\n'
401      '<manifest xmlns:android="http://schemas.android.com/apk/res/android">\n'
402      '    %s\n'
403      '</manifest>\n')
404
405  def uses_non_sdk_api(self, value):
406    return '<application %s/>' % ('android:usesNonSdkApi="true"' if value else '')
407
408  def test_set_true(self):
409    """Empty new_uses_libraries must not touch the manifest."""
410    manifest_input = self.manifest_tmpl % self.uses_non_sdk_api(False)
411    expected = self.manifest_tmpl % self.uses_non_sdk_api(True)
412    output = self.run_test(manifest_input)
413    self.assert_xml_equal(output, expected)
414
415  def test_already_set(self):
416    """new_uses_libraries must not overwrite existing tags."""
417    manifest_input = self.manifest_tmpl % self.uses_non_sdk_api(True)
418    expected = manifest_input
419    output = self.run_test(manifest_input)
420    self.assert_xml_equal(output, expected)
421
422  def test_multiple_applications(self):
423    """new_uses_libraries must be added to all applications."""
424    manifest_input = self.manifest_tmpl % (self.uses_non_sdk_api(True) +  self.uses_non_sdk_api(False))
425    expected = self.manifest_tmpl % (self.uses_non_sdk_api(True) +  self.uses_non_sdk_api(True))
426    output = self.run_test(manifest_input)
427    self.assert_xml_equal(output, expected)
428
429
430class UseEmbeddedDexTest(unittest.TestCase):
431  """Unit tests for add_use_embedded_dex function."""
432
433  def assert_xml_equal(self, output, expected):
434    self.assertEqual(ElementTree.canonicalize(output), ElementTree.canonicalize(expected))
435
436  def run_test(self, input_manifest):
437    doc = minidom.parseString(input_manifest)
438    manifest_fixer.add_use_embedded_dex(doc)
439    output = io.StringIO()
440    manifest_fixer.write_xml(output, doc)
441    return output.getvalue()
442
443  manifest_tmpl = (
444      '<?xml version="1.0" encoding="utf-8"?>\n'
445      '<manifest xmlns:android="http://schemas.android.com/apk/res/android">\n'
446      '    %s\n'
447      '</manifest>\n')
448
449  def use_embedded_dex(self, value):
450    return '<application android:useEmbeddedDex="%s" />' % value
451
452  def test_manifest_with_undeclared_preference(self):
453    manifest_input = self.manifest_tmpl % '<application/>'
454    expected = self.manifest_tmpl % self.use_embedded_dex('true')
455    output = self.run_test(manifest_input)
456    self.assert_xml_equal(output, expected)
457
458  def test_manifest_with_use_embedded_dex(self):
459    manifest_input = self.manifest_tmpl % self.use_embedded_dex('true')
460    expected = manifest_input
461    output = self.run_test(manifest_input)
462    self.assert_xml_equal(output, expected)
463
464  def test_manifest_with_not_use_embedded_dex(self):
465    manifest_input = self.manifest_tmpl % self.use_embedded_dex('false')
466    self.assertRaises(RuntimeError, self.run_test, manifest_input)
467
468  def test_multiple_applications(self):
469    manifest_input = self.manifest_tmpl % (
470        self.use_embedded_dex('true') +
471        '<application/>'
472    )
473    expected = self.manifest_tmpl % (
474        self.use_embedded_dex('true') +
475        self.use_embedded_dex('true')
476    )
477    output = self.run_test(manifest_input)
478    self.assert_xml_equal(output, expected)
479
480
481class AddExtractNativeLibsTest(unittest.TestCase):
482  """Unit tests for add_extract_native_libs function."""
483
484  def assert_xml_equal(self, output, expected):
485    self.assertEqual(ElementTree.canonicalize(output), ElementTree.canonicalize(expected))
486
487  def run_test(self, input_manifest, value):
488    doc = minidom.parseString(input_manifest)
489    manifest_fixer.add_extract_native_libs(doc, value)
490    output = io.StringIO()
491    manifest_fixer.write_xml(output, doc)
492    return output.getvalue()
493
494  manifest_tmpl = (
495      '<?xml version="1.0" encoding="utf-8"?>\n'
496      '<manifest xmlns:android="http://schemas.android.com/apk/res/android">\n'
497      '    %s\n'
498      '</manifest>\n')
499
500  def extract_native_libs(self, value):
501    return '<application android:extractNativeLibs="%s" />' % value
502
503  def test_set_true(self):
504    manifest_input = self.manifest_tmpl % '<application/>'
505    expected = self.manifest_tmpl % self.extract_native_libs('true')
506    output = self.run_test(manifest_input, True)
507    self.assert_xml_equal(output, expected)
508
509  def test_set_false(self):
510    manifest_input = self.manifest_tmpl % '<application/>'
511    expected = self.manifest_tmpl % self.extract_native_libs('false')
512    output = self.run_test(manifest_input, False)
513    self.assert_xml_equal(output, expected)
514
515  def test_match(self):
516    manifest_input = self.manifest_tmpl % self.extract_native_libs('true')
517    expected = manifest_input
518    output = self.run_test(manifest_input, True)
519    self.assert_xml_equal(output, expected)
520
521  def test_conflict(self):
522    manifest_input = self.manifest_tmpl % self.extract_native_libs('true')
523    self.assertRaises(RuntimeError, self.run_test, manifest_input, False)
524
525  def test_multiple_applications(self):
526    manifest_input = self.manifest_tmpl % (self.extract_native_libs('true') + '<application/>')
527    expected = self.manifest_tmpl % (self.extract_native_libs('true') + self.extract_native_libs('true'))
528    output = self.run_test(manifest_input, True)
529    self.assert_xml_equal(output, expected)
530
531
532class AddNoCodeApplicationTest(unittest.TestCase):
533  """Unit tests for set_has_code_to_false function."""
534
535  def assert_xml_equal(self, output, expected):
536    self.assertEqual(ElementTree.canonicalize(output), ElementTree.canonicalize(expected))
537
538  def run_test(self, input_manifest):
539    doc = minidom.parseString(input_manifest)
540    manifest_fixer.set_has_code_to_false(doc)
541    output = io.StringIO()
542    manifest_fixer.write_xml(output, doc)
543    return output.getvalue()
544
545  manifest_tmpl = (
546      '<?xml version="1.0" encoding="utf-8"?>\n'
547      '<manifest xmlns:android="http://schemas.android.com/apk/res/android">\n'
548      '%s'
549      '</manifest>\n')
550
551  def test_no_application(self):
552    manifest_input = self.manifest_tmpl % ''
553    expected = self.manifest_tmpl % '    <application android:hasCode="false"/>\n'
554    output = self.run_test(manifest_input)
555    self.assert_xml_equal(output, expected)
556
557  def test_has_application_no_has_code(self):
558    manifest_input = self.manifest_tmpl % '    <application/>\n'
559    expected = self.manifest_tmpl % '    <application android:hasCode="false"/>\n'
560    output = self.run_test(manifest_input)
561    self.assert_xml_equal(output, expected)
562
563  def test_has_application_has_code_false(self):
564    """ Do nothing if there's already an application element. """
565    manifest_input = self.manifest_tmpl % '    <application android:hasCode="false"/>\n'
566    output = self.run_test(manifest_input)
567    self.assert_xml_equal(output, manifest_input)
568
569  def test_has_application_has_code_true(self):
570    """ Do nothing if there's already an application element even if its
571     hasCode attribute is true. """
572    manifest_input = self.manifest_tmpl % '    <application android:hasCode="true"/>\n'
573    output = self.run_test(manifest_input)
574    self.assert_xml_equal(output, manifest_input)
575
576  def test_multiple_applications(self):
577    """ Apply to all applications  """
578    manifest_input = self.manifest_tmpl % (
579        '    <application android:hasCode="true" />\n' +
580        '    <application android:hasCode="false" />\n' +
581        '    <application/>\n')
582    expected = self.manifest_tmpl % (
583        '    <application android:hasCode="true" />\n' +
584        '    <application android:hasCode="false" />\n' +
585        '    <application android:hasCode="false" />\n')
586    output = self.run_test(manifest_input)
587    self.assert_xml_equal(output, expected)
588
589
590class AddTestOnlyApplicationTest(unittest.TestCase):
591  """Unit tests for set_test_only_flag_to_true function."""
592
593  def assert_xml_equal(self, output, expected):
594    self.assertEqual(ElementTree.canonicalize(output), ElementTree.canonicalize(expected))
595
596  def run_test(self, input_manifest):
597    doc = minidom.parseString(input_manifest)
598    manifest_fixer.set_test_only_flag_to_true(doc)
599    output = io.StringIO()
600    manifest_fixer.write_xml(output, doc)
601    return output.getvalue()
602
603  manifest_tmpl = (
604      '<?xml version="1.0" encoding="utf-8"?>\n'
605      '<manifest xmlns:android="http://schemas.android.com/apk/res/android">\n'
606      '%s'
607      '</manifest>\n')
608
609  def test_no_application(self):
610    manifest_input = self.manifest_tmpl % ''
611    expected = self.manifest_tmpl % '    <application android:testOnly="true"/>\n'
612    output = self.run_test(manifest_input)
613    self.assert_xml_equal(output, expected)
614
615  def test_has_application_no_test_only(self):
616    manifest_input = self.manifest_tmpl % '    <application/>\n'
617    expected = self.manifest_tmpl % '    <application android:testOnly="true"/>\n'
618    output = self.run_test(manifest_input)
619    self.assert_xml_equal(output, expected)
620
621  def test_has_application_test_only_true(self):
622    """ If there's already an application element."""
623    manifest_input = self.manifest_tmpl % '    <application android:testOnly="true"/>\n'
624    output = self.run_test(manifest_input)
625    self.assert_xml_equal(output, manifest_input)
626
627  def test_has_application_test_only_false(self):
628    """ If there's already an application element with the testOnly attribute as false."""
629    manifest_input = self.manifest_tmpl % '    <application android:testOnly="false"/>\n'
630    output = self.run_test(manifest_input)
631    self.assert_xml_equal(output, manifest_input)
632
633  def test_multiple_applications(self):
634    manifest_input = self.manifest_tmpl % (
635        '    <application android:testOnly="true" />\n' +
636        '    <application android:testOnly="false" />\n' +
637        '    <application/>\n'
638    )
639    expected = self.manifest_tmpl % (
640        '    <application android:testOnly="true" />\n' +
641        '    <application android:testOnly="false" />\n' +
642        '    <application android:testOnly="true" />\n'
643    )
644    output = self.run_test(manifest_input)
645    self.assert_xml_equal(output, expected)
646
647
648class SetMaxSdkVersionTest(unittest.TestCase):
649  """Unit tests for set_max_sdk_version function."""
650
651  def assert_xml_equal(self, output, expected):
652    self.assertEqual(ElementTree.canonicalize(output), ElementTree.canonicalize(expected))
653
654  def run_test(self, input_manifest, max_sdk_version):
655    doc = minidom.parseString(input_manifest)
656    manifest_fixer.set_max_sdk_version(doc, max_sdk_version)
657    output = io.StringIO()
658    manifest_fixer.write_xml(output, doc)
659    return output.getvalue()
660
661  manifest_tmpl = (
662      '<?xml version="1.0" encoding="utf-8"?>\n'
663      '<manifest xmlns:android="http://schemas.android.com/apk/res/android">\n'
664      '%s'
665      '</manifest>\n')
666
667  def permission(self, max_sdk=None):
668    if max_sdk is None:
669      return '   <permission/>'
670    return '    <permission android:maxSdkVersion="%s"/>\n' % max_sdk
671
672  def uses_permission(self, max_sdk=None):
673    if max_sdk is None:
674      return '   <uses-permission/>'
675    return '    <uses-permission android:maxSdkVersion="%s"/>\n' % max_sdk
676
677  def test_permission_no_max_sdk_version(self):
678    """Tests if permission has no maxSdkVersion attribute"""
679    manifest_input = self.manifest_tmpl % self.permission()
680    expected = self.manifest_tmpl % self.permission()
681    output = self.run_test(manifest_input, '9000')
682    self.assert_xml_equal(output, expected)
683
684  def test_permission_max_sdk_version_changed(self):
685    """Tests if permission maxSdkVersion attribute is set to current"""
686    manifest_input = self.manifest_tmpl % self.permission('current')
687    expected = self.manifest_tmpl % self.permission(9000)
688    output = self.run_test(manifest_input, '9000')
689    self.assert_xml_equal(output, expected)
690
691  def test_permission_max_sdk_version_not_changed(self):
692    """Tests if permission maxSdkVersion attribute is not set to current"""
693    manifest_input = self.manifest_tmpl % self.permission(30)
694    expected = self.manifest_tmpl % self.permission(30)
695    output = self.run_test(manifest_input, '9000')
696    self.assert_xml_equal(output, expected)
697
698  def test_uses_permission_no_max_sdk_version(self):
699    """Tests if uses-permission has no maxSdkVersion attribute"""
700    manifest_input = self.manifest_tmpl % self.uses_permission()
701    expected = self.manifest_tmpl % self.uses_permission()
702    output = self.run_test(manifest_input, '9000')
703    self.assert_xml_equal(output, expected)
704
705  def test_uses_permission_max_sdk_version_changed(self):
706    """Tests if uses-permission maxSdkVersion attribute is set to current"""
707    manifest_input = self.manifest_tmpl % self.uses_permission('current')
708    expected = self.manifest_tmpl % self.uses_permission(9000)
709    output = self.run_test(manifest_input, '9000')
710    self.assert_xml_equal(output, expected)
711
712  def test_uses_permission_max_sdk_version_not_changed(self):
713    """Tests if uses-permission maxSdkVersion attribute is not set to current"""
714    manifest_input = self.manifest_tmpl % self.uses_permission(30)
715    expected = self.manifest_tmpl % self.uses_permission(30)
716    output = self.run_test(manifest_input, '9000')
717    self.assert_xml_equal(output, expected)
718
719
720class OverrideDefaultVersionTest(unittest.TestCase):
721  """Unit tests for override_default_version function."""
722
723  def assert_xml_equal(self, output, expected):
724    self.assertEqual(ElementTree.canonicalize(output), ElementTree.canonicalize(expected))
725
726  def run_test(self, input_manifest, version):
727    doc = minidom.parseString(input_manifest)
728    manifest_fixer.override_placeholder_version(doc, version)
729    output = io.StringIO()
730    manifest_fixer.write_xml(output, doc)
731    return output.getvalue()
732
733  manifest_tmpl = (
734      '<?xml version="1.0" encoding="utf-8"?>\n'
735      '<manifest xmlns:android="http://schemas.android.com/apk/res/android" '
736      'android:versionCode="%s">\n'
737      '</manifest>\n')
738
739  def test_doesnt_override_existing_version(self):
740    """Tests that an existing version is not overridden"""
741    manifest_input = self.manifest_tmpl % '12345'
742    expected = manifest_input
743    output = self.run_test(manifest_input, '67890')
744    self.assert_xml_equal(output, expected)
745
746  def test_overrides_default_version(self):
747    """Tests that a default version is overridden"""
748    manifest_input = self.manifest_tmpl % '0'
749    expected = self.manifest_tmpl % '67890'
750    output = self.run_test(manifest_input, '67890')
751    self.assert_xml_equal(output, expected)
752
753
754if __name__ == '__main__':
755  unittest.main(verbosity=2)
756