1# Lint as: python3
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"""Tests for the generate_module package."""
17
18import io
19import os
20from xml.etree import cElementTree as ET
21import csuite_test
22import generate_module
23from pyfakefs import fake_filesystem_unittest
24
25_AUTO_GENERATE_NOTE = 'THIS FILE WAS AUTO-GENERATED. DO NOT EDIT MANUALLY!'
26
27
28class WriteTestModuleTest(csuite_test.TestCase):
29
30  def test_output_contains_license(self):
31    out = io.StringIO()
32
33    generate_module.write_module(generate_module.DEFAULT_BUILD_MODULE_TEMPLATE,
34                                 'a.package.name', out)
35
36    self.assertIn('Copyright', out.getvalue())
37    self.assertIn('Android Open Source Project', out.getvalue())
38
39  def test_output_is_valid_xml(self):
40    out = io.StringIO()
41
42    generate_module.write_module(generate_module.DEFAULT_TEST_MODULE_TEMPLATE,
43                                 'a.package.name', out)
44
45    self.assert_valid_xml(out.getvalue())
46
47  def test_output_contains_package_name(self):
48    package_name = 'a.package.name'
49    out = io.StringIO()
50
51    generate_module.write_module(generate_module.DEFAULT_TEST_MODULE_TEMPLATE,
52                                 'a.package.name', out)
53
54    self.assertIn(package_name, out.getvalue())
55
56  def assert_valid_xml(self, xml_str: bytes) -> None:
57    try:
58      ET.parse(io.BytesIO(xml_str.encode('utf8')))
59    except ET.ParseError as e:
60      self.fail('Input \'%s\' is not a valid XML document: %s' % (xml_str, e))
61
62
63class WriteBuildModuleTest(csuite_test.TestCase):
64
65  def test_output_contains_license(self):
66    out = io.StringIO()
67
68    generate_module.write_module(generate_module.DEFAULT_BUILD_MODULE_TEMPLATE,
69                                 'a.package.name', out)
70
71    self.assertIn('Copyright', out.getvalue())
72    self.assertIn('Android Open Source Project', out.getvalue())
73
74  def test_output_is_valid_build_file(self):
75    package_name = 'a.package.name'
76    out = io.StringIO()
77
78    generate_module.write_module(generate_module.DEFAULT_BUILD_MODULE_TEMPLATE,
79                                 'a.package.name', out)
80
81    out_str = out.getvalue()
82    self.assert_braces_balanced(out_str)
83    self.assertIn('csuite_config', out_str)
84    self.assertIn(package_name, out_str)
85
86  def assert_braces_balanced(self, generated_str: bytes) -> None:
87    """Checks whether all braces in the provided string are balanced."""
88    count = 0
89
90    for c in generated_str:
91      if c == '{':
92        count += 1
93      elif c == '}':
94        count -= 1
95
96      if count < 0:
97        break
98
99    self.assertEqual(count, 0,
100                     'Braces in \'%s\' are not balanced' % generated_str)
101
102
103class ParsePackageListTest(csuite_test.TestCase):
104
105  def test_accepts_empty_lines(self):
106    lines = io.StringIO('\n\n\npackage_name\n\n')
107
108    package_list = generate_module.parse_package_list(lines)
109
110    self.assertListEqual(['package_name'], list(package_list))
111
112  def test_strips_trailing_whitespace(self):
113    lines = io.StringIO('  package_name  ')
114
115    package_list = generate_module.parse_package_list(lines)
116
117    self.assertListEqual(['package_name'], list(package_list))
118
119  def test_duplicate_package_name(self):
120    lines = io.StringIO('\n\npackage_name\n\npackage_name\n')
121
122    package_list = generate_module.parse_package_list(lines)
123
124    self.assertListEqual(['package_name'], list(package_list))
125
126  def test_ignore_comment_lines(self):
127    lines = io.StringIO('\n# Comments.\npackage_name\n')
128
129    package_list = generate_module.parse_package_list(lines)
130
131    self.assertListEqual(['package_name'], list(package_list))
132
133
134class ParseArgsTest(fake_filesystem_unittest.TestCase):
135
136  def setUp(self):
137    super(ParseArgsTest, self).setUp()
138    self.setUpPyfakefs()
139
140  def test_configuration_file_not_exist(self):
141    package_list_file_path = '/test/package_list.txt'
142    root_dir = '/test/modules'
143    os.makedirs(root_dir)
144
145    with self.assertRaises(SystemExit):
146      generate_module.parse_args(
147          ['--package-list', package_list_file_path, '--root-dir', root_dir],
148          out=io.StringIO(),
149          err=io.StringIO())
150
151  def test_module_dir_not_exist(self):
152    package_list_file_path = '/test/package_list.txt'
153    package_name1 = 'package_name_1'
154    package_name2 = 'package_name_2'
155    self.fs.create_file(
156        package_list_file_path, contents=(package_name1 + '\n' + package_name2))
157    root_dir = '/test/modules'
158
159    with self.assertRaises(SystemExit):
160      generate_module.parse_args(
161          ['--package-list', package_list_file_path, '--root-dir', root_dir],
162          out=io.StringIO(),
163          err=io.StringIO())
164
165  def test_test_module_template_file_not_exist(self):
166    package_list_file_path = '/test/package_list.txt'
167    package_name1 = 'package_name_1'
168    package_name2 = 'package_name_2'
169    self.fs.create_file(
170        package_list_file_path, contents=(package_name1 + '\n' + package_name2))
171    root_dir = '/test/modules'
172    os.makedirs(root_dir)
173    template_file_path = '/test/template.txt'
174
175    with self.assertRaises(SystemExit):
176      generate_module.parse_args([
177          '--package-list', package_list_file_path, '--root-dir', root_dir,
178          '--test', template_file_path
179      ],
180                                 out=io.StringIO(),
181                                 err=io.StringIO())
182
183  def test_build_module_template_file_not_exist(self):
184    package_list_file_path = '/test/package_list.txt'
185    package_name1 = 'package_name_1'
186    package_name2 = 'package_name_2'
187    self.fs.create_file(
188        package_list_file_path, contents=(package_name1 + '\n' + package_name2))
189    root_dir = '/test/modules'
190    os.makedirs(root_dir)
191    template_file_path = '/test/template.txt'
192
193    with self.assertRaises(SystemExit):
194      generate_module.parse_args([
195          '--package-list', package_list_file_path, '--root-dir', root_dir,
196          '--template', template_file_path
197      ],
198                                 out=io.StringIO(),
199                                 err=io.StringIO())
200
201
202class GenerateAllModulesFromConfigTest(fake_filesystem_unittest.TestCase):
203
204  def setUp(self):
205    super(GenerateAllModulesFromConfigTest, self).setUp()
206    self.setUpPyfakefs()
207
208  def test_creates_package_files(self):
209    package_list_file_path = '/test/package_list.txt'
210    package_name1 = 'package_name_1'
211    package_name2 = 'package_name_2'
212    self.fs.create_file(
213        package_list_file_path, contents=(package_name1 + '\n' + package_name2))
214    root_dir = '/test/modules'
215    self.fs.create_dir(root_dir)
216
217    generate_module.generate_all_modules_from_config(package_list_file_path,
218                                                     root_dir)
219
220    self.assertTrue(
221        os.path.exists(os.path.join(root_dir, package_name1, 'Android.bp')))
222    self.assertTrue(
223        os.path.exists(
224            os.path.join(root_dir, package_name1, 'AndroidTest.xml')))
225    self.assertTrue(
226        os.path.exists(os.path.join(root_dir, package_name2, 'Android.bp')))
227    self.assertTrue(
228        os.path.exists(
229            os.path.join(root_dir, package_name2, 'AndroidTest.xml')))
230
231  def test_removes_all_existing_package_files(self):
232    root_dir = '/test/'
233    package_dir = '/test/existing_package/'
234    self.fs.create_file(
235        'test/existing_package/AndroidTest.xml', contents=_AUTO_GENERATE_NOTE)
236    self.fs.create_file(
237        'test/existing_package/Android.bp', contents=_AUTO_GENERATE_NOTE)
238
239    generate_module.remove_existing_package_files(root_dir)
240
241    self.assertFalse(os.path.exists(package_dir))
242
243
244if __name__ == '__main__':
245  csuite_test.main()
246