• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/env python3
2#
3# Copyright 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"""Unittests for native_module_info."""
18
19import logging
20import os
21import unittest
22from unittest import mock
23
24from aidegen import constant
25from aidegen.lib import common_util
26from aidegen.lib import module_info
27from aidegen.lib import native_module_info
28
29import atest
30
31_PATH_TO_MULT_MODULES_WITH_MULTI_ARCH = 'shared/path/to/be/used2'
32_TESTABLE_MODULES_WITH_SHARED_PATH = [
33    'multiarch', 'multiarch1', 'multiarch2', 'multiarch3', 'multiarch3_32'
34]
35_REBUILD_TARGET1 = 'android.frameworks.bufferhub@1.0'
36_NATIVE_INCLUDES1 = [
37    'frameworks/native/include',
38    'frameworks/native/libs/ui',
39    'out/soong/.intermediates/' + _REBUILD_TARGET1 + '_genc++_headers/gen'
40]
41_CC_NAME_TO_MODULE_INFO = {
42    'multiarch': {
43        'path': [
44            'shared/path/to/be/used2'
45        ],
46        'srcs': [
47            'shared/path/to/be/used2/multiarch.cpp',
48            'out/soong/.intermediates/shared/path/to/be/used2/gen/Iarch.cpp'
49        ],
50        'local_common_flags': {
51            constant.KEY_HEADER: _NATIVE_INCLUDES1
52        },
53        'module_name': 'multiarch'
54    },
55    'multiarch1': {
56        'path': [
57            'shared/path/to/be/used2/arch1'
58        ],
59        'module_name': 'multiarch1'
60    },
61    'multiarch2': {
62        'path': [
63            'shared/path/to/be/used2/arch2'
64        ],
65        'module_name': 'multiarch2'
66    },
67    'multiarch3': {
68        'path': [
69            'shared/path/to/be/used2/arch3'
70        ],
71        'module_name': 'multiarch3'
72    },
73    'multiarch3_32': {
74        'path': [
75            'shared/path/to/be/used2/arch3_32'
76        ],
77        'module_name': 'multiarch3_32'
78    },
79    _REBUILD_TARGET1: {
80        'path': [
81            '/path/to/rebuild'
82        ],
83        'module_name': _REBUILD_TARGET1
84    },
85    'multiarch-eng': {
86        'path': [
87            'shared/path/to/be/used2-eng'
88        ],
89        'srcs': [
90            'shared/path/to/be/used2/multiarch-eng.cpp',
91            'out/soong/.intermediates/shared/path/to/be/used2/gen/Iarch-eng.cpp'
92        ],
93        'module_name': 'multiarch-eng'
94    }
95}
96_CC_MODULE_INFO = {
97    'clang': '${ANDROID_ROOT}/prebuilts/clang/host/linux-x86/bin/clang',
98    'clang++': '${ANDROID_ROOT}/prebuilts/clang/host/linux-x86/bin/clang++',
99    'modules': _CC_NAME_TO_MODULE_INFO
100}
101
102
103# pylint: disable=protected-access
104class NativeModuleInfoUnittests(unittest.TestCase):
105    """Unit tests for module_info.py"""
106
107    @mock.patch.object(
108        native_module_info.NativeModuleInfo, '_load_module_info_file')
109    @mock.patch.object(common_util, 'get_related_paths')
110    def test_get_module_names_in_targets_paths(self, mock_relpath, mock_load):
111        """Test get_module_names_in_targets_paths handling."""
112        mock_load.return_value = None, _CC_NAME_TO_MODULE_INFO
113        mod_info = native_module_info.NativeModuleInfo()
114        mock_relpath.return_value = (_PATH_TO_MULT_MODULES_WITH_MULTI_ARCH, '')
115        result = mod_info.get_module_names_in_targets_paths(['multiarch'])
116        self.assertEqual(_TESTABLE_MODULES_WITH_SHARED_PATH, result)
117
118    @mock.patch.object(
119        native_module_info.NativeModuleInfo, '_load_module_info_file')
120    def test_get_module_includes_empty(self, mock_load):
121        """Test get_module_includes without include paths."""
122        mock_load.return_value = None, _CC_NAME_TO_MODULE_INFO
123        mod_info = native_module_info.NativeModuleInfo()
124        result = mod_info.get_module_includes('multiarch1')
125        self.assertEqual(set(), result)
126
127    @mock.patch.object(
128        native_module_info.NativeModuleInfo, '_load_module_info_file')
129    def test_get_module_includes_not_empty(self, mock_load):
130        """Test get_module_includes with include paths."""
131        mock_load.return_value = None, _CC_NAME_TO_MODULE_INFO
132        mod_info = native_module_info.NativeModuleInfo()
133        mod_info.name_to_module_info = _CC_NAME_TO_MODULE_INFO
134        result = mod_info.get_module_includes('multiarch')
135        self.assertEqual(set(_NATIVE_INCLUDES1), result)
136
137    @mock.patch.object(logging, 'warning')
138    @mock.patch.object(
139        native_module_info.NativeModuleInfo, '_load_module_info_file')
140    def test_is_module_need_build_without_mod_info(self, mock_load, mock_warn):
141        """Test get_module_includes without module info."""
142        mock_load.return_value = None, _CC_NAME_TO_MODULE_INFO
143        mod_info = native_module_info.NativeModuleInfo()
144        self.assertFalse(mod_info.is_module_need_build('test_multiarch'))
145        self.assertTrue(mock_warn.called)
146
147    @mock.patch.object(logging, 'warning')
148    @mock.patch.object(
149        native_module_info.NativeModuleInfo, '_load_module_info_file')
150    def test_is_module_need_build_with_mod_info(self, mock_load, mock_warn):
151        """Test get_module_includes with module info."""
152        mock_load.return_value = None, _CC_NAME_TO_MODULE_INFO
153        mod_info = native_module_info.NativeModuleInfo()
154        self.assertFalse(mod_info.is_module_need_build('multiarch1'))
155        self.assertFalse(mock_warn.called)
156
157    @mock.patch.object(native_module_info.NativeModuleInfo,
158                       '_is_include_need_build')
159    @mock.patch.object(native_module_info.NativeModuleInfo,
160                       '_is_source_need_build')
161    @mock.patch.object(logging, 'warning')
162    @mock.patch.object(
163        native_module_info.NativeModuleInfo, '_load_module_info_file')
164    def test_is_module_need_build_with_src_needs(
165            self, mock_load, mock_warn, mock_src_need, mock_inc_need):
166        """Test get_module_includes with needed build source modules."""
167        mock_load.return_value = None, _CC_NAME_TO_MODULE_INFO
168        mod_info = native_module_info.NativeModuleInfo()
169        mock_src_need.return_value = True
170        mock_inc_need.return_value = False
171        self.assertTrue(mod_info.is_module_need_build('multiarch'))
172        self.assertFalse(mock_warn.called)
173
174    @mock.patch.object(native_module_info.NativeModuleInfo,
175                       '_is_include_need_build')
176    @mock.patch.object(native_module_info.NativeModuleInfo,
177                       '_is_source_need_build')
178    @mock.patch.object(logging, 'warning')
179    @mock.patch.object(
180        native_module_info.NativeModuleInfo, '_load_module_info_file')
181    def test_is_module_need_build_with_inc_needs(
182            self, mock_load, mock_warn, mock_src_need, mock_inc_need):
183        """Test get_module_includes with needed build include modules."""
184        mock_load.return_value = None, _CC_NAME_TO_MODULE_INFO
185        mod_info = native_module_info.NativeModuleInfo()
186        mock_src_need.return_value = False
187        mock_inc_need.return_value = True
188        self.assertTrue(mod_info.is_module_need_build('multiarch'))
189        self.assertFalse(mock_warn.called)
190
191    @mock.patch.object(native_module_info.NativeModuleInfo,
192                       '_is_include_need_build')
193    @mock.patch.object(native_module_info.NativeModuleInfo,
194                       '_is_source_need_build')
195    @mock.patch.object(logging, 'warning')
196    @mock.patch.object(
197        native_module_info.NativeModuleInfo, '_load_module_info_file')
198    def test_is_module_need_build_without_needs(
199            self, mock_load, mock_warn, mock_src_need, mock_inc_need):
200        """Test get_module_includes without needs."""
201        mock_load.return_value = None, _CC_NAME_TO_MODULE_INFO
202        mod_info = native_module_info.NativeModuleInfo()
203        mock_src_need.return_value = False
204        mock_inc_need.return_value = False
205        self.assertFalse(mod_info.is_module_need_build('multiarch1'))
206        self.assertFalse(mock_warn.called)
207
208    @mock.patch.object(os.path, 'isfile')
209    @mock.patch.object(
210        native_module_info.NativeModuleInfo, '_load_module_info_file')
211    def test_is_source_need_build_return_true(self, mock_load, mock_isfile):
212        """Test _is_source_need_build with source paths or not existing."""
213        mock_load.return_value = None, _CC_NAME_TO_MODULE_INFO
214        mod_info = native_module_info.NativeModuleInfo()
215        mock_isfile.return_value = False
216        self.assertTrue(mod_info._is_source_need_build(
217            _CC_NAME_TO_MODULE_INFO['multiarch']))
218
219    @mock.patch.object(os.path, 'isfile')
220    @mock.patch.object(
221        native_module_info.NativeModuleInfo, '_load_module_info_file')
222    def test_is_source_need_build_return_false(self, mock_load, mock_isfile):
223        """Test _is_source_need_build without source paths or paths exist."""
224        mock_load.return_value = None, _CC_NAME_TO_MODULE_INFO
225        mod_info = native_module_info.NativeModuleInfo()
226        self.assertFalse(mod_info._is_source_need_build(
227            _CC_NAME_TO_MODULE_INFO['multiarch1']))
228        mock_isfile.return_value = True
229        self.assertFalse(mod_info._is_source_need_build(
230            _CC_NAME_TO_MODULE_INFO['multiarch']))
231
232    @mock.patch.object(os.path, 'isdir')
233    @mock.patch.object(
234        native_module_info.NativeModuleInfo, '_load_module_info_file')
235    def test_is_include_need_build_return_true(self, mock_load, mock_isdir):
236        """Test _is_include_need_build with include paths and not existing."""
237        mock_load.return_value = None, _CC_NAME_TO_MODULE_INFO
238        mock_isdir.return_value = False
239        mod_info = native_module_info.NativeModuleInfo()
240        self.assertTrue(mod_info._is_include_need_build(
241            _CC_NAME_TO_MODULE_INFO['multiarch']))
242
243    @mock.patch.object(os.path, 'isdir')
244    @mock.patch.object(
245        native_module_info.NativeModuleInfo, '_load_module_info_file')
246    def test_is_include_need_build_return_false(self, mock_load, mock_isdir):
247        """Test _is_include_need_build without include paths or paths exist."""
248        mock_load.return_value = None, _CC_NAME_TO_MODULE_INFO
249        mod_info = native_module_info.NativeModuleInfo()
250        self.assertFalse(mod_info._is_include_need_build(
251            _CC_NAME_TO_MODULE_INFO['multiarch1']))
252        mock_isdir.return_value = True
253        self.assertFalse(mod_info._is_include_need_build(
254            _CC_NAME_TO_MODULE_INFO['multiarch']))
255        mock_isdir.return_value = True
256        self.assertFalse(mod_info._is_include_need_build(
257            _CC_NAME_TO_MODULE_INFO['multiarch']))
258
259    def test_not_implemented_methods(self):
260        """Test not implemented methods."""
261        mod_info = native_module_info.NativeModuleInfo()
262        target = 'test'
263        with self.assertRaises(NotImplementedError):
264            mod_info.get_testable_modules()
265        with self.assertRaises(NotImplementedError):
266            mod_info.is_testable_module(mock.Mock())
267        with self.assertRaises(NotImplementedError):
268            mod_info.has_test_config(mock.Mock())
269        with self.assertRaises(NotImplementedError):
270            mod_info.get_robolectric_test_name(target)
271        with self.assertRaises(NotImplementedError):
272            mod_info.is_robolectric_test(target)
273        with self.assertRaises(NotImplementedError):
274            mod_info.is_auto_gen_test_config(target)
275        with self.assertRaises(NotImplementedError):
276            mod_info.is_robolectric_module(mock.Mock())
277        with self.assertRaises(NotImplementedError):
278            mod_info.is_native_test(target)
279
280    @mock.patch.object(
281        native_module_info.NativeModuleInfo, '_load_module_info_file')
282    def test_not_implement_methods_check(self, mock_load):
283        """Test for all not implemented methods which should raise error."""
284        mock_load.return_value = None, _CC_NAME_TO_MODULE_INFO
285        mod_info = native_module_info.NativeModuleInfo()
286        with self.assertRaises(NotImplementedError):
287            suite_name = 'test'
288            test_data = {'a': 'test'}
289            mod_info.is_suite_in_compatibility_suites(suite_name, test_data)
290
291        with self.assertRaises(NotImplementedError):
292            mod_info.get_testable_modules()
293
294        with self.assertRaises(NotImplementedError):
295            test_data = {'a': 'test'}
296            mod_info.is_testable_module(test_data)
297
298        with self.assertRaises(NotImplementedError):
299            test_data = {'a': 'test'}
300            mod_info.has_test_config(test_data)
301
302        with self.assertRaises(NotImplementedError):
303            test_mod = 'mod_a'
304            mod_info.get_robolectric_test_name(test_mod)
305
306        with self.assertRaises(NotImplementedError):
307            test_mod = 'mod_a'
308            mod_info.is_robolectric_test(test_mod)
309
310        with self.assertRaises(NotImplementedError):
311            test_mod = 'a'
312            mod_info.is_auto_gen_test_config(test_mod)
313
314        with self.assertRaises(NotImplementedError):
315            test_data = {'a': 'test'}
316            mod_info.is_robolectric_module(test_data)
317
318        with self.assertRaises(NotImplementedError):
319            test_mod = 'a'
320            mod_info.is_native_test(test_mod)
321
322    @mock.patch.object(atest.module_info.ModuleInfo, '_load_module_info_file')
323    @mock.patch.object(os.path, 'isfile')
324    @mock.patch.object(common_util, 'get_json_dict')
325    @mock.patch.object(module_info.AidegenModuleInfo,
326                       '_discover_mod_file_and_target')
327    @mock.patch.object(common_util, 'get_blueprint_json_path')
328    def test_load_module_info_file(self, mock_get_json, mock_load, mock_dict,
329                                   mock_isfile, mock_base_load):
330        """Test _load_module_info_file."""
331        force_build = True
332        mod_file = '/test/path'
333        mock_get_json.return_value = mod_file
334        native_module_info.NativeModuleInfo(force_build)
335        self.assertTrue(mock_get_json.called_with(
336            constant.BLUEPRINT_CC_JSONFILE_NAME))
337        mock_load.return_value = mod_file, mod_file
338        self.assertTrue(mock_load.called_with(True))
339        mock_dict.return_value = _CC_MODULE_INFO
340        self.assertTrue(mock_dict.called_with(mod_file))
341        self.assertFalse(mock_base_load.called)
342        mock_base_load.reset_mock()
343        mock_get_json.reset_mock()
344        mock_load.reset_mock()
345        mock_dict.reset_mock()
346
347        native_module_info.NativeModuleInfo(force_build, mod_file)
348        self.assertFalse(mock_get_json.called)
349        mock_load.return_value = None, mod_file
350        self.assertTrue(mock_load.called_with(True))
351        self.assertTrue(mock_dict.called_with(mod_file))
352        self.assertFalse(mock_base_load.called)
353        mock_base_load.reset_mock()
354        mock_get_json.reset_mock()
355        mock_load.reset_mock()
356        mock_dict.reset_mock()
357
358        force_build = False
359        mock_get_json.return_value = mod_file
360        native_module_info.NativeModuleInfo(force_build, mod_file)
361        self.assertFalse(mock_get_json.called)
362        mock_isfile.return_value = True
363        self.assertFalse(mock_load.called)
364        mock_dict.return_value = _CC_MODULE_INFO
365        self.assertTrue(mock_dict.called_with(mod_file))
366        self.assertFalse(mock_base_load.called)
367        mock_base_load.reset_mock()
368        mock_get_json.reset_mock()
369        mock_load.reset_mock()
370        mock_dict.reset_mock()
371
372
373if __name__ == '__main__':
374    unittest.main()
375