1#!/usr/bin/env python
2#
3# Copyright (C) 2020 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
17import io
18import os
19import unittest
20
21from lxml import etree
22from pyfakefs import fake_filesystem_unittest
23
24import generate_module
25
26
27class WriteTestModuleTest(unittest.TestCase):
28
29    def test_xml_is_valid(self):
30        package_name = 'package_name'
31        out = io.StringIO()
32
33        generate_module.write_test_module(package_name, out)
34
35        test_module_generated = out.getvalue()
36        self.assertTrue(self._contains_license(test_module_generated))
37        self.assertTrue(self._is_validate_xml(test_module_generated))
38
39    def _contains_license(self, generated_str: bytes) -> bool:
40        return 'Copyright' in generated_str and \
41                'Android Open Source Project' in generated_str
42
43    def _is_validate_xml(self, xml_str: bytes) -> bool:
44        xmlschema_doc = etree.parse(
45            io.BytesIO('''<?xml version="1.0" encoding="UTF-8" ?>
46        <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
47        <xs:element name="configuration">
48        <xs:complexType>
49            <xs:sequence>
50            <xs:element name="option" minOccurs="0" maxOccurs="unbounded"/>
51            <xs:element name="target_preparer" minOccurs="0" maxOccurs="unbounded"/>
52            <xs:element name="test" minOccurs="0" maxOccurs="unbounded"/>
53            </xs:sequence>
54            <xs:attribute name="description"/>
55        </xs:complexType>
56        </xs:element>
57        </xs:schema>
58        '''.encode('utf8')))
59        xmlschema = etree.XMLSchema(xmlschema_doc)
60
61        xml_doc = etree.parse(io.BytesIO(xml_str.encode('utf8')))
62        result = xmlschema.validate(xml_doc)
63
64        return result
65
66
67class WriteBuildModuleTest(unittest.TestCase):
68
69    def test_build_file_is_valid(self):
70        package_name = 'package_name'
71        out = io.StringIO()
72
73        generate_module.write_build_module(package_name, out)
74
75        build_module_generated = out.getvalue()
76        self.assertTrue(self._contains_license(build_module_generated))
77        self.assertTrue(self._are_parentheses_balanced(build_module_generated))
78        self.assertIn('csuite_config', build_module_generated)
79        self.assertIn(package_name, build_module_generated)
80
81    def _contains_license(self, generated_str: bytes) -> bool:
82        return 'Copyright' in generated_str and \
83                'Android Open Source Project' in generated_str
84
85    def _are_parentheses_balanced(self, generated_str: bytes) -> bool:
86        parenthese_count = 0
87
88        for elem in generated_str:
89            if elem == '{':
90                parenthese_count += 1
91            elif elem == '}':
92                parenthese_count -= 1
93
94            if parenthese_count < 0:
95                return False
96
97        return parenthese_count == 0
98
99
100class ParsePackageListTest(unittest.TestCase):
101
102    def test_accepts_empty_lines(self):
103        input = io.StringIO('\n\n\npackage_name\n\n')
104
105        package_list = generate_module.parse_package_list(input)
106
107        self.assertEqual(len(package_list), 1)
108        self.assertIn('package_name', package_list)
109        self.assertTrue(all(package_list))
110
111    def test_strips_trailing_whitespace(self):
112        input = io.StringIO('  package_name  ')
113
114        package_list = generate_module.parse_package_list(input)
115
116        self.assertEqual(len(package_list), 1)
117        self.assertIn('package_name', package_list)
118        self.assertTrue(all(package_list))
119
120    def test_duplicate_package_name(self):
121        input = io.StringIO('\n\npackage_name\n\npackage_name\n')
122
123        package_list = generate_module.parse_package_list(input)
124
125        self.assertEqual(len(package_list), 1)
126        self.assertIn('package_name', package_list)
127        self.assertTrue(all(package_list))
128
129
130class ParseArgsTest(fake_filesystem_unittest.TestCase):
131
132    def setUp(self):
133        super(ParseArgsTest, self).setUp()
134        self.setUpPyfakefs()
135
136    def test_configuration_file_not_exist(self):
137        package_list_file_path = '/test/package_list.txt'
138        root_dir = '/test/modules'
139        os.makedirs(root_dir)
140
141        with self.assertRaises(SystemExit):
142            generate_module.parse_args(
143                ['--package_list', package_list_file_path,
144                 '--root_dir', root_dir])
145
146    def test_module_dir_not_exist(self):
147        package_list_file_path = '/test/package_list.txt'
148        package_name1 = 'package_name_1'
149        package_name2 = 'package_name_2'
150        self.fs.create_file(package_list_file_path,
151                            contents=(package_name1+'\n'+package_name2))
152        root_dir = '/test/modules'
153
154        with self.assertRaises(SystemExit):
155            generate_module.parse_args(
156                ['--package_list', package_list_file_path,
157                 '--root_dir', root_dir])
158
159
160class GenerateAllModulesFromConfigTest(fake_filesystem_unittest.TestCase):
161
162    def setUp(self):
163        super(GenerateAllModulesFromConfigTest, self).setUp()
164        self.setUpPyfakefs()
165
166    def test_creates_package_files(self):
167        package_list_file_path = '/test/package_list.txt'
168        package_name1 = 'package_name_1'
169        package_name2 = 'package_name_2'
170        self.fs.create_file(package_list_file_path,
171                            contents=(package_name1+'\n'+package_name2))
172        root_dir = '/test/modules'
173        self.fs.create_dir(root_dir)
174
175        generate_module.generate_all_modules_from_config(
176            package_list_file_path, root_dir)
177
178        self.assertTrue(os.path.exists(
179            os.path.join(root_dir, package_name1, 'Android.bp')))
180        self.assertTrue(os.path.exists(
181            os.path.join(root_dir, package_name1, 'AndroidTest.xml')))
182        self.assertTrue(os.path.exists(
183            os.path.join(root_dir, package_name2, 'Android.bp')))
184        self.assertTrue(os.path.exists(
185            os.path.join(root_dir, package_name2, 'AndroidTest.xml')))
186
187    def test_removes_all_existing_package_files(self):
188        root_dir = '/test/'
189        package_dir = '/test/existing_package/'
190        existing_package_file1 = 'test/existing_package/AndroidTest.xml'
191        existing_package_file2 = 'test/existing_package/Android.bp'
192        self.fs.create_file(existing_package_file1, contents='auto-generated')
193        self.fs.create_file(existing_package_file2, contents='auto-generated')
194
195        generate_module.remove_existing_package_files(root_dir)
196
197        self.assertFalse(os.path.exists(existing_package_file1))
198        self.assertFalse(os.path.exists(existing_package_file2))
199        self.assertFalse(os.path.exists(package_dir))
200
201
202if __name__ == '__main__':
203    unittest.main()
204