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 AidegenConfig class.""" 18 19import os 20import shutil 21import tempfile 22import unittest 23from unittest import mock 24 25from aidegen import constant 26 27from aidegen.lib import common_util 28from aidegen.lib import config 29 30 31# pylint: disable=protected-access 32class AidegenConfigUnittests(unittest.TestCase): 33 """Unit tests for config.py""" 34 35 _TMP_DIR = None 36 37 def setUp(self): 38 """Prepare the testdata related path.""" 39 AidegenConfigUnittests._TMP_DIR = tempfile.mkdtemp() 40 config.AidegenConfig._CONFIG_DIR = os.path.join( 41 AidegenConfigUnittests._TMP_DIR, '.config', 'asuite', 'aidegen') 42 config.AidegenConfig._CONFIG_FILE_PATH = os.path.join( 43 config.AidegenConfig._CONFIG_DIR, 44 config.AidegenConfig._DEFAULT_CONFIG_FILE) 45 config.AidegenConfig._ENABLE_DEBUG_DIR = os.path.join( 46 config.AidegenConfig._CONFIG_DIR, 47 config.AidegenConfig._ENABLE_DEBUG_CONFIG_DIR) 48 config.AidegenConfig.DEBUG_ENABLED_FILE_PATH = os.path.join( 49 config.AidegenConfig._CONFIG_DIR, 50 config.AidegenConfig._ENABLE_DEBUG_CONFIG_FILE) 51 52 def tearDown(self): 53 """Clear the testdata related path.""" 54 shutil.rmtree(AidegenConfigUnittests._TMP_DIR) 55 56 @mock.patch('json.load') 57 @mock.patch('builtins.open') 58 @mock.patch('os.path.exists') 59 def test_load_aidegen_config(self, mock_file_exists, mock_file_open, 60 mock_json_load): 61 """Test loading aidegen config.""" 62 mock_file_exists.return_value = False 63 cfg = config.AidegenConfig() 64 cfg._load_aidegen_config() 65 self.assertFalse(mock_file_open.called) 66 self.assertFalse(mock_json_load.called) 67 mock_file_exists.return_value = True 68 cfg = config.AidegenConfig() 69 cfg._load_aidegen_config() 70 self.assertTrue(mock_file_open.called) 71 self.assertTrue(mock_json_load.called) 72 73 @mock.patch('logging.info') 74 @mock.patch('logging.error') 75 @mock.patch('builtins.open') 76 @mock.patch('os.path.exists') 77 def test_error_load_aidegen_config(self, mock_file_exists, mock_file_open, 78 mock_error, mock_info): 79 """Test loading aidegen config with errors.""" 80 mock_file_exists.return_value = True 81 cfg = config.AidegenConfig() 82 mock_file_open.side_effect = IOError() 83 with self.assertRaises(IOError): 84 cfg._load_aidegen_config() 85 self.assertTrue(mock_error.called) 86 self.assertFalse(mock_info.called) 87 mock_file_open.reset() 88 mock_file_open.side_effect = ValueError() 89 cfg._load_aidegen_config() 90 self.assertTrue(mock_info.called) 91 92 @mock.patch('json.dump') 93 @mock.patch('builtins.open') 94 @mock.patch.object(config.AidegenConfig, '_is_config_modified') 95 def test_aidegen_config_no_changed(self, mock_is_config_modified, 96 mock_file_open, mock_json_dump): 97 """Skip saving aidegen config when no configuration data is modified.""" 98 mock_is_config_modified.return_value = False 99 cfg = config.AidegenConfig() 100 cfg._save_aidegen_config() 101 self.assertFalse(mock_file_open.called) 102 self.assertFalse(mock_json_dump.called) 103 104 @mock.patch('json.dump') 105 @mock.patch('builtins.open') 106 @mock.patch.object(config.AidegenConfig, '_is_config_modified') 107 def test_update_aidegen_config(self, mock_is_config_modified, 108 mock_file_open, mock_json_dump): 109 """Save the aidegen config once any configuration data is modified.""" 110 mock_is_config_modified.return_value = True 111 cfg = config.AidegenConfig() 112 cfg._save_aidegen_config() 113 self.assertTrue(mock_file_open.called) 114 self.assertTrue(mock_json_dump.called) 115 116 @mock.patch('logging.warning') 117 @mock.patch.object(config.AidegenConfig, '_gen_enable_debugger_config') 118 @mock.patch.object(config.AidegenConfig, '_gen_androidmanifest') 119 @mock.patch.object(config.AidegenConfig, '_gen_enable_debug_sub_dir') 120 def test_create_enable_debugger(self, mock_debug, mock_androidmanifest, 121 mock_enable, mock_warning): 122 """Test create_enable_debugger_module.""" 123 cfg = config.AidegenConfig() 124 self.assertTrue(cfg.create_enable_debugger_module('')) 125 mock_debug.side_effect = IOError() 126 self.assertFalse(cfg.create_enable_debugger_module('')) 127 self.assertTrue(mock_warning.called) 128 mock_debug.side_effect = OSError() 129 self.assertFalse(cfg.create_enable_debugger_module('')) 130 self.assertTrue(mock_warning.called) 131 mock_androidmanifest.side_effect = IOError() 132 self.assertFalse(cfg.create_enable_debugger_module('')) 133 self.assertTrue(mock_warning.called) 134 mock_androidmanifest.side_effect = OSError() 135 self.assertFalse(cfg.create_enable_debugger_module('')) 136 self.assertTrue(mock_warning.called) 137 mock_enable.side_effect = IOError() 138 self.assertFalse(cfg.create_enable_debugger_module('')) 139 self.assertTrue(mock_warning.called) 140 mock_enable.side_effect = OSError() 141 self.assertFalse(cfg.create_enable_debugger_module('')) 142 self.assertTrue(mock_warning.called) 143 144 @mock.patch.object(common_util, 'file_generate') 145 @mock.patch('os.path.exists') 146 def test_gen_debugger_config(self, mock_file_exists, mock_file_generate): 147 """Test generating the enable debugger config.""" 148 cfg = config.AidegenConfig() 149 android_sdk_version = '' 150 mock_file_exists.return_value = False 151 cfg._gen_enable_debugger_config(android_sdk_version) 152 self.assertTrue(mock_file_generate.called) 153 154 @mock.patch('os.stat') 155 @mock.patch.object(common_util, 'file_generate') 156 @mock.patch('os.path.exists') 157 def test_androidmanifest_no_changed(self, mock_file_exists, 158 mock_file_generate, mock_file_stat): 159 """No generate the AndroidManifest.xml when it exists and size > 0.""" 160 cfg = config.AidegenConfig() 161 mock_file_exists.return_value = True 162 mock_file_stat.return_value.st_size = 1 163 cfg._gen_androidmanifest() 164 self.assertFalse(mock_file_generate.called) 165 166 @mock.patch('os.stat') 167 @mock.patch.object(common_util, 'file_generate') 168 @mock.patch('os.path.exists') 169 def test_override_androidmanifest(self, mock_file_exists, 170 mock_file_generate, mock_file_stat): 171 """Override the AndroidManifest.xml when the file size is zero.""" 172 cfg = config.AidegenConfig() 173 mock_file_exists.return_value = True 174 mock_file_stat.return_value.st_size = 0 175 cfg._gen_androidmanifest() 176 self.assertTrue(mock_file_generate.called) 177 178 @mock.patch.object(common_util, 'file_generate') 179 @mock.patch('os.path.exists') 180 def test_gen_androidmanifest(self, mock_file_exists, mock_file_generate): 181 """Generate the AndroidManifest.xml when it doesn't exist.""" 182 cfg = config.AidegenConfig() 183 mock_file_exists.return_value = False 184 cfg._gen_androidmanifest() 185 self.assertTrue(mock_file_generate.called) 186 187 @mock.patch('os.makedirs') 188 @mock.patch('os.path.exists') 189 def test_config_folder_exists(self, mock_folder_exists, mock_makedirs): 190 """Skipping create the config folder once it exists.""" 191 mock_folder_exists.return_value = True 192 config.AidegenConfig() 193 self.assertFalse(mock_makedirs.called) 194 195 @mock.patch('os.makedirs') 196 @mock.patch('os.path.exists') 197 def test_create_config_folder(self, mock_folder_exists, mock_makedirs): 198 """Create the config folder when it doesn't exist.""" 199 mock_folder_exists.return_value = False 200 config.AidegenConfig() 201 self.assertTrue(mock_makedirs.called) 202 203 @mock.patch('os.path.isfile') 204 @mock.patch('builtins.open', create=True) 205 def test_deprecated_intellij_version(self, mock_open, mock_isfile): 206 """Test deprecated_intellij_version.""" 207 # Test the idea.sh file contains the deprecated string. 208 cfg = config.AidegenConfig() 209 expacted_data = ('#!/bin/sh\n\n' 210 'SUMMARY="This version of IntelliJ Community Edition ' 211 'is no longer supported."\n') 212 mock_open.side_effect = [ 213 mock.mock_open(read_data=expacted_data).return_value 214 ] 215 mock_isfile.return_value = True 216 self.assertTrue(cfg.deprecated_intellij_version(0)) 217 218 # Test the idea.sh file doesn't contains the deprecated string. 219 expacted_data = ('#!/bin/sh\n\n' 220 'JAVA_BIN="$JDK/bin/java"\n' 221 '"$JAVA_BIN" \\n') 222 mock_open.side_effect = [ 223 mock.mock_open(read_data=expacted_data).return_value 224 ] 225 self.assertFalse(cfg.deprecated_intellij_version(0)) 226 227 @mock.patch.object(config.AidegenConfig, 'deprecated_studio_version') 228 @mock.patch.object(config.AidegenConfig, 'deprecated_intellij_version') 229 def test_deprecated_version(self, mock_inj, mock_studio): 230 """Test deprecated_version.""" 231 cfg = config.AidegenConfig() 232 ide_name = constant.IDE_INTELLIJ 233 test_path = '' 234 cfg.deprecated_version(ide_name, test_path) 235 self.assertTrue(mock_inj.called) 236 237 ide_name = constant.IDE_ANDROID_STUDIO 238 cfg.deprecated_version(ide_name, test_path) 239 self.assertTrue(mock_studio.called) 240 test_ide = '' 241 self.assertFalse(cfg.deprecated_version(test_ide, test_path)) 242 243 @mock.patch.object(os.path, 'isfile') 244 def test_deprecated_studio_version(self, mock_is_file): 245 """Test deprecated_studio_version.""" 246 test_sh_name = 'test.sh' 247 # temp_dir/test 248 temp_base = os.path.join(self._TMP_DIR, 'test') 249 os.mkdir(temp_base) 250 # temp_dir/test/studio/bin 251 os.mkdir(os.path.join(temp_base, 'studio')) 252 test_bin_path = os.path.join(self._TMP_DIR, 'test', 'studio', 'bin') 253 os.mkdir(test_bin_path) 254 # /temp_dir/test/studio/bin/test.sh 255 test_sh_path = os.path.join(self._TMP_DIR, 'test', 'studio', 'bin', 256 test_sh_name) 257 # Real test.sh doesn't exist. 258 cfg = config.AidegenConfig() 259 self.assertTrue(cfg.deprecated_studio_version(test_sh_path)) 260 # The /temp_dir/test/studio/lib doesn't exist case. 261 mock_is_file.return_value = True 262 self.assertTrue(cfg.deprecated_studio_version(test_sh_path)) 263 # The /temp_dir/test/studio/lib exists. 264 test_lib_path = os.path.join(self._TMP_DIR, 'test', 'studio', 'lib') 265 os.mkdir(test_lib_path) 266 self.assertFalse(cfg.deprecated_studio_version(test_sh_path)) 267 shutil.rmtree(temp_base) 268 269 @mock.patch('os.path.isfile') 270 def test_idea_path_not_file(self, mock_isfile): 271 """Test deprecated_intellij_version.""" 272 # Test the idea_path is not a file. 273 cfg = config.AidegenConfig() 274 mock_isfile.return_value = False 275 self.assertFalse(cfg.deprecated_intellij_version(0)) 276 277 @mock.patch.object(config.AidegenConfig, 'deprecated_version') 278 @mock.patch.object(config.AidegenConfig, 'deprecated_intellij_version') 279 def test_preferred_version(self, mock_deprecated_intj, mock_deprecated): 280 """Test get preferred IntelliJ version.""" 281 cfg = config.AidegenConfig() 282 cfg._config['preferred_version'] = '' 283 self.assertEqual(cfg.preferred_version(), None) 284 285 result = 'test_intellij' 286 cfg._config['IntelliJ_preferred_version'] = result 287 mock_deprecated.return_value = False 288 self.assertEqual(cfg.preferred_version(constant.IDE_INTELLIJ), result) 289 self.assertEqual(cfg.preferred_version(result), None) 290 mock_deprecated.return_value = True 291 self.assertEqual(cfg.preferred_version(constant.IDE_INTELLIJ), None) 292 293 mock_deprecated_intj.return_value = False 294 cfg._config['preferred_version'] = 'a' 295 self.assertEqual(cfg.preferred_version(), 'a') 296 mock_deprecated_intj.return_value = True 297 self.assertEqual(cfg.preferred_version(), None) 298 299 def test_set_preferred_version(self): 300 """Test set_preferred_version.""" 301 cfg = config.AidegenConfig() 302 cfg._config[config.AidegenConfig._KEY_APPEND] = 'Yes' 303 cfg.set_preferred_version('test', None) 304 self.assertEqual(cfg._config[config.AidegenConfig._KEY_APPEND], 'test') 305 cfg.set_preferred_version('test', constant.IDE_INTELLIJ) 306 self.assertEqual(cfg._config['IntelliJ_preferred_version'], 'test') 307 308 @mock.patch('os.makedirs') 309 @mock.patch('os.path.exists') 310 def test_gen_enable_debug_sub_dir(self, mock_file_exists, mock_makedirs): 311 """Test _gen_enable_debug_sub_dir.""" 312 cfg = config.AidegenConfig() 313 mock_file_exists.return_value = True 314 cfg._gen_enable_debug_sub_dir('a') 315 self.assertFalse(mock_makedirs.called) 316 mock_file_exists.return_value = False 317 cfg._gen_enable_debug_sub_dir('a') 318 self.assertTrue(mock_makedirs.called) 319 320 321class IdeaPropertiesUnittests(unittest.TestCase): 322 """Unit tests for IdeaProperties class.""" 323 324 _CONFIG_DIR = None 325 326 def setUp(self): 327 """Prepare the testdata related path.""" 328 IdeaPropertiesUnittests._CONFIG_DIR = tempfile.mkdtemp() 329 330 def tearDown(self): 331 """Clear the testdata related path.""" 332 shutil.rmtree(IdeaPropertiesUnittests._CONFIG_DIR) 333 334 def test_set_default_properties(self): 335 """Test creating the idea.properties with default content.""" 336 cfg = config.IdeaProperties(IdeaPropertiesUnittests._CONFIG_DIR) 337 cfg._set_default_idea_properties() 338 expected_data = cfg._PROPERTIES_CONTENT.format( 339 KEY_FILE_SIZE=cfg._KEY_FILESIZE, 340 VALUE_FILE_SIZE=cfg._FILESIZE_LIMIT) 341 generated_file = os.path.join(IdeaPropertiesUnittests._CONFIG_DIR, 342 cfg._PROPERTIES_FILE) 343 generated_content = common_util.read_file_content(generated_file) 344 self.assertEqual(expected_data, generated_content) 345 346 @mock.patch.object(common_util, 'read_file_content') 347 def test_reset_max_file_size(self, mock_content): 348 """Test reset the file size limit when it's smaller than 100000.""" 349 mock_content.return_value = ('# custom IntelliJ IDEA properties\n' 350 'idea.max.intellisense.filesize=5000') 351 expected_data = ('# custom IntelliJ IDEA properties\n' 352 'idea.max.intellisense.filesize=100000') 353 cfg = config.IdeaProperties(IdeaPropertiesUnittests._CONFIG_DIR) 354 cfg._reset_max_file_size() 355 generated_file = os.path.join(IdeaPropertiesUnittests._CONFIG_DIR, 356 cfg._PROPERTIES_FILE) 357 with open(generated_file) as properties_file: 358 generated_content = properties_file.read() 359 self.assertEqual(expected_data, generated_content) 360 361 @mock.patch.object(common_util, 'file_generate') 362 @mock.patch.object(common_util, 'read_file_content') 363 def test_no_reset_max_file_size(self, mock_content, mock_gen_file): 364 """Test when the file size is larger than 100000.""" 365 mock_content.return_value = ('# custom IntelliJ IDEA properties\n' 366 'idea.max.intellisense.filesize=110000') 367 cfg = config.IdeaProperties(IdeaPropertiesUnittests._CONFIG_DIR) 368 cfg._reset_max_file_size() 369 self.assertFalse(mock_gen_file.called) 370 371 @mock.patch.object(config.IdeaProperties, '_reset_max_file_size') 372 @mock.patch.object(config.IdeaProperties, '_set_default_idea_properties') 373 @mock.patch('os.path.exists') 374 def test_set_idea_properties_called(self, mock_file_exists, 375 mock_set_default, 376 mock_reset_file_size): 377 """Test _set_default_idea_properties() method is called.""" 378 mock_file_exists.return_value = False 379 cfg = config.IdeaProperties(IdeaPropertiesUnittests._CONFIG_DIR) 380 cfg.set_max_file_size() 381 self.assertTrue(mock_set_default.called) 382 self.assertFalse(mock_reset_file_size.called) 383 384 @mock.patch.object(config.IdeaProperties, '_reset_max_file_size') 385 @mock.patch.object(config.IdeaProperties, '_set_default_idea_properties') 386 @mock.patch('os.path.exists') 387 def test_reset_properties_called(self, mock_file_exists, mock_set_default, 388 mock_reset_file_size): 389 """Test _reset_max_file_size() method is called.""" 390 mock_file_exists.return_value = True 391 cfg = config.IdeaProperties(IdeaPropertiesUnittests._CONFIG_DIR) 392 cfg.set_max_file_size() 393 self.assertFalse(mock_set_default.called) 394 self.assertTrue(mock_reset_file_size.called) 395 396 397if __name__ == '__main__': 398 unittest.main() 399