1#!/usr/bin/env python
2#
3# Copyright (C) 2019 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 process_compat_config.py."""
18
19import difflib
20import io
21from StringIO import StringIO
22import unittest
23import xml.dom.minidom
24from inspect import currentframe, getframeinfo
25
26import process_compat_config
27
28def here():
29    f = currentframe().f_back
30    return "%s:%d" % (getframeinfo(f).filename, f.f_lineno)
31
32class ProcessCompatConfigTest(unittest.TestCase):
33
34    def setUp(self):
35        self.merger = process_compat_config.ConfigMerger(detect_conflicts = True)
36        self.stderr = StringIO()
37        self.merger.write_errors_to = self.stderr
38        self.xml = io.BytesIO()
39
40    def assert_same_xml(self, got, expected):
41        got = xml.dom.minidom.parseString(got).toprettyxml()
42        expected = xml.dom.minidom.parseString(expected).toprettyxml()
43        diffs = [diff for diff in difflib.ndiff(got.split('\n'), expected.split('\n')) if not diff.startswith(" ")]
44        self.assertEqual("", "\n".join(diffs), msg="Got unexpected diffs in XML")
45
46    def test_no_config_to_merge(self):
47        self.merger.write(self.xml)
48        self.assert_same_xml(self.xml.getvalue(), "<config />")
49
50    def test_merge_one_file(self):
51        self.merger.merge(io.BytesIO(b'<config><compat-change id="1234" name="TEST_CHANGE" /></config>'), here())
52        self.merger.write(self.xml)
53        self.assert_same_xml(self.xml.getvalue(), '<config><compat-change id="1234" name="TEST_CHANGE" /></config>')
54
55    def test_merge_two_files(self):
56        self.merger.merge(io.BytesIO(b'<config><compat-change id="1234" name="TEST_CHANGE" /></config>'), here())
57        self.merger.merge(io.BytesIO(b'<config><compat-change id="1235" name="TEST_CHANGE2" /></config>'), here())
58        self.merger.write(self.xml)
59        self.assert_same_xml(self.xml.getvalue(),
60            '<config><compat-change id="1234" name="TEST_CHANGE" /><compat-change id="1235" name="TEST_CHANGE2" /></config>')
61
62    def test_merge_two_files_metadata(self):
63        self.merger.merge(io.BytesIO(
64            b'<config><compat-change id="1234" name="TEST_CHANGE"><meta-data definedIn="some.Class" sourcePosition="some.java:1" />'
65            b'</compat-change></config>'), here())
66        self.merger.merge(io.BytesIO(
67            b'<config><compat-change id="1235" name="TEST_CHANGE2"><meta-data definedIn="other.Class" sourcePosition="other.java:2" />'
68            b'</compat-change></config>'), here())
69        self.merger.write(self.xml)
70        self.assert_same_xml(self.xml.getvalue(), b'<config>'
71            b'<compat-change id="1234" name="TEST_CHANGE"><meta-data definedIn="some.Class" sourcePosition="some.java:1" /></compat-change>'
72            b'<compat-change id="1235" name="TEST_CHANGE2"><meta-data definedIn="other.Class" sourcePosition="other.java:2" /></compat-change>'
73            b'</config>')
74
75    def test_write_device_config_metadata_stripped(self):
76        self.merger.merge(io.BytesIO(
77            b'<config><compat-change id="1234" name="TEST_CHANGE"><meta-data definedIn="some.Class" sourcePosition="file.java:1"/>'
78            b'</compat-change></config>'), here())
79        self.merger.write_device_config(self.xml)
80        self.assert_same_xml(self.xml.getvalue(), b'<config>'
81            b'<compat-change id="1234" name="TEST_CHANGE" />'
82            b'</config>')
83
84    def test_merge_two_files_duplicate_id(self):
85        self.merger.merge(io.BytesIO(b'<config><compat-change id="1234" name="TEST_CHANGE" /></config>'), here())
86        self.merger.merge(io.BytesIO(b'<config><compat-change id="1234" name="TEST_CHANGE2" /></config>'), here())
87        self.assertIn(r'ERROR: Duplicate definitions for compat change with ID 1234', self.stderr.getvalue())
88        with self.assertRaisesRegexp(Exception, ' 1 .*error'):
89            self.merger.write(self.xml)
90
91    def test_merge_two_files_duplicate_name(self):
92        self.merger.merge(io.BytesIO(b'<config><compat-change id="1234" name="TEST_CHANGE" /></config>'), here())
93        self.merger.merge(io.BytesIO(b'<config><compat-change id="1235" name="TEST_CHANGE" /></config>'), here())
94        self.assertIn(r'ERROR: Duplicate definitions for compat change with name TEST_CHANGE', self.stderr.getvalue())
95        with self.assertRaisesRegexp(Exception, ' 1 .*error'):
96            self.merger.write(self.xml)
97
98    def test_merge_two_files_duplicate_id_allow_duplicates(self):
99        self.merger = process_compat_config.ConfigMerger(detect_conflicts = False)
100        self.merger.merge(io.BytesIO(b'<config><compat-change id="1234" name="TEST_CHANGE" /></config>'), here())
101        self.merger.merge(io.BytesIO(b'<config><compat-change id="1234" name="TEST_CHANGE2" /></config>'), here())
102        self.merger.write(self.xml)
103
104    def test_merge_two_files_duplicate_name_allow_duplicates(self):
105        self.merger = process_compat_config.ConfigMerger(detect_conflicts = False)
106        self.merger.merge(io.BytesIO(b'<config><compat-change id="1234" name="TEST_CHANGE" /></config>'), here())
107        self.merger.merge(io.BytesIO(b'<config><compat-change id="1235" name="TEST_CHANGE" /></config>'), here())
108        self.merger.write(self.xml)
109
110if __name__ == '__main__':
111  unittest.main(verbosity=2)