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 = '[email protected]' 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 result = mod_info.get_module_includes('multiarch') 134 self.assertEqual(set(_NATIVE_INCLUDES1), result) 135 136 @mock.patch.object(logging, 'warning') 137 @mock.patch.object( 138 native_module_info.NativeModuleInfo, '_load_module_info_file') 139 def test_is_module_need_build_without_mod_info(self, mock_load, mock_warn): 140 """Test get_module_includes without module info.""" 141 mock_load.return_value = None, _CC_NAME_TO_MODULE_INFO 142 mod_info = native_module_info.NativeModuleInfo() 143 self.assertFalse(mod_info.is_module_need_build('test_multiarch')) 144 self.assertTrue(mock_warn.called) 145 146 @mock.patch.object(logging, 'warning') 147 @mock.patch.object( 148 native_module_info.NativeModuleInfo, '_load_module_info_file') 149 def test_is_module_need_build_with_mod_info(self, mock_load, mock_warn): 150 """Test get_module_includes with module info.""" 151 mock_load.return_value = None, _CC_NAME_TO_MODULE_INFO 152 mod_info = native_module_info.NativeModuleInfo() 153 self.assertFalse(mod_info.is_module_need_build('multiarch1')) 154 self.assertFalse(mock_warn.called) 155 156 @mock.patch.object(native_module_info.NativeModuleInfo, 157 '_is_include_need_build') 158 @mock.patch.object(native_module_info.NativeModuleInfo, 159 '_is_source_need_build') 160 @mock.patch.object(logging, 'warning') 161 @mock.patch.object( 162 native_module_info.NativeModuleInfo, '_load_module_info_file') 163 def test_is_module_need_build_with_src_needs( 164 self, mock_load, mock_warn, mock_src_need, mock_inc_need): 165 """Test get_module_includes with needed build source modules.""" 166 mock_load.return_value = None, _CC_NAME_TO_MODULE_INFO 167 mod_info = native_module_info.NativeModuleInfo() 168 mock_src_need.return_value = True 169 mock_inc_need.return_value = False 170 self.assertTrue(mod_info.is_module_need_build('multiarch')) 171 self.assertFalse(mock_warn.called) 172 173 @mock.patch.object(native_module_info.NativeModuleInfo, 174 '_is_include_need_build') 175 @mock.patch.object(native_module_info.NativeModuleInfo, 176 '_is_source_need_build') 177 @mock.patch.object(logging, 'warning') 178 @mock.patch.object( 179 native_module_info.NativeModuleInfo, '_load_module_info_file') 180 def test_is_module_need_build_with_inc_needs( 181 self, mock_load, mock_warn, mock_src_need, mock_inc_need): 182 """Test get_module_includes with needed build include modules.""" 183 mock_load.return_value = None, _CC_NAME_TO_MODULE_INFO 184 mod_info = native_module_info.NativeModuleInfo() 185 mock_src_need.return_value = False 186 mock_inc_need.return_value = True 187 self.assertTrue(mod_info.is_module_need_build('multiarch')) 188 self.assertFalse(mock_warn.called) 189 190 @mock.patch.object(native_module_info.NativeModuleInfo, 191 '_is_include_need_build') 192 @mock.patch.object(native_module_info.NativeModuleInfo, 193 '_is_source_need_build') 194 @mock.patch.object(logging, 'warning') 195 @mock.patch.object( 196 native_module_info.NativeModuleInfo, '_load_module_info_file') 197 def test_is_module_need_build_without_needs( 198 self, mock_load, mock_warn, mock_src_need, mock_inc_need): 199 """Test get_module_includes without needs.""" 200 mock_load.return_value = None, _CC_NAME_TO_MODULE_INFO 201 mod_info = native_module_info.NativeModuleInfo() 202 mock_src_need.return_value = False 203 mock_inc_need.return_value = False 204 self.assertFalse(mod_info.is_module_need_build('multiarch1')) 205 self.assertFalse(mock_warn.called) 206 207 @mock.patch.object(os.path, 'isfile') 208 @mock.patch.object( 209 native_module_info.NativeModuleInfo, '_load_module_info_file') 210 def test_is_source_need_build_return_true(self, mock_load, mock_isfile): 211 """Test _is_source_need_build with source paths or not existing.""" 212 mock_load.return_value = None, _CC_NAME_TO_MODULE_INFO 213 mod_info = native_module_info.NativeModuleInfo() 214 mock_isfile.return_value = False 215 self.assertTrue(mod_info._is_source_need_build( 216 _CC_NAME_TO_MODULE_INFO['multiarch'])) 217 218 @mock.patch.object(os.path, 'isfile') 219 @mock.patch.object( 220 native_module_info.NativeModuleInfo, '_load_module_info_file') 221 def test_is_source_need_build_return_false(self, mock_load, mock_isfile): 222 """Test _is_source_need_build without source paths or paths exist.""" 223 mock_load.return_value = None, _CC_NAME_TO_MODULE_INFO 224 mod_info = native_module_info.NativeModuleInfo() 225 self.assertFalse(mod_info._is_source_need_build( 226 _CC_NAME_TO_MODULE_INFO['multiarch1'])) 227 mock_isfile.return_value = True 228 self.assertFalse(mod_info._is_source_need_build( 229 _CC_NAME_TO_MODULE_INFO['multiarch'])) 230 231 @mock.patch.object(os.path, 'isdir') 232 @mock.patch.object( 233 native_module_info.NativeModuleInfo, '_load_module_info_file') 234 def test_is_include_need_build_return_true(self, mock_load, mock_isdir): 235 """Test _is_include_need_build with include paths and not existing.""" 236 mock_load.return_value = None, _CC_NAME_TO_MODULE_INFO 237 mock_isdir.return_value = False 238 mod_info = native_module_info.NativeModuleInfo() 239 self.assertTrue(mod_info._is_include_need_build( 240 _CC_NAME_TO_MODULE_INFO['multiarch'])) 241 242 @mock.patch.object(os.path, 'isdir') 243 @mock.patch.object( 244 native_module_info.NativeModuleInfo, '_load_module_info_file') 245 def test_is_include_need_build_return_false(self, mock_load, mock_isdir): 246 """Test _is_include_need_build without include paths or paths exist.""" 247 mock_load.return_value = None, _CC_NAME_TO_MODULE_INFO 248 mod_info = native_module_info.NativeModuleInfo() 249 self.assertFalse(mod_info._is_include_need_build( 250 _CC_NAME_TO_MODULE_INFO['multiarch1'])) 251 mock_isdir.return_value = True 252 self.assertFalse(mod_info._is_include_need_build( 253 _CC_NAME_TO_MODULE_INFO['multiarch'])) 254 mock_isdir.return_value = True 255 self.assertFalse(mod_info._is_include_need_build( 256 _CC_NAME_TO_MODULE_INFO['multiarch'])) 257 258 def test_not_implemented_methods(self): 259 """Test not implemented methods.""" 260 mod_info = native_module_info.NativeModuleInfo() 261 target = 'test' 262 with self.assertRaises(NotImplementedError): 263 mod_info.get_testable_modules() 264 with self.assertRaises(NotImplementedError): 265 mod_info.is_testable_module(mock.Mock()) 266 with self.assertRaises(NotImplementedError): 267 mod_info.has_test_config(mock.Mock()) 268 with self.assertRaises(NotImplementedError): 269 mod_info.get_robolectric_test_name(target) 270 with self.assertRaises(NotImplementedError): 271 mod_info.is_robolectric_test(target) 272 with self.assertRaises(NotImplementedError): 273 mod_info.is_auto_gen_test_config(target) 274 with self.assertRaises(NotImplementedError): 275 mod_info.is_robolectric_module(mock.Mock()) 276 with self.assertRaises(NotImplementedError): 277 mod_info.is_native_test(target) 278 279 @mock.patch.object( 280 native_module_info.NativeModuleInfo, '_load_module_info_file') 281 def test_not_implement_methods_check(self, mock_load): 282 """Test for all not implemented methods which should raise error.""" 283 mock_load.return_value = None, _CC_NAME_TO_MODULE_INFO 284 mod_info = native_module_info.NativeModuleInfo() 285 with self.assertRaises(NotImplementedError): 286 suite_name = 'test' 287 test_data = {'a': 'test'} 288 mod_info.is_suite_in_compatibility_suites(suite_name, test_data) 289 290 with self.assertRaises(NotImplementedError): 291 mod_info.get_testable_modules() 292 293 with self.assertRaises(NotImplementedError): 294 test_data = {'a': 'test'} 295 mod_info.is_testable_module(test_data) 296 297 with self.assertRaises(NotImplementedError): 298 test_data = {'a': 'test'} 299 mod_info.has_test_config(test_data) 300 301 with self.assertRaises(NotImplementedError): 302 test_mod = 'mod_a' 303 mod_info.get_robolectric_test_name(test_mod) 304 305 with self.assertRaises(NotImplementedError): 306 test_mod = 'mod_a' 307 mod_info.is_robolectric_test(test_mod) 308 309 with self.assertRaises(NotImplementedError): 310 test_mod = 'a' 311 mod_info.is_auto_gen_test_config(test_mod) 312 313 with self.assertRaises(NotImplementedError): 314 test_data = {'a': 'test'} 315 mod_info.is_robolectric_module(test_data) 316 317 with self.assertRaises(NotImplementedError): 318 test_mod = 'a' 319 mod_info.is_native_test(test_mod) 320 321 @mock.patch.object(atest.module_info.ModuleInfo, '_load_module_info_file') 322 @mock.patch.object(os.path, 'isfile') 323 @mock.patch.object(common_util, 'get_json_dict') 324 @mock.patch.object(module_info.AidegenModuleInfo, 325 '_discover_mod_file_and_target') 326 @mock.patch.object(common_util, 'get_blueprint_json_path') 327 def test_load_module_info_file(self, mock_get_json, mock_load, mock_dict, 328 mock_isfile, mock_base_load): 329 """Test _load_module_info_file.""" 330 force_build = True 331 mod_file = '/test/path' 332 mock_get_json.return_value = mod_file 333 native_module_info.NativeModuleInfo(force_build) 334 self.assertTrue(mock_get_json.called_with( 335 constant.BLUEPRINT_CC_JSONFILE_NAME)) 336 mock_load.return_value = mod_file, mod_file 337 self.assertTrue(mock_load.called_with(True)) 338 mock_dict.return_value = _CC_MODULE_INFO 339 self.assertTrue(mock_dict.called_with(mod_file)) 340 self.assertFalse(mock_base_load.called) 341 mock_base_load.reset_mock() 342 mock_get_json.reset_mock() 343 mock_load.reset_mock() 344 mock_dict.reset_mock() 345 346 native_module_info.NativeModuleInfo(force_build, mod_file) 347 self.assertFalse(mock_get_json.called) 348 mock_load.return_value = None, mod_file 349 self.assertTrue(mock_load.called_with(True)) 350 self.assertTrue(mock_dict.called_with(mod_file)) 351 self.assertFalse(mock_base_load.called) 352 mock_base_load.reset_mock() 353 mock_get_json.reset_mock() 354 mock_load.reset_mock() 355 mock_dict.reset_mock() 356 357 force_build = False 358 mock_get_json.return_value = mod_file 359 native_module_info.NativeModuleInfo(force_build, mod_file) 360 self.assertFalse(mock_get_json.called) 361 mock_isfile.return_value = True 362 self.assertFalse(mock_load.called) 363 mock_dict.return_value = _CC_MODULE_INFO 364 self.assertTrue(mock_dict.called_with(mod_file)) 365 self.assertFalse(mock_base_load.called) 366 mock_base_load.reset_mock() 367 mock_get_json.reset_mock() 368 mock_load.reset_mock() 369 mock_dict.reset_mock() 370 371 372if __name__ == '__main__': 373 unittest.main() 374