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